[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,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")?;