diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index b97fc539..c1c55aba 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -36,6 +36,10 @@ pub enum Instruction { LoadExternFunction(usize), // NOTE: FUNKY, might want to indirect this index. Call(usize), Return, + StringAdd, + CompareBool, + CompareString, + CompareFloat, } pub enum Export { @@ -366,7 +370,11 @@ 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(Instruction::FloatAdd); + c.push(match c.semantics.type_of(t) { + Type::F64 => Instruction::FloatAdd, + Type::String => Instruction::StringAdd, + _ => Instruction::Panic, + }); } TokenKind::Minus => { compile_expression(c, tr.nth_tree(2)?); @@ -404,6 +412,25 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR { c.patch(jump_end_index, |i| Instruction::Jump(i)); } + TokenKind::EqualEqual => { + let arg_tree = tr.nth_tree(2)?; + let arg_type = c.semantics.type_of(arg_tree); + + compile_expression(c, tr.nth_tree(2)?); + + if arg_type.compatible_with(&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, + }); + } + } _ => ice!(c, t, "Unsupported binary expression"), } OK diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index afc21fb7..afa2b2c7 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -723,6 +723,11 @@ impl<'a> Semantics<'a> { (TokenKind::And | TokenKind::Or, Type::Bool, Type::Bool) => Some(Type::Bool), + (TokenKind::EqualEqual, Type::F64, Type::F64) => Some(Type::Bool), + (TokenKind::EqualEqual, Type::String, Type::String) => Some(Type::Bool), + (TokenKind::EqualEqual, Type::Bool, Type::Bool) => Some(Type::Bool), + (TokenKind::EqualEqual, Type::Nothing, Type::Nothing) => Some(Type::Bool), + // This is dumb and should be punished, probably. (_, _, Type::Unreachable) => { self.report_error( diff --git a/fine/src/vm.rs b/fine/src/vm.rs index b63eeadf..9fa42424 100644 --- a/fine/src/vm.rs +++ b/fine/src/vm.rs @@ -95,6 +95,13 @@ impl Frame { } } + fn pop_string(&mut self) -> Result> { + match self.pop_value()? { + StackValue::String(v) => Ok(v), + v => Err(VMErrorCode::StackTypeMismatch(v, Type::String)), + } + } + fn push_value(&mut self, v: StackValue) { self.stack.push(v) } @@ -237,10 +244,10 @@ fn eval_one( Instruction::FloatDivide => { let x = f.pop_float()?; let y = f.pop_float()?; - if y == 0. { + if x == 0. { return Err(VMErrorCode::DivideByZero); } - f.push_float(x / y); + f.push_float(y / x); } Instruction::FloatMultiply => { let x = f.pop_float()?; @@ -250,7 +257,7 @@ fn eval_one( Instruction::FloatSubtract => { let x = f.pop_float()?; let y = f.pop_float()?; - f.push_float(x - y); + f.push_float(y - x); } Instruction::Jump(i) => { *index = i; @@ -335,6 +342,30 @@ fn eval_one( } None => return Ok(Flow::Break), }, + Instruction::StringAdd => { + let x = f.pop_string()?; + let y = f.pop_string()?; + + let mut new_string = x.to_string(); + new_string.push_str(&y); + + f.push_string(new_string.into()); + } + Instruction::CompareBool => { + let x = f.pop_bool()?; + let y = f.pop_bool()?; + f.push_bool(x == y); + } + Instruction::CompareFloat => { + let x = f.pop_float()?; + let y = f.pop_float()?; + f.push_bool(x == y); + } + Instruction::CompareString => { + let x = f.pop_string()?; + let y = f.pop_string()?; + f.push_bool(x == y); + } } Ok(Flow::Continue) diff --git a/fine/tests/expression/comparisons.fine b/fine/tests/expression/comparisons.fine new file mode 100644 index 00000000..9e14e7ba --- /dev/null +++ b/fine/tests/expression/comparisons.fine @@ -0,0 +1,18 @@ +fun is_hello(x:string) -> bool { + x == "hello" +} + +fun is_23(x:f64) -> bool { + x == 23.0 +} + +fun is_false(x:bool) -> bool { + x == false +} + +fun test() -> bool { + is_hello("hello") and is_23(23) and is_false(false) +} + +// @no-errors +// @eval: Bool(true) diff --git a/fine/tests/expression/worst_fib.fine b/fine/tests/expression/worst_fib.fine new file mode 100644 index 00000000..3bd0df04 --- /dev/null +++ b/fine/tests/expression/worst_fib.fine @@ -0,0 +1,16 @@ +fun worst_fib(n: f64) -> f64 { + if n == 0 { + 0 + } else if n == 1 { + 1 + } else { + worst_fib(n-2) + worst_fib(n-1) + } +} + +fun test() -> f64 { + worst_fib(10) +} + +// @no-errors +// @eval: Float(55.0)