diff --git a/mute-interpreter/src/env/core.rs b/mute-interpreter/src/env/core.rs index 69b4b95..09d8373 100644 --- a/mute-interpreter/src/env/core.rs +++ b/mute-interpreter/src/env/core.rs @@ -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 { @@ -63,13 +64,37 @@ pub(super) fn core() -> HashMap { .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 { ( "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 { ( "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 { ( "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 { ( "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 { ( "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 { ( "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 { ( "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 { ( "<", 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 { ( ">", 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 { ( "<=", 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 { ( ">=", 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 { ( "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()) diff --git a/mute-interpreter/src/evaluator.rs b/mute-interpreter/src/evaluator.rs index 916a6c0..92e52a0 100644 --- a/mute-interpreter/src/evaluator.rs +++ b/mute-interpreter/src/evaluator.rs @@ -51,7 +51,8 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { .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 { } } - // TODO: Native functions??? _ => Err(Error::InvalidOperator)?, } } @@ -153,6 +153,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { | 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")] diff --git a/mute-interpreter/src/macros.rs b/mute-interpreter/src/macros.rs index c719a1f..814915a 100644 --- a/mute-interpreter/src/macros.rs +++ b/mute-interpreter/src/macros.rs @@ -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; diff --git a/mute-parser/src/node.rs b/mute-parser/src/node.rs index 1853694..11daaec 100644 --- a/mute-parser/src/node.rs +++ b/mute-parser/src/node.rs @@ -13,6 +13,8 @@ pub enum Node { Nil, Void, // XXX: Not sure if this should be a node + Error(String), + Vector(Vec), Map(HashMap), @@ -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()