[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::{
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,12 +584,10 @@ 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 {
// 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)
@ -608,14 +606,11 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
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,12 +633,10 @@ 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 {
// 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;
@ -662,17 +655,20 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
// TODO: Assert slot is in field range?
Instruction::LoadSlot(index)
}
}
}
Declaration::Function { declaration, .. } => {
let key = FunctionKey { tree: *declaration };
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,
variable_decl.location,
Location::Local,
"expected loop variable to be local"
);
*index
}
_ => ice!(c, vt, "loop variable was not a variable"),
};
let variable_slot = variable_decl.index;
// Figure out the 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)]
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<Semantics>,
tree: Option<TreeRef>,
declaration: Box<Declaration>,
},
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<TreeRef> {
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<EnvironmentRef>,
pub module: ModuleId,
pub location: Location,
pub next_index: usize,
pub declarations: HashMap<Box<str>, Declaration>,
@ -426,7 +402,7 @@ pub struct 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
.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<Error>) -> 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<str>, t: TreeRef) -> Option<Declaration> {
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(
&mut env.declarations
};
let existing = target.insert(
(&*method.name).into(),
Declaration::Function {
declaration: method.declaration,
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::Variable { .. }) => {
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))
}
Some(Declaration::Function { .. } | Declaration::ExternFunction { .. }) => {
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))
}
Some(Declaration::ImportedModule { .. }) => {
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::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<Type> {
fn type_of_member_access(&self, tree: &Tree) -> Option<Type> {
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<TreeRef>, 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<TreeRef>) {
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();
}

View file

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