blob: 2a606401e37117593dde84fd9dc8c1413506cfa0 [file] [log] [blame]
swissChili8cfb7c42021-04-18 21:17:58 -07001/* -*- mode:c -*- */
2
swissChilica107a02021-04-14 12:07:30 -07003#include "compiler.h"
swissChilif3e7f182021-04-20 13:57:22 -07004#include "lib/std.h"
swissChili53472e82021-05-08 16:06:32 -07005#include "plat/plat.h"
swissChiliddc97542021-07-04 11:47:42 -07006#include "gc.h"
swissChilica107a02021-04-14 12:07:30 -07007
8#include <dasm_proto.h>
9#include <dasm_x86.h>
10
swissChili923b5362021-05-09 20:31:43 -070011#include <stdlib.h>
12#include <string.h>
13
swissChili53472e82021-05-08 16:06:32 -070014#define value_size sizeof(value_t)
swissChilica107a02021-04-14 12:07:30 -070015
16|.arch x86;
17
18|.macro setup, nvars;
swissChili74348422021-07-04 13:23:24 -070019|->function_start:
swissChilica107a02021-04-14 12:07:30 -070020| push ebp;
21| mov ebp, esp;
swissChili8cfb7c42021-04-18 21:17:58 -070022| sub esp, (value_size * nvars);
swissChilica107a02021-04-14 12:07:30 -070023|.endmacro;
24
25|.macro cleanup;
26| mov esp, ebp;
27| pop ebp;
28| ret;
29|.endmacro;
30
swissChili67bdf282021-06-06 18:46:08 -070031|.macro local_var, index;
32|.endmacro;
33
swissChilica107a02021-04-14 12:07:30 -070034dasm_State *d;
35unsigned int npc = 8;
36
swissChili9e57da42021-06-15 22:22:46 -070037|.macro run_gc;
swissChilie9fec8b2021-06-22 13:59:33 -070038| mov eax, esp;
swissChili9e57da42021-06-15 22:22:46 -070039| push ebp;
swissChilie9fec8b2021-06-22 13:59:33 -070040| push eax;
swissChili9e57da42021-06-15 22:22:46 -070041| mov eax, _do_gc;
42| call eax;
43|.endmacro;
swissChili6d6525e2021-06-15 21:20:53 -070044
swissChili53472e82021-05-08 16:06:32 -070045struct function *find_function(struct environment *env, char *name)
swissChilica107a02021-04-14 12:07:30 -070046{
swissChilif68671f2021-07-05 14:14:44 -070047 struct function *f;
swissChilica107a02021-04-14 12:07:30 -070048
swissChilif68671f2021-07-05 14:14:44 -070049 for (f = env->first; f && strcmp(f->name, name); f = f->prev)
swissChilica107a02021-04-14 12:07:30 -070050 {
swissChilica107a02021-04-14 12:07:30 -070051 }
52
53 return f;
54}
55
swissChili67bdf282021-06-06 18:46:08 -070056unsigned int local_alloc(struct local *local)
57{
58 for (int i = 0; i < local->num_stack_slots; i++)
59 {
60 if (local->stack_slots[i] == false)
61 {
62 local->stack_slots[i] = true;
63
64 if (i >= local->num_stack_entries)
65 local->num_stack_entries++;
66
67 return i;
68 }
69 }
70
71 int old_size = local->num_stack_slots;
72 local->num_stack_slots += 4;
73 local->stack_slots = realloc(local->stack_slots, local->num_stack_slots * sizeof(bool));
74 // unreadable: set the remaining slots to unused
75 memset(local->stack_slots + old_size, 0, local->num_stack_slots - old_size);
76 local->stack_slots[old_size] = true;
77
78 return old_size;
79}
80
81void local_free(struct local *local, unsigned int slot)
82{
83 local->stack_slots[slot] = false;
84}
85
swissChili708d4c42021-07-04 17:40:07 -070086void del_local(struct local *local)
87{
88 free(local->stack_slots);
89
90 for (struct variable *next, *f = local->first; f; f = next)
91 {
92 next = f->prev;
93 free(f);
94 }
95}
96
97void del_env(struct environment *env)
98{
99 for (struct function *next, *f = env->first; f; f = next)
100 {
101 next = f->prev;
102 // We're not gonna bother munmap()ing the function
103 free(f);
104 }
swissChilif68671f2021-07-05 14:14:44 -0700105
106 for (struct loaded_file *next, *l = env->first_loaded; l; l = next)
107 {
108 next = l->previous;
109 free(l->resolved_path);
110 free(l);
111 }
112}
113
114void add_load(struct environment *env, char *path)
115{
116 static char buffer[512];
117 long size = readlink(path, buffer, 512);
118 buffer[size] = '\0';
119 char *resolved = strdup(buffer);
120
121 struct loaded_file *f = malloc(sizeof(struct loaded_file));
122 f->resolved_path = resolved;
123 f->previous = env->first_loaded;
124 env->first_loaded = f;
swissChili708d4c42021-07-04 17:40:07 -0700125}
126
swissChilif1ba8c12021-07-02 18:45:38 -0700127struct dasm_State *compile_function(value_t args, enum namespace namespace,
swissChiliddc97542021-07-04 11:47:42 -0700128 struct environment *env, struct local *local_out,
swissChili15f1cae2021-07-05 19:08:47 -0700129 struct local *local_parent, struct args **args_out,
130 char *name)
swissChilif1ba8c12021-07-02 18:45:38 -0700131{
132 dasm_State *d;
133 dasm_State **Dst = &d;
134
135 |.section code;
136 dasm_init(&d, DASM_MAXSECTION);
137
138 |.globals lbl_;
139 void *labels[lbl__MAX];
140 dasm_setupglobal(&d, labels, lbl__MAX);
141
142 |.actionlist lisp_actions;
143 dasm_setup(&d, lisp_actions);
144
145 struct local local;
146 local.parent = NULL;
147 local.first = NULL;
148 local.num_vars = 0;
149 local.npc = 8;
150 local.nextpc = 0;
151 local.stack_slots = malloc(sizeof(bool) * 4);
152 memset(local.stack_slots, 0, sizeof(bool) * 4);
153 local.num_stack_slots = 4;
154 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700155 local.num_closure_slots = 0;
156 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700157 local.current_function_name = name;
swissChilif1ba8c12021-07-02 18:45:38 -0700158
159 dasm_growpc(&d, local.npc);
160
swissChilif1ba8c12021-07-02 18:45:38 -0700161 value_t arglist = car(args);
162 value_t body = cdr(args);
163
swissChili15f1cae2021-07-05 19:08:47 -0700164 // This will add the arguments to local too.
165 struct args *ar = list_to_args(env, arglist, &local);
166 local.args = ar;
swissChili74348422021-07-04 13:23:24 -0700167
swissChili15f1cae2021-07-05 19:08:47 -0700168 if (!ar)
swissChilif1ba8c12021-07-02 18:45:38 -0700169 {
swissChili15f1cae2021-07-05 19:08:47 -0700170 err("Malformed args list");
swissChilif1ba8c12021-07-02 18:45:38 -0700171 }
172
173 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
174 {
175 walk_and_alloc(&local, car(body_));
176 }
177
178 | setup (local.num_stack_entries);
179
180 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
181 local.num_stack_entries = 0;
182
183 for (; !nilp(body); body = cdr(body))
184 {
185 compile_expression(env, &local, car(body), Dst);
186 }
187
188 | cleanup;
189
190 if (local_out)
191 *local_out = local;
192
swissChili15f1cae2021-07-05 19:08:47 -0700193 if (args_out)
194 *args_out = ar;
swissChilif1ba8c12021-07-02 18:45:38 -0700195
196 return d;
197}
198
swissChili53472e82021-05-08 16:06:32 -0700199void compile_tl(value_t val, struct environment *env)
swissChilica107a02021-04-14 12:07:30 -0700200{
swissChili53472e82021-05-08 16:06:32 -0700201 if (!listp(val))
202 err("Top level must be a list");
swissChilica107a02021-04-14 12:07:30 -0700203
swissChili53472e82021-05-08 16:06:32 -0700204 value_t form = car(val);
205 value_t args = cdr(val);
206
swissChili2999dd12021-07-02 14:19:53 -0700207 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700208 {
swissChili2999dd12021-07-02 14:19:53 -0700209 enum namespace namespace = NS_FUNCTION;
210
211 if (symstreq(form, "defmacro"))
212 namespace = NS_MACRO;
213
swissChili8fc5e2f2021-04-22 13:45:10 -0700214 struct local local;
swissChili15f1cae2021-07-05 19:08:47 -0700215 struct args *a;
swissChili74348422021-07-04 13:23:24 -0700216 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChilif68671f2021-07-05 14:14:44 -0700217
swissChili15f1cae2021-07-05 19:08:47 -0700218 dasm_State *d = compile_function(cdr(args), namespace, env, &local, NULL, &a, name);
swissChilia820dea2021-05-09 16:46:55 -0700219
swissChilif68671f2021-07-05 14:14:44 -0700220 add_function(env, name, link_program(&d),
swissChili15f1cae2021-07-05 19:08:47 -0700221 a, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700222
swissChili53472e82021-05-08 16:06:32 -0700223 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700224 del_local(&local);
swissChili67bdf282021-06-06 18:46:08 -0700225 }
swissChilif68671f2021-07-05 14:14:44 -0700226 else if (symstreq(form, "progn"))
227 {
228 for (value_t val = args; !nilp(val); val = cdr(val))
229 {
230 compile_tl(car(val), env);
231 }
232 }
swissChili67bdf282021-06-06 18:46:08 -0700233}
234
235void walk_and_alloc(struct local *local, value_t body)
236{
237 if (!listp(body))
238 return;
239
240 value_t args = cdr(body);
241
242 if (symstreq(car(body), "let1"))
243 {
244 int slot = local_alloc(local);
245
246 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700247 for (; !nilp(expr); expr = cdr(expr))
248 {
swissChiliddc97542021-07-04 11:47:42 -0700249 walk_and_alloc(local, car(expr));
swissChilif1ba8c12021-07-02 18:45:38 -0700250 }
swissChili67bdf282021-06-06 18:46:08 -0700251
252 local_free(local, slot);
253 }
swissChilif1ba8c12021-07-02 18:45:38 -0700254 else if (symstreq(car(body), "lambda"))
255 {
256 // We don't want to walk the lambda because it's another function. When
257 // the lambda is compiled it will be walked.
258 return;
259 }
swissChili67bdf282021-06-06 18:46:08 -0700260 else
261 {
262 for (; !nilp(args); args = cdr(args))
263 {
264 walk_and_alloc(local, car(args));
265 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700266 }
267}
268
swissChilif68671f2021-07-05 14:14:44 -0700269bool load(struct environment *env, char *path)
swissChili8fc5e2f2021-04-22 13:45:10 -0700270{
swissChilif68671f2021-07-05 14:14:44 -0700271 if (!file_exists(path))
272 return false;
273
274 add_load(env, path);
275
swissChilib8fd4712021-06-23 15:32:04 -0700276 unsigned char pool = make_pool();
277 unsigned char pop = push_pool(pool);
278
swissChilif68671f2021-07-05 14:14:44 -0700279 struct istream *is = new_fistream(path, false);
280 if (!is)
281 return false;
282
swissChili8fc5e2f2021-04-22 13:45:10 -0700283 value_t val;
swissChili53472e82021-05-08 16:06:32 -0700284
285 while (read1(is, &val))
swissChili8fc5e2f2021-04-22 13:45:10 -0700286 {
swissChilif68671f2021-07-05 14:14:44 -0700287 compile_tl(val, env);
swissChili8fc5e2f2021-04-22 13:45:10 -0700288 }
swissChilif3e7f182021-04-20 13:57:22 -0700289
swissChilif68671f2021-07-05 14:14:44 -0700290 del_fistream(is);
swissChilib8fd4712021-06-23 15:32:04 -0700291 pop_pool(pop);
292
swissChilif68671f2021-07-05 14:14:44 -0700293 return true;
294}
295
296struct environment compile_file(char *filename, bool *ok)
297{
298 value_t val;
299 struct environment env;
300 env.first = NULL;
301 env.first_loaded = NULL;
302
303 add_load(&env, filename);
304 load_std(&env);
305
306 bool ok_ = load(&env, filename);
307
308 if (ok)
309 *ok = ok_;
310
swissChili8fc5e2f2021-04-22 13:45:10 -0700311 return env;
swissChilica107a02021-04-14 12:07:30 -0700312}
swissChilib3ca4fb2021-04-20 10:33:00 -0700313
swissChili53472e82021-05-08 16:06:32 -0700314int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700315{
swissChili53472e82021-05-08 16:06:32 -0700316 int n = local->nextpc++;
317 if (n > local->npc)
318 {
319 local->npc += 16;
320 dasm_growpc(Dst, local->npc);
321 }
322 return n;
323}
324
swissChili6b47b6d2021-06-30 22:08:55 -0700325void compile_backquote(struct environment *env, struct local *local,
326 value_t val, dasm_State **Dst)
327{
328 if (!listp(val))
329 {
330 | mov eax, (val);
331 }
332 else
333 {
334 value_t fsym = car(val),
335 args = cdr(val);
336 int nargs = length(args);
337
338 // TODO
339 }
340}
341
swissChiliddc97542021-07-04 11:47:42 -0700342void compile_variable(struct variable *v, dasm_State *Dst)
343{
344 switch (v->type)
345 {
346 case V_ARGUMENT:
347 | mov eax, dword [ebp + (value_size * (v->number + 2))];
348 break;
349 case V_BOUND:
350 | mov eax, dword [ebp - ((v->number + 1) * value_size)];
351 break;
352 case V_FREE:
353 // edi is the closure context pointer
354 | mov eax, dword [edi + (v->number * value_size)];
355 break;
356 default:
357 err("Sorry, can only access V_ARGUMENT, V_FREE and V_BOUND variables for now :(");
358 }
359}
360
swissChili53472e82021-05-08 16:06:32 -0700361void compile_expression(struct environment *env, struct local *local,
362 value_t val, dasm_State **Dst)
363{
364 if (symstreq(val, "nil"))
365 {
366 | mov eax, (nil);
367 }
swissChili923b5362021-05-09 20:31:43 -0700368 else if (symstreq(val, "t"))
369 {
370 | mov eax, (t);
371 }
372 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700373 {
374 | mov eax, val;
375 }
swissChili53472e82021-05-08 16:06:32 -0700376 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700377 {
swissChili53472e82021-05-08 16:06:32 -0700378 value_t fsym = car(val);
379 value_t args = cdr(val);
380 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700381
swissChili53472e82021-05-08 16:06:32 -0700382 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700383 {
swissChili53472e82021-05-08 16:06:32 -0700384 err("function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700385 }
386
swissChili53472e82021-05-08 16:06:32 -0700387 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700388 {
swissChili53472e82021-05-08 16:06:32 -0700389 if (nargs < 2 || nargs > 3)
390 err("Must give at least 2 arguments to if");
swissChilib3ca4fb2021-04-20 10:33:00 -0700391
swissChili53472e82021-05-08 16:06:32 -0700392 compile_expression(env, local, car(args), Dst);
393 int false_label = nextpc(local, Dst),
394 after_label = nextpc(local, Dst);
395
396 // result is in eax
397 | cmp eax, (nil);
398 | je =>false_label;
399
400 compile_expression(env, local, elt(args, 1), Dst);
swissChilia820dea2021-05-09 16:46:55 -0700401 | jmp =>after_label;
swissChili923b5362021-05-09 20:31:43 -0700402 |=>false_label:;
swissChili53472e82021-05-08 16:06:32 -0700403 if (nargs == 3)
404 compile_expression(env, local, elt(args, 2), Dst);
405 |=>after_label:
406 }
swissChilif68671f2021-07-05 14:14:44 -0700407 else if (symstreq(fsym, "progn"))
408 {
409 for (value_t val = args; !nilp(val); val = cdr(val))
410 {
411 compile_expression(env, local, car(val), Dst);
412 }
413 }
swissChili67bdf282021-06-06 18:46:08 -0700414 else if (symstreq(fsym, "let1"))
415 {
416 if (nargs < 2)
417 {
418 err("Must give at least 2 arguments to let1");
419 }
420 value_t binding = car(args);
421 value_t rest = cdr(args);
422
423 if (length(binding) != 2)
424 {
425 err("Binding list in let1 must contain exactly two entries");
426 }
427
428 value_t name = car(binding);
429 value_t value = car(cdr(binding));
430
431 compile_expression(env, local, value, Dst);
432
433 int i = local_alloc(local);
434
435 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
436
437 | mov dword [ebp - ((i + 1) * value_size)], eax;
438
439 for (; !nilp(rest); rest = cdr(rest))
440 {
441 compile_expression(env, local, car(rest), Dst);
442 }
443
444 local_free(local, i);
445 }
swissChilie9fec8b2021-06-22 13:59:33 -0700446 else if (symstreq(fsym, "gc"))
447 {
448 if (nargs)
449 {
450 err("gc takes no arguments");
451 }
452
453 | run_gc;
454 }
swissChili6b47b6d2021-06-30 22:08:55 -0700455 else if (symstreq(fsym, "quote"))
456 {
457 if (nargs != 1)
458 err("quote should take exactly 1 argument");
459
460 // Simple!
461 | mov eax, (car(args));
462 }
463 else if (symstreq(fsym, "backquote"))
464 {
465 if (nargs != 1)
466 err("backquote should take exactly 1 argument");
467
468 compile_backquote(env, local, car(args), Dst);
469 }
swissChili74348422021-07-04 13:23:24 -0700470 else if (symstreq(fsym, "function"))
471 {
472 if (nargs != 1)
473 {
474 err("function should take exactly 1 argument");
475 }
476
477 if (!symbolp(car(args)))
478 {
479 err("argument to function should be a symbol resolvable at compile time");
480 }
481
482 struct function *f = find_function(env, (char *)(car(args) ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -0700483 value_t closure = create_closure(f->code_ptr, f->args, 0);
swissChili74348422021-07-04 13:23:24 -0700484
485 | mov eax, (closure);
486 }
swissChili6b47b6d2021-06-30 22:08:55 -0700487 else if (symstreq(fsym, "list"))
488 {
489 | push (nil);
490
491 for (int i = nargs - 1; i >= 0; i--)
492 {
493 compile_expression(env, local, elt(args, i), Dst);
494
495 // push the ith item
496 | push eax;
497 // cons the top two stack items
498 | mov ebx, (cons);
499 | call ebx;
500 // remove the stack items from use
501 | add esp, (2 * value_size);
502 // put the new thing on the stack
503 | push eax;
504 }
505
506 | pop eax;
507 }
swissChiliddc97542021-07-04 11:47:42 -0700508 else if (symstreq(fsym, "lambda"))
509 {
510 // Compile the function with this as the parent scope
511 struct local new_local;
512 int nargs_out;
swissChili74348422021-07-04 13:23:24 -0700513 dasm_State *d = compile_function(args, NS_ANONYMOUS, env, &new_local, local, &nargs_out, "recurse");
swissChiliddc97542021-07-04 11:47:42 -0700514
515 // Link the function
swissChilif68671f2021-07-05 14:14:44 -0700516 void *func_ptr = link_program(&d);
swissChiliddc97542021-07-04 11:47:42 -0700517
518 // Create a closure object with the correct number of captures at
519 // runtime
swissChiliddc97542021-07-04 11:47:42 -0700520 | push (new_local.num_closure_slots);
521 | push (nargs_out);
522 | push (func_ptr);
swissChili74348422021-07-04 13:23:24 -0700523 | mov ebx, (create_closure);
swissChiliddc97542021-07-04 11:47:42 -0700524 | call ebx;
525 | add esp, 12;
526
527 // Walk the generated local scope for V_FREE variables, since each
528 // of these exists in our scope (or higher), evaluate it and set it
529 // as a member of the lambda capture.
530
531 for (struct variable *var = new_local.first; var; var = var->prev)
532 {
533 if (var->type == V_FREE)
534 {
535 // Closure in eax
536 | push eax;
537 // Variable now in eax
538 compile_variable(find_variable(local, var->name), Dst);
539 | push eax;
540
swissChiliddc97542021-07-04 11:47:42 -0700541 // The capture offset
542 | push (var->number);
swissChili74348422021-07-04 13:23:24 -0700543 | mov ebx, (set_closure_capture_variable);
swissChiliddc97542021-07-04 11:47:42 -0700544 | call ebx;
545 // Skip the value and index
546 | add esp, 8;
547 // Pop the closure back in to eax
548 | pop eax;
549 }
550 }
551
552 // Closure is still in eax
553
554 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700555 del_local(&new_local);
swissChiliddc97542021-07-04 11:47:42 -0700556 }
swissChili53472e82021-05-08 16:06:32 -0700557 else
558 {
swissChili74348422021-07-04 13:23:24 -0700559 char *name = (char *)(fsym ^ SYMBOL_TAG);
560 struct function *func = find_function(env, name);
561
562 bool is_recursive = false;
swissChili15f1cae2021-07-05 19:08:47 -0700563 struct args *nargs_needed = NULL;
swissChili53472e82021-05-08 16:06:32 -0700564
swissChili74348422021-07-04 13:23:24 -0700565 if (symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700566 {
swissChili74348422021-07-04 13:23:24 -0700567 is_recursive = true;
swissChili15f1cae2021-07-05 19:08:47 -0700568 nargs_needed = local->args;
swissChili74348422021-07-04 13:23:24 -0700569 }
570 else
571 {
572 if (func == NULL)
573 {
574 fprintf(stderr, "Function call: %s at %s:%d\n", name, cons_file(val), cons_line(val));
575 err("Function undefined");
576 }
577
swissChili15f1cae2021-07-05 19:08:47 -0700578 nargs_needed = func->args;
swissChili74348422021-07-04 13:23:24 -0700579 }
580
swissChili15f1cae2021-07-05 19:08:47 -0700581 if (!are_args_acceptable(nargs_needed, nargs))
swissChili74348422021-07-04 13:23:24 -0700582 {
583 fprintf(stderr, "Function call: %s at %s:%d, want %d args but given %d\n",
swissChili15f1cae2021-07-05 19:08:47 -0700584 name, cons_file(val), cons_line(val), nargs_needed->num_required, nargs);
swissChili53472e82021-05-08 16:06:32 -0700585 err("wrong number of args");
swissChilif1ba8c12021-07-02 18:45:38 -0700586 }
swissChili53472e82021-05-08 16:06:32 -0700587
swissChili74348422021-07-04 13:23:24 -0700588 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700589 {
swissChili15f1cae2021-07-05 19:08:47 -0700590 int nargs = length(args);
591
592 if (nargs <= nargs_needed->num_required)
593 {
594 // Push the variadic list (nil)
595 | push (nil);
596 }
597
598 for (int i = nargs_needed->num_optional - 1; i >= nargs - nargs_needed->num_required; i--)
599 {
600 // Push the default optional values
601 | push (nargs_needed->optional_arguments[i].value);
602 }
603
604 for (int i = nargs - 1; i >= 0; i--)
swissChili2999dd12021-07-02 14:19:53 -0700605 {
606 compile_expression(env, local, elt(args, i), Dst);
607 | push eax;
608 }
swissChili15f1cae2021-07-05 19:08:47 -0700609
swissChili74348422021-07-04 13:23:24 -0700610 if (is_recursive)
611 {
612 | call ->function_start;
613 }
614 else
615 {
616 | mov ebx, (func->code_addr);
617 | call ebx;
618 }
swissChili2999dd12021-07-02 14:19:53 -0700619 | add esp, (nargs * value_size);
620 // result in eax
621 }
622 else if (func->namespace == NS_MACRO)
623 {
swissChilif68671f2021-07-05 14:14:44 -0700624 // Make sure that the stuff allocated by the macro isn't in a pool
625 unsigned char pool = push_pool(0);
626
swissChili2999dd12021-07-02 14:19:53 -0700627 value_t expanded_to = call_list(func, args);
628
swissChilif68671f2021-07-05 14:14:44 -0700629 pop_pool(pool);
630
swissChili2999dd12021-07-02 14:19:53 -0700631 compile_expression(env, local, expanded_to, Dst);
632 }
swissChili53472e82021-05-08 16:06:32 -0700633 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700634 }
swissChili923b5362021-05-09 20:31:43 -0700635 else if (symbolp(val))
636 {
swissChili923b5362021-05-09 20:31:43 -0700637 struct variable *v = find_variable(local, (char *)(val ^ SYMBOL_TAG));
638
639 if (!v)
swissChilie9fec8b2021-06-22 13:59:33 -0700640 {
641 fprintf(stderr, "var: %s\n", (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700642 err("Variable unbound");
swissChilie9fec8b2021-06-22 13:59:33 -0700643 }
swissChili923b5362021-05-09 20:31:43 -0700644
swissChiliddc97542021-07-04 11:47:42 -0700645 compile_variable(v, Dst);
swissChili923b5362021-05-09 20:31:43 -0700646 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700647}
swissChilif3e7f182021-04-20 13:57:22 -0700648
swissChili53472e82021-05-08 16:06:32 -0700649void compile_expr_to_func(struct environment *env, char *name, value_t val,
650 dasm_State **Dst)
swissChilif3e7f182021-04-20 13:57:22 -0700651{
652 | setup 0;
653
654 struct local local;
swissChili53472e82021-05-08 16:06:32 -0700655 compile_expression(env, &local, val, Dst);
656
swissChilif3e7f182021-04-20 13:57:22 -0700657 | cleanup;
658
swissChilif68671f2021-07-05 14:14:44 -0700659 add_function(env, name, link_program(Dst), 0, NS_FUNCTION);
swissChilif3e7f182021-04-20 13:57:22 -0700660}
swissChili923b5362021-05-09 20:31:43 -0700661
662struct variable *add_variable(struct local *local, enum var_type type,
663 char *name, int number)
664{
665 struct variable *var = malloc(sizeof(struct variable));
666 var->prev = local->first;
667 var->type = type;
668 var->name = name;
669 var->number = number;
670
671 local->first = var;
672
673 return var;
674}
675
676void destroy_local(struct local *local)
677{
678 for (struct variable *v = local->first; v;)
679 {
680 struct variable *t = v;
681 v = v->prev;
682 free(t);
683 }
684}
685
686struct variable *find_variable(struct local *local, char *name)
687{
688 struct variable *v = local->first;
689
690 for (; v && strcmp(v->name, name) != 0; v = v->prev)
691 {}
692
swissChiliddc97542021-07-04 11:47:42 -0700693 if (!v)
694 {
695 if (local->parent)
696 {
697 v = find_variable(local->parent, name);
698
699 if (v)
700 {
swissChili15f1cae2021-07-05 19:08:47 -0700701 // We found this in a parent scope, add it as a V_FREE variable
702 // to skip the search.
swissChiliddc97542021-07-04 11:47:42 -0700703 v = add_variable(local, V_FREE, name, local->num_closure_slots++);
704 }
705 }
706 }
swissChili923b5362021-05-09 20:31:43 -0700707 return v;
708}
swissChili2999dd12021-07-02 14:19:53 -0700709
swissChiliddc97542021-07-04 11:47:42 -0700710extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -0700711
swissChili15f1cae2021-07-05 19:08:47 -0700712value_t call_list_args(void *code_ptr, struct args *args, value_t list, void *data)
swissChili2999dd12021-07-02 14:19:53 -0700713{
swissChili15f1cae2021-07-05 19:08:47 -0700714 list = deep_copy(list);
715 int nargs = length(list);
716
717 value_t *val = NULL;
718
719 for (value_t i = list; !nilp(i); i = cdr(i))
720 {
721 val = cdrref(i);
722 }
723
724 int total_required = args->num_required + args->num_optional;
725
726 if (nargs > total_required)
727 {
728 // Take the remainder of the list and put it as the last item in the
729 // list.
730 value_t trailing = cxdr(list, total_required);
731 value_t last_item = cons(trailing, nil);
732
733 *cxdrref(&list, total_required) = last_item;
734 }
735 else if (nargs < total_required)
736 {
737 for (int i = nargs - args->num_required; i < args->num_optional; i++)
738 {
739 // Append the i-th defualt argument
740 value_t appended = cons(args->optional_arguments[i].value, nil);
741 *val = appended;
742 val = cdrref(appended);
743 }
744 }
745
746 // We want to call this if we pass the correct # of arguments or less, just
747 // not if we have already passed varargs. Appends a nil argument.
748 if (nargs <= total_required)
749 {
750 // Enough real arguments but no variadic arguments. Pass a nil list.
751 *val = cons(nil, nil);
752 }
753
754 return _call_list(code_ptr, list, data);
755}
756
757value_t call_list(struct function *fun, value_t list)
758{
759 return call_list_args(fun->code_ptr, fun->args, list, NULL);
swissChiliddc97542021-07-04 11:47:42 -0700760}
761
762value_t call_list_closure(struct closure *c, value_t list)
763{
swissChili15f1cae2021-07-05 19:08:47 -0700764 return call_list_args(c->function, c->args, list, c->data);
765}
766
767struct args *new_args()
768{
769 struct args *a = malloc(sizeof(struct args));
770 a->num_optional = 0;
771 a->num_required = 0;
772 a->variadic = false;
773
774 return a;
775}
776
777struct args *add_optional_arg(struct args *args, value_t name,
778 value_t value)
779{
780 int i = args->num_optional++;
781 args = realloc(args, sizeof(struct args) +
782 sizeof(struct optional_argument) * args->num_optional);
783
784 args->optional_arguments[i] = (struct optional_argument)
785 {
786 .value = value ,
787 .name = name,
788 };
789
790 return args;
791}
792
793bool are_args_acceptable(struct args *args, int number)
794{
795 if (args->variadic)
796 {
797 return number >= args->num_required;
798 }
799 else
800 {
801 return number >= args->num_required &&
802 number <= args->num_required + args->num_optional;
803 }
804}
805
806struct args *list_to_args(struct environment *env, value_t list, struct local *local)
807{
808 struct args *args = new_args();
809
810 bool in_optional = false;
811
812 for (value_t i = list; !nilp(i); i = cdr(i))
813 {
814 value_t val = car(i);
815 if (symbolp(val))
816 {
817 if (!args->variadic && symstreq(val, "&"))
818 {
819 i = cdr(i);
820 value_t name = car(i);
821
822 if (!symbolp(name))
823 {
824 err("You must provide a symbol after & in an argument list to bind the\n"
825 "variadic arguments to.");
826 }
827
828 args->variadic = true;
829
830 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
831 args->num_optional + args->num_required);
832
833 continue;
834 }
835
836 if (!in_optional)
837 {
838 add_variable(local, V_ARGUMENT, (char *)(val ^ SYMBOL_TAG), args->num_required++);
839 }
840 else
841 {
842 char *name = (char *)(val ^ SYMBOL_TAG);
843 if (name[0] == '&')
844 {
845 err("Non-optional argument following optional arguments starts with a &\n"
846 "did you mean to declare a variadic argument? If so leave a space\n"
847 "between the & and name.");
848 }
849 else
850 {
851 err("Cannot define a non-optional argument after an optional one.");
852 }
853 }
854 }
855 else if (listp(val))
856 {
857 in_optional = true;
858 int len = length(val);
859
860 if (len != 2)
861 {
862 err("A list defining an optional value must be structured like (name expr)\n"
863 "with exactly two arguments.");
864 }
865
866 value_t name = car(val);
867 value_t expr = car(cdr(val));
868
869 value_t function = cons(nil, cons(expr, nil));
870
871 dasm_State *d = compile_function(function, NS_ANONYMOUS, env, NULL, NULL, NULL, NULL);
872
873 // TODO: GC stack top!
874 value_t (*compiled)() = link_program(&d);
875
876 value_t value = compiled();
877 args = add_optional_arg(args, name, value);
878
879 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG), args->num_required + args->num_optional - 1);
880 }
881 }
882
883 return args;
884}
885
886void display_args(struct args *args)
887{
888 printf("Args object taking %d require arguments and %d optionals:\n",
889 args->num_required, args->num_optional);
890
891 for (int i = 0; i < args->num_optional; i++)
892 {
893 printf(" %d\t%s\n", i, (char *)(args->optional_arguments[i].name ^ SYMBOL_TAG));
894 printval(args->optional_arguments[i].value, 2);
895 }
swissChili2999dd12021-07-02 14:19:53 -0700896}