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::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())
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue