e540ff13352de5a1c4f8efe095814e48cf793ccc
[jackhill/mal.git] / rust / src / types.rs
1 #![allow(dead_code)]
2
3 use std::rc::Rc;
4 use std::collections::HashMap;
5 use std::fmt;
6 use super::printer::{escape_str,pr_list};
7 use super::env::{Env,env_new,env_bind};
8
9 #[deriving(Clone)]
10 #[allow(non_camel_case_types)]
11 pub enum MalType {
12 Nil,
13 True,
14 False,
15 Int(int),
16 Strn(String),
17 Sym(String),
18 List(Vec<MalVal>),
19 Vector(Vec<MalVal>),
20 Hash_Map(HashMap<String, MalVal>),
21 Func(fn(Vec<MalVal>) -> MalRet),
22 //Func(fn(&[MalVal]) -> MalRet),
23 //Func(|Vec<MalVal>|:'a -> MalRet),
24 MalFunc(MalFuncData),
25 }
26
27 pub type MalVal = Rc<MalType>;
28
29 pub type MalRet = Result<MalVal,String>;
30
31 #[deriving(Clone)]
32 pub struct MalFuncData {
33 pub eval: fn(MalVal, Env) -> MalRet,
34 pub exp: MalVal,
35 pub env: Env,
36 pub params: MalVal,
37 pub is_macro: bool,
38 }
39
40 impl MalType {
41 pub fn pr_str(&self, print_readably: bool) -> String {
42 let _r = print_readably;
43 let mut res = String::new();
44 match *self {
45 Nil => res.push_str("nil"),
46 True => res.push_str("true"),
47 False => res.push_str("false"),
48 Int(v) => res.push_str(v.to_string().as_slice()),
49 Sym(ref v) => res.push_str((*v).as_slice()),
50 Strn(ref v) => {
51 if print_readably {
52 res.push_str(escape_str((*v).as_slice()).as_slice())
53 } else {
54 res.push_str(v.as_slice())
55 }
56 },
57 List(ref v) => {
58 res = pr_list(v, _r, "(", ")", " ")
59 },
60 Vector(ref v) => {
61 res = pr_list(v, _r, "[", "]", " ")
62 },
63 Hash_Map(ref v) => {
64 let mut first = true;
65 res.push_str("{");
66 for (key, value) in v.iter() {
67 if first { first = false; } else { res.push_str(" "); }
68 if print_readably {
69 res.push_str(escape_str(key.as_slice()).as_slice())
70 } else {
71 res.push_str(key.as_slice())
72 }
73 res.push_str(" ");
74 res.push_str(value.pr_str(_r).as_slice());
75 }
76 res.push_str("}")
77 },
78 // TODO: better native function representation
79 Func(_) => {
80 res.push_str(format!("#<function ...>").as_slice())
81 },
82 MalFunc(ref mf) => {
83 res.push_str(format!("(fn* {} {})", mf.params, mf.exp).as_slice())
84 },
85 /*
86 Atom(ref v) => v.fmt(f),
87 */
88 };
89 res
90 }
91
92 pub fn apply(&self, args:Vec<MalVal>) -> MalRet {
93 match *self {
94 Func(f) => f(args),
95 MalFunc(ref mf) => {
96 let mfc = mf.clone();
97 let alst = list(args);
98 let new_env = env_new(Some(mfc.env.clone()));
99 match env_bind(&new_env, mfc.params, alst) {
100 Ok(_) => (mfc.eval)(mfc.exp, new_env),
101 Err(e) => Err(e),
102 }
103 },
104 _ => Err("attempt to call non-function".to_string()),
105 }
106
107 }
108 }
109
110 impl PartialEq for MalType {
111 fn eq(&self, other: &MalType) -> bool {
112 match (self, other) {
113 (&Nil, &Nil) |
114 (&True, &True) |
115 (&False, &False) => true,
116 (&Int(ref a), &Int(ref b)) => a == b,
117 (&Strn(ref a), &Strn(ref b)) => a == b,
118 (&Sym(ref a), &Sym(ref b)) => a == b,
119 (&List(ref a), &List(ref b)) |
120 (&Vector(ref a), &Vector(ref b)) |
121 (&List(ref a), &Vector(ref b)) |
122 (&Vector(ref a), &List(ref b)) => a == b,
123 (&Hash_Map(ref a), &Hash_Map(ref b)) => a == b,
124 // TODO: fix this
125 (&Func(_), &Func(_)) => false,
126 (&MalFunc(_), &MalFunc(_)) => false,
127 _ => return false,
128 }
129 }
130 }
131
132 impl fmt::Show for MalType {
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 write!(f, "{}", self.pr_str(true))
135 }
136 }
137
138
139 // Convenience constructor functions
140 pub fn _nil() -> MalVal { Rc::new(Nil) }
141 pub fn _true() -> MalVal { Rc::new(True) }
142 pub fn _false() -> MalVal { Rc::new(False) }
143 pub fn _int(i: int) -> MalVal { Rc::new(Int(i)) }
144
145 pub fn symbol(strn: &str) -> MalVal { Rc::new(Sym(strn.to_string())) }
146 pub fn strn(strn: &str) -> MalVal { Rc::new(Strn(strn.to_string())) }
147 pub fn string(strn: String) -> MalVal { Rc::new(Strn(strn)) }
148
149 pub fn list(seq: Vec<MalVal>) -> MalVal { Rc::new(List(seq)) }
150 pub fn vector(seq: Vec<MalVal>) -> MalVal { Rc::new(Vector(seq)) }
151 pub fn hash_map(hm: HashMap<String,MalVal>) -> MalVal { Rc::new(Hash_Map(hm)) }
152
153 pub fn hash_mapv(seq: Vec<MalVal>) -> MalRet {
154 if seq.len() % 2 == 1 {
155 return Err("odd number of elements to hash-map".to_string());
156 }
157 let mut new_hm: HashMap<String,MalVal> = HashMap::new();
158 let mut it = seq.iter();
159 loop {
160 let k = match it.next() {
161 Some(mv) => match *mv.clone() {
162 Strn(ref s) => s.to_string(),
163 _ => return Err("key is not a string in hash-map call".to_string()),
164 },
165 None => break,
166 };
167 let v = it.next().unwrap();
168 new_hm.insert(k, v.clone());
169 }
170 Ok(Rc::new(Hash_Map(new_hm)))
171 }
172
173 pub fn func(f: fn(Vec<MalVal>) -> MalRet ) -> MalVal {
174 Rc::new(Func(f))
175 }
176 pub fn malfunc(eval: fn(MalVal, Env) -> MalRet,
177 exp: MalVal, env: Env, params: MalVal) -> MalVal {
178 Rc::new(MalFunc(MalFuncData{eval: eval, exp: exp, env: env,
179 params: params, is_macro: false}))
180 }
181 pub fn malfuncd(mfd: MalFuncData) -> MalVal {
182 Rc::new(MalFunc(mfd))
183 }