grammar: Make UseTree less ultra-janky

This commit is contained in:
John 2024-04-21 18:57:46 -05:00
parent 5341631781
commit e36a684422
7 changed files with 69 additions and 47 deletions

View File

@ -228,15 +228,17 @@ pub enum ImplKind {
/// An import of nonlocal [Item]s /// An import of nonlocal [Item]s
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Use { pub struct Use {
pub absolute: bool,
pub tree: UseTree, pub tree: UseTree,
} }
/// A tree of [Item] imports /// A tree of [Item] imports
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum UseTree { pub enum UseTree {
Tree(Path, Vec<UseTree>), Tree(Vec<UseTree>),
Alias(Path, Identifier), Path(PathPart, Box<UseTree>),
Path(Path), Alias(Identifier, Identifier),
Name(Identifier),
Glob, Glob,
} }

View File

@ -283,20 +283,22 @@ mod display {
impl Display for Use { impl Display for Use {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { tree } = self; let Self { absolute, tree } = self;
if *absolute {
write!(f, "use ::{tree}")
} else {
write!(f, "use {tree}") write!(f, "use {tree}")
} }
} }
}
impl Display for UseTree { impl Display for UseTree {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
UseTree::Tree(path, tree) => { UseTree::Tree(tree) => separate(tree, ", ")(f.delimit(INLINE_BRACES)),
write!(f, "{path}")?; UseTree::Path(path, rest) => write!(f, "{path}::{rest}"),
separate(tree, ", ")(f.delimit(INLINE_BRACES))
}
UseTree::Alias(path, name) => write!(f, "{path} as {name}"), 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, "*"), UseTree::Glob => write!(f, "*"),
} }
} }

View File

@ -159,8 +159,8 @@ pub trait Fold {
or_fold_impl_kind(self, kind) or_fold_impl_kind(self, kind)
} }
fn fold_use(&mut self, u: Use) -> Use { fn fold_use(&mut self, u: Use) -> Use {
let Use { tree } = u; let Use { absolute, tree } = u;
Use { tree: self.fold_use_tree(tree) } Use { absolute, tree: self.fold_use_tree(tree) }
} }
fn fold_use_tree(&mut self, tree: UseTree) -> UseTree { fn fold_use_tree(&mut self, tree: UseTree) -> UseTree {
or_fold_use_tree(self, tree) or_fold_use_tree(self, tree)
@ -468,16 +468,19 @@ pub fn or_fold_impl_kind<F: Fold + ?Sized>(folder: &mut F, kind: ImplKind) -> Im
#[inline] #[inline]
pub fn or_fold_use_tree<F: Fold + ?Sized>(folder: &mut F, tree: UseTree) -> UseTree { pub fn or_fold_use_tree<F: Fold + ?Sized>(folder: &mut F, tree: UseTree) -> UseTree {
match tree { match tree {
UseTree::Tree(path, tree) => UseTree::Tree( UseTree::Tree(tree) => UseTree::Tree(
folder.fold_path(path),
tree.into_iter() tree.into_iter()
.map(|tree| folder.fold_use_tree(tree)) .map(|tree| folder.fold_use_tree(tree))
.collect(), .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(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, UseTree::Glob => UseTree::Glob,
} }
} }

View File

@ -131,7 +131,7 @@ pub trait Visit<'a>: Sized {
or_visit_impl_kind(self, target) or_visit_impl_kind(self, target)
} }
fn visit_use(&mut self, u: &'a Use) { fn visit_use(&mut self, u: &'a Use) {
let Use { tree } = u; let Use { absolute: _, tree } = u;
self.visit_use_tree(tree); self.visit_use_tree(tree);
} }
fn visit_use_tree(&mut self, tree: &'a UseTree) { 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) { pub fn or_visit_use_tree<'a, V: Visit<'a>>(visitor: &mut V, tree: &'a UseTree) {
match tree { match tree {
UseTree::Tree(path, tree) => { UseTree::Tree(tree) => {
visitor.visit_path(path);
tree.iter().for_each(|tree| visitor.visit_use_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) => { UseTree::Alias(path, name) => {
visitor.visit_path(path); visitor.visit_identifier(path);
visitor.visit_identifier(name);
}
UseTree::Name(name) => {
visitor.visit_identifier(name); visitor.visit_identifier(name);
} }
UseTree::Path(path) => visitor.visit_path(path),
UseTree::Glob => {} UseTree::Glob => {}
} }
} }

View File

@ -607,30 +607,40 @@ impl<'t> Parser<'t> {
pub fn parse_use(&mut self) -> PResult<Use> { pub fn parse_use(&mut self) -> PResult<Use> {
self.consume_peeked(); 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<UseTree> { pub fn parse_use_tree(&mut self) -> PResult<UseTree> {
const PARSING: Parsing = Parsing::UseTree; const PARSING: Parsing = Parsing::UseTree;
// glob import // glob import
if self.match_op(Punct::Star, PARSING).is_ok() { Ok(match self.peek_kind(PARSING)? {
return Ok(UseTree::Glob); TokenKind::Punct(Punct::Star) => {
}
let path = self.path()?;
Ok(match self.peek_kind(PARSING) {
Ok(TokenKind::As) => {
self.consume_peeked(); self.consume_peeked();
UseTree::Alias(path, self.identifier()?) UseTree::Glob
} }
Ok(TokenKind::Punct(Punct::LCurly)) => UseTree::Tree( TokenKind::Punct(Punct::LCurly) => UseTree::Tree(delim(
path,
delim(
sep(Self::parse_use_tree, Punct::Comma, CURLIES.1, PARSING), sep(Self::parse_use_tree, Punct::Comma, CURLIES.1, PARSING),
CURLIES, CURLIES,
PARSING, PARSING,
)(self)?, )(self)?),
), TokenKind::SelfKw | TokenKind::Super | TokenKind::Identifier => {
_ => UseTree::Path(path), 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))?,
}) })
} }

View File

@ -325,16 +325,17 @@ pub mod yamlify {
} }
impl Yamlify for Use { impl Yamlify for Use {
fn yaml(&self, y: &mut Yamler) { fn yaml(&self, y: &mut Yamler) {
let Self { tree } = self; let Self { absolute, tree } = self;
y.key("Use").yaml(tree); y.key("Use").pair("absolute", absolute).yaml(tree);
} }
} }
impl Yamlify for UseTree { impl Yamlify for UseTree {
fn yaml(&self, y: &mut Yamler) { fn yaml(&self, y: &mut Yamler) {
match self { match self {
UseTree::Tree(path, tree) => y.pair("path", path).pair("tree", tree), UseTree::Tree(trees) => y.pair("trees", trees),
UseTree::Alias(path, name) => y.pair("path", path).pair("name", name), UseTree::Path(path, tree) => y.pair("path", path).pair("tree", tree),
UseTree::Path(path) => y.pair("path", path), UseTree::Alias(from, to) => y.pair("from", from).pair("to", to),
UseTree::Name(name) => y.pair("name", name),
UseTree::Glob => y.value("Glob"), UseTree::Glob => y.value("Glob"),
}; };
} }

View File

@ -45,10 +45,9 @@ Alias = "type" Identifier ('=' Ty)? ';' ;
Impl = "impl" Path '{' Item* '}' ; Impl = "impl" Path '{' Item* '}' ;
(* TODO: Impl Trait for Target*) (* TODO: Impl Trait for Target*)
Use = "use" UseTree ; Use = "use" '::'? UseTree ';' ;
UseTree = Path '{' (UseTree ',')* UseTree? '}' UseTree = '*' | '{' (UseTree ',')* UseTree? '}'
| Path "as" Identifier | PathPart ('::' UseTree | "as" Identifier)? ;
| Path | '*' ;
(* type *) (* type *)
Ty = Never | Empty | Path | TyTuple | TyRef | TyFn ; Ty = Never | Empty | Path | TyTuple | TyRef | TyFn ;