[fine] Lookup semantics by mid

This isn't actually correct, I really need a global view to make this
right.
This commit is contained in:
John Doty 2024-03-29 06:30:02 -07:00
parent 2c03989da3
commit 4c061fbd28
2 changed files with 59 additions and 18 deletions

View file

@ -664,6 +664,12 @@ enum Incremental<T> {
Complete(T), Complete(T),
} }
#[derive(Debug)]
struct ImportMap {
by_name: HashMap<String, ImportRecord>,
by_id: HashMap<ModuleId, ImportRecord>,
}
pub struct Semantics { pub struct Semantics {
mid: ModuleId, mid: ModuleId,
file: Rc<str>, file: Rc<str>,
@ -671,7 +677,7 @@ pub struct Semantics {
syntax_tree: Rc<SyntaxTree>, syntax_tree: Rc<SyntaxTree>,
lines: Rc<Lines>, lines: Rc<Lines>,
import_map: OnceCell<HashMap<String, ImportRecord>>, import_map: OnceCell<ImportMap>,
// Instead of physical parents, this is the set of *logical* parents. // Instead of physical parents, this is the set of *logical* parents.
// This is what is used for binding. // This is what is used for binding.
@ -726,9 +732,26 @@ impl Semantics {
} }
pub fn set_imports(&self, imports: HashMap<String, ImportRecord>) { pub fn set_imports(&self, imports: HashMap<String, ImportRecord>) {
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"); self.import_map.set(imports).expect("imports already set");
} }
pub fn import_by_id(&self, mid: ModuleId) -> Option<Rc<Semantics>> {
// 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<str> { pub fn source(&self) -> Rc<str> {
self.source.clone() self.source.clone()
} }
@ -1268,18 +1291,9 @@ impl Semantics {
pub fn class_of(&self, mid: ModuleId, t: TreeRef) -> ClassRef { pub fn class_of(&self, mid: ModuleId, t: TreeRef) -> ClassRef {
if mid != self.mid { if mid != self.mid {
let weak_semantics = self let Some(other_semantics) = self.import_by_id(mid) else {
.import_map self.internal_compiler_error(Some(t), "Have a class we can't resolve");
.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); return other_semantics.class_of(mid, t);
} }
@ -2215,7 +2229,15 @@ impl Semantics {
if declaration.module == self.mid { if declaration.module == self.mid {
self.type_of(*t) self.type_of(*t)
} else { } 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 // The details of a class are computed lazily, but this is enough of
// a belly-button. // a belly-button.
let name = tree.nth_token(1)?; 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())) 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.... // 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 { let Some(import_map) = self.import_map.get() else {
self.internal_compiler_error(None, "import map not initialized"); self.internal_compiler_error(None, "import map not initialized");
}; };
let name = string_constant_to_string(tok.as_str(&self.source)); match import_map.by_name.get(&name) {
match import_map.get(&name) {
Some(import) => Some(Type::Module(name.into(), import.clone())), Some(import) => Some(Type::Module(name.into(), import.clone())),
None => { None => {
let error = let error =
@ -2669,7 +2711,7 @@ impl Semantics {
match self.import_map.get() { match self.import_map.get() {
Some(m) => { Some(m) => {
eprintln!("Import map:"); 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!(" {k} => {} ({:?})", b.name, b.module_id);
} }
eprintln!(); eprintln!();

View file

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