Compare commits
No commits in common. "526d8ada4763b96c78b83f857df7521fa1f08dfe" and "4ac41e7df19fe51fa27e5da79a80993036f8ad03" have entirely different histories.
526d8ada47
...
4ac41e7df1
@ -95,12 +95,3 @@ for k, v in (ipairs(table)) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
print("hello " .. "there")
|
print("hello " .. "there")
|
||||||
|
|
||||||
|
|
||||||
SETMETATABLE(table, {
|
|
||||||
__add = function ()
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
print(table + 5)
|
|
||||||
@ -889,7 +889,6 @@ impl Parse for TableConstructorEntry {
|
|||||||
(stream.peek(), stream.peek2())
|
(stream.peek(), stream.peek2())
|
||||||
{
|
{
|
||||||
let key = stream.parse::<Node<String>>()?;
|
let key = stream.parse::<Node<String>>()?;
|
||||||
dbg!(&key);
|
|
||||||
let key = key.with(Expression::Literal(Literal::String(key.kind.clone())));
|
let key = key.with(Expression::Literal(Literal::String(key.kind.clone())));
|
||||||
if let Some(Token::Symbol('=')) = stream.peek() {
|
if let Some(Token::Symbol('=')) = stream.peek() {
|
||||||
stream.next();
|
stream.next();
|
||||||
|
|||||||
389
src/vm/mod.rs
389
src/vm/mod.rs
@ -5,44 +5,11 @@ use std::{cell::RefCell, collections::HashMap, fmt::Debug, i64, rc::Rc};
|
|||||||
use crate::{
|
use crate::{
|
||||||
CompilationUnit,
|
CompilationUnit,
|
||||||
ast::{BinaryOperator, UnaryOperator},
|
ast::{BinaryOperator, UnaryOperator},
|
||||||
vm::value::{Constant, IndexableValue, LuaBool, LuaInteger, RustFunction, Table, Value},
|
vm::value::{Constant, IndexableValue, LuaInteger, Table, Value},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SetMetatable;
|
|
||||||
impl RustFunction for SetMetatable {
|
|
||||||
fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError> {
|
|
||||||
let table = parameters
|
|
||||||
.get(0)
|
|
||||||
.ok_or(RuntimeError::NotTable(Value::Nil))?;
|
|
||||||
let metatable = parameters
|
|
||||||
.get(1)
|
|
||||||
.ok_or(RuntimeError::NotTable(Value::Nil))?;
|
|
||||||
|
|
||||||
match table {
|
|
||||||
Value::Table {
|
|
||||||
metatable: inner, ..
|
|
||||||
} => match metatable {
|
|
||||||
Value::Table {
|
|
||||||
contents: metatable,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
*inner.borrow_mut() = metatable.borrow().clone();
|
|
||||||
Ok(Vec::new())
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::NotTable(metatable.clone())),
|
|
||||||
},
|
|
||||||
_ => Err(RuntimeError::NotTable(table.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_indexable(&self) -> String {
|
|
||||||
"SETMETATABLE".to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
/// R(A) := R(B)
|
/// R(A) := R(B)
|
||||||
@ -77,8 +44,6 @@ pub enum Instruction {
|
|||||||
|
|
||||||
/// R(A) := R(B) + R(C)
|
/// R(A) := R(B) + R(C)
|
||||||
Add(u16, u16, u16),
|
Add(u16, u16, u16),
|
||||||
/// R(A) := R(B) - R(C)
|
|
||||||
Sub(u16, u16, u16),
|
|
||||||
/// R(A) := R(B) * R(C)
|
/// R(A) := R(B) * R(C)
|
||||||
Mult(u16, u16, u16),
|
Mult(u16, u16, u16),
|
||||||
/// R(A) := R(B) / R(C)
|
/// R(A) := R(B) / R(C)
|
||||||
@ -187,7 +152,6 @@ impl Debug for Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2),
|
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2),
|
||||||
Instruction::Sub(arg0, arg1, arg2) => write!(f, "SUB {} {} {}", arg0, arg1, arg2),
|
|
||||||
Instruction::Mult(arg0, arg1, arg2) => write!(f, "MUL {} {} {}", 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::Div(arg0, arg1, arg2) => write!(f, "DIV {} {} {}", arg0, arg1, arg2),
|
||||||
Instruction::IDiv(arg0, arg1, arg2) => write!(f, "IDIV {} {} {}", arg0, arg1, arg2),
|
Instruction::IDiv(arg0, arg1, arg2) => write!(f, "IDIV {} {} {}", arg0, arg1, arg2),
|
||||||
@ -218,16 +182,6 @@ impl Debug for Instruction {
|
|||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
#[error("Unable to perform {0:?} operator between {1:?} and {2:?}")]
|
#[error("Unable to perform {0:?} operator between {1:?} and {2:?}")]
|
||||||
InvalidOperands(BinaryOperator, Value, Value),
|
InvalidOperands(BinaryOperator, Value, Value),
|
||||||
#[error("Unable to call metamethod {0} for values {1:?} and {2:?}")]
|
|
||||||
InvalidBinop(String, Value, Value),
|
|
||||||
#[error("Unable to call metamethod {0} for value {1:?}")]
|
|
||||||
InvalidUnop(String, Value),
|
|
||||||
#[error("Metatable is not a table: {0:?}")]
|
|
||||||
MetatableNotTable(Value),
|
|
||||||
#[error("Metafunction not found: {0}")]
|
|
||||||
MetafunctionNotFound(String),
|
|
||||||
#[error("Metafunction is not callable: {0:?}")]
|
|
||||||
MetafunctionNotCallable(Value),
|
|
||||||
#[error("Unable to perform {0:?} operator to {1:?}")]
|
#[error("Unable to perform {0:?} operator to {1:?}")]
|
||||||
InvalidOperand(UnaryOperator, Value),
|
InvalidOperand(UnaryOperator, Value),
|
||||||
#[error("Tried calling a non-function: {0:?}")]
|
#[error("Tried calling a non-function: {0:?}")]
|
||||||
@ -254,7 +208,7 @@ pub struct Prototype {
|
|||||||
pub parameters: usize,
|
pub parameters: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct VirtualMachine {
|
pub struct VirtualMachine {
|
||||||
pub(super) environment: Table,
|
pub(super) environment: Table,
|
||||||
pub(super) constants: Vec<Constant>,
|
pub(super) constants: Vec<Constant>,
|
||||||
@ -262,22 +216,6 @@ pub struct VirtualMachine {
|
|||||||
pub(super) proto_counter: u32,
|
pub(super) proto_counter: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VirtualMachine {
|
|
||||||
fn default() -> Self {
|
|
||||||
let environment: Table = Default::default();
|
|
||||||
environment.borrow_mut().insert(
|
|
||||||
IndexableValue::String("SETMETATABLE".into()),
|
|
||||||
SetMetatable.into(),
|
|
||||||
);
|
|
||||||
Self {
|
|
||||||
environment,
|
|
||||||
constants: Default::default(),
|
|
||||||
prototypes: Default::default(),
|
|
||||||
proto_counter: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VirtualMachine {
|
impl VirtualMachine {
|
||||||
pub fn new_prototype(&mut self, instructions: Prototype) -> u32 {
|
pub fn new_prototype(&mut self, instructions: Prototype) -> u32 {
|
||||||
let proto_id = self.proto_counter;
|
let proto_id = self.proto_counter;
|
||||||
@ -285,7 +223,9 @@ impl VirtualMachine {
|
|||||||
self.prototypes.insert(proto_id, instructions);
|
self.prototypes.insert(proto_id, instructions);
|
||||||
proto_id
|
proto_id
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualMachine {
|
||||||
pub(crate) fn create_closure(&self, prototype: u32) -> Closure {
|
pub(crate) fn create_closure(&self, prototype: u32) -> Closure {
|
||||||
Closure {
|
Closure {
|
||||||
vm: self.clone(),
|
vm: self.clone(),
|
||||||
@ -534,10 +474,7 @@ impl ClosureRunner {
|
|||||||
{
|
{
|
||||||
self.set_stack(
|
self.set_stack(
|
||||||
*reg,
|
*reg,
|
||||||
StackValue::Value(Value::Table {
|
StackValue::Value(Value::Table(self.closure.environment.clone())),
|
||||||
contents: self.closure.environment.clone(),
|
|
||||||
metatable: Rc::new(RefCell::new(HashMap::new())),
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let environment = self.closure.environment.borrow_mut().clone();
|
let environment = self.closure.environment.borrow_mut().clone();
|
||||||
@ -570,7 +507,7 @@ impl ClosureRunner {
|
|||||||
match table {
|
match table {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let mut table = value.borrow_mut();
|
let mut table = value.borrow_mut();
|
||||||
if let Value::Table { contents, .. } = &mut *table {
|
if let Value::Table(table) = &mut *table {
|
||||||
let index_value = self
|
let index_value = self
|
||||||
.stack
|
.stack
|
||||||
.get(indexreg)
|
.get(indexreg)
|
||||||
@ -584,10 +521,10 @@ impl ClosureRunner {
|
|||||||
.unwrap_or(Value::Nil);
|
.unwrap_or(Value::Nil);
|
||||||
match value {
|
match value {
|
||||||
Value::Nil => {
|
Value::Nil => {
|
||||||
contents.borrow_mut().remove(&index_value);
|
table.borrow_mut().remove(&index_value);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
contents.borrow_mut().insert(index_value, value);
|
table.borrow_mut().insert(index_value, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -601,8 +538,8 @@ impl ClosureRunner {
|
|||||||
let value = match self.stack.get(tablereg).cloned() {
|
let value = match self.stack.get(tablereg).cloned() {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let table = value.borrow();
|
let table = value.borrow();
|
||||||
if let Value::Table { contents, .. } = &*table {
|
if let Value::Table(table) = &*table {
|
||||||
let table = contents.borrow();
|
let table = table.borrow();
|
||||||
let index_value = self
|
let index_value = self
|
||||||
.stack
|
.stack
|
||||||
.get(indexreg)
|
.get(indexreg)
|
||||||
@ -630,12 +567,12 @@ impl ClosureRunner {
|
|||||||
match table {
|
match table {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let mut table = value.borrow_mut();
|
let mut table = value.borrow_mut();
|
||||||
if let Value::Table { contents, .. } = &mut *table {
|
if let Value::Table(table) = &mut *table {
|
||||||
let mut counter = *start_idx as i64;
|
let mut counter = *start_idx as i64;
|
||||||
for i in self.function_register..self.top {
|
for i in self.function_register..self.top {
|
||||||
let value = self.get_stack(i + 1);
|
let value = self.get_stack(i + 1);
|
||||||
match value {
|
match value {
|
||||||
StackValue::Value(value) => contents.borrow_mut().insert(
|
StackValue::Value(value) => table.borrow_mut().insert(
|
||||||
IndexableValue::Integer(LuaInteger(counter)),
|
IndexableValue::Integer(LuaInteger(counter)),
|
||||||
value.clone(),
|
value.clone(),
|
||||||
),
|
),
|
||||||
@ -652,10 +589,7 @@ impl ClosureRunner {
|
|||||||
Instruction::NewTable(reg) => {
|
Instruction::NewTable(reg) => {
|
||||||
self.set_stack(
|
self.set_stack(
|
||||||
*reg,
|
*reg,
|
||||||
StackValue::Value(Value::Table {
|
StackValue::Value(Value::Table(Rc::new(RefCell::new(HashMap::new())))),
|
||||||
contents: Rc::new(RefCell::new(HashMap::new())),
|
|
||||||
metatable: Rc::new(RefCell::new(HashMap::new())),
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Instruction::Jmp(b) => {
|
Instruction::Jmp(b) => {
|
||||||
@ -806,213 +740,66 @@ impl ClosureRunner {
|
|||||||
|
|
||||||
Instruction::Concat(res, lhs, rhs) => {
|
Instruction::Concat(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.concat(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.concat(&rhs),
|
|
||||||
"__concat",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Add(res, lhs, rhs) => {
|
Instruction::Add(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.add(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.add(&rhs),
|
|
||||||
"__add",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Instruction::Sub(res, lhs, rhs) => {
|
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
|
||||||
self.set_stack(
|
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
rhs.unm().and_then(|rhs| lhs.add(&rhs)),
|
|
||||||
"__sub",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::Mult(res, lhs, rhs) => {
|
Instruction::Mult(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.mult(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.mult(&rhs),
|
|
||||||
"__mult",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::Div(res, lhs, rhs) => {
|
Instruction::Div(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.div(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.div(&rhs),
|
|
||||||
"__div",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::IDiv(res, lhs, rhs) => {
|
Instruction::IDiv(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.idiv(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.idiv(&rhs),
|
|
||||||
"__idiv",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::Mod(res, lhs, rhs) => {
|
Instruction::Mod(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.r#mod(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.r#mod(&rhs),
|
|
||||||
"__mod",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::Exp(res, lhs, rhs) => {
|
Instruction::Exp(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.exp(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.exp(&rhs),
|
|
||||||
"__exp",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BitAnd(res, lhs, rhs) => {
|
Instruction::BitAnd(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.band(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.band(&rhs),
|
|
||||||
"__band",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::BitOr(res, lhs, rhs) => {
|
Instruction::BitOr(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.bor(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.bor(&rhs),
|
|
||||||
"__bor",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::BitXOr(res, lhs, rhs) => {
|
Instruction::BitXOr(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.bxor(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.bxor(&rhs),
|
|
||||||
"__bxor",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::BitSRight(res, lhs, rhs) => {
|
Instruction::BitSRight(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.bsright(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.bsright(&rhs),
|
|
||||||
"__shr",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::BitSLeft(res, lhs, rhs) => {
|
Instruction::BitSLeft(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.bsleft(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(self.result_or_metamethod_binop(
|
|
||||||
lhs.bsleft(&rhs),
|
|
||||||
"__shl",
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
)?),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Equal(res, lhs, rhs) => {
|
Instruction::Equal(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
match (&lhs, &rhs) {
|
self.set_stack(*res, StackValue::Value(lhs.eq(&rhs)?));
|
||||||
(Value::Table { metatable, .. }, Value::Table { .. }) => {
|
|
||||||
self.set_stack(
|
|
||||||
*res,
|
|
||||||
StackValue::Value(Value::Boolean(LuaBool(
|
|
||||||
self.call_metamethod(
|
|
||||||
metatable,
|
|
||||||
"__eq",
|
|
||||||
vec![lhs.clone(), rhs.clone()],
|
|
||||||
)?
|
|
||||||
.is_truthy(),
|
|
||||||
))),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.set_stack(*res, StackValue::Value(lhs.eq(&rhs)?));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Instruction::LessThan(res, lhs, rhs) => {
|
Instruction::LessThan(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.lt(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(Value::Boolean(LuaBool(
|
|
||||||
self.result_or_metamethod_binop(
|
|
||||||
lhs.lt(&rhs),
|
|
||||||
"__lt",
|
|
||||||
lhs.clone(),
|
|
||||||
rhs.clone(),
|
|
||||||
)?
|
|
||||||
.is_truthy(),
|
|
||||||
))),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Instruction::LessThanOrEqual(res, lhs, rhs) => {
|
Instruction::LessThanOrEqual(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(
|
self.set_stack(*res, StackValue::Value(lhs.lte(&rhs)?));
|
||||||
*res,
|
|
||||||
StackValue::Value(Value::Boolean(LuaBool(
|
|
||||||
self.result_or_metamethod_binop(
|
|
||||||
lhs.lte(&rhs),
|
|
||||||
"__le",
|
|
||||||
lhs.clone(),
|
|
||||||
rhs.clone(),
|
|
||||||
)?
|
|
||||||
.is_truthy(),
|
|
||||||
))),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Or(res, lhs, rhs) => {
|
Instruction::Or(res, lhs, rhs) => {
|
||||||
@ -1025,41 +812,28 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Unm(res, reg) => {
|
Instruction::Unm(res, reg) => {
|
||||||
let value = self
|
|
||||||
.stack
|
|
||||||
.get(reg)
|
|
||||||
.map(|v| v.borrow().clone())
|
|
||||||
.unwrap_or(Value::Nil);
|
|
||||||
self.set_stack(
|
self.set_stack(
|
||||||
*res,
|
*res,
|
||||||
StackValue::Value(self.result_or_metamethod_unop(
|
StackValue::Value(
|
||||||
value.unm(),
|
self.stack
|
||||||
"__unm",
|
.get(reg)
|
||||||
value.clone(),
|
.map(|v| v.borrow().clone())
|
||||||
)?),
|
.unwrap_or(Value::Nil)
|
||||||
|
.unm()?,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Instruction::Len(res, reg) => {
|
Instruction::Len(res, reg) => {
|
||||||
let value = self
|
self.set_stack(
|
||||||
.stack
|
*res,
|
||||||
.get(reg)
|
StackValue::Value(
|
||||||
.map(|v| v.borrow().clone())
|
self.stack
|
||||||
.unwrap_or(Value::Nil);
|
.get(reg)
|
||||||
match &value {
|
.map(|v| v.borrow().clone())
|
||||||
Value::Table { metatable, .. } => {
|
.unwrap_or(Value::Nil)
|
||||||
match self.call_metamethod(&metatable, "__len", vec![value.clone()]) {
|
.len()?,
|
||||||
Ok(result) => {
|
),
|
||||||
self.set_stack(*res, StackValue::Value(result));
|
);
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
self.set_stack(*res, StackValue::Value(value.len()?));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.set_stack(*res, StackValue::Value(value.len()?));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Instruction::Not(res, reg) => {
|
Instruction::Not(res, reg) => {
|
||||||
self.set_stack(
|
self.set_stack(
|
||||||
@ -1129,79 +903,6 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn result_or_metamethod_unop(
|
|
||||||
&self,
|
|
||||||
value: Result<Value, RuntimeError>,
|
|
||||||
metamethod: &str,
|
|
||||||
param: Value,
|
|
||||||
) -> Result<Value, RuntimeError> {
|
|
||||||
match value {
|
|
||||||
Ok(value) => Ok(value),
|
|
||||||
Err(_) => match ¶m {
|
|
||||||
Value::Table { metatable, .. } => {
|
|
||||||
self.call_metamethod(metatable, metamethod, vec![param.clone()])
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::InvalidUnop(
|
|
||||||
metamethod.to_owned(),
|
|
||||||
param.clone(),
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result_or_metamethod_binop(
|
|
||||||
&self,
|
|
||||||
value: Result<Value, RuntimeError>,
|
|
||||||
metamethod: &str,
|
|
||||||
lhs: Value,
|
|
||||||
rhs: Value,
|
|
||||||
) -> Result<Value, RuntimeError> {
|
|
||||||
match value {
|
|
||||||
Ok(value) => Ok(value),
|
|
||||||
Err(_) => match (&lhs, &rhs) {
|
|
||||||
(Value::Table { metatable, .. }, _) => {
|
|
||||||
self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()])
|
|
||||||
}
|
|
||||||
(_, Value::Table { metatable, .. }) => {
|
|
||||||
self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()])
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::InvalidBinop(metamethod.to_owned(), lhs, rhs)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_metamethod(
|
|
||||||
&self,
|
|
||||||
metatable: &Table,
|
|
||||||
metamethod: &str,
|
|
||||||
params: Vec<Value>,
|
|
||||||
) -> Result<Value, RuntimeError> {
|
|
||||||
if let Some(value) = metatable
|
|
||||||
.borrow()
|
|
||||||
.get(&IndexableValue::String(metamethod.to_owned()))
|
|
||||||
{
|
|
||||||
match value {
|
|
||||||
Value::RustFunction(function) => {
|
|
||||||
let result = function.borrow_mut().execute(params)?;
|
|
||||||
Ok(result.into_iter().next().unwrap())
|
|
||||||
}
|
|
||||||
Value::Function(closure) => {
|
|
||||||
let mut runnable = closure.run(params);
|
|
||||||
#[allow(unused_assignments)]
|
|
||||||
let mut return_value = None;
|
|
||||||
while {
|
|
||||||
return_value = runnable.next()?;
|
|
||||||
return_value.is_none()
|
|
||||||
} {}
|
|
||||||
Ok(return_value.unwrap().into_iter().next().unwrap())
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::MetafunctionNotCallable(value.clone())),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(RuntimeError::MetafunctionNotFound(metamethod.to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lhs_and_rhs(&self, lhs: &u16, rhs: &u16) -> (Value, Value) {
|
fn lhs_and_rhs(&self, lhs: &u16, rhs: &u16) -> (Value, Value) {
|
||||||
(
|
(
|
||||||
self.stack
|
self.stack
|
||||||
|
|||||||
@ -136,7 +136,7 @@ pub enum Value {
|
|||||||
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
||||||
Function(Closure),
|
Function(Closure),
|
||||||
Nil,
|
Nil,
|
||||||
Table { contents: Table, metatable: Table },
|
Table(Table),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
@ -151,7 +151,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
Value::Function(closure) => Ok(IndexableValue::Function(closure.prototype)),
|
Value::Function(closure) => Ok(IndexableValue::Function(closure.prototype)),
|
||||||
Value::Nil => Err(RuntimeError::InvalidTableIndex(self)),
|
Value::Nil => Err(RuntimeError::InvalidTableIndex(self)),
|
||||||
Value::Table { .. } => Err(RuntimeError::InvalidTableIndex(self)),
|
Value::Table(_) => Err(RuntimeError::InvalidTableIndex(self)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ impl Display for Value {
|
|||||||
}
|
}
|
||||||
Value::Function(closure) => write!(f, "<function({})>", closure.prototype),
|
Value::Function(closure) => write!(f, "<function({})>", closure.prototype),
|
||||||
Value::Nil => write!(f, "nil"),
|
Value::Nil => write!(f, "nil"),
|
||||||
Value::Table { .. } => write!(f, "<table>"),
|
Value::Table(_) => write!(f, "<table>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,8 +514,8 @@ impl Value {
|
|||||||
pub fn len(&self) -> Result<Value, RuntimeError> {
|
pub fn len(&self) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::String(value) => Ok(Self::Integer(LuaInteger(value.len() as i64))),
|
Value::String(value) => Ok(Self::Integer(LuaInteger(value.len() as i64))),
|
||||||
Value::Table { contents, .. } => {
|
Value::Table(table) => {
|
||||||
let table = contents.borrow();
|
let table = table.borrow();
|
||||||
let mut int_indexes = table
|
let mut int_indexes = table
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|v| match v {
|
.filter(|v| match v {
|
||||||
@ -585,7 +585,7 @@ impl Value {
|
|||||||
Value::RustFunction(_) => true,
|
Value::RustFunction(_) => true,
|
||||||
Value::Function(_) => true,
|
Value::Function(_) => true,
|
||||||
Value::Nil => false,
|
Value::Nil => false,
|
||||||
Value::Table { .. } => true,
|
Value::Table(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -602,9 +602,9 @@ impl Debug for Value {
|
|||||||
.debug_tuple(&format!("Function({})", closure.prototype))
|
.debug_tuple(&format!("Function({})", closure.prototype))
|
||||||
.finish(),
|
.finish(),
|
||||||
Value::Nil => write!(f, "Nil"),
|
Value::Nil => write!(f, "Nil"),
|
||||||
Value::Table { contents, .. } => {
|
Value::Table(hash_map) => {
|
||||||
let mut table = f.debug_struct("Table");
|
let mut table = f.debug_struct("Table");
|
||||||
for (key, value) in contents.borrow().iter() {
|
for (key, value) in hash_map.borrow().iter() {
|
||||||
table.field(&format!("{:?}", key), value);
|
table.field(&format!("{:?}", key), value);
|
||||||
}
|
}
|
||||||
table.finish()
|
table.finish()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user