From 1129e1e2d90d660482e85ea5edad94a76cb08129 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 27 Dec 2021 20:43:01 +0000 Subject: [PATCH] New prims `abs` and `<` --- src/main.rs | 72 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index a675b8f..987b559 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -#![feature(let_else)] #![feature(array_windows)] +#![feature(assert_matches)] #![feature(box_patterns)] +#![feature(let_else)] mod grammar; @@ -13,6 +14,7 @@ use rustyline::validate::{ }; use rustyline::Editor; use rustyline_derive::{Completer, Helper, Highlighter, Hinter}; +use std::assert_matches::assert_matches; use std::collections::HashMap; use std::io; use std::rc::Rc; @@ -238,20 +240,8 @@ fn eval(t: &Tree, env: &mut Env) -> Result { fn default_env() -> Env<'static> { let mut vars = HashMap::new(); - for (name, fun) in [ - ("*", prims::mul as Func), - ("+", prims::add as Func), - ("-", prims::sub as Func), - ("/", prims::div as Func), - // TODO: Spec compiance - ("=", prims::equals as Func), - ("eq?", prims::equals as Func), - ("eqv?", prims::equals as Func), - ("equal?", prims::equals as Func), - ("display", prims::display as Func), - ("newline", prims::newline as Func), - ] { - vars.insert(name.to_owned(), Value::Func(fun)); + for (name, fun) in prims::prims() { + assert_matches!(vars.insert((*name).to_owned(), Value::Func(*fun)), None) } Env { @@ -261,24 +251,42 @@ fn default_env() -> Env<'static> { } mod prims { - use crate::{err, RTError, Value}; + use crate::{err, Func, RTError, Value}; + + pub(crate) fn prims() -> &'static [(&'static str, Func)] { + &[ + ("*", mul), + ("+", add), + ("-", sub), + ("/", div), + // TODO: Spec compiance + ("=", equals), + ("eq?", equals), + ("eqv?", equals), + ("equal?", equals), + ("display", display), + ("newline", newline), + ("abs", abs), + ("<", lt), + ] + } // TODO: DRY +-/* - pub(crate) fn add(args: &[Value]) -> Result { + fn add(args: &[Value]) -> Result { args.iter() .map(Value::as_num) .try_fold(0.0, |a, b| Ok(a + b?)) .map(Value::Num) } - pub(crate) fn mul(args: &[Value]) -> Result { + fn mul(args: &[Value]) -> Result { args.iter() .map(Value::as_num) .try_fold(1.0, |a, b| Ok(a * b?)) .map(Value::Num) } - pub(crate) fn div(args: &[Value]) -> Result { + fn div(args: &[Value]) -> Result { let init = args .get(0) .ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))? @@ -292,7 +300,7 @@ mod prims { })) } - pub(crate) fn sub(args: &[Value]) -> Result { + fn sub(args: &[Value]) -> Result { let init = args .get(0) .ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))? @@ -306,23 +314,41 @@ mod prims { })) } - pub(crate) fn equals(args: &[Value]) -> Result { + fn equals(args: &[Value]) -> Result { Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r))) } - pub(crate) fn display(args: &[Value]) -> Result { + fn display(args: &[Value]) -> Result { let [arg] = args else {return err("To many args to `display`".to_owned())}; print!("{:?}", arg); Ok(Value::NotAValue) } - pub(crate) fn newline(args: &[Value]) -> Result { + fn newline(args: &[Value]) -> Result { if !args.is_empty() { return err("Newline takes no args".to_owned()); } println!(""); Ok(Value::NotAValue) } + + fn abs(args: &[Value]) -> Result { + let [v] = args else { return err("abs takes 1 arg".to_owned()) }; + let ans = v.as_num()?.abs(); + Ok(Value::Num(ans)) + } + + // TODO: gt le ge + fn lt(args: &[Value]) -> Result { + for [l, r] in args.array_windows() { + let (Value::Num(l), Value::Num(r)) = (l,r) else { return err("lt args must be numbers".to_owned()); }; + if !(l < r) { + return Ok(Value::Bool(false)); + }; + } + + Ok(Value::Bool(true)) + } } // #[cfg(test)]