rust: fix Dockerfile to include WORKDIR=/mal
[jackhill/mal.git] / rust / core.rs
1 use std::rc::Rc;
2 use std::fs::File;
3 use std::io::Read;
4 use std::sync::Mutex;
5 use std::time::{SystemTime, UNIX_EPOCH};
6
7 extern crate rustyline;
8 use rustyline::error::ReadlineError;
9 use rustyline::Editor;
10
11 use types::{MalVal,MalArgs,MalRet,error,func,hash_map,_assoc,_dissoc,atom};
12 use types::MalVal::{Nil,Bool,Int,Str,Sym,List,Vector,Hash,Func,MalFunc,Atom};
13 use types::MalErr::{ErrMalVal};
14 use reader::read_str;
15 use printer::pr_seq;
16
17 macro_rules! fn_t_int_int {
18 ($ret:ident, $fn:expr) => {{
19 |a:MalArgs| {
20 match (a[0].clone(), a[1].clone()) {
21 (Int(a0), Int(a1)) => Ok($ret($fn(a0, a1))),
22 _ => error("expecting (int,int) args"),
23 }
24 }
25 }};
26 }
27
28 macro_rules! fn_is_type {
29 ($($ps:pat),*) => {{
30 |a:MalArgs| { Ok(Bool(match a[0] { $($ps => true,)* _ => false})) }
31 }};
32 ($p:pat if $e:expr) => {{
33 |a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, _ => false})) }
34 }};
35 ($p:pat if $e:expr,$($ps:pat),*) => {{
36 |a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, $($ps => true,)* _ => false})) }
37 }};
38 }
39
40 macro_rules! fn_str {
41 ($fn:expr) => {{
42 |a:MalArgs| {
43 match a[0].clone() {
44 Str(a0) => $fn(a0),
45 _ => error("expecting (str) arg"),
46 }
47 }
48 }};
49 }
50
51 fn symbol(a: MalArgs) -> MalRet {
52 match a[0] {
53 Str(ref s) => Ok(Sym(s.to_string())),
54 _ => error("illegal symbol call")
55 }
56 }
57
58 fn readline(a: MalArgs) -> MalRet {
59 lazy_static! {
60 static ref RL: Mutex<Editor<()>> = Mutex::new(Editor::<()>::new());
61 }
62 //let mut rl = Editor::<()>::new();
63
64 match a[0] {
65 Str(ref p) => {
66 //match rl.readline(p) {
67 match RL.lock().unwrap().readline(p) {
68 Ok(line) => Ok(Str(line)),
69 Err(ReadlineError::Eof) => Ok(Nil),
70 Err(e) => error(&format!("{:?}", e))
71 }
72 },
73 _ => error("readline: prompt is not Str"),
74 }
75 }
76
77 fn slurp(f: String) -> MalRet {
78 let mut s = String::new();
79 match File::open(f).and_then(|mut f| f.read_to_string(&mut s)) {
80 Ok(_) => Ok(Str(s)),
81 Err(e) => error(&e.to_string()),
82 }
83 }
84
85 fn time_ms(_a: MalArgs) -> MalRet {
86 let ms_e = match SystemTime::now().duration_since(UNIX_EPOCH) {
87 Ok(d) => d,
88 Err(e) => return error(&format!("{:?}", e)),
89 };
90 Ok(Int(ms_e.as_secs() as i64 * 1000 +
91 ms_e.subsec_nanos() as i64 / 1_000_000))
92 }
93
94 fn get(a: MalArgs) -> MalRet {
95 match (a[0].clone(), a[1].clone()) {
96 (Nil, _) => Ok(Nil),
97 (Hash(ref hm,_), Str(ref s)) => {
98 match hm.get(s) {
99 Some(mv) => Ok(mv.clone()),
100 None => Ok(Nil),
101 }
102 },
103 _ => error("illegal get args")
104 }
105 }
106
107 fn assoc(a: MalArgs) -> MalRet {
108 match a[0] {
109 Hash(ref hm,_) => _assoc((**hm).clone(), a[1..].to_vec()),
110 _ => error("assoc on non-Hash Map")
111 }
112 }
113
114 fn dissoc(a: MalArgs) -> MalRet {
115 match a[0] {
116 Hash(ref hm,_) => _dissoc((**hm).clone(), a[1..].to_vec()),
117 _ => error("dissoc on non-Hash Map")
118 }
119 }
120
121 fn contains_q(a: MalArgs) -> MalRet {
122 match (a[0].clone(), a[1].clone()) {
123 (Hash(ref hm,_), Str(ref s)) => {
124 Ok(Bool(hm.contains_key(s)))
125 },
126 _ => error("illegal get args")
127 }
128 }
129
130 fn keys(a: MalArgs) -> MalRet {
131 match a[0] {
132 Hash(ref hm,_) => {
133 Ok(list!(hm.keys().map(|k|{Str(k.to_string())}).collect()))
134 },
135 _ => error("keys requires Hash Map")
136 }
137 }
138
139 fn vals(a: MalArgs) -> MalRet {
140 match a[0] {
141 Hash(ref hm,_) => {
142 Ok(list!(hm.values().map(|v|{v.clone()}).collect()))
143 },
144 _ => error("keys requires Hash Map")
145 }
146 }
147
148 fn cons(a: MalArgs) -> MalRet {
149 match a[1].clone() {
150 List(v,_) | Vector(v,_) => {
151 let mut new_v = vec![a[0].clone()];
152 new_v.extend_from_slice(&v);
153 Ok(list!(new_v.to_vec()))
154 },
155 _ => error("cons expects seq as second arg"),
156 }
157 }
158
159 fn concat(a: MalArgs) -> MalRet {
160 let mut new_v = vec![];
161 for seq in a.iter() {
162 match seq {
163 List(v,_) | Vector(v,_) => new_v.extend_from_slice(v),
164 _ => return error("non-seq passed to concat"),
165 }
166 }
167 Ok(list!(new_v.to_vec()))
168 }
169
170 fn nth(a: MalArgs) -> MalRet {
171 match (a[0].clone(), a[1].clone()) {
172 (List(seq,_), Int(idx)) | (Vector(seq,_), Int(idx)) => {
173 if seq.len() <= idx as usize {
174 return error("nth: index out of range");
175 }
176 Ok(seq[idx as usize].clone())
177 }
178 _ => error("invalid args to nth"),
179 }
180 }
181
182 fn first(a: MalArgs) -> MalRet {
183 match a[0].clone() {
184 List(ref seq,_) | Vector(ref seq,_) if seq.len() == 0 => Ok(Nil),
185 List(ref seq,_) | Vector(ref seq,_) => Ok(seq[0].clone()),
186 Nil => Ok(Nil),
187 _ => error("invalid args to first"),
188 }
189 }
190
191 fn rest(a: MalArgs) -> MalRet {
192 match a[0].clone() {
193 List(ref seq,_) | Vector(ref seq,_) => {
194 if seq.len() > 1 {
195 Ok(list!(seq[1..].to_vec()))
196 } else {
197 Ok(list![])
198 }
199 },
200 Nil => Ok(list![]),
201 _ => error("invalid args to first"),
202 }
203 }
204
205 fn apply(a: MalArgs) -> MalRet {
206 match a[a.len()-1] {
207 List(ref v,_) | Vector(ref v,_) => {
208 let f = &a[0];
209 let mut fargs = a[1..a.len()-1].to_vec();
210 fargs.extend_from_slice(&v);
211 f.apply(fargs)
212 },
213 _ => error("apply called with non-seq"),
214 }
215 }
216
217 fn map(a: MalArgs) -> MalRet {
218 match a[1] {
219 List(ref v,_) | Vector(ref v,_) => {
220 let mut res = vec![];
221 for mv in v.iter() {
222 res.push(a[0].apply(vec![mv.clone()])?)
223 }
224 Ok(list!(res))
225 },
226 _ => error("map called with non-seq"),
227 }
228 }
229
230 fn conj(a: MalArgs) -> MalRet {
231 match a[0] {
232 List(ref v,_) => {
233 let sl = a[1..].iter().rev().map(|a|{a.clone()}).collect::<Vec<MalVal>>();
234 Ok(list!([&sl[..],v].concat()))
235 },
236 Vector(ref v,_) => Ok(vector!([v,&a[1..]].concat())),
237 _ => error("conj: called with non-seq"),
238 }
239 }
240
241 fn seq(a: MalArgs) -> MalRet {
242 match a[0] {
243 List(ref v,_) | Vector(ref v,_) if v.len() == 0 => Ok(Nil),
244 List(ref v,_) | Vector(ref v,_) => Ok(list!(v.to_vec())),
245 Str(ref s) if s.len() == 0 => Ok(Nil),
246 Str(ref s) if !a[0].keyword_q() => {
247 Ok(list!(s.chars().map(|c|{Str(c.to_string())}).collect()))
248 },
249 Nil => Ok(Nil),
250 _ => error("seq: called with non-seq"),
251 }
252 }
253
254 pub fn ns() -> Vec<(&'static str, MalVal)> {
255 vec![
256 ("=", func(|a|{Ok(Bool(a[0] == a[1]))})),
257 ("throw", func(|a|{Err(ErrMalVal(a[0].clone()))})),
258
259 ("nil?", func(fn_is_type!(Nil))),
260 ("true?", func(fn_is_type!(Bool(true)))),
261 ("false?", func(fn_is_type!(Bool(false)))),
262 ("symbol", func(symbol)),
263 ("symbol?", func(fn_is_type!(Sym(_)))),
264 ("string?", func(fn_is_type!(Str(ref s) if !s.starts_with("\u{29e}")))),
265 ("keyword", func(|a|{a[0].keyword()})),
266 ("keyword?", func(fn_is_type!(Str(ref s) if s.starts_with("\u{29e}")))),
267 ("number?", func(fn_is_type!(Int(_)))),
268 ("fn?", func(fn_is_type!(MalFunc{is_macro,..} if !is_macro,Func(_,_)))),
269 ("macro?", func(fn_is_type!(MalFunc{is_macro,..} if is_macro))),
270
271 ("pr-str", func(|a|Ok(Str(pr_seq(&a, true, "", "", " "))))),
272 ("str", func(|a|Ok(Str(pr_seq(&a, false, "", "", ""))))),
273 ("prn", func(|a|{println!("{}", pr_seq(&a, true, "", "", " ")); Ok(Nil)})),
274 ("println", func(|a|{println!("{}", pr_seq(&a, false, "", "", " ")); Ok(Nil)})),
275 ("read-string", func(fn_str!(|s|{read_str(s)}))),
276 ("readline", func(readline)),
277 ("slurp", func(fn_str!(|f|{slurp(f)}))),
278
279 ("<", func(fn_t_int_int!(Bool,|i,j|{i<j}))),
280 ("<=", func(fn_t_int_int!(Bool,|i,j|{i<=j}))),
281 (">", func(fn_t_int_int!(Bool,|i,j|{i>j}))),
282 (">=", func(fn_t_int_int!(Bool,|i,j|{i>=j}))),
283 ("+", func(fn_t_int_int!(Int,|i,j|{i+j}))),
284 ("-", func(fn_t_int_int!(Int,|i,j|{i-j}))),
285 ("*", func(fn_t_int_int!(Int,|i,j|{i*j}))),
286 ("/", func(fn_t_int_int!(Int,|i,j|{i/j}))),
287 ("time-ms", func(time_ms)),
288
289 ("sequential?", func(fn_is_type!(List(_,_),Vector(_,_)))),
290 ("list", func(|a|{Ok(list!(a))})),
291 ("list?", func(fn_is_type!(List(_,_)))),
292 ("vector", func(|a|{Ok(vector!(a))})),
293 ("vector?", func(fn_is_type!(Vector(_,_)))),
294 ("hash-map", func(|a|{hash_map(a)})),
295 ("map?", func(fn_is_type!(Hash(_,_)))),
296 ("assoc", func(assoc)),
297 ("dissoc", func(dissoc)),
298 ("get", func(get)),
299 ("contains?", func(contains_q)),
300 ("keys", func(keys)),
301 ("vals", func(vals)),
302
303 ("cons", func(cons)),
304 ("concat", func(concat)),
305 ("empty?", func(|a|{a[0].empty_q()})),
306 ("nth", func(nth)),
307 ("first", func(first)),
308 ("rest", func(rest)),
309 ("count", func(|a|{a[0].count()})),
310 ("apply", func(apply)),
311 ("map", func(map)),
312
313 ("conj", func(conj)),
314 ("seq", func(seq)),
315
316 ("meta", func(|a|{a[0].get_meta()})),
317 ("with-meta", func(|a|{a[0].clone().with_meta(&a[1])})),
318 ("atom", func(|a|{Ok(atom(&a[0]))})),
319 ("atom?", func(fn_is_type!(Atom(_)))),
320 ("deref", func(|a|{a[0].deref()})),
321 ("reset!", func(|a|{a[0].reset_bang(&a[1])})),
322 ("swap!", func(|a|{a[0].swap_bang(&a[1..].to_vec())})),
323 ]
324 }
325
326 // vim: ts=2:sw=2:expandtab
327