cl-typeck: Module imports v0.1
- NameCollects use items - Preprocesses them - Uses no fancy algorithms - Doesn't respect item visibility at all - *declaration-order-dependent* :( - works, though! :) - TODO: Lazy evaluation of literally any of this stuff.
This commit is contained in:
parent
ef190f2d66
commit
b796411742
@ -49,6 +49,7 @@ impl Display for DefKind<'_> {
|
|||||||
match self {
|
match self {
|
||||||
DefKind::Undecided => write!(f, "undecided"),
|
DefKind::Undecided => write!(f, "undecided"),
|
||||||
DefKind::Impl(id) => write!(f, "impl {id}"),
|
DefKind::Impl(id) => write!(f, "impl {id}"),
|
||||||
|
DefKind::Use(id) => write!(f, "use (inside {id})"),
|
||||||
DefKind::Type(kind) => write!(f, "{kind}"),
|
DefKind::Type(kind) => write!(f, "{kind}"),
|
||||||
DefKind::Value(kind) => write!(f, "{kind}"),
|
DefKind::Value(kind) => write!(f, "{kind}"),
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,8 @@ pub mod definition {
|
|||||||
Undecided,
|
Undecided,
|
||||||
/// An impl block
|
/// An impl block
|
||||||
Impl(DefID),
|
Impl(DefID),
|
||||||
|
/// A use tree, and its parent
|
||||||
|
Use(DefID),
|
||||||
/// A type, such as a `type`, `struct`, or `enum`
|
/// A type, such as a `type`, `struct`, or `enum`
|
||||||
Type(TypeKind<'a>),
|
Type(TypeKind<'a>),
|
||||||
/// A value, such as a `const`, `static`, or `fn`
|
/// A value, such as a `const`, `static`, or `fn`
|
||||||
@ -132,7 +134,7 @@ pub mod definition {
|
|||||||
Alias(Option<DefID>),
|
Alias(Option<DefID>),
|
||||||
/// A primitive type, built-in to the compiler
|
/// A primitive type, built-in to the compiler
|
||||||
Intrinsic(Intrinsic),
|
Intrinsic(Intrinsic),
|
||||||
/// A user-defined abstract data type
|
/// A user-defined aromatic data type
|
||||||
Adt(Adt<'a>),
|
Adt(Adt<'a>),
|
||||||
/// A reference to an already-defined type: &T
|
/// A reference to an already-defined type: &T
|
||||||
Ref(u16, DefID),
|
Ref(u16, DefID),
|
||||||
@ -154,7 +156,7 @@ pub mod definition {
|
|||||||
Module,
|
Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A user-defined Abstract Data Type
|
/// A user-defined Aromatic Data Type
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Adt<'a> {
|
pub enum Adt<'a> {
|
||||||
/// A union-like enum type
|
/// A union-like enum type
|
||||||
@ -243,7 +245,7 @@ pub mod module {
|
|||||||
pub parent: Option<DefID>,
|
pub parent: Option<DefID>,
|
||||||
pub types: HashMap<&'a str, DefID>,
|
pub types: HashMap<&'a str, DefID>,
|
||||||
pub values: HashMap<&'a str, DefID>,
|
pub values: HashMap<&'a str, DefID>,
|
||||||
pub imports: HashMap<&'a str, DefID>,
|
pub imports: Vec<DefID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module<'_> {
|
impl Module<'_> {
|
||||||
@ -261,7 +263,7 @@ pub mod module {
|
|||||||
if let Some(parent) = parent {
|
if let Some(parent) = parent {
|
||||||
writeln!(f, "Parent: {}", parent.get())?;
|
writeln!(f, "Parent: {}", parent.get())?;
|
||||||
}
|
}
|
||||||
for (name, table) in [("Types", types), ("Values", values), ("Imports", imports)] {
|
for (name, table) in [("Types", types), ("Values", values)] {
|
||||||
if table.is_empty() {
|
if table.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -270,6 +272,12 @@ pub mod module {
|
|||||||
writeln!(f, " {name} => {id}")?;
|
writeln!(f, " {name} => {id}")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !imports.is_empty() {
|
||||||
|
write!(f, "Imports:")?;
|
||||||
|
for id in imports {
|
||||||
|
write!(f, "{id},")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -348,9 +356,8 @@ pub mod project {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Project<'a> {
|
pub struct Project<'a> {
|
||||||
pub pool: Pool<Def<'a>, DefID>,
|
pub pool: Pool<Def<'a>, DefID>,
|
||||||
/// Stores anonymous tuples, function pointer types, etc.\
|
/// Stores anonymous tuples, function pointer types, etc.
|
||||||
pub anon_types: HashMap<TypeKind<'a>, DefID>,
|
pub anon_types: HashMap<TypeKind<'a>, DefID>,
|
||||||
pub impls_pending: Vec<(&'a cl_ast::Impl, DefID)>,
|
|
||||||
pub root: DefID,
|
pub root: DefID,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +391,7 @@ pub mod project {
|
|||||||
module: module::Module::new(root),
|
module: module::Module::new(root),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
// TODO: Self is not a real type!
|
||||||
let selfty = pool.insert(Def {
|
let selfty = pool.insert(Def {
|
||||||
name: "Self",
|
name: "Self",
|
||||||
vis: Visibility::Public,
|
vis: Visibility::Public,
|
||||||
@ -397,7 +405,7 @@ pub mod project {
|
|||||||
anon_types.insert(TypeKind::Never, never);
|
anon_types.insert(TypeKind::Never, never);
|
||||||
anon_types.insert(TypeKind::SelfTy, selfty);
|
anon_types.insert(TypeKind::SelfTy, selfty);
|
||||||
|
|
||||||
Self { pool, root, anon_types, impls_pending: Default::default() }
|
Self { pool, root, anon_types }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,9 +616,20 @@ pub mod project {
|
|||||||
Path::from(self).evaluate(prj, parent)
|
Path::from(self).evaluate(prj, parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl EvaluableTypeExpression for PathPart {
|
||||||
|
type Out = DefID;
|
||||||
|
fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> {
|
||||||
|
match self {
|
||||||
|
PathPart::SuperKw => prj
|
||||||
|
.parent_of(parent)
|
||||||
|
.ok_or_else(|| "Attempt to get super of root".into()),
|
||||||
|
PathPart::SelfKw => Ok(parent),
|
||||||
|
PathPart::Ident(Identifier(name)) => name.as_str().evaluate(prj, parent),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<'a> EvaluableTypeExpression for Path<'a> {
|
impl<'a> EvaluableTypeExpression for Path<'a> {
|
||||||
type Out = DefID;
|
type Out = DefID;
|
||||||
|
|
||||||
fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> {
|
fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> {
|
||||||
let (id, path) = prj.get_type(*self, parent).ok_or("Failed to get type")?;
|
let (id, path) = prj.get_type(*self, parent).ok_or("Failed to get type")?;
|
||||||
|
|
||||||
@ -714,7 +733,7 @@ pub mod name_collector {
|
|||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
ModuleKind::Inline(file) => file.collect(c, module)?,
|
ModuleKind::Inline(file) => file.collect(c, module)?,
|
||||||
ModuleKind::Outline => todo!("Out of line modules"),
|
ModuleKind::Outline => todo!("Out of line modules: {name}"),
|
||||||
};
|
};
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
@ -731,6 +750,17 @@ pub mod name_collector {
|
|||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'a> NameCollectable<'a> for Use {
|
||||||
|
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
||||||
|
let def =
|
||||||
|
Def { module: Mod::new(parent), kind: DefKind::Use(parent), ..Default::default() };
|
||||||
|
|
||||||
|
let id = c.pool.insert(def);
|
||||||
|
c[parent].module.imports.push(id);
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<'a> NameCollectable<'a> for Alias {
|
impl<'a> NameCollectable<'a> for Alias {
|
||||||
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
||||||
let Alias { to: Identifier(name), .. } = self;
|
let Alias { to: Identifier(name), .. } = self;
|
||||||
@ -809,17 +839,6 @@ pub mod name_collector {
|
|||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> NameCollectable<'a> for Use {
|
|
||||||
fn collect(&'a self, _c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
|
||||||
let Self { tree } = self;
|
|
||||||
todo!("Use {tree} in {parent}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> NameCollectable<'a> for UseTree {
|
|
||||||
fn collect(&'a self, _c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
|
||||||
todo!("Use {self} in {parent}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> NameCollectable<'a> for Block {
|
impl<'a> NameCollectable<'a> for Block {
|
||||||
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result<DefID, &'static str> {
|
||||||
self.stmts.as_slice().collect(c, parent)
|
self.stmts.as_slice().collect(c, parent)
|
||||||
@ -904,6 +923,135 @@ pub mod name_collector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod use_importer {
|
||||||
|
#![allow(unused)]
|
||||||
|
use std::fmt::format;
|
||||||
|
|
||||||
|
use cl_ast::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
definition::{Def, DefKind},
|
||||||
|
key::DefID,
|
||||||
|
project::Project,
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseResult = Result<(), String>;
|
||||||
|
|
||||||
|
impl<'a> Project<'a> {
|
||||||
|
pub fn resolve_imports(&mut self) -> UseResult {
|
||||||
|
for id in self.pool.key_iter() {
|
||||||
|
self.visit_def(id)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_def(&mut self, id: DefID) -> UseResult {
|
||||||
|
let Def { name, vis, meta, kind, source, module } = &self.pool[id];
|
||||||
|
if let (DefKind::Use(parent), Some(source)) = (kind, source) {
|
||||||
|
let Item { kind: ItemKind::Use(u), .. } = source else {
|
||||||
|
Err(format!("Not a use item: {source}"))?
|
||||||
|
};
|
||||||
|
println!("Importing use item {u}");
|
||||||
|
|
||||||
|
self.visit_use(u, *parent);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_use(&mut self, u: &'a Use, parent: DefID) -> UseResult {
|
||||||
|
let Use { absolute, tree } = u;
|
||||||
|
|
||||||
|
self.visit_use_tree(tree, parent, if *absolute { self.root } else { parent })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_use_tree(&mut self, tree: &'a UseTree, parent: DefID, c: DefID) -> UseResult {
|
||||||
|
match tree {
|
||||||
|
UseTree::Tree(trees) => {
|
||||||
|
for tree in trees {
|
||||||
|
self.visit_use_tree(tree, parent, c)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UseTree::Path(part, rest) => {
|
||||||
|
let c = self.evaluate(part, c)?;
|
||||||
|
self.visit_use_tree(rest, parent, c)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
UseTree::Name(name) => self.visit_use_leaf(name, parent, c)?,
|
||||||
|
UseTree::Alias(Identifier(from), Identifier(to)) => {
|
||||||
|
self.visit_use_alias(from, to, parent, c)?
|
||||||
|
}
|
||||||
|
UseTree::Glob => self.visit_use_glob(parent, c)?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_use_path(&mut self) -> UseResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_use_leaf(
|
||||||
|
&mut self,
|
||||||
|
part: &'a Identifier,
|
||||||
|
parent: DefID,
|
||||||
|
c: DefID,
|
||||||
|
) -> UseResult {
|
||||||
|
let Identifier(name) = part;
|
||||||
|
self.visit_use_alias(name, name, parent, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_use_alias(
|
||||||
|
&mut self,
|
||||||
|
from: &'a str,
|
||||||
|
name: &'a str,
|
||||||
|
parent: DefID,
|
||||||
|
c: DefID,
|
||||||
|
) -> UseResult {
|
||||||
|
let mut imported = false;
|
||||||
|
let c_mod = &self[c].module;
|
||||||
|
let (tid, vid) = (
|
||||||
|
c_mod.types.get(from).copied(),
|
||||||
|
c_mod.values.get(from).copied(),
|
||||||
|
);
|
||||||
|
let parent = &mut self[parent].module;
|
||||||
|
|
||||||
|
if let Some(tid) = tid {
|
||||||
|
parent.types.insert(name, tid);
|
||||||
|
imported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(vid) = vid {
|
||||||
|
parent.values.insert(name, vid);
|
||||||
|
imported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if imported {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Identifier {name} not found in module {c}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_use_glob(&mut self, parent: DefID, c: DefID) -> UseResult {
|
||||||
|
// Loop over all the items in c, and add them as items in the parent
|
||||||
|
if parent == c {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let [parent, c] = self
|
||||||
|
.pool
|
||||||
|
.get_many_mut([parent, c])
|
||||||
|
.expect("parent and c are not the same");
|
||||||
|
|
||||||
|
for (k, v) in &c.module.types {
|
||||||
|
parent.module.types.entry(*k).or_insert(*v);
|
||||||
|
}
|
||||||
|
for (k, v) in &c.module.values {
|
||||||
|
parent.module.values.entry(*k).or_insert(*v);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod type_resolver {
|
pub mod type_resolver {
|
||||||
//! Performs step 2 of type checking: Evaluating type definitions
|
//! Performs step 2 of type checking: Evaluating type definitions
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user