[fine] Evaluate is expressions, SO MANY BUG FIXES

This commit is contained in:
John Doty 2024-02-03 09:38:08 -08:00
parent b5b56b49a9
commit 198dc5bdb3
6 changed files with 215 additions and 42 deletions

View file

@ -26,7 +26,7 @@ pub enum Instruction {
FloatSubtract,
Jump(usize),
JumpFalse(usize),
JumpTrue(usize),
JumpTrue(usize), // TODO: Only one of these, and use BoolNot?
LoadArgument(usize),
LoadExternFunction(usize), // NOTE: FUNKY, might want to indirect this index.
LoadFunction(usize),
@ -44,6 +44,9 @@ pub enum Instruction {
StoreLocal(usize),
StoreModule(usize),
StringAdd,
IsClass(i64),
PushInt(i64),
}
pub enum Export {
@ -286,19 +289,22 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
let tree = &c.syntax[t];
let cr = match tree.kind {
TreeKind::Error => None,
TreeKind::LiteralExpression => compile_literal(c, t, tree),
TreeKind::GroupingExpression => compile_grouping(c, tree),
TreeKind::UnaryExpression => compile_unary_operator(c, t, tree),
TreeKind::ConditionalExpression => compile_condition_expression(c, tree),
TreeKind::BinaryExpression => compile_binary_expression(c, t, tree),
TreeKind::Identifier => compile_identifier_expression(c, t, tree),
TreeKind::CallExpression => compile_call_expression(c, tree),
TreeKind::Block => compile_block_expression(c, tree),
TreeKind::Argument => compile_argument(c, tree),
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
TreeKind::BinaryExpression => compile_binary_expression(c, t, tree),
TreeKind::Block => compile_block_expression(c, tree),
TreeKind::CallExpression => compile_call_expression(c, tree),
TreeKind::ConditionalExpression => compile_condition_expression(c, tree),
TreeKind::FieldValue => compile_field_value(c, t, tree),
TreeKind::GroupingExpression => compile_grouping(c, tree),
TreeKind::Identifier => compile_identifier_expression(c, t, tree),
TreeKind::IsExpression => compile_is_expression(c, t, tree),
TreeKind::LiteralExpression => compile_literal(c, t, tree),
TreeKind::MemberAccess => compile_member_access(c, tree),
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
TreeKind::SelfReference => compile_self_reference(c),
TreeKind::UnaryExpression => compile_unary_operator(c, t, tree),
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
};
if matches!(cr, None) {
@ -374,15 +380,16 @@ fn compile_condition_expression(c: &mut Compiler, t: &Tree) -> CR {
let then_branch = t.nth_tree(2)?;
compile_expression(c, then_branch);
if let Some(else_branch) = t.nth_tree(4) {
let jump_end_index = c.push(Instruction::Jump(0));
c.patch(jump_else_index, |i| Instruction::JumpFalse(i));
let jump_end_index = c.push(Instruction::Jump(0));
c.patch(jump_else_index, |i| Instruction::JumpFalse(i));
if let Some(else_branch) = t.nth_tree(4) {
compile_expression(c, else_branch);
c.patch(jump_end_index, |i| Instruction::Jump(i));
} else {
c.patch(jump_else_index, |i| Instruction::JumpFalse(i));
c.push(Instruction::PushNothing);
}
c.patch(jump_end_index, |i| Instruction::Jump(i));
OK
}
@ -420,30 +427,54 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatDivide)
}
TokenKind::And => {
// Compile the left hand side, it leaves a bool on the stack
compile_expression(c, tr.nth_tree(0)?);
let jump_false_index = c.push(Instruction::JumpFalse(0));
c.push(Instruction::PushTrue);
// If the first part is true (hooray!) then we need to evaluate
// the right hand side, so jump around the short circuit...
let jump_true_index = c.push(Instruction::JumpTrue(0));
// ...but if the first part is false then we stop here. We need
// to leave a value on the stack (it was consumed by jump above)
// so we push an extra False here, and jump to the end.
c.push(Instruction::PushFalse);
let jump_end_index = c.push(Instruction::Jump(0));
c.patch(jump_false_index, |i| Instruction::JumpFalse(i));
// Here we are, we consumed the `true` off the stack now time to
// do the right hand side.
c.patch(jump_true_index, |i| Instruction::JumpTrue(i));
// The right hand side leaves true or false on the stack, it's
// the result of the expression.
compile_expression(c, tr.nth_tree(2)?);
// (here's where you go after you leave the "false" on the stack.)
c.patch(jump_end_index, |i| Instruction::Jump(i));
OK
}
TokenKind::Or => {
// Compile the left hand side, it leaves a bool on the stack
compile_expression(c, tr.nth_tree(0)?);
let jump_true_index = c.push(Instruction::JumpTrue(0));
// If the first part is false (boo!) then we need to evaluate the
// right hand side, so jump around the short circuit...
let jump_false_index = c.push(Instruction::JumpFalse(0));
// ...but if the first part os true then we stop here. We need to
// leave a value on the stack (it was consumed by jump above) so
// we push an extra True here and jump to the end.
c.push(Instruction::PushTrue);
let jump_end_index = c.push(Instruction::Jump(0));
c.patch(jump_true_index, |i| Instruction::JumpTrue(i));
// Here we are, we consumed the `false` off the stack now time to
// do the right hand side.
c.patch(jump_false_index, |i| Instruction::JumpFalse(i));
// The right hand side leaves true or false on the stack, it's
// the result of the expression.
compile_expression(c, tr.nth_tree(2)?);
// (here's where you go after you leave "true" on the stack.)
c.patch(jump_end_index, |i| Instruction::Jump(i));
OK
}
@ -589,6 +620,112 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
OK
}
fn compile_is_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> Option<()> {
compile_expression(c, tree.nth_tree(0)?);
// If you have a binding, dup and store now, it is in scope.
let type_expr =
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::Variable {
location: Location::Local,
index,
..
} = declaration
else {
ice!(c, t, "is cannot make a non-local, non-variable declaration")
};
c.push(Instruction::Dup);
c.push(Instruction::StoreLocal(*index));
}
binding.child_tree_of_kind(c.syntax, TreeKind::TypeExpression)?
} else {
tree.child_tree_of_kind(c.syntax, TreeKind::TypeExpression)?
};
compile_type_expr_eq(c, type_expr.nth_tree(0)?);
if let Some(tok) = tree.nth_token(3) {
if tok.kind == TokenKind::And {
let jump_true_index = c.push(Instruction::JumpTrue(0));
c.push(Instruction::PushFalse);
let jump_end_index = c.push(Instruction::Jump(0));
c.patch(jump_true_index, |i| Instruction::JumpTrue(i));
compile_expression(c, tree.nth_tree(4)?);
c.patch(jump_end_index, |i| Instruction::Jump(i));
}
}
OK
}
fn compile_type_expr_eq(c: &mut Compiler, t: TreeRef) {
let tree = &c.syntax[t];
let result = match tree.kind {
TreeKind::TypeIdentifier => compile_type_identifier_eq(c, t, tree),
TreeKind::AlternateType => compile_type_alternate_eq(c, tree),
_ => ice!(c, t, "tree is not a type expression"),
};
if result.is_none() {
c.push(inst_panic!("panic compiling type expression eq {:?}", tree));
}
}
fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
let identifier = tree.nth_token(0)?;
let environment = c.semantics.environment_of(t);
match environment.bind(identifier)? {
Declaration::Class { declaration, .. } => {
// The runtime identifier of the class is the tree index of the
// class declaration sure why not.
let index = declaration.index();
c.push(Instruction::IsClass(index.try_into().unwrap()));
}
// TODO: enforce that type identifier binds to class in `is`
// expresion, we don't support RTTI for other types yet.
_ => return None,
}
OK
}
fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
// Compile the left hand side, it leaves a bool on the stack
compile_type_expr_eq(c, tree.nth_tree(0)?);
// If the first part is false (boo!) then we need to evaluate the
// right hand side, so jump around the short circuit...
let jump_false_index = c.push(Instruction::JumpFalse(0));
// ...but if the first part is true then we stop here. We need to
// leave a value on the stack (it was consumed by jump above) so
// we push an extra True here and jump to the end.
c.push(Instruction::PushTrue);
let jump_end_index = c.push(Instruction::Jump(0));
// Here we are, we consumed the `false` off the stack now time to
// do the right hand side.
c.patch(jump_false_index, |i| Instruction::JumpFalse(i));
// The right hand side leaves true or false on the stack, it's
// the result of the expression.
compile_type_expr_eq(c, tree.nth_tree(2)?);
// (here's where you go after you leave "true" on the stack.)
c.patch(jump_end_index, |i| Instruction::Jump(i));
OK
}
fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
let arg_list = tree.child_tree_of_kind(c.syntax, TreeKind::ArgumentList)?;
let mut args: Vec<_> = arg_list.child_trees().collect();
@ -883,6 +1020,7 @@ fn compile_function(c: &mut Compiler, t: TreeRef) -> CR {
let name = tree.nth_token(1)?.as_str();
let name_index = c.add_string(name.to_string());
c.push(Instruction::PushString(name_index));
c.push(Instruction::PushInt(t.index().try_into().unwrap()));
c.push(Instruction::NewObject(count));
}
_ => ice!(c, t, "what is this tree doing in compile_function?"),