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:
2024-04-20 14:51:54 -05:00
parent 9dc0cc7841
commit efd442bbfa
11 changed files with 192 additions and 11 deletions

View File

@@ -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",

View File

@@ -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) {