Commit | Line | Data |
---|---|---|
8c7587af MK |
1 | @include "types.awk" |
2 | @include "reader.awk" | |
3 | @include "printer.awk" | |
4 | @include "env.awk" | |
5 | @include "core.awk" | |
6 | ||
7 | function READ(str) | |
8 | { | |
9 | return reader_read_str(str) | |
10 | } | |
11 | ||
fbfe6784 NB |
12 | # Return 0, an error or the unquote argument (second element of ast). |
13 | function starts_with(ast, sym, idx, len) | |
8c7587af | 14 | { |
fbfe6784 NB |
15 | if (ast !~ /^\(/) |
16 | return 0 | |
17 | idx = substr(ast, 2) | |
18 | len = types_heap[idx]["len"] | |
19 | if (!len || types_heap[idx][0] != sym) | |
20 | return 0 | |
21 | if (len != 2) | |
22 | return "!\"'" sym "' expects 1 argument, not " (len - 1) "." | |
23 | return types_heap[idx][1] | |
8c7587af MK |
24 | } |
25 | ||
fbfe6784 | 26 | function quasiquote(ast, new_idx, ret, ast_idx, elt_i, elt, previous) |
8c7587af | 27 | { |
fbfe6784 NB |
28 | if (ast !~ /^[(['{]/) { |
29 | return ast | |
30 | } | |
31 | if (ast ~ /['\{]/) { | |
8c7587af MK |
32 | new_idx = types_allocate() |
33 | types_heap[new_idx][0] = "'quote" | |
34 | types_heap[new_idx][1] = ast | |
35 | types_heap[new_idx]["len"] = 2 | |
36 | return "(" new_idx | |
37 | } | |
fbfe6784 NB |
38 | ret = starts_with(ast, "'unquote") |
39 | if (ret ~ /^!/) { | |
8c7587af MK |
40 | types_release(ast) |
41 | return ret | |
42 | } | |
fbfe6784 NB |
43 | if (ret) { |
44 | types_addref(ret) | |
45 | types_release(ast) | |
46 | return ret | |
47 | } | |
48 | new_idx = types_allocate() | |
49 | types_heap[new_idx]["len"] = 0 | |
50 | ast_idx = substr(ast, 2) | |
51 | for (elt_i=types_heap[ast_idx]["len"]-1; 0<=elt_i; elt_i--) { | |
52 | elt = types_heap[ast_idx][elt_i] | |
53 | ret = starts_with(elt, "'splice-unquote") | |
54 | if (ret ~ /^!/) { | |
55 | types_release("(" new_idx) | |
8c7587af | 56 | types_release(ast) |
fbfe6784 | 57 | return ret |
8c7587af | 58 | } |
fbfe6784 NB |
59 | if (ret) { |
60 | previous = "(" new_idx | |
61 | new_idx = types_allocate() | |
62 | types_heap[new_idx][0] = "'concat" | |
63 | types_heap[new_idx][1] = types_addref(ret) | |
64 | types_heap[new_idx][2] = previous | |
65 | types_heap[new_idx]["len"] = 3 | |
66 | } else { | |
67 | ret = quasiquote(types_addref(elt)) | |
68 | if (ret ~ /^!/) { | |
69 | types_release(ast) | |
70 | return ret | |
71 | } | |
72 | previous = "(" new_idx | |
73 | new_idx = types_allocate() | |
74 | types_heap[new_idx][0] = "'cons" | |
75 | types_heap[new_idx][1] = ret | |
76 | types_heap[new_idx][2] = previous | |
77 | types_heap[new_idx]["len"] = 3 | |
8c7587af | 78 | } |
8c7587af | 79 | } |
fbfe6784 NB |
80 | if (ast ~ /^\[/) { |
81 | previous = "(" new_idx | |
82 | new_idx = types_allocate() | |
83 | types_heap[new_idx][0] = "'vec" | |
84 | types_heap[new_idx][1] = previous | |
85 | types_heap[new_idx]["len"] = 2 | |
8c7587af | 86 | } |
8c7587af | 87 | types_release(ast) |
8c7587af MK |
88 | return "(" new_idx |
89 | } | |
90 | ||
fbfe6784 | 91 | function is_macro_call(ast, env, idx, len, sym, f) |
8c7587af | 92 | { |
fbfe6784 NB |
93 | if (ast !~ /^\(/) return 0 |
94 | idx = substr(ast, 2) | |
95 | len = types_heap[idx]["len"] | |
96 | if (len == 0) return 0 | |
97 | sym = types_heap[idx][0] | |
98 | if (sym !~ /^'/) return 0 | |
8c7587af MK |
99 | f = env_get(env, sym) |
100 | return f ~ /^\$/ && types_heap[substr(f, 2)]["is_macro"] | |
101 | } | |
102 | ||
103 | function macroexpand(ast, env, idx, f_idx, new_env) | |
104 | { | |
105 | while (is_macro_call(ast, env)) { | |
106 | idx = substr(ast, 2) | |
107 | f_idx = substr(env_get(env, types_heap[idx][0]), 2) | |
108 | new_env = env_new(types_heap[f_idx]["env"], types_heap[f_idx]["params"], idx) | |
109 | types_release(ast) | |
110 | if (new_env ~ /^!/) { | |
111 | return new_env | |
112 | } | |
113 | types_addref(ast = types_heap[f_idx]["body"]) | |
114 | ast = EVAL(ast, new_env) | |
115 | env_release(new_env) | |
116 | if (ast ~ /^!/) { | |
117 | return ast | |
118 | } | |
119 | } | |
120 | return ast | |
121 | } | |
122 | ||
123 | function eval_ast(ast, env, i, idx, len, new_idx, ret) | |
124 | { | |
125 | switch (ast) { | |
126 | case /^'/: | |
127 | ret = env_get(env, ast) | |
128 | if (ret !~ /^!/) { | |
129 | types_addref(ret) | |
130 | } | |
131 | return ret | |
132 | case /^[([]/: | |
133 | idx = substr(ast, 2) | |
134 | len = types_heap[idx]["len"] | |
135 | new_idx = types_allocate() | |
136 | for (i = 0; i < len; ++i) { | |
137 | ret = EVAL(types_addref(types_heap[idx][i]), env) | |
138 | if (ret ~ /^!/) { | |
139 | types_heap[new_idx]["len"] = i | |
140 | types_release(substr(ast, 1, 1) new_idx) | |
141 | return ret | |
142 | } | |
143 | types_heap[new_idx][i] = ret | |
144 | } | |
145 | types_heap[new_idx]["len"] = len | |
146 | return substr(ast, 1, 1) new_idx | |
147 | case /^\{/: | |
148 | idx = substr(ast, 2) | |
149 | new_idx = types_allocate() | |
150 | for (i in types_heap[idx]) { | |
151 | if (i ~ /^[":]/) { | |
152 | ret = EVAL(types_addref(types_heap[idx][i]), env) | |
153 | if (ret ~ /^!/) { | |
154 | types_release("{" new_idx) | |
155 | return ret | |
156 | } | |
157 | types_heap[new_idx][i] = ret | |
158 | } | |
159 | } | |
160 | return "{" new_idx | |
161 | default: | |
162 | return ast | |
163 | } | |
164 | } | |
165 | ||
166 | function EVAL_def(ast, env, idx, sym, ret, len) | |
167 | { | |
168 | idx = substr(ast, 2) | |
169 | if (types_heap[idx]["len"] != 3) { | |
170 | len = types_heap[idx]["len"] | |
171 | types_release(ast) | |
172 | env_release(env) | |
173 | return "!\"Invalid argument length for 'def!'. Expects exactly 2 arguments, supplied" (len - 1) "." | |
174 | } | |
175 | sym = types_heap[idx][1] | |
176 | if (sym !~ /^'/) { | |
177 | types_release(ast) | |
178 | env_release(env) | |
179 | return "!\"Incompatible type for argument 1 of 'def!'. Expects symbol, supplied " types_typename(sym) "." | |
180 | } | |
181 | ret = EVAL(types_addref(types_heap[idx][2]), env) | |
182 | if (ret !~ /^!/) { | |
183 | env_set(env, sym, ret) | |
184 | types_addref(ret) | |
185 | } | |
186 | types_release(ast) | |
187 | env_release(env) | |
188 | return ret | |
189 | } | |
190 | ||
191 | function EVAL_let(ast, env, ret_env, idx, params, params_idx, params_len, new_env, i, sym, ret, body, len) | |
192 | { | |
193 | idx = substr(ast, 2) | |
194 | if (types_heap[idx]["len"] != 3) { | |
195 | len = types_heap[idx]["len"] | |
196 | types_release(ast) | |
197 | env_release(env) | |
198 | return "!\"Invalid argument length for 'let*'. Expects exactly 2 arguments, supplied " (len - 1) "." | |
199 | } | |
200 | params = types_heap[idx][1] | |
201 | if (params !~ /^[([]/) { | |
202 | types_release(ast) | |
203 | env_release(env) | |
204 | return "!\"Incompatible type for argument 1 of 'let*'. Expects list or vector, supplied " types_typename(params) "." | |
205 | } | |
206 | params_idx = substr(params, 2) | |
207 | params_len = types_heap[params_idx]["len"] | |
208 | if (params_len % 2 != 0) { | |
209 | types_release(ast) | |
210 | env_release(env) | |
211 | return "!\"Invalid elements count for argument 1 of 'let*'. Expects even number of elements, supplied " params_len "." | |
212 | } | |
213 | new_env = env_new(env) | |
214 | env_release(env) | |
215 | for (i = 0; i < params_len; i += 2) { | |
216 | sym = types_heap[params_idx][i] | |
217 | if (sym !~ /^'/) { | |
218 | types_release(ast) | |
219 | env_release(new_env) | |
220 | return "!\"Incompatible type for odd element of argument 1 of 'let*'. Expects symbol, supplied " types_typename(sym) "." | |
221 | } | |
222 | ret = EVAL(types_addref(types_heap[params_idx][i + 1]), new_env) | |
223 | if (ret ~ /^!/) { | |
224 | types_release(ast) | |
225 | env_release(new_env) | |
226 | return ret | |
227 | } | |
228 | env_set(new_env, sym, ret) | |
229 | } | |
230 | types_addref(body = types_heap[idx][2]) | |
231 | types_release(ast) | |
232 | ret_env[0] = new_env | |
233 | return body | |
234 | } | |
235 | ||
236 | function EVAL_defmacro(ast, env, idx, sym, ret, len) | |
237 | { | |
238 | idx = substr(ast, 2) | |
239 | if (types_heap[idx]["len"] != 3) { | |
240 | len = types_heap[idx]["len"] | |
241 | types_release(ast) | |
242 | env_release(env) | |
243 | return "!\"Invalid argument length for 'defmacro!'. Expects exactly 2 arguments, supplied" (len - 1) "." | |
244 | } | |
245 | sym = types_heap[idx][1] | |
246 | if (sym !~ /^'/) { | |
247 | types_release(ast) | |
248 | env_release(env) | |
249 | return "!\"Incompatible type for argument 1 of 'defmacro!'. Expects symbol, supplied " types_typename(sym) "." | |
250 | } | |
251 | ret = EVAL(types_addref(types_heap[idx][2]), env) | |
252 | types_release(ast) | |
253 | if (ret ~ /^!/) { | |
254 | env_release(env) | |
255 | return ret | |
256 | } | |
257 | if (ret !~ /^\$/) { | |
258 | types_release(ret) | |
259 | env_release(env) | |
260 | return "!\"Incompatible type for argument 2 of 'defmacro!'. Expects function, supplied " types_typename(ret) "." | |
261 | } | |
262 | types_heap[substr(ret, 2)]["is_macro"] = 1 | |
263 | env_set(env, sym, ret) | |
264 | types_addref(ret) | |
265 | env_release(env) | |
266 | return ret | |
267 | } | |
268 | ||
269 | function EVAL_try(ast, env, catch_body, catch_env, idx, catch, catch_idx, catch_sym, ret, len, str) | |
270 | { | |
271 | idx = substr(ast, 2) | |
c738a39f DM |
272 | len = types_heap[idx]["len"] |
273 | if (len != 2 && len != 3) { | |
8c7587af MK |
274 | types_release(ast) |
275 | env_release(env) | |
c738a39f DM |
276 | return "!\"Invalid argument length for 'try*'. Expects 1 or 2 arguments, supplied" (len - 1) "." |
277 | } | |
278 | if (len == 2) { | |
279 | ret = EVAL(types_addref(types_heap[idx][1]), env) | |
280 | types_release(ast) | |
281 | env_release(env) | |
282 | return ret | |
8c7587af MK |
283 | } |
284 | catch = types_heap[idx][2] | |
285 | if (catch !~ /^\(/) { | |
286 | types_release(ast) | |
287 | env_release(env) | |
288 | return "!\"Incompatible type for argument 2 of 'try*'. Expects list, supplied " types_typename(catch) "." | |
289 | } | |
290 | catch_idx = substr(catch, 2) | |
291 | if (types_heap[catch_idx]["len"] != 3) { | |
292 | len = types_heap[catch_idx]["len"] | |
293 | types_release(ast) | |
294 | env_release(env) | |
295 | return "!\"Invalid elements count for argument 2 of 'try*'. Expects exactly 3 elements, supplied " len "." | |
296 | } | |
297 | if (types_heap[catch_idx][0] != "'catch*") { | |
298 | str = printer_pr_str(types_heap[catch_idx][0]) | |
299 | types_release(ast) | |
300 | env_release(env) | |
301 | return "!\"Invalid first element of argument 2 of 'try*'. Expects symbol 'catch*', supplied '" str "'." | |
302 | } | |
303 | catch_sym = types_heap[catch_idx][1] | |
304 | if (catch_sym !~ /^'/) { | |
305 | types_release(ast) | |
306 | env_release(env) | |
307 | return "!\"Incompatible type for second element of argument 2 of 'try*'. Expects symbol, supplied " types_typename(catch_sym) "." | |
308 | } | |
309 | ret = EVAL(types_addref(types_heap[idx][1]), env) | |
310 | if (ret !~ /^!/) { | |
311 | types_release(ast) | |
312 | env_release(env) | |
313 | return ret | |
314 | } | |
315 | types_addref(catch_body[0] = types_heap[catch_idx][2]) | |
316 | catch_env[0] = env_new(env) | |
317 | env_release(env) | |
318 | env_set(catch_env[0], catch_sym, substr(ret, 2)) | |
319 | types_release(ast) | |
320 | return "" | |
321 | } | |
322 | ||
323 | function EVAL_do(ast, env, idx, len, i, body, ret) | |
324 | { | |
325 | idx = substr(ast, 2) | |
326 | len = types_heap[idx]["len"] | |
327 | if (len == 1) { | |
328 | types_release(ast) | |
329 | env_release(env) | |
330 | return "!\"Invalid argument length for 'do'. Expects at least 1 argument, supplied" (len - 1) "." | |
331 | } | |
332 | for (i = 1; i < len - 1; ++i) { | |
333 | ret = EVAL(types_addref(types_heap[idx][i]), env) | |
334 | if (ret ~ /^!/) { | |
335 | types_release(ast) | |
336 | env_release(env) | |
337 | return ret | |
338 | } | |
339 | types_release(ret) | |
340 | } | |
341 | types_addref(body = types_heap[idx][len - 1]) | |
342 | types_release(ast) | |
343 | return body | |
344 | } | |
345 | ||
346 | function EVAL_if(ast, env, idx, len, ret, body) | |
347 | { | |
348 | idx = substr(ast, 2) | |
349 | len = types_heap[idx]["len"] | |
350 | if (len != 3 && len != 4) { | |
351 | types_release(ast) | |
352 | return "!\"Invalid argument length for 'if'. Expects 2 or 3 arguments, supplied " (len - 1) "." | |
353 | } | |
354 | ret = EVAL(types_addref(types_heap[idx][1]), env) | |
355 | if (ret ~ /^!/) { | |
356 | types_release(ast) | |
357 | return ret | |
358 | } | |
359 | types_release(ret) | |
360 | switch (ret) { | |
361 | case "#nil": | |
362 | case "#false": | |
363 | if (len == 3) { | |
364 | body = "#nil" | |
365 | } else { | |
366 | types_addref(body = types_heap[idx][3]) | |
367 | } | |
368 | break | |
369 | default: | |
370 | types_addref(body = types_heap[idx][2]) | |
371 | break | |
372 | } | |
373 | types_release(ast) | |
374 | return body | |
375 | } | |
376 | ||
377 | function EVAL_fn(ast, env, idx, params, params_idx, params_len, i, sym, f_idx, len) | |
378 | { | |
379 | idx = substr(ast, 2) | |
380 | if (types_heap[idx]["len"] != 3) { | |
381 | len = types_heap[idx]["len"] | |
382 | types_release(ast) | |
383 | env_release(env) | |
384 | return "!\"Invalid argument length for 'fn*'. Expects exactly 2 arguments, supplied " (len - 1) "." | |
385 | } | |
386 | params = types_heap[idx][1] | |
387 | if (params !~ /^[([]/) { | |
388 | types_release(ast) | |
389 | env_release(env) | |
390 | return "!\"Incompatible type for argument 1 of 'fn*'. Expects list or vector, supplied " types_typename(params) "." | |
391 | } | |
392 | params_idx = substr(params, 2) | |
393 | params_len = types_heap[params_idx]["len"] | |
394 | for (i = 0; i < params_len; ++i) { | |
395 | sym = types_heap[params_idx][i] | |
396 | if (sym !~ /^'/) { | |
397 | types_release(ast) | |
398 | env_release(env) | |
399 | return "!\"Incompatible type for element of argument 1 of 'fn*'. Expects symbol, supplied " types_typename(sym) "." | |
400 | } | |
401 | if (sym == "'&" && i + 2 != params_len) { | |
402 | types_release(ast) | |
403 | env_release(env) | |
404 | return "!\"Symbol '&' should be followed by last parameter. Parameter list length is " params_len ", position of symbol '&' is " (i + 1) "." | |
405 | } | |
406 | } | |
407 | f_idx = types_allocate() | |
408 | types_addref(types_heap[f_idx]["params"] = types_heap[idx][1]) | |
409 | types_addref(types_heap[f_idx]["body"] = types_heap[idx][2]) | |
410 | types_heap[f_idx]["env"] = env | |
411 | types_release(ast) | |
412 | return "$" f_idx | |
413 | } | |
414 | ||
415 | function EVAL(ast, env, body, new_ast, ret, idx, len, f, f_idx, ret_body, ret_env) | |
416 | { | |
417 | env_addref(env) | |
418 | for (;;) { | |
419 | if (ast !~ /^\(/) { | |
420 | ret = eval_ast(ast, env) | |
421 | types_release(ast) | |
422 | env_release(env) | |
423 | return ret | |
424 | } | |
425 | if (types_heap[substr(ast, 2)]["len"] == 0) { | |
426 | env_release(env) | |
427 | return ast | |
428 | } | |
429 | ast = macroexpand(ast, env) | |
430 | if (ast ~ /^!/) { | |
431 | env_release(env) | |
432 | return ast | |
433 | } | |
434 | if (ast !~ /^\(/) { | |
435 | ret = eval_ast(ast, env) | |
436 | types_release(ast) | |
437 | env_release(env) | |
438 | return ret | |
439 | } | |
440 | idx = substr(ast, 2) | |
441 | len = types_heap[idx]["len"] | |
442 | switch (types_heap[idx][0]) { | |
443 | case "'def!": | |
444 | return EVAL_def(ast, env) | |
445 | case "'let*": | |
446 | ast = EVAL_let(ast, env, ret_env) | |
447 | if (ast ~ /^!/) { | |
448 | return ast | |
449 | } | |
450 | env = ret_env[0] | |
451 | continue | |
452 | case "'quote": | |
453 | if (len != 2) { | |
454 | types_release(ast) | |
455 | env_release(env) | |
456 | return "!\"Invalid argument length for 'quote'. Expects exactly 1 argument, supplied " (len - 1) "." | |
457 | } | |
458 | types_addref(body = types_heap[idx][1]) | |
459 | types_release(ast) | |
460 | env_release(env) | |
461 | return body | |
fbfe6784 NB |
462 | case "'quasiquoteexpand": |
463 | env_release(env) | |
464 | if (len != 2) { | |
465 | types_release(ast) | |
466 | return "!\"Invalid argument length for 'quasiquoteexpand'. Expects exactly 1 argument, supplied " (len - 1) "." | |
467 | } | |
468 | types_addref(body = types_heap[idx][1]) | |
469 | types_release(ast) | |
470 | return quasiquote(body) | |
8c7587af MK |
471 | case "'quasiquote": |
472 | if (len != 2) { | |
473 | types_release(ast) | |
474 | env_release(env) | |
475 | return "!\"Invalid argument length for 'quasiquote'. Expects exactly 1 argument, supplied " (len - 1) "." | |
476 | } | |
477 | types_addref(body = types_heap[idx][1]) | |
478 | types_release(ast) | |
479 | ast = quasiquote(body) | |
480 | if (ast ~ /^!/) { | |
481 | env_release(env) | |
482 | return ast | |
483 | } | |
484 | continue | |
485 | case "'defmacro!": | |
486 | return EVAL_defmacro(ast, env) | |
487 | case "'macroexpand": | |
488 | if (len != 2) { | |
489 | types_release(ast) | |
490 | env_release(env) | |
491 | return "!\"Invalid argument length for 'macroexpand'. Expects exactly 1 argument, supplied " (len - 1) "." | |
492 | } | |
493 | types_addref(body = types_heap[idx][1]) | |
494 | types_release(ast) | |
495 | ret = macroexpand(body, env) | |
496 | env_release(env) | |
497 | return ret | |
498 | case "'try*": | |
499 | ret = EVAL_try(ast, env, ret_body, ret_env) | |
500 | if (ret != "") { | |
501 | return ret | |
502 | } | |
503 | ast = ret_body[0] | |
504 | env = ret_env[0] | |
505 | continue | |
506 | case "'do": | |
507 | ast = EVAL_do(ast, env) | |
508 | if (ast ~ /^!/) { | |
509 | return ast | |
510 | } | |
511 | continue | |
512 | case "'if": | |
513 | ast = EVAL_if(ast, env) | |
514 | if (ast !~ /^['([{]/) { | |
515 | env_release(env) | |
516 | return ast | |
517 | } | |
518 | continue | |
519 | case "'fn*": | |
520 | return EVAL_fn(ast, env) | |
521 | default: | |
522 | new_ast = eval_ast(ast, env) | |
523 | types_release(ast) | |
524 | env_release(env) | |
525 | if (new_ast ~ /^!/) { | |
526 | return new_ast | |
527 | } | |
528 | idx = substr(new_ast, 2) | |
529 | f = types_heap[idx][0] | |
530 | f_idx = substr(f, 2) | |
531 | switch (f) { | |
532 | case /^\$/: | |
533 | env = env_new(types_heap[f_idx]["env"], types_heap[f_idx]["params"], idx) | |
534 | if (env ~ /^!/) { | |
535 | types_release(new_ast) | |
536 | return env | |
537 | } | |
538 | types_addref(ast = types_heap[f_idx]["body"]) | |
539 | types_release(new_ast) | |
540 | continue | |
541 | case /^&/: | |
542 | ret = @f_idx(idx) | |
543 | types_release(new_ast) | |
544 | return ret | |
545 | default: | |
546 | types_release(new_ast) | |
547 | return "!\"First element of list must be function, supplied " types_typename(f) "." | |
548 | } | |
549 | } | |
550 | } | |
551 | } | |
552 | ||
553 | function PRINT(expr, str) | |
554 | { | |
555 | str = printer_pr_str(expr, 1) | |
556 | types_release(expr) | |
557 | return str | |
558 | } | |
559 | ||
560 | function rep(str, ast, expr) | |
561 | { | |
562 | ast = READ(str) | |
563 | if (ast ~ /^!/) { | |
564 | return ast | |
565 | } | |
566 | expr = EVAL(ast, repl_env) | |
567 | if (expr ~ /^!/) { | |
568 | return expr | |
569 | } | |
570 | return PRINT(expr) | |
571 | } | |
572 | ||
573 | function eval(idx) | |
574 | { | |
575 | if (types_heap[idx]["len"] != 2) { | |
576 | return "!\"Invalid argument length for builtin function 'eval'. Expects exactly 1 argument, supplied " (types_heap[idx]["len"] - 1) "." | |
577 | } | |
578 | return EVAL(types_addref(types_heap[idx][1]), repl_env) | |
579 | } | |
580 | ||
581 | function main(str, ret, i, idx) | |
582 | { | |
583 | repl_env = env_new() | |
584 | for (i in core_ns) { | |
585 | env_set(repl_env, i, core_ns[i]) | |
586 | } | |
587 | ||
588 | env_set(repl_env, "'eval", "&eval") | |
589 | ||
590 | rep("(def! not (fn* (a) (if a false true)))") | |
e6d41de4 | 591 | rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\\nnil)\")))))") |
8c7587af | 592 | rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") |
8c7587af MK |
593 | |
594 | idx = types_allocate() | |
595 | env_set(repl_env, "'*ARGV*", "(" idx) | |
596 | if (ARGC > 1) { | |
597 | for (i = 2; i < ARGC; ++i) { | |
598 | types_heap[idx][i - 2] = "\"" ARGV[i] | |
599 | } | |
600 | types_heap[idx]["len"] = ARGC - 2 | |
601 | ARGC = 1 | |
602 | rep("(load-file \"" ARGV[1] "\")") | |
603 | return | |
604 | } | |
605 | types_heap[idx]["len"] = 0 | |
606 | ||
607 | while (1) { | |
608 | printf("user> ") | |
609 | if (getline str <= 0) { | |
610 | break | |
611 | } | |
612 | ret = rep(str) | |
613 | if (ret ~ /^!/) { | |
614 | print "ERROR: " printer_pr_str(substr(ret, 2)) | |
615 | } else { | |
616 | print ret | |
617 | } | |
618 | } | |
619 | } | |
620 | ||
621 | BEGIN { | |
622 | main() | |
623 | env_check(0) | |
624 | env_dump() | |
625 | types_dump() | |
626 | exit(0) | |
627 | } |