blob: 280796723c82ac89473445cd0c5f6fd92f783618 [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,
swissChili74348422021-07-04 13:23:24 -0700129 struct local *local_parent, int *nargs, char *name)
swissChilif1ba8c12021-07-02 18:45:38 -0700130{
131 dasm_State *d;
132 dasm_State **Dst = &d;
133
134 |.section code;
135 dasm_init(&d, DASM_MAXSECTION);
136
137 |.globals lbl_;
138 void *labels[lbl__MAX];
139 dasm_setupglobal(&d, labels, lbl__MAX);
140
141 |.actionlist lisp_actions;
142 dasm_setup(&d, lisp_actions);
143
144 struct local local;
145 local.parent = NULL;
146 local.first = NULL;
147 local.num_vars = 0;
148 local.npc = 8;
149 local.nextpc = 0;
150 local.stack_slots = malloc(sizeof(bool) * 4);
151 memset(local.stack_slots, 0, sizeof(bool) * 4);
152 local.num_stack_slots = 4;
153 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700154 local.num_closure_slots = 0;
155 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700156 local.current_function_name = name;
swissChilif1ba8c12021-07-02 18:45:38 -0700157
158 dasm_growpc(&d, local.npc);
159
swissChilif1ba8c12021-07-02 18:45:38 -0700160 value_t arglist = car(args);
161 value_t body = cdr(args);
162
swissChili74348422021-07-04 13:23:24 -0700163 local.num_args = length(arglist);
164
swissChilif1ba8c12021-07-02 18:45:38 -0700165 value_t a = arglist;
166 for (int i = 0; !nilp(a); a = cdr(a), i++)
167 {
168 if (!symbolp(car(a)))
169 {
170 err("defun argument must be a symbol");
171 }
172
173 add_variable(&local, V_ARGUMENT, (char *)(car(a) ^ SYMBOL_TAG), i);
174 }
175
176 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
177 {
178 walk_and_alloc(&local, car(body_));
179 }
180
181 | setup (local.num_stack_entries);
182
183 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
184 local.num_stack_entries = 0;
185
186 for (; !nilp(body); body = cdr(body))
187 {
188 compile_expression(env, &local, car(body), Dst);
189 }
190
191 | cleanup;
192
193 if (local_out)
194 *local_out = local;
195
196 if (nargs)
197 *nargs = length(arglist);
198
199 return d;
200}
201
swissChili53472e82021-05-08 16:06:32 -0700202void compile_tl(value_t val, struct environment *env)
swissChilica107a02021-04-14 12:07:30 -0700203{
swissChili53472e82021-05-08 16:06:32 -0700204 if (!listp(val))
205 err("Top level must be a list");
swissChilica107a02021-04-14 12:07:30 -0700206
swissChili53472e82021-05-08 16:06:32 -0700207 value_t form = car(val);
208 value_t args = cdr(val);
209
swissChili2999dd12021-07-02 14:19:53 -0700210 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700211 {
swissChili2999dd12021-07-02 14:19:53 -0700212 enum namespace namespace = NS_FUNCTION;
213
214 if (symstreq(form, "defmacro"))
215 namespace = NS_MACRO;
216
swissChili8fc5e2f2021-04-22 13:45:10 -0700217 struct local local;
swissChilif1ba8c12021-07-02 18:45:38 -0700218 int nargs;
swissChili74348422021-07-04 13:23:24 -0700219 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChilif68671f2021-07-05 14:14:44 -0700220
swissChili74348422021-07-04 13:23:24 -0700221 dasm_State *d = compile_function(cdr(args), namespace, env, &local, NULL, &nargs, name);
swissChilia820dea2021-05-09 16:46:55 -0700222
swissChilif68671f2021-07-05 14:14:44 -0700223 add_function(env, name, link_program(&d),
swissChilif1ba8c12021-07-02 18:45:38 -0700224 nargs, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700225
swissChili53472e82021-05-08 16:06:32 -0700226 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700227 del_local(&local);
swissChili67bdf282021-06-06 18:46:08 -0700228 }
swissChilif68671f2021-07-05 14:14:44 -0700229 else if (symstreq(form, "progn"))
230 {
231 for (value_t val = args; !nilp(val); val = cdr(val))
232 {
233 compile_tl(car(val), env);
234 }
235 }
swissChili67bdf282021-06-06 18:46:08 -0700236}
237
238void walk_and_alloc(struct local *local, value_t body)
239{
240 if (!listp(body))
241 return;
242
243 value_t args = cdr(body);
244
245 if (symstreq(car(body), "let1"))
246 {
247 int slot = local_alloc(local);
248
249 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700250 for (; !nilp(expr); expr = cdr(expr))
251 {
swissChiliddc97542021-07-04 11:47:42 -0700252 walk_and_alloc(local, car(expr));
swissChilif1ba8c12021-07-02 18:45:38 -0700253 }
swissChili67bdf282021-06-06 18:46:08 -0700254
255 local_free(local, slot);
256 }
swissChilif1ba8c12021-07-02 18:45:38 -0700257 else if (symstreq(car(body), "lambda"))
258 {
259 // We don't want to walk the lambda because it's another function. When
260 // the lambda is compiled it will be walked.
261 return;
262 }
swissChili67bdf282021-06-06 18:46:08 -0700263 else
264 {
265 for (; !nilp(args); args = cdr(args))
266 {
267 walk_and_alloc(local, car(args));
268 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700269 }
270}
271
swissChilif68671f2021-07-05 14:14:44 -0700272bool load(struct environment *env, char *path)
swissChili8fc5e2f2021-04-22 13:45:10 -0700273{
swissChilif68671f2021-07-05 14:14:44 -0700274 if (!file_exists(path))
275 return false;
276
277 add_load(env, path);
278
swissChilib8fd4712021-06-23 15:32:04 -0700279 unsigned char pool = make_pool();
280 unsigned char pop = push_pool(pool);
281
swissChilif68671f2021-07-05 14:14:44 -0700282 struct istream *is = new_fistream(path, false);
283 if (!is)
284 return false;
285
swissChili8fc5e2f2021-04-22 13:45:10 -0700286 value_t val;
swissChili53472e82021-05-08 16:06:32 -0700287
288 while (read1(is, &val))
swissChili8fc5e2f2021-04-22 13:45:10 -0700289 {
swissChilif68671f2021-07-05 14:14:44 -0700290 compile_tl(val, env);
swissChili8fc5e2f2021-04-22 13:45:10 -0700291 }
swissChilif3e7f182021-04-20 13:57:22 -0700292
swissChilif68671f2021-07-05 14:14:44 -0700293 del_fistream(is);
swissChilib8fd4712021-06-23 15:32:04 -0700294 pop_pool(pop);
295
swissChilif68671f2021-07-05 14:14:44 -0700296 return true;
297}
298
299struct environment compile_file(char *filename, bool *ok)
300{
301 value_t val;
302 struct environment env;
303 env.first = NULL;
304 env.first_loaded = NULL;
305
306 add_load(&env, filename);
307 load_std(&env);
308
309 bool ok_ = load(&env, filename);
310
311 if (ok)
312 *ok = ok_;
313
swissChili8fc5e2f2021-04-22 13:45:10 -0700314 return env;
swissChilica107a02021-04-14 12:07:30 -0700315}
swissChilib3ca4fb2021-04-20 10:33:00 -0700316
swissChili53472e82021-05-08 16:06:32 -0700317int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700318{
swissChili53472e82021-05-08 16:06:32 -0700319 int n = local->nextpc++;
320 if (n > local->npc)
321 {
322 local->npc += 16;
323 dasm_growpc(Dst, local->npc);
324 }
325 return n;
326}
327
swissChili6b47b6d2021-06-30 22:08:55 -0700328void compile_backquote(struct environment *env, struct local *local,
329 value_t val, dasm_State **Dst)
330{
331 if (!listp(val))
332 {
333 | mov eax, (val);
334 }
335 else
336 {
337 value_t fsym = car(val),
338 args = cdr(val);
339 int nargs = length(args);
340
341 // TODO
342 }
343}
344
swissChiliddc97542021-07-04 11:47:42 -0700345void compile_variable(struct variable *v, dasm_State *Dst)
346{
347 switch (v->type)
348 {
349 case V_ARGUMENT:
350 | mov eax, dword [ebp + (value_size * (v->number + 2))];
351 break;
352 case V_BOUND:
353 | mov eax, dword [ebp - ((v->number + 1) * value_size)];
354 break;
355 case V_FREE:
356 // edi is the closure context pointer
357 | mov eax, dword [edi + (v->number * value_size)];
358 break;
359 default:
360 err("Sorry, can only access V_ARGUMENT, V_FREE and V_BOUND variables for now :(");
361 }
362}
363
swissChili53472e82021-05-08 16:06:32 -0700364void compile_expression(struct environment *env, struct local *local,
365 value_t val, dasm_State **Dst)
366{
367 if (symstreq(val, "nil"))
368 {
369 | mov eax, (nil);
370 }
swissChili923b5362021-05-09 20:31:43 -0700371 else if (symstreq(val, "t"))
372 {
373 | mov eax, (t);
374 }
375 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700376 {
377 | mov eax, val;
378 }
swissChili53472e82021-05-08 16:06:32 -0700379 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700380 {
swissChili53472e82021-05-08 16:06:32 -0700381 value_t fsym = car(val);
382 value_t args = cdr(val);
383 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700384
swissChili53472e82021-05-08 16:06:32 -0700385 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700386 {
swissChili53472e82021-05-08 16:06:32 -0700387 err("function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700388 }
389
swissChili53472e82021-05-08 16:06:32 -0700390 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700391 {
swissChili53472e82021-05-08 16:06:32 -0700392 if (nargs < 2 || nargs > 3)
393 err("Must give at least 2 arguments to if");
swissChilib3ca4fb2021-04-20 10:33:00 -0700394
swissChili53472e82021-05-08 16:06:32 -0700395 compile_expression(env, local, car(args), Dst);
396 int false_label = nextpc(local, Dst),
397 after_label = nextpc(local, Dst);
398
399 // result is in eax
400 | cmp eax, (nil);
401 | je =>false_label;
402
403 compile_expression(env, local, elt(args, 1), Dst);
swissChilia820dea2021-05-09 16:46:55 -0700404 | jmp =>after_label;
swissChili923b5362021-05-09 20:31:43 -0700405 |=>false_label:;
swissChili53472e82021-05-08 16:06:32 -0700406 if (nargs == 3)
407 compile_expression(env, local, elt(args, 2), Dst);
408 |=>after_label:
409 }
swissChilif68671f2021-07-05 14:14:44 -0700410 else if (symstreq(fsym, "progn"))
411 {
412 for (value_t val = args; !nilp(val); val = cdr(val))
413 {
414 compile_expression(env, local, car(val), Dst);
415 }
416 }
swissChili67bdf282021-06-06 18:46:08 -0700417 else if (symstreq(fsym, "let1"))
418 {
419 if (nargs < 2)
420 {
421 err("Must give at least 2 arguments to let1");
422 }
423 value_t binding = car(args);
424 value_t rest = cdr(args);
425
426 if (length(binding) != 2)
427 {
428 err("Binding list in let1 must contain exactly two entries");
429 }
430
431 value_t name = car(binding);
432 value_t value = car(cdr(binding));
433
434 compile_expression(env, local, value, Dst);
435
436 int i = local_alloc(local);
437
438 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
439
440 | mov dword [ebp - ((i + 1) * value_size)], eax;
441
442 for (; !nilp(rest); rest = cdr(rest))
443 {
444 compile_expression(env, local, car(rest), Dst);
445 }
446
447 local_free(local, i);
448 }
swissChilie9fec8b2021-06-22 13:59:33 -0700449 else if (symstreq(fsym, "gc"))
450 {
451 if (nargs)
452 {
453 err("gc takes no arguments");
454 }
455
456 | run_gc;
457 }
swissChili6b47b6d2021-06-30 22:08:55 -0700458 else if (symstreq(fsym, "quote"))
459 {
460 if (nargs != 1)
461 err("quote should take exactly 1 argument");
462
463 // Simple!
464 | mov eax, (car(args));
465 }
466 else if (symstreq(fsym, "backquote"))
467 {
468 if (nargs != 1)
469 err("backquote should take exactly 1 argument");
470
471 compile_backquote(env, local, car(args), Dst);
472 }
swissChili74348422021-07-04 13:23:24 -0700473 else if (symstreq(fsym, "function"))
474 {
475 if (nargs != 1)
476 {
477 err("function should take exactly 1 argument");
478 }
479
480 if (!symbolp(car(args)))
481 {
482 err("argument to function should be a symbol resolvable at compile time");
483 }
484
485 struct function *f = find_function(env, (char *)(car(args) ^ SYMBOL_TAG));
486 value_t closure = create_closure(f->code_ptr, f->nargs, 0);
487
488 | mov eax, (closure);
489 }
swissChili6b47b6d2021-06-30 22:08:55 -0700490 else if (symstreq(fsym, "list"))
491 {
492 | push (nil);
493
494 for (int i = nargs - 1; i >= 0; i--)
495 {
496 compile_expression(env, local, elt(args, i), Dst);
497
498 // push the ith item
499 | push eax;
500 // cons the top two stack items
501 | mov ebx, (cons);
502 | call ebx;
503 // remove the stack items from use
504 | add esp, (2 * value_size);
505 // put the new thing on the stack
506 | push eax;
507 }
508
509 | pop eax;
510 }
swissChiliddc97542021-07-04 11:47:42 -0700511 else if (symstreq(fsym, "lambda"))
512 {
513 // Compile the function with this as the parent scope
514 struct local new_local;
515 int nargs_out;
swissChili74348422021-07-04 13:23:24 -0700516 dasm_State *d = compile_function(args, NS_ANONYMOUS, env, &new_local, local, &nargs_out, "recurse");
swissChiliddc97542021-07-04 11:47:42 -0700517
518 // Link the function
swissChilif68671f2021-07-05 14:14:44 -0700519 void *func_ptr = link_program(&d);
swissChiliddc97542021-07-04 11:47:42 -0700520
521 // Create a closure object with the correct number of captures at
522 // runtime
swissChiliddc97542021-07-04 11:47:42 -0700523 | push (new_local.num_closure_slots);
524 | push (nargs_out);
525 | push (func_ptr);
swissChili74348422021-07-04 13:23:24 -0700526 | mov ebx, (create_closure);
swissChiliddc97542021-07-04 11:47:42 -0700527 | call ebx;
528 | add esp, 12;
529
530 // Walk the generated local scope for V_FREE variables, since each
531 // of these exists in our scope (or higher), evaluate it and set it
532 // as a member of the lambda capture.
533
534 for (struct variable *var = new_local.first; var; var = var->prev)
535 {
536 if (var->type == V_FREE)
537 {
538 // Closure in eax
539 | push eax;
540 // Variable now in eax
541 compile_variable(find_variable(local, var->name), Dst);
542 | push eax;
543
swissChiliddc97542021-07-04 11:47:42 -0700544 // The capture offset
545 | push (var->number);
swissChili74348422021-07-04 13:23:24 -0700546 | mov ebx, (set_closure_capture_variable);
swissChiliddc97542021-07-04 11:47:42 -0700547 | call ebx;
548 // Skip the value and index
549 | add esp, 8;
550 // Pop the closure back in to eax
551 | pop eax;
552 }
553 }
554
555 // Closure is still in eax
556
557 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700558 del_local(&new_local);
swissChiliddc97542021-07-04 11:47:42 -0700559 }
swissChili53472e82021-05-08 16:06:32 -0700560 else
561 {
swissChili74348422021-07-04 13:23:24 -0700562 char *name = (char *)(fsym ^ SYMBOL_TAG);
563 struct function *func = find_function(env, name);
564
565 bool is_recursive = false;
566 int nargs_needed = 0;
swissChili53472e82021-05-08 16:06:32 -0700567
swissChili74348422021-07-04 13:23:24 -0700568 if (symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700569 {
swissChili74348422021-07-04 13:23:24 -0700570 is_recursive = true;
571 nargs_needed = local->num_args;
572 }
573 else
574 {
575 if (func == NULL)
576 {
577 fprintf(stderr, "Function call: %s at %s:%d\n", name, cons_file(val), cons_line(val));
578 err("Function undefined");
579 }
580
581 nargs_needed = func->nargs;
582 }
583
584 if (nargs != nargs_needed)
585 {
586 fprintf(stderr, "Function call: %s at %s:%d, want %d args but given %d\n",
587 name, cons_file(val), cons_line(val), nargs_needed, nargs);
swissChili53472e82021-05-08 16:06:32 -0700588 err("wrong number of args");
swissChilif1ba8c12021-07-02 18:45:38 -0700589 }
swissChili53472e82021-05-08 16:06:32 -0700590
swissChili74348422021-07-04 13:23:24 -0700591 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700592 {
swissChili2999dd12021-07-02 14:19:53 -0700593 for (int i = length(args) - 1; i >= 0; i--)
594 {
595 compile_expression(env, local, elt(args, i), Dst);
596 | push eax;
597 }
swissChili74348422021-07-04 13:23:24 -0700598
599 if (is_recursive)
600 {
601 | call ->function_start;
602 }
603 else
604 {
605 | mov ebx, (func->code_addr);
606 | call ebx;
607 }
swissChili2999dd12021-07-02 14:19:53 -0700608 | add esp, (nargs * value_size);
609 // result in eax
610 }
611 else if (func->namespace == NS_MACRO)
612 {
swissChilif68671f2021-07-05 14:14:44 -0700613 // Make sure that the stuff allocated by the macro isn't in a pool
614 unsigned char pool = push_pool(0);
615
swissChili2999dd12021-07-02 14:19:53 -0700616 value_t expanded_to = call_list(func, args);
617
swissChilif68671f2021-07-05 14:14:44 -0700618 pop_pool(pool);
619
swissChili2999dd12021-07-02 14:19:53 -0700620 compile_expression(env, local, expanded_to, Dst);
621 }
swissChili53472e82021-05-08 16:06:32 -0700622 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700623 }
swissChili923b5362021-05-09 20:31:43 -0700624 else if (symbolp(val))
625 {
swissChili923b5362021-05-09 20:31:43 -0700626 struct variable *v = find_variable(local, (char *)(val ^ SYMBOL_TAG));
627
628 if (!v)
swissChilie9fec8b2021-06-22 13:59:33 -0700629 {
630 fprintf(stderr, "var: %s\n", (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700631 err("Variable unbound");
swissChilie9fec8b2021-06-22 13:59:33 -0700632 }
swissChili923b5362021-05-09 20:31:43 -0700633
swissChiliddc97542021-07-04 11:47:42 -0700634 compile_variable(v, Dst);
swissChili923b5362021-05-09 20:31:43 -0700635 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700636}
swissChilif3e7f182021-04-20 13:57:22 -0700637
swissChili53472e82021-05-08 16:06:32 -0700638void compile_expr_to_func(struct environment *env, char *name, value_t val,
639 dasm_State **Dst)
swissChilif3e7f182021-04-20 13:57:22 -0700640{
641 | setup 0;
642
643 struct local local;
swissChili53472e82021-05-08 16:06:32 -0700644 compile_expression(env, &local, val, Dst);
645
swissChilif3e7f182021-04-20 13:57:22 -0700646 | cleanup;
647
swissChilif68671f2021-07-05 14:14:44 -0700648 add_function(env, name, link_program(Dst), 0, NS_FUNCTION);
swissChilif3e7f182021-04-20 13:57:22 -0700649}
swissChili923b5362021-05-09 20:31:43 -0700650
651struct variable *add_variable(struct local *local, enum var_type type,
652 char *name, int number)
653{
654 struct variable *var = malloc(sizeof(struct variable));
655 var->prev = local->first;
656 var->type = type;
657 var->name = name;
658 var->number = number;
659
660 local->first = var;
661
662 return var;
663}
664
665void destroy_local(struct local *local)
666{
667 for (struct variable *v = local->first; v;)
668 {
669 struct variable *t = v;
670 v = v->prev;
671 free(t);
672 }
673}
674
675struct variable *find_variable(struct local *local, char *name)
676{
677 struct variable *v = local->first;
678
679 for (; v && strcmp(v->name, name) != 0; v = v->prev)
680 {}
681
swissChiliddc97542021-07-04 11:47:42 -0700682 if (!v)
683 {
684 if (local->parent)
685 {
686 v = find_variable(local->parent, name);
687
688 if (v)
689 {
690 // We found this in a parent scope, add it as a V_FREE variable to skip the search.
691 v = add_variable(local, V_FREE, name, local->num_closure_slots++);
692 }
693 }
694 }
swissChili923b5362021-05-09 20:31:43 -0700695 return v;
696}
swissChili2999dd12021-07-02 14:19:53 -0700697
swissChiliddc97542021-07-04 11:47:42 -0700698extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -0700699
700value_t call_list(struct function *func, value_t list)
701{
swissChiliddc97542021-07-04 11:47:42 -0700702 return _call_list(func->code_ptr, list, NULL);
703}
704
705value_t call_list_closure(struct closure *c, value_t list)
706{
707 return _call_list(c->function, list, c->data);
swissChili2999dd12021-07-02 14:19:53 -0700708}