diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index f71f45ca..166beb8a 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -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() } _ => { diff --git a/fine/src/lib.rs b/fine/src/lib.rs index b340968e..c1235117 100644 --- a/fine/src/lib.rs +++ b/fine/src/lib.rs @@ -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, } 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 = 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)); } } } diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 16e9ce5c..578c3232 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -116,10 +116,19 @@ impl std::ops::Deref for ClassRef { } } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct ModuleId(u64); + +impl From 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, } @@ -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), + Class(ModuleId, TreeRef, Rc), // 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), + Object(ModuleId, TreeRef, Rc), // 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, + tree: Option, + declaration: Box, + }, +} + +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 { + 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 { } pub struct Semantics { + mid: ModuleId, file: Rc, source: Rc, syntax_tree: Rc, @@ -654,7 +713,13 @@ pub struct Semantics { } impl Semantics { - pub fn new(file: Rc, source: Rc, tree: Rc, lines: Rc) -> Self { + pub fn new( + mid: ModuleId, + file: Rc, + source: Rc, + tree: Rc, + lines: Rc, + ) -> 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 { - TreeKind::FunctionDecl => { - let Some(name) = ct.nth_token(1) else { - continue; - }; - if name.kind != TokenKind::Identifier { - continue; - } + let binding = { + // Redeclare t to be mutable (and a copy) + let mut t = *t; + let mut exported = false; - let declaration = Declaration::Function { declaration: *t }; - Some(("function", name, declaration)) - } - TreeKind::ClassDecl => { - let Some(name) = ct.nth_token(1) else { - continue; - }; - if name.kind != TokenKind::Identifier { - continue; - } + // 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 { + break None; + }; + if name.kind != TokenKind::Identifier { + break None; + } - let declaration = Declaration::Class { declaration: *t }; - Some(("class", name, declaration)) - } - TreeKind::Import => { - let Some(name) = ct.nth_token(3) else { - continue; - }; - if name.kind != TokenKind::Identifier { - continue; - } + let declaration = Declaration::Function { + declaration: t, + exported, + }; + break Some(("function", name, declaration)); + } + TreeKind::ClassDecl => { + let Some(name) = ct.nth_token(1) else { + break None; + }; + if name.kind != TokenKind::Identifier { + break None; + } - let declaration = Declaration::Import { declaration: *t }; - Some(("import", name, declaration)) + let declaration = Declaration::Class { + declaration: t, + exported, + }; + break Some(("class", name, declaration)); + } + TreeKind::Import => { + let Some(name) = ct.nth_token(3) else { + 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; + } + 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, 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 { @@ -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 = "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"); } } diff --git a/fine/tests/modules/import.fine b/fine/tests/modules/import.fine index b4e509cd..da98ad17 100644 --- a/fine/tests/modules/import.fine +++ b/fine/tests/modules/import.fine @@ -4,5 +4,5 @@ fun test() -> string { foo.hello() + " world" } -// @ignore WIP +// TODO: Obviously run the code duh // @no-errors