Rust: apply improvements in stepA to other steps.
[jackhill/mal.git] / rust / src / bin / step2_eval.rs
CommitLineData
bbeb1b87 1extern crate mal;
0ab374bc 2
0ab374bc 3use std::collections::HashMap;
8f5b0f10 4
fb439f3c
JM
5use mal::types::{MalVal, MalRet, MalError, err_str, err_string};
6use mal::types::{list, vector, hash_map, _int, func};
bbeb1b87 7use mal::types::MalError::{ErrString, ErrMalVal};
fb439f3c 8use mal::types::MalType::{Sym, List, Vector, Hash_Map, Int};
bbeb1b87 9use mal::{readline, reader};
0ab374bc
JM
10
11// read
12fn read(str: String) -> MalRet {
13 reader::read_str(str)
14}
15
16// eval
17fn eval_ast(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet {
18 match *ast {
19 Sym(ref sym) => {
bbeb1b87
AC
20 match env.get(sym) {
21 Some(mv) => Ok(mv.clone()),
fb439f3c
JM
22 //None => Ok(_nil()),
23 None => err_string(format!("'{}' not found", sym)),
0ab374bc
JM
24 }
25 },
bd306723 26 List(ref a,_) | Vector(ref a,_) => {
0ab374bc
JM
27 let mut ast_vec : Vec<MalVal> = vec![];
28 for mv in a.iter() {
fb439f3c
JM
29 let mv2 = mv.clone();
30 ast_vec.push(try!(eval(mv2, env)));
0ab374bc 31 }
bd306723 32 Ok(match *ast { List(_,_) => list(ast_vec),
77b2da6c 33 _ => vector(ast_vec) })
fb439f3c 34 }
bd306723 35 Hash_Map(ref hm,_) => {
5939404b
JM
36 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
37 for (key, value) in hm.iter() {
fb439f3c
JM
38 new_hm.insert(key.to_string(),
39 try!(eval(value.clone(), env)));
5939404b
JM
40 }
41 Ok(hash_map(new_hm))
0ab374bc 42 }
fb439f3c 43 _ => Ok(ast.clone()),
0ab374bc
JM
44 }
45}
46
47fn eval(ast: MalVal, env: &HashMap<String,MalVal>) -> MalRet {
fb439f3c
JM
48 //println!("eval: {}", ast);
49 match *ast {
bd306723 50 List(_,_) => (), // continue
fb439f3c 51 _ => return eval_ast(ast, env),
0ab374bc
JM
52 }
53
54 // apply list
fb439f3c
JM
55 match *try!(eval_ast(ast, env)) {
56 List(ref args,_) => {
57 let ref f = args.clone()[0];
58 f.apply(args[1..].to_vec())
59 },
60 _ => return err_str("Expected list"),
0ab374bc
JM
61 }
62}
63
64// print
65fn print(exp: MalVal) -> String {
66 exp.pr_str(true)
67}
68
3744d566 69fn rep(str: &str, env: &HashMap<String,MalVal>) -> Result<String,MalError> {
fb439f3c
JM
70 let ast = try!(read(str.to_string()));
71 //println!("read: {}", ast);
72 let exp = try!(eval(ast, env));
73 Ok(print(exp))
0ab374bc
JM
74}
75
bbeb1b87
AC
76fn int_op<F>(f: F, a:Vec<MalVal>) -> MalRet
77 where F: FnOnce(isize, isize) -> isize
78{
0ab374bc
JM
79 match *a[0] {
80 Int(a0) => match *a[1] {
4ee7c0f2 81 Int(a1) => Ok(_int(f(a0,a1))),
3744d566 82 _ => err_str("second arg must be an int"),
0ab374bc 83 },
3744d566 84 _ => err_str("first arg must be an int"),
0ab374bc
JM
85 }
86}
87fn add(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i+j }, a) }
88fn sub(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i-j }, a) }
89fn mul(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i*j }, a) }
90fn div(a:Vec<MalVal>) -> MalRet { int_op(|i,j| { i/j }, a) }
91
92fn main() {
93 let mut repl_env : HashMap<String,MalVal> = HashMap::new();
4ee7c0f2
JM
94 repl_env.insert("+".to_string(), func(add));
95 repl_env.insert("-".to_string(), func(sub));
96 repl_env.insert("*".to_string(), func(mul));
97 repl_env.insert("/".to_string(), func(div));
0ab374bc
JM
98
99 loop {
100 let line = readline::mal_readline("user> ");
101 match line { None => break, _ => () }
bbeb1b87 102 match rep(&line.unwrap(), &repl_env) {
0ab374bc 103 Ok(str) => println!("{}", str),
3744d566
JM
104 Err(ErrMalVal(_)) => (), // Blank line
105 Err(ErrString(s)) => println!("Error: {}", s),
0ab374bc
JM
106 }
107 }
108}