Commit | Line | Data |
---|---|---|
0a4d62f2 JM |
1 | // support precompiled regexes in reader.rs |
2 | #![feature(phase)] | |
3 | #[phase(plugin)] | |
4 | extern crate regex_macros; | |
5 | extern crate regex; | |
6 | ||
5939404b JM |
7 | use std::collections::HashMap; |
8 | ||
3744d566 JM |
9 | use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str, |
10 | Nil,False,Sym,List,Vector,Hash_Map, | |
5939404b | 11 | _nil,list,vector,hash_map,malfunc}; |
a77e2b31 | 12 | use env::{Env,env_new,env_set,env_get}; |
0a4d62f2 JM |
13 | mod readline; |
14 | mod types; | |
15 | mod reader; | |
16 | mod printer; | |
17 | mod env; | |
18 | mod core; | |
19 | ||
20 | // read | |
21 | fn read(str: String) -> MalRet { | |
22 | reader::read_str(str) | |
23 | } | |
24 | ||
25 | // eval | |
26 | fn eval_ast(ast: MalVal, env: Env) -> MalRet { | |
27 | let ast2 = ast.clone(); | |
28 | match *ast2 { | |
29 | //match *ast { | |
30 | Sym(ref sym) => { | |
31 | env_get(env.clone(), sym.clone()) | |
32 | }, | |
5939404b | 33 | List(ref a) | Vector(ref a) => { |
0a4d62f2 JM |
34 | let mut ast_vec : Vec<MalVal> = vec![]; |
35 | for mv in a.iter() { | |
36 | let mv2 = mv.clone(); | |
37 | match eval(mv2, env.clone()) { | |
38 | Ok(mv) => { ast_vec.push(mv); }, | |
39 | Err(e) => { return Err(e); }, | |
40 | } | |
41 | } | |
5939404b JM |
42 | Ok(match *ast { List(_) => list(ast_vec), |
43 | _ => vector(ast_vec) }) | |
44 | }, | |
45 | Hash_Map(ref hm) => { | |
46 | let mut new_hm: HashMap<String,MalVal> = HashMap::new(); | |
47 | for (key, value) in hm.iter() { | |
48 | match eval(value.clone(), env.clone()) { | |
49 | Ok(mv) => { new_hm.insert(key.to_string(), mv); }, | |
50 | Err(e) => return Err(e), | |
51 | } | |
52 | } | |
53 | Ok(hash_map(new_hm)) | |
0a4d62f2 JM |
54 | }, |
55 | _ => { | |
56 | Ok(ast) | |
57 | } | |
58 | } | |
59 | } | |
60 | ||
61 | fn eval(ast: MalVal, env: Env) -> MalRet { | |
62 | //println!("eval: {}, {}", ast, env.borrow()); | |
63 | //println!("eval: {}", ast); | |
64 | let ast2 = ast.clone(); | |
65 | match *ast2 { | |
66 | List(_) => (), // continue | |
67 | _ => return eval_ast(ast2, env), | |
68 | } | |
69 | ||
70 | // apply list | |
71 | match *ast2 { | |
3744d566 JM |
72 | List(_) => (), // continue |
73 | _ => return Ok(ast2), | |
74 | } | |
75 | ||
76 | let (args, a0sym) = match *ast2 { | |
0a4d62f2 JM |
77 | List(ref args) => { |
78 | if args.len() == 0 { | |
79 | return Ok(ast); | |
80 | } | |
81 | let ref a0 = *args[0]; | |
82 | match *a0 { | |
3744d566 JM |
83 | Sym(ref a0sym) => (args, a0sym.as_slice()), |
84 | _ => (args, "__<fn*>__"), | |
85 | } | |
86 | }, | |
87 | _ => return err_str("Expected list"), | |
88 | }; | |
89 | ||
90 | match a0sym { | |
91 | "def!" => { | |
92 | let a1 = (*args)[1].clone(); | |
93 | let a2 = (*args)[2].clone(); | |
94 | let res = eval(a2, env.clone()); | |
95 | match res { | |
96 | Ok(r) => { | |
97 | match *a1 { | |
98 | Sym(ref s) => { | |
99 | env_set(&env.clone(), s.clone(), r.clone()); | |
100 | return Ok(r); | |
0a4d62f2 | 101 | }, |
3744d566 JM |
102 | _ => { |
103 | return err_str("def! of non-symbol") | |
104 | } | |
0a4d62f2 | 105 | } |
3744d566 JM |
106 | }, |
107 | Err(e) => return Err(e), | |
0a4d62f2 | 108 | } |
3744d566 JM |
109 | }, |
110 | "let*" => { | |
111 | let let_env = env_new(Some(env.clone())); | |
112 | let a1 = (*args)[1].clone(); | |
113 | let a2 = (*args)[2].clone(); | |
114 | match *a1 { | |
115 | List(ref binds) | Vector(ref binds) => { | |
116 | let mut it = binds.iter(); | |
117 | while it.len() >= 2 { | |
118 | let b = it.next().unwrap(); | |
119 | let exp = it.next().unwrap(); | |
120 | match **b { | |
121 | Sym(ref bstr) => { | |
122 | match eval(exp.clone(), let_env.clone()) { | |
123 | Ok(r) => { | |
124 | env_set(&let_env, bstr.clone(), r); | |
125 | }, | |
126 | Err(e) => { | |
127 | return Err(e); | |
128 | }, | |
129 | } | |
130 | }, | |
131 | _ => { | |
132 | return err_str("let* with non-symbol binding"); | |
133 | }, | |
134 | } | |
135 | } | |
136 | }, | |
137 | _ => return err_str("let* with non-list bindings"), | |
138 | } | |
139 | return eval(a2, let_env.clone()); | |
140 | }, | |
141 | "do" => { | |
142 | let el = list(args.slice(1,args.len()).to_vec()); | |
143 | return match eval_ast(el, env.clone()) { | |
144 | Err(e) => return Err(e), | |
0a4d62f2 JM |
145 | Ok(el) => { |
146 | match *el { | |
3744d566 JM |
147 | List(ref lst) => { |
148 | let ref last = lst[lst.len()-1]; | |
149 | return Ok(last.clone()); | |
0a4d62f2 | 150 | } |
3744d566 | 151 | _ => return err_str("invalid do call"), |
0a4d62f2 | 152 | } |
3744d566 JM |
153 | }, |
154 | }; | |
155 | }, | |
156 | "if" => { | |
157 | let a1 = (*args)[1].clone(); | |
158 | let cond = eval(a1, env.clone()); | |
159 | match cond { | |
160 | Err(e) => return Err(e), | |
161 | Ok(c) => match *c { | |
162 | False | Nil => { | |
163 | if args.len() >= 4 { | |
164 | let a3 = (*args)[3].clone(); | |
165 | return eval(a3, env.clone()); | |
166 | } else { | |
167 | return Ok(_nil()); | |
168 | } | |
169 | }, | |
170 | _ => { | |
171 | let a2 = (*args)[2].clone(); | |
172 | return eval(a2, env.clone()); | |
173 | }, | |
0a4d62f2 JM |
174 | } |
175 | } | |
3744d566 JM |
176 | }, |
177 | "fn*" => { | |
178 | let a1 = (*args)[1].clone(); | |
179 | let a2 = (*args)[2].clone(); | |
180 | return Ok(malfunc(eval, a2, env.clone(), a1)); | |
181 | }, | |
182 | _ => { // function call | |
183 | return match eval_ast(ast, env.clone()) { | |
184 | Err(e) => Err(e), | |
185 | Ok(el) => { | |
186 | let args = match *el { | |
187 | List(ref args) => args, | |
188 | _ => return err_str("Invalid apply"), | |
189 | }; | |
190 | let ref f = args.clone()[0]; | |
191 | f.apply(args.slice(1,args.len()).to_vec()) | |
192 | } | |
193 | }; | |
194 | }, | |
0a4d62f2 JM |
195 | } |
196 | } | |
197 | ||
198 | ||
199 | fn print(exp: MalVal) -> String { | |
200 | exp.pr_str(true) | |
201 | } | |
202 | ||
3744d566 JM |
203 | fn rep(str: &str, env: Env) -> Result<String,MalError> { |
204 | match read(str.to_string()) { | |
0a4d62f2 JM |
205 | Err(e) => Err(e), |
206 | Ok(ast) => { | |
207 | //println!("read: {}", ast); | |
208 | match eval(ast, env) { | |
209 | Err(e) => Err(e), | |
210 | Ok(exp) => Ok(print(exp)), | |
211 | } | |
212 | } | |
213 | } | |
214 | } | |
215 | ||
216 | fn main() { | |
3744d566 | 217 | // core.rs: defined using rust |
0a4d62f2 JM |
218 | let repl_env = env_new(None); |
219 | for (k, v) in core::ns().into_iter() { env_set(&repl_env, k, v); } | |
220 | ||
3744d566 JM |
221 | // core.mal: defined using the language itself |
222 | let _ = rep("(def! not (fn* (a) (if a false true)))", repl_env.clone()); | |
0a4d62f2 JM |
223 | |
224 | loop { | |
225 | let line = readline::mal_readline("user> "); | |
226 | match line { None => break, _ => () } | |
3744d566 | 227 | match rep(line.unwrap().as_slice(), repl_env.clone()) { |
0a4d62f2 | 228 | Ok(str) => println!("{}", str), |
3744d566 JM |
229 | Err(ErrMalVal(_)) => (), // Blank line |
230 | Err(ErrString(s)) => println!("Error: {}", s), | |
0a4d62f2 JM |
231 | } |
232 | } | |
233 | } |