Merge pull request #406 from chr15m/lib-alias-hacks
[jackhill/mal.git] / logo / core.lg
1 load "../logo/types.lg
2 load "../logo/reader.lg
3 load "../logo/printer.lg
4
5 make "global_exception []
6
7 to bool_to_mal :bool
8 output ifelse :bool [true_new] [false_new]
9 end
10
11 to mal_equal_q :a :b
12 output bool_to_mal equal_q :a :b
13 end
14
15 to mal_throw :a
16 make "global_exception :a
17 (throw "error "_mal_exception_)
18 end
19
20 to mal_nil_q :a
21 output bool_to_mal ((obj_type :a) = "nil)
22 end
23
24 to mal_true_q :a
25 output bool_to_mal ((obj_type :a) = "true)
26 end
27
28 to mal_false_q :a
29 output bool_to_mal ((obj_type :a) = "false)
30 end
31
32 to mal_string_q :a
33 output bool_to_mal ((obj_type :a) = "string)
34 end
35
36 to mal_symbol :a
37 output symbol_new obj_val :a
38 end
39
40 to mal_symbol_q :a
41 output bool_to_mal ((obj_type :a) = "symbol)
42 end
43
44 to mal_keyword :a
45 output obj_new "keyword obj_val :a
46 end
47
48 to mal_keyword_q :a
49 output bool_to_mal ((obj_type :a) = "keyword)
50 end
51
52 to mal_number_q :a
53 output bool_to_mal ((obj_type :a) = "number)
54 end
55
56 to mal_fn_q :a
57 case obj_type :a [
58 [[nativefn] output true_new ]
59 [[fn] output bool_to_mal not fn_is_macro :a]
60 [else output false_new ]
61 ]
62 end
63
64 to mal_macro_q :a
65 if ((obj_type :a) = "fn) [ output bool_to_mal fn_is_macro :a ]
66 output false_new
67 end
68
69 to mal_pr_str [:args]
70 output obj_new "string pr_seq :args "true " " :space_char
71 end
72
73 to mal_str [:args]
74 output obj_new "string pr_seq :args "false " " "
75 end
76
77 to mal_prn [:args]
78 print pr_seq :args "true " " :space_char
79 output nil_new
80 end
81
82 to mal_println [:args]
83 print pr_seq :args "false " " :space_char
84 output nil_new
85 end
86
87 to mal_read_string :str
88 output read_str obj_val :str
89 end
90
91 to mal_readline :prompt
92 localmake "line readline obj_val :prompt
93 if :line=[] [output nil_new]
94 output obj_new "string :line
95 end
96
97 to mal_slurp :str
98 openread obj_val :str
99 setread obj_val :str
100 localmake "content "
101 while [not eofp] [
102 make "content word :content readchar
103 ]
104 close obj_val :str
105 output obj_new "string :content
106 end
107
108 to mal_lt :a :b
109 output bool_to_mal ((obj_val :a) < (obj_val :b))
110 end
111
112 to mal_lte :a :b
113 output bool_to_mal ((obj_val :a) <= (obj_val :b))
114 end
115
116 to mal_gt :a :b
117 output bool_to_mal ((obj_val :a) > (obj_val :b))
118 end
119
120 to mal_gte :a :b
121 output bool_to_mal ((obj_val :a) >= (obj_val :b))
122 end
123
124 to mal_add :a :b
125 output obj_new "number ((obj_val :a) + (obj_val :b))
126 end
127
128 to mal_sub :a :b
129 output obj_new "number ((obj_val :a) - (obj_val :b))
130 end
131
132 to mal_mul :a :b
133 output obj_new "number ((obj_val :a) * (obj_val :b))
134 end
135
136 to mal_div :a :b
137 output obj_new "number ((obj_val :a) / (obj_val :b))
138 end
139
140 to mal_time_ms
141 ; Native function timems is added to coms.c (see Dockerfile)
142 output obj_new "number timems
143 end
144
145 to mal_list [:args]
146 output obj_new "list :args
147 end
148
149 to mal_list_q :a
150 output bool_to_mal ((obj_type :a) = "list)
151 end
152
153 to mal_vector [:args]
154 output obj_new "vector :args
155 end
156
157 to mal_vector_q :a
158 output bool_to_mal ((obj_type :a) = "vector)
159 end
160
161 to mal_hash_map [:args]
162 localmake "h []
163 localmake "i 1
164 while [:i < count :args] [
165 make "h hashmap_put :h item :i :args item (:i + 1) :args
166 make "i (:i + 2)
167 ]
168 output obj_new "hashmap :h
169 end
170
171 to mal_map_q :a
172 output bool_to_mal ((obj_type :a) = "hashmap)
173 end
174
175 to mal_assoc :map [:args]
176 localmake "h obj_val :map
177 localmake "i 1
178 while [:i < count :args] [
179 make "h hashmap_put :h item :i :args item (:i + 1) :args
180 make "i (:i + 2)
181 ]
182 output obj_new "hashmap :h
183 end
184
185 to mal_dissoc :map [:args]
186 localmake "h obj_val :map
187 foreach :args [make "h hashmap_delete :h ?]
188 output obj_new "hashmap :h
189 end
190
191 to mal_get :map :key
192 localmake "val hashmap_get obj_val :map :key
193 if emptyp :val [output nil_new]
194 output :val
195 end
196
197 to mal_contains_q :map :key
198 localmake "val hashmap_get obj_val :map :key
199 output bool_to_mal not emptyp :val
200 end
201
202 to mal_keys :map
203 localmake "h obj_val :map
204 localmake "keys []
205 localmake "i 1
206 while [:i <= count :h] [
207 make "keys lput item :i :h :keys
208 make "i (:i + 2)
209 ]
210 output obj_new "list :keys
211 end
212
213 to mal_vals :map
214 localmake "h obj_val :map
215 localmake "values []
216 localmake "i 2
217 while [:i <= count :h] [
218 make "values lput item :i :h :values
219 make "i (:i + 2)
220 ]
221 output obj_new "list :values
222 end
223
224 to mal_sequential_q :a
225 output bool_to_mal sequentialp :a
226 end
227
228 to mal_cons :a :b
229 output obj_new "list fput :a obj_val :b
230 end
231
232 to mal_concat [:args]
233 output obj_new "list apply "sentence map [obj_val ?] :args
234 end
235
236 to mal_nth :a :i
237 if (obj_val :i) >= _count :a [(throw "error [nth: index out of range])]
238 output nth :a obj_val :i
239 end
240
241 to mal_first :a
242 output cond [
243 [[(obj_type :a) = "nil] nil_new]
244 [[(_count :a) = 0] nil_new]
245 [else first obj_val :a]
246 ]
247 end
248
249 to mal_rest :a
250 output obj_new "list cond [
251 [[(obj_type :a) = "nil] []]
252 [[(_count :a) = 0] []]
253 [else butfirst obj_val :a]
254 ]
255 end
256
257 to mal_empty_q :a
258 output bool_to_mal (emptyp obj_val :a)
259 end
260
261 to mal_count :a
262 output obj_new "number _count :a
263 end
264
265 to mal_apply :f [:args]
266 localmake "callargs obj_new "list sentence butlast :args obj_val last :args
267 output invoke_fn :f :callargs
268 end
269
270 to mal_map :f :seq
271 output obj_new "list map [invoke_fn :f obj_new "list (list ?)] obj_val :seq
272 end
273
274 to mal_conj :a0 [:rest]
275 case obj_type :a0 [
276 [[list] localmake "newlist :a0
277 foreach :rest [make "newlist mal_cons ? :newlist]
278 output :newlist ]
279 [[vector] output obj_new "vector sentence obj_val :a0 :rest ]
280 [else (throw "error [conj requires list or vector]) ]
281 ]
282 end
283
284 to mal_seq :a
285 case obj_type :a [
286 [[string]
287 if (_count :a) = 0 [output nil_new]
288 localmake "chars []
289 foreach obj_val :a [ make "chars lput obj_new "string ? :chars ]
290 output obj_new "list :chars ]
291 [[list]
292 if (_count :a) = 0 [output nil_new]
293 output :a ]
294 [[vector]
295 if (_count :a) = 0 [output nil_new]
296 output obj_new "list obj_val :a ]
297 [[nil] output nil_new ]
298 [else (throw "error [seq requires string or list or vector or nil]) ]
299 ]
300 end
301
302 to mal_meta :a
303 localmake "m obj_meta :a
304 if emptyp :m [output nil_new]
305 output :m
306 end
307
308 to mal_with_meta :a :new_meta
309 localmake "m ifelse (obj_type :new_meta) = "nil [[]] [:new_meta]
310 output obj_new_with_meta obj_type :a obj_val :a :m
311 end
312
313 to mal_atom :a
314 output obj_new "atom :a
315 end
316
317 to mal_atom_q :a
318 output bool_to_mal ((obj_type :a) = "atom)
319 end
320
321 to mal_deref :a
322 output obj_val :a
323 end
324
325 to mal_reset_bang :a :val
326 .setfirst butfirst :a :val
327 output :val
328 end
329
330 to invoke_fn :f :callargs
331 output case obj_type :f [
332 [[nativefn]
333 apply obj_val :f obj_val :callargs ]
334 [[fn]
335 _eval fn_body :f env_new fn_env :f fn_args :f :callargs ]
336 [else
337 (throw "error [Wrong type for apply])]
338 ]
339 end
340
341 to mal_swap_bang :atom :f [:args]
342 localmake "callargs obj_new "list fput mal_deref :atom :args
343 output mal_reset_bang :atom invoke_fn :f :callargs
344 end
345
346 to logo_to_mal :a
347 output cond [
348 [[:a = "true] true_new]
349 [[:a = "false] false_new]
350 [[numberp :a] obj_new "number :a]
351 [[wordp :a] obj_new "string :a]
352 [[listp :a] obj_new "list map [logo_to_mal ?] :a]
353 [else nil_new]
354 ]
355 end
356
357 to mal_logo_eval :str
358 make "res runresult obj_val :str
359 if emptyp :res [output nil_new]
360 output logo_to_mal first :res
361 end
362
363 make "core_ns [
364 [[symbol =] [nativefn mal_equal_q]]
365 [[symbol throw] [nativefn mal_throw]]
366
367 [[symbol nil?] [nativefn mal_nil_q]]
368 [[symbol true?] [nativefn mal_true_q]]
369 [[symbol false?] [nativefn mal_false_q]]
370 [[symbol string?] [nativefn mal_string_q]]
371 [[symbol symbol] [nativefn mal_symbol]]
372 [[symbol symbol?] [nativefn mal_symbol_q]]
373 [[symbol keyword] [nativefn mal_keyword]]
374 [[symbol keyword?] [nativefn mal_keyword_q]]
375 [[symbol number?] [nativefn mal_number_q]]
376 [[symbol fn?] [nativefn mal_fn_q]]
377 [[symbol macro?] [nativefn mal_macro_q]]
378
379 [[symbol pr-str] [nativefn mal_pr_str]]
380 [[symbol str] [nativefn mal_str]]
381 [[symbol prn] [nativefn mal_prn]]
382 [[symbol println] [nativefn mal_println]]
383 [[symbol read-string] [nativefn mal_read_string]]
384 [[symbol readline] [nativefn mal_readline]]
385 [[symbol slurp] [nativefn mal_slurp]]
386
387 [[symbol <] [nativefn mal_lt]]
388 [[symbol <=] [nativefn mal_lte]]
389 [[symbol >] [nativefn mal_gt]]
390 [[symbol >=] [nativefn mal_gte]]
391 [[symbol +] [nativefn mal_add]]
392 [[symbol -] [nativefn mal_sub]]
393 [[symbol *] [nativefn mal_mul]]
394 [[symbol /] [nativefn mal_div]]
395 [[symbol time-ms] [nativefn mal_time_ms]]
396
397 [[symbol list] [nativefn mal_list]]
398 [[symbol list?] [nativefn mal_list_q]]
399 [[symbol vector] [nativefn mal_vector]]
400 [[symbol vector?] [nativefn mal_vector_q]]
401 [[symbol hash-map] [nativefn mal_hash_map]]
402 [[symbol map?] [nativefn mal_map_q]]
403 [[symbol assoc] [nativefn mal_assoc]]
404 [[symbol dissoc] [nativefn mal_dissoc]]
405 [[symbol get] [nativefn mal_get]]
406 [[symbol contains?] [nativefn mal_contains_q]]
407 [[symbol keys] [nativefn mal_keys]]
408 [[symbol vals] [nativefn mal_vals]]
409
410 [[symbol sequential?] [nativefn mal_sequential_q]]
411 [[symbol cons] [nativefn mal_cons]]
412 [[symbol concat] [nativefn mal_concat]]
413 [[symbol nth] [nativefn mal_nth]]
414 [[symbol first] [nativefn mal_first]]
415 [[symbol rest] [nativefn mal_rest]]
416 [[symbol empty?] [nativefn mal_empty_q]]
417 [[symbol count] [nativefn mal_count]]
418 [[symbol apply] [nativefn mal_apply]]
419 [[symbol map] [nativefn mal_map]]
420
421 [[symbol conj] [nativefn mal_conj]]
422 [[symbol seq] [nativefn mal_seq]]
423
424 [[symbol meta] [nativefn mal_meta]]
425 [[symbol with-meta] [nativefn mal_with_meta]]
426 [[symbol atom] [nativefn mal_atom]]
427 [[symbol atom?] [nativefn mal_atom_q]]
428 [[symbol deref] [nativefn mal_deref]]
429 [[symbol reset!] [nativefn mal_reset_bang]]
430 [[symbol swap!] [nativefn mal_swap_bang]]
431
432 [[symbol logo-eval] [nativefn mal_logo_eval]]
433 ]