diff --git a/crates/cli/tests/benchmarks/platform/Host.roc b/crates/cli/tests/benchmarks/platform/Host.roc index 25019c7c90..e30616d0ae 100644 --- a/crates/cli/tests/benchmarks/platform/Host.roc +++ b/crates/cli/tests/benchmarks/platform/Host.roc @@ -1,6 +1,4 @@ -hosted Host - exposes [put_line!, put_int!, get_int!] - imports [] +hosted [put_line!, put_int!, get_int!] put_line! : Str => {} diff --git a/crates/cli/tests/test-projects/false-interpreter/platform/Host.roc b/crates/cli/tests/test-projects/false-interpreter/platform/Host.roc index ef6aaaa5d7..79b6782819 100644 --- a/crates/cli/tests/test-projects/false-interpreter/platform/Host.roc +++ b/crates/cli/tests/test-projects/false-interpreter/platform/Host.roc @@ -1,6 +1,4 @@ -hosted Host - exposes [open_file!, close_file!, get_file_line!, get_file_bytes!, put_line!, put_raw!, get_line!, get_char!] - imports [] +hosted [open_file!, close_file!, get_file_line!, get_file_bytes!, put_line!, put_raw!, get_line!, get_char!] open_file! : Str => U64 diff --git a/crates/cli/tests/test-projects/test-platform-effects-zig/Effect.roc b/crates/cli/tests/test-projects/test-platform-effects-zig/Effect.roc index c719a7886c..0e0ff5d3a3 100644 --- a/crates/cli/tests/test-projects/test-platform-effects-zig/Effect.roc +++ b/crates/cli/tests/test-projects/test-platform-effects-zig/Effect.roc @@ -1,6 +1,4 @@ -hosted Effect - exposes [put_line!, get_line!] - imports [] +hosted [put_line!, get_line!] put_line! : Str => {} diff --git a/crates/compiler/fmt/src/header.rs b/crates/compiler/fmt/src/header.rs index d7f2f0bbfa..39ab89ddfa 100644 --- a/crates/compiler/fmt/src/header.rs +++ b/crates/compiler/fmt/src/header.rs @@ -199,15 +199,10 @@ pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) { pub fn fmt_hosted_header<'a>(buf: &mut Buf, header: &'a HostedHeader<'a>) { buf.indent(0); buf.push_str("hosted"); - let indent = INDENT; - fmt_default_spaces(buf, header.before_name, indent); - buf.push_str(header.name.value.as_str()); + let indent = fmt_spaces_with_outdent(buf, header.before_exposes, 0); - header.exposes.keyword.format(buf, indent); - fmt_exposes(buf, header.exposes.item, indent); - header.imports.keyword.format(buf, indent); - fmt_imports(buf, header.imports.item, indent); + fmt_exposes(buf, header.exposes, indent); } pub fn fmt_app_header<'a>(buf: &mut Buf, header: &'a AppHeader<'a>) { diff --git a/crates/compiler/load_internal/src/file.rs b/crates/compiler/load_internal/src/file.rs index 5a22355898..8f7170dd46 100644 --- a/crates/compiler/load_internal/src/file.rs +++ b/crates/compiler/load_internal/src/file.rs @@ -3952,17 +3952,25 @@ fn parse_header<'a>( }, parse_state, )) => { + let module_name = match opt_expected_module_name { + Some(pq_name) => arena.alloc_str(pq_name.as_inner().as_str()), + None => { + // [modules-revamp] [privacy-changes] TODO: Support test/check on nested modules + arena.alloc_str(filename.file_stem().unwrap().to_str().unwrap()) + } + }; + let info = HeaderInfo { filename, is_root_module, opt_shorthand, packages: &[], header_type: HeaderType::Hosted { - name: header.name.value, - exposes: unspace(arena, header.exposes.item.items), + name: roc_parse::header::ModuleName::new(module_name), + exposes: unspace(arena, header.exposes.items), }, module_comments: comments, - header_imports: Some(header.imports), + header_imports: header.old_imports, }; let (module_id, _, header) = diff --git a/crates/compiler/parse/src/ast.rs b/crates/compiler/parse/src/ast.rs index 4c18323c60..cdff4d6499 100644 --- a/crates/compiler/parse/src/ast.rs +++ b/crates/compiler/parse/src/ast.rs @@ -172,7 +172,14 @@ impl<'a> Header<'a> { }), Self::header_imports_to_defs(arena, header.old_imports), ), - Header::Package(_) | Header::Platform(_) | Header::Hosted(_) => (self, Defs::default()), + Header::Hosted(header) => ( + Header::Hosted(HostedHeader { + old_imports: None, + ..header + }), + Self::header_imports_to_defs(arena, header.old_imports), + ), + Header::Package(_) | Header::Platform(_) => (self, Defs::default()), }; (header, defs) diff --git a/crates/compiler/parse/src/header.rs b/crates/compiler/parse/src/header.rs index e664bc32dd..161c2238f0 100644 --- a/crates/compiler/parse/src/header.rs +++ b/crates/compiler/parse/src/header.rs @@ -103,7 +103,7 @@ pub fn header<'a>() -> impl Parser<'a, SpacesBefore<'a, Header<'a>>, EHeader<'a> map( skip_first( keyword("hosted", EHeader::Start), - increment_min_indent(hosted_header()) + increment_min_indent(one_of![hosted_header(), old_hosted_header()]) ), Header::Hosted ), @@ -184,15 +184,38 @@ fn imports_none_if_empty(value: ImportsKeywordItem<'_>) -> Option() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> { - record!(HostedHeader { - before_name: space0_e(EHeader::IndentStart), - name: loc(module_name_help(EHeader::ModuleName)), - exposes: specialize_err(EHeader::Exposes, exposes_values_kw()), - imports: specialize_err(EHeader::Imports, imports()), - }) + map( + and( + backtrackable(space0_e(EHeader::IndentStart)), + specialize_err(EHeader::Exposes, exposes_list()), + ), + |(before_exposes, exposes)| HostedHeader { + before_exposes, + exposes, + old_imports: None, + }, + ) .trace("hosted_header") } +#[inline(always)] +fn old_hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> { + map( + record!(OldHostedHeader { + before_name: space0_e(EHeader::IndentStart), + name: loc(module_name_help(EHeader::ModuleName)), + exposes: specialize_err(EHeader::Exposes, exposes_values_kw()), + imports: specialize_err(EHeader::Imports, imports()), + }), + |old_hosted| HostedHeader { + before_exposes: old_hosted.before_name, + exposes: old_hosted.exposes.item, + old_imports: Some(old_hosted.imports), + }, + ) + .trace("old_hosted_header") +} + fn chomp_module_name(buffer: &[u8]) -> Result<&str, Progress> { use encode_unicode::CharExt; @@ -1196,6 +1219,15 @@ pub type ImportsCollection<'a> = Collection<'a, Loc> #[derive(Clone, Debug, PartialEq)] pub struct HostedHeader<'a> { + pub before_exposes: &'a [CommentOrNewline<'a>], + pub exposes: Collection<'a, Loc>>>, + + // Keeping this so we can format old interface header into module headers + pub old_imports: Option>>, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct OldHostedHeader<'a> { pub before_name: &'a [CommentOrNewline<'a>], pub name: Loc>, pub exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc>>>>, diff --git a/crates/compiler/parse/src/normalize.rs b/crates/compiler/parse/src/normalize.rs index 2f49efaa57..66b39ee003 100644 --- a/crates/compiler/parse/src/normalize.rs +++ b/crates/compiler/parse/src/normalize.rs @@ -172,10 +172,9 @@ impl<'a> Normalize<'a> for Header<'a> { provides: header.provides.normalize(arena), }), Header::Hosted(header) => Header::Hosted(HostedHeader { - before_name: &[], - name: header.name.normalize(arena), + before_exposes: &[], exposes: header.exposes.normalize(arena), - imports: header.imports.normalize(arena), + old_imports: None, }), } } diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.result-ast index 3109a99ed4..eaf1163c06 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.result-ast @@ -2,26 +2,9 @@ SpacesBefore { before: [], item: Hosted( HostedHeader { - before_name: [], - name: @7-10 ModuleName( - "Foo", - ), - exposes: KeywordItem { - keyword: Spaces { - before: [], - item: ExposesKeyword, - after: [], - }, - item: [], - }, - imports: KeywordItem { - keyword: Spaces { - before: [], - item: ImportsKeyword, - after: [], - }, - item: [], - }, + before_exposes: [], + exposes: [], + old_imports: None, }, ), } diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.roc index be42a79bdc..aad4617748 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_hosted_header.header.roc @@ -1 +1 @@ -hosted Foo exposes [] imports [] +hosted [] diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.formatted.roc new file mode 100644 index 0000000000..aad4617748 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.formatted.roc @@ -0,0 +1 @@ +hosted [] diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.result-ast new file mode 100644 index 0000000000..628a47833d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.result-ast @@ -0,0 +1,19 @@ +SpacesBefore { + before: [], + item: Hosted( + HostedHeader { + before_exposes: [], + exposes: [], + old_imports: Some( + KeywordItem { + keyword: Spaces { + before: [], + item: ImportsKeyword, + after: [], + }, + item: [], + }, + ), + }, + ), +} diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.roc new file mode 100644 index 0000000000..be42a79bdc --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_old_hosted_header.header.roc @@ -0,0 +1 @@ +hosted Foo exposes [] imports [] diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.formatted.roc index ef3bf3291b..97c4fd30d2 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.formatted.roc @@ -1,12 +1,5 @@ -hosted Foo - exposes - [ - Stuff, - Things, - somethingElse, - ] - imports - [ - Blah, - Baz.{ stuff, things }, - ] +hosted [ + Stuff, + Things, + somethingElse, +] diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.result-ast index b94ff73ac9..90186af504 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.result-ast @@ -2,99 +2,29 @@ SpacesBefore { before: [], item: Hosted( HostedHeader { - before_name: [], - name: @7-10 ModuleName( - "Foo", - ), - exposes: KeywordItem { - keyword: Spaces { - before: [ - Newline, - ], - item: ExposesKeyword, - after: [ - Newline, - ], - }, - item: Collection { - items: [ - @45-50 SpaceBefore( - ExposedName( - "Stuff", - ), - [ - Newline, - ], + before_exposes: [], + exposes: Collection { + items: [ + @8-13 ExposedName( + "Stuff", + ), + @15-21 ExposedName( + "Things", + ), + @27-40 SpaceBefore( + ExposedName( + "somethingElse", ), - @64-70 SpaceBefore( - ExposedName( - "Things", - ), - [ - Newline, - ], - ), - @84-97 SpaceBefore( - ExposedName( - "somethingElse", - ), - [ - Newline, - ], - ), - ], - final_comments: [ - Newline, - ], - }, - }, - imports: KeywordItem { - keyword: Spaces { - before: [ - Newline, - ], - item: ImportsKeyword, - after: [ - Newline, - ], - }, - item: Collection { - items: [ - @143-147 SpaceBefore( - Module( - ModuleName( - "Blah", - ), - [], - ), - [ - Newline, - ], - ), - @161-182 SpaceBefore( - Module( - ModuleName( - "Baz", - ), - [ - @167-172 ExposedName( - "stuff", - ), - @174-180 ExposedName( - "things", - ), - ], - ), - [ - Newline, - ], - ), - ], - final_comments: [ - Newline, - ], - }, + [ + Newline, + ], + ), + ], + final_comments: [ + Newline, + ], }, + old_imports: None, }, ), } diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.roc b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.roc index f555902730..66140a6122 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_hosted_header.header.roc @@ -1,12 +1,3 @@ -hosted Foo - exposes - [ - Stuff, - Things, - somethingElse, - ] - imports - [ - Blah, - Baz.{ stuff, things }, - ] +hosted [Stuff, Things, + somethingElse, +] diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.formatted.roc new file mode 100644 index 0000000000..97c4fd30d2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.formatted.roc @@ -0,0 +1,5 @@ +hosted [ + Stuff, + Things, + somethingElse, +] diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.result-ast new file mode 100644 index 0000000000..996e259492 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.result-ast @@ -0,0 +1,88 @@ +SpacesBefore { + before: [], + item: Hosted( + HostedHeader { + before_exposes: [], + exposes: Collection { + items: [ + @45-50 SpaceBefore( + ExposedName( + "Stuff", + ), + [ + Newline, + ], + ), + @64-70 SpaceBefore( + ExposedName( + "Things", + ), + [ + Newline, + ], + ), + @84-97 SpaceBefore( + ExposedName( + "somethingElse", + ), + [ + Newline, + ], + ), + ], + final_comments: [ + Newline, + ], + }, + old_imports: Some( + KeywordItem { + keyword: Spaces { + before: [ + Newline, + ], + item: ImportsKeyword, + after: [ + Newline, + ], + }, + item: Collection { + items: [ + @143-147 SpaceBefore( + Module( + ModuleName( + "Blah", + ), + [], + ), + [ + Newline, + ], + ), + @161-182 SpaceBefore( + Module( + ModuleName( + "Baz", + ), + [ + @167-172 ExposedName( + "stuff", + ), + @174-180 ExposedName( + "things", + ), + ], + ), + [ + Newline, + ], + ), + ], + final_comments: [ + Newline, + ], + }, + }, + ), + }, + ), +} diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.roc b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.roc new file mode 100644 index 0000000000..f555902730 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nonempty_old_hosted_header.header.roc @@ -0,0 +1,12 @@ +hosted Foo + exposes + [ + Stuff, + Things, + somethingElse, + ] + imports + [ + Blah, + Baz.{ stuff, things }, + ] diff --git a/crates/compiler/test_syntax/tests/test_fmt.rs b/crates/compiler/test_syntax/tests/test_fmt.rs index 4b1d3cff97..7eae347bca 100644 --- a/crates/compiler/test_syntax/tests/test_fmt.rs +++ b/crates/compiler/test_syntax/tests/test_fmt.rs @@ -5813,27 +5813,40 @@ mod test_fmt { #[test] fn single_line_hosted() { - module_formats_same(indoc!( - r" - hosted Foo exposes [] imports []" - )); + module_formats_to( + indoc!( + r" + hosted Foo exposes [] imports []" + ), + indoc!( + r" + hosted []" + ), + ); } #[test] fn multi_line_hosted() { - module_formats_same(indoc!( - r" - hosted Foo - exposes [ + module_formats_to( + indoc!( + r" + hosted Foo + exposes [ + Stuff, + Things, + somethingElse, + ] + imports []" + ), + indoc!( + r" + hosted [ Stuff, Things, somethingElse, - ] - imports [ - Blah, - Baz.{ stuff, things }, ]" - )); + ), + ); } /// Annotations and aliases diff --git a/crates/compiler/test_syntax/tests/test_snapshots.rs b/crates/compiler/test_syntax/tests/test_snapshots.rs index da86f6992c..e043c474ea 100644 --- a/crates/compiler/test_syntax/tests/test_snapshots.rs +++ b/crates/compiler/test_syntax/tests/test_snapshots.rs @@ -436,6 +436,7 @@ mod test_snapshots { pass/empty_hosted_header.header, pass/empty_list.expr, pass/empty_module_header.header, + pass/empty_old_hosted_header.header, pass/empty_package_header.header, pass/empty_platform_header.header, pass/empty_record.expr, @@ -589,6 +590,7 @@ mod test_snapshots { pass/newline_singleton_list.expr, pass/no_newline_after_implements.expr, pass/nonempty_hosted_header.header, + pass/nonempty_old_hosted_header.header, pass/nonempty_package_header.header, pass/nonempty_platform_header.header, pass/not_double_parens.expr, diff --git a/crates/language_server/src/analysis/tokens.rs b/crates/language_server/src/analysis/tokens.rs index 53f5fbee30..7caa8d3994 100644 --- a/crates/language_server/src/analysis/tokens.rs +++ b/crates/language_server/src/analysis/tokens.rs @@ -299,15 +299,13 @@ impl IterTokens for PlatformHeader<'_> { impl IterTokens for HostedHeader<'_> { fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc> { let Self { - before_name: _, - name, + before_exposes: _, exposes, - imports, + old_imports, } = self; - (name.iter_tokens(arena).into_iter()) - .chain(exposes.item.iter_tokens(arena)) - .chain(imports.item.iter_tokens(arena)) + (exposes.iter_tokens(arena).into_iter()) + .chain(old_imports.iter().flat_map(|i| i.item.iter_tokens(arena))) .collect_in(arena) } }