Add all operators to VM properly
This commit is contained in:
parent
ed5c9d8b8f
commit
68da93541d
105
src/compile.rs
105
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)
|
||||
|
||||
234
src/vm/mod.rs
234
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
|
||||
|
||||
229
src/vm/value.rs
229
src/vm/value.rs
@ -166,6 +166,16 @@ impl Value {
|
||||
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bits(&self) -> Result<LuaInteger, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
match (self, other) {
|
||||
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||
@ -196,6 +227,196 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mult(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
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<Value, RuntimeError> {
|
||||
match (self, other) {
|
||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||
@ -325,6 +546,14 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not(&self) -> Result<Value, RuntimeError> {
|
||||
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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user