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

@@ -99,6 +99,8 @@ pub enum ItemKind {
Function(Function),
/// An [implementation](Impl)
Impl(Impl),
/// An [import](Use)
Use(Use),
}
/// An alias to another [Ty]
@@ -223,6 +225,21 @@ pub enum ImplKind {
Trait { impl_trait: Path, for_type: Box<Ty> },
}
/// An import of nonlocal [Item]s
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Use {
pub tree: UseTree,
}
/// A tree of [Item] imports
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum UseTree {
Tree(Path, Vec<UseTree>),
Alias(Path, Identifier),
Path(Path),
Glob,
}
/// A type expression
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Ty {

View File

@@ -116,6 +116,7 @@ mod display {
ItemKind::Struct(v) => v.fmt(f),
ItemKind::Enum(v) => v.fmt(f),
ItemKind::Impl(v) => v.fmt(f),
ItemKind::Use(v) => v.fmt(f),
}
}
}
@@ -280,6 +281,27 @@ 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}")
}
}
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::Alias(path, name) => write!(f, "{path} as {name}"),
UseTree::Path(path) => write!(f, "{path}"),
UseTree::Glob => write!(f, "*"),
}
}
}
impl Display for Ty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.kind.fmt(f)
@@ -665,6 +687,7 @@ mod convert {
Struct => ItemKind::Struct,
Enum => ItemKind::Enum,
Impl => ItemKind::Impl,
Use => ItemKind::Use,
}
impl From for StructKind {
Vec<Ty> => StructKind::Tuple,

View File

@@ -158,6 +158,13 @@ pub trait Fold {
fn fold_impl_kind(&mut self, kind: ImplKind) -> ImplKind {
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) }
}
fn fold_use_tree(&mut self, tree: UseTree) -> UseTree {
or_fold_use_tree(self, tree)
}
fn fold_ty(&mut self, t: Ty) -> Ty {
let Ty { extents, kind } = t;
Ty { extents: self.fold_span(extents), kind: self.fold_ty_kind(kind) }
@@ -375,6 +382,7 @@ pub fn or_fold_item_kind<F: Fold + ?Sized>(folder: &mut F, kind: ItemKind) -> It
ItemKind::Static(s) => ItemKind::Static(folder.fold_static(s)),
ItemKind::Function(f) => ItemKind::Function(folder.fold_function(f)),
ItemKind::Impl(i) => ItemKind::Impl(folder.fold_impl(i)),
ItemKind::Use(u) => ItemKind::Use(folder.fold_use(u)),
}
}
@@ -441,6 +449,23 @@ pub fn or_fold_impl_kind<F: Fold + ?Sized>(folder: &mut F, kind: ImplKind) -> Im
}
}
#[inline]
pub fn or_fold_use_tree<F: Fold + ?Sized>(folder: &mut F, tree: UseTree) -> UseTree {
match tree {
UseTree::Tree(path, tree) => UseTree::Tree(
folder.fold_path(path),
tree.into_iter()
.map(|tree| folder.fold_use_tree(tree))
.collect(),
),
UseTree::Alias(path, name) => {
UseTree::Alias(folder.fold_path(path), folder.fold_identifier(name))
}
UseTree::Path(path) => UseTree::Path(folder.fold_path(path)),
UseTree::Glob => UseTree::Glob,
}
}
#[inline]
/// Folds a [TyKind] in the default way
pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind {

View File

@@ -125,11 +125,18 @@ pub trait Visit<'a>: Sized {
fn visit_impl(&mut self, i: &'a Impl) {
let Impl { target, body } = i;
self.visit_impl_kind(target);
self.visit_file(body)
self.visit_file(body);
}
fn visit_impl_kind(&mut self, target: &'a ImplKind) {
or_visit_impl_kind(self, target)
}
fn visit_use(&mut self, u: &'a Use) {
let Use { tree } = u;
self.visit_use_tree(tree);
}
fn visit_use_tree(&mut self, tree: &'a UseTree) {
or_visit_use_tree(self, tree)
}
fn visit_ty(&mut self, t: &'a Ty) {
let Ty { extents, kind } = t;
self.visit_span(extents);
@@ -320,6 +327,7 @@ pub fn or_visit_item_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a ItemKind)
ItemKind::Static(s) => visitor.visit_static(s),
ItemKind::Function(f) => visitor.visit_function(f),
ItemKind::Impl(i) => visitor.visit_impl(i),
ItemKind::Use(u) => visitor.visit_use(u),
}
}
@@ -364,6 +372,21 @@ 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);
tree.iter().for_each(|tree| visitor.visit_use_tree(tree));
}
UseTree::Alias(path, name) => {
visitor.visit_path(path);
visitor.visit_identifier(name);
}
UseTree::Path(path) => visitor.visit_path(path),
UseTree::Glob => {}
}
}
pub fn or_visit_ty_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a TyKind) {
match kind {
TyKind::Never => {}