Rust: apply improvements in stepA to other steps.
[jackhill/mal.git] / rust / src / bin / step4_if_fn_do.rs
1 extern crate mal;
2
3 use std::collections::HashMap;
4
5 use mal::types::{MalVal, MalRet, MalError, err_str};
6 use mal::types::{symbol, _nil, list, vector, hash_map, malfunc};
7 use mal::types::MalError::{ErrString, ErrMalVal};
8 use mal::types::MalType::{Nil, False, Sym, List, Vector, Hash_Map};
9 use mal::{readline, reader, core};
10 use mal::env::{env_set, env_get, env_new, Env};
11
12
13 // read
14 fn read(str: String) -> MalRet {
15 reader::read_str(str)
16 }
17
18 // eval
19 fn eval_ast(ast: MalVal, env: Env) -> MalRet {
20 match *ast {
21 Sym(_) => env_get(&env, &ast),
22 List(ref a,_) | Vector(ref a,_) => {
23 let mut ast_vec : Vec<MalVal> = vec![];
24 for mv in a.iter() {
25 let mv2 = mv.clone();
26 ast_vec.push(try!(eval(mv2, env.clone())));
27 }
28 Ok(match *ast { List(_,_) => list(ast_vec),
29 _ => vector(ast_vec) })
30 }
31 Hash_Map(ref hm,_) => {
32 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
33 for (key, value) in hm.iter() {
34 new_hm.insert(key.to_string(),
35 try!(eval(value.clone(), env.clone())));
36 }
37 Ok(hash_map(new_hm))
38 }
39 _ => Ok(ast.clone()),
40 }
41 }
42
43 fn eval(ast: MalVal, env: Env) -> MalRet {
44 //println!("eval: {}, {}", ast, env.borrow());
45 //println!("eval: {}", ast);
46 match *ast {
47 List(_,_) => (), // continue
48 _ => return eval_ast(ast, env),
49 }
50
51 // apply list
52 match *ast {
53 List(_,_) => (), // continue
54 _ => return Ok(ast),
55 }
56
57 let tmp = ast;
58 let (args, a0sym) = match *tmp {
59 List(ref args,_) => {
60 if args.len() == 0 {
61 return Ok(tmp.clone());
62 }
63 let ref a0 = *args[0];
64 match *a0 {
65 Sym(ref a0sym) => (args, &a0sym[..]),
66 _ => (args, "__<fn*>__"),
67 }
68 },
69 _ => return err_str("Expected list"),
70 };
71
72 match a0sym {
73 "def!" => {
74 let a1 = (*args)[1].clone();
75 let a2 = (*args)[2].clone();
76 let r = try!(eval(a2, env.clone()));
77 match *a1 {
78 Sym(_) => {
79 env_set(&env.clone(), a1, r.clone());
80 return Ok(r);
81 },
82 _ => return err_str("def! of non-symbol"),
83 }
84 },
85 "let*" => {
86 let let_env = env_new(Some(env.clone()));
87 let a1 = (*args)[1].clone();
88 let a2 = (*args)[2].clone();
89 match *a1 {
90 List(ref binds,_) | Vector(ref binds,_) => {
91 let mut it = binds.iter();
92 while it.len() >= 2 {
93 let b = it.next().unwrap();
94 let exp = it.next().unwrap();
95 match **b {
96 Sym(_) => {
97 let r = try!(eval(exp.clone(), let_env.clone()));
98 env_set(&let_env, b.clone(), r);
99 },
100 _ => return err_str("let* with non-symbol binding"),
101 }
102 }
103 },
104 _ => return err_str("let* with non-list bindings"),
105 }
106 return eval(a2, let_env.clone());
107 },
108 "do" => {
109 let el = list(args[1..].to_vec());
110 match *try!(eval_ast(el, env.clone())) {
111 List(ref lst,_) => {
112 let ref last = lst[lst.len()-1];
113 return Ok(last.clone());
114 }
115 _ => return err_str("invalid do call"),
116 }
117 },
118 "if" => {
119 let a1 = (*args)[1].clone();
120 let c = try!(eval(a1, env.clone()));
121 match *c {
122 False | Nil => {
123 if args.len() >= 4 {
124 let a3 = (*args)[3].clone();
125 return eval(a3, env.clone());
126 } else {
127 return Ok(_nil());
128 }
129 },
130 _ => {
131 let a2 = (*args)[2].clone();
132 return eval(a2, env.clone());
133 },
134 }
135 },
136 "fn*" => {
137 let a1 = args[1].clone();
138 let a2 = args[2].clone();
139 return Ok(malfunc(eval, a2, env, a1, _nil()));
140 },
141 _ => { // function call
142 let el = try!(eval_ast(tmp.clone(), env.clone()));
143 let args = match *el {
144 List(ref args,_) => args,
145 _ => return err_str("Invalid apply"),
146 };
147 let ref f = args.clone()[0];
148 f.apply(args[1..].to_vec())
149 },
150 }
151 }
152
153 // print
154 fn print(exp: MalVal) -> String {
155 exp.pr_str(true)
156 }
157
158 fn rep(str: &str, env: Env) -> Result<String,MalError> {
159 let ast = try!(read(str.to_string()));
160 //println!("read: {}", ast);
161 let exp = try!(eval(ast, env));
162 Ok(print(exp))
163 }
164
165 fn main() {
166 // core.rs: defined using rust
167 let repl_env = env_new(None);
168 for (k, v) in core::ns().into_iter() {
169 env_set(&repl_env, symbol(&k), v);
170 }
171
172 // core.mal: defined using the language itself
173 let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone());
174
175 // repl loop
176 loop {
177 let line = readline::mal_readline("user> ");
178 match line { None => break, _ => () }
179 match rep(&line.unwrap(), repl_env.clone()) {
180 Ok(str) => println!("{}", str),
181 Err(ErrMalVal(_)) => (), // Blank line
182 Err(ErrString(s)) => println!("Error: {}", s),
183 }
184 }
185 }