diff --git a/examples/test.lua b/examples/test.lua index aa8896b..0cc0e9f 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -20,4 +20,5 @@ print(max(11, 9)) print(add(10)(15)) print(add(10)(15)) print(b) -print(min(11, 9)) \ No newline at end of file +print(min(11, 9)) +print(10 > 5 or 11 < 10) \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 0948f67..3a253f6 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -320,23 +320,29 @@ pub struct PrimaryExpression(Node); #[derive(Debug, Clone, Copy)] pub enum BinaryOperator { + And, + Or, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, Equal, Add, + Sub, } impl BinaryOperator { pub fn precedence(&self) -> u32 { match self { + BinaryOperator::Or => 0, + BinaryOperator::And => 1, BinaryOperator::LessThan => 10, BinaryOperator::LessThanOrEqual => 10, BinaryOperator::GreaterThan => 10, BinaryOperator::GreaterThanOrEqual => 10, BinaryOperator::Equal => 10, BinaryOperator::Add => 20, + BinaryOperator::Sub => 20, } } } @@ -419,6 +425,11 @@ impl Parse for BinaryOperator { fn parse(mut stream: TokenStream) -> Result { if let Some(token) = stream.next() { match (token, stream.peek()) { + (Token::Word(word), _) => match word.as_str() { + "and" => Ok(BinaryOperator::And), + "or" => Ok(BinaryOperator::Or), + _ => Err(stream.expected_err("binop")), + }, (Token::Symbol('<'), Some(Token::Symbol('='))) => { stream.next(); Ok(BinaryOperator::LessThanOrEqual) @@ -434,6 +445,7 @@ impl Parse for BinaryOperator { (Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan), (Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan), (Token::Symbol('+'), _) => Ok(BinaryOperator::Add), + (Token::Symbol('-'), _) => Ok(BinaryOperator::Sub), _ => Err(stream.expected_err("binop")), } } else { diff --git a/src/compile.rs b/src/compile.rs index c565020..cfda0ef 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -350,6 +350,25 @@ impl Expression { *rhs.get(0).unwrap(), )); } + BinaryOperator::Sub => { + let temp = scope.register_counter.next(); + instructions.push(Instruction::Unm(temp, *rhs.get(0).unwrap())); + instructions.push(Instruction::Add(reg, *lhs.get(0).unwrap(), temp)); + } + BinaryOperator::And => { + instructions.push(Instruction::And( + reg, + *rhs.get(0).unwrap(), + *lhs.get(0).unwrap(), + )); + } + BinaryOperator::Or => { + instructions.push(Instruction::Or( + reg, + *rhs.get(0).unwrap(), + *lhs.get(0).unwrap(), + )); + } }; (instructions, vec![reg]) } @@ -364,15 +383,11 @@ impl Expression { inner_scope.highest_upvalue = scope.highest_upvalue + scope.register_counter.0; inner_scope.upvalues = scope.upvalues.clone(); - dbg!(&scope.locals); for (name, reg) in &scope.locals { let new_reg = *reg + scope.highest_upvalue + 1; inner_scope.upvalues.insert(name.clone(), new_reg); } - dbg!(&inner_scope.highest_upvalue); - dbg!(&inner_scope.upvalues); - let instructions = block.compile(state, &mut inner_scope); state.prototypes.push(instructions); diff --git a/src/vm.rs b/src/vm.rs index eae8c35..ccd551e 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -40,12 +40,18 @@ pub enum Instruction { SetUpVal(u16, u16), /// R(A) := R(B) + R(C) Add(u16, u16, u16), + /// R(A) := -R(B) + Unm(u16, u16), /// R(A) := R(B) == R(C) Equal(u16, u16, u16), /// R(A) := R(B) < R(C) LessThan(u16, u16, u16), /// R(A) := R(B) <= R(C) LessThanOrEqual(u16, u16, u16), + /// R(A) := R(B) or R(C) + Or(u16, u16, u16), + /// R(A) := R(B) and R(C) + And(u16, u16, u16), /// PC += sAx Jmp(i32), /// if (R(B) <=> C) then R(A) := R(B) else PC++ @@ -83,6 +89,9 @@ impl Debug for Instruction { } Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2), Instruction::LoadNil(arg0, arg1) => write!(f, "LOADNIL {} {}", arg0, arg1), + Instruction::Unm(arg0, arg1) => write!(f, "UNM {} {}", arg0, arg1), + Instruction::Or(arg0, arg1, arg2) => write!(f, "OR {} {} {}", arg0, arg1, arg2), + Instruction::And(arg0, arg1, arg2) => write!(f, "AND {} {} {}", arg0, arg1, arg2), } } } @@ -140,6 +149,50 @@ impl Value { _ => Value::Nil, } } + + pub fn unm(&self) -> Value { + match self { + Value::Number(lhs) => { + let res = -LuaNumber::from_bits(*lhs); + Value::Number((res as u64 as f64).to_bits()) + } + _ => Value::Nil, + } + } + + pub fn and(&self, other: &Value) -> Value { + match (self, other) { + (Value::Nil, _) | (_, Value::Nil) => Value::Nil, + (Value::Number(lhs), Value::Number(rhs)) => { + let res = LuaNumber::from_bits(*lhs) > 0. && LuaNumber::from_bits(*rhs) > 0.; + Value::Number((res as u64 as f64).to_bits()) + } + (Value::Number(value), _) | (_, Value::Number(value)) => { + let res = LuaNumber::from_bits(*value) > 0.; + Value::Number((res as u64 as f64).to_bits()) + } + _ => Value::Nil, + } + } + + pub fn or(&self, other: &Value) -> Value { + match (self, other) { + (Value::Nil, value) | (value, Value::Nil) => value.clone(), + (Value::Number(lhs), Value::Number(rhs)) => { + let res = LuaNumber::from_bits(*lhs) > 0. || LuaNumber::from_bits(*rhs) > 0.; + Value::Number((res as u64 as f64).to_bits()) + } + (Value::Number(value), other) => { + if LuaNumber::from_bits(*value) > 0. { + Value::Number(*value) + } else { + other.clone() + } + } + (value, _) => value.clone(), + _ => Value::Nil, + } + } } impl Debug for Value { @@ -508,6 +561,42 @@ impl ClosureRunner { .unwrap_or(Value::Nil); self.set_stack(*res, lhs.lte(&rhs)); } + Instruction::Unm(res, reg) => { + self.set_stack( + *res, + self.stack + .get(reg) + .map(|v| v.borrow().clone()) + .unwrap_or(Value::Nil) + .unm(), + ); + } + Instruction::Or(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.or(&rhs)); + } + Instruction::And(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.and(&rhs)); + } }; self.program_counter += 1;