feat: return errors on bad operations
The vast majority of these will turn into parse time type checks
This commit is contained in:
parent
1958da3a96
commit
5669a04db0
1 changed files with 71 additions and 22 deletions
93
mute-interpreter/src/env/core.rs
vendored
93
mute-interpreter/src/env/core.rs
vendored
|
@ -17,7 +17,11 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(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<String, Value> {
|
|||
(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<String, Value> {
|
|||
(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<String, Value> {
|
|||
(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<String, Value> {
|
|||
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<String, Value> {
|
|||
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<String, Value> {
|
|||
(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<String, Value> {
|
|||
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<String, Value> {
|
|||
(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<String, Value> {
|
|||
(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<String, Value> {
|
|||
(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<String, Value> {
|
|||
(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<String, Value> {
|
|||
NativeFunc(|args| {
|
||||
arg_count!(1, args.len());
|
||||
|
||||
let val = args[0].borrow();
|
||||
let val = args.into_iter().next().unwrap();
|
||||
Node::String(val.to_string())
|
||||
}),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue