[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:
John Doty 2024-02-11 09:31:51 -08:00
parent d5059dd450
commit 2dbdbb3957
7 changed files with 502 additions and 329 deletions

View file

@ -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);