1use std::io::{stdout, Write};
2use std::sync::atomic::{AtomicIsize, Ordering};
3
4use gc::Gc;
5use oftlisp::Value;
6use oftlisp::gensym::gensym as make_gensym;
7use oftlisp::interpreter::Primitives;
8use oftlisp::reader::symbolish::str_is_symbol;
9use oftlisp::util::{from_assoc, to_assoc};
10
11use errors::RuntimeError;
12use types::Context;
13
14pub static PRIMITIVES: Primitives<Context> = Primitives {
16 apply,
17 atomic_word_cas,
18 atomic_word_load,
19 atomic_word_new,
20 atomic_word_store,
21 byte_of_fixnum,
22 bytes_of_string,
23 car,
24 cdr,
25 compare,
26 concat_strings,
27 cons,
28 debug,
29 eq,
30 exit_with,
31 fixnum_of_byte,
32 gensym,
33 is_byte,
34 is_cons,
35 is_fixnum,
36 is_nil,
37 is_object,
38 is_string,
39 is_symbol,
40 is_vector,
41 list_of_vector,
42 make_vector,
43 object_data_len,
44 object_get_data,
45 object_get_func,
46 object_has_func,
47 object_seal,
48 object_unseal,
49 op_add,
50 op_cmp,
51 op_div,
52 op_equ,
53 op_mod,
54 op_mul,
55 op_sub,
56 panic,
57 show_primitive,
58 string_of_symbol,
59 symbol_of_string,
60 unwind_protect,
61 vector_of_list,
62 write_bytes,
63};
64
65type Args = Vec<Gc<Value<Context>>>;
66type Return = Result<Gc<Value<Context>>, RuntimeError>;
67
68macro_rules! args {
69 ([$args:expr, $name:expr]($($req:ident)*) => $block:block) => {
70 args!([$args, $name]($($req)* ... rest) => {
71 if rest.len() == 0 {
72 $block
73 } else {
74 unimplemented!("bad argn in call to {}", $name)
75 }
76 })
77 };
78 ([$args:expr, $name:expr]($($req:ident)* ... $rest:ident) => $block:block) => {{
79 let mut args = $args;
80 args.reverse();
81 $(let $req = if args.is_empty() {
82 unimplemented!("bad argn in call to {}", $name)
83 } else {
84 args.pop().unwrap()
85 };)*
86 args.reverse();
87 let $rest = args;
88 #[allow(unused_macros)]
89 macro_rules! __oftlisp_func_name {
90 () => { $name };
91 }
92 $block
93 }};
94}
95macro_rules! type_check {
96 (atomic <- $expr:expr) => { type_check!(Value::AtomicWord(ref n, _), n, $expr) };
97 (byte <- $expr:expr) => { type_check!(Value::Byte(n, _), n, $expr) };
98 (bytes <- $expr:expr) => { type_check!(Value::Bytes(ref b, _), b, $expr) };
99 (cons <- $expr:expr) => { type_check!(Value::Cons(ref h, ref t, _), (h, t), $expr) };
100 (fixnum <- $expr:expr) => { type_check!(Value::Fixnum(n, _), n, $expr) };
101 (obj <- $expr:expr) => { type_check!(Value::Object(ref f, ref d, _), (f, d), $expr) };
102 (string <- $expr:expr) => { type_check!(Value::String(ref s, _), s, $expr) };
103 (symbol <- $expr:expr) => { type_check!(Value::Symbol(s, _), s, $expr) };
104 (vector <- $expr:expr) => { type_check!(Value::Vector(ref v, _), v, $expr) };
105 ($pat:pat, $out:expr, $expr:expr) => {{
106 let value = &*$expr;
107 if let $pat = *value {
108 $out
109 } else {
110 unimplemented!("type_check in {} failed: could not match {} with {}", __oftlisp_func_name!(), value, stringify!($pat))
111 }
112 }};
113
114 (list <- $expr:expr) => {{
115 let value = $expr;
116 if let Some(l) = $crate::oftlisp::util::as_list(value.clone()) {
117 l
118 } else {
119 unimplemented!("type_check in {} failed: {} is not a list", __oftlisp_func_name!(), value)
120 }
121 }};
122}
123macro_rules! define_ops {
124 ($(($sym_name:ident, $fn_name:expr) = $fn:expr;)*) => {
125 $(fn $sym_name(args: Args) -> Return {
126 args!([args, $fn_name](l r) => {
127 match (&*l, &*r) {
128 (&Value::Byte(a, _), &Value::Byte(b, _)) => {
129 Ok(Gc::new(Value::Byte(($fn)(a, b), Default::default())))
130 },
131 (&Value::Fixnum(a, _), &Value::Fixnum(b, _)) => {
132 Ok(Gc::new(Value::Fixnum(($fn)(a, b), Default::default())))
133 },
134 (_, _) => unimplemented!("invalid arg types to {}", __oftlisp_func_name!()),
135 }
136 })
137 })*
138 };
139}
140
141define_ops! {
142 (op_add, "+/2") = |a, b| a + b;
143 (op_sub, "-/2") = |a, b| a - b;
144 (op_mul, "*/2") = |a, b| a * b;
145 (op_div, "//2") = |a, b| a / b;
146 (op_mod, "mod/2") = |a, b| a % b;
147}
148
149fn apply(args: Args) -> Return {
150 args!([args, "apply"](func args) => {
151 let args = type_check!(list <- args);
152 match *func {
153 Value::BuiltinFunction(..) | Value::Func(..) => {
154 Context::apply(func, args)
155 },
156 _ => unimplemented!("cannot apply to non-func"),
157 }
158 })
159}
160
161fn atomic_word_cas(args: Args) -> Return {
162 args!([args, "atomic-word.cas"](a before after) => {
163 let a = type_check!(atomic <- a);
164 let before = type_check!(fixnum <- before);
165 let after = type_check!(fixnum <- after);
166 let n = a.compare_and_swap(before, after, Ordering::SeqCst);
167 Ok(Gc::new(Value::Fixnum(n, Default::default())))
168 })
169}
170
171fn atomic_word_load(args: Args) -> Return {
172 args!([args, "atomic-word.load"](a) => {
173 let a = type_check!(atomic <- a);
174 let n = a.load(Ordering::SeqCst);
175 Ok(Gc::new(Value::Fixnum(n, Default::default())))
176 })
177}
178
179fn atomic_word_new(args: Args) -> Return {
180 args!([args, "atomic-word.new"](n) => {
181 let n = type_check!(fixnum <- n);
182 Ok(Gc::new(Value::AtomicWord(AtomicIsize::new(n), Default::default())))
183 })
184}
185
186fn atomic_word_store(args: Args) -> Return {
187 args!([args, "atomic-word.store"](a n) => {
188 let a = type_check!(atomic <- a);
189 let n = type_check!(fixnum <- n);
190 a.store(n, Ordering::SeqCst);
191 Ok(Gc::new(Value::Nil(Default::default())))
192 })
193}
194
195fn byte_of_fixnum(args: Args) -> Return {
196 args!([args, "byte<-fixnum"](val) => {
197 let n = type_check!(fixnum <- val);
198 Ok(Gc::new(if n >= 0 && n < 256 {
199 Value::Byte(n as u8, Default::default())
200 } else {
201 Value::Nil(Default::default())
202 }))
203 })
204}
205
206fn bytes_of_string(args: Args) -> Return {
207 args!([args, "bytes<-string"](val) => {
208 let s = type_check!(string <- val);
209 let bs = Gc::new(Clone::clone(&**s).into_bytes());
210 Ok(Gc::new(Value::Bytes(bs, Default::default())))
211 })
212}
213
214fn car(args: Args) -> Return {
215 args!([args, "car"](l) => {
216 let (h, _) = type_check!(cons <- l);
217 Ok(h.clone())
218 })
219}
220
221fn compare(args: Args) -> Return {
222 args!([args, "compare"](x y) => {
223 Ok(Value::ordering(x.partial_cmp(&y)))
224 })
225}
226
227fn cdr(args: Args) -> Return {
228 args!([args, "cdr"](l) => {
229 let (_, t) = type_check!(cons <- l);
230 Ok(t.clone())
231 })
232}
233
234fn concat_strings(args: Args) -> Return {
235 args!([args, "concat-strings"](... strs) => {
236 let mut buf = String::new();
237 for s in strs {
238 let s = type_check!(string <- s);
239 buf += s;
240 }
241 Ok(Gc::new(Value::String(Gc::new(buf), Default::default())))
242 })
243}
244
245fn cons(args: Args) -> Return {
246 args!([args, "cons"](h t) => {
247 Ok(Gc::new(Value::Cons(h, t, Default::default())))
248 })
249}
250
251fn debug(args: Args) -> Return {
252 args!([args, "debug"](x) => {
253 warn!("{}", x);
254 Ok(x)
255 })
256}
257
258fn eq(args: Args) -> Return {
259 args!([args, "eq"](l r) => {
260 Ok(Value::bool(l == r))
261 })
262}
263
264fn exit_with(args: Args) -> Return {
265 args!([args, "exit-with"](code) => {
266 let code = type_check!(byte <- code);
267 Err(RuntimeError::Exit(code))
268 })
269}
270
271fn fixnum_of_byte(args: Args) -> Return {
272 args!([args, "fixnum<-byte"](val) => {
273 let n = type_check!(byte <- val);
274 Ok(Gc::new(Value::Fixnum(n as isize, Default::default())))
275 })
276}
277
278fn gensym(args: Args) -> Return {
279 args!([args, "gensym"]() => {
280 Ok(Gc::new(Value::Symbol(make_gensym(), Default::default())))
281 })
282}
283
284fn is_byte(args: Args) -> Return {
285 args!([args, "byte?"](val) => {
286 Ok(Value::bool(if let Value::Byte(..) = *val {
287 true
288 } else {
289 false
290 }))
291 })
292}
293
294fn is_cons(args: Args) -> Return {
295 args!([args, "cons?"](val) => {
296 Ok(Value::bool(if let Value::Cons(..) = *val {
297 true
298 } else {
299 false
300 }))
301 })
302}
303
304fn is_fixnum(args: Args) -> Return {
305 args!([args, "fixnum?"](val) => {
306 Ok(Value::bool(if let Value::Fixnum(..) = *val {
307 true
308 } else {
309 false
310 }))
311 })
312}
313
314fn is_nil(args: Args) -> Return {
315 args!([args, "nil?"](val) => {
316 Ok(Value::bool(if let Value::Nil(_) = *val {
317 true
318 } else {
319 false
320 }))
321 })
322}
323
324fn is_object(args: Args) -> Return {
325 args!([args, "object?"](val) => {
326 Ok(Value::bool(if let Value::Object(..) = *val {
327 true
328 } else {
329 false
330 }))
331 })
332}
333
334fn is_symbol(args: Args) -> Return {
335 args!([args, "symbol?"](val) => {
336 Ok(Value::bool(if let Value::Symbol(..) = *val {
337 true
338 } else {
339 false
340 }))
341 })
342}
343
344fn is_string(args: Args) -> Return {
345 args!([args, "string?"](val) => {
346 Ok(Value::bool(if let Value::String(..) = *val {
347 true
348 } else {
349 false
350 }))
351 })
352}
353
354fn is_vector(args: Args) -> Return {
355 args!([args, "vector?"](val) => {
356 Ok(Value::bool(if let Value::Vector(..) = *val {
357 true
358 } else {
359 false
360 }))
361 })
362}
363
364fn list_of_vector(args: Args) -> Return {
365 args!([args, "list<-vector"](v) => {
366 let v = type_check!(vector <- v);
367 Ok(Value::list(v.clone(), Default::default()))
368 })
369}
370
371fn make_vector(args: Args) -> Return {
372 args!([args, "make-vector"](l) => {
373 let l = type_check!(fixnum <- l) as usize;
374 let v = vec![Gc::new(Value::Nil(Default::default())); l];
375 Ok(Gc::new(Value::Vector(v, Default::default())))
376 })
377}
378
379fn object_data_len(args: Args) -> Return {
380 args!([args, "object-data-len"](val) => {
381 let (_, data) = type_check!(obj <- val);
382 Ok(Gc::new(Value::Fixnum(data.len() as isize, Default::default())))
383 })
384}
385
386fn object_get_data(args: Args) -> Return {
387 args!([args, "object-get-data"](val i) => {
388 let (_, data) = type_check!(obj <- val);
389 let i = type_check!(fixnum <- i);
390 if i < 0 || i as usize >= data.len() {
391 return Err(RuntimeError::ObjectDataOutOfBounds(i, val.clone()));
392 } else {
393 Ok(data[i as usize].clone())
394 }
395 })
396}
397
398fn object_get_func(args: Args) -> Return {
399 args!([args, "object-get-func"](val name) => {
400 let (vt, _) = type_check!(obj <- val);
401 let name = type_check!(symbol <- name);
402 if let Some(func) = vt.get(&name) {
403 Ok(func.clone())
404 } else {
405 Err(RuntimeError::ObjectNoSuchFunc(name, val.clone()))
406 }
407 })
408}
409
410fn object_has_func(args: Args) -> Return {
411 args!([args, "object-has-func?"](val name) => {
412 let (vt, _) = type_check!(obj <- val);
413 let name = type_check!(symbol <- name);
414 Ok(Value::bool(vt.contains_key(&name)))
415 })
416}
417
418fn object_seal(args: Args) -> Return {
419 args!([args, "object-seal"](vtbl data) => {
420 let vtbl = if let Some(vtbl) = from_assoc(vtbl.clone()) {
421 vtbl
422 } else {
423 return Err(RuntimeError::InvalidVTable(vtbl));
424 };
425 let data = type_check!(vector <- data);
426 Ok(Gc::new(Value::Object(vtbl, data.clone(), Default::default())))
427 })
428}
429
430fn object_unseal(args: Args) -> Return {
431 args!([args, "object-unseal"](val) => {
432 let (vtbl, data) = type_check!(obj <- val);
433 let vtbl = to_assoc(vtbl);
434 let data = Value::vector(data.clone());
435 Ok(Gc::new(Value::Cons(vtbl, data, Default::default())))
436 })
437}
438
439fn op_cmp(args: Args) -> Return {
440 args!([args, "<>"](l r) => {
441 match (&*l, &*r) {
442 (&Value::Fixnum(l, _), &Value::Fixnum(r, _)) => Ok(Value::ordering(Some(l.cmp(&r)))),
443 (_, _) => unimplemented!("invalid arg types to <>"),
444 }
445 })
446}
447
448fn op_equ(args: Args) -> Return {
449 args!([args, "="](l r) => {
450 Ok(Value::bool(l == r))
451 })
452}
453
454fn panic(args: Args) -> Return {
455 Err(RuntimeError::Panic(args))
456}
457
458fn show_primitive(args: Args) -> Return {
459 args!([args, "show-primitive"](val) => {
460 let s = Gc::new(format!("{}", val));
461 Ok(Gc::new(Value::String(s, Default::default())))
462 })
463}
464
465fn string_of_symbol(args: Args) -> Return {
466 args!([args, "string<-symbol"](val) => {
467 let s = type_check!(symbol <- val);
468 Ok(Gc::new(Value::String(Gc::new(s.to_string()), Default::default())))
469 })
470}
471
472fn symbol_of_string(args: Args) -> Return {
473 args!([args, "symbol<-string"](val) => {
474 let s = type_check!(string <- val);
475 Ok(Gc::new(if str_is_symbol(s) {
476 Value::Symbol(s.as_str().into(), Default::default())
477 } else {
478 Value::Nil(Default::default())
479 }))
480 })
481}
482
483fn unwind_protect(args: Args) -> Return {
484 args!([args, "unwind-protect"](try finally) => {
485 let val = Context::apply(try, vec![]);
486 Context::apply(finally, vec![])?;
487 val
488 })
489}
490
491fn vector_of_list(args: Args) -> Return {
492 args!([args, "vector<-list"](l) => {
493 let l = type_check!(list <- l);
494 Ok(Value::vector(l))
495 })
496}
497
498fn write_bytes(args: Args) -> Return {
499 args!([args, "write-bytes"](val) => {
500 let bs = type_check!(bytes <- val);
501 stdout().write_all(bs)?;
502 Ok(Gc::new(Value::Nil(Default::default())))
503 })
504}