blob: 668d59a9763e8e61593371166205d8984f10b072 [file] [log] [blame]
swissChili8cfb7c42021-04-18 21:17:58 -07001/* -*- mode:c -*- */
2
swissChilica107a02021-04-14 12:07:30 -07003#include "compiler.h"
swissChiliddc97542021-07-04 11:47:42 -07004#include "gc.h"
swissChili7e1393c2021-07-07 12:59:12 -07005#include "lib/std.h"
6#include "lisp.h"
7#include "plat/plat.h"
swissChilica107a02021-04-14 12:07:30 -07008
9#include <dasm_proto.h>
10#include <dasm_x86.h>
11
swissChili7e1393c2021-07-07 12:59:12 -070012#include <libgen.h>
13#include <stdio.h>
swissChili923b5362021-05-09 20:31:43 -070014#include <stdlib.h>
15#include <string.h>
16
swissChili53472e82021-05-08 16:06:32 -070017#define value_size sizeof(value_t)
swissChilica107a02021-04-14 12:07:30 -070018
19|.arch x86;
20
21|.macro setup, nvars;
swissChili7e1393c2021-07-07 12:59:12 -070022|->function_start : | push ebp;
swissChilica107a02021-04-14 12:07:30 -070023| mov ebp, esp;
swissChili8cfb7c42021-04-18 21:17:58 -070024| sub esp, (value_size * nvars);
swissChilica107a02021-04-14 12:07:30 -070025|.endmacro;
26
27|.macro cleanup;
28| mov esp, ebp;
29| pop ebp;
30| ret;
31|.endmacro;
32
swissChili67bdf282021-06-06 18:46:08 -070033|.macro local_var, index;
34|.endmacro;
35
swissChilica107a02021-04-14 12:07:30 -070036dasm_State *d;
37unsigned int npc = 8;
38
swissChili9e57da42021-06-15 22:22:46 -070039|.macro run_gc;
swissChilie9fec8b2021-06-22 13:59:33 -070040| mov eax, esp;
swissChili9e57da42021-06-15 22:22:46 -070041| push ebp;
swissChilie9fec8b2021-06-22 13:59:33 -070042| push eax;
swissChili9e57da42021-06-15 22:22:46 -070043| mov eax, _do_gc;
44| call eax;
45|.endmacro;
swissChili6d6525e2021-06-15 21:20:53 -070046
swissChili53472e82021-05-08 16:06:32 -070047struct function *find_function(struct environment *env, char *name)
swissChilica107a02021-04-14 12:07:30 -070048{
swissChilif68671f2021-07-05 14:14:44 -070049 struct function *f;
swissChilica107a02021-04-14 12:07:30 -070050
swissChilif68671f2021-07-05 14:14:44 -070051 for (f = env->first; f && strcmp(f->name, name); f = f->prev)
swissChilica107a02021-04-14 12:07:30 -070052 {
swissChilica107a02021-04-14 12:07:30 -070053 }
54
55 return f;
56}
57
swissChili67bdf282021-06-06 18:46:08 -070058unsigned int local_alloc(struct local *local)
59{
60 for (int i = 0; i < local->num_stack_slots; i++)
61 {
62 if (local->stack_slots[i] == false)
63 {
64 local->stack_slots[i] = true;
65
66 if (i >= local->num_stack_entries)
67 local->num_stack_entries++;
68
69 return i;
70 }
71 }
72
73 int old_size = local->num_stack_slots;
74 local->num_stack_slots += 4;
swissChili7e1393c2021-07-07 12:59:12 -070075 local->stack_slots =
76 realloc(local->stack_slots, local->num_stack_slots * sizeof(bool));
swissChili67bdf282021-06-06 18:46:08 -070077 // unreadable: set the remaining slots to unused
78 memset(local->stack_slots + old_size, 0, local->num_stack_slots - old_size);
79 local->stack_slots[old_size] = true;
80
81 return old_size;
82}
83
84void local_free(struct local *local, unsigned int slot)
85{
86 local->stack_slots[slot] = false;
87}
88
swissChili708d4c42021-07-04 17:40:07 -070089void del_local(struct local *local)
90{
91 free(local->stack_slots);
92
93 for (struct variable *next, *f = local->first; f; f = next)
94 {
95 next = f->prev;
96 free(f);
97 }
98}
99
100void del_env(struct environment *env)
101{
102 for (struct function *next, *f = env->first; f; f = next)
103 {
104 next = f->prev;
105 // We're not gonna bother munmap()ing the function
106 free(f);
107 }
swissChilif68671f2021-07-05 14:14:44 -0700108
109 for (struct loaded_file *next, *l = env->first_loaded; l; l = next)
110 {
111 next = l->previous;
112 free(l->resolved_path);
113 free(l);
114 }
swissChili7e1393c2021-07-07 12:59:12 -0700115
116 free(env);
swissChilif68671f2021-07-05 14:14:44 -0700117}
118
119void add_load(struct environment *env, char *path)
120{
121 static char buffer[512];
122 long size = readlink(path, buffer, 512);
123 buffer[size] = '\0';
124 char *resolved = strdup(buffer);
125
126 struct loaded_file *f = malloc(sizeof(struct loaded_file));
127 f->resolved_path = resolved;
128 f->previous = env->first_loaded;
129 env->first_loaded = f;
swissChili708d4c42021-07-04 17:40:07 -0700130}
131
swissChilif1ba8c12021-07-02 18:45:38 -0700132struct dasm_State *compile_function(value_t args, enum namespace namespace,
swissChili7e1393c2021-07-07 12:59:12 -0700133 struct environment *env,
134 struct local *local_out,
135 struct local *local_parent,
136 struct args **args_out, char *name,
137 char *path)
swissChilif1ba8c12021-07-02 18:45:38 -0700138{
139 dasm_State *d;
140 dasm_State **Dst = &d;
141
142 |.section code;
143 dasm_init(&d, DASM_MAXSECTION);
144
145 |.globals lbl_;
146 void *labels[lbl__MAX];
147 dasm_setupglobal(&d, labels, lbl__MAX);
148
149 |.actionlist lisp_actions;
150 dasm_setup(&d, lisp_actions);
151
152 struct local local;
153 local.parent = NULL;
154 local.first = NULL;
155 local.num_vars = 0;
156 local.npc = 8;
157 local.nextpc = 0;
158 local.stack_slots = malloc(sizeof(bool) * 4);
159 memset(local.stack_slots, 0, sizeof(bool) * 4);
160 local.num_stack_slots = 4;
161 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700162 local.num_closure_slots = 0;
163 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700164 local.current_function_name = name;
swissChili7e1393c2021-07-07 12:59:12 -0700165 local.current_file_path = path;
swissChilif1ba8c12021-07-02 18:45:38 -0700166
167 dasm_growpc(&d, local.npc);
168
swissChilif1ba8c12021-07-02 18:45:38 -0700169 value_t arglist = car(args);
170 value_t body = cdr(args);
171
swissChili15f1cae2021-07-05 19:08:47 -0700172 // This will add the arguments to local too.
173 struct args *ar = list_to_args(env, arglist, &local);
174 local.args = ar;
swissChili74348422021-07-04 13:23:24 -0700175
swissChili15f1cae2021-07-05 19:08:47 -0700176 if (!ar)
swissChilif1ba8c12021-07-02 18:45:38 -0700177 {
swissChili15f1cae2021-07-05 19:08:47 -0700178 err("Malformed args list");
swissChilif1ba8c12021-07-02 18:45:38 -0700179 }
180
181 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
182 {
183 walk_and_alloc(&local, car(body_));
184 }
185
swissChili7e1393c2021-07-07 12:59:12 -0700186 | setup(local.num_stack_entries);
swissChilif1ba8c12021-07-02 18:45:38 -0700187
188 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
189 local.num_stack_entries = 0;
190
191 for (; !nilp(body); body = cdr(body))
192 {
193 compile_expression(env, &local, car(body), Dst);
194 }
195
196 | cleanup;
197
198 if (local_out)
199 *local_out = local;
200
swissChili15f1cae2021-07-05 19:08:47 -0700201 if (args_out)
202 *args_out = ar;
swissChilif1ba8c12021-07-02 18:45:38 -0700203
204 return d;
205}
206
swissChili7e1393c2021-07-07 12:59:12 -0700207void compile_tl(value_t val, struct environment *env, char *fname)
swissChilica107a02021-04-14 12:07:30 -0700208{
swissChili53472e82021-05-08 16:06:32 -0700209 if (!listp(val))
210 err("Top level must be a list");
swissChilica107a02021-04-14 12:07:30 -0700211
swissChili53472e82021-05-08 16:06:32 -0700212 value_t form = car(val);
213 value_t args = cdr(val);
214
swissChili2999dd12021-07-02 14:19:53 -0700215 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700216 {
swissChili2999dd12021-07-02 14:19:53 -0700217 enum namespace namespace = NS_FUNCTION;
218
219 if (symstreq(form, "defmacro"))
swissChili7e1393c2021-07-07 12:59:12 -0700220 namespace = NS_MACRO;
swissChili2999dd12021-07-02 14:19:53 -0700221
swissChili8fc5e2f2021-04-22 13:45:10 -0700222 struct local local;
swissChili15f1cae2021-07-05 19:08:47 -0700223 struct args *a;
swissChili74348422021-07-04 13:23:24 -0700224 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChilif68671f2021-07-05 14:14:44 -0700225
swissChili7e1393c2021-07-07 12:59:12 -0700226 dasm_State *d = compile_function(cdr(args), namespace, env, &local,
227 NULL, &a, name, fname);
swissChilia820dea2021-05-09 16:46:55 -0700228
swissChili7e1393c2021-07-07 12:59:12 -0700229 add_function(env, name, link_program(&d), a, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700230
swissChili53472e82021-05-08 16:06:32 -0700231 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700232 del_local(&local);
swissChili67bdf282021-06-06 18:46:08 -0700233 }
swissChilif68671f2021-07-05 14:14:44 -0700234 else if (symstreq(form, "progn"))
235 {
236 for (value_t val = args; !nilp(val); val = cdr(val))
237 {
swissChili7e1393c2021-07-07 12:59:12 -0700238 compile_tl(car(val), env, fname);
swissChilif68671f2021-07-05 14:14:44 -0700239 }
240 }
swissChili67bdf282021-06-06 18:46:08 -0700241}
242
243void walk_and_alloc(struct local *local, value_t body)
244{
245 if (!listp(body))
246 return;
247
248 value_t args = cdr(body);
249
250 if (symstreq(car(body), "let1"))
251 {
252 int slot = local_alloc(local);
253
254 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700255 for (; !nilp(expr); expr = cdr(expr))
256 {
swissChiliddc97542021-07-04 11:47:42 -0700257 walk_and_alloc(local, car(expr));
swissChilif1ba8c12021-07-02 18:45:38 -0700258 }
swissChili67bdf282021-06-06 18:46:08 -0700259
260 local_free(local, slot);
261 }
swissChilif1ba8c12021-07-02 18:45:38 -0700262 else if (symstreq(car(body), "lambda"))
263 {
264 // We don't want to walk the lambda because it's another function. When
265 // the lambda is compiled it will be walked.
266 return;
267 }
swissChili67bdf282021-06-06 18:46:08 -0700268 else
269 {
270 for (; !nilp(args); args = cdr(args))
271 {
272 walk_and_alloc(local, car(args));
273 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700274 }
275}
276
swissChilif68671f2021-07-05 14:14:44 -0700277bool load(struct environment *env, char *path)
swissChili8fc5e2f2021-04-22 13:45:10 -0700278{
swissChilif68671f2021-07-05 14:14:44 -0700279 if (!file_exists(path))
280 return false;
281
282 add_load(env, path);
283
swissChilib8fd4712021-06-23 15:32:04 -0700284 unsigned char pool = make_pool();
285 unsigned char pop = push_pool(pool);
286
swissChilif68671f2021-07-05 14:14:44 -0700287 struct istream *is = new_fistream(path, false);
288 if (!is)
289 return false;
290
swissChili8fc5e2f2021-04-22 13:45:10 -0700291 value_t val;
swissChili53472e82021-05-08 16:06:32 -0700292
293 while (read1(is, &val))
swissChili8fc5e2f2021-04-22 13:45:10 -0700294 {
swissChili7e1393c2021-07-07 12:59:12 -0700295 compile_tl(val, env, path);
swissChili8fc5e2f2021-04-22 13:45:10 -0700296 }
swissChilif3e7f182021-04-20 13:57:22 -0700297
swissChilif68671f2021-07-05 14:14:44 -0700298 del_fistream(is);
swissChilib8fd4712021-06-23 15:32:04 -0700299 pop_pool(pop);
300
swissChilif68671f2021-07-05 14:14:44 -0700301 return true;
302}
303
swissChili7e1393c2021-07-07 12:59:12 -0700304value_t load_relative(struct environment *env, char *to, value_t name)
305{
306 if (!stringp(name))
307 return nil;
308
309 char *new_path = (char *)(name ^ STRING_TAG);
310 char *relative_to = strdup(to);
311 char full_path[512];
312
313 snprintf(full_path, 512, "%s/%s", dirname(relative_to), new_path);
314
315 if (load(env, full_path))
316 return t;
317 else
318 return nil;
319}
320
321struct environment *compile_file(char *filename, bool *ok)
swissChilif68671f2021-07-05 14:14:44 -0700322{
323 value_t val;
swissChili7e1393c2021-07-07 12:59:12 -0700324 struct environment *env = malloc(sizeof(struct environment));
325 env->first = NULL;
326 env->first_loaded = NULL;
swissChilif68671f2021-07-05 14:14:44 -0700327
swissChili7e1393c2021-07-07 12:59:12 -0700328 add_load(env, filename);
329 load_std(env);
swissChilif68671f2021-07-05 14:14:44 -0700330
swissChili7e1393c2021-07-07 12:59:12 -0700331 bool ok_ = load(env, filename);
swissChilif68671f2021-07-05 14:14:44 -0700332
333 if (ok)
334 *ok = ok_;
335
swissChili8fc5e2f2021-04-22 13:45:10 -0700336 return env;
swissChilica107a02021-04-14 12:07:30 -0700337}
swissChilib3ca4fb2021-04-20 10:33:00 -0700338
swissChili53472e82021-05-08 16:06:32 -0700339int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700340{
swissChili53472e82021-05-08 16:06:32 -0700341 int n = local->nextpc++;
342 if (n > local->npc)
343 {
344 local->npc += 16;
345 dasm_growpc(Dst, local->npc);
346 }
347 return n;
348}
349
swissChili6b47b6d2021-06-30 22:08:55 -0700350void compile_backquote(struct environment *env, struct local *local,
351 value_t val, dasm_State **Dst)
352{
353 if (!listp(val))
354 {
355 | mov eax, (val);
356 }
357 else
358 {
swissChili7e1393c2021-07-07 12:59:12 -0700359 value_t fsym = car(val), args = cdr(val);
swissChili6b47b6d2021-06-30 22:08:55 -0700360 int nargs = length(args);
361
362 // TODO
363 }
364}
365
swissChili7e1393c2021-07-07 12:59:12 -0700366value_t eval(struct environment *env, value_t form)
367{
368 // Eval!
369 value_t function = cons(nil, cons(form, nil));
370
371 struct local local;
372 struct args *args;
373
374 dasm_State *d = compile_function(function, NS_ANONYMOUS, env, &local, NULL,
375 &args, NULL, "/");
376
377 del_local(&local);
378
379 value_t (*f)() = link_program(&d);
380 return f();
381}
382
swissChiliddc97542021-07-04 11:47:42 -0700383void compile_variable(struct variable *v, dasm_State *Dst)
384{
385 switch (v->type)
386 {
387 case V_ARGUMENT:
swissChili7e1393c2021-07-07 12:59:12 -0700388 | mov eax, dword[ebp + (value_size * (v->number + 2))];
swissChiliddc97542021-07-04 11:47:42 -0700389 break;
390 case V_BOUND:
swissChili7e1393c2021-07-07 12:59:12 -0700391 | mov eax, dword[ebp - ((v->number + 1) * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700392 break;
393 case V_FREE:
394 // edi is the closure context pointer
swissChili7e1393c2021-07-07 12:59:12 -0700395 | mov eax, dword[edi + (v->number * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700396 break;
397 default:
swissChili7e1393c2021-07-07 12:59:12 -0700398 err("Sorry, can only access V_ARGUMENT, V_FREE and V_BOUND variables "
399 "for now :(");
swissChiliddc97542021-07-04 11:47:42 -0700400 }
401}
402
swissChili53472e82021-05-08 16:06:32 -0700403void compile_expression(struct environment *env, struct local *local,
404 value_t val, dasm_State **Dst)
405{
swissChili7e1393c2021-07-07 12:59:12 -0700406 if (symstreq(val, "nil") || nilp(val))
swissChili53472e82021-05-08 16:06:32 -0700407 {
408 | mov eax, (nil);
409 }
swissChili923b5362021-05-09 20:31:43 -0700410 else if (symstreq(val, "t"))
411 {
412 | mov eax, (t);
413 }
414 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700415 {
416 | mov eax, val;
417 }
swissChili53472e82021-05-08 16:06:32 -0700418 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700419 {
swissChili53472e82021-05-08 16:06:32 -0700420 value_t fsym = car(val);
421 value_t args = cdr(val);
422 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700423
swissChili53472e82021-05-08 16:06:32 -0700424 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700425 {
swissChili7e1393c2021-07-07 12:59:12 -0700426 printval(val, 2);
427 err_at(val, "function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700428 }
429
swissChili53472e82021-05-08 16:06:32 -0700430 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700431 {
swissChili53472e82021-05-08 16:06:32 -0700432 if (nargs < 2 || nargs > 3)
433 err("Must give at least 2 arguments to if");
swissChilib3ca4fb2021-04-20 10:33:00 -0700434
swissChili53472e82021-05-08 16:06:32 -0700435 compile_expression(env, local, car(args), Dst);
436 int false_label = nextpc(local, Dst),
437 after_label = nextpc(local, Dst);
438
439 // result is in eax
440 | cmp eax, (nil);
swissChili7e1393c2021-07-07 12:59:12 -0700441 | je = > false_label;
swissChili53472e82021-05-08 16:06:32 -0700442
443 compile_expression(env, local, elt(args, 1), Dst);
swissChili7e1393c2021-07-07 12:59:12 -0700444 | jmp = > after_label;
445 |= > false_label:;
swissChili53472e82021-05-08 16:06:32 -0700446 if (nargs == 3)
swissChili7e1393c2021-07-07 12:59:12 -0700447 compile_expression(env, local, elt(args, 2), Dst);
448 |= > after_label:
swissChili53472e82021-05-08 16:06:32 -0700449 }
swissChilif68671f2021-07-05 14:14:44 -0700450 else if (symstreq(fsym, "progn"))
451 {
452 for (value_t val = args; !nilp(val); val = cdr(val))
453 {
454 compile_expression(env, local, car(val), Dst);
455 }
456 }
swissChili67bdf282021-06-06 18:46:08 -0700457 else if (symstreq(fsym, "let1"))
458 {
459 if (nargs < 2)
460 {
461 err("Must give at least 2 arguments to let1");
462 }
463 value_t binding = car(args);
464 value_t rest = cdr(args);
465
466 if (length(binding) != 2)
467 {
468 err("Binding list in let1 must contain exactly two entries");
469 }
470
471 value_t name = car(binding);
472 value_t value = car(cdr(binding));
473
474 compile_expression(env, local, value, Dst);
475
476 int i = local_alloc(local);
477
478 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
479
swissChili7e1393c2021-07-07 12:59:12 -0700480 | mov dword[ebp - ((i + 1) * value_size)], eax;
swissChili67bdf282021-06-06 18:46:08 -0700481
482 for (; !nilp(rest); rest = cdr(rest))
483 {
484 compile_expression(env, local, car(rest), Dst);
485 }
486
487 local_free(local, i);
488 }
swissChilie9fec8b2021-06-22 13:59:33 -0700489 else if (symstreq(fsym, "gc"))
490 {
491 if (nargs)
492 {
swissChili7e1393c2021-07-07 12:59:12 -0700493 err_at(val, "gc takes no arguments");
swissChilie9fec8b2021-06-22 13:59:33 -0700494 }
495
496 | run_gc;
497 }
swissChili6b47b6d2021-06-30 22:08:55 -0700498 else if (symstreq(fsym, "quote"))
499 {
500 if (nargs != 1)
501 err("quote should take exactly 1 argument");
502
503 // Simple!
504 | mov eax, (car(args));
505 }
506 else if (symstreq(fsym, "backquote"))
507 {
508 if (nargs != 1)
509 err("backquote should take exactly 1 argument");
510
511 compile_backquote(env, local, car(args), Dst);
512 }
swissChili74348422021-07-04 13:23:24 -0700513 else if (symstreq(fsym, "function"))
514 {
515 if (nargs != 1)
516 {
517 err("function should take exactly 1 argument");
518 }
519
520 if (!symbolp(car(args)))
521 {
swissChili7e1393c2021-07-07 12:59:12 -0700522 err("argument to function should be a symbol resolvable at "
523 "compile time");
swissChili74348422021-07-04 13:23:24 -0700524 }
525
swissChili7e1393c2021-07-07 12:59:12 -0700526 struct function *f =
527 find_function(env, (char *)(car(args) ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -0700528 value_t closure = create_closure(f->code_ptr, f->args, 0);
swissChili74348422021-07-04 13:23:24 -0700529
530 | mov eax, (closure);
531 }
swissChili6b47b6d2021-06-30 22:08:55 -0700532 else if (symstreq(fsym, "list"))
533 {
swissChili7e1393c2021-07-07 12:59:12 -0700534 | push(nil);
swissChili6b47b6d2021-06-30 22:08:55 -0700535
536 for (int i = nargs - 1; i >= 0; i--)
537 {
538 compile_expression(env, local, elt(args, i), Dst);
539
540 // push the ith item
541 | push eax;
542 // cons the top two stack items
543 | mov ebx, (cons);
544 | call ebx;
545 // remove the stack items from use
546 | add esp, (2 * value_size);
547 // put the new thing on the stack
548 | push eax;
549 }
550
551 | pop eax;
552 }
swissChiliddc97542021-07-04 11:47:42 -0700553 else if (symstreq(fsym, "lambda"))
554 {
555 // Compile the function with this as the parent scope
556 struct local new_local;
557 int nargs_out;
swissChili7e1393c2021-07-07 12:59:12 -0700558 dasm_State *d = compile_function(
559 args, NS_ANONYMOUS, env, &new_local, local, &nargs_out,
560 "recurse", local->current_file_path);
swissChiliddc97542021-07-04 11:47:42 -0700561
562 // Link the function
swissChilif68671f2021-07-05 14:14:44 -0700563 void *func_ptr = link_program(&d);
swissChiliddc97542021-07-04 11:47:42 -0700564
565 // Create a closure object with the correct number of captures at
566 // runtime
swissChili7e1393c2021-07-07 12:59:12 -0700567 | push(new_local.num_closure_slots);
568 | push(nargs_out);
569 | push(func_ptr);
swissChili74348422021-07-04 13:23:24 -0700570 | mov ebx, (create_closure);
swissChiliddc97542021-07-04 11:47:42 -0700571 | call ebx;
572 | add esp, 12;
573
574 // Walk the generated local scope for V_FREE variables, since each
575 // of these exists in our scope (or higher), evaluate it and set it
576 // as a member of the lambda capture.
577
578 for (struct variable *var = new_local.first; var; var = var->prev)
579 {
580 if (var->type == V_FREE)
581 {
582 // Closure in eax
583 | push eax;
584 // Variable now in eax
585 compile_variable(find_variable(local, var->name), Dst);
586 | push eax;
587
swissChiliddc97542021-07-04 11:47:42 -0700588 // The capture offset
swissChili7e1393c2021-07-07 12:59:12 -0700589 | push(var->number);
swissChili74348422021-07-04 13:23:24 -0700590 | mov ebx, (set_closure_capture_variable);
swissChiliddc97542021-07-04 11:47:42 -0700591 | call ebx;
592 // Skip the value and index
593 | add esp, 8;
594 // Pop the closure back in to eax
595 | pop eax;
596 }
597 }
598
599 // Closure is still in eax
600
601 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700602 del_local(&new_local);
swissChiliddc97542021-07-04 11:47:42 -0700603 }
swissChili7e1393c2021-07-07 12:59:12 -0700604 else if (symstreq(fsym, "eval"))
605 {
606 if (nargs != 1)
607 {
608 err("eval takes exactly 1 argument");
609 }
610
611 compile_expression(env, local, car(args), Dst);
612 | push eax;
613 | push(env);
614 | mov ebx, (eval);
615 | call ebx;
616 }
617 else if (symstreq(fsym, "load"))
618 {
619 if (nargs != 1)
620 {
621 err_at(val, "load takes exactly 1 argument, %d given", nargs);
622 }
623
624 compile_expression(env, local, car(args), Dst);
625 | push eax;
626 | push(local->current_file_path);
627 | push(env);
628 | mov ebx, (load_relative);
629 | call ebx;
630 }
swissChili53472e82021-05-08 16:06:32 -0700631 else
632 {
swissChili74348422021-07-04 13:23:24 -0700633 char *name = (char *)(fsym ^ SYMBOL_TAG);
634 struct function *func = find_function(env, name);
swissChili7e1393c2021-07-07 12:59:12 -0700635
swissChili74348422021-07-04 13:23:24 -0700636 bool is_recursive = false;
swissChili15f1cae2021-07-05 19:08:47 -0700637 struct args *nargs_needed = NULL;
swissChili53472e82021-05-08 16:06:32 -0700638
swissChili7e1393c2021-07-07 12:59:12 -0700639 if (local->current_function_name &&
640 symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700641 {
swissChili74348422021-07-04 13:23:24 -0700642 is_recursive = true;
swissChili15f1cae2021-07-05 19:08:47 -0700643 nargs_needed = local->args;
swissChili74348422021-07-04 13:23:24 -0700644 }
645 else
646 {
647 if (func == NULL)
648 {
swissChili7e1393c2021-07-07 12:59:12 -0700649 err_at(val, "Function %s undefined", name);
swissChili74348422021-07-04 13:23:24 -0700650 }
651
swissChili15f1cae2021-07-05 19:08:47 -0700652 nargs_needed = func->args;
swissChili74348422021-07-04 13:23:24 -0700653 }
654
swissChili15f1cae2021-07-05 19:08:47 -0700655 if (!are_args_acceptable(nargs_needed, nargs))
swissChili74348422021-07-04 13:23:24 -0700656 {
swissChili7e1393c2021-07-07 12:59:12 -0700657 err_at(val,
658 "wrong number of args in function call: %s at %s:%d, "
659 "want %d args but given %d\n",
660 name, cons_file(val), cons_line(val),
661 nargs_needed->num_required, nargs);
swissChilif1ba8c12021-07-02 18:45:38 -0700662 }
swissChili53472e82021-05-08 16:06:32 -0700663
swissChili74348422021-07-04 13:23:24 -0700664 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700665 {
swissChili15f1cae2021-07-05 19:08:47 -0700666 int nargs = length(args);
667
668 if (nargs <= nargs_needed->num_required)
669 {
670 // Push the variadic list (nil)
swissChili7e1393c2021-07-07 12:59:12 -0700671 | push(nil);
swissChili15f1cae2021-07-05 19:08:47 -0700672 }
673
swissChili7e1393c2021-07-07 12:59:12 -0700674 for (int i = nargs_needed->num_optional - 1;
675 i >= nargs - nargs_needed->num_required; i--)
swissChili15f1cae2021-07-05 19:08:47 -0700676 {
677 // Push the default optional values
swissChili7e1393c2021-07-07 12:59:12 -0700678 | push(nargs_needed->optional_arguments[i].value);
swissChili15f1cae2021-07-05 19:08:47 -0700679 }
680
681 for (int i = nargs - 1; i >= 0; i--)
swissChili2999dd12021-07-02 14:19:53 -0700682 {
683 compile_expression(env, local, elt(args, i), Dst);
684 | push eax;
685 }
swissChili15f1cae2021-07-05 19:08:47 -0700686
swissChili74348422021-07-04 13:23:24 -0700687 if (is_recursive)
688 {
swissChili7e1393c2021-07-07 12:59:12 -0700689 | call->function_start;
swissChili74348422021-07-04 13:23:24 -0700690 }
691 else
692 {
693 | mov ebx, (func->code_addr);
694 | call ebx;
695 }
swissChili2999dd12021-07-02 14:19:53 -0700696 | add esp, (nargs * value_size);
697 // result in eax
698 }
699 else if (func->namespace == NS_MACRO)
700 {
swissChili7e1393c2021-07-07 12:59:12 -0700701 // Make sure that the stuff allocated by the macro isn't in a
702 // pool
swissChilif68671f2021-07-05 14:14:44 -0700703 unsigned char pool = push_pool(0);
704
swissChili2999dd12021-07-02 14:19:53 -0700705 value_t expanded_to = call_list(func, args);
706
swissChilif68671f2021-07-05 14:14:44 -0700707 pop_pool(pool);
708
swissChili2999dd12021-07-02 14:19:53 -0700709 compile_expression(env, local, expanded_to, Dst);
710 }
swissChili53472e82021-05-08 16:06:32 -0700711 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700712 }
swissChili923b5362021-05-09 20:31:43 -0700713 else if (symbolp(val))
714 {
swissChili7e1393c2021-07-07 12:59:12 -0700715 if (symstreq(val, "+current-file+"))
swissChilie9fec8b2021-06-22 13:59:33 -0700716 {
swissChili7e1393c2021-07-07 12:59:12 -0700717 value_t file_name_val = strval(local->current_file_path);
718
719 | mov eax, (file_name_val);
swissChilie9fec8b2021-06-22 13:59:33 -0700720 }
swissChili7e1393c2021-07-07 12:59:12 -0700721 else
722 {
723 struct variable *v =
724 find_variable(local, (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700725
swissChili7e1393c2021-07-07 12:59:12 -0700726 if (!v)
727 {
728 fprintf(stderr, "var: %s\n", (char *)(val ^ SYMBOL_TAG));
729 err("Variable unbound");
730 }
731
732 compile_variable(v, Dst);
733 }
swissChili923b5362021-05-09 20:31:43 -0700734 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700735}
swissChilif3e7f182021-04-20 13:57:22 -0700736
swissChili923b5362021-05-09 20:31:43 -0700737struct variable *add_variable(struct local *local, enum var_type type,
738 char *name, int number)
739{
740 struct variable *var = malloc(sizeof(struct variable));
741 var->prev = local->first;
742 var->type = type;
743 var->name = name;
744 var->number = number;
745
746 local->first = var;
747
748 return var;
749}
750
751void destroy_local(struct local *local)
752{
753 for (struct variable *v = local->first; v;)
754 {
755 struct variable *t = v;
756 v = v->prev;
757 free(t);
758 }
759}
760
761struct variable *find_variable(struct local *local, char *name)
762{
763 struct variable *v = local->first;
764
765 for (; v && strcmp(v->name, name) != 0; v = v->prev)
swissChili7e1393c2021-07-07 12:59:12 -0700766 {
767 }
swissChili923b5362021-05-09 20:31:43 -0700768
swissChiliddc97542021-07-04 11:47:42 -0700769 if (!v)
770 {
771 if (local->parent)
772 {
773 v = find_variable(local->parent, name);
774
775 if (v)
776 {
swissChili15f1cae2021-07-05 19:08:47 -0700777 // We found this in a parent scope, add it as a V_FREE variable
778 // to skip the search.
swissChili7e1393c2021-07-07 12:59:12 -0700779 v = add_variable(local, V_FREE, name,
780 local->num_closure_slots++);
swissChiliddc97542021-07-04 11:47:42 -0700781 }
782 }
783 }
swissChili923b5362021-05-09 20:31:43 -0700784 return v;
785}
swissChili2999dd12021-07-02 14:19:53 -0700786
swissChiliddc97542021-07-04 11:47:42 -0700787extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -0700788
swissChili7e1393c2021-07-07 12:59:12 -0700789value_t call_list_args(void *code_ptr, struct args *args, value_t list,
790 void *data)
swissChili2999dd12021-07-02 14:19:53 -0700791{
swissChili15f1cae2021-07-05 19:08:47 -0700792 list = deep_copy(list);
793 int nargs = length(list);
794
795 value_t *val = NULL;
796
797 for (value_t i = list; !nilp(i); i = cdr(i))
798 {
799 val = cdrref(i);
800 }
801
802 int total_required = args->num_required + args->num_optional;
803
804 if (nargs > total_required)
805 {
806 // Take the remainder of the list and put it as the last item in the
807 // list.
808 value_t trailing = cxdr(list, total_required);
809 value_t last_item = cons(trailing, nil);
810
811 *cxdrref(&list, total_required) = last_item;
812 }
813 else if (nargs < total_required)
814 {
815 for (int i = nargs - args->num_required; i < args->num_optional; i++)
816 {
817 // Append the i-th defualt argument
818 value_t appended = cons(args->optional_arguments[i].value, nil);
819 *val = appended;
820 val = cdrref(appended);
821 }
822 }
823
824 // We want to call this if we pass the correct # of arguments or less, just
825 // not if we have already passed varargs. Appends a nil argument.
826 if (nargs <= total_required)
827 {
828 // Enough real arguments but no variadic arguments. Pass a nil list.
829 *val = cons(nil, nil);
830 }
831
832 return _call_list(code_ptr, list, data);
833}
834
835value_t call_list(struct function *fun, value_t list)
836{
837 return call_list_args(fun->code_ptr, fun->args, list, NULL);
swissChiliddc97542021-07-04 11:47:42 -0700838}
839
840value_t call_list_closure(struct closure *c, value_t list)
841{
swissChili15f1cae2021-07-05 19:08:47 -0700842 return call_list_args(c->function, c->args, list, c->data);
843}
844
845struct args *new_args()
846{
847 struct args *a = malloc(sizeof(struct args));
848 a->num_optional = 0;
849 a->num_required = 0;
850 a->variadic = false;
851
852 return a;
853}
854
swissChili7e1393c2021-07-07 12:59:12 -0700855struct args *add_optional_arg(struct args *args, value_t name, value_t value)
swissChili15f1cae2021-07-05 19:08:47 -0700856{
857 int i = args->num_optional++;
swissChili7e1393c2021-07-07 12:59:12 -0700858 args =
859 realloc(args, sizeof(struct args) + sizeof(struct optional_argument) *
860 args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -0700861
swissChili7e1393c2021-07-07 12:59:12 -0700862 args->optional_arguments[i] = (struct optional_argument){
863 .value = value,
864 .name = name,
swissChili15f1cae2021-07-05 19:08:47 -0700865 };
866
867 return args;
868}
869
870bool are_args_acceptable(struct args *args, int number)
871{
872 if (args->variadic)
873 {
874 return number >= args->num_required;
875 }
876 else
877 {
878 return number >= args->num_required &&
swissChili7e1393c2021-07-07 12:59:12 -0700879 number <= args->num_required + args->num_optional;
swissChili15f1cae2021-07-05 19:08:47 -0700880 }
881}
882
swissChili7e1393c2021-07-07 12:59:12 -0700883struct args *list_to_args(struct environment *env, value_t list,
884 struct local *local)
swissChili15f1cae2021-07-05 19:08:47 -0700885{
886 struct args *args = new_args();
887
888 bool in_optional = false;
889
890 for (value_t i = list; !nilp(i); i = cdr(i))
891 {
892 value_t val = car(i);
893 if (symbolp(val))
894 {
895 if (!args->variadic && symstreq(val, "&"))
896 {
897 i = cdr(i);
898 value_t name = car(i);
899
900 if (!symbolp(name))
901 {
swissChili7e1393c2021-07-07 12:59:12 -0700902 err("You must provide a symbol after & in an argument list "
903 "to bind the\n"
904 "variadic arguments to.");
swissChili15f1cae2021-07-05 19:08:47 -0700905 }
906
907 args->variadic = true;
908
909 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
swissChili7e1393c2021-07-07 12:59:12 -0700910 args->num_optional + args->num_required);
swissChili15f1cae2021-07-05 19:08:47 -0700911
912 continue;
913 }
914
915 if (!in_optional)
916 {
swissChili7e1393c2021-07-07 12:59:12 -0700917 add_variable(local, V_ARGUMENT, (char *)(val ^ SYMBOL_TAG),
918 args->num_required++);
swissChili15f1cae2021-07-05 19:08:47 -0700919 }
920 else
921 {
922 char *name = (char *)(val ^ SYMBOL_TAG);
923 if (name[0] == '&')
924 {
swissChili7e1393c2021-07-07 12:59:12 -0700925 err("Non-optional argument following optional arguments "
926 "starts with a &\n"
927 "did you mean to declare a variadic argument? If so "
928 "leave a space\n"
929 "between the & and name.");
swissChili15f1cae2021-07-05 19:08:47 -0700930 }
931 else
932 {
swissChili7e1393c2021-07-07 12:59:12 -0700933 err("Cannot define a non-optional argument after an "
934 "optional one.");
swissChili15f1cae2021-07-05 19:08:47 -0700935 }
936 }
937 }
938 else if (listp(val))
939 {
940 in_optional = true;
941 int len = length(val);
942
943 if (len != 2)
944 {
swissChili7e1393c2021-07-07 12:59:12 -0700945 err("A list defining an optional value must be structured like "
946 "(name expr)\n"
947 "with exactly two arguments.");
swissChili15f1cae2021-07-05 19:08:47 -0700948 }
949
950 value_t name = car(val);
951 value_t expr = car(cdr(val));
952
953 value_t function = cons(nil, cons(expr, nil));
954
swissChili7e1393c2021-07-07 12:59:12 -0700955 dasm_State *d =
956 compile_function(function, NS_ANONYMOUS, env, NULL, NULL, NULL,
957 NULL, local->current_file_path);
swissChili15f1cae2021-07-05 19:08:47 -0700958
959 // TODO: GC stack top!
960 value_t (*compiled)() = link_program(&d);
961
962 value_t value = compiled();
963 args = add_optional_arg(args, name, value);
964
swissChili7e1393c2021-07-07 12:59:12 -0700965 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
966 args->num_required + args->num_optional - 1);
swissChili15f1cae2021-07-05 19:08:47 -0700967 }
968 }
969
970 return args;
971}
972
973void display_args(struct args *args)
974{
975 printf("Args object taking %d require arguments and %d optionals:\n",
swissChili7e1393c2021-07-07 12:59:12 -0700976 args->num_required, args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -0700977
978 for (int i = 0; i < args->num_optional; i++)
979 {
swissChili7e1393c2021-07-07 12:59:12 -0700980 printf(" %d\t%s\n", i,
981 (char *)(args->optional_arguments[i].name ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -0700982 printval(args->optional_arguments[i].value, 2);
983 }
swissChili2999dd12021-07-02 14:19:53 -0700984}