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(array_windows)]
|
||||||
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(let_else)]
|
||||||
|
|
||||||
mod grammar;
|
mod grammar;
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ use rustyline::validate::{
|
||||||
};
|
};
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
use rustyline_derive::{Completer, Helper, Highlighter, Hinter};
|
use rustyline_derive::{Completer, Helper, Highlighter, Hinter};
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -238,20 +240,8 @@ fn eval(t: &Tree, env: &mut Env) -> Result<Value, RTError> {
|
||||||
fn default_env() -> Env<'static> {
|
fn default_env() -> Env<'static> {
|
||||||
let mut vars = HashMap::new();
|
let mut vars = HashMap::new();
|
||||||
|
|
||||||
for (name, fun) in [
|
for (name, fun) in prims::prims() {
|
||||||
("*", prims::mul as Func),
|
assert_matches!(vars.insert((*name).to_owned(), Value::Func(*fun)), None)
|
||||||
("+", 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Env {
|
Env {
|
||||||
|
@ -261,24 +251,42 @@ fn default_env() -> Env<'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod prims {
|
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 +-/*
|
// TODO: DRY +-/*
|
||||||
pub(crate) fn add(args: &[Value]) -> Result<Value, RTError> {
|
fn add(args: &[Value]) -> Result<Value, RTError> {
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(Value::as_num)
|
.map(Value::as_num)
|
||||||
.try_fold(0.0, |a, b| Ok(a + b?))
|
.try_fold(0.0, |a, b| Ok(a + b?))
|
||||||
.map(Value::Num)
|
.map(Value::Num)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mul(args: &[Value]) -> Result<Value, RTError> {
|
fn mul(args: &[Value]) -> Result<Value, RTError> {
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(Value::as_num)
|
.map(Value::as_num)
|
||||||
.try_fold(1.0, |a, b| Ok(a * b?))
|
.try_fold(1.0, |a, b| Ok(a * b?))
|
||||||
.map(Value::Num)
|
.map(Value::Num)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn div(args: &[Value]) -> Result<Value, RTError> {
|
fn div(args: &[Value]) -> Result<Value, RTError> {
|
||||||
let init = args
|
let init = args
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
.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
|
let init = args
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
.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)))
|
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())};
|
let [arg] = args else {return err("To many args to `display`".to_owned())};
|
||||||
print!("{:?}", arg);
|
print!("{:?}", arg);
|
||||||
Ok(Value::NotAValue)
|
Ok(Value::NotAValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn newline(args: &[Value]) -> Result<Value, RTError> {
|
fn newline(args: &[Value]) -> Result<Value, RTError> {
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
return err("Newline takes no args".to_owned());
|
return err("Newline takes no args".to_owned());
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
Ok(Value::NotAValue)
|
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)]
|
// #[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue