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)
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")
print(table + 5);

View File

@ -889,6 +889,7 @@ impl Parse for TableConstructorEntry {
(stream.peek(), stream.peek2())
{
let key = stream.parse::<Node<String>>()?;
dbg!(&key);
let key = key.with(Expression::Literal(Literal::String(key.kind.clone())));
if let Some(Token::Symbol('=')) = stream.peek() {
stream.next();

View File

@ -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<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)]
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<Constant>,
@ -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<Value>,
) -> Result<Value, RuntimeError> {
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()))
}
}

View File

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