[fine] Evaluate is expressions, SO MANY BUG FIXES
This commit is contained in:
parent
b5b56b49a9
commit
198dc5bdb3
6 changed files with 215 additions and 42 deletions
|
|
@ -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?"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue