diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index 8600fd0b..0086b35c 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use crate::{ parser::{Child, SyntaxTree, Tree, TreeKind, TreeRef}, - semantics::{string_constant_to_string, Declaration, Location, Semantics, Type}, + semantics::{string_constant_to_string, Declaration, Location, Origin, Semantics, Type}, tokens::TokenKind, }; @@ -584,38 +584,33 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR { _ => return Err("unsupported lval expression"), }; - let instruction = match declaration { - Declaration::Variable { - location, index, .. - } => { - let index = *index; - match location { - Location::Argument => { - compiler_assert!(c, t, index < c.function.args); - Instruction::StoreArgument(index) - } - Location::Local => { - if index >= c.function.locals { - c.function.locals = index + 1; - } - Instruction::StoreLocal(index) - } - Location::Module => { - compiler_assert!(c, t, index < c.module.globals); - Instruction::StoreModule(index) - } - Location::Slot => { - compile_expression(c, ltree.nth_tree(0).ok_or("no obj lhs")?); - Instruction::StoreSlot(index) - } + // TODO: Handle storage to non-local module. + + let index = declaration.index; + let instruction = match declaration.location { + Location::Argument => { + compiler_assert!(c, t, index < c.function.args); + Instruction::StoreArgument(index) + } + Location::Local => { + if index >= c.function.locals { + c.function.locals = index + 1; } + Instruction::StoreLocal(index) + } + Location::Module => { + compiler_assert!(c, t, index < c.module.globals); + Instruction::StoreModule(index) + } + Location::Slot => { + compile_expression(c, ltree.nth_tree(0).ok_or("no obj lhs")?); + Instruction::StoreSlot(index) } - Declaration::ExternFunction { .. } => c.inst_panic("store ext"), - Declaration::Function { .. } => c.inst_panic("store func"), - Declaration::Class { .. } => c.inst_panic("store class"), - Declaration::ImportedModule { .. } => c.inst_panic("store import"), - Declaration::ImportedDeclaration { .. } => c.inst_panic("store import decl"), + Location::ExternalFunction + | Location::Function + | Location::Class + | Location::Import => c.inst_panic("store to invalid location"), }; c.push(instruction); OK @@ -638,41 +633,42 @@ fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C } fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declaration) -> CR { - let instruction = match declaration { - Declaration::Variable { - location, index, .. - } => { - let index = *index; - match location { - Location::Local => { - if index >= c.function.locals { - c.function.locals = index + 1; - } - Instruction::LoadLocal(index) - } - Location::Argument => { - compiler_assert!(c, t, index < c.function.args); - Instruction::LoadArgument(index) - } - Location::Module => { - compiler_assert!(c, t, index < c.module.globals); - Instruction::LoadModule(index) - } - Location::Slot => { - // TODO: Assert slot is in field range? - Instruction::LoadSlot(index) - } + // TODO: Handle load of non-local value. + + let index = declaration.index; + let instruction = match declaration.location { + Location::Local => { + if index >= c.function.locals { + c.function.locals = index + 1; } + Instruction::LoadLocal(index) } - Declaration::Function { declaration, .. } => { - let key = FunctionKey { tree: *declaration }; + Location::Argument => { + compiler_assert!(c, t, index < c.function.args); + Instruction::LoadArgument(index) + } + Location::Module => { + compiler_assert!(c, t, index < c.module.globals); + Instruction::LoadModule(index) + } + Location::Slot => { + // TODO: Assert slot is in field range? + Instruction::LoadSlot(index) + } + + Location::Function => { + // TODO: Assert declaration is local + let Origin::Source(ft) = declaration.origin else { + ice!(c, t, "Function location but external origin?"); + }; + let key = FunctionKey { tree: ft }; let index = match c.function_bindings.get(&key) { Some(index) => *index, None => { - let tree = &c.syntax[*declaration]; + let tree = &c.syntax[ft]; compiler_assert_eq!(c, t, tree.kind, TreeKind::FunctionDecl); - compile_function_declaration(c, *declaration, tree, false)?; + compile_function_declaration(c, ft, tree, false)?; match c.function_bindings.get(&key) { Some(index) => *index, @@ -689,14 +685,14 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat }; Instruction::LoadFunction(index) } - Declaration::ExternFunction { id, .. } => Instruction::LoadExternFunction(id.id()), + + Location::ExternalFunction => Instruction::LoadExternFunction(index), // Must be a static don't worry about it. - Declaration::Class { .. } => return OK, + Location::Class => return OK, // fix later - Declaration::ImportedModule { .. } => ice!(c, t, "import compile not supported"), - Declaration::ImportedDeclaration { .. } => ice!(c, t, "import decl not supported"), + Location::Import => ice!(c, t, "import compile not supported"), }; c.push(instruction); @@ -766,14 +762,12 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR { ice!(c, t, "cannot bind pattern variable `{id}`"); }; - let Declaration::Variable { - location: Location::Local, - index, - .. - } = declaration - else { - ice!(c, t, "is cannot make a non-local, non-variable declaration") - }; + compiler_assert!( + c, + t, + declaration.location == Location::Local, + "is cannot make a non-local, non-variable declaration" + ); // If we aren't a wildcard or we have an attached predicate then // we will need the value on the stack, otherwise we can discard @@ -781,7 +775,7 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR { if and_index.is_some() || !is_wildcard { c.push(Instruction::Dup); } - c.push(Instruction::StoreLocal(*index)); + c.push(Instruction::StoreLocal(declaration.index)); } } @@ -857,11 +851,17 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR { } _ => { let environment = c.semantics.environment_of(t); - match environment.bind(identifier).ok_or("cannot bind")? { - Declaration::Class { declaration, .. } => { - // The runtime identifier of the class is the tree index of the - // class declaration sure why not. - let index = declaration.index(); + let declaration = environment.bind(identifier).ok_or("cannot bind")?; + match declaration.location { + Location::Class => { + // TODO: Handle non-local class declaration! + + // The runtime identifier of the class is the tree index + // of the class declaration sure why not. + let Origin::Source(classdecl) = declaration.origin else { + ice!(c, t, "This class declaration doesn't have an origin"); + }; + let index = classdecl.index(); c.push(Instruction::IsClass(index.try_into().unwrap())); } @@ -985,13 +985,17 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C .ok_or("no type id")? .as_str(&c.source); let environment = c.semantics.environment_of(t); - match environment.bind(identifier).ok_or("cannot bind type")? { - Declaration::Class { declaration, .. } => { - let key = FunctionKey { tree: *declaration }; + let declaration = environment.bind(identifier).ok_or("cannot bind type")?; + match declaration.location { + Location::Class => { + let Origin::Source(classdecl) = declaration.origin else { + ice!(c, t, "this class declaration has no source?"); + }; + let key = FunctionKey { tree: classdecl }; let index = match c.function_bindings.get(&key) { Some(index) => *index, None => { - let tree = &c.syntax[*declaration]; + let tree = &c.syntax[classdecl]; compiler_assert_eq!(c, t, tree.kind, TreeKind::ClassDecl); compile_class_declaration(c, t, tree, false)?; @@ -1146,15 +1150,10 @@ fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: b .bind(tree.nth_token(1).ok_or("no id")?.as_str(&c.source)) .ok_or("cannot bind")?; - let Declaration::Variable { - location, index, .. - } = declaration - else { - ice!(c, t, "let cannot make a non-variable declaration") - }; + // TODO: ASSERT LOCAL DECLARATION? - let index = *index; - let instruction = match location { + let index = declaration.index; + let instruction = match declaration.location { Location::Local => { if index >= c.function.locals { c.function.locals = index + 1; @@ -1314,22 +1313,15 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR { let Some(variable_decl) = env.bind(id) else { ice!(c, body, "Unable to bind {id} in loop body"); }; - let variable_slot = match variable_decl { - Declaration::Variable { - location, index, .. - } => { - compiler_assert_eq!( - c, - vt, - *location, - Location::Local, - "expected loop variable to be local" - ); - *index - } - _ => ice!(c, vt, "loop variable was not a variable"), - }; + compiler_assert_eq!( + c, + vt, + variable_decl.location, + Location::Local, + "expected loop variable to be local" + ); + let variable_slot = variable_decl.index; // Figure out the generator. let iterable = tree.nth_tree(3).ok_or("no generator")?; diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 5da01e6e..98723b94 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -332,13 +332,22 @@ impl std::cmp::Ord for Type { } } +// NOTE: I tried to actually embed the coordinate inside the location but +// that doesn't work well for other things we want to express, so we +// leave it alone. A data modeling maximalist might make *two* enums +// (with and without a coordinate) but... that's a lot of complexity +// for very little gain. Maybe we can come back to it when things this +// design is a little more stable. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Location { - Argument, - Local, - Module, - Slot, - // TODO: ArrayIndex + Argument, // An argument to a function + Local, // A local in an frame + Slot, // A slot in an object + Module, // A global in a module + Function, // A function in a module (index unrelated) + ExternalFunction, // An external function (module unrelated) + Class, // A class in a module (index unrelated) + Import, // An import in a module (index unrelated) } // TODO: Is `usize` what we want? Do we want e.g. dyn trait for invoke? @@ -352,73 +361,40 @@ impl ExternalFunctionId { } #[derive(Clone, Debug)] -pub enum Declaration { - Variable { - declaration: TreeRef, - location: Location, - index: usize, - exported: bool, - }, - Function { - declaration: TreeRef, //? - exported: bool, - }, - ExternFunction { - declaration_type: Type, - id: ExternalFunctionId, - }, - Class { - declaration: TreeRef, //? - exported: bool, - }, - ImportedModule { - declaration: TreeRef, - exported: bool, - }, - ImportedDeclaration { - semantics: Weak, - tree: Option, - declaration: Box, - }, +pub enum Origin { + Source(TreeRef), + External(Type), +} + +#[derive(Clone, Debug)] +pub struct Declaration { + pub location: Location, + pub index: usize, + pub module: ModuleId, + pub origin: Origin, + pub exported: bool, } 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, - } + self.exported } 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, + match self.origin { + Origin::Source(t) => Some(t), + _ => None, } } 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 { .. } => (), - } + self.exported = true } } pub struct Environment { pub parent: Option, + pub module: ModuleId, pub location: Location, pub next_index: usize, pub declarations: HashMap, Declaration>, @@ -426,7 +402,7 @@ pub struct Environment { } impl Environment { - pub fn new(parent: Option, location: Location) -> Self { + pub fn new(module: ModuleId, parent: Option, location: Location) -> Self { let parent_location = parent .as_ref() .map(|p| p.location) @@ -440,11 +416,12 @@ impl Environment { (_, Location::Local) => 0, (Location::Module, Location::Module) => base, - (_, Location::Module) => panic!("What?"), + _ => panic!("{location:?} is not suitable as a default location"), }; Environment { parent, + module, location, next_index, declarations: HashMap::new(), @@ -457,9 +434,9 @@ impl Environment { } pub fn error(why: Rc) -> EnvironmentRef { - // TODO: Exactly once? EnvironmentRef::new(Environment { parent: None, + module: ModuleId(0), location: Location::Local, next_index: 0, declarations: HashMap::new(), @@ -474,10 +451,11 @@ impl Environment { pub fn insert_name(&mut self, name: Box, t: TreeRef) -> Option { let result = self.declarations.insert( name, - Declaration::Variable { - declaration: t, + Declaration { location: self.location, index: self.next_index, + module: self.module, + origin: Origin::Source(t), exported: false, }, ); @@ -720,7 +698,7 @@ impl Semantics { set_logical_parents(&mut logical_parents, &tree, root, None); } - let root_environment = Environment::new(None, Location::Module); + let root_environment = Environment::new(mid, None, Location::Module); let mut semantics = Semantics { mid, @@ -937,7 +915,7 @@ impl Semantics { } fn environment_of_block(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { - let mut environment = Environment::new(Some(parent), Location::Local); + let mut environment = Environment::new(self.mid, Some(parent), Location::Local); for child in tree.children.iter() { match child { Child::Tree(t) => { @@ -949,8 +927,11 @@ impl Semantics { let existing = environment.declarations.insert( name.as_str(&self.source).into(), - Declaration::Function { - declaration: *t, + Declaration { + location: Location::Function, + index: 0, + module: self.mid, + origin: Origin::Source(*t), exported: false, }, ); @@ -973,7 +954,7 @@ impl Semantics { } fn environment_of_file(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { - let mut environment = Environment::new(Some(parent), Location::Module); + let mut environment = Environment::new(self.mid, Some(parent), Location::Module); let mut explicit_exports = Vec::new(); @@ -1001,8 +982,11 @@ impl Semantics { break None; } - let declaration = Declaration::Function { - declaration: t, + let declaration = Declaration { + location: Location::Function, + index: 0, + module: self.mid, + origin: Origin::Source(t), exported, }; break Some(("function", name, declaration)); @@ -1015,8 +999,11 @@ impl Semantics { break None; } - let declaration = Declaration::Class { - declaration: t, + let declaration = Declaration { + location: Location::Class, + index: 0, + module: self.mid, + origin: Origin::Source(t), exported, }; break Some(("class", name, declaration)); @@ -1029,8 +1016,11 @@ impl Semantics { break None; } - let declaration = Declaration::ImportedModule { - declaration: t, + let declaration = Declaration { + location: Location::Import, + index: 0, + module: self.mid, + origin: Origin::Source(t), exported, }; break Some(("import", name, declaration)); @@ -1087,23 +1077,28 @@ impl Semantics { fn environment_of_let(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { let Some(name) = tree.nth_token(1) else { - return parent; // Error is already reported? + return parent; // Error is already reported, don't clobber parent bindings. }; let Some(declaration) = tree.nth_tree(3) else { - return parent; + return parent; // Error is already reported, don't clobber parent bindings. }; - // eprintln!("{} => {}", name, declaration_type); - let location = match parent.location { Location::Local => Location::Local, Location::Module => Location::Module, Location::Argument => Location::Local, Location::Slot => Location::Local, + _ => { + let message = format!( + "Unsuitable environment location for a let: {:?}", + parent.location + ); + self.internal_compiler_error(Some(tree.self_ref), &message); + } }; - let mut environment = Environment::new(Some(parent), location); + let mut environment = Environment::new(self.mid, Some(parent), location); environment.insert(name.as_str(&self.source), declaration); EnvironmentRef::new(environment) @@ -1112,7 +1107,7 @@ impl Semantics { fn environment_of_paramlist(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { assert!(tree.kind == TreeKind::ParamList); - let mut environment = Environment::new(Some(parent), Location::Argument); + let mut environment = Environment::new(self.mid, Some(parent), Location::Argument); for (i, child) in tree.children.iter().enumerate() { let Child::Tree(ct) = child else { continue; @@ -1132,7 +1127,7 @@ impl Semantics { } else if i != 1 { self.report_error_tree( param, - "self parameter must be the first parameter in the list", + "self parameter must be the first parameter} in the list", ); } } @@ -1166,7 +1161,7 @@ impl Semantics { return parent; }; - let mut environment = Environment::new(Some(parent), Location::Local); + let mut environment = Environment::new(self.mid, Some(parent), Location::Local); environment.insert(id.as_str(&self.source), it); EnvironmentRef::new(environment) } @@ -1266,7 +1261,7 @@ impl Semantics { // TODO: This binding should be un-assignable! Don't assign to this! - let mut env = Environment::new(Some(parent), Location::Local); + let mut env = Environment::new(self.mid, Some(parent), Location::Local); env.insert(variable.as_str(&self.source), variable_decl); EnvironmentRef::new(env) } @@ -1359,37 +1354,37 @@ impl Semantics { } // Build into an environment - let mut env = Environment::new(None, Location::Slot); - let mut static_env = Environment::new(None, Location::Slot); + let mut env = Environment::new(self.mid, None, Location::Slot); + let mut static_env = Environment::new(self.mid, None, Location::Slot); for (index, field) in fields.iter().enumerate() { env.declarations.insert( (&*field.name).into(), - Declaration::Variable { - index, - declaration: field.declaration, + Declaration { location: Location::Slot, + index, + module: self.mid, + origin: Origin::Source(field.declaration), exported: false, }, ); } for method in methods.iter() { - let existing = if method.is_static { - static_env.declarations.insert( - (&*method.name).into(), - Declaration::Function { - declaration: method.declaration, - exported: false, - }, - ) + let target = if method.is_static { + &mut static_env.declarations } else { - env.declarations.insert( - (&*method.name).into(), - Declaration::Function { - declaration: method.declaration, - exported: false, - }, - ) + &mut env.declarations }; + + let existing = target.insert( + (&*method.name).into(), + Declaration { + location: Location::Function, + index: 0, + module: self.mid, + origin: Origin::Source(method.declaration), + exported: false, + }, + ); if existing.is_some() { self.report_error_tree_ref( method.declaration, @@ -1545,7 +1540,7 @@ impl Semantics { TreeKind::MatchArm => self.type_of_match_arm(tree), TreeKind::MatchBody => self.type_of_match_body(tree), TreeKind::MatchExpression => self.type_of_match_expression(tree), - TreeKind::MemberAccess => self.type_of_member_access(t, tree), + TreeKind::MemberAccess => self.type_of_member_access(tree), TreeKind::NewObjectExpression => self.type_of_new_object_expression(tree), TreeKind::Parameter => self.type_of_parameter(tree), TreeKind::Pattern => self.type_of_pattern(tree), @@ -1745,36 +1740,29 @@ impl Semantics { } }; - match declaration { - Declaration::Variable { .. } => (), - Declaration::ExternFunction { .. } | Declaration::Function { .. } => { + match declaration.location { + Location::Argument | Location::Slot | Location::Local | Location::Module => (), + Location::ExternalFunction | Location::Function => { let error = self.report_error_tree_ref( left_tree, "cannot assign a new value to a function declaration", ); return Some(Type::Error(error)); } - Declaration::Class { .. } => { + Location::Class => { let error = self.report_error_tree_ref( left_tree, "cannot assign a new value to a class declaration", ); return Some(Type::Error(error)); } - Declaration::ImportedModule { .. } => { + Location::Import => { let error = self.report_error_tree_ref( left_tree, "cannot assign a new value to an imported module", ); return Some(Type::Error(error)); } - Declaration::ImportedDeclaration { .. } => { - let error = self.report_error_tree_ref( - left_tree, - "cannot assign a new value to a member of an imported module", - ); - return Some(Type::Error(error)); - } } let _ = environment; @@ -1834,40 +1822,39 @@ impl Semantics { _ => { let environment = self.environment_of(t); match environment.bind(token) { - Some(Declaration::Class { declaration, .. }) => { - Some(self.type_of(*declaration)) + Some(declaration) => { + match declaration.location { + Location::Class => Some(self.type_of_declaration(declaration)), + + Location::Argument + | Location::Slot + | Location::Local + | Location::Module => { + let error = self.report_error_tree( + tree, + format!("'{token}' is a variable and cannot be used as a type"), + ); + Some(Type::Error(error)) + } + + Location::Function | Location::ExternalFunction => { + let error = self.report_error_tree( + tree, + format!("'{token}' is a function and cannot be used as a type"), + ); + Some(Type::Error(error)) + } + + Location::Import => { + let error = self.report_error_tree( + tree, + format!("'{token}' is an imported module and cannot be used as a type"), + ); + Some(Type::Error(error)) + } + } } - Some(Declaration::Variable { .. }) => { - let error = self.report_error_tree( - tree, - format!("'{token}' is a variable and cannot be used as a type"), - ); - Some(Type::Error(error)) - } - Some(Declaration::Function { .. } | Declaration::ExternFunction { .. }) => { - let error = self.report_error_tree( - tree, - format!("'{token}' is a function and cannot be used as a type"), - ); - Some(Type::Error(error)) - } - Some(Declaration::ImportedModule { .. }) => { - let error = self.report_error_tree( - tree, - format!("'{token}' is an imported module and cannot be used as a type"), - ); - Some(Type::Error(error)) - } - Some(Declaration::ImportedDeclaration { - semantics, - tree, - declaration, - }) => Some( - semantics - .upgrade() - .unwrap() - .type_of_declaration(*tree, declaration), - ), + None => { let error = if let Some(e) = &environment.error { e.clone() @@ -2096,7 +2083,7 @@ impl Semantics { Some(result) } - fn type_of_member_access(&self, t: TreeRef, tree: &Tree) -> Option { + fn type_of_member_access(&self, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::MemberAccess); let lhs = tree.nth_tree(0)?; @@ -2121,7 +2108,7 @@ impl Semantics { return Some(Type::Error(error)); }; - Some(self.type_of_declaration(Some(t), declaration)) + Some(self.type_of_declaration(declaration)) } pub fn member_environment(&self, t: TreeRef, typ: &Type) -> EnvironmentRef { @@ -2146,21 +2133,11 @@ impl Semantics { let rt = &other.syntax_tree[root]; assert_eq!(rt.kind, TreeKind::File); - let mut result = Environment::new(None, Location::Module); + let mut result = Environment::new(self.mid, 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); + result.declarations.insert(name.clone(), decl.clone()); } } EnvironmentRef::new(result) @@ -2203,7 +2180,24 @@ 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(Some(t), declaration)); + let typ = self.type_of_declaration(declaration); + + // The one weirdsy here is that if this is an identifier that refers + // directly to a class then this should be a *class* type not an + // *object* type. + let typ = if declaration.location == Location::Class { + match typ { + Type::Object(m, t, n) => Type::Class(m, t, n), + _ => self.internal_compiler_error( + Some(t), + "This class declaration did not yield type object!", + ), + } + } else { + typ + }; + + return Some(typ); } let error = if let Some(e) = &environment.error { @@ -2214,26 +2208,16 @@ impl Semantics { Some(Type::Error(error)) } - 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::ImportedModule { declaration, .. } => self.type_of(*declaration), - Declaration::ExternFunction { - declaration_type, .. - } => declaration_type.clone(), - Declaration::Class { declaration, .. } => match self.type_of(*declaration) { - 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), + fn type_of_declaration(&self, declaration: &Declaration) -> Type { + match &declaration.origin { + Origin::External(t) => t.clone(), + Origin::Source(t) => { + if declaration.module == self.mid { + self.type_of(*t) + } else { + self.internal_compiler_error(Some(*t), "Not implemented: deref this module"); + } + } } } @@ -2261,13 +2245,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(match declaration { - Declaration::Variable { declaration, .. } => self.type_of(*declaration), - _ => self.internal_compiler_error( - Some(t), - "how did I bind something other than a variable to self?", - ), - }); + return Some(self.type_of_declaration(declaration)); } let error = if let Some(e) = &environment.error { @@ -2420,38 +2398,28 @@ impl Semantics { return Some(Type::Error(error)); } }; - match declaration { - Declaration::Variable { declaration, .. } - | Declaration::Function { declaration, .. } => Some(self.type_of(*declaration)), + match declaration.location { + Location::Argument + | Location::Slot + | Location::Local + | Location::Module + | Location::Function + | Location::ExternalFunction => Some(self.type_of_declaration(declaration)), - Declaration::ExternFunction { - declaration_type, .. - } => Some(declaration_type.clone()), - - Declaration::Class { .. } => { + Location::Class => { let error = self.report_error_tree( tree, format!("'{id}' is a class, and cannot be the value of a field"), ); Some(Type::Error(error)) } - Declaration::ImportedModule { .. } => { + Location::Import => { let error = self.report_error_tree( tree, format!("'{id}' is an imported module, and cannot be the value of a field"), ); Some(Type::Error(error)) } - Declaration::ImportedDeclaration { - semantics, - tree, - declaration, - } => Some( - semantics - .upgrade() - .unwrap() - .type_of_declaration(*tree, declaration), - ), } } @@ -2676,6 +2644,7 @@ impl Semantics { } pub fn dump_compiler_state(&self, tr: Option) { + eprintln!("Module: {:?}", self.mid); eprintln!("Parsed the tree as:"); eprintln!("\n{}", self.syntax_tree.dump(&self.source, true)); @@ -2727,29 +2696,10 @@ impl Semantics { eprint!(" *** ERROR: {error}"); } for (k, v) in env.declarations.iter() { - eprint!(" {k}: "); - match v { - Declaration::Variable { - location, index, .. - } => { - eprintln!("(variable {location:?} {index})"); - } - Declaration::Function { declaration, .. } => { - eprintln!(" (function {declaration:?})"); - } - Declaration::ExternFunction { id, .. } => { - eprintln!(" (extern {id:?})"); - } - Declaration::Class { declaration, .. } => { - eprintln!(" (class {declaration:?})"); - } - Declaration::ImportedModule { declaration, .. } => { - eprintln!(" (imported module {declaration:?})"); - } - Declaration::ImportedDeclaration { .. } => { - eprintln!(" (imported member)"); - } - }; + eprintln!( + " {k}: {:?} {} ({:?} {:?})", + v.location, v.index, v.module, v.origin + ); } environment = env.parent.clone(); } diff --git a/fine/tests/modules/import.fine b/fine/tests/modules/import.fine index da98ad17..39265c4f 100644 --- a/fine/tests/modules/import.fine +++ b/fine/tests/modules/import.fine @@ -4,5 +4,6 @@ fun test() -> string { foo.hello() + " world" } +// @ignore working on declaration rebuild // TODO: Obviously run the code duh // @no-errors