feat: error node
Errors as values, baby!!
This commit is contained in:
parent
ff6b12e408
commit
2e19a44c0a
4 changed files with 57 additions and 32 deletions
65
mute-interpreter/src/env/core.rs
vendored
65
mute-interpreter/src/env/core.rs
vendored
|
@ -2,6 +2,7 @@ use std::borrow::Borrow;
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::{NativeFunc, Value};
|
||||
use crate::macros::arg_count;
|
||||
use crate::Node;
|
||||
|
||||
pub(super) fn core() -> HashMap<String, Value> {
|
||||
|
@ -63,13 +64,37 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
.unwrap_or(Node::Int(0))
|
||||
}),
|
||||
),
|
||||
(
|
||||
"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()),
|
||||
};
|
||||
|
||||
Node::Error(msg)
|
||||
}),
|
||||
),
|
||||
(
|
||||
"error?",
|
||||
NativeFunc(|args| {
|
||||
arg_count!(1, args.len());
|
||||
|
||||
if let Node::Error(_) = args[0].borrow() {
|
||||
return Node::Boolean(true);
|
||||
}
|
||||
|
||||
Node::Boolean(false)
|
||||
}),
|
||||
),
|
||||
// Collections
|
||||
("list", NativeFunc(Node::List)),
|
||||
(
|
||||
"list?",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
if let Node::List(_list) = args[0].borrow() {
|
||||
return Node::Boolean(true);
|
||||
|
@ -82,8 +107,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"vector?",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
if let Node::Vector(_vec) = args[0].borrow() {
|
||||
return Node::Boolean(true);
|
||||
|
@ -95,8 +119,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"hashmap",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(modulo: 2, args.len());
|
||||
arg_count!(modulo: 2, args.len());
|
||||
|
||||
let mut index = -1;
|
||||
let (keys, values): (Vec<_>, Vec<_>) = args.into_iter().partition(|_| {
|
||||
|
@ -118,8 +141,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"hashmap?",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
if let Node::Map(_map) = args[0].borrow() {
|
||||
return Node::Boolean(true);
|
||||
|
@ -131,8 +153,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"empty?",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
match args[0].borrow() {
|
||||
Node::List(list) => Node::Boolean(list.is_empty()),
|
||||
|
@ -145,8 +166,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"count",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
match args[0].borrow() {
|
||||
Node::List(list) => Node::Int(list.len() as i64),
|
||||
|
@ -160,8 +180,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"eq?",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(2, args.len());
|
||||
arg_count!(2, args.len());
|
||||
|
||||
let lhs = args[0].borrow();
|
||||
let rhs = args[1].borrow();
|
||||
|
@ -178,8 +197,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"not",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
let expr = args[0].borrow();
|
||||
if let Node::Boolean(false) = expr {
|
||||
|
@ -192,8 +210,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"<",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(2, args.len());
|
||||
arg_count!(2, args.len());
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let lhs = args.next().unwrap();
|
||||
|
@ -213,8 +230,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
">",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(2, args.len());
|
||||
arg_count!(2, args.len());
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let lhs = args.next().unwrap();
|
||||
|
@ -234,8 +250,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"<=",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(2, args.len());
|
||||
arg_count!(2, args.len());
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let lhs = args.next().unwrap();
|
||||
|
@ -255,8 +270,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
">=",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(2, args.len());
|
||||
arg_count!(2, args.len());
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let lhs = args.next().unwrap();
|
||||
|
@ -277,8 +291,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
(
|
||||
"str",
|
||||
NativeFunc(|args| {
|
||||
// TODO: Reimplement this
|
||||
// arg_count!(1, args.len());
|
||||
arg_count!(1, args.len());
|
||||
|
||||
let val = args[0].borrow();
|
||||
Node::String(val.to_string())
|
||||
|
|
|
@ -51,7 +51,8 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
|
|||
.to_owned()
|
||||
}
|
||||
|
||||
// HACK: This feels sooooooo wrong
|
||||
// HACK: This feels sooooooo wrong but it works
|
||||
// Native Functions /should/ be their own type, but they're not.
|
||||
Node::Symbol(sym) => {
|
||||
let operator = env.get(sym).ok_or_else(|| Error::NotInEnv(sym.clone()))?;
|
||||
match operator {
|
||||
|
@ -66,7 +67,6 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Native functions???
|
||||
_ => Err(Error::InvalidOperator)?,
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +153,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
|
|||
| Node::Boolean(_)
|
||||
| Node::Nil
|
||||
| Node::Void
|
||||
| Node::Error(_)
|
||||
| Node::Vector(_)
|
||||
| Node::Map(_)
|
||||
| Node::Function { .. } => ast_node,
|
||||
|
@ -176,6 +177,11 @@ mod test {
|
|||
#[case(":owo", ":owo")]
|
||||
#[case("()", "()")]
|
||||
#[case("nil", "()")]
|
||||
// Errors
|
||||
#[case("(error \"this failed\")", "error: this failed")]
|
||||
#[case("(error? (error \"this failed\"))", "true")]
|
||||
#[case("(error? 69)", "false")]
|
||||
#[case("(str 1 2 3)", "error: expected 1 args, got 3")]
|
||||
// Meta
|
||||
#[case("(eval (list + 1 1))", "2")]
|
||||
#[case("(apply + (list 1 2 3))", "6")]
|
||||
|
|
|
@ -2,18 +2,19 @@
|
|||
macro_rules! arg_count {
|
||||
($expected:expr, $given:expr) => {
|
||||
if $expected != $given {
|
||||
Err(Error::MismatchedArgCount($expected, $given))?
|
||||
return Node::Error(format!("expected {} args, got {}", $expected, $given));
|
||||
}
|
||||
};
|
||||
|
||||
(modulo: $modulo:expr, $given:expr) => {
|
||||
if $given % $modulo != 0 {
|
||||
Err(Error::MismatchedArgCount(
|
||||
return Node::Error(format!(
|
||||
"expected {} args, got {}",
|
||||
($given / $modulo) * $modulo + $modulo,
|
||||
$given,
|
||||
))?
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
pub(crate) use arg_count;
|
||||
|
|
|
@ -13,6 +13,8 @@ pub enum Node {
|
|||
Nil,
|
||||
Void, // XXX: Not sure if this should be a node
|
||||
|
||||
Error(String),
|
||||
|
||||
Vector(Vec<Node>),
|
||||
Map(HashMap<String, Node>),
|
||||
|
||||
|
@ -62,6 +64,7 @@ impl Node {
|
|||
Node::Boolean(_) => "boolean".to_string(),
|
||||
Node::Nil => "nil".to_string(),
|
||||
Node::Void => "void".to_string(),
|
||||
Node::Error(_) => "error".to_string(),
|
||||
Node::Vector(_) => "vector".to_string(),
|
||||
Node::Map(_) => "map".to_string(),
|
||||
Node::Define { .. } => "define".to_string(),
|
||||
|
@ -101,6 +104,8 @@ impl std::fmt::Display for Node {
|
|||
Node::Nil => write!(f, "()"),
|
||||
Node::Void => write!(f, ""),
|
||||
|
||||
Node::Error(val) => write!(f, "error: {}", val),
|
||||
|
||||
Node::Vector(vec) => {
|
||||
let s = vec
|
||||
.iter()
|
||||
|
|
Loading…
Reference in a new issue