lisp.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #![allow(non_snake_case)]
  2. use bls12_381::Scalar;
  3. use sapvi::bls_extensions::BlsStringConversion;
  4. use sapvi::serial::{Decodable, Encodable};
  5. use simplelog::*;
  6. use std::fs;
  7. use std::fs::File;
  8. use std::rc::Rc;
  9. use std::time::Instant;
  10. //use std::collections::HashMap;
  11. use fnv::FnvHashMap;
  12. use itertools::Itertools;
  13. #[macro_use]
  14. extern crate clap;
  15. #[macro_use]
  16. extern crate lazy_static;
  17. extern crate fnv;
  18. extern crate itertools;
  19. extern crate regex;
  20. #[macro_use]
  21. mod types;
  22. use crate::types::MalErr::{ErrMalVal, ErrString};
  23. use crate::types::MalVal::{
  24. Add, Bool, Func, Hash, Lc0, Lc1, Lc2, List, MalFunc, Nil, Str, Sub, Sym, Vector, Zk,
  25. };
  26. use crate::types::ZKCircuit;
  27. use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal};
  28. mod env;
  29. mod printer;
  30. mod reader;
  31. use crate::env::{env_bind, env_find, env_get, env_new, env_set, env_sets, Env};
  32. #[macro_use]
  33. mod core;
  34. // read
  35. fn read(str: &str) -> MalRet {
  36. reader::read_str(str.to_string())
  37. }
  38. // eval
  39. fn qq_iter(elts: &MalArgs) -> MalVal {
  40. let mut acc = list![];
  41. for elt in elts.iter().rev() {
  42. if let List(v, _) = elt {
  43. if v.len() == 2 {
  44. if let Sym(ref s) = v[0] {
  45. if s == "splice-unquote" {
  46. acc = list![Sym("concat".to_string()), v[1].clone(), acc];
  47. continue;
  48. }
  49. }
  50. }
  51. }
  52. acc = list![Sym("cons".to_string()), quasiquote(&elt), acc];
  53. }
  54. return acc;
  55. }
  56. fn quasiquote(ast: &MalVal) -> MalVal {
  57. match ast {
  58. List(v, _) => {
  59. if v.len() == 2 {
  60. if let Sym(ref s) = v[0] {
  61. if s == "unquote" {
  62. return v[1].clone();
  63. }
  64. }
  65. }
  66. return qq_iter(&v);
  67. }
  68. Vector(v, _) => return list![Sym("vec".to_string()), qq_iter(&v)],
  69. Hash(_, _) | Sym(_) => return list![Sym("quote".to_string()), ast.clone()],
  70. _ => ast.clone(),
  71. }
  72. }
  73. fn is_macro_call(ast: &MalVal, env: &Env) -> Option<(MalVal, MalArgs)> {
  74. match ast {
  75. List(v, _) => match v[0] {
  76. Sym(ref s) => match env_find(env, s) {
  77. Some(e) => match env_get(&e, &v[0]) {
  78. Ok(f @ MalFunc { is_macro: true, .. }) => Some((f, v[1..].to_vec())),
  79. _ => None,
  80. },
  81. _ => None,
  82. },
  83. _ => None,
  84. },
  85. _ => None,
  86. }
  87. }
  88. fn macroexpand(mut ast: MalVal, env: &Env) -> (bool, MalRet) {
  89. let mut was_expanded = false;
  90. while let Some((mf, args)) = is_macro_call(&ast, env) {
  91. //println!("macroexpand 1: {:?}", ast);
  92. ast = match mf.apply(args) {
  93. Err(e) => return (false, Err(e)),
  94. Ok(a) => a,
  95. };
  96. //println!("macroexpand 2: {:?}", ast);
  97. was_expanded = true;
  98. }
  99. ((was_expanded, Ok(ast)))
  100. }
  101. fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
  102. match ast {
  103. Sym(_) => Ok(env_get(&env, &ast)?),
  104. List(v, _) => {
  105. let mut lst: MalArgs = vec![];
  106. for a in v.iter() {
  107. lst.push(eval(a.clone(), env.clone())?)
  108. }
  109. Ok(list!(lst))
  110. }
  111. Vector(v, _) => {
  112. let mut lst: MalArgs = vec![];
  113. for a in v.iter() {
  114. lst.push(eval(a.clone(), env.clone())?)
  115. }
  116. Ok(vector!(lst))
  117. }
  118. Hash(hm, _) => {
  119. let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
  120. for (k, v) in hm.iter() {
  121. new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
  122. }
  123. Ok(Hash(Rc::new(new_hm), Rc::new(Nil)))
  124. }
  125. _ => Ok(ast.clone()),
  126. }
  127. }
  128. fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
  129. let ret: MalRet;
  130. 'tco: loop {
  131. ret = match ast.clone() {
  132. List(l, _) => {
  133. if l.len() == 0 {
  134. return Ok(ast);
  135. }
  136. match macroexpand(ast.clone(), &env) {
  137. (true, Ok(new_ast)) => {
  138. ast = new_ast;
  139. continue 'tco;
  140. }
  141. (_, Err(e)) => return Err(e),
  142. _ => (),
  143. }
  144. if l.len() == 0 {
  145. return Ok(ast);
  146. }
  147. let a0 = &l[0];
  148. match a0 {
  149. Sym(ref a0sym) if a0sym == "def!" => {
  150. env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
  151. }
  152. Sym(ref a0sym) if a0sym == "let*" => {
  153. env = env_new(Some(env.clone()));
  154. let (a1, a2) = (l[1].clone(), l[2].clone());
  155. match a1 {
  156. List(ref binds, _) | Vector(ref binds, _) => {
  157. for (b, e) in binds.iter().tuples() {
  158. match b {
  159. Sym(_) => {
  160. let _ = env_set(
  161. &env,
  162. b.clone(),
  163. eval(e.clone(), env.clone())?,
  164. );
  165. }
  166. _ => {
  167. return error("let* with non-Sym binding");
  168. }
  169. }
  170. }
  171. }
  172. _ => {
  173. return error("let* with non-List bindings");
  174. }
  175. };
  176. ast = a2;
  177. continue 'tco;
  178. }
  179. Sym(ref a0sym) if a0sym == "quote" => Ok(l[1].clone()),
  180. Sym(ref a0sym) if a0sym == "quasiquoteexpand" => Ok(quasiquote(&l[1])),
  181. Sym(ref a0sym) if a0sym == "quasiquote" => {
  182. ast = quasiquote(&l[1]);
  183. continue 'tco;
  184. }
  185. Sym(ref a0sym) if a0sym == "defmacro!" => {
  186. let (a1, a2) = (l[1].clone(), l[2].clone());
  187. let r = eval(a2, env.clone())?;
  188. match r {
  189. MalFunc {
  190. eval,
  191. ast,
  192. env,
  193. params,
  194. ..
  195. } => Ok(env_set(
  196. &env,
  197. a1.clone(),
  198. MalFunc {
  199. eval: eval,
  200. ast: ast.clone(),
  201. env: env.clone(),
  202. params: params.clone(),
  203. is_macro: true,
  204. meta: Rc::new(Nil),
  205. },
  206. )?),
  207. _ => error("set_macro on non-function"),
  208. }
  209. }
  210. Sym(ref a0sym) if a0sym == "macroexpand" => {
  211. match macroexpand(l[1].clone(), &env) {
  212. (_, Ok(new_ast)) => Ok(new_ast),
  213. (_, e) => return e,
  214. }
  215. }
  216. Sym(ref a0sym) if a0sym == "try*" => match eval(l[1].clone(), env.clone()) {
  217. Err(ref e) if l.len() >= 3 => {
  218. let exc = match e {
  219. ErrMalVal(mv) => mv.clone(),
  220. ErrString(s) => Str(s.to_string()),
  221. };
  222. match l[2].clone() {
  223. List(c, _) => {
  224. let catch_env = env_bind(
  225. Some(env.clone()),
  226. list!(vec![c[1].clone()]),
  227. vec![exc],
  228. )?;
  229. eval(c[2].clone(), catch_env)
  230. }
  231. _ => error("invalid catch block"),
  232. }
  233. }
  234. res => res,
  235. },
  236. Sym(ref a0sym) if a0sym == "do" => {
  237. match eval_ast(&list!(l[1..l.len() - 1].to_vec()), &env)? {
  238. List(_, _) => {
  239. ast = l.last().unwrap_or(&Nil).clone();
  240. continue 'tco;
  241. }
  242. _ => error("invalid do form"),
  243. }
  244. }
  245. Sym(ref a0sym) if a0sym == "if" => {
  246. let cond = eval(l[1].clone(), env.clone())?;
  247. match cond {
  248. Bool(false) | Nil if l.len() >= 4 => {
  249. ast = l[3].clone();
  250. continue 'tco;
  251. }
  252. Bool(false) | Nil => Ok(Nil),
  253. _ if l.len() >= 3 => {
  254. ast = l[2].clone();
  255. continue 'tco;
  256. }
  257. _ => Ok(Nil),
  258. }
  259. }
  260. Sym(ref a0sym) if a0sym == "zkcons!" => {
  261. let (a1, a2) = (l[1].clone(), l[2].clone());
  262. match env_get(&env, &a1).ok().unwrap() {
  263. Zk(mut zk) => match eval_ast(&a2, &env)? {
  264. List(ref el, _) => {
  265. let args = el.to_vec();
  266. for b in args.iter() {
  267. match b {
  268. Sym(_) => {}
  269. Add(b1, b2) => {
  270. println!("Add {:?} {:?}", b1, b2);
  271. zk.private.push(Scalar::from_string(&b2.pr_str(false).to_string()));
  272. env_set(&env, a1.clone(), types::MalVal::Zk(zk.clone()));
  273. }
  274. Sub(b1, b2) => {
  275. println!("Sub {:?} {:?}", b1, b2);
  276. zk.private.push(Scalar::from_string(&b2.pr_str(false).to_string()));
  277. env_set(&env, a1.clone(), types::MalVal::Zk(zk.clone()));
  278. }
  279. _ => {
  280. println!("not mapped");
  281. }
  282. }
  283. }
  284. }
  285. _ => {
  286. error("not mapped");
  287. }
  288. },
  289. _ => {
  290. error("zk circuit not found on env");
  291. }
  292. }
  293. Ok(Nil)
  294. }
  295. Sym(ref a0sym) if a0sym == "defzk!" => {
  296. let (a1, a2) = (l[1].clone(), l[2].clone());
  297. let zk_circuit = MalVal::Zk(ZKCircuit {
  298. name: a1.pr_str(true),
  299. constraints: Vec::new(),
  300. private: Vec::new(),
  301. public: Vec::new(),
  302. });
  303. env_set(&env, l[1].clone(), zk_circuit.clone());
  304. Ok(zk_circuit)
  305. }
  306. Sym(ref a0sym) if a0sym == "fn*" => {
  307. let (a1, a2) = (l[1].clone(), l[2].clone());
  308. Ok(MalFunc {
  309. eval: eval,
  310. ast: Rc::new(a2),
  311. env: env,
  312. params: Rc::new(a1),
  313. is_macro: false,
  314. meta: Rc::new(Nil),
  315. })
  316. }
  317. Sym(ref a0sym) if a0sym == "eval" => {
  318. ast = eval(l[1].clone(), env.clone())?;
  319. while let Some(ref e) = env.clone().outer {
  320. env = e.clone();
  321. }
  322. continue 'tco;
  323. }
  324. _ => match eval_ast(&ast, &env)? {
  325. List(ref el, _) => {
  326. let ref f = el[0].clone();
  327. let args = el[1..].to_vec();
  328. match f {
  329. Func(_, _) => f.apply(args),
  330. MalFunc {
  331. ast: mast,
  332. env: menv,
  333. params,
  334. ..
  335. } => {
  336. let a = &**mast;
  337. let p = &**params;
  338. env = env_bind(Some(menv.clone()), p.clone(), args)?;
  339. ast = a.clone();
  340. continue 'tco;
  341. }
  342. _ => {
  343. Ok(Nil)
  344. //error("call non-function")
  345. }
  346. }
  347. }
  348. _ => error("expected a list"),
  349. },
  350. }
  351. }
  352. _ => eval_ast(&ast, &env),
  353. };
  354. break;
  355. } // end 'tco loop
  356. ret
  357. }
  358. // print
  359. fn print(ast: &MalVal) -> String {
  360. ast.pr_str(true)
  361. }
  362. fn rep(str: &str, env: &Env) -> Result<String, MalErr> {
  363. let ast = read(str)?;
  364. let exp = eval(ast, env.clone())?;
  365. Ok(print(&exp))
  366. }
  367. fn main() -> Result<(), ()> {
  368. let matches = clap_app!(zklisp =>
  369. (version: "0.1.0")
  370. (author: "Roberto Santacroce Martins <miles.chet@gmail.com>")
  371. (about: "A Lisp Interpreter for Zero Knowledge Virtual Machine")
  372. (@subcommand load =>
  373. (about: "Load the file into the interpreter")
  374. (@arg FILE: +required "Lisp Contract filename")
  375. )
  376. )
  377. .get_matches();
  378. CombinedLogger::init(vec![TermLogger::new(
  379. LevelFilter::Debug,
  380. Config::default(),
  381. TerminalMode::Mixed,
  382. )
  383. .unwrap()])
  384. .unwrap();
  385. match matches.subcommand() {
  386. Some(("load", matches)) => {
  387. let file: String = matches.value_of("FILE").unwrap().parse().unwrap();
  388. repl_load(file);
  389. }
  390. _ => {
  391. eprintln!("error: Invalid subcommand invoked");
  392. std::process::exit(-1);
  393. }
  394. }
  395. Ok(())
  396. }
  397. fn repl_load(file: String) -> Result<(), ()> {
  398. let repl_env = env_new(None);
  399. for (k, v) in core::ns() {
  400. env_sets(&repl_env, k, v);
  401. }
  402. let _ = rep("(def! *host-language* \"rust\")", &repl_env);
  403. let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env);
  404. let _ = rep(
  405. "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))",
  406. &repl_env,
  407. );
  408. let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", &repl_env);
  409. match rep(&format!("(load-file \"{}\")", file), &repl_env) {
  410. Ok(_) => std::process::exit(0),
  411. Err(e) => {
  412. println!("Error: {}", format_error(e));
  413. std::process::exit(1);
  414. }
  415. }
  416. Ok(())
  417. }