Add calling metamethods
This commit is contained in:
parent
232a729fe2
commit
5c4dbacaa7
@ -182,6 +182,14 @@ impl Debug for Instruction {
|
|||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
#[error("Unable to perform {0:?} operator between {1:?} and {2:?}")]
|
#[error("Unable to perform {0:?} operator between {1:?} and {2:?}")]
|
||||||
InvalidOperands(BinaryOperator, Value, Value),
|
InvalidOperands(BinaryOperator, Value, Value),
|
||||||
|
#[error("Unable to call metamethod {0} for values {1:?} and {2:?}")]
|
||||||
|
InvalidOperation(String, Value, Value),
|
||||||
|
#[error("Metatable is not a table: {0:?}")]
|
||||||
|
MetatableNotTable(Value),
|
||||||
|
#[error("Metafunction not found: {0}")]
|
||||||
|
MetafunctionNotFound(String),
|
||||||
|
#[error("Metafunction is not callable: {0:?}")]
|
||||||
|
MetafunctionNotCallable(Value),
|
||||||
#[error("Unable to perform {0:?} operator to {1:?}")]
|
#[error("Unable to perform {0:?} operator to {1:?}")]
|
||||||
InvalidOperand(UnaryOperator, Value),
|
InvalidOperand(UnaryOperator, Value),
|
||||||
#[error("Tried calling a non-function: {0:?}")]
|
#[error("Tried calling a non-function: {0:?}")]
|
||||||
@ -751,7 +759,15 @@ impl ClosureRunner {
|
|||||||
|
|
||||||
Instruction::Add(res, lhs, rhs) => {
|
Instruction::Add(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
self.set_stack(*res, StackValue::Value(lhs.add(&rhs)?));
|
self.set_stack(
|
||||||
|
*res,
|
||||||
|
StackValue::Value(self.result_or_metamethod(
|
||||||
|
lhs.add(&rhs),
|
||||||
|
"__add",
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
)?),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Instruction::Mult(res, lhs, rhs) => {
|
Instruction::Mult(res, lhs, rhs) => {
|
||||||
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
let (lhs, rhs) = self.lhs_and_rhs(lhs, rhs);
|
||||||
@ -909,6 +925,68 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn result_or_metamethod(
|
||||||
|
&self,
|
||||||
|
value: Result<Value, RuntimeError>,
|
||||||
|
metamethod: &str,
|
||||||
|
lhs: Value,
|
||||||
|
rhs: Value,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
|
match value {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(_) => match (&lhs, &rhs) {
|
||||||
|
(Value::Table { metatable, .. }, _) => {
|
||||||
|
self.call_metamethod(*metatable.clone(), metamethod, vec![lhs, rhs])
|
||||||
|
}
|
||||||
|
(_, Value::Table { metatable, .. }) => {
|
||||||
|
self.call_metamethod(*metatable.clone(), metamethod, vec![rhs, lhs])
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperation(
|
||||||
|
metamethod.to_owned(),
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_metamethod(
|
||||||
|
&self,
|
||||||
|
metatable: Value,
|
||||||
|
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()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => 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) {
|
||||||
(
|
(
|
||||||
self.stack
|
self.stack
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user