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