diff --git a/src/ast.rs b/src/ast.rs index 396dfff..8db73a1 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -321,7 +321,9 @@ pub struct PrimaryExpression(Node); #[derive(Debug, Clone, Copy)] pub enum BinaryOperator { LessThan, - Gt, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual, Add, } @@ -329,7 +331,9 @@ impl BinaryOperator { pub fn precedence(&self) -> u32 { match self { BinaryOperator::LessThan => 10, - BinaryOperator::Gt => 10, + BinaryOperator::LessThanOrEqual => 10, + BinaryOperator::GreaterThan => 10, + BinaryOperator::GreaterThanOrEqual => 10, BinaryOperator::Add => 20, } } @@ -412,10 +416,18 @@ fn parse_binop_rhs( impl Parse for BinaryOperator { fn parse(mut stream: TokenStream) -> Result { if let Some(token) = stream.next() { - match token { - Token::Symbol('<') => Ok(BinaryOperator::LessThan), - Token::Symbol('>') => Ok(BinaryOperator::Gt), - Token::Symbol('+') => Ok(BinaryOperator::Add), + match (token, stream.peek()) { + (Token::Symbol('<'), Some(Token::Symbol('='))) => { + stream.next(); + Ok(BinaryOperator::LessThanOrEqual) + } + (Token::Symbol('>'), Some(Token::Symbol('='))) => { + stream.next(); + Ok(BinaryOperator::GreaterThanOrEqual) + } + (Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan), + (Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan), + (Token::Symbol('+'), _) => Ok(BinaryOperator::Add), _ => Err(stream.expected_err("binop")), } } else { diff --git a/src/compile.rs b/src/compile.rs index 4a824af..70e34fd 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -315,13 +315,27 @@ impl Expression { *rhs.get(0).unwrap(), )); } - BinaryOperator::Gt => { + BinaryOperator::LessThanOrEqual => { + instructions.push(Instruction::LessThanOrEqual( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + )); + } + BinaryOperator::GreaterThan => { instructions.push(Instruction::LessThan( reg, *rhs.get(0).unwrap(), *lhs.get(0).unwrap(), )); } + BinaryOperator::GreaterThanOrEqual => { + instructions.push(Instruction::LessThanOrEqual( + reg, + *rhs.get(0).unwrap(), + *lhs.get(0).unwrap(), + )); + } BinaryOperator::Add => { instructions.push(Instruction::Add( reg, diff --git a/src/vm.rs b/src/vm.rs index f9f44f7..5621f4b 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -42,6 +42,8 @@ pub enum Instruction { Add(u16, u16, u16), /// R(A) := R(B) < R(C) LessThan(u16, u16, u16), + /// R(A) := R(B) < R(C) + LessThanOrEqual(u16, u16, u16), /// PC += sAx Jmp(i32), /// if (R(B) <=> C) then R(A) := R(B) else PC++ @@ -72,7 +74,10 @@ impl Debug for Instruction { Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0), Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1), Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1), - Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LE {} {} {}", arg0, arg1, arg2), + Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LT {} {} {}", arg0, arg1, arg2), + Instruction::LessThanOrEqual(arg0, arg1, arg2) => { + write!(f, "LE {} {} {}", arg0, arg1, arg2) + } Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2), Instruction::LoadNil(arg0, arg1) => write!(f, "LOADNIL {} {}", arg0, arg1), } @@ -112,6 +117,16 @@ impl Value { _ => Value::Nil, } } + + pub fn lte(&self, other: &Value) -> Value { + match (self, other) { + (Value::Number(lhs), Value::Number(rhs)) => { + let res = LuaNumber::from_bits(*lhs) <= LuaNumber::from_bits(*rhs); + Value::Number((res as u64 as f64).to_bits()) + } + _ => Value::Nil, + } + } } impl Debug for Value { @@ -454,6 +469,19 @@ impl ClosureRunner { .unwrap_or(Value::Nil); self.set_stack(*res, lhs.lt(&rhs)); } + Instruction::LessThanOrEqual(res, lhs, rhs) => { + let lhs = self + .stack + .get(lhs) + .map(|v| v.borrow().clone()) + .unwrap_or(Value::Nil); + let rhs = self + .stack + .get(rhs) + .map(|v| v.borrow().clone()) + .unwrap_or(Value::Nil); + self.set_stack(*res, lhs.lte(&rhs)); + } }; self.program_counter += 1;