Compare commits

...

3 Commits

Author SHA1 Message Date
3360f14913 Make tables indexable via pointer value 2026-03-21 15:21:04 +02:00
10bc804a01 Make tables indexable 2026-03-21 15:17:16 +02:00
ce3ee7a273 Separate metamethod errors from meta-metamethod errors 2026-03-21 15:07:35 +02:00
4 changed files with 72 additions and 59 deletions

View File

@ -109,3 +109,4 @@ SETMETATABLE(table, {
print(table + 5) print(table + 5)
print(table("hello", "there")) print(table("hello", "there"))
print("hello ", table)

View File

@ -25,7 +25,14 @@ impl value::RustFunction for Max {
pub struct Print; pub struct Print;
impl value::RustFunction for Print { impl value::RustFunction for Print {
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> { fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
println!("{:?}", parameters); println!(
"{}",
parameters
.iter()
.map(|v| format!("{}", v))
.collect::<Vec<_>>()
.join("\t")
);
Ok(Vec::new()) Ok(Vec::new())
} }

View File

@ -657,7 +657,7 @@ impl ClosureRunner {
vec![value.unwrap().clone(), index_value.clone()], vec![value.unwrap().clone(), index_value.clone()],
) { ) {
Ok(value) => { Ok(value) => {
StackValue::Value(value.first().unwrap().clone()) StackValue::Value(value?.first().unwrap().clone())
} }
Err(_) => StackValue::Value(Value::Nil), Err(_) => StackValue::Value(Value::Nil),
} }
@ -816,7 +816,7 @@ impl ClosureRunner {
let mut metamethod_params = vec![value.clone()]; let mut metamethod_params = vec![value.clone()];
metamethod_params.extend(params); metamethod_params.extend(params);
let ret_values = let ret_values =
self.call_metamethod(&metatable, "__call", metamethod_params)?; self.call_metamethod(&metatable, "__call", metamethod_params)??;
if *ret_len != 0 { if *ret_len != 0 {
for i in 0..=(*ret_len - 2) { for i in 0..=(*ret_len - 2) {
@ -890,7 +890,7 @@ impl ClosureRunner {
"__concat", "__concat",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
@ -903,7 +903,7 @@ impl ClosureRunner {
"__add", "__add",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::Sub(res, lhs, rhs) => { Instruction::Sub(res, lhs, rhs) => {
@ -915,7 +915,7 @@ impl ClosureRunner {
"__sub", "__sub",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::Mult(res, lhs, rhs) => { Instruction::Mult(res, lhs, rhs) => {
@ -927,7 +927,7 @@ impl ClosureRunner {
"__mult", "__mult",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::Div(res, lhs, rhs) => { Instruction::Div(res, lhs, rhs) => {
@ -939,7 +939,7 @@ impl ClosureRunner {
"__div", "__div",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::IDiv(res, lhs, rhs) => { Instruction::IDiv(res, lhs, rhs) => {
@ -951,7 +951,7 @@ impl ClosureRunner {
"__idiv", "__idiv",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::Mod(res, lhs, rhs) => { Instruction::Mod(res, lhs, rhs) => {
@ -963,7 +963,7 @@ impl ClosureRunner {
"__mod", "__mod",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::Exp(res, lhs, rhs) => { Instruction::Exp(res, lhs, rhs) => {
@ -975,7 +975,7 @@ impl ClosureRunner {
"__exp", "__exp",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
@ -988,7 +988,7 @@ impl ClosureRunner {
"__band", "__band",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::BitOr(res, lhs, rhs) => { Instruction::BitOr(res, lhs, rhs) => {
@ -1000,7 +1000,7 @@ impl ClosureRunner {
"__bor", "__bor",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::BitXOr(res, lhs, rhs) => { Instruction::BitXOr(res, lhs, rhs) => {
@ -1012,7 +1012,7 @@ impl ClosureRunner {
"__bxor", "__bxor",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::BitSRight(res, lhs, rhs) => { Instruction::BitSRight(res, lhs, rhs) => {
@ -1024,7 +1024,7 @@ impl ClosureRunner {
"__shr", "__shr",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
Instruction::BitSLeft(res, lhs, rhs) => { Instruction::BitSLeft(res, lhs, rhs) => {
@ -1036,7 +1036,7 @@ impl ClosureRunner {
"__shl", "__shl",
lhs, lhs,
rhs, rhs,
)?), )??),
); );
} }
@ -1051,7 +1051,7 @@ impl ClosureRunner {
metatable, metatable,
"__eq", "__eq",
vec![lhs.clone(), rhs.clone()], vec![lhs.clone(), rhs.clone()],
)? )??
.first() .first()
.unwrap() .unwrap()
.is_truthy(), .is_truthy(),
@ -1073,7 +1073,7 @@ impl ClosureRunner {
"__lt", "__lt",
lhs.clone(), lhs.clone(),
rhs.clone(), rhs.clone(),
)? )??
.is_truthy(), .is_truthy(),
))), ))),
); );
@ -1088,7 +1088,7 @@ impl ClosureRunner {
"__le", "__le",
lhs.clone(), lhs.clone(),
rhs.clone(), rhs.clone(),
)? )??
.is_truthy(), .is_truthy(),
))), ))),
); );
@ -1115,7 +1115,7 @@ impl ClosureRunner {
value.unm(), value.unm(),
"__unm", "__unm",
value.clone(), value.clone(),
)?), )??),
); );
} }
Instruction::Len(res, reg) => { Instruction::Len(res, reg) => {
@ -1130,7 +1130,7 @@ impl ClosureRunner {
Ok(result) => { Ok(result) => {
self.set_stack( self.set_stack(
*res, *res,
StackValue::Value(result.first().unwrap().clone()), StackValue::Value(result?.first().unwrap().clone()),
); );
} }
Err(_) => { Err(_) => {
@ -1216,20 +1216,20 @@ impl ClosureRunner {
value: Result<Value, RuntimeError>, value: Result<Value, RuntimeError>,
metamethod: &str, metamethod: &str,
param: Value, param: Value,
) -> Result<Value, RuntimeError> { ) -> Result<Result<Value, RuntimeError>, RuntimeError> {
match value { match value {
Ok(value) => Ok(value), Ok(value) => Ok(Ok(value)),
Err(_) => match &param { Err(_) => match &param {
Value::Table { metatable, .. } => { Value::Table { metatable, .. } => {
if metatable if metatable
.borrow() .borrow()
.contains_key(&IndexableValue::String(metamethod.to_owned())) .contains_key(&IndexableValue::String(metamethod.to_owned()))
{ {
Ok(self Ok(extract_ret_value(self.call_metamethod(
.call_metamethod(metatable, metamethod, vec![param.clone()])? metatable,
.into_iter() metamethod,
.next() vec![param.clone()],
.unwrap()) )?))
} else { } else {
Err(RuntimeError::InvalidUnop( Err(RuntimeError::InvalidUnop(
metamethod.to_owned(), metamethod.to_owned(),
@ -1251,35 +1251,31 @@ impl ClosureRunner {
metamethod: &str, metamethod: &str,
lhs: Value, lhs: Value,
rhs: Value, rhs: Value,
) -> Result<Value, RuntimeError> { ) -> Result<Result<Value, RuntimeError>, RuntimeError> {
match value { match value {
Ok(value) => Ok(value), Ok(value) => Ok(Ok(value)),
Err(_) => { Err(_) => {
if let Value::Table { metatable, .. } = &lhs { if let Value::Table { metatable, .. } = &lhs {
if metatable if metatable
.borrow() .borrow()
.contains_key(&IndexableValue::String(metamethod.to_owned())) .contains_key(&IndexableValue::String(metamethod.to_owned()))
{ {
Ok(self Ok(extract_ret_value(self.call_metamethod(
.call_metamethod(&metatable, metamethod, vec![lhs.clone(), rhs])? &metatable,
.into_iter() metamethod,
.next() vec![lhs.clone(), rhs],
.unwrap()) )?))
} else { } else {
if let Value::Table { metatable, .. } = &rhs { if let Value::Table { metatable, .. } = &rhs {
if metatable if metatable
.borrow() .borrow()
.contains_key(&IndexableValue::String(metamethod.to_owned())) .contains_key(&IndexableValue::String(metamethod.to_owned()))
{ {
Ok(self Ok(extract_ret_value(self.call_metamethod(
.call_metamethod(
&metatable, &metatable,
metamethod, metamethod,
vec![lhs, rhs.clone()], vec![lhs, rhs.clone()],
)? )?))
.into_iter()
.next()
.unwrap())
} else { } else {
Err(RuntimeError::InvalidBinop( Err(RuntimeError::InvalidBinop(
metamethod.to_owned(), metamethod.to_owned(),
@ -1300,11 +1296,11 @@ impl ClosureRunner {
.borrow() .borrow()
.contains_key(&IndexableValue::String(metamethod.to_owned())) .contains_key(&IndexableValue::String(metamethod.to_owned()))
{ {
Ok(self Ok(extract_ret_value(self.call_metamethod(
.call_metamethod(&metatable, metamethod, vec![lhs, rhs.clone()])? &metatable,
.into_iter() metamethod,
.next() vec![lhs, rhs.clone()],
.unwrap()) )?))
} else { } else {
Err(RuntimeError::InvalidBinop( Err(RuntimeError::InvalidBinop(
metamethod.to_owned(), metamethod.to_owned(),
@ -1328,25 +1324,28 @@ impl ClosureRunner {
metatable: &Table, metatable: &Table,
metamethod: &str, metamethod: &str,
params: Vec<Value>, params: Vec<Value>,
) -> Result<Vec<Value>, RuntimeError> { ) -> Result<Result<Vec<Value>, RuntimeError>, RuntimeError> {
if let Some(value) = metatable if let Some(value) = metatable
.borrow() .borrow()
.get(&IndexableValue::String(metamethod.to_owned())) .get(&IndexableValue::String(metamethod.to_owned()))
{ {
match value { match value {
Value::RustFunction(function) => { Value::RustFunction(function) => {
let result = function.borrow_mut().execute(params)?; let result = function.borrow_mut().execute(params);
Ok(result) Ok(result)
} }
Value::Function(closure) => { Value::Function(closure) => {
let mut runnable = closure.run(params); let mut runnable = closure.run(params);
#[allow(unused_assignments)] #[allow(unused_assignments)]
let mut return_value = None; let mut return_value = Ok(None);
while { while {
return_value = runnable.next()?; return_value = runnable.next();
return_value.is_none() match return_value {
Ok(None) => true,
_ => false,
}
} {} } {}
Ok(return_value.unwrap()) Ok(return_value.map(|v| v.unwrap()))
} }
_ => Err(RuntimeError::MetafunctionNotCallable(value.clone())), _ => Err(RuntimeError::MetafunctionNotCallable(value.clone())),
} }
@ -1371,3 +1370,7 @@ impl ClosureRunner {
) )
} }
} }
fn extract_ret_value(values: Result<Vec<Value>, RuntimeError>) -> Result<Value, RuntimeError> {
values.map(|v| v.into_iter().next().unwrap())
}

View File

@ -125,7 +125,8 @@ impl Debug for Constant {
} }
} }
pub type Table = Rc<RefCell<HashMap<IndexableValue, Value>>>; pub type Table = Rc<RefCell<TableMap>>;
pub type TableMap = HashMap<IndexableValue, Value>;
#[derive(Clone)] #[derive(Clone)]
pub enum Value { pub enum Value {
@ -151,7 +152,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 { contents, .. } => Ok(IndexableValue::Table(contents.as_ptr())),
} }
} }
@ -201,7 +202,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 { contents, .. } => write!(f, "<table#{}>", contents.as_ptr() as u64),
} }
} }
} }
@ -621,6 +622,7 @@ pub enum IndexableValue {
Bool(LuaBool), Bool(LuaBool),
RustFunction(String), RustFunction(String),
Function(u32), Function(u32),
Table(*mut TableMap),
} }
impl From<&str> for IndexableValue { impl From<&str> for IndexableValue {