New prims `abs` and `<`

trunk
Alona EM 2021-12-27 20:43:01 +00:00
parent 4c4928ea9f
commit 1129e1e2d9
1 changed files with 49 additions and 23 deletions

View File

@ -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<Value, RTError> {
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<Value, RTError> {
fn add(args: &[Value]) -> Result<Value, RTError> {
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<Value, RTError> {
fn mul(args: &[Value]) -> Result<Value, RTError> {
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<Value, RTError> {
fn div(args: &[Value]) -> Result<Value, RTError> {
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<Value, RTError> {
fn sub(args: &[Value]) -> Result<Value, RTError> {
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<Value, RTError> {
fn equals(args: &[Value]) -> Result<Value, RTError> {
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
}
pub(crate) fn display(args: &[Value]) -> Result<Value, RTError> {
fn display(args: &[Value]) -> Result<Value, RTError> {
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<Value, RTError> {
fn newline(args: &[Value]) -> Result<Value, RTError> {
if !args.is_empty() {
return err("Newline takes no args".to_owned());
}
println!("");
Ok(Value::NotAValue)
}
fn abs(args: &[Value]) -> Result<Value, RTError> {
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<Value, RTError> {
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)]