[fine] Lifetime garbage, big refactor
So it turns out that I can't hold `&str` in token because it makes it impossible to encapsulate a source file in the larger context- self referential structure problems again. Everything gets rebuilt so that the source can be passed through. While we're at it, more things become Rc<> because, man..... life it too short. Semantics in particular has become a giant hub of the module state: we can basically just hold an Rc<Semantics> and have everything we could possibly want to know about a source file, computed lazily if necessary.
This commit is contained in:
parent
d5059dd450
commit
2dbdbb3957
7 changed files with 502 additions and 329 deletions
|
|
@ -148,8 +148,9 @@ struct FunctionKey {
|
|||
}
|
||||
|
||||
struct Compiler<'a> {
|
||||
semantics: &'a Semantics<'a>,
|
||||
syntax: &'a SyntaxTree<'a>,
|
||||
source: &'a str,
|
||||
semantics: &'a Semantics,
|
||||
syntax: &'a SyntaxTree,
|
||||
|
||||
function_bindings: HashMap<FunctionKey, usize>,
|
||||
pending_functions: Vec<(FunctionKey, usize, Function)>,
|
||||
|
|
@ -183,8 +184,7 @@ macro_rules! compiler_assert_eq {
|
|||
let left = &$ll;
|
||||
let right = &$rr;
|
||||
if left != right {
|
||||
let semantics = $compiler.semantics;
|
||||
semantics.dump_compiler_state(Some($tr));
|
||||
$compiler.semantics.dump_compiler_state(Some($tr));
|
||||
|
||||
assert_eq!(left, right);
|
||||
}
|
||||
|
|
@ -194,8 +194,7 @@ macro_rules! compiler_assert_eq {
|
|||
let left = &$ll;
|
||||
let right = &$rr;
|
||||
if left != right {
|
||||
let semantics = $compiler.semantics;
|
||||
semantics.dump_compiler_state(Some($tr));
|
||||
$compiler.semantics.dump_compiler_state(Some($tr));
|
||||
|
||||
assert_eq!(left, right, $($t)*);
|
||||
}
|
||||
|
|
@ -205,8 +204,7 @@ macro_rules! compiler_assert_eq {
|
|||
macro_rules! compiler_assert {
|
||||
($compiler:expr, $tr:expr, $cond:expr $(,)?) => {{
|
||||
if !$cond {
|
||||
let semantics = $compiler.semantics;
|
||||
semantics.dump_compiler_state(Some($tr));
|
||||
$compiler.semantics.dump_compiler_state(Some($tr));
|
||||
|
||||
assert!($cond);
|
||||
}
|
||||
|
|
@ -214,8 +212,7 @@ macro_rules! compiler_assert {
|
|||
|
||||
($compiler:expr, $tr:expr, $cond:expr, $($arg:tt)+) => {{
|
||||
if !$cond {
|
||||
let semantics = $compiler.semantics;
|
||||
semantics.dump_compiler_state(Some($tr));
|
||||
$compiler.semantics.dump_compiler_state(Some($tr));
|
||||
|
||||
assert!($cond, $($arg)*);
|
||||
}
|
||||
|
|
@ -223,9 +220,8 @@ macro_rules! compiler_assert {
|
|||
}
|
||||
|
||||
macro_rules! ice {
|
||||
($compiler: expr, $tr:expr, $($t:tt)+) => {{
|
||||
let semantics = $compiler.semantics;
|
||||
semantics.dump_compiler_state(Some($tr));
|
||||
($compiler:expr, $tr:expr, $($t:tt)+) => {{
|
||||
$compiler.semantics.dump_compiler_state(Some($tr));
|
||||
panic!($($t)*)
|
||||
}}
|
||||
}
|
||||
|
|
@ -241,10 +237,15 @@ macro_rules! inst_panic {
|
|||
// ($compiler:expr, $tr:expr, $($t:tt)*) => {{}};
|
||||
// }
|
||||
|
||||
pub fn compile(semantics: &Semantics) -> Rc<Module> {
|
||||
pub fn compile(semantics: Rc<Semantics>) -> Rc<Module> {
|
||||
let source = semantics.source();
|
||||
let syntax_tree = semantics.tree();
|
||||
|
||||
let mut compiler = Compiler {
|
||||
semantics,
|
||||
syntax: semantics.tree(),
|
||||
source: &source,
|
||||
semantics: &semantics,
|
||||
syntax: &syntax_tree,
|
||||
|
||||
function_bindings: HashMap::new(),
|
||||
pending_functions: Vec::new(),
|
||||
temp_functions: Vec::new(),
|
||||
|
|
@ -328,14 +329,16 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
|||
fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||
let tok = tr.nth_token(0)?;
|
||||
match c.semantics.type_of(t) {
|
||||
Type::F64 => c.push(Instruction::PushFloat(tok.as_str().parse().unwrap())),
|
||||
Type::F64 => c.push(Instruction::PushFloat(
|
||||
tok.as_str(c.source).parse().unwrap(),
|
||||
)),
|
||||
Type::Bool => c.push(if tok.kind == TokenKind::True {
|
||||
Instruction::PushTrue
|
||||
} else {
|
||||
Instruction::PushFalse
|
||||
}),
|
||||
Type::String => {
|
||||
let result = string_constant_to_string(tok.as_str());
|
||||
let result = string_constant_to_string(tok.as_str(c.source));
|
||||
let index = c.add_string(result);
|
||||
c.push(Instruction::PushString(index))
|
||||
}
|
||||
|
|
@ -534,24 +537,16 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
|||
let declaration = match ltree.kind {
|
||||
// TODO: Assign to list access
|
||||
TreeKind::Identifier => {
|
||||
let id = ltree.nth_token(0)?;
|
||||
let id = ltree.nth_token(0)?.as_str(&c.source);
|
||||
environment = c.semantics.environment_of(lvalue);
|
||||
environment.bind(id)?
|
||||
}
|
||||
TreeKind::MemberAccess => {
|
||||
let id = ltree.nth_token(2)?;
|
||||
let typ = c.semantics.type_of(ltree.nth_tree(0)?);
|
||||
environment = match &typ {
|
||||
Type::Object(ct, _) => {
|
||||
let class = c.semantics.class_of(*ct);
|
||||
class.env.clone()
|
||||
}
|
||||
Type::Class(ct, _) => {
|
||||
let class = c.semantics.class_of(*ct);
|
||||
class.static_env.clone()
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let id = ltree.nth_token(2)?.as_str(&c.source);
|
||||
|
||||
let t = ltree.nth_tree(0)?;
|
||||
let typ = c.semantics.type_of(t);
|
||||
environment = c.semantics.member_environment(t, &typ);
|
||||
environment.bind(id)?
|
||||
}
|
||||
_ => return None,
|
||||
|
|
@ -587,16 +582,22 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
|||
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
|
||||
Declaration::Function { .. } => inst_panic!("store func"),
|
||||
Declaration::Class { .. } => inst_panic!("store class"),
|
||||
Declaration::Import { .. } => inst_panic!("store import"),
|
||||
};
|
||||
c.push(instruction);
|
||||
OK
|
||||
}
|
||||
_ => ice!(c, t, "Unsupported binary expression '{op}'"),
|
||||
_ => ice!(
|
||||
c,
|
||||
t,
|
||||
"Unsupported binary expression '{}'",
|
||||
op.as_str(&c.source)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> Option<()> {
|
||||
let ident = tree.nth_token(0)?;
|
||||
let ident = tree.nth_token(0)?.as_str(&c.source);
|
||||
let environment = c.semantics.environment_of(t);
|
||||
let declaration = environment.bind(ident)?;
|
||||
|
||||
|
|
@ -659,6 +660,8 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
|
|||
|
||||
// Must be a static don't worry about it.
|
||||
Declaration::Class { .. } => return OK,
|
||||
|
||||
Declaration::Import { .. } => todo!(),
|
||||
};
|
||||
|
||||
c.push(instruction);
|
||||
|
|
@ -677,10 +680,10 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
|
|||
|
||||
// Let's *try* to generate good code in the presence of a wildcard pattern....
|
||||
let is_wildcard = tree
|
||||
.child_tree_of_kind(c.syntax, TreeKind::WildcardPattern)
|
||||
.child_tree_of_kind(&c.syntax, TreeKind::WildcardPattern)
|
||||
.is_some();
|
||||
|
||||
let type_expr = tree.child_tree_of_kind(c.syntax, TreeKind::TypeExpression);
|
||||
let type_expr = tree.child_tree_of_kind(&c.syntax, TreeKind::TypeExpression);
|
||||
|
||||
let and_index = tree.children.iter().position(|c| match c {
|
||||
Child::Token(t) => t.kind == TokenKind::And,
|
||||
|
|
@ -688,10 +691,10 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
|
|||
});
|
||||
|
||||
// If you have a binding, dup and store now, it is in scope.
|
||||
if let Some(binding) = tree.child_tree_of_kind(c.syntax, TreeKind::VariableBinding) {
|
||||
if let Some(binding) = tree.child_tree_of_kind(&c.syntax, TreeKind::VariableBinding) {
|
||||
if let Some(variable) = binding.nth_token(0) {
|
||||
let environment = c.semantics.environment_of(t);
|
||||
let declaration = environment.bind(variable)?;
|
||||
let declaration = environment.bind(variable.as_str(&c.source))?;
|
||||
|
||||
let Declaration::Variable {
|
||||
location: Location::Local,
|
||||
|
|
@ -765,8 +768,8 @@ fn compile_type_expr_eq(c: &mut Compiler, t: TreeRef) {
|
|||
}
|
||||
|
||||
fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||
let identifier = tree.nth_token(0)?;
|
||||
match identifier.as_str() {
|
||||
let identifier = tree.nth_token(0)?.as_str(&c.source);
|
||||
match identifier {
|
||||
"f64" => {
|
||||
c.push(Instruction::IsFloat);
|
||||
}
|
||||
|
|
@ -825,7 +828,7 @@ fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
|
|||
}
|
||||
|
||||
fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
|
||||
let arg_list = tree.child_tree_of_kind(c.syntax, TreeKind::ArgumentList)?;
|
||||
let arg_list = tree.child_tree_of_kind(&c.syntax, TreeKind::ArgumentList)?;
|
||||
let mut args: Vec<_> = arg_list.child_trees().collect();
|
||||
let arg_count = args.len();
|
||||
|
||||
|
|
@ -876,12 +879,12 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
|
|||
};
|
||||
let class = c.semantics.class_of(ct);
|
||||
|
||||
let field_list = tree.child_tree_of_kind(c.syntax, TreeKind::FieldList)?;
|
||||
let field_list = tree.child_tree_of_kind(&c.syntax, TreeKind::FieldList)?;
|
||||
let mut field_bindings = HashMap::new();
|
||||
for field in field_list.children_of_kind(c.syntax, TreeKind::FieldValue) {
|
||||
for field in field_list.children_of_kind(&c.syntax, TreeKind::FieldValue) {
|
||||
let f = &c.syntax[field];
|
||||
let name = f.nth_token(0)?;
|
||||
field_bindings.insert(name.as_str(), field);
|
||||
field_bindings.insert(name.as_str(&c.source), field);
|
||||
}
|
||||
|
||||
// The fields come in this order and since arguments are backwards
|
||||
|
|
@ -894,8 +897,8 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
|
|||
|
||||
// Fetch the correct constructor.
|
||||
// TODO: Binding this type should be done by semantics, and we should borrow it.
|
||||
let type_reference = tree.child_tree_of_kind(c.syntax, TreeKind::TypeIdentifier)?;
|
||||
let identifier = type_reference.nth_token(0)?;
|
||||
let type_reference = tree.child_tree_of_kind(&c.syntax, TreeKind::TypeIdentifier)?;
|
||||
let identifier = type_reference.nth_token(0)?.as_str(&c.source);
|
||||
let environment = c.semantics.environment_of(t);
|
||||
match environment.bind(identifier)? {
|
||||
Declaration::Class { declaration, .. } => {
|
||||
|
|
@ -931,7 +934,7 @@ fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
|||
|
||||
// Form 2: { x, ... }
|
||||
let environment = c.semantics.environment_of(t);
|
||||
let id = tree.nth_token(0)?;
|
||||
let id = tree.nth_token(0)?.as_str(&c.source);
|
||||
let declaration = environment.bind(id)?;
|
||||
|
||||
compile_load_declaration(c, t, declaration)
|
||||
|
|
@ -944,7 +947,7 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
|||
compile_expression(c, tree.nth_tree(0)?);
|
||||
|
||||
let typ = c.semantics.type_of(tree.nth_tree(0)?);
|
||||
let ident = tree.nth_token(2)?;
|
||||
let ident = tree.nth_token(2)?.as_str(&c.source);
|
||||
|
||||
let environment = match &typ {
|
||||
Type::Object(ct, _) => {
|
||||
|
|
@ -976,7 +979,7 @@ fn compile_self_reference(c: &mut Compiler) -> CR {
|
|||
|
||||
fn compile_list_constructor(c: &mut Compiler, tree: &Tree) -> CR {
|
||||
let mut children: Vec<_> = tree
|
||||
.children_of_kind(c.syntax, TreeKind::ListConstructorElement)
|
||||
.children_of_kind(&c.syntax, TreeKind::ListConstructorElement)
|
||||
.collect();
|
||||
children.reverse();
|
||||
let count = children.len();
|
||||
|
|
@ -1046,7 +1049,7 @@ fn compile_expression_statement(c: &mut Compiler, tree: &Tree, gen_value: bool)
|
|||
fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: bool) -> CR {
|
||||
compile_expression(c, tree.nth_tree(3)?);
|
||||
let environment = c.semantics.environment_of(t);
|
||||
let declaration = environment.bind(tree.nth_token(1)?)?;
|
||||
let declaration = environment.bind(tree.nth_token(1)?.as_str(&c.source))?;
|
||||
|
||||
let Declaration::Variable {
|
||||
location, index, ..
|
||||
|
|
@ -1087,19 +1090,16 @@ fn compile_function_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_v
|
|||
let fk = FunctionKey { tree: t };
|
||||
if !c.function_bindings.contains_key(&fk) {
|
||||
// TODO: If this is a method the name should be different.
|
||||
let name = tree.nth_token(1)?;
|
||||
let name = tree.nth_token(1)?.as_str(&c.source);
|
||||
|
||||
let param_list = tree.child_tree_of_kind(c.syntax, TreeKind::ParamList)?;
|
||||
let param_list = tree.child_tree_of_kind(&c.syntax, TreeKind::ParamList)?;
|
||||
let param_count = param_list.children.len() - 2;
|
||||
|
||||
let function_index = c.temp_functions.len();
|
||||
c.temp_functions.push(None);
|
||||
|
||||
c.pending_functions.push((
|
||||
fk.clone(),
|
||||
function_index,
|
||||
Function::new(name.as_str(), param_count),
|
||||
));
|
||||
c.pending_functions
|
||||
.push((fk.clone(), function_index, Function::new(name, param_count)));
|
||||
c.function_bindings.insert(fk, function_index);
|
||||
c.module
|
||||
.exports
|
||||
|
|
@ -1118,18 +1118,15 @@ fn compile_class_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_valu
|
|||
// Classes get compiled as constructor functions which get called.
|
||||
let fk = FunctionKey { tree: t };
|
||||
if !c.function_bindings.contains_key(&fk) {
|
||||
let name = tree.nth_token(1)?;
|
||||
let name = tree.nth_token(1)?.as_str(&c.source);
|
||||
|
||||
let field_count = tree.children.len() - 2;
|
||||
|
||||
let function_index = c.temp_functions.len();
|
||||
c.temp_functions.push(None);
|
||||
|
||||
c.pending_functions.push((
|
||||
fk.clone(),
|
||||
function_index,
|
||||
Function::new(name.as_str(), field_count),
|
||||
));
|
||||
c.pending_functions
|
||||
.push((fk.clone(), function_index, Function::new(name, field_count)));
|
||||
c.function_bindings.insert(fk, function_index);
|
||||
c.module
|
||||
.exports
|
||||
|
|
@ -1147,16 +1144,18 @@ fn compile_function(c: &mut Compiler, t: TreeRef) -> CR {
|
|||
let tree = &c.syntax[t];
|
||||
match tree.kind {
|
||||
TreeKind::FunctionDecl => {
|
||||
let block = tree.child_of_kind(c.syntax, TreeKind::Block)?;
|
||||
let block = tree.child_of_kind(&c.syntax, TreeKind::Block)?;
|
||||
compile_expression(c, block);
|
||||
}
|
||||
TreeKind::ClassDecl => {
|
||||
let count = tree.children_of_kind(c.syntax, TreeKind::FieldDecl).count();
|
||||
let count = tree
|
||||
.children_of_kind(&c.syntax, TreeKind::FieldDecl)
|
||||
.count();
|
||||
for i in 0..count {
|
||||
c.push(Instruction::LoadArgument(count - 1 - i));
|
||||
}
|
||||
|
||||
let name = tree.nth_token(1)?.as_str();
|
||||
let name = tree.nth_token(1)?.as_str(&c.source);
|
||||
let name_index = c.add_string(name.to_string());
|
||||
c.push(Instruction::PushString(name_index));
|
||||
c.push(Instruction::PushInt(t.index().try_into().unwrap()));
|
||||
|
|
@ -1209,7 +1208,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
|||
// Figure out the variable.
|
||||
let vt = tree.nth_tree(1)?;
|
||||
let var = &c.syntax[vt];
|
||||
let id = var.nth_token(0)?;
|
||||
let id = var.nth_token(0)?.as_str(&c.source);
|
||||
|
||||
let body = tree.nth_tree(4)?;
|
||||
let env = c.semantics.environment_of(body);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue