Files
schemers/src/primitives.rs

221 lines
5.2 KiB
Rust

use crate::interpreter::has_tag;
use crate::interpreter::is_true;
use crate::parser::make_symbol;
use crate::parser::Datum;
use crate::parser::Datum::*;
use std::io;
use std::io::prelude::*;
use std::mem;
pub fn add(mut args: Vec<Datum>) -> Datum {
let mut r = 0;
for i in 1..args.len() {
let datum = mem::take(&mut args[i]);
if let Number(n) = datum {
r += n;
} else {
panic!("ADD -- not-all-args-are-numbers {:?}", args)
}
}
Number(r)
}
pub fn mul(mut args: Vec<Datum>) -> Datum {
let mut r = 1;
for i in 1..args.len() {
let datum = mem::take(&mut args[i]);
if let Number(n) = datum {
r *= n;
} else {
panic!("MUL -- not-all-args-are-numbers {:?}", args)
}
}
Number(r)
}
pub fn sub(mut args: Vec<Datum>) -> Datum {
if args.len() == 2 {
let datum = mem::take(&mut args[1]);
if let Number(n) = datum {
return Number(-n);
} else {
panic!("SUB -- not-all-args-are-numbers {:?}", args)
}
}
let mut r;
let datum = mem::take(&mut args[1]);
if let Number(n) = datum {
r = n;
} else {
panic!("SUB -- not-all-args-are-numbers {:?}", args)
}
for i in 2..args.len() {
let datum = mem::take(&mut args[i]);
if let Number(n) = datum {
r -= n;
} else {
panic!("SUB -- not-all-args-are-numbers {:?}", args)
}
}
Number(r)
}
pub fn eq(args: Vec<Datum>) -> Datum {
if args.len() == 1 {
Boolean(true)
} else {
let first = &args[1];
for i in 2..args.len() {
let current = &args[i];
if first != current {
return Boolean(false);
}
}
Boolean(true)
}
}
pub fn lt(args: Vec<Datum>) -> Datum {
if args.len() == 1 {
Boolean(true)
} else {
for i in 1..(args.len() - 1) {
if &args[i] >= &args[i + 1] {
return Boolean(false);
}
}
Boolean(true)
}
}
pub fn or(args: Vec<Datum>) -> Datum {
if args.len() == 1 {
Boolean(false)
} else {
for i in 1..args.len() {
if is_true(&args[i]) {
return args[i].clone();
}
}
Boolean(false)
}
}
pub fn and(args: Vec<Datum>) -> Datum {
if args.len() == 1 {
Boolean(true)
} else {
for i in 1..args.len() {
if !is_true(&args[i]) {
return Boolean(false);
}
}
args[args.len() - 1].clone()
}
}
pub fn not(args: Vec<Datum>) -> Datum {
if args.len() != 2 {
panic!("NOT -- takes one argument");
} else {
if is_true(&args[1]) {
Boolean(false)
} else {
Boolean(true)
}
}
}
pub fn display(args: Vec<Datum>) -> Datum {
for i in 1..args.len() {
print!("{}", args[i]);
}
io::stdout().flush().ok().expect("Could not flush stdout");
Unspecified
}
pub fn list(mut args: Vec<Datum>) -> Datum {
args[0] = make_symbol("list");
Datum::List(args)
}
pub fn cons(mut args: Vec<Datum>) -> Datum {
if args.len() != 3 {
panic!("CONS -- two args expected {:?}", args);
}
let a = std::mem::take(&mut args[1]);
let b = std::mem::take(&mut args[2]);
match b {
List(b_vec) if has_tag(&b_vec, "list") => {
let mut r_vec = vec![make_symbol("list"), a];
r_vec.append(&mut b_vec[1..].to_vec());
Datum::List(r_vec)
}
_ => Datum::Pair(Box::new((a, b))),
}
}
pub fn car(mut args: Vec<Datum>) -> Datum {
if args.len() != 2 {
panic!("CAR -- expected a single arg {:?}", args);
}
let a = std::mem::take(&mut args[1]);
match a {
List(mut v) if has_tag(&v, "list") => std::mem::take(&mut v[1]),
Pair(p) => p.0,
_ => panic!("CAR -- could not get car {:?}", a),
}
}
pub fn cdr(mut args: Vec<Datum>) -> Datum {
if args.len() != 2 {
panic!("CDR -- expected a single arg {:?}", args);
}
let a = std::mem::take(&mut args[1]);
match a {
List(v) if has_tag(&v, "list") => {
let mut v_cdr = v[1..].to_vec();
v_cdr[0] = make_symbol("list");
List(v_cdr)
}
Pair(p) => p.1,
_ => panic!("CAR -- could not get car {:?}", a),
}
}
pub fn pair(args: Vec<Datum>) -> Datum {
if args.len() != 2 {
panic!("PAIR? -- expected a single arg {:?}", args);
}
match &args[1] {
List(v) if has_tag(&v, "list") => {
if v.len() == 1 {
Boolean(false)
} else {
Boolean(true)
}
}
Pair(_) => Boolean(true),
_ => Boolean(false),
}
}
pub fn null(args: Vec<Datum>) -> Datum {
if args.len() != 2 {
panic!("PAIR? -- expected a single arg {:?}", args);
}
match &args[1] {
List(v) if has_tag(&v, "list") => {
if v.len() == 1 {
Boolean(true)
} else {
Boolean(false)
}
}
Pair(_) => Boolean(false),
_ => Boolean(false),
}
}