diff --git a/compiler/cl-ast/src/ast.rs b/compiler/cl-ast/src/ast.rs index 7fafffa..1a8b271 100644 --- a/compiler/cl-ast/src/ast.rs +++ b/compiler/cl-ast/src/ast.rs @@ -228,15 +228,17 @@ pub enum ImplKind { /// An import of nonlocal [Item]s #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Use { + pub absolute: bool, pub tree: UseTree, } /// A tree of [Item] imports #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum UseTree { - Tree(Path, Vec), - Alias(Path, Identifier), - Path(Path), + Tree(Vec), + Path(PathPart, Box), + Alias(Identifier, Identifier), + Name(Identifier), Glob, } diff --git a/compiler/cl-ast/src/ast_impl.rs b/compiler/cl-ast/src/ast_impl.rs index 8db3133..5eca237 100644 --- a/compiler/cl-ast/src/ast_impl.rs +++ b/compiler/cl-ast/src/ast_impl.rs @@ -283,20 +283,22 @@ mod display { impl Display for Use { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { tree } = self; - write!(f, "use {tree}") + let Self { absolute, tree } = self; + if *absolute { + write!(f, "use ::{tree}") + } else { + write!(f, "use {tree}") + } } } impl Display for UseTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - UseTree::Tree(path, tree) => { - write!(f, "{path}")?; - separate(tree, ", ")(f.delimit(INLINE_BRACES)) - } + UseTree::Tree(tree) => separate(tree, ", ")(f.delimit(INLINE_BRACES)), + UseTree::Path(path, rest) => write!(f, "{path}::{rest}"), UseTree::Alias(path, name) => write!(f, "{path} as {name}"), - UseTree::Path(path) => write!(f, "{path}"), + UseTree::Name(name) => write!(f, "{name}"), UseTree::Glob => write!(f, "*"), } } diff --git a/compiler/cl-ast/src/ast_visitor/fold.rs b/compiler/cl-ast/src/ast_visitor/fold.rs index 7ee0fec..7bc1dea 100644 --- a/compiler/cl-ast/src/ast_visitor/fold.rs +++ b/compiler/cl-ast/src/ast_visitor/fold.rs @@ -159,8 +159,8 @@ pub trait Fold { or_fold_impl_kind(self, kind) } fn fold_use(&mut self, u: Use) -> Use { - let Use { tree } = u; - Use { tree: self.fold_use_tree(tree) } + let Use { absolute, tree } = u; + Use { absolute, tree: self.fold_use_tree(tree) } } fn fold_use_tree(&mut self, tree: UseTree) -> UseTree { or_fold_use_tree(self, tree) @@ -468,16 +468,19 @@ pub fn or_fold_impl_kind(folder: &mut F, kind: ImplKind) -> Im #[inline] pub fn or_fold_use_tree(folder: &mut F, tree: UseTree) -> UseTree { match tree { - UseTree::Tree(path, tree) => UseTree::Tree( - folder.fold_path(path), + UseTree::Tree(tree) => UseTree::Tree( tree.into_iter() .map(|tree| folder.fold_use_tree(tree)) .collect(), ), + UseTree::Path(path, rest) => UseTree::Path( + folder.fold_path_part(path), + Box::new(folder.fold_use_tree(*rest)), + ), UseTree::Alias(path, name) => { - UseTree::Alias(folder.fold_path(path), folder.fold_identifier(name)) + UseTree::Alias(folder.fold_identifier(path), folder.fold_identifier(name)) } - UseTree::Path(path) => UseTree::Path(folder.fold_path(path)), + UseTree::Name(name) => UseTree::Name(folder.fold_identifier(name)), UseTree::Glob => UseTree::Glob, } } diff --git a/compiler/cl-ast/src/ast_visitor/visit.rs b/compiler/cl-ast/src/ast_visitor/visit.rs index fe17611..e18efa9 100644 --- a/compiler/cl-ast/src/ast_visitor/visit.rs +++ b/compiler/cl-ast/src/ast_visitor/visit.rs @@ -131,7 +131,7 @@ pub trait Visit<'a>: Sized { or_visit_impl_kind(self, target) } fn visit_use(&mut self, u: &'a Use) { - let Use { tree } = u; + let Use { absolute: _, tree } = u; self.visit_use_tree(tree); } fn visit_use_tree(&mut self, tree: &'a UseTree) { @@ -386,15 +386,20 @@ pub fn or_visit_impl_kind<'a, V: Visit<'a>>(visitor: &mut V, target: &'a ImplKin pub fn or_visit_use_tree<'a, V: Visit<'a>>(visitor: &mut V, tree: &'a UseTree) { match tree { - UseTree::Tree(path, tree) => { - visitor.visit_path(path); + UseTree::Tree(tree) => { tree.iter().for_each(|tree| visitor.visit_use_tree(tree)); } + UseTree::Path(path, rest) => { + visitor.visit_path_part(path); + visitor.visit_use_tree(rest) + } UseTree::Alias(path, name) => { - visitor.visit_path(path); + visitor.visit_identifier(path); + visitor.visit_identifier(name); + } + UseTree::Name(name) => { visitor.visit_identifier(name); } - UseTree::Path(path) => visitor.visit_path(path), UseTree::Glob => {} } } diff --git a/compiler/cl-parser/src/parser.rs b/compiler/cl-parser/src/parser.rs index 8b3082a..c3faf35 100644 --- a/compiler/cl-parser/src/parser.rs +++ b/compiler/cl-parser/src/parser.rs @@ -607,30 +607,40 @@ impl<'t> Parser<'t> { pub fn parse_use(&mut self) -> PResult { self.consume_peeked(); - Ok(Use { tree: self.parse_use_tree()? }) + let absolute = self.match_op(Punct::ColonColon, Parsing::Use).is_ok(); + let tree = self.parse_use_tree()?; + self.match_op(Punct::Semi, Parsing::Use)?; + Ok(Use { tree, absolute }) } pub fn parse_use_tree(&mut self) -> PResult { const PARSING: Parsing = Parsing::UseTree; // glob import - if self.match_op(Punct::Star, PARSING).is_ok() { - return Ok(UseTree::Glob); - } - let path = self.path()?; - Ok(match self.peek_kind(PARSING) { - Ok(TokenKind::As) => { + Ok(match self.peek_kind(PARSING)? { + TokenKind::Punct(Punct::Star) => { self.consume_peeked(); - UseTree::Alias(path, self.identifier()?) + UseTree::Glob } - Ok(TokenKind::Punct(Punct::LCurly)) => UseTree::Tree( - path, - delim( - sep(Self::parse_use_tree, Punct::Comma, CURLIES.1, PARSING), - CURLIES, - PARSING, - )(self)?, - ), - _ => UseTree::Path(path), + TokenKind::Punct(Punct::LCurly) => UseTree::Tree(delim( + sep(Self::parse_use_tree, Punct::Comma, CURLIES.1, PARSING), + CURLIES, + PARSING, + )(self)?), + TokenKind::SelfKw | TokenKind::Super | TokenKind::Identifier => { + let name = self.path_part()?; + if self.match_op(Punct::ColonColon, PARSING).is_ok() { + UseTree::Path(name, Box::new(self.parse_use_tree()?)) + } else { + let PathPart::Ident(name) = name else { + Err(self.error( + ErrorKind::ExpectedParsing { want: Parsing::Identifier }, + PARSING, + ))? + }; + UseTree::Name(name) + } + } + t => Err(self.error(Unexpected(t), Parsing::UseTree))?, }) } diff --git a/compiler/cl-repl/examples/yaml.rs b/compiler/cl-repl/examples/yaml.rs index 503967d..c0574ad 100644 --- a/compiler/cl-repl/examples/yaml.rs +++ b/compiler/cl-repl/examples/yaml.rs @@ -325,16 +325,17 @@ pub mod yamlify { } impl Yamlify for Use { fn yaml(&self, y: &mut Yamler) { - let Self { tree } = self; - y.key("Use").yaml(tree); + let Self { absolute, tree } = self; + y.key("Use").pair("absolute", absolute).yaml(tree); } } impl Yamlify for UseTree { fn yaml(&self, y: &mut Yamler) { match self { - UseTree::Tree(path, tree) => y.pair("path", path).pair("tree", tree), - UseTree::Alias(path, name) => y.pair("path", path).pair("name", name), - UseTree::Path(path) => y.pair("path", path), + UseTree::Tree(trees) => y.pair("trees", trees), + UseTree::Path(path, tree) => y.pair("path", path).pair("tree", tree), + UseTree::Alias(from, to) => y.pair("from", from).pair("to", to), + UseTree::Name(name) => y.pair("name", name), UseTree::Glob => y.value("Glob"), }; } diff --git a/grammar.ebnf b/grammar.ebnf index ba02f91..235ade0 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -45,10 +45,9 @@ Alias = "type" Identifier ('=' Ty)? ';' ; Impl = "impl" Path '{' Item* '}' ; (* TODO: Impl Trait for Target*) -Use = "use" UseTree ; -UseTree = Path '{' (UseTree ',')* UseTree? '}' - | Path "as" Identifier - | Path | '*' ; +Use = "use" '::'? UseTree ';' ; +UseTree = '*' | '{' (UseTree ',')* UseTree? '}' + | PathPart ('::' UseTree | "as" Identifier)? ; (* type *) Ty = Never | Empty | Path | TyTuple | TyRef | TyFn ;