[fine] Working on rebuilding declarations

Running into walls dealing with imported declarations, thinking maybe
this structure will help me.
This commit is contained in:
John Doty 2024-03-28 16:56:42 -07:00
parent f3a8203be3
commit 2c03989da3
3 changed files with 277 additions and 334 deletions

View file

@ -3,7 +3,7 @@ use std::rc::Rc;
use crate::{ use crate::{
parser::{Child, SyntaxTree, Tree, TreeKind, TreeRef}, 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, tokens::TokenKind,
}; };
@ -584,38 +584,33 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
_ => return Err("unsupported lval expression"), _ => return Err("unsupported lval expression"),
}; };
let instruction = match declaration { // TODO: Handle storage to non-local module.
Declaration::Variable {
location, index, .. let index = declaration.index;
} => { let instruction = match declaration.location {
let index = *index; Location::Argument => {
match location { compiler_assert!(c, t, index < c.function.args);
Location::Argument => { Instruction::StoreArgument(index)
compiler_assert!(c, t, index < c.function.args); }
Instruction::StoreArgument(index) Location::Local => {
} if index >= c.function.locals {
Location::Local => { c.function.locals = index + 1;
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)
}
} }
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"), Location::ExternalFunction
Declaration::Function { .. } => c.inst_panic("store func"), | Location::Function
Declaration::Class { .. } => c.inst_panic("store class"), | Location::Class
Declaration::ImportedModule { .. } => c.inst_panic("store import"), | Location::Import => c.inst_panic("store to invalid location"),
Declaration::ImportedDeclaration { .. } => c.inst_panic("store import decl"),
}; };
c.push(instruction); c.push(instruction);
OK 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 { fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declaration) -> CR {
let instruction = match declaration { // TODO: Handle load of non-local value.
Declaration::Variable {
location, index, .. let index = declaration.index;
} => { let instruction = match declaration.location {
let index = *index; Location::Local => {
match location { if index >= c.function.locals {
Location::Local => { c.function.locals = index + 1;
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)
}
} }
Instruction::LoadLocal(index)
} }
Declaration::Function { declaration, .. } => { Location::Argument => {
let key = FunctionKey { tree: *declaration }; 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) { let index = match c.function_bindings.get(&key) {
Some(index) => *index, Some(index) => *index,
None => { None => {
let tree = &c.syntax[*declaration]; let tree = &c.syntax[ft];
compiler_assert_eq!(c, t, tree.kind, TreeKind::FunctionDecl); 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) { match c.function_bindings.get(&key) {
Some(index) => *index, Some(index) => *index,
@ -689,14 +685,14 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
}; };
Instruction::LoadFunction(index) Instruction::LoadFunction(index)
} }
Declaration::ExternFunction { id, .. } => Instruction::LoadExternFunction(id.id()),
Location::ExternalFunction => Instruction::LoadExternFunction(index),
// Must be a static don't worry about it. // Must be a static don't worry about it.
Declaration::Class { .. } => return OK, Location::Class => return OK,
// fix later // fix later
Declaration::ImportedModule { .. } => ice!(c, t, "import compile not supported"), Location::Import => ice!(c, t, "import compile not supported"),
Declaration::ImportedDeclaration { .. } => ice!(c, t, "import decl not supported"),
}; };
c.push(instruction); c.push(instruction);
@ -766,14 +762,12 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR {
ice!(c, t, "cannot bind pattern variable `{id}`"); ice!(c, t, "cannot bind pattern variable `{id}`");
}; };
let Declaration::Variable { compiler_assert!(
location: Location::Local, c,
index, t,
.. declaration.location == Location::Local,
} = declaration "is cannot make a non-local, non-variable declaration"
else { );
ice!(c, t, "is cannot make a non-local, non-variable declaration")
};
// If we aren't a wildcard or we have an attached predicate then // 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 // 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 { if and_index.is_some() || !is_wildcard {
c.push(Instruction::Dup); 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); let environment = c.semantics.environment_of(t);
match environment.bind(identifier).ok_or("cannot bind")? { let declaration = environment.bind(identifier).ok_or("cannot bind")?;
Declaration::Class { declaration, .. } => { match declaration.location {
// The runtime identifier of the class is the tree index of the Location::Class => {
// class declaration sure why not. // TODO: Handle non-local class declaration!
let index = declaration.index();
// 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())); 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")? .ok_or("no type id")?
.as_str(&c.source); .as_str(&c.source);
let environment = c.semantics.environment_of(t); let environment = c.semantics.environment_of(t);
match environment.bind(identifier).ok_or("cannot bind type")? { let declaration = environment.bind(identifier).ok_or("cannot bind type")?;
Declaration::Class { declaration, .. } => { match declaration.location {
let key = FunctionKey { tree: *declaration }; 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) { let index = match c.function_bindings.get(&key) {
Some(index) => *index, Some(index) => *index,
None => { None => {
let tree = &c.syntax[*declaration]; let tree = &c.syntax[classdecl];
compiler_assert_eq!(c, t, tree.kind, TreeKind::ClassDecl); compiler_assert_eq!(c, t, tree.kind, TreeKind::ClassDecl);
compile_class_declaration(c, t, tree, false)?; 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)) .bind(tree.nth_token(1).ok_or("no id")?.as_str(&c.source))
.ok_or("cannot bind")?; .ok_or("cannot bind")?;
let Declaration::Variable { // TODO: ASSERT LOCAL DECLARATION?
location, index, ..
} = declaration
else {
ice!(c, t, "let cannot make a non-variable declaration")
};
let index = *index; let index = declaration.index;
let instruction = match location { let instruction = match declaration.location {
Location::Local => { Location::Local => {
if index >= c.function.locals { if index >= c.function.locals {
c.function.locals = index + 1; 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 { let Some(variable_decl) = env.bind(id) else {
ice!(c, body, "Unable to bind {id} in loop body"); 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 compiler_assert_eq!(
} c,
_ => ice!(c, vt, "loop variable was not a variable"), vt,
}; variable_decl.location,
Location::Local,
"expected loop variable to be local"
);
let variable_slot = variable_decl.index;
// Figure out the generator. // Figure out the generator.
let iterable = tree.nth_tree(3).ok_or("no generator")?; let iterable = tree.nth_tree(3).ok_or("no generator")?;

View file

@ -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)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Location { pub enum Location {
Argument, Argument, // An argument to a function
Local, Local, // A local in an frame
Module, Slot, // A slot in an object
Slot, Module, // A global in a module
// TODO: ArrayIndex 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? // TODO: Is `usize` what we want? Do we want e.g. dyn trait for invoke?
@ -352,73 +361,40 @@ impl ExternalFunctionId {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Declaration { pub enum Origin {
Variable { Source(TreeRef),
declaration: TreeRef, External(Type),
location: Location, }
index: usize,
exported: bool, #[derive(Clone, Debug)]
}, pub struct Declaration {
Function { pub location: Location,
declaration: TreeRef, //? pub index: usize,
exported: bool, pub module: ModuleId,
}, pub origin: Origin,
ExternFunction { pub exported: bool,
declaration_type: Type,
id: ExternalFunctionId,
},
Class {
declaration: TreeRef, //?
exported: bool,
},
ImportedModule {
declaration: TreeRef,
exported: bool,
},
ImportedDeclaration {
semantics: Weak<Semantics>,
tree: Option<TreeRef>,
declaration: Box<Declaration>,
},
} }
impl Declaration { impl Declaration {
pub fn is_exported(&self) -> bool { pub fn is_exported(&self) -> bool {
match self { self.exported
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> { pub fn tree(&self) -> Option<TreeRef> {
match self { match self.origin {
Declaration::Variable { declaration, .. } => Some(*declaration), Origin::Source(t) => Some(t),
Declaration::Function { declaration, .. } => Some(*declaration), _ => None,
Declaration::ExternFunction { .. } => None,
Declaration::Class { declaration, .. } => Some(*declaration),
Declaration::ImportedModule { declaration, .. } => Some(*declaration),
Declaration::ImportedDeclaration { tree, .. } => *tree,
} }
} }
pub fn set_exported(&mut self) { pub fn set_exported(&mut self) {
match self { self.exported = true
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 { pub struct Environment {
pub parent: Option<EnvironmentRef>, pub parent: Option<EnvironmentRef>,
pub module: ModuleId,
pub location: Location, pub location: Location,
pub next_index: usize, pub next_index: usize,
pub declarations: HashMap<Box<str>, Declaration>, pub declarations: HashMap<Box<str>, Declaration>,
@ -426,7 +402,7 @@ pub struct Environment {
} }
impl Environment { impl Environment {
pub fn new(parent: Option<EnvironmentRef>, location: Location) -> Self { pub fn new(module: ModuleId, parent: Option<EnvironmentRef>, location: Location) -> Self {
let parent_location = parent let parent_location = parent
.as_ref() .as_ref()
.map(|p| p.location) .map(|p| p.location)
@ -440,11 +416,12 @@ impl Environment {
(_, Location::Local) => 0, (_, Location::Local) => 0,
(Location::Module, Location::Module) => base, (Location::Module, Location::Module) => base,
(_, Location::Module) => panic!("What?"), _ => panic!("{location:?} is not suitable as a default location"),
}; };
Environment { Environment {
parent, parent,
module,
location, location,
next_index, next_index,
declarations: HashMap::new(), declarations: HashMap::new(),
@ -457,9 +434,9 @@ impl Environment {
} }
pub fn error(why: Rc<Error>) -> EnvironmentRef { pub fn error(why: Rc<Error>) -> EnvironmentRef {
// TODO: Exactly once?
EnvironmentRef::new(Environment { EnvironmentRef::new(Environment {
parent: None, parent: None,
module: ModuleId(0),
location: Location::Local, location: Location::Local,
next_index: 0, next_index: 0,
declarations: HashMap::new(), declarations: HashMap::new(),
@ -474,10 +451,11 @@ impl Environment {
pub fn insert_name(&mut self, name: Box<str>, t: TreeRef) -> Option<Declaration> { pub fn insert_name(&mut self, name: Box<str>, t: TreeRef) -> Option<Declaration> {
let result = self.declarations.insert( let result = self.declarations.insert(
name, name,
Declaration::Variable { Declaration {
declaration: t,
location: self.location, location: self.location,
index: self.next_index, index: self.next_index,
module: self.module,
origin: Origin::Source(t),
exported: false, exported: false,
}, },
); );
@ -720,7 +698,7 @@ impl Semantics {
set_logical_parents(&mut logical_parents, &tree, root, None); 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 { let mut semantics = Semantics {
mid, mid,
@ -937,7 +915,7 @@ impl Semantics {
} }
fn environment_of_block(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { 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() { for child in tree.children.iter() {
match child { match child {
Child::Tree(t) => { Child::Tree(t) => {
@ -949,8 +927,11 @@ impl Semantics {
let existing = environment.declarations.insert( let existing = environment.declarations.insert(
name.as_str(&self.source).into(), name.as_str(&self.source).into(),
Declaration::Function { Declaration {
declaration: *t, location: Location::Function,
index: 0,
module: self.mid,
origin: Origin::Source(*t),
exported: false, exported: false,
}, },
); );
@ -973,7 +954,7 @@ impl Semantics {
} }
fn environment_of_file(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { 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(); let mut explicit_exports = Vec::new();
@ -1001,8 +982,11 @@ impl Semantics {
break None; break None;
} }
let declaration = Declaration::Function { let declaration = Declaration {
declaration: t, location: Location::Function,
index: 0,
module: self.mid,
origin: Origin::Source(t),
exported, exported,
}; };
break Some(("function", name, declaration)); break Some(("function", name, declaration));
@ -1015,8 +999,11 @@ impl Semantics {
break None; break None;
} }
let declaration = Declaration::Class { let declaration = Declaration {
declaration: t, location: Location::Class,
index: 0,
module: self.mid,
origin: Origin::Source(t),
exported, exported,
}; };
break Some(("class", name, declaration)); break Some(("class", name, declaration));
@ -1029,8 +1016,11 @@ impl Semantics {
break None; break None;
} }
let declaration = Declaration::ImportedModule { let declaration = Declaration {
declaration: t, location: Location::Import,
index: 0,
module: self.mid,
origin: Origin::Source(t),
exported, exported,
}; };
break Some(("import", name, declaration)); break Some(("import", name, declaration));
@ -1087,23 +1077,28 @@ impl Semantics {
fn environment_of_let(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { fn environment_of_let(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
let Some(name) = tree.nth_token(1) else { 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 { 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 { let location = match parent.location {
Location::Local => Location::Local, Location::Local => Location::Local,
Location::Module => Location::Module, Location::Module => Location::Module,
Location::Argument => Location::Local, Location::Argument => Location::Local,
Location::Slot => 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); environment.insert(name.as_str(&self.source), declaration);
EnvironmentRef::new(environment) EnvironmentRef::new(environment)
@ -1112,7 +1107,7 @@ impl Semantics {
fn environment_of_paramlist(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { fn environment_of_paramlist(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
assert!(tree.kind == TreeKind::ParamList); 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() { for (i, child) in tree.children.iter().enumerate() {
let Child::Tree(ct) = child else { let Child::Tree(ct) = child else {
continue; continue;
@ -1132,7 +1127,7 @@ impl Semantics {
} else if i != 1 { } else if i != 1 {
self.report_error_tree( self.report_error_tree(
param, 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; 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); environment.insert(id.as_str(&self.source), it);
EnvironmentRef::new(environment) EnvironmentRef::new(environment)
} }
@ -1266,7 +1261,7 @@ impl Semantics {
// TODO: This binding should be un-assignable! Don't assign to this! // 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); env.insert(variable.as_str(&self.source), variable_decl);
EnvironmentRef::new(env) EnvironmentRef::new(env)
} }
@ -1359,37 +1354,37 @@ impl Semantics {
} }
// Build into an environment // Build into an environment
let mut env = Environment::new(None, Location::Slot); let mut env = Environment::new(self.mid, None, Location::Slot);
let mut static_env = Environment::new(None, Location::Slot); let mut static_env = Environment::new(self.mid, None, Location::Slot);
for (index, field) in fields.iter().enumerate() { for (index, field) in fields.iter().enumerate() {
env.declarations.insert( env.declarations.insert(
(&*field.name).into(), (&*field.name).into(),
Declaration::Variable { Declaration {
index,
declaration: field.declaration,
location: Location::Slot, location: Location::Slot,
index,
module: self.mid,
origin: Origin::Source(field.declaration),
exported: false, exported: false,
}, },
); );
} }
for method in methods.iter() { for method in methods.iter() {
let existing = if method.is_static { let target = if method.is_static {
static_env.declarations.insert( &mut static_env.declarations
(&*method.name).into(),
Declaration::Function {
declaration: method.declaration,
exported: false,
},
)
} else { } else {
env.declarations.insert( &mut env.declarations
(&*method.name).into(),
Declaration::Function {
declaration: method.declaration,
exported: false,
},
)
}; };
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() { if existing.is_some() {
self.report_error_tree_ref( self.report_error_tree_ref(
method.declaration, method.declaration,
@ -1545,7 +1540,7 @@ impl Semantics {
TreeKind::MatchArm => self.type_of_match_arm(tree), TreeKind::MatchArm => self.type_of_match_arm(tree),
TreeKind::MatchBody => self.type_of_match_body(tree), TreeKind::MatchBody => self.type_of_match_body(tree),
TreeKind::MatchExpression => self.type_of_match_expression(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::NewObjectExpression => self.type_of_new_object_expression(tree),
TreeKind::Parameter => self.type_of_parameter(tree), TreeKind::Parameter => self.type_of_parameter(tree),
TreeKind::Pattern => self.type_of_pattern(tree), TreeKind::Pattern => self.type_of_pattern(tree),
@ -1745,36 +1740,29 @@ impl Semantics {
} }
}; };
match declaration { match declaration.location {
Declaration::Variable { .. } => (), Location::Argument | Location::Slot | Location::Local | Location::Module => (),
Declaration::ExternFunction { .. } | Declaration::Function { .. } => { Location::ExternalFunction | Location::Function => {
let error = self.report_error_tree_ref( let error = self.report_error_tree_ref(
left_tree, left_tree,
"cannot assign a new value to a function declaration", "cannot assign a new value to a function declaration",
); );
return Some(Type::Error(error)); return Some(Type::Error(error));
} }
Declaration::Class { .. } => { Location::Class => {
let error = self.report_error_tree_ref( let error = self.report_error_tree_ref(
left_tree, left_tree,
"cannot assign a new value to a class declaration", "cannot assign a new value to a class declaration",
); );
return Some(Type::Error(error)); return Some(Type::Error(error));
} }
Declaration::ImportedModule { .. } => { Location::Import => {
let error = self.report_error_tree_ref( let error = self.report_error_tree_ref(
left_tree, left_tree,
"cannot assign a new value to an imported module", "cannot assign a new value to an imported module",
); );
return Some(Type::Error(error)); 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; let _ = environment;
@ -1834,40 +1822,39 @@ impl Semantics {
_ => { _ => {
let environment = self.environment_of(t); let environment = self.environment_of(t);
match environment.bind(token) { match environment.bind(token) {
Some(Declaration::Class { declaration, .. }) => { Some(declaration) => {
Some(self.type_of(*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 => { None => {
let error = if let Some(e) = &environment.error { let error = if let Some(e) = &environment.error {
e.clone() e.clone()
@ -2096,7 +2083,7 @@ impl Semantics {
Some(result) Some(result)
} }
fn type_of_member_access(&self, t: TreeRef, tree: &Tree) -> Option<Type> { fn type_of_member_access(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::MemberAccess); assert_eq!(tree.kind, TreeKind::MemberAccess);
let lhs = tree.nth_tree(0)?; let lhs = tree.nth_tree(0)?;
@ -2121,7 +2108,7 @@ impl Semantics {
return Some(Type::Error(error)); 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 { pub fn member_environment(&self, t: TreeRef, typ: &Type) -> EnvironmentRef {
@ -2146,21 +2133,11 @@ impl Semantics {
let rt = &other.syntax_tree[root]; let rt = &other.syntax_tree[root];
assert_eq!(rt.kind, TreeKind::File); 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); let other_env = other.environment_of(root);
for (name, decl) in other_env.declarations.iter() { for (name, decl) in other_env.declarations.iter() {
if decl.is_exported() { if decl.is_exported() {
// eprintln!("******* {} is exported!", name); result.declarations.insert(name.clone(), decl.clone());
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) EnvironmentRef::new(result)
@ -2203,7 +2180,24 @@ impl Semantics {
let id = tree.nth_token(0)?.as_str(&self.source); let id = tree.nth_token(0)?.as_str(&self.source);
let environment = self.environment_of(t); let environment = self.environment_of(t);
if let Some(declaration) = environment.bind(id) { 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 { let error = if let Some(e) = &environment.error {
@ -2214,26 +2208,16 @@ impl Semantics {
Some(Type::Error(error)) Some(Type::Error(error))
} }
fn type_of_declaration(&self, t: Option<TreeRef>, declaration: &Declaration) -> Type { fn type_of_declaration(&self, declaration: &Declaration) -> Type {
match declaration { match &declaration.origin {
Declaration::Variable { declaration, .. } => self.type_of(*declaration), Origin::External(t) => t.clone(),
Declaration::Function { declaration, .. } => self.type_of(*declaration), Origin::Source(t) => {
Declaration::ImportedModule { declaration, .. } => self.type_of(*declaration), if declaration.module == self.mid {
Declaration::ExternFunction { self.type_of(*t)
declaration_type, .. } else {
} => declaration_type.clone(), self.internal_compiler_error(Some(*t), "Not implemented: deref this module");
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),
} }
} }
@ -2261,13 +2245,7 @@ impl Semantics {
let id = tree.nth_token(0)?.as_str(&self.source); let id = tree.nth_token(0)?.as_str(&self.source);
let environment = self.environment_of(t); let environment = self.environment_of(t);
if let Some(declaration) = environment.bind(id) { if let Some(declaration) = environment.bind(id) {
return Some(match declaration { return Some(self.type_of_declaration(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?",
),
});
} }
let error = if let Some(e) = &environment.error { let error = if let Some(e) = &environment.error {
@ -2420,38 +2398,28 @@ impl Semantics {
return Some(Type::Error(error)); return Some(Type::Error(error));
} }
}; };
match declaration { match declaration.location {
Declaration::Variable { declaration, .. } Location::Argument
| Declaration::Function { declaration, .. } => Some(self.type_of(*declaration)), | Location::Slot
| Location::Local
| Location::Module
| Location::Function
| Location::ExternalFunction => Some(self.type_of_declaration(declaration)),
Declaration::ExternFunction { Location::Class => {
declaration_type, ..
} => Some(declaration_type.clone()),
Declaration::Class { .. } => {
let error = self.report_error_tree( let error = self.report_error_tree(
tree, tree,
format!("'{id}' is a class, and cannot be the value of a field"), format!("'{id}' is a class, and cannot be the value of a field"),
); );
Some(Type::Error(error)) Some(Type::Error(error))
} }
Declaration::ImportedModule { .. } => { Location::Import => {
let error = self.report_error_tree( let error = self.report_error_tree(
tree, tree,
format!("'{id}' is an imported module, and cannot be the value of a field"), format!("'{id}' is an imported module, and cannot be the value of a field"),
); );
Some(Type::Error(error)) 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<TreeRef>) { pub fn dump_compiler_state(&self, tr: Option<TreeRef>) {
eprintln!("Module: {:?}", self.mid);
eprintln!("Parsed the tree as:"); eprintln!("Parsed the tree as:");
eprintln!("\n{}", self.syntax_tree.dump(&self.source, true)); eprintln!("\n{}", self.syntax_tree.dump(&self.source, true));
@ -2727,29 +2696,10 @@ impl Semantics {
eprint!(" *** ERROR: {error}"); eprint!(" *** ERROR: {error}");
} }
for (k, v) in env.declarations.iter() { for (k, v) in env.declarations.iter() {
eprint!(" {k}: "); eprintln!(
match v { " {k}: {:?} {} ({:?} {:?})",
Declaration::Variable { v.location, v.index, v.module, v.origin
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)");
}
};
} }
environment = env.parent.clone(); environment = env.parent.clone();
} }

View file

@ -4,5 +4,6 @@ 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