From 5669a04db08d6c37559929cd81e16f2572bff0a4 Mon Sep 17 00:00:00 2001 From: Roman Godmaire Date: Fri, 10 May 2024 19:23:48 -0400 Subject: [PATCH] feat: return errors on bad operations The vast majority of these will turn into parse time type checks --- mute-interpreter/src/env/core.rs | 93 ++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/mute-interpreter/src/env/core.rs b/mute-interpreter/src/env/core.rs index 05db53d..e0dc07c 100644 --- a/mute-interpreter/src/env/core.rs +++ b/mute-interpreter/src/env/core.rs @@ -17,7 +17,11 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs + rhs), (Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 + rhs), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs + rhs as f64), - _ => todo!(), + (lhs, rhs) => Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )), }) .unwrap_or(Node::Int(0)) }), @@ -31,7 +35,11 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs - rhs), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs - rhs as f64), (Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 - rhs), - _ => todo!(), + (lhs, rhs) => Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )), }) .unwrap_or(Node::Int(0)) }), @@ -45,7 +53,11 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs * rhs), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs * rhs as f64), (Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 * rhs), - _ => todo!(), + (lhs, rhs) => Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )), }) .unwrap_or(Node::Int(0)) }), @@ -59,22 +71,24 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs / rhs), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs / rhs as f64), (Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 / rhs), - _ => todo!(), + (lhs, rhs) => Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )), }) .unwrap_or(Node::Int(0)) }), ), // Errors! - // XXX: I fully expect errors to be overhauled when chaining and tagged unions - // are implemented. ( "error", NativeFunc(|args| { arg_count!(1, args.len()); - let msg = match args.into_iter().next() { - Some(Node::String(msg)) => msg, - _ => return Node::Error("Expected string".to_string()), + let msg = match args.into_iter().next().unwrap() { + Node::String(msg) => msg, + msg => return Node::Error(format!("expected string, got {}", msg.get_type())), }; Node::Error(msg) @@ -162,7 +176,10 @@ pub(super) fn core() -> HashMap { Node::List(list) => Node::Boolean(list.is_empty()), Node::Vector(vec) => Node::Boolean(vec.is_empty()), Node::Map(map) => Node::Boolean(map.is_empty()), - _ => todo!(), + arg => Node::Error(format!( + "TypeError: expected list, vector, or hashmap, got {}.", + arg.get_type() + )), } }), ), @@ -175,7 +192,10 @@ pub(super) fn core() -> HashMap { Node::List(list) => Node::Int(list.len() as i64), Node::Vector(vec) => Node::Int(vec.len() as i64), Node::Map(map) => Node::Int(map.len() as i64), - _ => todo!(), + arg => Node::Error(format!( + "TypeError: expected list, vector, or hashmap, got {}.", + arg.get_type() + )), } }), ), @@ -193,7 +213,14 @@ pub(super) fn core() -> HashMap { (Node::Boolean(lhs), Node::Boolean(rhs)) => Node::Boolean(lhs == rhs), (Node::String(lhs), Node::String(rhs)) => Node::Boolean(lhs == rhs), (Node::Nil, Node::Nil) => Node::Boolean(true), - _ => todo!(), + (lhs, rhs) if lhs.get_type() == rhs.get_type() => { + Node::Error("TypeError: expected int, boolean, or string.".to_string()) + } + (lhs, rhs) => Node::Error(format!( + "TypeError: expected pair of int, boolean, or string, got {} and {}.", + lhs.get_type(), + rhs.get_type() + )), } }), ), @@ -202,12 +229,10 @@ pub(super) fn core() -> HashMap { NativeFunc(|args| { arg_count!(1, args.len()); - let expr = args[0].borrow(); - if let Node::Boolean(false) = expr { - return Node::Boolean(true); + match args.into_iter().next().unwrap() { + Node::Boolean(val) => Node::Boolean(!val), + expr => Node::Error(format!("expected boolean, got {}", expr.get_type())), } - - Node::Boolean(false) }), ), ( @@ -224,7 +249,13 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => lhs < rhs, (Node::Float(lhs), Node::Int(rhs)) => lhs < rhs as f64, (Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) < rhs, - _ => todo!(), + (lhs, rhs) => { + return Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )) + } }; Node::Boolean(less_than) @@ -244,7 +275,13 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => lhs > rhs, (Node::Float(lhs), Node::Int(rhs)) => lhs > rhs as f64, (Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) > rhs, - _ => todo!(), + (lhs, rhs) => { + return Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )) + } }; Node::Boolean(greater_than) @@ -264,7 +301,13 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => lhs <= rhs, (Node::Float(lhs), Node::Int(rhs)) => lhs <= rhs as f64, (Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) <= rhs, - _ => todo!(), + (lhs, rhs) => { + return Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )) + } }; Node::Boolean(less_than_equal) @@ -284,7 +327,13 @@ pub(super) fn core() -> HashMap { (Node::Float(lhs), Node::Float(rhs)) => lhs >= rhs, (Node::Float(lhs), Node::Int(rhs)) => lhs >= rhs as f64, (Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) >= rhs, - _ => todo!(), + (lhs, rhs) => { + return Node::Error(format!( + "expected int or float, got {} and {}", + lhs.get_type(), + rhs.get_type() + )) + } }; Node::Boolean(greater_than_equal) @@ -296,7 +345,7 @@ pub(super) fn core() -> HashMap { NativeFunc(|args| { arg_count!(1, args.len()); - let val = args[0].borrow(); + let val = args.into_iter().next().unwrap(); Node::String(val.to_string()) }), ),