New prims `abs` and `<`
parent
4c4928ea9f
commit
1129e1e2d9
72
src/main.rs
72
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<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)]
|
||||
|
|
Loading…
Reference in New Issue