[fine] Assignments!

And new error capabilities!
This commit is contained in:
John Doty 2024-01-19 19:08:17 -08:00
parent 92cf840766
commit f20f5a5e03
12 changed files with 400 additions and 64 deletions

View file

@ -14,6 +14,10 @@ pub enum Instruction {
Panic,
BoolNot,
Call(usize),
CompareBool,
CompareFloat,
CompareString,
Discard,
FloatAdd,
FloatDivide,
@ -23,6 +27,8 @@ pub enum Instruction {
JumpFalse(usize),
JumpTrue(usize),
LoadArgument(usize),
LoadExternFunction(usize), // NOTE: FUNKY, might want to indirect this index.
LoadFunction(usize),
LoadLocal(usize),
LoadModule(usize),
PushFalse,
@ -30,16 +36,12 @@ pub enum Instruction {
PushNothing,
PushString(usize),
PushTrue,
Return,
StoreArgument(usize),
StoreLocal(usize),
StoreModule(usize),
LoadFunction(usize),
LoadExternFunction(usize), // NOTE: FUNKY, might want to indirect this index.
Call(usize),
Return,
StringAdd,
CompareBool,
CompareString,
CompareFloat,
Dup,
}
pub enum Export {
@ -372,30 +374,41 @@ fn compile_condition_expression(c: &mut Compiler, t: &Tree) -> CR {
OK
}
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
fn compile_simple_binary_expression<T>(c: &mut Compiler, tr: &Tree, f: T) -> CR
where
T: FnOnce(&mut Compiler, &Type) -> Instruction,
{
compile_expression(c, tr.nth_tree(0)?);
let arg_tree = tr.nth_tree(2)?;
let arg_type = c.semantics.type_of(arg_tree);
compile_expression(c, arg_tree);
let inst = f(c, &arg_type);
c.push(inst);
OK
}
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
match tr.nth_token(1)?.kind {
TokenKind::Plus => {
compile_expression(c, tr.nth_tree(2)?);
c.push(match c.semantics.type_of(t) {
Type::F64 => Instruction::FloatAdd,
Type::String => Instruction::StringAdd,
_ => Instruction::Panic,
});
}
TokenKind::Plus => compile_simple_binary_expression(c, tr, |_, t| match t {
Type::F64 => Instruction::FloatAdd,
Type::String => Instruction::StringAdd,
_ => Instruction::Panic,
}),
TokenKind::Minus => {
compile_expression(c, tr.nth_tree(2)?);
c.push(Instruction::FloatSubtract);
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatSubtract)
}
TokenKind::Star => {
compile_expression(c, tr.nth_tree(2)?);
c.push(Instruction::FloatMultiply);
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatMultiply)
}
TokenKind::Slash => {
compile_expression(c, tr.nth_tree(2)?);
c.push(Instruction::FloatDivide);
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatDivide)
}
TokenKind::And => {
compile_expression(c, tr.nth_tree(0)?);
let jump_false_index = c.push(Instruction::JumpFalse(0));
c.push(Instruction::PushTrue);
@ -406,8 +419,10 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
compile_expression(c, tr.nth_tree(2)?);
c.patch(jump_end_index, |i| Instruction::Jump(i));
OK
}
TokenKind::Or => {
compile_expression(c, tr.nth_tree(0)?);
let jump_true_index = c.push(Instruction::JumpTrue(0));
c.push(Instruction::PushTrue);
@ -418,29 +433,70 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
compile_expression(c, tr.nth_tree(2)?);
c.patch(jump_end_index, |i| Instruction::Jump(i));
OK
}
TokenKind::EqualEqual => {
let arg_tree = tr.nth_tree(2)?;
let arg_type = c.semantics.type_of(arg_tree);
compile_simple_binary_expression(c, tr, |c, arg_type| {
if c.semantics.type_compat(&arg_type, &Type::Nothing) {
c.push(Instruction::Discard);
c.push(Instruction::Discard);
Instruction::PushTrue
} else {
match arg_type {
Type::F64 => Instruction::CompareFloat,
Type::String => Instruction::CompareString,
Type::Bool => Instruction::CompareBool, // ?
_ => Instruction::Panic,
}
}
})
}
TokenKind::Equal => {
compile_expression(c, tr.nth_tree(2)?);
c.push(Instruction::Dup);
if c.semantics.type_compat(&arg_type, &Type::Nothing) {
c.push(Instruction::Discard);
c.push(Instruction::Discard);
c.push(Instruction::PushTrue);
} else {
c.push(match arg_type {
Type::F64 => Instruction::CompareFloat,
Type::String => Instruction::CompareString,
Type::Bool => Instruction::CompareBool, // ?
_ => Instruction::Panic,
});
let lvalue = tr.nth_tree(0)?;
let ltree = &c.syntax[lvalue];
match ltree.kind {
TreeKind::Identifier => {
let ident = ltree.nth_token(0)?;
let environment = c.semantics.environment_of(lvalue);
let declaration = environment.bind(ident)?;
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)
}
}
}
Declaration::ExternFunction { .. } => Instruction::Panic,
Declaration::Function { .. } => Instruction::Panic,
};
c.push(instruction);
}
_ => ice!(c, t, "Unsupported lvalue type"),
}
OK
}
_ => ice!(c, t, "Unsupported binary expression"),
}
OK
}
fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> Option<()> {