From b4918e7312d568bcef70ffa856d8bccbec03d9e3 Mon Sep 17 00:00:00 2001 From: Sofia Date: Fri, 20 Mar 2026 21:31:39 +0200 Subject: [PATCH] Add better error messages to metamethods --- src/vm/mod.rs | 78 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/src/vm/mod.rs b/src/vm/mod.rs index b807236..57241d5 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -224,8 +224,8 @@ pub enum RuntimeError { InvalidUnop(String, Value), #[error("Metatable is not a table: {0:?}")] MetatableNotTable(Value), - #[error("Metafunction not found: {0}")] - MetafunctionNotFound(String), + #[error("Metafunction not found: {0} for {1:?}")] + MetafunctionNotFound(String, Value), #[error("Metafunction is not callable: {0:?}")] MetafunctionNotCallable(Value), #[error("Unable to perform {0:?} operator to {1:?}")] @@ -1139,7 +1139,17 @@ impl ClosureRunner { Ok(value) => Ok(value), Err(_) => match ¶m { Value::Table { metatable, .. } => { - self.call_metamethod(metatable, metamethod, vec![param.clone()]) + if metatable + .borrow() + .contains_key(&IndexableValue::String(metamethod.to_owned())) + { + self.call_metamethod(metatable, metamethod, vec![param.clone()]) + } else { + Err(RuntimeError::InvalidUnop( + metamethod.to_owned(), + param.clone(), + )) + } } _ => Err(RuntimeError::InvalidUnop( metamethod.to_owned(), @@ -1158,15 +1168,56 @@ impl ClosureRunner { ) -> Result { match value { Ok(value) => Ok(value), - Err(_) => match (&lhs, &rhs) { - (Value::Table { metatable, .. }, _) => { - self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()]) + Err(_) => { + if let Value::Table { metatable, .. } = &lhs { + if metatable + .borrow() + .contains_key(&IndexableValue::String(metamethod.to_owned())) + { + 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())) + { + 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(), + )) + } + } + } else if let Value::Table { metatable, .. } = &rhs { + if metatable + .borrow() + .contains_key(&IndexableValue::String(metamethod.to_owned())) + { + 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(), + )) } - (_, Value::Table { metatable, .. }) => { - self.call_metamethod(metatable, metamethod, vec![lhs.clone(), rhs.clone()]) - } - _ => Err(RuntimeError::InvalidBinop(metamethod.to_owned(), lhs, rhs)), - }, + } } } @@ -1198,7 +1249,10 @@ impl ClosureRunner { _ => Err(RuntimeError::MetafunctionNotCallable(value.clone())), } } else { - Err(RuntimeError::MetafunctionNotFound(metamethod.to_owned())) + Err(RuntimeError::MetafunctionNotFound( + metamethod.to_owned(), + params.get(0).unwrap().clone(), + )) } }