From ed28efb6239beaa385b38892abea0260a989ff89 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Thu, 15 May 2025 19:44:38 +0800 Subject: [PATCH] feat: error handling (WIP) --- src/builtins/mod.rs | 12 ++++----- src/ty/internal/mod.rs | 57 ++++++++++++++++++++------------------- src/ty/internal/primop.rs | 13 ++++----- src/vm/mod.rs | 2 +- 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 06bc924..374c359 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -12,15 +12,15 @@ pub fn env<'vm>(vm: &'vm VM) -> Rc> { let primops = [ PrimOp::new("add", 2, |_, args| { let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.add(second) + first.add(second).ok() }), PrimOp::new("sub", 2, |_, args| { let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.add(second.neg()) + first.add(second.neg()).ok() }), PrimOp::new("mul", 2, |_, args| { let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.mul(second) + first.mul(second).ok() }), PrimOp::new("div", 2, |_, args| { let [first, second]: [Value; 2] = args.try_into().unwrap(); @@ -28,17 +28,17 @@ pub fn env<'vm>(vm: &'vm VM) -> Rc> { }), PrimOp::new("lessThan", 2, |_, args| { let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.lt(second) + first.lt(second).ok() }), PrimOp::new("seq", 2, |vm, args| { let [mut first, second]: [Value; 2] = args.try_into().unwrap(); first.force(vm).unwrap(); - second + second.ok() }), PrimOp::new("deepSeq", 2, |vm, args| { let [mut first, second]: [Value; 2] = args.try_into().unwrap(); first.force_deep(vm).unwrap(); - second + second.ok() }), ]; diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index ffc5093..718da3f 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -102,6 +102,10 @@ impl<'v, 'vm: 'v> Value<'vm> { use Value::Const as VmConst; impl<'vm> Value<'vm> { + pub fn ok(self) -> Result { + Ok(self) + } + pub fn typename(&self) -> &'static str { use Value::*; match self { @@ -126,9 +130,9 @@ impl<'vm> Value<'vm> { } } - pub fn call(self, vm: &'vm VM<'_>, args: Vec>) -> Result> { + pub fn call(self, vm: &'vm VM<'_>, args: Vec) -> Result { use Value::*; - Ok(match self { + match self { PrimOp(func) => func.call(vm, args), PartialPrimOp(func) => func.call(vm, args), mut func @ Value::Func(_) => { @@ -136,23 +140,23 @@ impl<'vm> Value<'vm> { while let Some(arg) = iter.next() { func = match func { PrimOp(func) => { - return Ok(func.call(vm, [arg].into_iter().chain(iter).collect())); + return func.call(vm, [arg].into_iter().chain(iter).collect()); } PartialPrimOp(func) => { - return Ok(func.call(vm, [arg].into_iter().chain(iter).collect())); + return func.call(vm, [arg].into_iter().chain(iter).collect()); } Func(func) => func.call(vm, arg)?, _ => todo!(), } } - func + func.ok() } - x @ Catchable(_) => x, + x @ Catchable(_) => x.ok(), _ => todo!(), - }) + } } - pub fn not(self) -> Value<'vm> { + pub fn not(self) -> Self { use Const::*; match self { VmConst(Bool(bool)) => VmConst(Bool(!bool)), @@ -161,7 +165,7 @@ impl<'vm> Value<'vm> { } } - pub fn and(self, other: Value<'vm>) -> Value<'vm> { + pub fn and(self, other: Self) -> Self { use Const::*; match (self, other) { (VmConst(Bool(a)), VmConst(Bool(b))) => VmConst(Bool(a && b)), @@ -170,7 +174,7 @@ impl<'vm> Value<'vm> { } } - pub fn or(self, other: Value<'vm>) -> Value<'vm> { + pub fn or(self, other: Self) -> Self { use Const::*; match (self, other) { (VmConst(Bool(a)), VmConst(Bool(b))) => VmConst(Bool(a || b)), @@ -179,7 +183,7 @@ impl<'vm> Value<'vm> { } } - pub fn eq(self, other: Value<'vm>) -> Value<'vm> { + pub fn eq(self, other: Self) -> Self { use Const::Bool; match (self, other) { (x @ Value::Catchable(_), _) | (_, x @ Value::Catchable(_)) => x, @@ -187,7 +191,7 @@ impl<'vm> Value<'vm> { } } - pub fn lt(self, other: Value<'vm>) -> Value<'vm> { + pub fn lt(self, other: Self) -> Self { use Const::*; VmConst(Bool(match (self, other) { (VmConst(Int(a)), VmConst(Int(b))) => a < b, @@ -200,7 +204,7 @@ impl<'vm> Value<'vm> { })) } - pub fn neg(self) -> Value<'vm> { + pub fn neg(self) -> Self { use Const::*; match self { VmConst(Int(int)) => VmConst(Int(-int)), @@ -210,7 +214,7 @@ impl<'vm> Value<'vm> { } } - pub fn add(self, other: Value<'vm>) -> Value<'vm> { + pub fn add(self, other: Self) -> Self { use Const::*; match (self, other) { (VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a + b)), @@ -227,7 +231,7 @@ impl<'vm> Value<'vm> { } } - pub fn mul(self, other: Value<'vm>) -> Value<'vm> { + pub fn mul(self, other: Self) -> Self { use Const::*; match (self, other) { (VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a * b)), @@ -239,21 +243,20 @@ impl<'vm> Value<'vm> { } } - pub fn div(self, other: Value<'vm>) -> Value<'vm> { + pub fn div(self, other: Self) -> Result { use Const::*; - match (self, other) { - (_, VmConst(Int(0))) => todo!(), - (_, VmConst(Float(0.))) => todo!(), - (VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a / b)), + Ok(match (self, other) { + (_, VmConst(Int(0))) => return Err(Error::EvalError("division by zero".to_string())), + (_, VmConst(Float(0.))) => return Err(Error::EvalError("division by zero".to_string())), (VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a / b)), (VmConst(Int(a)), VmConst(Float(b))) => VmConst(Float(a as f64 / b)), (VmConst(Float(a)), VmConst(Int(b))) => VmConst(Float(a / b as f64)), (VmConst(Float(a)), VmConst(Float(b))) => VmConst(Float(a / b)), (x @ Value::Catchable(_), _) | (_, x @ Value::Catchable(_)) => x, _ => todo!(), - } + }) } - pub fn concat_string(&mut self, mut other: Value<'vm>) -> &mut Self { + pub fn concat_string(&mut self, mut other: Self) -> &mut Self { match (self.coerce_to_string(), other.coerce_to_string()) { (VmConst(Const::String(a)), VmConst(Const::String(b))) => a.push_str(b.as_str()), (_, Value::Catchable(_)) => *self = other, @@ -263,7 +266,7 @@ impl<'vm> Value<'vm> { self } - pub fn push(&mut self, elem: Value<'vm>) -> &mut Self { + pub fn push(&mut self, elem: Self) -> &mut Self { if let Value::List(list) = self { list.push(elem); } else if let Value::Catchable(_) = self { @@ -275,7 +278,7 @@ impl<'vm> Value<'vm> { self } - pub fn concat(self, other: Value<'vm>) -> Value<'vm> { + pub fn concat(self, other: Self) -> Self { match (self, other) { (Value::List(a), Value::List(b)) => Value::List(a.concat(b)), (x @ Value::Catchable(_), _) | (_, x @ Value::Catchable(_)) => x, @@ -283,7 +286,7 @@ impl<'vm> Value<'vm> { } } - pub fn push_attr(&mut self, sym: usize, val: Value<'vm>) -> &mut Self { + pub fn push_attr(&mut self, sym: usize, val: Self) -> &mut Self { if let Value::AttrSet(attrs) = self { attrs.push_attr(sym, val) } else if let Value::RecAttrSet(attrs) = self { @@ -297,7 +300,7 @@ impl<'vm> Value<'vm> { self } - pub fn update(self, other: Value<'vm>) -> Value<'vm> { + pub fn update(self, other: Self) -> Self { match (self, other) { (Value::AttrSet(a), Value::AttrSet(b)) => Value::AttrSet(a.update(b)), (Value::RecAttrSet(a), Value::AttrSet(b)) => Value::AttrSet(a.update_normal(b)), @@ -325,7 +328,7 @@ impl<'vm> Value<'vm> { Ok(self) } - pub fn select_with_default(&mut self, sym: usize, default: Value<'vm>) -> Result<&mut Self> { + pub fn select_with_default(&mut self, sym: usize, default: Self) -> Result<&mut Self> { let val = match self { Value::AttrSet(attrs) => attrs.select(sym).unwrap_or(default), Value::RecAttrSet(attrs) => attrs.select(sym).unwrap_or(default), diff --git a/src/ty/internal/primop.rs b/src/ty/internal/primop.rs index 9ae1f7e..e16e740 100644 --- a/src/ty/internal/primop.rs +++ b/src/ty/internal/primop.rs @@ -1,6 +1,7 @@ use derive_more::Constructor; use crate::vm::VM; +use crate::error::Result; use super::Value; @@ -8,7 +9,7 @@ use super::Value; pub struct PrimOp<'vm> { pub name: &'static str, arity: u8, - func: fn(&'vm VM<'_>, Vec>) -> Value<'vm>, + func: fn(&'vm VM<'_>, Vec>) -> Result>, } impl PartialEq for PrimOp<'_> { @@ -18,14 +19,14 @@ impl PartialEq for PrimOp<'_> { } impl<'vm> PrimOp<'vm> { - pub fn call(self, vm: &'vm VM<'_>, args: Vec>) -> Value<'vm> { + pub fn call(self, vm: &'vm VM<'_>, args: Vec>) -> Result> { if (args.len() as u8) < self.arity { Value::PartialPrimOp(PartialPrimOp { name: self.name, arity: self.arity - args.len() as u8, args, func: self.func, - }) + }).ok() } else if args.len() as u8 == self.arity { (self.func)(vm, args) } else { @@ -39,7 +40,7 @@ pub struct PartialPrimOp<'vm> { pub name: &'static str, arity: u8, args: Vec>, - func: fn(&'vm VM<'_>, Vec>) -> Value<'vm>, + func: fn(&'vm VM<'_>, Vec>) -> Result>, } impl PartialEq for PartialPrimOp<'_> { @@ -49,7 +50,7 @@ impl PartialEq for PartialPrimOp<'_> { } impl<'vm> PartialPrimOp<'vm> { - pub fn call(mut self, vm: &'vm VM<'_>, args: Vec>) -> Value<'vm> { + pub fn call(mut self, vm: &'vm VM<'_>, args: Vec>) -> Result> { let len = args.len() as u8; self.args.extend(args); if len < self.arity { @@ -58,7 +59,7 @@ impl<'vm> PartialPrimOp<'vm> { arity: self.arity - len, args: self.args, func: self.func, - }) + }).ok() } else if len == self.arity { (self.func)(vm, self.args) } else { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 4174956..982c595 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -152,7 +152,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { Add => lhs.add(rhs), Sub => lhs.add(rhs.neg()), Mul => lhs.mul(rhs), - Div => lhs.div(rhs), + Div => lhs.div(rhs)?, And => lhs.and(rhs), Or => lhs.or(rhs), Eq => lhs.eq(rhs),