[fine] Working on rebuilding declarations
Running into walls dealing with imported declarations, thinking maybe this structure will help me.
This commit is contained in:
parent
f3a8203be3
commit
2c03989da3
3 changed files with 277 additions and 334 deletions
|
|
@ -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")?;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
(&*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<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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@ fun test() -> string {
|
|||
foo.hello() + " world"
|
||||
}
|
||||
|
||||
// @ignore working on declaration rebuild
|
||||
// TODO: Obviously run the code duh
|
||||
// @no-errors
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue