diff --git a/examples/test.lua b/examples/test.lua index bc22765..c88c080 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1,97 +1,9 @@ -global b = 5 -function add(x) - return function (y) - x = x + 1 - b = b + 1 - return x + y, 1, 2, b +table = { 1, 2, 3 } +SETMETATABLE(table, { + __add = function () + return 1 end -end +}) -function min(x, y) - local m = x - if y < x then - m = y - end - return m -end - - -function f(x, ...) - local b = {10, ..., add(10)(15)} - return x + 5, b -end - -global sometable = {} -sometable["hello"] = { 100, 150, add(10)(15) } -print(#sometable["hello"]) -sometable["hello"].there = "my dude" -print(sometable.hello.there) - -print(max(11.12345, 9)) -print(add(10)(15)) -print(add(10)(15)) -print(b) -print(min(11, 9)) -print(10 - 15) -print("hello there!") -print(true or 0) - -global value, table = f(10, 11, 12) - -print("hello") -for i=1,#table do - print(table[i]) - if i > 2 then - goto test - end -end -::test:: - -local test = table[1] -if test == 10 then - print("first") -elseif test == 11 then - print("second") -else - print("third") -end -print("after if/elseif/else") - - -local i = 0 -print("before") -while i < 10 do - i = i + 1 - print(i) -end -print("after while") - - -local i = 0 -print("before") -repeat - i = i + 1 - print(i) -until i >= 10 -print("after repeat") - - -function ipairs(t) - print("inside!") - local i = 0 - return function (state, control) - print(state, control) - i = i + 1 - if i > #table then - return nil, nil - end - return i, t[i] - end, "otus", "potus" -end - -for k, v in (ipairs(table)) do - print(k, v) -end - -print("hello " .. "there") \ No newline at end of file +print(table + 5); \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 26f2648..9806094 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -889,6 +889,7 @@ impl Parse for TableConstructorEntry { (stream.peek(), stream.peek2()) { let key = stream.parse::>()?; + dbg!(&key); let key = key.with(Expression::Literal(Literal::String(key.kind.clone()))); if let Some(Token::Symbol('=')) = stream.peek() { stream.next(); diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 3a55f7b..9fbba7b 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -5,11 +5,44 @@ use std::{cell::RefCell, collections::HashMap, fmt::Debug, i64, rc::Rc}; use crate::{ CompilationUnit, ast::{BinaryOperator, UnaryOperator}, - vm::value::{Constant, IndexableValue, LuaInteger, Table, Value}, + vm::value::{Constant, IndexableValue, LuaInteger, RustFunction, Table, Value}, }; pub mod value; +#[derive(Debug)] +pub struct SetMetatable; +impl RustFunction for SetMetatable { + fn execute(&self, parameters: Vec) -> Result, 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)] pub enum Instruction { /// R(A) := R(B) @@ -216,7 +249,7 @@ pub struct Prototype { pub parameters: usize, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct VirtualMachine { pub(super) environment: Table, pub(super) constants: Vec, @@ -224,6 +257,22 @@ pub struct VirtualMachine { 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 { pub fn new_prototype(&mut self, instructions: Prototype) -> u32 { let proto_id = self.proto_counter; @@ -231,9 +280,7 @@ impl VirtualMachine { self.prototypes.insert(proto_id, instructions); proto_id } -} -impl VirtualMachine { pub(crate) fn create_closure(&self, prototype: u32) -> Closure { Closure { vm: self.clone(), @@ -484,7 +531,7 @@ impl ClosureRunner { *reg, StackValue::Value(Value::Table { contents: self.closure.environment.clone(), - metatable: Box::new(Value::Nil), + metatable: Rc::new(RefCell::new(HashMap::new())), }), ); } else { @@ -602,7 +649,7 @@ impl ClosureRunner { *reg, StackValue::Value(Value::Table { contents: Rc::new(RefCell::new(HashMap::new())), - metatable: Box::new(Value::Nil), + metatable: Rc::new(RefCell::new(HashMap::new())), }), ); } @@ -936,10 +983,10 @@ impl ClosureRunner { Ok(value) => Ok(value), Err(_) => match (&lhs, &rhs) { (Value::Table { metatable, .. }, _) => { - self.call_metamethod(*metatable.clone(), metamethod, vec![lhs, rhs]) + self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()]) } (_, Value::Table { metatable, .. }) => { - self.call_metamethod(*metatable.clone(), metamethod, vec![rhs, lhs]) + self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()]) } _ => Err(RuntimeError::InvalidOperation( metamethod.to_owned(), @@ -952,38 +999,33 @@ impl ClosureRunner { fn call_metamethod( &self, - metatable: Value, + metatable: &Table, metamethod: &str, params: Vec, ) -> Result { - match metatable { - Value::Table { contents, .. } => { - if let Some(value) = contents - .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())) + 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())), } - _ => Err(RuntimeError::MetatableNotTable(metatable)), + } else { + Err(RuntimeError::MetafunctionNotFound(metamethod.to_owned())) } } diff --git a/src/vm/value.rs b/src/vm/value.rs index 58835f6..136bd50 100644 --- a/src/vm/value.rs +++ b/src/vm/value.rs @@ -136,10 +136,7 @@ pub enum Value { RustFunction(Rc>), Function(Closure), Nil, - Table { - contents: Table, - metatable: Box, - }, + Table { contents: Table, metatable: Table }, } impl Value {