ada.2: typo
[jackhill/mal.git] / impls / tcl / core.tcl
CommitLineData
54d9903c
DM
1proc mal_equal {a} {
2 bool_new [equal_q [lindex $a 0] [lindex $a 1]]
3}
4
5set ::mal_exception_obj 0
6proc mal_throw {a} {
7 set ::mal_exception_obj [lindex $a 0]
8 error "__MalException__"
9}
10
11proc mal_nil_q {a} {
12 bool_new [nil_q [lindex $a 0]]
13}
14
15proc mal_true_q {a} {
16 bool_new [true_q [lindex $a 0]]
17}
18
19proc mal_false_q {a} {
20 bool_new [false_q [lindex $a 0]]
21}
22
23proc mal_symbol {a} {
24 symbol_new [obj_val [lindex $a 0]]
25}
26
27proc mal_symbol_q {a} {
28 bool_new [symbol_q [lindex $a 0]]
29}
30
0e198b2c
DM
31proc mal_string_q {a} {
32 bool_new [string_q [lindex $a 0]]
33}
34
54d9903c
DM
35proc mal_keyword {a} {
36 keyword_new [obj_val [lindex $a 0]]
37}
38
39proc mal_keyword_q {a} {
40 bool_new [keyword_q [lindex $a 0]]
41}
42
c91c8de9
DM
43proc mal_number_q {a} {
44 bool_new [integer_q [lindex $a 0]]
45}
46
47proc mal_fn_q {a} {
48 set f [lindex $a 0]
49 switch [obj_type $f] {
50 function { return [bool_new [expr {![macro_q $f]}]] }
51 nativefunction { return $::mal_true }
52 default { return $::mal_false }
53 }
54}
55
56proc mal_macro_q {a} {
57 bool_new [macro_q [lindex $a 0]]
58}
59
54d9903c
DM
60proc render_array {arr readable delim} {
61 set res {}
62 foreach e $arr {
63 lappend res [pr_str $e $readable]
64 }
65 join $res $delim
66}
67
68proc mal_pr_str {a} {
69 string_new [render_array $a 1 " "]
70}
71
72proc mal_str {a} {
73 string_new [render_array $a 0 ""]
74}
75
76proc mal_prn {a} {
77 puts [render_array $a 1 " "]
78 return $::mal_nil
79}
80
81proc mal_println {a} {
82 puts [render_array $a 0 " "]
83 return $::mal_nil
84}
85
86proc mal_read_string {a} {
87 read_str [obj_val [lindex $a 0]]
88}
89
90proc mal_readline {a} {
91 set prompt [obj_val [lindex $a 0]]
92 set res [_readline $prompt]
93 if {[lindex $res 0] == "EOF"} {
94 return $::mal_nil
95 }
96 string_new [lindex $res 1]
97}
98
99proc mal_slurp {a} {
100 set filename [obj_val [lindex $a 0]]
101 set file [open $filename]
102 set content [read $file]
103 close $file
104 string_new $content
105}
106
107proc mal_lt {a} {
108 bool_new [expr {[obj_val [lindex $a 0]] < [obj_val [lindex $a 1]]}]
109}
110
111proc mal_lte {a} {
112 bool_new [expr {[obj_val [lindex $a 0]] <= [obj_val [lindex $a 1]]}]
113}
114
115proc mal_gt {a} {
116 bool_new [expr {[obj_val [lindex $a 0]] > [obj_val [lindex $a 1]]}]
117}
118
119proc mal_gte {a} {
120 bool_new [expr {[obj_val [lindex $a 0]] >= [obj_val [lindex $a 1]]}]
121}
122
123proc mal_add {a} {
124 integer_new [expr {[obj_val [lindex $a 0]] + [obj_val [lindex $a 1]]}]
125}
126
127proc mal_sub {a} {
128 integer_new [expr {[obj_val [lindex $a 0]] - [obj_val [lindex $a 1]]}]
129}
130
131proc mal_mul {a} {
132 integer_new [expr {[obj_val [lindex $a 0]] * [obj_val [lindex $a 1]]}]
133}
134
135proc mal_div {a} {
136 integer_new [expr {[obj_val [lindex $a 0]] / [obj_val [lindex $a 1]]}]
137}
138
139proc mal_time_ms {a} {
140 integer_new [clock milliseconds]
141}
142
143proc mal_list {a} {
144 list_new $a
145}
146
147proc mal_list_q {a} {
148 bool_new [list_q [lindex $a 0]]
149}
150
151proc mal_vector {a} {
152 vector_new $a
153}
154
155proc mal_vector_q {a} {
156 bool_new [vector_q [lindex $a 0]]
157}
158
159proc mal_hash_map {a} {
160 set d [dict create]
161 foreach {k v} $a {
162 dict set d [obj_val $k] $v
163 }
164 hashmap_new $d
165}
166
167proc mal_map_q {a} {
168 bool_new [hashmap_q [lindex $a 0]]
169}
170
171proc mal_assoc {a} {
172 set d [dict create]
173 dict for {k v} [obj_val [lindex $a 0]] {
174 dict set d $k $v
175 }
176 foreach {k v} [lrange $a 1 end] {
177 dict set d [obj_val $k] $v
178 }
179 hashmap_new $d
180}
181
182proc mal_dissoc {a} {
183 set d [dict create]
184 dict for {k v} [obj_val [lindex $a 0]] {
185 dict set d $k $v
186 }
187 foreach k [lrange $a 1 end] {
188 dict unset d [obj_val $k]
189 }
190 hashmap_new $d
191}
192
193proc mal_get {a} {
194 lassign $a hashmap_obj key_obj
195 if {[dict exists [obj_val $hashmap_obj] [obj_val $key_obj]]} {
196 dict get [obj_val $hashmap_obj] [obj_val $key_obj]
197 } else {
198 return $::mal_nil
199 }
200}
201
202proc mal_contains_q {a} {
203 lassign $a hashmap_obj key_obj
204 bool_new [dict exists [obj_val $hashmap_obj] [obj_val $key_obj]]
205}
206
207proc mal_keys {a} {
208 set res {}
209 foreach k [dict keys [obj_val [lindex $a 0]]] {
210 lappend res [string_new $k]
211 }
212 list_new $res
213}
214
215proc mal_vals {a} {
216 list_new [dict values [obj_val [lindex $a 0]]]
217}
218
219proc mal_sequential_q {a} {
220 bool_new [sequential_q [lindex $a 0]]
221}
222
223proc mal_cons {a} {
224 lassign $a head lst
225 list_new [concat [list $head] [obj_val $lst]]
226}
227
228proc mal_concat {a} {
229 set res {}
230 foreach lst $a {
231 if {[nil_q $lst]} {
232 continue
233 }
234 set res [concat $res [obj_val $lst]]
235 }
236 list_new $res
237}
238
239proc mal_nth {a} {
240 lassign $a lst_obj index_obj
241 set index [obj_val $index_obj]
242 set lst [obj_val $lst_obj]
243 if {$index >= [llength $lst]} {
244 error "nth: index out of range"
245 }
246 lindex $lst $index
247}
248
249proc mal_first {a} {
250 lassign $a lst
251 if {[nil_q $lst] || [llength [obj_val $lst]] == 0} {
252 return $::mal_nil
253 }
254 lindex [obj_val $lst] 0
255}
256
257proc mal_rest {a} {
258 lassign $a lst
259 list_new [lrange [obj_val $lst] 1 end]
260}
261
262proc mal_empty_q {a} {
263 bool_new [expr {[llength [obj_val [lindex $a 0]]] == 0}]
264}
265
266proc mal_count {a} {
267 integer_new [llength [obj_val [lindex $a 0]]]
268}
269
270proc mal_apply {a} {
271 set f [lindex $a 0]
272 if {[llength $a] > 1} {
273 set mid_args [lrange $a 1 end-1]
274 set last_list [lindex $a end]
275 set apply_args [concat $mid_args [obj_val $last_list]]
276 } else {
277 set apply_args {}
278 }
279
280 switch [obj_type $f] {
281 function {
282 set funcdict [obj_val $f]
283 set body [dict get $funcdict body]
284 set env [dict get $funcdict env]
285 set binds [dict get $funcdict binds]
286 set funcenv [Env new $env $binds $apply_args]
287 return [EVAL $body $funcenv]
288 }
289 nativefunction {
290 set body [concat [list [obj_val $f]] {$a}]
291 set lambda [list {a} $body]
292 return [apply $lambda $apply_args]
293 }
294 default {
295 error "Not a function"
296 }
297 }
298}
299
300proc mal_map {a} {
301 lassign $a f seq
302 set res {}
303 foreach item [obj_val $seq] {
304 set mappeditem [mal_apply [list $f [list_new [list $item]]]]
305 lappend res $mappeditem
306 }
307 list_new $res
308}
309
310proc mal_conj {a} {
311 lassign $a a0
312 if {[list_q $a0]} {
313 set lst $a0
314 foreach item [lrange $a 1 end] {
315 set lst [mal_cons [list $item $lst]]
316 }
317 return $lst
318 } elseif {[vector_q $a0]} {
319 set res [obj_val $a0]
320 foreach item [lrange $a 1 end] {
321 lappend res $item
322 }
323 vector_new $res
324 } else {
325 error "conj requires list or vector"
326 }
327}
328
0e198b2c
DM
329proc mal_seq {a} {
330 lassign $a a0
331 if {[string_q $a0]} {
332 set str [obj_val $a0]
333 if {$str == ""} {
334 return $::mal_nil
335 }
336 set res {}
337 foreach char [split $str {}] {
338 lappend res [string_new $char]
339 }
340 list_new $res
341 } elseif {[list_q $a0]} {
342 if {[llength [obj_val $a0]] == 0} {
343 return $::mal_nil
344 }
345 return $a0
346 } elseif {[vector_q $a0]} {
347 if {[llength [obj_val $a0]] == 0} {
348 return $::mal_nil
349 }
350 list_new [obj_val $a0]
351 } elseif {[nil_q $a0]} {
352 return $::mal_nil
353 } else {
354 error "seq requires string or list or vector or nil"
355 }
356}
357
54d9903c
DM
358proc mal_meta {a} {
359 obj_meta [lindex $a 0]
360}
361
362proc mal_with_meta {a} {
363 lassign $a a0 a1
364 obj_new [obj_type $a0] [obj_val $a0] $a1
365}
366
367proc mal_atom {a} {
368 atom_new [lindex $a 0]
369}
370
371proc mal_atom_q {a} {
372 bool_new [atom_q [lindex $a 0]]
373}
374
375proc mal_deref {a} {
376 obj_val [lindex $a 0]
377}
378
379proc mal_reset_bang {a} {
380 lassign $a a0 a1
381 obj_set_val $a0 $a1
382}
383
384proc mal_swap_bang {a} {
385 lassign $a a0 f
386 set apply_args [concat [list [obj_val $a0]] [lrange $a 2 end]]
387 set newval [mal_apply [list $f [list_new $apply_args]]]
388 mal_reset_bang [list $a0 $newval]
389}
390
391set core_ns [dict create \
392 "=" [nativefunction_new mal_equal] \
393 "throw" [nativefunction_new mal_throw] \
394 \
395 "nil?" [nativefunction_new mal_nil_q] \
396 "true?" [nativefunction_new mal_true_q] \
397 "false?" [nativefunction_new mal_false_q] \
398 "symbol" [nativefunction_new mal_symbol] \
399 "symbol?" [nativefunction_new mal_symbol_q] \
0e198b2c 400 "string?" [nativefunction_new mal_string_q] \
54d9903c
DM
401 "keyword" [nativefunction_new mal_keyword] \
402 "keyword?" [nativefunction_new mal_keyword_q] \
c91c8de9
DM
403 "number?" [nativefunction_new mal_number_q] \
404 "fn?" [nativefunction_new mal_fn_q] \
405 "macro?" [nativefunction_new mal_macro_q] \
54d9903c
DM
406 \
407 "pr-str" [nativefunction_new mal_pr_str] \
408 "str" [nativefunction_new mal_str] \
409 "prn" [nativefunction_new mal_prn] \
410 "println" [nativefunction_new mal_println] \
411 "read-string" [nativefunction_new mal_read_string] \
412 "readline" [nativefunction_new mal_readline] \
413 "slurp" [nativefunction_new mal_slurp] \
414 \
415 "<" [nativefunction_new mal_lt] \
416 "<=" [nativefunction_new mal_lte] \
417 ">" [nativefunction_new mal_gt] \
418 ">=" [nativefunction_new mal_gte] \
419 "+" [nativefunction_new mal_add] \
420 "-" [nativefunction_new mal_sub] \
421 "*" [nativefunction_new mal_mul] \
422 "/" [nativefunction_new mal_div] \
423 "time-ms" [nativefunction_new mal_time_ms] \
424 \
425 "list" [nativefunction_new mal_list] \
426 "list?" [nativefunction_new mal_list_q] \
427 "vector" [nativefunction_new mal_vector] \
428 "vector?" [nativefunction_new mal_vector_q] \
429 "hash-map" [nativefunction_new mal_hash_map] \
430 "map?" [nativefunction_new mal_map_q] \
431 "assoc" [nativefunction_new mal_assoc] \
432 "dissoc" [nativefunction_new mal_dissoc] \
433 "get" [nativefunction_new mal_get] \
434 "contains?" [nativefunction_new mal_contains_q] \
435 "keys" [nativefunction_new mal_keys] \
436 "vals" [nativefunction_new mal_vals] \
437 \
438 "sequential?" [nativefunction_new mal_sequential_q] \
439 "cons" [nativefunction_new mal_cons] \
440 "concat" [nativefunction_new mal_concat] \
441 "nth" [nativefunction_new mal_nth] \
442 "first" [nativefunction_new mal_first] \
443 "rest" [nativefunction_new mal_rest] \
444 "empty?" [nativefunction_new mal_empty_q] \
445 "count" [nativefunction_new mal_count] \
446 "apply" [nativefunction_new mal_apply] \
447 "map" [nativefunction_new mal_map] \
448 \
449 "conj" [nativefunction_new mal_conj] \
0e198b2c 450 "seq" [nativefunction_new mal_seq] \
54d9903c
DM
451 \
452 "meta" [nativefunction_new mal_meta] \
453 "with-meta" [nativefunction_new mal_with_meta] \
454 "atom" [nativefunction_new mal_atom] \
455 "atom?" [nativefunction_new mal_atom_q] \
456 "deref" [nativefunction_new mal_deref] \
457 "reset!" [nativefunction_new mal_reset_bang] \
458 "swap!" [nativefunction_new mal_swap_bang] \
459]