diff --git a/compiler/fmt/src/module.rs b/compiler/fmt/src/module.rs index aa856ca8ca..6ceca3d28c 100644 --- a/compiler/fmt/src/module.rs +++ b/compiler/fmt/src/module.rs @@ -175,7 +175,7 @@ fn fmt_imports_entry<'a>(buf: &mut String<'a>, entry: &'a ImportsEntry<'a>, inde } } - Package(_name, _entries) => { + Package(_pkg, _name, _entries) => { todo!("TODO Format imported package"); } diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index f3cba328a6..0175e0bb77 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2796,7 +2796,7 @@ fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec) { (module_name.as_str().into(), exposed) } - Package(_package_name, _exposes) => { + Package(_package_name, _module_name, _exposes) => { todo!("TODO support exposing package-qualified module names."); } diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index 7fda5784cb..5e2da09ea9 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -177,7 +177,11 @@ pub enum ImportsEntry<'a> { Module(ModuleName<'a>, Vec<'a, Loc>>), /// e.g. `base.Task` or `base.Task.{ after }` or `base.{ Task.{ Task, after } }` - Package(&'a str, Vec<'a, Loc<&'a ImportsEntry<'a>>>), + Package( + &'a str, + ModuleName<'a>, + Vec<'a, Loc>>, + ), // Spaces SpaceBefore(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]), diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index fff9a6a94f..5440f0b54c 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -544,11 +544,16 @@ fn typed_ident<'a>() -> impl Parser<'a, TypedIdent<'a>> { } #[inline(always)] +#[allow(clippy::type_complexity)] fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>> { map_with_arena!( and!( - // e.g. `Task` - module_name(), + and!( + // e.g. `base.` + optional(skip_second!(lowercase_ident(), ascii_char(b'.'))), + // e.g. `Task` + module_name() + ), // e.g. `.{ Task, after}` optional(skip_first!( ascii_char(b'.'), @@ -562,13 +567,17 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>> { )) ), |arena, - (module_name, opt_values): ( - ModuleName<'a>, + ((opt_shortname, module_name), opt_values): ( + (Option<&'a str>, ModuleName<'a>), Option>>> )| { let exposed_values = opt_values.unwrap_or_else(|| Vec::new_in(arena)); - ImportsEntry::Module(module_name, exposed_values) + match opt_shortname { + Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values), + + None => ImportsEntry::Module(module_name, exposed_values), + } } ) } diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 059c78ad4a..9e01d1de26 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -27,8 +27,8 @@ mod test_parse { self, Attempting, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch, }; use roc_parse::header::{ - AppHeader, Effects, ExposesEntry, InterfaceHeader, ModuleName, PackageEntry, PackageName, - PackageOrPath, PlatformHeader, To, + AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, + PackageName, PackageOrPath, PlatformHeader, To, }; use roc_parse::module::{app_header, interface_header, module_defs, platform_header}; use roc_parse::parser::{Fail, FailReason, Parser, State}; @@ -2358,16 +2358,19 @@ mod test_parse { use ExposesEntry::Exposed; use PackageOrPath::Path; + let newlines = &[Newline]; let pkg_entry = PackageEntry::Entry { shorthand: "base", spaces_after_shorthand: &[], - package_or_path: Located::new(0, 0, 33, 45, Path(PlainLine("./platform"))), + package_or_path: Located::new(1, 1, 21, 33, Path(PlainLine("./platform"))), }; - let loc_pkg_entry = Located::new(0, 0, 27, 45, pkg_entry); + let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); let arena = Bump::new(); let packages = bumpalo::vec![in &arena; loc_pkg_entry]; - let imports = Vec::new_in(&arena); - let provide_entry = Located::new(0, 0, 59, 68, Exposed("quicksort")); + let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena)); + let loc_import = Located::new(2, 2, 14, 25, import); + let imports = bumpalo::vec![in &arena; loc_import]; + let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); let provides = bumpalo::vec![in &arena; provide_entry]; let module_name = StrLiteral::PlainLine("quicksort"); let expected = AppHeader { @@ -2375,13 +2378,13 @@ mod test_parse { packages, imports, provides, - to: Located::new(0, 0, 74, 78, To::ExistingPackage("base")), + to: Located::new(3, 3, 30, 34, To::ExistingPackage("base")), after_app_keyword: &[], - before_packages: &[], + before_packages: newlines, after_packages: &[], - before_imports: &[], + before_imports: newlines, after_imports: &[], - before_provides: &[], + before_provides: newlines, after_provides: &[], before_to: &[], after_to: &[], @@ -2389,7 +2392,10 @@ mod test_parse { let src = indoc!( r#" - app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base + app "quicksort" + packages { base: "./platform" } + imports [ foo.Bar.Baz ] + provides [ quicksort ] to base "# ); let actual = app_header()