Selaa lähdekoodia

added lisp files

ada 5 vuotta sitten
vanhempi
sitoutus
fea2b6c313
10 muutettua tiedostoa jossa 1178 lisäystä ja 0 poistoa
  1. 15 0
      lisp/Cargo.toml
  2. 319 0
      lisp/core.rs
  3. 85 0
      lisp/env.rs
  4. 46 0
      lisp/jubjub.lisp
  5. 2 0
      lisp/new.lisp
  6. 61 0
      lisp/printer.rs
  7. 113 0
      lisp/racket/jj.rkt
  8. 141 0
      lisp/racket/zk.rkt
  9. 156 0
      lisp/reader.rs
  10. 240 0
      lisp/types.rs

+ 15 - 0
lisp/Cargo.toml

@@ -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 - 0
lisp/core.rs

@@ -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 - 0
lisp/env.rs

@@ -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 - 0
lisp/jubjub.lisp

@@ -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 - 0
lisp/new.lisp

@@ -0,0 +1,2 @@
+(def! C_D "0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1")
+(println C_D)

+ 61 - 0
lisp/printer.rs

@@ -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 - 0
lisp/racket/jj.rkt

@@ -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 - 0
lisp/racket/zk.rkt

@@ -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 - 0
lisp/reader.rs

@@ -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 - 0
lisp/types.rs

@@ -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)
+}