Commit | Line | Data |
---|---|---|
21986733 DM |
1 | require, "types.i" |
2 | ||
3 | func mal_equal(a) { return new_boolean(equal(*a(1), *a(2))); } | |
4 | func mal_throw(a) { return MalError(obj=a(1)); } | |
5 | ||
6 | func mal_nil_q(a) { return new_boolean(structof(*a(1)) == MalNil); } | |
7 | func mal_true_q(a) { return new_boolean(structof(*a(1)) == MalTrue); } | |
8 | func mal_false_q(a) { return new_boolean(structof(*a(1)) == MalFalse); } | |
9 | func mal_string_q(a) { return new_boolean(structof(*a(1)) == MalString); } | |
10 | func mal_symbol(a) { return MalSymbol(val=a(1)->val); } | |
11 | func mal_symbol_q(a) { return new_boolean(structof(*a(1)) == MalSymbol); } | |
12 | func mal_keyword(a) { return MalKeyword(val=a(1)->val); } | |
13 | func mal_keyword_q(a) { return new_boolean(structof(*a(1)) == MalKeyword); } | |
7cecb87a DM |
14 | func mal_number_q(a) { return new_boolean(structof(*a(1)) == MalNumber); } |
15 | func mal_fn_q(a) | |
16 | { | |
17 | if (structof(*a(1)) == MalNativeFunction) return MAL_TRUE; | |
18 | return new_boolean(structof(*a(1)) == MalFunction && !a(1)->macro); | |
19 | } | |
20 | func mal_macro_q(a) { return new_boolean(structof(*a(1)) == MalFunction && a(1)->macro); } | |
21986733 DM |
21 | |
22 | func string_helper(a, delimiter, readable) | |
23 | { | |
24 | res = "" | |
25 | for (i = 1; i <= numberof(a); ++i) { | |
26 | if (i > 1) res += delimiter | |
27 | res += pr_str(*a(i), readable) | |
28 | } | |
29 | return res | |
30 | } | |
31 | ||
32 | func mal_pr_str(a) { return MalString(val=string_helper(a, " ", 1)); } | |
33 | func mal_str(a) { return MalString(val=string_helper(a, "", 0)); } | |
34 | func mal_prn(a) { write, format="%s\n", string_helper(a, " ", 1); return MAL_NIL; } | |
35 | func mal_println(a) { write, format="%s\n", string_helper(a, " ", 0); return MAL_NIL; } | |
36 | func mal_read_string(a) { return read_str(a(1)->val); } | |
37 | ||
38 | func mal_readline(a) | |
39 | { | |
40 | extern stdin_file | |
6c4cc8ad | 41 | stdin_file = open("/dev/stdin", "r") |
21986733 DM |
42 | write, format="%s", a(1)->val |
43 | line = rdline(stdin_file, prompt="") | |
44 | return line ? MalString(val=line) : MAL_NIL | |
45 | } | |
46 | ||
47 | func mal_slurp(a) | |
48 | { | |
49 | f = open(a(1)->val) | |
50 | lines = rdfile(f) | |
51 | close, f | |
52 | s = "" | |
53 | for (i = 1; i <= numberof(lines); ++i) { | |
54 | s += (lines(i) + "\n") | |
55 | } | |
56 | return MalString(val=s) | |
57 | } | |
58 | ||
59 | func mal_lt(a) { return new_boolean(a(1)->val < a(2)->val); } | |
60 | func mal_lte(a) { return new_boolean(a(1)->val <= a(2)->val); } | |
61 | func mal_gt(a) { return new_boolean(a(1)->val > a(2)->val); } | |
62 | func mal_gte(a) { return new_boolean(a(1)->val >= a(2)->val); } | |
63 | ||
64 | func mal_add(a) { return MalNumber(val=(a(1)->val + a(2)->val)); } | |
65 | func mal_sub(a) { return MalNumber(val=(a(1)->val - a(2)->val)); } | |
66 | func mal_mul(a) { return MalNumber(val=(a(1)->val * a(2)->val)); } | |
67 | func mal_div(a) { return MalNumber(val=(a(1)->val / a(2)->val)); } | |
68 | ||
69 | func mal_time_ms(a) | |
70 | { | |
71 | elapsed = array(double, 3) | |
72 | timer, elapsed | |
73 | return MalNumber(val=floor(elapsed(3) * 1000)) | |
74 | } | |
75 | ||
76 | func mal_list(a) { return MalList(val=&a); } | |
77 | func mal_list_q(a) { return new_boolean(structof(*a(1)) == MalList); } | |
78 | func mal_vector(a) { return MalVector(val=&a); } | |
79 | func mal_vector_q(a) { return new_boolean(structof(*a(1)) == MalVector); } | |
80 | func mal_hash_map(a) { return array_to_hashmap(a); } | |
81 | func mal_map_q(a) { return new_boolean(structof(*a(1)) == MalHashmap); } | |
82 | ||
83 | func mal_assoc(a) { | |
84 | h = *(a(1)->val) | |
85 | k1 = *h.keys | |
86 | v1 = *h.vals | |
87 | new_h = Hash(keys=&k1, vals=&v1) | |
88 | for (i = 2; i <= numberof(a); i += 2) { | |
89 | hash_set, new_h, hashmap_obj_to_key(*a(i)), *a(i + 1) | |
90 | } | |
91 | return MalHashmap(val=&new_h); | |
92 | } | |
93 | ||
94 | func mal_dissoc(a) { | |
95 | h = *(a(1)->val) | |
96 | k1 = *h.keys | |
97 | v1 = *h.vals | |
98 | new_h = Hash(keys=&k1, vals=&v1) | |
99 | for (i = 2; i <= numberof(a); ++i) { | |
100 | hash_delete, new_h, hashmap_obj_to_key(*a(i)) | |
101 | } | |
102 | return MalHashmap(val=&new_h); | |
103 | } | |
104 | ||
105 | func mal_get(a) { | |
106 | if (structof(*a(1)) == MalNil) return MAL_NIL | |
107 | h = *(a(1)->val) | |
108 | key_obj = *a(2) | |
109 | val = hash_get(h, hashmap_obj_to_key(key_obj)) | |
110 | return is_void(val) ? MAL_NIL : val | |
111 | } | |
112 | ||
113 | func mal_contains_q(a) { | |
114 | if (structof(*a(1)) == MalNil) return MAL_FALSE | |
115 | h = *(a(1)->val) | |
116 | key_obj = *a(2) | |
117 | return hash_has_key(h, hashmap_obj_to_key(key_obj)) ? MAL_TRUE : MAL_FALSE | |
118 | } | |
119 | ||
120 | func mal_keys(a) { | |
121 | keys_strs = *(a(1)->val->keys) | |
122 | if (numberof(keys_strs) == 0) return MalList(val=&[]) | |
123 | res = array(pointer, numberof(keys_strs)) | |
124 | for (i = 1; i <= numberof(keys_strs); ++i) { | |
125 | res(i) = &hashmap_key_to_obj(keys_strs(i)) | |
126 | } | |
127 | return MalList(val=&res); | |
128 | } | |
129 | ||
130 | func mal_vals(a) { return MalList(val=a(1)->val->vals); } | |
131 | ||
132 | func mal_sequential_q(a) { return new_boolean(structof(*a(1)) == MalList || structof(*a(1)) == MalVector); } | |
133 | ||
134 | func mal_cons(a) | |
135 | { | |
136 | a2_len = count(*a(2)) | |
137 | seq = array(pointer, a2_len + 1) | |
138 | seq(1) = a(1) | |
139 | if (a2_len > 0) { | |
140 | seq(2:) = *(a(2)->val) | |
141 | } | |
142 | return MalList(val=&seq) | |
143 | } | |
144 | ||
145 | func mal_concat(a) | |
146 | { | |
147 | seq = [] | |
148 | for (i = 1; i <= numberof(a); ++i) { | |
149 | grow, seq, *(a(i)->val) | |
150 | } | |
151 | return MalList(val=&seq) | |
152 | } | |
153 | ||
154 | func mal_nth(a) | |
155 | { | |
156 | index = a(2)->val | |
157 | if (index >= count(*a(1))) return MalError(message="nth: index out of range") | |
158 | return *((*(a(1)->val))(index + 1)) | |
159 | } | |
160 | ||
161 | func mal_first(a) | |
162 | { | |
163 | if (structof(*a(1)) == MalNil || count(*a(1)) == 0) return MAL_NIL | |
164 | return *((*(a(1)->val))(1)) | |
165 | } | |
166 | ||
167 | func mal_rest(a) | |
168 | { | |
169 | if (structof(*a(1)) == MalNil) return MalList(val=&[]) | |
170 | return rest(*a(1)) | |
171 | } | |
172 | ||
173 | func mal_empty_q(a) { return new_boolean((structof(*a(1)) == MalNil ? 1 : count(*a(1)) == 0)); } | |
174 | func mal_count(a) { return MalNumber(val=(structof(*a(1)) == MalNil ? 0 : count(*a(1)))); } | |
175 | ||
176 | func call_func(fn, args) | |
177 | { | |
178 | if (structof(fn) == MalNativeFunction) { | |
179 | return call_core_fn(fn.val, args) | |
180 | } else if (structof(fn) == MalFunction) { | |
181 | fn_env = env_new(fn.env, binds=*fn.binds, exprs=args) | |
182 | return EVAL(*fn.ast, fn_env) | |
183 | } else { | |
184 | return MalError(message="Unknown function type") | |
185 | } | |
186 | } | |
187 | ||
188 | func mal_apply(a) { | |
189 | mid_args = numberof(a) > 2 ? a(2:-1) : [] | |
190 | return call_func(*a(1), grow(mid_args, *(a(0)->val))) | |
191 | } | |
192 | ||
193 | func mal_map(a) { | |
194 | fn = *a(1) | |
195 | seq = *(a(2)->val) | |
196 | if (numberof(seq) == 0) return MalList(val=&[]) | |
197 | new_seq = array(pointer, numberof(seq)) | |
198 | for (i = 1; i <= numberof(seq); ++i) { | |
199 | new_val = call_func(fn, [seq(i)]) | |
200 | if (structof(new_val) == MalError) return new_val | |
201 | new_seq(i) = &new_val | |
202 | } | |
203 | return MalList(val=&new_seq) | |
204 | } | |
205 | ||
206 | func mal_conj(a) | |
207 | { | |
208 | obj = *a(1) | |
209 | type = structof(obj) | |
210 | if (type == MalList) { | |
211 | res = obj | |
212 | for (i = 2; i <= numberof(a); ++i) { | |
213 | res = mal_cons([a(i), &res]) | |
214 | } | |
215 | return res | |
216 | } else if (type == MalVector) { | |
217 | seq = *obj.val | |
218 | grow, seq, a(2:) | |
219 | return MalVector(val=&seq) | |
220 | } else { | |
221 | return MalError(message="conj requires list or vector") | |
222 | } | |
223 | } | |
224 | ||
225 | func mal_seq(a) | |
226 | { | |
227 | obj = *a(1) | |
228 | type = structof(obj) | |
229 | if (type == MalString) { | |
230 | len = strlen(obj.val) | |
231 | if (len == 0) return MAL_NIL | |
232 | seq = array(pointer, len) | |
233 | for (i = 1; i <= len; ++i) { | |
234 | seq(i) = &MalString(val=strpart(obj.val, i:i)) | |
235 | } | |
236 | return MalList(val=&seq) | |
237 | } else if (type == MalList) { | |
238 | return count(obj) == 0 ? MAL_NIL : obj | |
239 | } else if (type == MalVector) { | |
240 | return count(obj) == 0 ? MAL_NIL : MalList(val=obj.val) | |
241 | } else if (type == MalNil) { | |
242 | return MAL_NIL | |
243 | } else { | |
244 | return MalError(message="seq requires string or list or vector or nil") | |
245 | } | |
246 | } | |
247 | ||
248 | func mal_meta(a) | |
249 | { | |
250 | meta_obj = *(a(1)->meta) | |
251 | return is_void(meta_obj) ? MAL_NIL : meta_obj | |
252 | } | |
253 | ||
254 | func mal_with_meta(a) | |
255 | { | |
256 | new_obj = *a(1) | |
257 | new_obj.meta = a(2) | |
258 | return new_obj | |
259 | } | |
260 | ||
261 | func mal_atom(a) { return MalAtom(val=&MalAtomVal(val=a(1))); } | |
262 | func mal_atom_q(a) { return new_boolean(structof(*a(1)) == MalAtom); } | |
263 | func mal_deref(a) { return *(a(1)->val->val); } | |
264 | func mal_reset_bang(a) { a(1)->val->val = a(2); return *(a(1)->val->val); } | |
265 | func mal_swap_bang(a) | |
266 | { | |
267 | old_val = mal_deref([a(1)]) | |
268 | args = array(pointer, numberof(a) - 1) | |
269 | args(1) = &old_val | |
270 | if (numberof(a) > 2) args(2:) = a(3:) | |
271 | new_val = call_func(*a(2), args) | |
272 | if (structof(new_val) == MalError) return new_val | |
273 | return mal_reset_bang([a(1), &new_val]) | |
274 | } | |
275 | ||
276 | func mal_eval(a) { return EVAL(*a(1), repl_env); } | |
277 | ||
c81a869e DM |
278 | func yorick_to_mal(e) |
279 | { | |
280 | if (is_void(e)) return MAL_NIL | |
281 | if (is_scalar(e)) { | |
282 | if (is_numerical(e)) return MalNumber(val=e) | |
283 | else if (is_string(e)) return MalString(val=e) | |
284 | else return MalString(val=totxt(e)) | |
285 | } else { | |
286 | seq = array(pointer, numberof(e)) | |
287 | for (i = 1; i <= numberof(e); ++i) { | |
288 | seq(i) = &yorick_to_mal(e(i)) | |
289 | } | |
290 | return MalList(val=&seq) | |
291 | } | |
292 | } | |
293 | ||
294 | func mal_yorick_eval(a) { return yorick_to_mal(exec(a(1)->val)); } | |
295 | ||
21986733 DM |
296 | core_ns = h_new() |
297 | ||
298 | h_set, core_ns, "=", mal_equal | |
299 | h_set, core_ns, "throw", mal_throw | |
300 | ||
301 | h_set, core_ns, "nil?", mal_nil_q | |
302 | h_set, core_ns, "true?", mal_true_q | |
303 | h_set, core_ns, "false?", mal_false_q | |
304 | h_set, core_ns, "string?", mal_string_q | |
305 | h_set, core_ns, "symbol", mal_symbol | |
306 | h_set, core_ns, "symbol?", mal_symbol_q | |
307 | h_set, core_ns, "keyword", mal_keyword | |
308 | h_set, core_ns, "keyword?", mal_keyword_q | |
7cecb87a DM |
309 | h_set, core_ns, "number?", mal_number_q |
310 | h_set, core_ns, "fn?", mal_fn_q | |
311 | h_set, core_ns, "macro?", mal_macro_q | |
21986733 DM |
312 | |
313 | h_set, core_ns, "pr-str", mal_pr_str | |
314 | h_set, core_ns, "str", mal_str | |
315 | h_set, core_ns, "prn", mal_prn | |
316 | h_set, core_ns, "println", mal_println | |
317 | h_set, core_ns, "read-string", mal_read_string | |
318 | h_set, core_ns, "readline", mal_readline | |
319 | h_set, core_ns, "slurp", mal_slurp | |
320 | ||
321 | h_set, core_ns, "<", mal_lt | |
322 | h_set, core_ns, "<=", mal_lte | |
323 | h_set, core_ns, ">", mal_gt | |
324 | h_set, core_ns, ">=", mal_gte | |
325 | h_set, core_ns, "+", mal_add | |
326 | h_set, core_ns, "-", mal_sub | |
327 | h_set, core_ns, "*", mal_mul | |
328 | h_set, core_ns, "/", mal_div | |
329 | h_set, core_ns, "time-ms", mal_time_ms | |
330 | ||
331 | h_set, core_ns, "list", mal_list | |
332 | h_set, core_ns, "list?", mal_list_q | |
333 | h_set, core_ns, "vector", mal_vector | |
334 | h_set, core_ns, "vector?", mal_vector_q | |
335 | h_set, core_ns, "hash-map", mal_hash_map | |
336 | h_set, core_ns, "map?", mal_map_q | |
337 | h_set, core_ns, "assoc", mal_assoc | |
338 | h_set, core_ns, "dissoc", mal_dissoc | |
339 | h_set, core_ns, "get", mal_get | |
340 | h_set, core_ns, "contains?", mal_contains_q | |
341 | h_set, core_ns, "keys", mal_keys | |
342 | h_set, core_ns, "vals", mal_vals | |
343 | ||
344 | h_set, core_ns, "sequential?", mal_sequential_q | |
345 | h_set, core_ns, "cons", mal_cons | |
346 | h_set, core_ns, "concat", mal_concat | |
347 | h_set, core_ns, "nth", mal_nth | |
348 | h_set, core_ns, "first", mal_first | |
349 | h_set, core_ns, "rest", mal_rest | |
350 | h_set, core_ns, "empty?", mal_empty_q | |
351 | h_set, core_ns, "count", mal_count | |
352 | h_set, core_ns, "apply", mal_apply | |
353 | h_set, core_ns, "map", mal_map | |
354 | ||
355 | h_set, core_ns, "conj", mal_conj | |
356 | h_set, core_ns, "seq", mal_seq | |
357 | ||
358 | h_set, core_ns, "meta", mal_meta | |
359 | h_set, core_ns, "with-meta", mal_with_meta | |
360 | h_set, core_ns, "atom", mal_atom | |
361 | h_set, core_ns, "atom?", mal_atom_q | |
362 | h_set, core_ns, "deref", mal_deref | |
363 | h_set, core_ns, "reset!", mal_reset_bang | |
364 | h_set, core_ns, "swap!", mal_swap_bang | |
365 | ||
366 | h_set, core_ns, "eval", mal_eval | |
c81a869e | 367 | h_set, core_ns, "yorick-eval", mal_yorick_eval |
21986733 DM |
368 | |
369 | func call_core_fn(name, args_list) | |
370 | { | |
371 | f = h_get(core_ns, name) | |
372 | return f(args_list) | |
373 | } |