diff --git a/src/compile.rs b/src/compile.rs index 6de570b..8ec1ccf 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -858,18 +858,91 @@ impl Expression { *rhs.get(0).unwrap(), ))); } - BinaryOperator::Concat => todo!(), - BinaryOperator::NotEqual => todo!(), - BinaryOperator::Mult => todo!(), - BinaryOperator::Div => todo!(), - BinaryOperator::IDiv => todo!(), - BinaryOperator::Mod => todo!(), - BinaryOperator::Exp => todo!(), - BinaryOperator::BitAnd => todo!(), - BinaryOperator::BitOr => todo!(), - BinaryOperator::BitXOr => todo!(), - BinaryOperator::BitSRight => todo!(), - BinaryOperator::BitSLeft => todo!(), + BinaryOperator::Concat => { + instructions.push(PreInstr::Instr(Instruction::Concat( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::NotEqual => { + instructions.push(PreInstr::Instr(Instruction::Equal( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + instructions.push(PreInstr::Instr(Instruction::Not(reg, reg))); + } + BinaryOperator::Mult => { + instructions.push(PreInstr::Instr(Instruction::Mult( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::Div => { + instructions.push(PreInstr::Instr(Instruction::Div( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::IDiv => { + instructions.push(PreInstr::Instr(Instruction::IDiv( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::Mod => { + instructions.push(PreInstr::Instr(Instruction::Mod( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::Exp => { + instructions.push(PreInstr::Instr(Instruction::Exp( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::BitAnd => { + instructions.push(PreInstr::Instr(Instruction::BitAnd( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::BitOr => { + instructions.push(PreInstr::Instr(Instruction::BitOr( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::BitXOr => { + instructions.push(PreInstr::Instr(Instruction::BitXOr( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::BitSRight => { + instructions.push(PreInstr::Instr(Instruction::BitSRight( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } + BinaryOperator::BitSLeft => { + instructions.push(PreInstr::Instr(Instruction::BitSLeft( + reg, + *lhs.get(0).unwrap(), + *rhs.get(0).unwrap(), + ))); + } }; (instructions, vec![reg]) } @@ -885,8 +958,12 @@ impl Expression { UnaryOperator::Length => { instructions.push(PreInstr::Instr(Instruction::Len(*reg, *reg))) } - UnaryOperator::Not => todo!(), - UnaryOperator::BitNot => todo!(), + UnaryOperator::Not => { + instructions.push(PreInstr::Instr(Instruction::Not(*reg, *reg))) + } + UnaryOperator::BitNot => { + instructions.push(PreInstr::Instr(Instruction::BitNot(*reg, *reg))) + } } } (instructions, registers) diff --git a/src/vm/mod.rs b/src/vm/mod.rs index a8a2344..80d6f8c 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,6 +1,6 @@ use thiserror::Error; -use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, fmt::Debug, i64, rc::Rc}; use crate::{ CompilationUnit, @@ -16,6 +16,7 @@ pub enum Instruction { Move(u16, u16), /// R(A) ... R(A + func_register - top) := previous function return values MoveRetValues(u16), + /// R(A) := K(Bx) LoadK(u16, u32), /// R(A), ..., R(B) := nil @@ -34,24 +35,58 @@ pub enum Instruction { SetList(u16, u32), /// R(A) := R(B)[R(C)] GetTable(u16, u16, u16), + /// R(A) := {} NewTable(u16), + + /// R(A) := R(B) .. R(C) + Concat(u16, u16, u16), + /// R(A) := R(B) + R(C) Add(u16, u16, u16), + /// R(A) := R(B) * R(C) + Mult(u16, u16, u16), + /// R(A) := R(B) / R(C) + Div(u16, u16, u16), + /// R(A) := R(B) // R(C) + IDiv(u16, u16, u16), + /// R(A) := R(B) % R(C) + Mod(u16, u16, u16), + /// R(A) := R(B) ^ R(C) + Exp(u16, u16, u16), + + /// R(A) := R(B) & R(C) + BitAnd(u16, u16, u16), + /// R(A) := R(B) | R(C) + BitOr(u16, u16, u16), + /// R(A) := R(B) ~ R(C) + BitXOr(u16, u16, u16), + /// R(A) := R(B) >> R(C) + BitSRight(u16, u16, u16), + /// R(A) := R(B) << R(C) + BitSLeft(u16, u16, u16), + /// R(A) := -R(B) Unm(u16, u16), /// R(A) := #R(B) (length operator) Len(u16, u16), + /// R(A) := not R(B) + Not(u16, u16), + /// R(A) := ~R(B) + BitNot(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), /// PC = Ax @@ -69,10 +104,12 @@ pub enum Instruction { Call(u16, u16, u16), /// return R(A), ... , R(B) Return(u16, u16), + /// close stack variables up to R(A) Close(u16), /// R(A) := closure(KPROTO[Bx], R(A), ..., R(A+n)) Closure(u16, u32), + /// R(A), ... , R(A+B-2) := varargs Vararg(u16, u16), } @@ -105,15 +142,35 @@ 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::Concat(arg0, arg1, arg2) => write!(f, "CONCAT {} {} {}", arg0, arg1, arg2), + Instruction::Equal(arg0, arg1, arg2) => write!(f, "EQ {} {} {}", 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::Mult(arg0, arg1, arg2) => write!(f, "MUL {} {} {}", arg0, arg1, arg2), + Instruction::Div(arg0, arg1, arg2) => write!(f, "DIV {} {} {}", arg0, arg1, arg2), + Instruction::IDiv(arg0, arg1, arg2) => write!(f, "IDIV {} {} {}", arg0, arg1, arg2), + Instruction::Mod(arg0, arg1, arg2) => write!(f, "MOD {} {} {}", arg0, arg1, arg2), + Instruction::Exp(arg0, arg1, arg2) => write!(f, "EXP {} {} {}", arg0, arg1, arg2), + + Instruction::BitAnd(arg0, arg1, arg2) => write!(f, "BAND {} {} {}", arg0, arg1, arg2), + Instruction::BitOr(arg0, arg1, arg2) => write!(f, "BOR {} {} {}", arg0, arg1, arg2), + Instruction::BitXOr(arg0, arg1, arg2) => write!(f, "BXOR {} {} {}", arg0, arg1, arg2), + Instruction::BitSRight(arg0, arg1, arg2) => write!(f, "BSR {} {} {}", arg0, arg1, arg2), + Instruction::BitSLeft(arg0, arg1, arg2) => write!(f, "BSL {} {} {}", arg0, arg1, arg2), + Instruction::LoadNil(arg0, arg1) => write!(f, "LOADNIL {} {}", arg0, arg1), + Instruction::Unm(arg0, arg1) => write!(f, "UNM {} {}", arg0, arg1), Instruction::Len(arg0, arg1) => write!(f, "LEN {} {}", arg0, arg1), + Instruction::Not(arg0, arg1) => write!(f, "NOT {} {}", arg0, arg1), + Instruction::BitNot(arg0, arg1) => write!(f, "BNOT {} {}", arg0, arg1), + Instruction::Or(arg0, arg1, arg2) => write!(f, "OR {} {} {}", arg0, arg1, arg2), Instruction::And(arg0, arg1, arg2) => write!(f, "AND {} {} {}", arg0, arg1, arg2), Instruction::Vararg(arg0, arg1) => write!(f, "VARARG {} {}", arg0, arg1), @@ -137,6 +194,8 @@ pub enum RuntimeError { NotTable(Value), #[error("Value is not coercable to a float: {0:?}")] NotFloatable(Value), + #[error("Value is not coercable to bits: {0:?}")] + NotBittable(Value), #[error("Value does not have a length: {0:?}")] NotLengthable(Value), #[error("{0}")] @@ -678,6 +737,21 @@ impl ClosureRunner { } return Ok(Some(ret_values)); } + + Instruction::Concat(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, StackValue::Value(lhs.concat(&rhs)?)); + } + Instruction::Add(res, lhs, rhs) => { let lhs = self .stack @@ -691,6 +765,138 @@ impl ClosureRunner { .unwrap_or(Value::Nil); self.set_stack(*res, StackValue::Value(lhs.add(&rhs)?)); } + Instruction::Mult(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, StackValue::Value(lhs.mult(&rhs)?)); + } + Instruction::Div(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, StackValue::Value(lhs.div(&rhs)?)); + } + Instruction::IDiv(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, StackValue::Value(lhs.idiv(&rhs)?)); + } + Instruction::Mod(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, StackValue::Value(lhs.r#mod(&rhs)?)); + } + Instruction::Exp(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, StackValue::Value(lhs.exp(&rhs)?)); + } + + Instruction::BitAnd(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, StackValue::Value(lhs.band(&rhs)?)); + } + Instruction::BitOr(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, StackValue::Value(lhs.bor(&rhs)?)); + } + Instruction::BitXOr(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, StackValue::Value(lhs.bxor(&rhs)?)); + } + Instruction::BitSRight(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, StackValue::Value(lhs.bsright(&rhs)?)); + } + Instruction::BitSLeft(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, StackValue::Value(lhs.bsleft(&rhs)?)); + } + Instruction::Equal(res, lhs, rhs) => { let lhs = self .stack @@ -730,6 +936,7 @@ impl ClosureRunner { .unwrap_or(Value::Nil); self.set_stack(*res, StackValue::Value(lhs.lte(&rhs)?)); } + Instruction::Unm(res, reg) => { self.set_stack( *res, @@ -754,6 +961,31 @@ impl ClosureRunner { ), ); } + Instruction::Not(res, reg) => { + self.set_stack( + *res, + StackValue::Value( + self.stack + .get(reg) + .map(|v| v.borrow().clone()) + .unwrap_or(Value::Nil) + .not()?, + ), + ); + } + Instruction::BitNot(res, reg) => { + self.set_stack( + *res, + StackValue::Value( + self.stack + .get(reg) + .map(|v| v.borrow().clone()) + .unwrap_or(Value::Nil) + .bxor(&Value::Integer(LuaInteger(u64::MAX as i64)))?, + ), + ); + } + Instruction::Or(res, lhs, rhs) => { let lhs = self .stack diff --git a/src/vm/value.rs b/src/vm/value.rs index 7eebeb7..bf1d4e2 100644 --- a/src/vm/value.rs +++ b/src/vm/value.rs @@ -166,6 +166,16 @@ impl Value { _ => Err(RuntimeError::NotFloatable(self.clone())), } } + + pub fn as_bits(&self) -> Result { + match self { + Value::Float(vmfloat) => Ok(LuaInteger(vmfloat.lua_number().0 as i64)), + Value::Integer(lua_integer) => Ok(LuaInteger(lua_integer.0 as i64)), + Value::Boolean(lua_bool) => Ok(LuaInteger(lua_bool.0 as i64)), + Value::Nil => Ok(LuaInteger(0)), + _ => Err(RuntimeError::NotFloatable(self.clone())), + } + } } impl From<&str> for Value { @@ -175,6 +185,27 @@ impl From<&str> for Value { } impl Value { + pub fn concat(&self, other: &Value) -> Result { + match (self, other) { + ( + Value::String(_) | Value::Integer(_) | Value::Boolean(_), + Value::String(_) | Value::Integer(_) | Value::Boolean(_), + ) => Ok(Value::String(format!("{:?}{:?}", self, other))), + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + ) => { + let res = LuaFloat(self.as_float()?.0 * other.as_float()?.0); + Ok(Value::Float(res.vm_number())) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::Concat, + self.clone(), + other.clone(), + )), + } + } + pub fn add(&self, other: &Value) -> Result { match (self, other) { (Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => { @@ -196,6 +227,196 @@ impl Value { } } + pub fn mult(&self, other: &Value) -> Result { + match (self, other) { + (Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => { + let res = LuaInteger(self.as_integer()?.0 * other.as_integer()?.0); + Ok(Value::Integer(res)) + } + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + ) => { + let res = LuaFloat(self.as_float()?.0 * other.as_float()?.0); + Ok(Value::Float(res.vm_number())) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::Mult, + self.clone(), + other.clone(), + )), + } + } + + pub fn div(&self, other: &Value) -> Result { + match (self, other) { + (Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => { + let res = LuaFloat(self.as_integer()?.0 as f64 / other.as_integer()?.0 as f64); + Ok(Value::Float(res.vm_number())) + } + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + ) => { + let res = LuaFloat(self.as_float()?.0 / other.as_float()?.0); + Ok(Value::Float(res.vm_number())) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::Div, + self.clone(), + other.clone(), + )), + } + } + + pub fn idiv(&self, other: &Value) -> Result { + match (self, other) { + (Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => { + let res = LuaInteger(self.as_integer()?.0 / other.as_integer()?.0); + Ok(Value::Integer(res)) + } + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + ) => { + let res = LuaInteger((self.as_float()?.0 / other.as_float()?.0).floor() as i64); + Ok(Value::Integer(res)) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::IDiv, + self.clone(), + other.clone(), + )), + } + } + + pub fn r#mod(&self, other: &Value) -> Result { + match (self, other) { + (Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => { + let res = LuaInteger(self.as_integer()?.0 % other.as_integer()?.0); + Ok(Value::Integer(res)) + } + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + ) => { + let res = LuaFloat(self.as_float()?.0 % other.as_float()?.0); + Ok(Value::Float(res.vm_number())) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::Mod, + self.clone(), + other.clone(), + )), + } + } + + pub fn exp(&self, other: &Value) -> Result { + match (self, other) { + (Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => { + let res = LuaInteger(self.as_integer()?.0.pow(other.as_integer()?.0 as u32)); + Ok(Value::Integer(res)) + } + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + Value::Float(_) | Value::Integer(_) | Value::Boolean(_), + ) => { + let res = LuaFloat(self.as_float()?.0.powf(other.as_float()?.0)); + Ok(Value::Float(res.vm_number())) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::Exp, + self.clone(), + other.clone(), + )), + } + } + + pub fn band(&self, other: &Value) -> Result { + match (self, other) { + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + ) => { + let res = LuaInteger(self.as_bits()?.0 & other.as_bits()?.0); + Ok(Value::Integer(res)) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::BitAnd, + self.clone(), + other.clone(), + )), + } + } + + pub fn bor(&self, other: &Value) -> Result { + match (self, other) { + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + ) => { + let res = LuaInteger(self.as_bits()?.0 | other.as_bits()?.0); + Ok(Value::Integer(res)) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::BitOr, + self.clone(), + other.clone(), + )), + } + } + + pub fn bxor(&self, other: &Value) -> Result { + match (self, other) { + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + ) => { + let res = LuaInteger(self.as_bits()?.0 ^ other.as_bits()?.0); + Ok(Value::Integer(res)) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::BitXOr, + self.clone(), + other.clone(), + )), + } + } + + pub fn bsleft(&self, other: &Value) -> Result { + match (self, other) { + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + ) => { + let res = LuaInteger(self.as_bits()?.0 << other.as_bits()?.0); + Ok(Value::Integer(res)) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::BitSLeft, + self.clone(), + other.clone(), + )), + } + } + + pub fn bsright(&self, other: &Value) -> Result { + match (self, other) { + ( + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil, + ) => { + let res = LuaInteger(self.as_bits()?.0 >> other.as_bits()?.0); + Ok(Value::Integer(res)) + } + _ => Err(RuntimeError::InvalidOperands( + BinaryOperator::BitSRight, + self.clone(), + other.clone(), + )), + } + } + pub fn eq(&self, other: &Value) -> Result { match (self, other) { (Value::Integer(lhs), Value::Integer(rhs)) => { @@ -325,6 +546,14 @@ impl Value { } } + pub fn not(&self) -> Result { + if self.is_truthy() { + Ok(Value::Boolean(LuaBool(false))) + } else { + Ok(Value::Boolean(LuaBool(true))) + } + } + pub fn is_truthy(&self) -> bool { match self { Value::String(_) => true,