Add RuntimeErrors
This commit is contained in:
parent
5162550095
commit
d4b13f3193
16
src/main.rs
16
src/main.rs
@ -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
122
src/vm.rs
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user