Update how result_or_metamethod-functions work

This commit is contained in:
Sofia 2026-03-21 15:38:35 +02:00
parent 76fa290988
commit 8a50965f2e
2 changed files with 63 additions and 146 deletions

View File

@ -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,33 +1036,24 @@ impl ClosureRunner {
"__shl", "__shl",
lhs, lhs,
rhs, 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);
self.set_stack(
let metatable = match (&lhs, &rhs) { *res,
(Value::Table { metatable, .. }, _) => Some(metatable), StackValue::Value(Value::Boolean(LuaBool(
(_, Value::Table { metatable, .. }) => Some(metatable), self.result_or_metamethod_binop(
_ => todo!(), lhs.eq(&rhs),
};
let value = if let Some(metatable) = metatable {
match self.call_metamethod(
metatable,
"__eq", "__eq",
vec![lhs.clone(), rhs.clone()], lhs.clone(),
) { rhs.clone(),
Ok(value) => StackValue::Value(extract_ret_value(value)?), )?
Err(_) => StackValue::Value(lhs.eq(&rhs)?), .is_truthy(),
} ))),
} else { );
StackValue::Value(lhs.eq(&rhs)?)
};
self.set_stack(*res, value);
} }
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);
@ -1074,7 +1065,7 @@ impl ClosureRunner {
"__lt", "__lt",
lhs.clone(), lhs.clone(),
rhs.clone(), rhs.clone(),
)?? )?
.is_truthy(), .is_truthy(),
))), ))),
); );
@ -1089,7 +1080,7 @@ impl ClosureRunner {
"__le", "__le",
lhs.clone(), lhs.clone(),
rhs.clone(), rhs.clone(),
)?? )?
.is_truthy(), .is_truthy(),
))), ))),
); );
@ -1116,7 +1107,7 @@ impl ClosureRunner {
value.unm(), value.unm(),
"__unm", "__unm",
value.clone(), value.clone(),
)??), )?),
); );
} }
Instruction::Len(res, reg) => { Instruction::Len(res, reg) => {
@ -1125,25 +1116,15 @@ impl ClosureRunner {
.get(reg) .get(reg)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
match &value {
Value::Table { metatable, .. } => {
match self.call_metamethod(&metatable, "__len", vec![value.clone()]) {
Ok(result) => {
self.set_stack( self.set_stack(
*res, *res,
StackValue::Value(result?.first().unwrap().clone()), StackValue::Value(self.result_or_metamethod_unop(
value.len(),
"__len",
value.clone(),
)?),
); );
} }
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(
*res, *res,
@ -1217,32 +1198,16 @@ impl ClosureRunner {
value: Result<Value, RuntimeError>, value: Result<Value, RuntimeError>,
metamethod: &str, metamethod: &str,
param: Value, param: Value,
) -> Result<Result<Value, RuntimeError>, RuntimeError> { ) -> Result<Value, RuntimeError> {
match value { let metatable = extract_metatable(&param);
Ok(value) => Ok(Ok(value)),
Err(_) => match &param { if let Some(metatable) = metatable {
Value::Table { metatable, .. } => { match self.call_metamethod(metatable, metamethod, vec![param.clone()]) {
if metatable Ok(value) => extract_ret_value(value),
.borrow() Err(_) => value,
.contains_key(&IndexableValue::String(metamethod.to_owned())) }
{
Ok(extract_ret_value(self.call_metamethod(
metatable,
metamethod,
vec![param.clone()],
)?))
} else { } else {
Err(RuntimeError::InvalidUnop( value
metamethod.to_owned(),
param.clone(),
))
}
}
_ => Err(RuntimeError::InvalidUnop(
metamethod.to_owned(),
param.clone(),
)),
},
} }
} }
@ -1252,71 +1217,16 @@ impl ClosureRunner {
metamethod: &str, metamethod: &str,
lhs: Value, lhs: Value,
rhs: Value, rhs: Value,
) -> Result<Result<Value, RuntimeError>, RuntimeError> { ) -> Result<Value, RuntimeError> {
match value { let metatable = extract_metatable(&lhs).or(extract_metatable(&rhs));
Ok(value) => Ok(Ok(value)),
Err(_) => { if let Some(metatable) = metatable {
if let Value::Table { metatable, .. } = &lhs { match self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()]) {
if metatable Ok(value) => extract_ret_value(value),
.borrow() Err(_) => value,
.contains_key(&IndexableValue::String(metamethod.to_owned()))
{
Ok(extract_ret_value(self.call_metamethod(
&metatable,
metamethod,
vec![lhs.clone(), rhs],
)?))
} else {
if let Value::Table { metatable, .. } = &rhs {
if metatable
.borrow()
.contains_key(&IndexableValue::String(metamethod.to_owned()))
{
Ok(extract_ret_value(self.call_metamethod(
&metatable,
metamethod,
vec![lhs, rhs.clone()],
)?))
} else {
Err(RuntimeError::InvalidBinop(
metamethod.to_owned(),
lhs.clone(),
rhs.clone(),
))
} }
} else { } else {
Err(RuntimeError::InvalidBinop( value
metamethod.to_owned(),
lhs.clone(),
rhs.clone(),
))
}
}
} else if let Value::Table { metatable, .. } = &rhs {
if metatable
.borrow()
.contains_key(&IndexableValue::String(metamethod.to_owned()))
{
Ok(extract_ret_value(self.call_metamethod(
&metatable,
metamethod,
vec![lhs, rhs.clone()],
)?))
} else {
Err(RuntimeError::InvalidBinop(
metamethod.to_owned(),
lhs.clone(),
rhs.clone(),
))
}
} else {
Err(RuntimeError::InvalidBinop(
metamethod.to_owned(),
lhs.clone(),
rhs.clone(),
))
}
}
} }
} }
@ -1372,6 +1282,13 @@ impl ClosureRunner {
} }
} }
fn extract_metatable(value: &Value) -> Option<&Table> {
match value {
Value::Table { metatable, .. } => Some(metatable),
_ => None,
}
}
fn extract_ret_value(values: Result<Vec<Value>, RuntimeError>) -> Result<Value, RuntimeError> { fn extract_ret_value(values: Result<Vec<Value>, RuntimeError>) -> Result<Value, RuntimeError> {
values.map(|v| v.into_iter().next().unwrap()) values.map(|v| v.into_iter().next().unwrap())
} }

View File

@ -198,7 +198,7 @@ impl Display for Value {
Value::Integer(lua_integer) => Display::fmt(&lua_integer.0, f), Value::Integer(lua_integer) => Display::fmt(&lua_integer.0, f),
Value::Boolean(lua_bool) => Display::fmt(&lua_bool.0, f), Value::Boolean(lua_bool) => Display::fmt(&lua_bool.0, f),
Value::RustFunction(ref_cell) => { Value::RustFunction(ref_cell) => {
write!(f, "<RustFunction#{}>", ref_cell.borrow().as_indexable()) write!(f, "<RustFunction#{})>", ref_cell.borrow().as_indexable())
} }
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"),