mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
added lisp files
This commit is contained in:
15
lisp/Cargo.toml
Normal file
15
lisp/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "mal"
|
||||
version = "0.1.0"
|
||||
authors = ["mileschet"]
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
regex = "1.3.1"
|
||||
itertools = "0.8.0"
|
||||
fnv = "1.0.6"
|
||||
|
||||
[[bin]]
|
||||
name = "lisp"
|
||||
path = "lisp.rs"
|
||||
319
lisp/core.rs
Normal file
319
lisp/core.rs
Normal file
@@ -0,0 +1,319 @@
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use crate::printer::pr_seq;
|
||||
use crate::reader::read_str;
|
||||
use crate::types::MalErr::ErrMalVal;
|
||||
use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector};
|
||||
use crate::types::{MalArgs, MalRet, MalVal, _assoc, _dissoc, atom, error, func, hash_map};
|
||||
|
||||
macro_rules! fn_t_int_int {
|
||||
($ret:ident, $fn:expr) => {{
|
||||
|a: MalArgs| match (a[0].clone(), a[1].clone()) {
|
||||
(Int(a0), Int(a1)) => Ok($ret($fn(a0, a1))),
|
||||
_ => error("expecting (int,int) args"),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! fn_is_type {
|
||||
($($ps:pat),*) => {{
|
||||
|a:MalArgs| { Ok(Bool(match a[0] { $($ps => true,)* _ => false})) }
|
||||
}};
|
||||
($p:pat if $e:expr) => {{
|
||||
|a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, _ => false})) }
|
||||
}};
|
||||
($p:pat if $e:expr,$($ps:pat),*) => {{
|
||||
|a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, $($ps => true,)* _ => false})) }
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! fn_str {
|
||||
($fn:expr) => {{
|
||||
|a: MalArgs| match a[0].clone() {
|
||||
Str(a0) => $fn(a0),
|
||||
_ => error("expecting (str) arg"),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
fn symbol(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
Str(ref s) => Ok(Sym(s.to_string())),
|
||||
_ => error("illegal symbol call"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn slurp(f: String) -> MalRet {
|
||||
let mut s = String::new();
|
||||
match File::open(f).and_then(|mut f| f.read_to_string(&mut s)) {
|
||||
Ok(_) => Ok(Str(s)),
|
||||
Err(e) => error(&e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn time_ms(_a: MalArgs) -> MalRet {
|
||||
let ms_e = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(d) => d,
|
||||
Err(e) => return error(&format!("{:?}", e)),
|
||||
};
|
||||
Ok(Int(
|
||||
ms_e.as_secs() as i64 * 1000 + ms_e.subsec_nanos() as i64 / 1_000_000
|
||||
))
|
||||
}
|
||||
|
||||
fn get(a: MalArgs) -> MalRet {
|
||||
match (a[0].clone(), a[1].clone()) {
|
||||
(Nil, _) => Ok(Nil),
|
||||
(Hash(ref hm, _), Str(ref s)) => match hm.get(s) {
|
||||
Some(mv) => Ok(mv.clone()),
|
||||
None => Ok(Nil),
|
||||
},
|
||||
_ => error("illegal get args"),
|
||||
}
|
||||
}
|
||||
|
||||
fn assoc(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
Hash(ref hm, _) => _assoc((**hm).clone(), a[1..].to_vec()),
|
||||
_ => error("assoc on non-Hash Map"),
|
||||
}
|
||||
}
|
||||
|
||||
fn dissoc(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
Hash(ref hm, _) => _dissoc((**hm).clone(), a[1..].to_vec()),
|
||||
_ => error("dissoc on non-Hash Map"),
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_q(a: MalArgs) -> MalRet {
|
||||
match (a[0].clone(), a[1].clone()) {
|
||||
(Hash(ref hm, _), Str(ref s)) => Ok(Bool(hm.contains_key(s))),
|
||||
_ => error("illegal get args"),
|
||||
}
|
||||
}
|
||||
|
||||
fn keys(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
Hash(ref hm, _) => Ok(list!(hm.keys().map(|k| { Str(k.to_string()) }).collect())),
|
||||
_ => error("keys requires Hash Map"),
|
||||
}
|
||||
}
|
||||
|
||||
fn vals(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
Hash(ref hm, _) => Ok(list!(hm.values().map(|v| { v.clone() }).collect())),
|
||||
_ => error("keys requires Hash Map"),
|
||||
}
|
||||
}
|
||||
|
||||
fn vec(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
List(ref v, _) | Vector(ref v, _) => Ok(vector!(v.to_vec())),
|
||||
_ => error("non-seq passed to vec"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cons(a: MalArgs) -> MalRet {
|
||||
match a[1].clone() {
|
||||
List(v, _) | Vector(v, _) => {
|
||||
let mut new_v = vec![a[0].clone()];
|
||||
new_v.extend_from_slice(&v);
|
||||
Ok(list!(new_v.to_vec()))
|
||||
}
|
||||
_ => error("cons expects seq as second arg"),
|
||||
}
|
||||
}
|
||||
|
||||
fn concat(a: MalArgs) -> MalRet {
|
||||
let mut new_v = vec![];
|
||||
for seq in a.iter() {
|
||||
match seq {
|
||||
List(v, _) | Vector(v, _) => new_v.extend_from_slice(v),
|
||||
_ => return error("non-seq passed to concat"),
|
||||
}
|
||||
}
|
||||
Ok(list!(new_v.to_vec()))
|
||||
}
|
||||
|
||||
fn nth(a: MalArgs) -> MalRet {
|
||||
match (a[0].clone(), a[1].clone()) {
|
||||
(List(seq, _), Int(idx)) | (Vector(seq, _), Int(idx)) => {
|
||||
if seq.len() <= idx as usize {
|
||||
return error("nth: index out of range");
|
||||
}
|
||||
Ok(seq[idx as usize].clone())
|
||||
}
|
||||
_ => error("invalid args to nth"),
|
||||
}
|
||||
}
|
||||
|
||||
fn first(a: MalArgs) -> MalRet {
|
||||
match a[0].clone() {
|
||||
List(ref seq, _) | Vector(ref seq, _) if seq.len() == 0 => Ok(Nil),
|
||||
List(ref seq, _) | Vector(ref seq, _) => Ok(seq[0].clone()),
|
||||
Nil => Ok(Nil),
|
||||
_ => error("invalid args to first"),
|
||||
}
|
||||
}
|
||||
|
||||
fn rest(a: MalArgs) -> MalRet {
|
||||
match a[0].clone() {
|
||||
List(ref seq, _) | Vector(ref seq, _) => {
|
||||
if seq.len() > 1 {
|
||||
Ok(list!(seq[1..].to_vec()))
|
||||
} else {
|
||||
Ok(list![])
|
||||
}
|
||||
}
|
||||
Nil => Ok(list![]),
|
||||
_ => error("invalid args to first"),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(a: MalArgs) -> MalRet {
|
||||
match a[a.len() - 1] {
|
||||
List(ref v, _) | Vector(ref v, _) => {
|
||||
let f = &a[0];
|
||||
let mut fargs = a[1..a.len() - 1].to_vec();
|
||||
fargs.extend_from_slice(&v);
|
||||
f.apply(fargs)
|
||||
}
|
||||
_ => error("apply called with non-seq"),
|
||||
}
|
||||
}
|
||||
|
||||
fn map(a: MalArgs) -> MalRet {
|
||||
match a[1] {
|
||||
List(ref v, _) | Vector(ref v, _) => {
|
||||
let mut res = vec![];
|
||||
for mv in v.iter() {
|
||||
res.push(a[0].apply(vec![mv.clone()])?)
|
||||
}
|
||||
Ok(list!(res))
|
||||
}
|
||||
_ => error("map called with non-seq"),
|
||||
}
|
||||
}
|
||||
|
||||
fn conj(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
List(ref v, _) => {
|
||||
let sl = a[1..]
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|a| a.clone())
|
||||
.collect::<Vec<MalVal>>();
|
||||
Ok(list!([&sl[..], v].concat()))
|
||||
}
|
||||
Vector(ref v, _) => Ok(vector!([v, &a[1..]].concat())),
|
||||
_ => error("conj: called with non-seq"),
|
||||
}
|
||||
}
|
||||
|
||||
fn seq(a: MalArgs) -> MalRet {
|
||||
match a[0] {
|
||||
List(ref v, _) | Vector(ref v, _) if v.len() == 0 => Ok(Nil),
|
||||
List(ref v, _) | Vector(ref v, _) => Ok(list!(v.to_vec())),
|
||||
Str(ref s) if s.len() == 0 => Ok(Nil),
|
||||
Str(ref s) if !a[0].keyword_q() => {
|
||||
Ok(list!(s.chars().map(|c| { Str(c.to_string()) }).collect()))
|
||||
}
|
||||
Nil => Ok(Nil),
|
||||
_ => error("seq: called with non-seq"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ns() -> Vec<(&'static str, MalVal)> {
|
||||
vec![
|
||||
("=", func(|a| Ok(Bool(a[0] == a[1])))),
|
||||
("throw", func(|a| Err(ErrMalVal(a[0].clone())))),
|
||||
("nil?", func(fn_is_type!(Nil))),
|
||||
("true?", func(fn_is_type!(Bool(true)))),
|
||||
("false?", func(fn_is_type!(Bool(false)))),
|
||||
("symbol", func(symbol)),
|
||||
("symbol?", func(fn_is_type!(Sym(_)))),
|
||||
(
|
||||
"string?",
|
||||
func(fn_is_type!(Str(ref s) if !s.starts_with("\u{29e}"))),
|
||||
),
|
||||
("keyword", func(|a| a[0].keyword())),
|
||||
(
|
||||
"keyword?",
|
||||
func(fn_is_type!(Str(ref s) if s.starts_with("\u{29e}"))),
|
||||
),
|
||||
("number?", func(fn_is_type!(Int(_)))),
|
||||
(
|
||||
"fn?",
|
||||
func(fn_is_type!(MalFunc{is_macro,..} if !is_macro,Func(_,_))),
|
||||
),
|
||||
(
|
||||
"macro?",
|
||||
func(fn_is_type!(MalFunc{is_macro,..} if is_macro)),
|
||||
),
|
||||
("pr-str", func(|a| Ok(Str(pr_seq(&a, true, "", "", " "))))),
|
||||
("str", func(|a| Ok(Str(pr_seq(&a, false, "", "", ""))))),
|
||||
(
|
||||
"prn",
|
||||
func(|a| {
|
||||
println!("{}", pr_seq(&a, true, "", "", " "));
|
||||
Ok(Nil)
|
||||
}),
|
||||
),
|
||||
(
|
||||
"println",
|
||||
func(|a| {
|
||||
println!("{}", pr_seq(&a, false, "", "", " "));
|
||||
Ok(Nil)
|
||||
}),
|
||||
),
|
||||
("read-string", func(fn_str!(|s| { read_str(s) }))),
|
||||
("slurp", func(fn_str!(|f| { slurp(f) }))),
|
||||
("<", func(fn_t_int_int!(Bool, |i, j| { i < j }))),
|
||||
("<=", func(fn_t_int_int!(Bool, |i, j| { i <= j }))),
|
||||
(">", func(fn_t_int_int!(Bool, |i, j| { i > j }))),
|
||||
(">=", func(fn_t_int_int!(Bool, |i, j| { i >= j }))),
|
||||
("+", func(fn_t_int_int!(Int, |i, j| { i + j }))),
|
||||
("-", func(fn_t_int_int!(Int, |i, j| { i - j }))),
|
||||
("*", func(fn_t_int_int!(Int, |i, j| { i * j }))),
|
||||
("/", func(fn_t_int_int!(Int, |i, j| { i / j }))),
|
||||
("time-ms", func(time_ms)),
|
||||
("sequential?", func(fn_is_type!(List(_, _), Vector(_, _)))),
|
||||
("list", func(|a| Ok(list!(a)))),
|
||||
("list?", func(fn_is_type!(List(_, _)))),
|
||||
("vector", func(|a| Ok(vector!(a)))),
|
||||
("vector?", func(fn_is_type!(Vector(_, _)))),
|
||||
("hash-map", func(|a| hash_map(a))),
|
||||
("map?", func(fn_is_type!(Hash(_, _)))),
|
||||
("assoc", func(assoc)),
|
||||
("dissoc", func(dissoc)),
|
||||
("get", func(get)),
|
||||
("contains?", func(contains_q)),
|
||||
("keys", func(keys)),
|
||||
("vals", func(vals)),
|
||||
("vec", func(vec)),
|
||||
("cons", func(cons)),
|
||||
("concat", func(concat)),
|
||||
("empty?", func(|a| a[0].empty_q())),
|
||||
("nth", func(nth)),
|
||||
("first", func(first)),
|
||||
("rest", func(rest)),
|
||||
("count", func(|a| a[0].count())),
|
||||
("apply", func(apply)),
|
||||
("map", func(map)),
|
||||
("conj", func(conj)),
|
||||
("seq", func(seq)),
|
||||
("meta", func(|a| a[0].get_meta())),
|
||||
("with-meta", func(|a| a[0].clone().with_meta(&a[1]))),
|
||||
("atom", func(|a| Ok(atom(&a[0])))),
|
||||
("atom?", func(fn_is_type!(Atom(_)))),
|
||||
("deref", func(|a| a[0].deref())),
|
||||
("reset!", func(|a| a[0].reset_bang(&a[1]))),
|
||||
("swap!", func(|a| a[0].swap_bang(&a[1..].to_vec()))),
|
||||
]
|
||||
}
|
||||
85
lisp/env.rs
Normal file
85
lisp/env.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
//use std::collections::HashMap;
|
||||
use fnv::FnvHashMap;
|
||||
|
||||
use crate::types::MalErr::ErrString;
|
||||
use crate::types::MalVal::{List, Nil, Sym, Vector};
|
||||
use crate::types::{error, MalErr, MalRet, MalVal};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EnvStruct {
|
||||
data: RefCell<FnvHashMap<String, MalVal>>,
|
||||
pub outer: Option<Env>,
|
||||
}
|
||||
|
||||
pub type Env = Rc<EnvStruct>;
|
||||
|
||||
// TODO: it would be nice to use impl here but it doesn't work on
|
||||
// a deftype (i.e. Env)
|
||||
|
||||
pub fn env_new(outer: Option<Env>) -> Env {
|
||||
Rc::new(EnvStruct {
|
||||
data: RefCell::new(FnvHashMap::default()),
|
||||
outer: outer,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: mbinds and exprs as & types
|
||||
pub fn env_bind(outer: Option<Env>, mbinds: MalVal, exprs: Vec<MalVal>) -> Result<Env, MalErr> {
|
||||
let env = env_new(outer);
|
||||
match mbinds {
|
||||
List(binds, _) | Vector(binds, _) => {
|
||||
for (i, b) in binds.iter().enumerate() {
|
||||
match b {
|
||||
Sym(s) if s == "&" => {
|
||||
env_set(&env, binds[i + 1].clone(), list!(exprs[i..].to_vec()))?;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
env_set(&env, b.clone(), exprs[i].clone())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(env)
|
||||
}
|
||||
_ => Err(ErrString("env_bind binds not List/Vector".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_find(env: &Env, key: &str) -> Option<Env> {
|
||||
match (env.data.borrow().contains_key(key), env.outer.clone()) {
|
||||
(true, _) => Some(env.clone()),
|
||||
(false, Some(o)) => env_find(&o, key),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_get(env: &Env, key: &MalVal) -> MalRet {
|
||||
match key {
|
||||
Sym(ref s) => match env_find(env, s) {
|
||||
Some(e) => Ok(e
|
||||
.data
|
||||
.borrow()
|
||||
.get(s)
|
||||
.ok_or(ErrString(format!("'{}' not found", s)))?
|
||||
.clone()),
|
||||
_ => error(&format!("'{}' not found", s)),
|
||||
},
|
||||
_ => error("Env.get called with non-Str"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet {
|
||||
match key {
|
||||
Sym(ref s) => {
|
||||
env.data.borrow_mut().insert(s.to_string(), val.clone());
|
||||
Ok(val)
|
||||
}
|
||||
_ => error("Env.set called with non-Str"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_sets(env: &Env, key: &str, val: MalVal) {
|
||||
env.data.borrow_mut().insert(key.to_string(), val);
|
||||
}
|
||||
46
lisp/jubjub.lisp
Normal file
46
lisp/jubjub.lisp
Normal file
@@ -0,0 +1,46 @@
|
||||
(def C_D (const "0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))
|
||||
(def C_ONE (const "0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
(def jjadd (fn x1 y1 x2 y2) (
|
||||
(def U (mul (add (x1 y1)) (add (x2 y2))))
|
||||
(enforce
|
||||
(add_lc0 (x1 y1))
|
||||
(add_lc1 (x2 y2))
|
||||
(add_lc2 U))
|
||||
(def A (mul (x2 x1)))
|
||||
(def B (mul (x2 y1)))
|
||||
(def C (mul (C_ONE A)))
|
||||
(enforce
|
||||
(add_coeff_lc0 (C_D A))
|
||||
(add_lc1 B)
|
||||
(add_lc2 C))
|
||||
(def Px
|
||||
(div (add A B)
|
||||
(add C_ONE C)))
|
||||
(enforce
|
||||
(add_one_lc0)
|
||||
(sub_lc0 C)
|
||||
(add_lc1 Px)
|
||||
(add_lc2 (A B)))
|
||||
|
||||
(def Py
|
||||
(div (sub U A B)
|
||||
(sub C_ONE C)))
|
||||
(enforce
|
||||
(add_one_lc0)
|
||||
(sub_lc0 C)
|
||||
(add_lc1 Py)
|
||||
(add_lc2 (U A B)))
|
||||
(Px Py)
|
||||
)
|
||||
(def input_spend (contract x1 y1 x2 y2) (
|
||||
(def P (jjadd (x1 y1 x2 y2)))
|
||||
(enforce
|
||||
(add_lc0 Px)
|
||||
(add_lc1_one)
|
||||
(add_lc2 Px))
|
||||
(enforce
|
||||
(add_lc0 Py)
|
||||
(add_lc1_one)
|
||||
(add_lc2 Py))
|
||||
)
|
||||
|
||||
2
lisp/new.lisp
Normal file
2
lisp/new.lisp
Normal file
@@ -0,0 +1,2 @@
|
||||
(def! C_D "0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1")
|
||||
(println C_D)
|
||||
61
lisp/printer.rs
Normal file
61
lisp/printer.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use crate::types::MalVal;
|
||||
use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector};
|
||||
|
||||
fn escape_str(s: &str) -> String {
|
||||
s.chars()
|
||||
.map(|c| match c {
|
||||
'"' => "\\\"".to_string(),
|
||||
'\n' => "\\n".to_string(),
|
||||
'\\' => "\\\\".to_string(),
|
||||
_ => c.to_string(),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("")
|
||||
}
|
||||
|
||||
impl MalVal {
|
||||
pub fn pr_str(&self, print_readably: bool) -> String {
|
||||
match self {
|
||||
Nil => String::from("nil"),
|
||||
Bool(true) => String::from("true"),
|
||||
Bool(false) => String::from("false"),
|
||||
Int(i) => format!("{}", i),
|
||||
//Float(f) => format!("{}", f),
|
||||
Str(s) => {
|
||||
if s.starts_with("\u{29e}") {
|
||||
format!(":{}", &s[2..])
|
||||
} else if print_readably {
|
||||
format!("\"{}\"", escape_str(s))
|
||||
} else {
|
||||
s.clone()
|
||||
}
|
||||
}
|
||||
Sym(s) => s.clone(),
|
||||
List(l, _) => pr_seq(&**l, print_readably, "(", ")", " "),
|
||||
Vector(l, _) => pr_seq(&**l, print_readably, "[", "]", " "),
|
||||
Hash(hm, _) => {
|
||||
let l: Vec<MalVal> = hm
|
||||
.iter()
|
||||
.flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()])
|
||||
.collect();
|
||||
pr_seq(&l, print_readably, "{", "}", " ")
|
||||
}
|
||||
Func(f, _) => format!("#<fn {:?}>", f),
|
||||
MalFunc {
|
||||
ast: a, params: p, ..
|
||||
} => format!("(fn* {} {})", p.pr_str(true), a.pr_str(true)),
|
||||
Atom(a) => format!("(atom {})", a.borrow().pr_str(true)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pr_seq(
|
||||
seq: &Vec<MalVal>,
|
||||
print_readably: bool,
|
||||
start: &str,
|
||||
end: &str,
|
||||
join: &str,
|
||||
) -> String {
|
||||
let strs: Vec<String> = seq.iter().map(|x| x.pr_str(print_readably)).collect();
|
||||
format!("{}{}{}", start, strs.join(join), end)
|
||||
}
|
||||
113
lisp/racket/jj.rkt
Normal file
113
lisp/racket/jj.rkt
Normal file
@@ -0,0 +1,113 @@
|
||||
#lang racket
|
||||
|
||||
(require "zk.rkt")
|
||||
|
||||
(struct jj_point
|
||||
(u v)
|
||||
)
|
||||
|
||||
(define (create_jj_param_point name)
|
||||
(jj_point
|
||||
(zk_param (string-append name "_u"))
|
||||
(zk_param (string-append name "_v"))
|
||||
)
|
||||
)
|
||||
(define (create_jj_public_point name)
|
||||
(jj_point
|
||||
(zk_public (string-append name "_u"))
|
||||
(zk_public (string-append name "_v"))
|
||||
)
|
||||
)
|
||||
|
||||
(define (zk_jj_add namespace result a b)
|
||||
(zk_comment "call jj_add()")
|
||||
(let* ([namespace (append namespace (list "_jj_add"))]
|
||||
[U (zk_private namespace 'U)]
|
||||
[A (zk_private namespace 'A)]
|
||||
[B (zk_private namespace 'B)]
|
||||
[C (zk_private namespace 'C)]
|
||||
[tmp (zk_local namespace 'tmp)])
|
||||
(zk_comment "Compute U = (x1 + y1) * (y2 - EDWARDS_A*x2)")
|
||||
(zk_comment " = (x1 + y1) * (x2 + y2)")
|
||||
(zk_set U (jj_point-u a))
|
||||
(zk_add U (jj_point-v a))
|
||||
|
||||
(zk_set tmp (jj_point-u b))
|
||||
(zk_add tmp (jj_point-v b))
|
||||
|
||||
(zk_mul U tmp)
|
||||
|
||||
(zk_comment "assert (x1 + y1) * (x2 + y2) == U")
|
||||
(zk_lc0_add (jj_point-u a))
|
||||
(zk_lc0_add (jj_point-v a))
|
||||
(zk_lc1_add (jj_point-u b))
|
||||
(zk_lc1_add (jj_point-v b))
|
||||
(zk_lc2_add U)
|
||||
(zk_enforce)
|
||||
|
||||
(zk_comment "Compute A = y2 * x1")
|
||||
(zk_set A (jj_point-v b))
|
||||
(zk_mul A (jj_point-u a))
|
||||
(zk_comment "Compute B = x2 * y1")
|
||||
(zk_set B (jj_point-u b))
|
||||
(zk_mul B (jj_point-v a))
|
||||
(zk_comment "Compute C = d*A*B")
|
||||
(zk_load C const_d)
|
||||
(zk_mul C A)
|
||||
(zk_mul C B)
|
||||
|
||||
(zk_comment "assert (d * A) * (B) == C")
|
||||
(zk_lc0_add_coeff const_d A)
|
||||
(zk_lc1_add B)
|
||||
(zk_lc2_add C)
|
||||
(zk_enforce)
|
||||
|
||||
(zk_comment "Compute P.x = (A + B) / (1 + C)")
|
||||
(zk_set (jj_point-u result) A)
|
||||
(zk_add (jj_point-u result) B)
|
||||
; Re-use the tmp variable from earlier here
|
||||
(zk_load tmp const_one)
|
||||
(zk_add tmp C)
|
||||
(zk_divide (jj_point-u result) tmp)
|
||||
|
||||
(zk_lc0_add_one)
|
||||
(zk_lc0_add C)
|
||||
(zk_lc1_add (jj_point-u result))
|
||||
(zk_lc2_add A)
|
||||
(zk_lc2_add B)
|
||||
(zk_enforce)
|
||||
|
||||
(zk_comment "Compute P.y = (U - A - B) / (1 - C)")
|
||||
(zk_set (jj_point-v result) U)
|
||||
(zk_sub (jj_point-v result) A)
|
||||
(zk_sub (jj_point-v result) B)
|
||||
; Re-use the tmp variable from earlier here
|
||||
(zk_load tmp const_one)
|
||||
(zk_sub tmp C)
|
||||
(zk_divide (jj_point-v result) tmp)
|
||||
|
||||
(zk_lc0_add_one)
|
||||
(zk_lc0_sub C)
|
||||
(zk_lc1_add (jj_point-v result))
|
||||
(zk_lc2_add U)
|
||||
(zk_lc2_sub A)
|
||||
(zk_lc2_sub B)
|
||||
(zk_enforce)
|
||||
)
|
||||
)
|
||||
|
||||
(create_zk_output "jj.psm")
|
||||
|
||||
(define const_d (zk_constant
|
||||
"d" "0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))
|
||||
(define const_one (zk_constant
|
||||
"one" "0x0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
|
||||
(zk_contract_begin "foo")
|
||||
(define namespace (list "_"))
|
||||
(define a (create_jj_param_point "a"))
|
||||
(define b (create_jj_param_point "b"))
|
||||
(define result (create_jj_public_point "result"))
|
||||
(zk_jj_add namespace result a b)
|
||||
(zk_contract_end)
|
||||
|
||||
141
lisp/racket/zk.rkt
Normal file
141
lisp/racket/zk.rkt
Normal file
@@ -0,0 +1,141 @@
|
||||
#lang racket
|
||||
|
||||
(provide zk_variable)
|
||||
(provide zk_constant)
|
||||
(provide zk_param)
|
||||
(provide zk_public)
|
||||
(provide zk_local)
|
||||
(provide zk_private)
|
||||
(provide zk_comment)
|
||||
(provide zk_set)
|
||||
(provide zk_add)
|
||||
(provide zk_sub)
|
||||
(provide zk_mul)
|
||||
(provide zk_divide)
|
||||
(provide zk_load)
|
||||
(provide zk_lc0_add)
|
||||
(provide zk_lc1_add)
|
||||
(provide zk_lc2_add)
|
||||
(provide zk_lc0_sub)
|
||||
(provide zk_lc1_sub)
|
||||
(provide zk_lc2_sub)
|
||||
(provide zk_lc0_add_coeff)
|
||||
(provide zk_lc1_add_coeff)
|
||||
(provide zk_lc2_add_coeff)
|
||||
(provide zk_lc0_add_one)
|
||||
(provide zk_lc1_add_one)
|
||||
(provide zk_lc2_add_one)
|
||||
(provide zk_enforce)
|
||||
|
||||
(provide create_zk_output)
|
||||
(provide zk_contract_begin)
|
||||
(provide zk_contract_end)
|
||||
|
||||
(define out '0)
|
||||
(define (create_zk_output filename)
|
||||
(set! out (open-output-file "jj.psm" #:exists 'truncate))
|
||||
)
|
||||
|
||||
(struct zk_variable
|
||||
(name type)
|
||||
)
|
||||
|
||||
(define (zk_constant name hex_value)
|
||||
(fprintf out "constant ~a ~a\n" name hex_value)
|
||||
name
|
||||
)
|
||||
|
||||
(define (zk_contract_begin contract_name)
|
||||
(fprintf out "contract ~a\n" contract_name)
|
||||
)
|
||||
(define (zk_contract_end)
|
||||
(fprintf out "end\n")
|
||||
)
|
||||
|
||||
(define (zk_param name)
|
||||
(fprintf out "param ~a\n" name)
|
||||
(zk_variable name 'param)
|
||||
)
|
||||
|
||||
(define (zk_public name)
|
||||
(fprintf out "public ~a\n" name)
|
||||
(zk_variable name 'public)
|
||||
)
|
||||
|
||||
(define (strings->string sts)
|
||||
(apply string-append sts))
|
||||
|
||||
(define (apply_ns namespace name)
|
||||
(strings->string
|
||||
(append namespace
|
||||
(list "__" (symbol->string name))
|
||||
)))
|
||||
|
||||
(define (zk_local namespace name)
|
||||
(let ([name (apply_ns namespace name)])
|
||||
(fprintf out "local ~a\n" name)
|
||||
(zk_variable name 'local)
|
||||
)
|
||||
)
|
||||
|
||||
(define (zk_private namespace name)
|
||||
(let ([name (apply_ns namespace name)])
|
||||
(fprintf out "private ~a\n" name)
|
||||
(zk_variable name 'private)
|
||||
)
|
||||
)
|
||||
|
||||
(define (zk_comment str)
|
||||
(fprintf out "# ~a\n" str)
|
||||
)
|
||||
|
||||
(define (zk_set self other)
|
||||
(fprintf out "set ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
|
||||
)
|
||||
(define (zk_add self other)
|
||||
(fprintf out "add ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
|
||||
)
|
||||
(define (zk_sub self other)
|
||||
(fprintf out "sub ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
|
||||
)
|
||||
(define (zk_mul self other)
|
||||
(fprintf out "mul ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
|
||||
)
|
||||
(define (zk_divide self other)
|
||||
(fprintf out "divide ~a ~a\n"
|
||||
(zk_variable-name self) (zk_variable-name other))
|
||||
)
|
||||
|
||||
(define (zk_load self constant)
|
||||
(fprintf out "load ~a ~a\n" (zk_variable-name self) constant)
|
||||
)
|
||||
|
||||
(define (zk_lc0_add self)
|
||||
(fprintf out "lc0_add ~a\n" (zk_variable-name self)))
|
||||
(define (zk_lc1_add self)
|
||||
(fprintf out "lc1_add ~a\n" (zk_variable-name self)))
|
||||
(define (zk_lc2_add self)
|
||||
(fprintf out "lc2_add ~a\n" (zk_variable-name self)))
|
||||
(define (zk_lc0_sub self)
|
||||
(fprintf out "lc0_sub ~a\n" (zk_variable-name self)))
|
||||
(define (zk_lc1_sub self)
|
||||
(fprintf out "lc1_sub ~a\n" (zk_variable-name self)))
|
||||
(define (zk_lc2_sub self)
|
||||
(fprintf out "lc2_sub ~a\n" (zk_variable-name self)))
|
||||
(define (zk_lc0_add_coeff constant self)
|
||||
(fprintf out "lc0_add_coeff ~a ~a\n" constant (zk_variable-name self)))
|
||||
(define (zk_lc1_add_coeff constant self)
|
||||
(fprintf out "lc1_add_coeff ~a ~a\n" constant (zk_variable-name self)))
|
||||
(define (zk_lc2_add_coeff constant self)
|
||||
(fprintf out "lc2_add_coeff ~a ~a\n" constant (zk_variable-name self)))
|
||||
(define (zk_lc0_add_one)
|
||||
(fprintf out "lc0_add_one\n"))
|
||||
(define (zk_lc1_add_one)
|
||||
(fprintf out "lc1_add_one\n"))
|
||||
(define (zk_lc2_add_one)
|
||||
(fprintf out "lc2_add_one\n"))
|
||||
(define (zk_enforce)
|
||||
(fprintf out "enforce\n")
|
||||
)
|
||||
|
||||
|
||||
156
lisp/reader.rs
Normal file
156
lisp/reader.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
use regex::{Captures, Regex};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::types::MalErr::ErrString;
|
||||
use crate::types::MalVal::{Bool, Int, List, Nil, Str, Sym, Vector};
|
||||
use crate::types::{error, hash_map, MalErr, MalRet, MalVal};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Reader {
|
||||
tokens: Vec<String>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Reader {
|
||||
fn next(&mut self) -> Result<String, MalErr> {
|
||||
self.pos = self.pos + 1;
|
||||
Ok(self
|
||||
.tokens
|
||||
.get(self.pos - 1)
|
||||
.ok_or(ErrString("underflow".to_string()))?
|
||||
.to_string())
|
||||
}
|
||||
fn peek(&self) -> Result<String, MalErr> {
|
||||
Ok(self
|
||||
.tokens
|
||||
.get(self.pos)
|
||||
.ok_or(ErrString("underflow".to_string()))?
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn tokenize(str: &str) -> Vec<String> {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(
|
||||
r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)]+)"###
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let mut res = vec![];
|
||||
for cap in RE.captures_iter(str) {
|
||||
if cap[1].starts_with(";") {
|
||||
continue;
|
||||
}
|
||||
res.push(String::from(&cap[1]));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn unescape_str(s: &str) -> String {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r#"\\(.)"#).unwrap();
|
||||
}
|
||||
RE.replace_all(&s, |caps: &Captures| {
|
||||
format!("{}", if &caps[1] == "n" { "\n" } else { &caps[1] })
|
||||
})
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn read_atom(rdr: &mut Reader) -> MalRet {
|
||||
lazy_static! {
|
||||
static ref INT_RE: Regex = Regex::new(r"^-?[0-9]+$").unwrap();
|
||||
static ref STR_RE: Regex = Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap();
|
||||
}
|
||||
let token = rdr.next()?;
|
||||
match &token[..] {
|
||||
"nil" => Ok(Nil),
|
||||
"false" => Ok(Bool(false)),
|
||||
"true" => Ok(Bool(true)),
|
||||
_ => {
|
||||
if INT_RE.is_match(&token) {
|
||||
Ok(Int(token.parse().unwrap()))
|
||||
} else if STR_RE.is_match(&token) {
|
||||
Ok(Str(unescape_str(&token[1..token.len() - 1])))
|
||||
} else if token.starts_with("\"") {
|
||||
error("expected '\"', got EOF")
|
||||
} else if token.starts_with(":") {
|
||||
Ok(Str(format!("\u{29e}{}", &token[1..])))
|
||||
} else {
|
||||
Ok(Sym(token.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_seq(rdr: &mut Reader, end: &str) -> MalRet {
|
||||
let mut seq: Vec<MalVal> = vec![];
|
||||
rdr.next()?;
|
||||
loop {
|
||||
let token = match rdr.peek() {
|
||||
Ok(t) => t,
|
||||
Err(_) => return error(&format!("expected '{}', got EOF", end)),
|
||||
};
|
||||
if token == end {
|
||||
break;
|
||||
}
|
||||
seq.push(read_form(rdr)?)
|
||||
}
|
||||
let _ = rdr.next();
|
||||
match end {
|
||||
")" => Ok(list!(seq)),
|
||||
"]" => Ok(vector!(seq)),
|
||||
"}" => hash_map(seq),
|
||||
_ => error("read_seq unknown end value"),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_form(rdr: &mut Reader) -> MalRet {
|
||||
let token = rdr.peek()?;
|
||||
match &token[..] {
|
||||
"'" => {
|
||||
let _ = rdr.next();
|
||||
Ok(list![Sym("quote".to_string()), read_form(rdr)?])
|
||||
}
|
||||
"`" => {
|
||||
let _ = rdr.next();
|
||||
Ok(list![Sym("quasiquote".to_string()), read_form(rdr)?])
|
||||
}
|
||||
"~" => {
|
||||
let _ = rdr.next();
|
||||
Ok(list![Sym("unquote".to_string()), read_form(rdr)?])
|
||||
}
|
||||
"~@" => {
|
||||
let _ = rdr.next();
|
||||
Ok(list![Sym("splice-unquote".to_string()), read_form(rdr)?])
|
||||
}
|
||||
"^" => {
|
||||
let _ = rdr.next();
|
||||
let meta = read_form(rdr)?;
|
||||
Ok(list![Sym("with-meta".to_string()), read_form(rdr)?, meta])
|
||||
}
|
||||
"@" => {
|
||||
let _ = rdr.next();
|
||||
Ok(list![Sym("deref".to_string()), read_form(rdr)?])
|
||||
}
|
||||
")" => error("unexpected ')'"),
|
||||
"(" => read_seq(rdr, ")"),
|
||||
"]" => error("unexpected ']'"),
|
||||
"[" => read_seq(rdr, "]"),
|
||||
"}" => error("unexpected '}'"),
|
||||
"{" => read_seq(rdr, "}"),
|
||||
_ => read_atom(rdr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_str(str: String) -> MalRet {
|
||||
let tokens = tokenize(&str);
|
||||
//println!("tokens: {:?}", tokens);
|
||||
if tokens.len() == 0 {
|
||||
return error("no input");
|
||||
}
|
||||
read_form(&mut Reader {
|
||||
pos: 0,
|
||||
tokens: tokens,
|
||||
})
|
||||
}
|
||||
240
lisp/types.rs
Normal file
240
lisp/types.rs
Normal file
@@ -0,0 +1,240 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
//use std::collections::HashMap;
|
||||
use fnv::FnvHashMap;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::env::{env_bind, Env};
|
||||
use crate::types::MalErr::{ErrMalVal, ErrString};
|
||||
use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MalVal {
|
||||
Nil,
|
||||
Bool(bool),
|
||||
Int(i64),
|
||||
//Float(f64),
|
||||
Str(String),
|
||||
Sym(String),
|
||||
List(Rc<Vec<MalVal>>, Rc<MalVal>),
|
||||
Vector(Rc<Vec<MalVal>>, Rc<MalVal>),
|
||||
Hash(Rc<FnvHashMap<String, MalVal>>, Rc<MalVal>),
|
||||
Func(fn(MalArgs) -> MalRet, Rc<MalVal>),
|
||||
MalFunc {
|
||||
eval: fn(ast: MalVal, env: Env) -> MalRet,
|
||||
ast: Rc<MalVal>,
|
||||
env: Env,
|
||||
params: Rc<MalVal>,
|
||||
is_macro: bool,
|
||||
meta: Rc<MalVal>,
|
||||
},
|
||||
Atom(Rc<RefCell<MalVal>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MalErr {
|
||||
ErrString(String),
|
||||
ErrMalVal(MalVal),
|
||||
}
|
||||
|
||||
pub type MalArgs = Vec<MalVal>;
|
||||
pub type MalRet = Result<MalVal, MalErr>;
|
||||
|
||||
// type utility macros
|
||||
|
||||
macro_rules! list {
|
||||
($seq:expr) => {{
|
||||
List(Rc::new($seq),Rc::new(Nil))
|
||||
}};
|
||||
[$($args:expr),*] => {{
|
||||
let v: Vec<MalVal> = vec![$($args),*];
|
||||
List(Rc::new(v),Rc::new(Nil))
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! vector {
|
||||
($seq:expr) => {{
|
||||
Vector(Rc::new($seq),Rc::new(Nil))
|
||||
}};
|
||||
[$($args:expr),*] => {{
|
||||
let v: Vec<MalVal> = vec![$($args),*];
|
||||
Vector(Rc::new(v),Rc::new(Nil))
|
||||
}}
|
||||
}
|
||||
|
||||
// type utility functions
|
||||
|
||||
pub fn error(s: &str) -> MalRet {
|
||||
Err(ErrString(s.to_string()))
|
||||
}
|
||||
|
||||
pub fn format_error(e: MalErr) -> String {
|
||||
match e {
|
||||
ErrString(s) => s.clone(),
|
||||
ErrMalVal(mv) => mv.pr_str(true),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn atom(mv: &MalVal) -> MalVal {
|
||||
Atom(Rc::new(RefCell::new(mv.clone())))
|
||||
}
|
||||
|
||||
impl MalVal {
|
||||
pub fn keyword(&self) -> MalRet {
|
||||
match self {
|
||||
Str(s) if s.starts_with("\u{29e}") => Ok(Str(s.to_string())),
|
||||
Str(s) => Ok(Str(format!("\u{29e}{}", s))),
|
||||
_ => error("invalid type for keyword"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty_q(&self) -> MalRet {
|
||||
match self {
|
||||
List(l, _) | Vector(l, _) => Ok(Bool(l.len() == 0)),
|
||||
Nil => Ok(Bool(true)),
|
||||
_ => error("invalid type for empty?"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(&self) -> MalRet {
|
||||
match self {
|
||||
List(l, _) | Vector(l, _) => Ok(Int(l.len() as i64)),
|
||||
Nil => Ok(Int(0)),
|
||||
_ => error("invalid type for count"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply(&self, args: MalArgs) -> MalRet {
|
||||
match *self {
|
||||
Func(f, _) => f(args),
|
||||
MalFunc {
|
||||
eval,
|
||||
ref ast,
|
||||
ref env,
|
||||
ref params,
|
||||
..
|
||||
} => {
|
||||
let a = &**ast;
|
||||
let p = &**params;
|
||||
let fn_env = env_bind(Some(env.clone()), p.clone(), args)?;
|
||||
Ok(eval(a.clone(), fn_env)?)
|
||||
}
|
||||
_ => error("attempt to call non-function"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keyword_q(&self) -> bool {
|
||||
match self {
|
||||
Str(s) if s.starts_with("\u{29e}") => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deref(&self) -> MalRet {
|
||||
match self {
|
||||
Atom(a) => Ok(a.borrow().clone()),
|
||||
_ => error("attempt to deref a non-Atom"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_bang(&self, new: &MalVal) -> MalRet {
|
||||
match self {
|
||||
Atom(a) => {
|
||||
*a.borrow_mut() = new.clone();
|
||||
Ok(new.clone())
|
||||
}
|
||||
_ => error("attempt to reset! a non-Atom"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_bang(&self, args: &MalArgs) -> MalRet {
|
||||
match self {
|
||||
Atom(a) => {
|
||||
let f = &args[0];
|
||||
let mut fargs = args[1..].to_vec();
|
||||
fargs.insert(0, a.borrow().clone());
|
||||
*a.borrow_mut() = f.apply(fargs)?;
|
||||
Ok(a.borrow().clone())
|
||||
}
|
||||
_ => error("attempt to swap! a non-Atom"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_meta(&self) -> MalRet {
|
||||
match self {
|
||||
List(_, meta) | Vector(_, meta) | Hash(_, meta) => Ok((&**meta).clone()),
|
||||
Func(_, meta) => Ok((&**meta).clone()),
|
||||
MalFunc { meta, .. } => Ok((&**meta).clone()),
|
||||
_ => error("meta not supported by type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_meta(&mut self, new_meta: &MalVal) -> MalRet {
|
||||
match self {
|
||||
List(_, ref mut meta)
|
||||
| Vector(_, ref mut meta)
|
||||
| Hash(_, ref mut meta)
|
||||
| Func(_, ref mut meta)
|
||||
| MalFunc { ref mut meta, .. } => {
|
||||
*meta = Rc::new((&*new_meta).clone());
|
||||
}
|
||||
_ => return error("with-meta not supported by type"),
|
||||
};
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for MalVal {
|
||||
fn eq(&self, other: &MalVal) -> bool {
|
||||
match (self, other) {
|
||||
(Nil, Nil) => true,
|
||||
(Bool(ref a), Bool(ref b)) => a == b,
|
||||
(Int(ref a), Int(ref b)) => a == b,
|
||||
(Str(ref a), Str(ref b)) => a == b,
|
||||
(Sym(ref a), Sym(ref b)) => a == b,
|
||||
(List(ref a, _), List(ref b, _))
|
||||
| (Vector(ref a, _), Vector(ref b, _))
|
||||
| (List(ref a, _), Vector(ref b, _))
|
||||
| (Vector(ref a, _), List(ref b, _)) => a == b,
|
||||
(Hash(ref a, _), Hash(ref b, _)) => a == b,
|
||||
(MalFunc { .. }, MalFunc { .. }) => false,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn func(f: fn(MalArgs) -> MalRet) -> MalVal {
|
||||
Func(f, Rc::new(Nil))
|
||||
}
|
||||
|
||||
pub fn _assoc(mut hm: FnvHashMap<String, MalVal>, kvs: MalArgs) -> MalRet {
|
||||
if kvs.len() % 2 != 0 {
|
||||
return error("odd number of elements");
|
||||
}
|
||||
for (k, v) in kvs.iter().tuples() {
|
||||
match k {
|
||||
Str(s) => {
|
||||
hm.insert(s.to_string(), v.clone());
|
||||
}
|
||||
_ => return error("key is not string"),
|
||||
}
|
||||
}
|
||||
Ok(Hash(Rc::new(hm), Rc::new(Nil)))
|
||||
}
|
||||
|
||||
pub fn _dissoc(mut hm: FnvHashMap<String, MalVal>, ks: MalArgs) -> MalRet {
|
||||
for k in ks.iter() {
|
||||
match k {
|
||||
Str(ref s) => {
|
||||
hm.remove(s);
|
||||
}
|
||||
_ => return error("key is not string"),
|
||||
}
|
||||
}
|
||||
Ok(Hash(Rc::new(hm), Rc::new(Nil)))
|
||||
}
|
||||
|
||||
pub fn hash_map(kvs: MalArgs) -> MalRet {
|
||||
let hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
|
||||
_assoc(hm, kvs)
|
||||
}
|
||||
Reference in New Issue
Block a user