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