Add RuntimeErrors

This commit is contained in:
Sofia 2026-03-16 17:19:16 +02:00
parent 5162550095
commit d4b13f3193
2 changed files with 104 additions and 68 deletions

View File

@ -6,7 +6,7 @@ use crate::{
TokenStream, TokenStream,
lexer::{Token, tokenize}, lexer::{Token, tokenize},
}, },
vm::{RustFunction, VirtualMachine}, vm::{RuntimeError, RustFunction, VirtualMachine},
}; };
mod ast; mod ast;
@ -19,24 +19,24 @@ static TEST: &str = include_str!("../examples/test.lua");
#[derive(Debug)] #[derive(Debug)]
pub struct Max; pub struct Max;
impl RustFunction for Max { impl RustFunction for Max {
fn execute(&self, parameters: Vec<vm::Value>) -> Vec<vm::Value> { fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil); let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil);
let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil); let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil);
match lhs.lt(&rhs) { match lhs.lt(&rhs)? {
vm::Value::Number(value) => { vm::Value::Number(value) => {
let res = LuaNumber::from_bits(value); let res = LuaNumber::from_bits(value);
vec![if res > 0. { rhs } else { lhs }] Ok(vec![if res > 0. { rhs } else { lhs }])
} }
_ => vec![vm::Value::Nil], _ => Ok(vec![vm::Value::Nil]),
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Print; pub struct Print;
impl RustFunction for Print { impl RustFunction for Print {
fn execute(&self, parameters: Vec<vm::Value>) -> Vec<vm::Value> { fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
println!("{:?}", parameters); println!("{:?}", parameters);
Vec::new() Ok(Vec::new())
} }
} }
@ -89,7 +89,7 @@ fn main() {
let mut run = closure.run(Vec::new()); let mut run = closure.run(Vec::new());
while run.next().is_none() {} while run.next().unwrap().is_none() {}
dbg!(&vm.environment.borrow().globals); dbg!(&vm.environment.borrow().globals);
} }

122
src/vm.rs
View File

@ -1,6 +1,8 @@
use thiserror::Error;
use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
use crate::ast::LuaNumber; use crate::ast::{BinaryOperator, LuaNumber, UnaryOperator};
pub type VMNumber = u64; pub type VMNumber = u64;
@ -96,6 +98,16 @@ impl Debug for Instruction {
} }
} }
#[derive(Error, Debug)]
pub enum RuntimeError {
#[error("Unable to perform {0:?} operator between {1:?} and {2:?}")]
InvalidOperands(BinaryOperator, Value, Value),
#[error("Unable to perform {0:?} operator to {1:?}")]
InvalidOperand(UnaryOperator, Value),
#[error("{0}")]
Custom(String),
}
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Environment { pub struct Environment {
pub globals: HashMap<Constant, Value>, pub globals: HashMap<Constant, Value>,
@ -110,87 +122,106 @@ pub enum Value {
} }
impl Value { impl Value {
pub fn add(&self, other: &Value) -> Value { pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) { match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => { (Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) + LuaNumber::from_bits(*rhs); let res = LuaNumber::from_bits(*lhs) + LuaNumber::from_bits(*rhs);
Value::Number(res.to_bits()) Ok(Value::Number(res.to_bits()))
} }
_ => Value::Nil, _ => Err(RuntimeError::InvalidOperands(
BinaryOperator::Add,
self.clone(),
other.clone(),
)),
} }
} }
pub fn eq(&self, other: &Value) -> Value { pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) { match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => { (Value::Number(lhs), Value::Number(rhs)) => {
let res = lhs == rhs; let res = lhs == rhs;
Value::Number((res as u64 as f64).to_bits()) Ok(Value::Number((res as u64 as f64).to_bits()))
} }
_ => Value::Nil, _ => Err(RuntimeError::InvalidOperands(
BinaryOperator::Equal,
self.clone(),
other.clone(),
)),
} }
} }
pub fn lt(&self, other: &Value) -> Value { pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) { match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => { (Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) < LuaNumber::from_bits(*rhs); let res = LuaNumber::from_bits(*lhs) < LuaNumber::from_bits(*rhs);
Value::Number((res as u64 as f64).to_bits()) Ok(Value::Number((res as u64 as f64).to_bits()))
} }
_ => Value::Nil, _ => Err(RuntimeError::InvalidOperands(
BinaryOperator::LessThan,
self.clone(),
other.clone(),
)),
} }
} }
pub fn lte(&self, other: &Value) -> Value { pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) { match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => { (Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) <= LuaNumber::from_bits(*rhs); let res = LuaNumber::from_bits(*lhs) <= LuaNumber::from_bits(*rhs);
Value::Number((res as u64 as f64).to_bits()) Ok(Value::Number((res as u64 as f64).to_bits()))
} }
_ => Value::Nil, _ => Err(RuntimeError::InvalidOperands(
BinaryOperator::LessThanOrEqual,
self.clone(),
other.clone(),
)),
} }
} }
pub fn unm(&self) -> Value { pub fn unm(&self) -> Result<Value, RuntimeError> {
match self { match self {
Value::Number(lhs) => { Value::Number(lhs) => {
let res = -LuaNumber::from_bits(*lhs); let res = -LuaNumber::from_bits(*lhs);
Value::Number(res.to_bits()) Ok(Value::Number(res.to_bits()))
} }
_ => Value::Nil, _ => Err(RuntimeError::InvalidOperand(
UnaryOperator::Negation,
self.clone(),
)),
} }
} }
pub fn and(&self, other: &Value) -> Value { pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) { match (self, other) {
(Value::Nil, _) | (_, Value::Nil) => Value::Nil, (Value::Nil, _) | (_, Value::Nil) => Ok(Value::Nil),
(Value::Number(lhs), Value::Number(rhs)) => { (Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) > 0. && LuaNumber::from_bits(*rhs) > 0.; let res = LuaNumber::from_bits(*lhs) > 0. && LuaNumber::from_bits(*rhs) > 0.;
Value::Number((res as u64 as f64).to_bits()) Ok(Value::Number((res as u64 as f64).to_bits()))
} }
(Value::Number(value), _) | (_, Value::Number(value)) => { (Value::Number(value), _) | (_, Value::Number(value)) => {
let res = LuaNumber::from_bits(*value) > 0.; let res = LuaNumber::from_bits(*value) > 0.;
Value::Number((res as u64 as f64).to_bits()) Ok(Value::Number((res as u64 as f64).to_bits()))
} }
_ => Value::Nil, _ => Ok(Value::Nil),
} }
} }
pub fn or(&self, other: &Value) -> Value { pub fn or(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) { match (self, other) {
(Value::Nil, value) | (value, Value::Nil) => value.clone(), (Value::Nil, value) | (value, Value::Nil) => Ok(value.clone()),
(Value::Number(lhs), Value::Number(rhs)) => { (Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber::from_bits(*lhs) > 0. || LuaNumber::from_bits(*rhs) > 0.; let res = LuaNumber::from_bits(*lhs) > 0. || LuaNumber::from_bits(*rhs) > 0.;
Value::Number((res as u64 as f64).to_bits()) Ok(Value::Number((res as u64 as f64).to_bits()))
} }
(Value::Number(value), other) => { (Value::Number(value), other) => {
if LuaNumber::from_bits(*value) > 0. { if LuaNumber::from_bits(*value) > 0. {
Value::Number(*value) Ok(Value::Number(*value))
} else { } else {
other.clone() Ok(other.clone())
} }
} }
(value, _) => value.clone(), (value, _) => Ok(value.clone()),
_ => Value::Nil, _ => Ok(Value::Nil),
} }
} }
} }
@ -210,7 +241,7 @@ impl Debug for Value {
} }
pub trait RustFunction: Debug { pub trait RustFunction: Debug {
fn execute(&self, parameters: Vec<Value>) -> Vec<Value>; fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError>;
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -276,9 +307,11 @@ impl ClosureRunner {
} }
} }
pub fn next(&mut self) -> Option<Vec<Value>> { pub fn next(&mut self) -> Result<Option<Vec<Value>>, RuntimeError> {
if let Some(inner) = &mut self.inner { if let Some(inner) = &mut self.inner {
if let Some(ret_values) = inner.next() { match inner.next() {
Ok(ret_values) => {
if let Some(ret_values) = ret_values {
self.inner = None; self.inner = None;
if self.return_registers.len() == 0 { if self.return_registers.len() == 0 {
for (i, value) in ret_values.iter().enumerate() { for (i, value) in ret_values.iter().enumerate() {
@ -298,7 +331,10 @@ impl ClosureRunner {
); );
} }
} else { } else {
return None; return Ok(None);
}
}
Err(e) => return Err(e),
} }
} }
@ -429,7 +465,7 @@ impl ClosureRunner {
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
match value { match value {
Value::RustFunction(func) => { Value::RustFunction(func) => {
let ret_values = func.borrow_mut().execute(params); let ret_values = func.borrow_mut().execute(params)?;
if *ret_len != 0 { if *ret_len != 0 {
for i in 0..=(*ret_len - 2) { for i in 0..=(*ret_len - 2) {
self.set_stack( self.set_stack(
@ -507,7 +543,7 @@ impl ClosureRunner {
.unwrap_or(Value::Nil), .unwrap_or(Value::Nil),
); );
} }
return Some(ret_values); return Ok(Some(ret_values));
} }
Instruction::Add(res, lhs, rhs) => { Instruction::Add(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -520,7 +556,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.add(&rhs)); self.set_stack(*res, lhs.add(&rhs)?);
} }
Instruction::Equal(res, lhs, rhs) => { Instruction::Equal(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -533,7 +569,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.eq(&rhs)); self.set_stack(*res, lhs.eq(&rhs)?);
} }
Instruction::LessThan(res, lhs, rhs) => { Instruction::LessThan(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -546,7 +582,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.lt(&rhs)); self.set_stack(*res, lhs.lt(&rhs)?);
} }
Instruction::LessThanOrEqual(res, lhs, rhs) => { Instruction::LessThanOrEqual(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -559,7 +595,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.lte(&rhs)); self.set_stack(*res, lhs.lte(&rhs)?);
} }
Instruction::Unm(res, reg) => { Instruction::Unm(res, reg) => {
self.set_stack( self.set_stack(
@ -568,7 +604,7 @@ impl ClosureRunner {
.get(reg) .get(reg)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil) .unwrap_or(Value::Nil)
.unm(), .unm()?,
); );
} }
Instruction::Or(res, lhs, rhs) => { Instruction::Or(res, lhs, rhs) => {
@ -582,7 +618,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.or(&rhs)); self.set_stack(*res, lhs.or(&rhs)?);
} }
Instruction::And(res, lhs, rhs) => { Instruction::And(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -595,15 +631,15 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.and(&rhs)); self.set_stack(*res, lhs.and(&rhs)?);
} }
}; };
self.program_counter += 1; self.program_counter += 1;
None Ok(None)
} else { } else {
Some(Vec::new()) Ok(Some(Vec::new()))
} }
} }
} }