From 4c061fbd28f113b281eca011b472269c38131c11 Mon Sep 17 00:00:00 2001 From: John Doty Date: Fri, 29 Mar 2024 06:30:02 -0700 Subject: [PATCH] [fine] Lookup semantics by mid This isn't actually correct, I really need a global view to make this right. --- fine/src/semantics.rs | 76 ++++++++++++++++++++++++++-------- fine/tests/modules/import.fine | 1 - 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 98723b94..d65b85c6 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -664,6 +664,12 @@ enum Incremental { Complete(T), } +#[derive(Debug)] +struct ImportMap { + by_name: HashMap, + by_id: HashMap, +} + pub struct Semantics { mid: ModuleId, file: Rc, @@ -671,7 +677,7 @@ pub struct Semantics { syntax_tree: Rc, lines: Rc, - import_map: OnceCell>, + import_map: OnceCell, // Instead of physical parents, this is the set of *logical* parents. // This is what is used for binding. @@ -726,9 +732,26 @@ impl Semantics { } pub fn set_imports(&self, imports: HashMap) { + let mut by_id = HashMap::new(); + for (_, v) in imports.iter() { + by_id.insert(v.module_id, v.clone()); + } + let imports = ImportMap { + by_name: imports, + by_id, + }; + self.import_map.set(imports).expect("imports already set"); } + pub fn import_by_id(&self, mid: ModuleId) -> Option> { + // TODO: ACTUALLY THIS IS WRONG, WE NEED THE GLOBAL MAP HERE, NOT THE LOCAL ONE. + let import_map = self.import_map.get()?; + let record = import_map.by_id.get(&mid)?; + + record.semantics.upgrade() + } + pub fn source(&self) -> Rc { self.source.clone() } @@ -1268,18 +1291,9 @@ impl Semantics { 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(); + let Some(other_semantics) = self.import_by_id(mid) else { + self.internal_compiler_error(Some(t), "Have a class we can't resolve"); + }; return other_semantics.class_of(mid, t); } @@ -2215,7 +2229,15 @@ impl Semantics { if declaration.module == self.mid { self.type_of(*t) } else { - self.internal_compiler_error(Some(*t), "Not implemented: deref this module"); + let Some(other_semantics) = self.import_by_id(declaration.module) else { + let message = format!( + "Cannot find a module matching this decl's mid: {:?}", + declaration.module + ); + self.internal_compiler_error(Some(*t), &message); + }; + + other_semantics.type_of(*t) } } } @@ -2364,6 +2386,26 @@ impl Semantics { // The details of a class are computed lazily, but this is enough of // a belly-button. let name = tree.nth_token(1)?; + + // NOTE: There's a kind of a weird design decision here, which is to + // return an instance type instead of a class type. This is + // because it turns out to be what you want most of the time: + // variables should be object type, arguments should be object + // type, etc. + // + // There are only two places where you have to deal with this + // being weird: first, in the new object expression, and + // second, in static member access. + // + // For new object expression it turns out to not matter much, + // you just have to be aware that the type identifier is an + // object type. + // + // For the static member access, that one is just plain weird. + // But it's easier to handle converting object type -> class + // type there (in type_of_identifier) rather than flipping the + // default here and dealing with converting class type -> + // object type literally everywhere else. Some(Type::Object(self.mid, t, name.as_str(&self.source).into())) } @@ -2499,12 +2541,12 @@ impl Semantics { } // do we bind it here? it's not normalized.... + let name = string_constant_to_string(tok.as_str(&self.source)); let Some(import_map) = self.import_map.get() else { self.internal_compiler_error(None, "import map not initialized"); }; - let name = string_constant_to_string(tok.as_str(&self.source)); - match import_map.get(&name) { + match import_map.by_name.get(&name) { Some(import) => Some(Type::Module(name.into(), import.clone())), None => { let error = @@ -2669,7 +2711,7 @@ impl Semantics { match self.import_map.get() { Some(m) => { eprintln!("Import map:"); - for (k, b) in m.iter() { + for (k, b) in m.by_name.iter() { eprintln!(" {k} => {} ({:?})", b.name, b.module_id); } eprintln!(); diff --git a/fine/tests/modules/import.fine b/fine/tests/modules/import.fine index 39265c4f..da98ad17 100644 --- a/fine/tests/modules/import.fine +++ b/fine/tests/modules/import.fine @@ -4,6 +4,5 @@ fun test() -> string { foo.hello() + " world" } -// @ignore working on declaration rebuild // TODO: Obviously run the code duh // @no-errors