rust: add step9_try. Refactor error handling.
[jackhill/mal.git] / rust / src / step4_if_fn_do.rs
CommitLineData
0a4d62f2
JM
1// support precompiled regexes in reader.rs
2#![feature(phase)]
3#[phase(plugin)]
4extern crate regex_macros;
5extern crate regex;
6
5939404b
JM
7use std::collections::HashMap;
8
3744d566
JM
9use 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 12use env::{Env,env_new,env_set,env_get};
0a4d62f2
JM
13mod readline;
14mod types;
15mod reader;
16mod printer;
17mod env;
18mod core;
19
20// read
21fn read(str: String) -> MalRet {
22 reader::read_str(str)
23}
24
25// eval
26fn 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
61fn 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// print
199fn print(exp: MalVal) -> String {
200 exp.pr_str(true)
201}
202
3744d566
JM
203fn 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
216fn 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}