16 void throw(MalVal
*obj
) {
23 MalVal
*equal_Q(MalVal
*a
, MalVal
*b
) {
24 if (_equal_Q(a
, b
)) { return &mal_true
; }
25 else { return &mal_false
; }
31 MalVal
*nil_Q(MalVal
*seq
) { return seq
->type
& MAL_NIL
? &mal_true
: &mal_false
; }
32 MalVal
*true_Q(MalVal
*seq
) { return seq
->type
& MAL_TRUE
? &mal_true
: &mal_false
; }
33 MalVal
*false_Q(MalVal
*seq
) { return seq
->type
& MAL_FALSE
? &mal_true
: &mal_false
; }
34 MalVal
*string_Q(MalVal
*seq
) {
35 if ((seq
->type
& MAL_STRING
) && (seq
->val
.string
[0] != '\x7f')) {
45 MalVal
*symbol(MalVal
*args
) {
46 assert_type(args
, MAL_STRING
,
47 "symbol called with non-string value");
48 args
->type
= MAL_SYMBOL
; // change string to symbol
52 MalVal
*symbol_Q(MalVal
*seq
) {
53 return seq
->type
& MAL_SYMBOL
? &mal_true
: &mal_false
; }
58 MalVal
*keyword(MalVal
*args
) {
59 assert_type(args
, MAL_STRING
,
60 "keyword called with non-string value");
61 if (args
->val
.string
[0] == '\x7f') {
64 return malval_new_keyword(args
->val
.string
);
68 MalVal
*keyword_Q(MalVal
*seq
) {
69 return seq
->type
& MAL_STRING
&& seq
->val
.string
[0] == '\x7f'
77 // Return a string representation of a MalVal sequence (in a format that can
78 // be read by the reader). Returned string must be freed by caller.
79 MalVal
*pr_str(MalVal
*args
) {
80 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
81 "pr_str called with non-sequential args");
82 return malval_new_string(_pr_str_args(args
, " ", 1));
85 // Return a string representation of a MalVal sequence with every item
86 // concatenated together. Returned string must be freed by caller.
87 MalVal
*str(MalVal
*args
) {
88 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
89 "str called with non-sequential args");
90 return malval_new_string(_pr_str_args(args
, "", 0));
93 // Print a string representation of a MalVal sequence (in a format that can
94 // be read by the reader) followed by a newline. Returns nil.
95 MalVal
*prn(MalVal
*args
) {
96 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
97 "prn called with non-sequential args");
98 char *repr
= _pr_str_args(args
, " ", 1);
99 g_print("%s\n", repr
);
104 // Print a string representation of a MalVal sequence (for human consumption)
105 // followed by a newline. Returns nil.
106 MalVal
*println(MalVal
*args
) {
107 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
108 "println called with non-sequential args");
109 char *repr
= _pr_str_args(args
, " ", 0);
110 g_print("%s\n", repr
);
115 MalVal
*mal_readline(MalVal
*str
) {
116 assert_type(str
, MAL_STRING
, "readline of non-string");
117 char * line
= _readline(str
->val
.string
);
118 if (line
) { return malval_new_string(line
); }
119 else { return &mal_nil
; }
122 MalVal
*read_string(MalVal
*str
) {
123 assert_type(str
, MAL_STRING
, "read_string of non-string");
124 return read_str(str
->val
.string
);
127 char *slurp_raw(char *path
) {
130 int fd
= open(path
, O_RDONLY
),
133 abort("slurp failed to open '%s'", path
);
135 if (fstat(fd
, &fst
) < 0) {
136 abort("slurp failed to stat '%s'", path
);
138 data
= malloc(fst
.st_size
+1);
139 sz
= read(fd
, data
, fst
.st_size
);
140 if (sz
< fst
.st_size
) {
141 abort("slurp failed to read '%s'", path
);
146 MalVal
*slurp(MalVal
*path
) {
147 assert_type(path
, MAL_STRING
, "slurp of non-string");
148 char *data
= slurp_raw(path
->val
.string
);
149 if (!data
|| mal_error
) { return NULL
; }
150 return malval_new_string(data
);
158 WRAP_INTEGER_OP(plus
,+)
159 WRAP_INTEGER_OP(minus
,-)
160 WRAP_INTEGER_OP(multiply
,*)
161 WRAP_INTEGER_OP(divide
,/)
162 WRAP_INTEGER_CMP_OP(gt
,>)
163 WRAP_INTEGER_CMP_OP(gte
,>=)
164 WRAP_INTEGER_CMP_OP(lt
,<)
165 WRAP_INTEGER_CMP_OP(lte
,<=)
167 MalVal
*time_ms(MalVal
*_
) {
170 gettimeofday(&tv
, NULL
);
171 msecs
= tv
.tv_sec
* 1000 + tv
.tv_usec
/1000.0 + 0.5;
173 return malval_new_integer(msecs
);
179 MalVal
*list(MalVal
*args
) { return _list(args
); }
180 MalVal
*list_Q(MalVal
*seq
) { return _list_Q(seq
) ? &mal_true
: &mal_false
; }
185 MalVal
*vector(MalVal
*args
) { return _vector(args
); }
186 MalVal
*vector_Q(MalVal
*seq
) { return _vector_Q(seq
) ? &mal_true
: &mal_false
; }
189 // Hash map functions
191 MalVal
*hash_map_Q(MalVal
*seq
) { return _hash_map_Q(seq
) ? &mal_true
: &mal_false
; }
193 MalVal
*assoc(MalVal
*args
) {
194 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
195 "assoc called with non-sequential arguments");
196 assert(_count(args
) >= 2,
197 "assoc needs at least 2 arguments");
198 GHashTable
*htable
= g_hash_table_copy(_first(args
)->val
.hash_table
);
199 MalVal
*hm
= malval_new_hash_map(htable
);
200 return _assoc_BANG(hm
, _rest(args
));
203 MalVal
*dissoc(MalVal
* args
) {
204 GHashTable
*htable
= g_hash_table_copy(_first(args
)->val
.hash_table
);
205 MalVal
*hm
= malval_new_hash_map(htable
);
206 return _dissoc_BANG(hm
, _rest(args
));
209 MalVal
*keys(MalVal
*obj
) {
210 assert_type(obj
, MAL_HASH_MAP
,
211 "keys called on non-hash-map");
215 MalVal
*seq
= malval_new_list(MAL_LIST
,
216 g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*),
218 g_hash_table_iter_init (&iter
, obj
->val
.hash_table
);
219 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
220 MalVal
*kname
= malval_new_string((char *)key
);
221 g_array_append_val(seq
->val
.array
, kname
);
226 MalVal
*vals(MalVal
*obj
) {
227 assert_type(obj
, MAL_HASH_MAP
,
228 "vals called on non-hash-map");
232 MalVal
*seq
= malval_new_list(MAL_LIST
,
233 g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*),
235 g_hash_table_iter_init (&iter
, obj
->val
.hash_table
);
236 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
237 g_array_append_val(seq
->val
.array
, value
);
243 // hash map and vector functions
244 MalVal
*get(MalVal
*obj
, MalVal
*key
) {
248 return _nth(obj
, key
->val
.intnum
);
250 if (g_hash_table_lookup_extended(obj
->val
.hash_table
,
252 NULL
, (gpointer
*)&val
)) {
260 abort("get called on unsupported type %d", obj
->type
);
264 MalVal
*contains_Q(MalVal
*obj
, MalVal
*key
) {
267 if (key
->val
.intnum
< obj
->val
.array
->len
) {
273 if (g_hash_table_contains(obj
->val
.hash_table
, key
->val
.string
)) {
279 abort("contains? called on unsupported type %d", obj
->type
);
284 // Sequence functions
286 MalVal
*sequential_Q(MalVal
*seq
) {
287 return _sequential_Q(seq
) ? &mal_true
: &mal_false
;
290 MalVal
*cons(MalVal
*x
, MalVal
*seq
) {
291 assert_type(seq
, MAL_LIST
|MAL_VECTOR
,
292 "second argument to cons is non-sequential");
293 int i
, len
= _count(seq
);
294 GArray
*new_arr
= g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*),
296 g_array_append_val(new_arr
, x
);
297 for (i
=0; i
<len
; i
++) {
298 g_array_append_val(new_arr
, g_array_index(seq
->val
.array
, MalVal
*, i
));
300 return malval_new_list(MAL_LIST
, new_arr
);
303 MalVal
*concat(MalVal
*args
) {
304 MalVal
*arg
, *e
, *lst
;
305 int i
, j
, arg_cnt
= _count(args
);
306 lst
= malval_new_list(MAL_LIST
,
307 g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*), arg_cnt
));
308 for (i
=0; i
<arg_cnt
; i
++) {
309 arg
= g_array_index(args
->val
.array
, MalVal
*, i
);
310 assert_type(arg
, MAL_LIST
|MAL_VECTOR
,
311 "concat called with non-sequential");
312 for (j
=0; j
<_count(arg
); j
++) {
313 e
= g_array_index(arg
->val
.array
, MalVal
*, j
);
314 g_array_append_val(lst
->val
.array
, e
);
320 MalVal
*nth(MalVal
*seq
, MalVal
*idx
) {
321 return _nth(seq
, idx
->val
.intnum
);
324 MalVal
*empty_Q(MalVal
*seq
) {
325 assert_type(seq
, MAL_LIST
|MAL_VECTOR
,
326 "empty? called with non-sequential");
327 return (seq
->val
.array
->len
== 0) ? &mal_true
: &mal_false
;
330 MalVal
*count(MalVal
*seq
) {
331 return malval_new_integer(_count(seq
));
334 MalVal
*apply(MalVal
*args
) {
335 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
336 "apply called with non-sequential");
337 MalVal
*f
= _nth(args
, 0);
338 MalVal
*last_arg
= _last(args
);
339 assert_type(last_arg
, MAL_LIST
|MAL_VECTOR
,
340 "last argument to apply is non-sequential");
341 int i
, len
= _count(args
) - 2 + _count(last_arg
);
342 GArray
*new_arr
= g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*),
345 for (i
=1; i
<_count(args
)-1; i
++) {
346 g_array_append_val(new_arr
, g_array_index(args
->val
.array
, MalVal
*, i
));
348 // Add arguments from last_arg
349 for (i
=0; i
<_count(last_arg
); i
++) {
350 g_array_append_val(new_arr
, g_array_index(last_arg
->val
.array
, MalVal
*, i
));
352 return _apply(f
, malval_new_list(MAL_LIST
, new_arr
));
355 MalVal
*map(MalVal
*mvf
, MalVal
*lst
) {
357 assert_type(mvf
, MAL_FUNCTION_C
|MAL_FUNCTION_MAL
,
358 "map called with non-function");
359 assert_type(lst
, MAL_LIST
|MAL_VECTOR
,
360 "map called with non-sequential");
361 int i
, len
= _count(lst
);
362 el
= malval_new_list(MAL_LIST
,
363 g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*), len
));
364 for (i
=0; i
<len
; i
++) {
365 // TODO: this is replicating some of apply functionality
366 if (mvf
->type
& MAL_FUNCTION_MAL
) {
367 Env
*fn_env
= new_env(mvf
->val
.func
.env
,
369 _slice(lst
, i
, i
+1));
370 res
= mvf
->val
.func
.evaluator(mvf
->val
.func
.body
, fn_env
);
372 res
= mvf
->val
.f1(g_array_index(lst
->val
.array
, MalVal
*, i
));
374 if (!res
|| mal_error
) return NULL
;
375 g_array_append_val(el
->val
.array
, res
);
380 MalVal
*sconj(MalVal
*args
) {
381 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
382 "conj called with non-sequential");
383 MalVal
*src_lst
= _nth(args
, 0);
384 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
385 "first argument to conj is non-sequential");
386 int i
, len
= _count(src_lst
) + _count(args
) - 1;
387 GArray
*new_arr
= g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*),
390 for (i
=0; i
<_count(src_lst
); i
++) {
391 g_array_append_val(new_arr
, g_array_index(src_lst
->val
.array
, MalVal
*, i
));
394 for (i
=1; i
<_count(args
); i
++) {
395 if (src_lst
->type
& MAL_LIST
) {
396 g_array_prepend_val(new_arr
, g_array_index(args
->val
.array
, MalVal
*, i
));
398 g_array_append_val(new_arr
, g_array_index(args
->val
.array
, MalVal
*, i
));
401 return malval_new_list(src_lst
->type
, new_arr
);
404 MalVal
*seq(MalVal
*obj
) {
405 assert_type(obj
, MAL_LIST
|MAL_VECTOR
|MAL_STRING
|MAL_NIL
,
406 "seq: called with non-sequential");
412 if (cnt
== 0) { return &mal_nil
; }
416 if (cnt
== 0) { return &mal_nil
; }
417 lst
= malval_new_list(MAL_LIST
,
418 g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*), cnt
));
419 lst
->val
.array
= obj
->val
.array
;
422 cnt
= strlen(obj
->val
.string
);
423 if (cnt
== 0) { return &mal_nil
; }
424 lst
= malval_new_list(MAL_LIST
,
425 g_array_sized_new(TRUE
, TRUE
, sizeof(MalVal
*), cnt
));
426 for (i
=0; i
<cnt
; i
++) {
427 mstr
= malval_new_string(g_strdup_printf("%c", obj
->val
.string
[i
]));
428 g_array_append_val(lst
->val
.array
, mstr
);
437 // Metadata functions
439 MalVal
*with_meta(MalVal
*obj
, MalVal
*meta
) {
440 MalVal
*new_obj
= malval_new(obj
->type
, meta
);
441 new_obj
->val
= obj
->val
;
445 MalVal
*meta(MalVal
*obj
) {
446 assert_type(obj
, MAL_LIST
|MAL_VECTOR
|MAL_HASH_MAP
|
447 MAL_FUNCTION_C
|MAL_FUNCTION_MAL
|MAL_ATOM
,
448 "attempt to get metadata from non-collection type");
449 if (obj
->metadata
== NULL
) {
452 return obj
->metadata
;
459 MalVal
*atom(MalVal
*val
) {
460 return malval_new_atom(val
);
463 MalVal
*atom_Q(MalVal
*exp
) { return _atom_Q(exp
) ? &mal_true
: &mal_false
; }
465 MalVal
*deref(MalVal
*atm
) {
466 assert_type(atm
, MAL_ATOM
,
467 "deref called on non-atom");
468 return atm
->val
.atom_val
;
471 MalVal
*reset_BANG(MalVal
*atm
, MalVal
*val
) {
472 assert_type(atm
, MAL_ATOM
,
473 "reset! called with non-atom");
474 atm
->val
.atom_val
= val
;
478 MalVal
*swap_BANG(MalVal
*args
) {
479 assert_type(args
, MAL_LIST
|MAL_VECTOR
,
480 "swap! called with invalid arguments");
481 assert(_count(args
) >= 2,
482 "swap! called with %d args, needs at least 2", _count(args
));
483 MalVal
*atm
= _nth(args
, 0),
485 *sargs
= _slice(args
, 2, _count(args
)),
486 *fargs
= cons(atm
->val
.atom_val
, sargs
),
487 *new_val
= _apply(f
, fargs
);
488 if (mal_error
) { return NULL
; }
489 atm
->val
.atom_val
= new_val
;
495 core_ns_entry core_ns
[58] = {
496 {"=", (void*(*)(void*))equal_Q
, 2},
497 {"throw", (void*(*)(void*))throw, 1},
498 {"nil?", (void*(*)(void*))nil_Q
, 1},
499 {"true?", (void*(*)(void*))true_Q
, 1},
500 {"false?", (void*(*)(void*))false_Q
, 1},
501 {"string?", (void*(*)(void*))string_Q
, 1},
502 {"symbol", (void*(*)(void*))symbol
, 1},
503 {"symbol?", (void*(*)(void*))symbol_Q
, 1},
504 {"keyword", (void*(*)(void*))keyword
, 1},
505 {"keyword?", (void*(*)(void*))keyword_Q
, 1},
507 {"pr-str", (void*(*)(void*))pr_str
, -1},
508 {"str", (void*(*)(void*))str
, -1},
509 {"prn", (void*(*)(void*))prn
, -1},
510 {"println", (void*(*)(void*))println
, -1},
511 {"readline", (void*(*)(void*))mal_readline
, 1},
512 {"read-string", (void*(*)(void*))read_string
, 1},
513 {"slurp", (void*(*)(void*))slurp
, 1},
514 {"<", (void*(*)(void*))int_lt
, 2},
515 {"<=", (void*(*)(void*))int_lte
, 2},
516 {">", (void*(*)(void*))int_gt
, 2},
517 {">=", (void*(*)(void*))int_gte
, 2},
518 {"+", (void*(*)(void*))int_plus
, 2},
519 {"-", (void*(*)(void*))int_minus
, 2},
520 {"*", (void*(*)(void*))int_multiply
, 2},
521 {"/", (void*(*)(void*))int_divide
, 2},
522 {"time-ms", (void*(*)(void*))time_ms
, 0},
524 {"list", (void*(*)(void*))list
, -1},
525 {"list?", (void*(*)(void*))list_Q
, 1},
526 {"vector", (void*(*)(void*))vector
, -1},
527 {"vector?", (void*(*)(void*))vector_Q
, 1},
528 {"hash-map", (void*(*)(void*))_hash_map
, -1},
529 {"map?", (void*(*)(void*))hash_map_Q
, 1},
530 {"assoc", (void*(*)(void*))assoc
, -1},
531 {"dissoc", (void*(*)(void*))dissoc
, -1},
532 {"get", (void*(*)(void*))get
, 2},
533 {"contains?", (void*(*)(void*))contains_Q
, 2},
534 {"keys", (void*(*)(void*))keys
, 1},
535 {"vals", (void*(*)(void*))vals
, 1},
537 {"sequential?", (void*(*)(void*))sequential_Q
, 1},
538 {"cons", (void*(*)(void*))cons
, 2},
539 {"concat", (void*(*)(void*))concat
, -1},
540 {"nth", (void*(*)(void*))nth
, 2},
541 {"first", (void*(*)(void*))_first
, 1},
542 {"rest", (void*(*)(void*))_rest
, 1},
543 {"last", (void*(*)(void*))_last
, 1},
544 {"empty?", (void*(*)(void*))empty_Q
, 1},
545 {"count", (void*(*)(void*))count
, 1},
546 {"apply", (void*(*)(void*))apply
, -1},
547 {"map", (void*(*)(void*))map
, 2},
549 {"conj", (void*(*)(void*))sconj
, -1},
550 {"seq", (void*(*)(void*))seq
, 1},
552 {"with-meta", (void*(*)(void*))with_meta
, 2},
553 {"meta", (void*(*)(void*))meta
, 1},
554 {"atom", (void*(*)(void*))atom
, 1},
555 {"atom?", (void*(*)(void*))atom_Q
, 1},
556 {"deref", (void*(*)(void*))deref
, 1},
557 {"reset!", (void*(*)(void*))reset_BANG
, 2},
558 {"swap!", (void*(*)(void*))swap_BANG
, -1},