feat: return errors on bad operations

The vast majority of these will turn into parse time type checks
This commit is contained in:
Roman Godmaire 2024-05-10 19:23:48 -04:00
parent 1958da3a96
commit 5669a04db0

View file

@ -17,7 +17,11 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs + rhs), (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs + rhs),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 + 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), (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)) .unwrap_or(Node::Int(0))
}), }),
@ -31,7 +35,11 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs - rhs), (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs - rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs - rhs as f64), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs - rhs as f64),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 - rhs), (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)) .unwrap_or(Node::Int(0))
}), }),
@ -45,7 +53,11 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs * rhs), (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs * rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs * rhs as f64), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs * rhs as f64),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 * rhs), (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)) .unwrap_or(Node::Int(0))
}), }),
@ -59,22 +71,24 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs / rhs), (Node::Float(lhs), Node::Float(rhs)) => Node::Float(lhs / rhs),
(Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs / rhs as f64), (Node::Float(lhs), Node::Int(rhs)) => Node::Float(lhs / rhs as f64),
(Node::Int(lhs), Node::Float(rhs)) => Node::Float(lhs as f64 / rhs), (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)) .unwrap_or(Node::Int(0))
}), }),
), ),
// Errors! // Errors!
// XXX: I fully expect errors to be overhauled when chaining and tagged unions
// are implemented.
( (
"error", "error",
NativeFunc(|args| { NativeFunc(|args| {
arg_count!(1, args.len()); arg_count!(1, args.len());
let msg = match args.into_iter().next() { let msg = match args.into_iter().next().unwrap() {
Some(Node::String(msg)) => msg, Node::String(msg) => msg,
_ => return Node::Error("Expected string".to_string()), msg => return Node::Error(format!("expected string, got {}", msg.get_type())),
}; };
Node::Error(msg) Node::Error(msg)
@ -162,7 +176,10 @@ pub(super) fn core() -> HashMap<String, Value> {
Node::List(list) => Node::Boolean(list.is_empty()), Node::List(list) => Node::Boolean(list.is_empty()),
Node::Vector(vec) => Node::Boolean(vec.is_empty()), Node::Vector(vec) => Node::Boolean(vec.is_empty()),
Node::Map(map) => Node::Boolean(map.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<String, Value> {
Node::List(list) => Node::Int(list.len() as i64), Node::List(list) => Node::Int(list.len() as i64),
Node::Vector(vec) => Node::Int(vec.len() as i64), Node::Vector(vec) => Node::Int(vec.len() as i64),
Node::Map(map) => Node::Int(map.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<String, Value> {
(Node::Boolean(lhs), Node::Boolean(rhs)) => Node::Boolean(lhs == rhs), (Node::Boolean(lhs), Node::Boolean(rhs)) => Node::Boolean(lhs == rhs),
(Node::String(lhs), Node::String(rhs)) => Node::Boolean(lhs == rhs), (Node::String(lhs), Node::String(rhs)) => Node::Boolean(lhs == rhs),
(Node::Nil, Node::Nil) => Node::Boolean(true), (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<String, Value> {
NativeFunc(|args| { NativeFunc(|args| {
arg_count!(1, args.len()); arg_count!(1, args.len());
let expr = args[0].borrow(); match args.into_iter().next().unwrap() {
if let Node::Boolean(false) = expr { Node::Boolean(val) => Node::Boolean(!val),
return Node::Boolean(true); expr => Node::Error(format!("expected boolean, got {}", expr.get_type())),
} }
Node::Boolean(false)
}), }),
), ),
( (
@ -224,7 +249,13 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => lhs < rhs, (Node::Float(lhs), Node::Float(rhs)) => lhs < rhs,
(Node::Float(lhs), Node::Int(rhs)) => lhs < rhs as f64, (Node::Float(lhs), Node::Int(rhs)) => lhs < rhs as f64,
(Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) < rhs, (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) Node::Boolean(less_than)
@ -244,7 +275,13 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => lhs > rhs, (Node::Float(lhs), Node::Float(rhs)) => lhs > rhs,
(Node::Float(lhs), Node::Int(rhs)) => lhs > rhs as f64, (Node::Float(lhs), Node::Int(rhs)) => lhs > rhs as f64,
(Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) > rhs, (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) Node::Boolean(greater_than)
@ -264,7 +301,13 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => lhs <= rhs, (Node::Float(lhs), Node::Float(rhs)) => lhs <= rhs,
(Node::Float(lhs), Node::Int(rhs)) => lhs <= rhs as f64, (Node::Float(lhs), Node::Int(rhs)) => lhs <= rhs as f64,
(Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) <= rhs, (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) Node::Boolean(less_than_equal)
@ -284,7 +327,13 @@ pub(super) fn core() -> HashMap<String, Value> {
(Node::Float(lhs), Node::Float(rhs)) => lhs >= rhs, (Node::Float(lhs), Node::Float(rhs)) => lhs >= rhs,
(Node::Float(lhs), Node::Int(rhs)) => lhs >= rhs as f64, (Node::Float(lhs), Node::Int(rhs)) => lhs >= rhs as f64,
(Node::Int(lhs), Node::Float(rhs)) => (lhs as f64) >= rhs, (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) Node::Boolean(greater_than_equal)
@ -296,7 +345,7 @@ pub(super) fn core() -> HashMap<String, Value> {
NativeFunc(|args| { NativeFunc(|args| {
arg_count!(1, args.len()); arg_count!(1, args.len());
let val = args[0].borrow(); let val = args.into_iter().next().unwrap();
Node::String(val.to_string()) Node::String(val.to_string())
}), }),
), ),