Add rudamentary metatables

This commit is contained in:
Sofia 2026-03-20 21:04:24 +02:00
parent 5c4dbacaa7
commit c919f3a6ea
4 changed files with 85 additions and 133 deletions

View File

@ -1,97 +1,9 @@
global b = 5
function add(x) table = { 1, 2, 3 }
return function (y) SETMETATABLE(table, {
x = x + 1 __add = function ()
b = b + 1 return 1
return x + y, 1, 2, b
end
end end
})
function min(x, y) print(table + 5);
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")

View File

@ -889,6 +889,7 @@ 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();

View File

@ -5,11 +5,44 @@ 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, LuaInteger, Table, Value}, vm::value::{Constant, IndexableValue, LuaInteger, RustFunction, 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)
@ -216,7 +249,7 @@ pub struct Prototype {
pub parameters: usize, pub parameters: usize,
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone)]
pub struct VirtualMachine { pub struct VirtualMachine {
pub(super) environment: Table, pub(super) environment: Table,
pub(super) constants: Vec<Constant>, pub(super) constants: Vec<Constant>,
@ -224,6 +257,22 @@ 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;
@ -231,9 +280,7 @@ 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(),
@ -484,7 +531,7 @@ impl ClosureRunner {
*reg, *reg,
StackValue::Value(Value::Table { StackValue::Value(Value::Table {
contents: self.closure.environment.clone(), contents: self.closure.environment.clone(),
metatable: Box::new(Value::Nil), metatable: Rc::new(RefCell::new(HashMap::new())),
}), }),
); );
} else { } else {
@ -602,7 +649,7 @@ impl ClosureRunner {
*reg, *reg,
StackValue::Value(Value::Table { StackValue::Value(Value::Table {
contents: Rc::new(RefCell::new(HashMap::new())), 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), Ok(value) => Ok(value),
Err(_) => match (&lhs, &rhs) { Err(_) => match (&lhs, &rhs) {
(Value::Table { metatable, .. }, _) => { (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, .. }) => { (_, 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( _ => Err(RuntimeError::InvalidOperation(
metamethod.to_owned(), metamethod.to_owned(),
@ -952,13 +999,11 @@ impl ClosureRunner {
fn call_metamethod( fn call_metamethod(
&self, &self,
metatable: Value, metatable: &Table,
metamethod: &str, metamethod: &str,
params: Vec<Value>, params: Vec<Value>,
) -> Result<Value, RuntimeError> { ) -> Result<Value, RuntimeError> {
match metatable { if let Some(value) = metatable
Value::Table { contents, .. } => {
if let Some(value) = contents
.borrow() .borrow()
.get(&IndexableValue::String(metamethod.to_owned())) .get(&IndexableValue::String(metamethod.to_owned()))
{ {
@ -983,9 +1028,6 @@ impl ClosureRunner {
Err(RuntimeError::MetafunctionNotFound(metamethod.to_owned())) Err(RuntimeError::MetafunctionNotFound(metamethod.to_owned()))
} }
} }
_ => Err(RuntimeError::MetatableNotTable(metatable)),
}
}
fn lhs_and_rhs(&self, lhs: &u16, rhs: &u16) -> (Value, Value) { fn lhs_and_rhs(&self, lhs: &u16, rhs: &u16) -> (Value, Value) {
( (

View File

@ -136,10 +136,7 @@ pub enum Value {
RustFunction(Rc<RefCell<dyn RustFunction>>), RustFunction(Rc<RefCell<dyn RustFunction>>),
Function(Closure), Function(Closure),
Nil, Nil,
Table { Table { contents: Table, metatable: Table },
contents: Table,
metatable: Box<Value>,
},
} }
impl Value { impl Value {