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