conlang: Import items into scope with use!
grammar: - Improve specification of `Path` - Add `Use` and `UseTree` rules - Add `Use` as a variant of ItemKind cl-token: - Add new keywords `use` and `as` cl-ast: - Add nodes for Use and UseTree - Add new ItemKind for Use - Implement traversal in Visit and Fold cl-interpret: - Mark ItemKind::Use with a todo cl-parser: - Update to match grammar cl-typeck: - Update to match changes in AST - Mark UseTrees as NameCollectable and TypeResolvable, but leave as todos
This commit is contained in:
@@ -30,7 +30,7 @@ pub enum ErrorKind {
|
||||
want: Parsing,
|
||||
},
|
||||
/// Indicates unfinished code
|
||||
Todo,
|
||||
Todo(&'static str),
|
||||
}
|
||||
impl From<LexError> for ErrorKind {
|
||||
fn from(value: LexError) -> Self {
|
||||
@@ -69,6 +69,8 @@ pub enum Parsing {
|
||||
VariantKind,
|
||||
Impl,
|
||||
ImplKind,
|
||||
Use,
|
||||
UseTree,
|
||||
|
||||
Ty,
|
||||
TyKind,
|
||||
@@ -116,7 +118,7 @@ impl Display for Error {
|
||||
let Self { reason, while_parsing, loc } = self;
|
||||
match reason {
|
||||
// TODO entries are debug-printed
|
||||
ErrorKind::Todo => write!(f, "{loc} {reason} {while_parsing:?}"),
|
||||
ErrorKind::Todo(_) => write!(f, "{loc} {reason} {while_parsing:?}"),
|
||||
// lexical errors print their own higher-resolution loc info
|
||||
ErrorKind::Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"),
|
||||
_ => write!(f, "{loc} {reason} while parsing {while_parsing}"),
|
||||
@@ -134,7 +136,7 @@ impl Display for ErrorKind {
|
||||
ErrorKind::Unexpected(t) => write!(f, "Encountered unexpected token `{t}`"),
|
||||
ErrorKind::ExpectedToken { want: e, got: g } => write!(f, "Expected `{e}`, got `{g}`"),
|
||||
ErrorKind::ExpectedParsing { want } => write!(f, "Expected {want}"),
|
||||
ErrorKind::Todo => write!(f, "TODO:"),
|
||||
ErrorKind::Todo(unfinished) => write!(f, "TODO: {unfinished}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,6 +168,8 @@ impl Display for Parsing {
|
||||
Parsing::VariantKind => "an enum variant",
|
||||
Parsing::Impl => "an impl block",
|
||||
Parsing::ImplKind => "the target of an impl block",
|
||||
Parsing::Use => "a use item",
|
||||
Parsing::UseTree => "a use-tree",
|
||||
|
||||
Parsing::Ty => "a type",
|
||||
Parsing::TyKind => "a type",
|
||||
|
||||
@@ -162,6 +162,7 @@ macro item_like() {
|
||||
| TokenKind::Struct
|
||||
| TokenKind::Enum
|
||||
| TokenKind::Impl
|
||||
| TokenKind::Use
|
||||
}
|
||||
|
||||
/// Top level parsing
|
||||
@@ -204,17 +205,24 @@ impl<'t> Parser<'t> {
|
||||
///
|
||||
/// See also: [Parser::path_part], [Parser::identifier]
|
||||
///
|
||||
/// [Path] = `::`? ([PathPart] `::`)* [PathPart]?
|
||||
/// [Path] = `::` *RelativePath*? | *RelativePath* \
|
||||
/// *RelativePath* = [PathPart] (`::` [PathPart])*
|
||||
pub fn path(&mut self) -> PResult<Path> {
|
||||
const PARSING: Parsing = Parsing::PathExpr;
|
||||
let absolute = self.match_op(Punct::ColonColon, PARSING).is_ok();
|
||||
let mut parts = vec![];
|
||||
|
||||
while let Ok(path_part) = self.path_part() {
|
||||
parts.push(path_part);
|
||||
if self.match_op(Punct::ColonColon, PARSING).is_err() {
|
||||
break;
|
||||
if absolute {
|
||||
match self.path_part() {
|
||||
Ok(part) => parts.push(part),
|
||||
Err(_) => return Ok(Path { absolute, parts }),
|
||||
}
|
||||
} else {
|
||||
parts.push(self.path_part()?)
|
||||
};
|
||||
|
||||
while self.match_op(Punct::ColonColon, Parsing::PathExpr).is_ok() {
|
||||
parts.push(self.path_part()?)
|
||||
}
|
||||
|
||||
Ok(Path { absolute, parts })
|
||||
@@ -295,6 +303,7 @@ impl<'t> Parser<'t> {
|
||||
TokenKind::Struct => self.parse_struct()?.into(),
|
||||
TokenKind::Enum => self.parse_enum()?.into(),
|
||||
TokenKind::Impl => self.parse_impl()?.into(),
|
||||
TokenKind::Use => self.parse_use()?.into(),
|
||||
t => Err(self.error(Unexpected(t), Parsing::Item))?,
|
||||
})
|
||||
}
|
||||
@@ -596,6 +605,35 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_use(&mut self) -> PResult<Use> {
|
||||
self.consume_peeked();
|
||||
Ok(Use { tree: self.parse_use_tree()? })
|
||||
}
|
||||
|
||||
pub fn parse_use_tree(&mut self) -> PResult<UseTree> {
|
||||
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) => {
|
||||
self.consume_peeked();
|
||||
UseTree::Alias(path, self.identifier()?)
|
||||
}
|
||||
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),
|
||||
})
|
||||
}
|
||||
|
||||
/// [Visibility] = `pub`?
|
||||
pub fn visibility(&mut self) -> Visibility {
|
||||
match self.match_type(TokenKind::Pub, Parsing::Visibility) {
|
||||
|
||||
Reference in New Issue
Block a user