rust: add step9_try. Refactor error handling.
[jackhill/mal.git] / rust / src / step2_eval.rs
CommitLineData
0ab374bc
JM
1// support precompiled regexes in reader.rs
2#![feature(phase)]
3#[phase(plugin)]
4extern crate regex_macros;
5extern crate regex;
6
0ab374bc 7use std::collections::HashMap;
8f5b0f10 8
3744d566
JM
9use types::{MalVal,MalRet,MalError,ErrString,ErrMalVal,err_str,
10 Int,Sym,List,Vector,Hash_Map,
5939404b 11 _nil,_int,list,vector,hash_map,func};
0ab374bc
JM
12mod readline;
13mod types;
14mod reader;
15mod printer;
3744d566 16mod env; // because types uses env
0ab374bc
JM
17
18// read
19fn read(str: String) -> MalRet {
20 reader::read_str(str)
21}
22
23// eval
24fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet {
25 match *ast {
26 Sym(ref sym) => {
8f5b0f10 27 match env.find_copy(sym) {
0ab374bc 28 Some(mv) => Ok(mv),
4ee7c0f2 29 None => Ok(_nil()),
0ab374bc
JM
30 }
31 },
5939404b 32 List(ref a) | Vector(ref a) => {
0ab374bc
JM
33 let mut ast_vec : Vec<MalVal> = vec![];
34 for mv in a.iter() {
5939404b
JM
35 match eval(mv.clone(), env) {
36 Ok(mv) => ast_vec.push(mv),
37 Err(e) => return Err(e),
0ab374bc
JM
38 }
39 }
5939404b
JM
40 Ok(match *ast { List(_) => list(ast_vec),
41 _ => vector(ast_vec) })
42 },
43 Hash_Map(ref hm) => {
44 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
45 for (key, value) in hm.iter() {
46 match eval(value.clone(), env) {
47 Ok(mv) => { new_hm.insert(key.to_string(), mv); },
48 Err(e) => return Err(e),
49 }
50 }
51 Ok(hash_map(new_hm))
0ab374bc
JM
52 },
53 _ => {
54 Ok(ast.clone())
55 }
56 }
57}
58
59fn eval(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet {
60 let ast2 = ast.clone();
61 match *ast2 {
62 List(_) => (), // continue
63 _ => return eval_ast(ast2, env),
64 }
65
66 // apply list
67 match eval_ast(ast, env) {
68 Err(e) => Err(e),
69 Ok(el) => {
70 match *el {
71 List(ref args) => {
a77e2b31
JM
72 let ref f = args.clone()[0];
73 f.apply(args.slice(1,args.len()).to_vec())
0ab374bc 74 }
3744d566 75 _ => err_str("Invalid apply"),
0ab374bc
JM
76 }
77 }
78 }
79}
80
81// print
82fn print(exp: MalVal) -> String {
83 exp.pr_str(true)
84}
85
3744d566
JM
86fn rep(str: &str, env: &HashMap<String,MalVal>) -> Result<String,MalError> {
87 match read(str.to_string()) {
0ab374bc
JM
88 Err(e) => Err(e),
89 Ok(ast) => {
90 //println!("read: {}", ast);
91 match eval(ast, env) {
92 Err(e) => Err(e),
93 Ok(exp) => Ok(print(exp)),
94 }
95 }
96 }
97}
98
99fn int_op(f: |i:int,j:int|-> int, a:Vec<MalVal>) -> MalRet {
100 match *a[0] {
101 Int(a0) => match *a[1] {
4ee7c0f2 102 Int(a1) => Ok(_int(f(a0,a1))),
3744d566 103 _ => err_str("second arg must be an int"),
0ab374bc 104 },
3744d566 105 _ => err_str("first arg must be an int"),
0ab374bc
JM
106 }
107}
108fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) }
109fn sub(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) }
110fn mul(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) }
111fn div(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) }
112
113fn main() {
114 let mut repl_env : HashMap<String,MalVal> = HashMap::new();
4ee7c0f2
JM
115 repl_env.insert("+".to_string(), func(add));
116 repl_env.insert("-".to_string(), func(sub));
117 repl_env.insert("*".to_string(), func(mul));
118 repl_env.insert("/".to_string(), func(div));
0ab374bc
JM
119
120 loop {
121 let line = readline::mal_readline("user> ");
122 match line { None => break, _ => () }
3744d566 123 match rep(line.unwrap().as_slice(), &repl_env) {
0ab374bc 124 Ok(str) => println!("{}", str),
3744d566
JM
125 Err(ErrMalVal(_)) => (), // Blank line
126 Err(ErrString(s)) => println!("Error: {}", s),
0ab374bc
JM
127 }
128 }
129}