[fine] Imports maybe

Feels a little sketchy
This commit is contained in:
John Doty 2024-03-07 20:07:41 -08:00
parent 1199646e29
commit 60e8f64c01
4 changed files with 299 additions and 85 deletions

View file

@ -582,7 +582,8 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
Declaration::Function { .. } => inst_panic!("store func"),
Declaration::Class { .. } => inst_panic!("store class"),
Declaration::Import { .. } => inst_panic!("store import"),
Declaration::ImportedModule { .. } => inst_panic!("store import"),
Declaration::ImportedDeclaration { .. } => inst_panic!("store import decl"),
};
c.push(instruction);
OK
@ -662,7 +663,8 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
Declaration::Class { .. } => return OK,
// fix later
Declaration::Import { .. } => ice!(c, t, "import compile not supported"),
Declaration::ImportedModule { .. } => ice!(c, t, "import compile not supported"),
Declaration::ImportedDeclaration { .. } => ice!(c, t, "import decl not supported"),
};
c.push(instruction);
@ -874,11 +876,12 @@ fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
// We pass in the arguments.... by... field order?
let Type::Object(ct, _) = c.semantics.type_of(t) else {
let Type::Object(mid, ct, _) = c.semantics.type_of(t) else {
c.push(inst_panic!("new obj not ob"));
return OK;
};
let class = c.semantics.class_of(ct);
let class = c.semantics.class_of(mid, ct);
let field_list = tree.child_tree_of_kind(&c.syntax, TreeKind::FieldList)?;
let mut field_bindings = HashMap::new();
@ -951,12 +954,12 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
let ident = tree.nth_token(2)?.as_str(&c.source);
let environment = match &typ {
Type::Object(ct, _) => {
let class = c.semantics.class_of(*ct);
Type::Object(mid, ct, _) => {
let class = c.semantics.class_of(*mid, *ct);
class.env.clone()
}
Type::Class(ct, _) => {
let class = c.semantics.class_of(*ct);
Type::Class(mid, ct, _) => {
let class = c.semantics.class_of(*mid, *ct);
class.static_env.clone()
}
_ => {

View file

@ -2,7 +2,7 @@ use std::{collections::HashMap, fs, path::PathBuf, rc::Rc};
use compiler::compile;
use parser::parse;
use semantics::{check, Error, ImportRecord, Semantics};
use semantics::{check, Error, ImportRecord, ModuleId, Semantics};
use vm::{eval, Context};
pub mod compiler;
@ -57,12 +57,12 @@ impl ModuleLoader for StandardModuleLoader {
}
pub struct Module {
id: u64,
id: ModuleId,
semantics: Rc<Semantics>,
}
impl Module {
pub fn id(&self) -> u64 {
pub fn id(&self) -> ModuleId {
self.id
}
@ -103,10 +103,18 @@ impl Runtime {
// TODO: Errors here are bad! Remember, run everything!
match self.loader.load_module(&name)? {
ModuleSource::SourceText(source) => {
let mid = ModuleId::from(id_assign);
id_assign += 1;
let source: Rc<str> = source.into();
let (tree, lines) = parse(&source);
let semantics =
Rc::new(Semantics::new(name.clone().into(), source, tree, lines));
let semantics = Rc::new(Semantics::new(
mid,
name.clone().into(),
source,
tree,
lines,
));
let mut normalized_imports = Vec::new();
for import in semantics.imports() {
@ -116,8 +124,7 @@ impl Runtime {
normalized_imports.push((import, normalized));
}
init_pending.insert(name, (id_assign, normalized_imports, semantics));
id_assign += 1;
init_pending.insert(name, (mid, normalized_imports, semantics));
}
}
}

View file

@ -116,10 +116,19 @@ impl std::ops::Deref for ClassRef {
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ModuleId(u64);
impl From<u64> for ModuleId {
fn from(value: u64) -> Self {
ModuleId(value)
}
}
#[derive(Clone, Debug)]
pub struct ImportRecord {
pub name: String,
pub module_id: u64,
pub module_id: ModuleId,
pub semantics: Weak<Semantics>,
}
@ -164,12 +173,12 @@ pub enum Type {
// A class is the static type of a class; when the class is referred to
// by name it has this type. (Distinct from an instance!)
Class(TreeRef, Rc<str>),
Class(ModuleId, TreeRef, Rc<str>),
// An object is the type of an allocated object instance. Details of its
// class need to be fetched explicitly from the semantics via the
// TreeRef and `Semantics::class_of`; they are computed lazily.
Object(TreeRef, Rc<str>),
Object(ModuleId, TreeRef, Rc<str>),
// An alternate is one or another type.
Alternate(Box<[Type]>),
@ -257,8 +266,8 @@ impl fmt::Display for Type {
write!(f, "$_")
}
List(t) => write!(f, "list<{t}>"),
Object(_, name) => write!(f, "{} instance", name),
Class(_, name) => write!(f, "class {}", name),
Object(_, _, name) => write!(f, "{} instance", name),
Class(_, _, name) => write!(f, "class {}", name),
Alternate(ts) => {
let mut first = true;
for t in ts.iter() {
@ -318,8 +327,12 @@ impl std::cmp::Ord for Type {
lv.cmp(&rv)
}
(Type::List(x), Type::List(y)) => x.cmp(y),
(Type::Class(lt, _), Type::Class(rt, _)) => lt.index().cmp(&rt.index()),
(Type::Object(lt, _), Type::Object(rt, _)) => lt.index().cmp(&rt.index()),
(Type::Class(lm, lt, _), Type::Class(rm, rt, _)) => {
(lm.0, lt.index()).cmp(&(rm.0, rt.index()))
}
(Type::Object(lm, lt, _), Type::Object(rm, rt, _)) => {
(lm.0, lt.index()).cmp(&(rm.0, rt.index()))
}
(Type::Alternate(ll), Type::Alternate(rr)) => ll.cmp(rr),
_ => Ordering::Equal,
@ -353,9 +366,11 @@ pub enum Declaration {
declaration: TreeRef,
location: Location,
index: usize,
exported: bool,
},
Function {
declaration: TreeRef, //?
exported: bool,
},
ExternFunction {
declaration_type: Type,
@ -363,10 +378,52 @@ pub enum Declaration {
},
Class {
declaration: TreeRef, //?
exported: bool,
},
Import {
ImportedModule {
declaration: TreeRef,
exported: bool,
},
ImportedDeclaration {
semantics: Weak<Semantics>,
tree: Option<TreeRef>,
declaration: Box<Declaration>,
},
}
impl Declaration {
pub fn is_exported(&self) -> bool {
match self {
Declaration::Variable { exported, .. } => *exported,
Declaration::Function { exported, .. } => *exported,
Declaration::ExternFunction { .. } => true,
Declaration::Class { exported, .. } => *exported,
Declaration::ImportedModule { exported, .. } => *exported,
Declaration::ImportedDeclaration { .. } => false,
}
}
pub fn tree(&self) -> Option<TreeRef> {
match self {
Declaration::Variable { declaration, .. } => Some(*declaration),
Declaration::Function { declaration, .. } => Some(*declaration),
Declaration::ExternFunction { .. } => None,
Declaration::Class { declaration, .. } => Some(*declaration),
Declaration::ImportedModule { declaration, .. } => Some(*declaration),
Declaration::ImportedDeclaration { tree, .. } => *tree,
}
}
pub fn set_exported(&mut self) {
match self {
Declaration::Variable { exported, .. } => *exported = true,
Declaration::Function { exported, .. } => *exported = true,
Declaration::ExternFunction { .. } => (),
Declaration::Class { exported, .. } => *exported = true,
Declaration::ImportedModule { exported, .. } => *exported = true,
Declaration::ImportedDeclaration { .. } => (),
}
}
}
pub struct Environment {
@ -426,6 +483,7 @@ impl Environment {
declaration: t,
location: self.location,
index: self.next_index,
exported: false,
},
);
self.next_index += 1;
@ -634,6 +692,7 @@ enum Incremental<T> {
}
pub struct Semantics {
mid: ModuleId,
file: Rc<str>,
source: Rc<str>,
syntax_tree: Rc<SyntaxTree>,
@ -654,7 +713,13 @@ pub struct Semantics {
}
impl Semantics {
pub fn new(file: Rc<str>, source: Rc<str>, tree: Rc<SyntaxTree>, lines: Rc<Lines>) -> Self {
pub fn new(
mid: ModuleId,
file: Rc<str>,
source: Rc<str>,
tree: Rc<SyntaxTree>,
lines: Rc<Lines>,
) -> Self {
let mut logical_parents = vec![None; tree.len()];
if let Some(root) = tree.root() {
set_logical_parents(&mut logical_parents, &tree, root, None);
@ -663,6 +728,7 @@ impl Semantics {
let root_environment = Environment::new(None, Location::Module);
let mut semantics = Semantics {
mid,
file,
source,
syntax_tree: tree.clone(),
@ -842,7 +908,10 @@ impl Semantics {
let existing = environment.declarations.insert(
name.as_str(&self.source).into(),
Declaration::Function { declaration: *t },
Declaration::Function {
declaration: *t,
exported: false,
},
);
if existing.is_some() {
self.report_error_tree(
@ -865,49 +934,89 @@ impl Semantics {
fn environment_of_file(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
let mut environment = Environment::new(Some(parent), Location::Module);
let mut explicit_exports = Vec::new();
for child in tree.children.iter() {
let Child::Tree(t) = child else {
continue;
};
let ct = &self.syntax_tree[*t];
let binding = match ct.kind {
let binding = {
// Redeclare t to be mutable (and a copy)
let mut t = *t;
let mut exported = false;
// Loop here in order to dereference TreeKind::Export;
// children of an export tree still go in the local
// environment.
loop {
let ct = &self.syntax_tree[t];
match ct.kind {
TreeKind::FunctionDecl => {
let Some(name) = ct.nth_token(1) else {
continue;
break None;
};
if name.kind != TokenKind::Identifier {
continue;
break None;
}
let declaration = Declaration::Function { declaration: *t };
Some(("function", name, declaration))
let declaration = Declaration::Function {
declaration: t,
exported,
};
break Some(("function", name, declaration));
}
TreeKind::ClassDecl => {
let Some(name) = ct.nth_token(1) else {
continue;
break None;
};
if name.kind != TokenKind::Identifier {
continue;
break None;
}
let declaration = Declaration::Class { declaration: *t };
Some(("class", name, declaration))
let declaration = Declaration::Class {
declaration: t,
exported,
};
break Some(("class", name, declaration));
}
TreeKind::Import => {
let Some(name) = ct.nth_token(3) else {
continue;
break None;
};
if name.kind != TokenKind::Identifier {
break None;
}
let declaration = Declaration::ImportedModule {
declaration: t,
exported,
};
break Some(("import", name, declaration));
}
TreeKind::Export => {
let Some(inner) = ct.nth_tree(1) else {
break None;
};
t = inner;
exported = true;
continue;
}
let declaration = Declaration::Import { declaration: *t };
Some(("import", name, declaration))
TreeKind::ExportList => {
for child in &ct.children {
if let Child::Token(tok) = child {
if tok.kind == TokenKind::Identifier {
explicit_exports.push(tok);
}
}
}
}
_ => break None,
}
}
_ => None,
};
let ct = &self.syntax_tree[*t];
if let Some((what, name, declaration)) = binding {
let existing = environment
.declarations
@ -924,6 +1033,14 @@ impl Semantics {
}
}
for tok in explicit_exports {
environment
.declarations
.get_mut(tok.as_str(&self.source))
// NOTE: If not present, we report the error elsewhere.
.map(|decl| decl.set_exported());
}
EnvironmentRef::new(environment)
}
@ -1113,7 +1230,23 @@ impl Semantics {
EnvironmentRef::new(env)
}
pub fn class_of(&self, t: TreeRef) -> ClassRef {
pub fn class_of(&self, mid: ModuleId, t: TreeRef) -> ClassRef {
if mid != self.mid {
let weak_semantics = self
.import_map
.get()
.unwrap()
.iter()
.find(|(_, v)| v.module_id == mid)
.unwrap()
.1
.semantics
.clone();
let other_semantics = weak_semantics.upgrade().unwrap();
return other_semantics.class_of(mid, t);
}
{
// I want to make sure that this borrow is dropped after this block.
let mut borrow = self.classes.borrow_mut();
@ -1194,6 +1327,7 @@ impl Semantics {
index,
declaration: field.declaration,
location: Location::Slot,
exported: false,
},
);
}
@ -1203,6 +1337,7 @@ impl Semantics {
(&*method.name).into(),
Declaration::Function {
declaration: method.declaration,
exported: false,
},
)
} else {
@ -1210,6 +1345,7 @@ impl Semantics {
(&*method.name).into(),
Declaration::Function {
declaration: method.declaration,
exported: false,
},
)
};
@ -1281,12 +1417,12 @@ impl Semantics {
.all(|(from, to)| self.can_convert(from, to))
}
(Type::Object(c_from, _), Type::Object(c_to, _)) => {
(Type::Object(m_from, c_from, _), Type::Object(m_to, c_to, _)) => {
// TODO: Structural comparisons. All that matters is that
// c_to has a subset of fields and methods, and the
// fields and methods are all compatible.
//
c_from == c_to
m_from == m_to && c_from == c_to
}
// Avoid introducing more errors
@ -1578,13 +1714,20 @@ impl Semantics {
);
return Some(Type::Error);
}
Declaration::Import { .. } => {
Declaration::ImportedModule { .. } => {
self.report_error_tree_ref(
left_tree,
"cannot assign a new value to an imported module",
);
return Some(Type::Error);
}
Declaration::ImportedDeclaration { .. } => {
self.report_error_tree_ref(
left_tree,
"cannot assign a new value to a member of an imported module",
);
return Some(Type::Error);
}
}
let _ = environment;
@ -1659,13 +1802,23 @@ impl Semantics {
);
Some(Type::Error)
}
Some(Declaration::Import { .. }) => {
Some(Declaration::ImportedModule { .. }) => {
self.report_error_tree(
tree,
format!("'{token}' is an imported module and cannot be used as a type"),
);
Some(Type::Error)
}
Some(Declaration::ImportedDeclaration {
semantics,
tree,
declaration,
}) => Some(
semantics
.upgrade()
.unwrap()
.type_of_declaration(*tree, declaration),
),
None => {
if !environment.is_error {
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
@ -1903,23 +2056,50 @@ impl Semantics {
return Some(Type::Error);
};
Some(self.type_of_declaration(t, declaration))
Some(self.type_of_declaration(Some(t), declaration))
}
pub fn member_environment(&self, t: TreeRef, typ: &Type) -> EnvironmentRef {
match &typ {
Type::Object(ct, _) => {
let class = self.class_of(*ct);
Type::Object(mid, ct, _) => {
let class = self.class_of(*mid, *ct);
class.env.clone()
}
Type::Class(ct, _) => {
let class = self.class_of(*ct);
Type::Class(mid, ct, _) => {
let class = self.class_of(*mid, *ct);
class.static_env.clone()
}
// Type::Module(_name) => {
// // Woof. Would like to bind this now.
// todo!();
// }
Type::Module(_, import) => {
// TODO: Cache this somehow, man.
let Some(other) = import.semantics.upgrade() else {
self.internal_compiler_error(Some(t), "Unable to bind module");
};
let Some(root) = other.syntax_tree.root() else {
self.internal_compiler_error(Some(t), "Other syntax tree has no root");
};
let rt = &other.syntax_tree[root];
assert_eq!(rt.kind, TreeKind::File);
let mut result = Environment::new(None, Location::Module);
let other_env = other.environment_of(root);
for (name, decl) in other_env.declarations.iter() {
if decl.is_exported() {
eprintln!("******* {} is exported!", name);
result.declarations.insert(
name.clone(),
Declaration::ImportedDeclaration {
semantics: import.semantics.clone(),
tree: decl.tree(),
declaration: Box::new(decl.clone()),
},
);
} else {
eprintln!("******* {} is NOT exported!", name);
}
}
EnvironmentRef::new(result)
}
Type::Error => return Environment::error(),
_ => {
self.report_error_tree_ref(t, format!("cannot access members of '{typ}'"));
@ -1957,7 +2137,7 @@ impl Semantics {
let id = tree.nth_token(0)?.as_str(&self.source);
let environment = self.environment_of(t);
if let Some(declaration) = environment.bind(id) {
return Some(self.type_of_declaration(t, declaration));
return Some(self.type_of_declaration(Some(t), declaration));
}
if !environment.is_error {
@ -1966,18 +2146,26 @@ impl Semantics {
Some(Type::Error)
}
fn type_of_declaration(&self, t: TreeRef, declaration: &Declaration) -> Type {
fn type_of_declaration(&self, t: Option<TreeRef>, declaration: &Declaration) -> Type {
match declaration {
Declaration::Variable { declaration, .. } => self.type_of(*declaration),
Declaration::Function { declaration, .. } => self.type_of(*declaration),
Declaration::Import { declaration, .. } => self.type_of(*declaration),
Declaration::ImportedModule { declaration, .. } => self.type_of(*declaration),
Declaration::ExternFunction {
declaration_type, ..
} => declaration_type.clone(),
Declaration::Class { declaration, .. } => match self.type_of(*declaration) {
Type::Object(cd, name) => Type::Class(cd, name.clone()),
_ => self.internal_compiler_error(Some(t), "bound to a class not understood"),
Type::Object(mid, cd, name) => Type::Class(mid, cd, name.clone()),
_ => self.internal_compiler_error(t, "bound to a class not understood"),
},
Declaration::ImportedDeclaration {
semantics,
tree,
declaration,
} => semantics
.upgrade()
.unwrap()
.type_of_declaration(*tree, declaration),
}
}
@ -2126,7 +2314,7 @@ impl Semantics {
// The details of a class are computed lazily, but this is enough of
// a belly-button.
let name = tree.nth_token(1)?;
Some(Type::Object(t, name.as_str(&self.source).into()))
Some(Type::Object(self.mid, t, name.as_str(&self.source).into()))
}
fn type_of_field_decl(&self, tree: &Tree) -> Option<Type> {
@ -2173,13 +2361,23 @@ impl Semantics {
);
Some(Type::Error)
}
Declaration::Import { .. } => {
Declaration::ImportedModule { .. } => {
self.report_error_tree(
tree,
format!("'{id}' is an imported module, and cannot be the value of a field"),
);
Some(Type::Error)
}
Declaration::ImportedDeclaration {
semantics,
tree,
declaration,
} => Some(
semantics
.upgrade()
.unwrap()
.type_of_declaration(*tree, declaration),
),
}
}
@ -2427,7 +2625,7 @@ impl Semantics {
Some(m) => {
eprintln!("Import map:");
for (k, b) in m.iter() {
eprintln!(" {k} => {} ({})", b.name, b.module_id);
eprintln!(" {k} => {} ({:?})", b.name, b.module_id);
}
eprintln!();
}
@ -2466,9 +2664,12 @@ impl Semantics {
Declaration::Class { declaration, .. } => {
eprintln!(" (class {declaration:?})");
}
Declaration::Import { declaration, .. } => {
Declaration::ImportedModule { declaration, .. } => {
eprintln!(" (imported module {declaration:?})");
}
Declaration::ImportedDeclaration { .. } => {
eprintln!(" (imported member)");
}
};
}
environment = env.parent.clone();
@ -2563,7 +2764,9 @@ pub fn check(s: &Semantics) {
}
TreeKind::Export => {}
TreeKind::ExportList => {}
TreeKind::ExportList => {
// TODO: Check that each name in the list is in the environment
}
}
}
}
@ -2686,8 +2889,9 @@ fn check_new_object_expression(s: &Semantics, tree: &Tree) {
let class_type = s.type_of(type_expression); // TODO: Should yield a ClassType not an ObjectType?
match &class_type {
Type::Object(c, _) => {
let class = s.class_of(*c);
Type::Object(mid, c, _) => {
// Get the class def from ... place.
let class = s.class_of(*mid, *c);
let mut any_errors = false;
let mut field_bindings = HashMap::new();
@ -2818,7 +3022,7 @@ mod tests {
pub fn ice() {
let source: Rc<str> = "1+1".into();
let (tree, lines) = parse(&source);
let semantics = Semantics::new("__test__".into(), source, tree.clone(), lines);
let semantics = Semantics::new(ModuleId(0), "__test__".into(), source, tree.clone(), lines);
semantics.internal_compiler_error(tree.root(), "oh no");
}
}

View file

@ -4,5 +4,5 @@ fun test() -> string {
foo.hello() + " world"
}
// @ignore WIP
// TODO: Obviously run the code duh
// @no-errors