blob: 3cb80d8fafcc8320253ffe0d7ee4052e560cb37e [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;
swissChili484295d2021-07-09 21:25:55 -070022|->function_start:;
23| push ebp;
swissChilica107a02021-04-14 12:07:30 -070024| mov ebp, esp;
swissChili8cfb7c42021-04-18 21:17:58 -070025| sub esp, (value_size * nvars);
swissChilica107a02021-04-14 12:07:30 -070026|.endmacro;
27
28|.macro cleanup;
29| mov esp, ebp;
30| pop ebp;
31| ret;
32|.endmacro;
33
swissChili484295d2021-07-09 21:25:55 -070034|.macro call_extern, address;
35| mov ebx, address;
36| call ebx;
swissChili67bdf282021-06-06 18:46:08 -070037|.endmacro;
38
swissChilica107a02021-04-14 12:07:30 -070039dasm_State *d;
40unsigned int npc = 8;
41
swissChili9e57da42021-06-15 22:22:46 -070042|.macro run_gc;
swissChilie9fec8b2021-06-22 13:59:33 -070043| mov eax, esp;
swissChili9e57da42021-06-15 22:22:46 -070044| push ebp;
swissChilie9fec8b2021-06-22 13:59:33 -070045| push eax;
swissChili9e57da42021-06-15 22:22:46 -070046| mov eax, _do_gc;
47| call eax;
48|.endmacro;
swissChili6d6525e2021-06-15 21:20:53 -070049
swissChili53472e82021-05-08 16:06:32 -070050struct function *find_function(struct environment *env, char *name)
swissChilica107a02021-04-14 12:07:30 -070051{
swissChilif68671f2021-07-05 14:14:44 -070052 struct function *f;
swissChilica107a02021-04-14 12:07:30 -070053
swissChilif68671f2021-07-05 14:14:44 -070054 for (f = env->first; f && strcmp(f->name, name); f = f->prev)
swissChilica107a02021-04-14 12:07:30 -070055 {
swissChilica107a02021-04-14 12:07:30 -070056 }
57
58 return f;
59}
60
swissChili67bdf282021-06-06 18:46:08 -070061unsigned int local_alloc(struct local *local)
62{
63 for (int i = 0; i < local->num_stack_slots; i++)
64 {
65 if (local->stack_slots[i] == false)
66 {
67 local->stack_slots[i] = true;
68
69 if (i >= local->num_stack_entries)
70 local->num_stack_entries++;
71
72 return i;
73 }
74 }
75
76 int old_size = local->num_stack_slots;
77 local->num_stack_slots += 4;
swissChili7e1393c2021-07-07 12:59:12 -070078 local->stack_slots =
79 realloc(local->stack_slots, local->num_stack_slots * sizeof(bool));
swissChili67bdf282021-06-06 18:46:08 -070080 // unreadable: set the remaining slots to unused
81 memset(local->stack_slots + old_size, 0, local->num_stack_slots - old_size);
82 local->stack_slots[old_size] = true;
83
84 return old_size;
85}
86
87void local_free(struct local *local, unsigned int slot)
88{
89 local->stack_slots[slot] = false;
90}
91
swissChili708d4c42021-07-04 17:40:07 -070092void del_local(struct local *local)
93{
94 free(local->stack_slots);
95
96 for (struct variable *next, *f = local->first; f; f = next)
97 {
98 next = f->prev;
99 free(f);
100 }
101}
102
103void del_env(struct environment *env)
104{
105 for (struct function *next, *f = env->first; f; f = next)
106 {
107 next = f->prev;
108 // We're not gonna bother munmap()ing the function
109 free(f);
110 }
swissChilif68671f2021-07-05 14:14:44 -0700111
112 for (struct loaded_file *next, *l = env->first_loaded; l; l = next)
113 {
114 next = l->previous;
115 free(l->resolved_path);
116 free(l);
117 }
swissChili7e1393c2021-07-07 12:59:12 -0700118
119 free(env);
swissChilif68671f2021-07-05 14:14:44 -0700120}
121
122void add_load(struct environment *env, char *path)
123{
124 static char buffer[512];
125 long size = readlink(path, buffer, 512);
126 buffer[size] = '\0';
127 char *resolved = strdup(buffer);
128
129 struct loaded_file *f = malloc(sizeof(struct loaded_file));
130 f->resolved_path = resolved;
131 f->previous = env->first_loaded;
132 env->first_loaded = f;
swissChili708d4c42021-07-04 17:40:07 -0700133}
134
swissChilif1ba8c12021-07-02 18:45:38 -0700135struct dasm_State *compile_function(value_t args, enum namespace namespace,
swissChili7e1393c2021-07-07 12:59:12 -0700136 struct environment *env,
137 struct local *local_out,
138 struct local *local_parent,
139 struct args **args_out, char *name,
140 char *path)
swissChilif1ba8c12021-07-02 18:45:38 -0700141{
142 dasm_State *d;
143 dasm_State **Dst = &d;
144
swissChili484295d2021-07-09 21:25:55 -0700145 |.section code, imports;
swissChilif1ba8c12021-07-02 18:45:38 -0700146 dasm_init(&d, DASM_MAXSECTION);
147
148 |.globals lbl_;
149 void *labels[lbl__MAX];
150 dasm_setupglobal(&d, labels, lbl__MAX);
151
152 |.actionlist lisp_actions;
153 dasm_setup(&d, lisp_actions);
154
155 struct local local;
156 local.parent = NULL;
157 local.first = NULL;
158 local.num_vars = 0;
159 local.npc = 8;
160 local.nextpc = 0;
161 local.stack_slots = malloc(sizeof(bool) * 4);
162 memset(local.stack_slots, 0, sizeof(bool) * 4);
163 local.num_stack_slots = 4;
164 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700165 local.num_closure_slots = 0;
166 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700167 local.current_function_name = name;
swissChili7e1393c2021-07-07 12:59:12 -0700168 local.current_file_path = path;
swissChilif1ba8c12021-07-02 18:45:38 -0700169
170 dasm_growpc(&d, local.npc);
171
swissChilif1ba8c12021-07-02 18:45:38 -0700172 value_t arglist = car(args);
173 value_t body = cdr(args);
174
swissChili15f1cae2021-07-05 19:08:47 -0700175 // This will add the arguments to local too.
176 struct args *ar = list_to_args(env, arglist, &local);
177 local.args = ar;
swissChili74348422021-07-04 13:23:24 -0700178
swissChili15f1cae2021-07-05 19:08:47 -0700179 if (!ar)
swissChilif1ba8c12021-07-02 18:45:38 -0700180 {
swissChili15f1cae2021-07-05 19:08:47 -0700181 err("Malformed args list");
swissChilif1ba8c12021-07-02 18:45:38 -0700182 }
183
184 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
185 {
186 walk_and_alloc(&local, car(body_));
187 }
188
swissChili484295d2021-07-09 21:25:55 -0700189 | setup (local.num_stack_entries);
swissChilif1ba8c12021-07-02 18:45:38 -0700190
191 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
192 local.num_stack_entries = 0;
193
194 for (; !nilp(body); body = cdr(body))
195 {
196 compile_expression(env, &local, car(body), Dst);
197 }
198
199 | cleanup;
200
201 if (local_out)
202 *local_out = local;
203
swissChili15f1cae2021-07-05 19:08:47 -0700204 if (args_out)
205 *args_out = ar;
swissChilif1ba8c12021-07-02 18:45:38 -0700206
207 return d;
208}
209
swissChili7e1393c2021-07-07 12:59:12 -0700210void compile_tl(value_t val, struct environment *env, char *fname)
swissChilica107a02021-04-14 12:07:30 -0700211{
swissChili53472e82021-05-08 16:06:32 -0700212 if (!listp(val))
213 err("Top level must be a list");
swissChilica107a02021-04-14 12:07:30 -0700214
swissChili53472e82021-05-08 16:06:32 -0700215 value_t form = car(val);
216 value_t args = cdr(val);
217
swissChili2999dd12021-07-02 14:19:53 -0700218 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700219 {
swissChili2999dd12021-07-02 14:19:53 -0700220 enum namespace namespace = NS_FUNCTION;
221
222 if (symstreq(form, "defmacro"))
swissChili7e1393c2021-07-07 12:59:12 -0700223 namespace = NS_MACRO;
swissChili2999dd12021-07-02 14:19:53 -0700224
swissChili8fc5e2f2021-04-22 13:45:10 -0700225 struct local local;
swissChili15f1cae2021-07-05 19:08:47 -0700226 struct args *a;
swissChili74348422021-07-04 13:23:24 -0700227 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChilif68671f2021-07-05 14:14:44 -0700228
swissChili7e1393c2021-07-07 12:59:12 -0700229 dasm_State *d = compile_function(cdr(args), namespace, env, &local,
230 NULL, &a, name, fname);
swissChilia820dea2021-05-09 16:46:55 -0700231
swissChili7e1393c2021-07-07 12:59:12 -0700232 add_function(env, name, link_program(&d), a, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700233
swissChili53472e82021-05-08 16:06:32 -0700234 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700235 del_local(&local);
swissChili67bdf282021-06-06 18:46:08 -0700236 }
swissChilif68671f2021-07-05 14:14:44 -0700237 else if (symstreq(form, "progn"))
238 {
239 for (value_t val = args; !nilp(val); val = cdr(val))
240 {
swissChili7e1393c2021-07-07 12:59:12 -0700241 compile_tl(car(val), env, fname);
swissChilif68671f2021-07-05 14:14:44 -0700242 }
243 }
swissChili484295d2021-07-09 21:25:55 -0700244 else if (symstreq(form, "load"))
245 {
246 if (length(args) != 1)
247 {
248 err_at(val, "load expects exactly 1 argument, %d given",
249 length(args));
250 }
251 load_relative(env, fname, car(args));
252 }
swissChili67bdf282021-06-06 18:46:08 -0700253}
254
255void walk_and_alloc(struct local *local, value_t body)
256{
257 if (!listp(body))
258 return;
259
260 value_t args = cdr(body);
261
262 if (symstreq(car(body), "let1"))
263 {
264 int slot = local_alloc(local);
265
266 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700267 for (; !nilp(expr); expr = cdr(expr))
268 {
swissChiliddc97542021-07-04 11:47:42 -0700269 walk_and_alloc(local, car(expr));
swissChilif1ba8c12021-07-02 18:45:38 -0700270 }
swissChili67bdf282021-06-06 18:46:08 -0700271
272 local_free(local, slot);
273 }
swissChilif1ba8c12021-07-02 18:45:38 -0700274 else if (symstreq(car(body), "lambda"))
275 {
276 // We don't want to walk the lambda because it's another function. When
277 // the lambda is compiled it will be walked.
278 return;
279 }
swissChili67bdf282021-06-06 18:46:08 -0700280 else
281 {
282 for (; !nilp(args); args = cdr(args))
283 {
284 walk_and_alloc(local, car(args));
285 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700286 }
287}
288
swissChilif68671f2021-07-05 14:14:44 -0700289bool load(struct environment *env, char *path)
swissChili8fc5e2f2021-04-22 13:45:10 -0700290{
swissChilif68671f2021-07-05 14:14:44 -0700291 if (!file_exists(path))
292 return false;
293
294 add_load(env, path);
295
swissChilib8fd4712021-06-23 15:32:04 -0700296 unsigned char pool = make_pool();
297 unsigned char pop = push_pool(pool);
298
swissChilif68671f2021-07-05 14:14:44 -0700299 struct istream *is = new_fistream(path, false);
300 if (!is)
301 return false;
302
swissChili8fc5e2f2021-04-22 13:45:10 -0700303 value_t val;
swissChili53472e82021-05-08 16:06:32 -0700304
305 while (read1(is, &val))
swissChili8fc5e2f2021-04-22 13:45:10 -0700306 {
swissChili7e1393c2021-07-07 12:59:12 -0700307 compile_tl(val, env, path);
swissChili8fc5e2f2021-04-22 13:45:10 -0700308 }
swissChilif3e7f182021-04-20 13:57:22 -0700309
swissChilif68671f2021-07-05 14:14:44 -0700310 del_fistream(is);
swissChilib8fd4712021-06-23 15:32:04 -0700311 pop_pool(pop);
312
swissChilif68671f2021-07-05 14:14:44 -0700313 return true;
314}
315
swissChili7e1393c2021-07-07 12:59:12 -0700316value_t load_relative(struct environment *env, char *to, value_t name)
317{
318 if (!stringp(name))
319 return nil;
320
swissChili484295d2021-07-09 21:25:55 -0700321 fprintf(stderr, "Called load_relative\n");
322
swissChili7e1393c2021-07-07 12:59:12 -0700323 char *new_path = (char *)(name ^ STRING_TAG);
324 char *relative_to = strdup(to);
325 char full_path[512];
326
327 snprintf(full_path, 512, "%s/%s", dirname(relative_to), new_path);
328
329 if (load(env, full_path))
330 return t;
331 else
332 return nil;
333}
334
335struct environment *compile_file(char *filename, bool *ok)
swissChilif68671f2021-07-05 14:14:44 -0700336{
337 value_t val;
swissChili7e1393c2021-07-07 12:59:12 -0700338 struct environment *env = malloc(sizeof(struct environment));
339 env->first = NULL;
340 env->first_loaded = NULL;
swissChilif68671f2021-07-05 14:14:44 -0700341
swissChili7e1393c2021-07-07 12:59:12 -0700342 add_load(env, filename);
343 load_std(env);
swissChilif68671f2021-07-05 14:14:44 -0700344
swissChili7e1393c2021-07-07 12:59:12 -0700345 bool ok_ = load(env, filename);
swissChilif68671f2021-07-05 14:14:44 -0700346
347 if (ok)
348 *ok = ok_;
349
swissChili8fc5e2f2021-04-22 13:45:10 -0700350 return env;
swissChilica107a02021-04-14 12:07:30 -0700351}
swissChilib3ca4fb2021-04-20 10:33:00 -0700352
swissChili53472e82021-05-08 16:06:32 -0700353int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700354{
swissChili53472e82021-05-08 16:06:32 -0700355 int n = local->nextpc++;
356 if (n > local->npc)
357 {
358 local->npc += 16;
359 dasm_growpc(Dst, local->npc);
360 }
361 return n;
362}
363
swissChili6b47b6d2021-06-30 22:08:55 -0700364void compile_backquote(struct environment *env, struct local *local,
365 value_t val, dasm_State **Dst)
366{
367 if (!listp(val))
368 {
369 | mov eax, (val);
370 }
371 else
372 {
swissChili7e1393c2021-07-07 12:59:12 -0700373 value_t fsym = car(val), args = cdr(val);
swissChili6b47b6d2021-06-30 22:08:55 -0700374 int nargs = length(args);
375
376 // TODO
377 }
378}
379
swissChili7e1393c2021-07-07 12:59:12 -0700380value_t eval(struct environment *env, value_t form)
381{
382 // Eval!
383 value_t function = cons(nil, cons(form, nil));
384
385 struct local local;
386 struct args *args;
387
388 dasm_State *d = compile_function(function, NS_ANONYMOUS, env, &local, NULL,
389 &args, NULL, "/");
390
391 del_local(&local);
392
393 value_t (*f)() = link_program(&d);
394 return f();
395}
396
swissChiliddc97542021-07-04 11:47:42 -0700397void compile_variable(struct variable *v, dasm_State *Dst)
398{
399 switch (v->type)
400 {
401 case V_ARGUMENT:
swissChili7e1393c2021-07-07 12:59:12 -0700402 | mov eax, dword[ebp + (value_size * (v->number + 2))];
swissChiliddc97542021-07-04 11:47:42 -0700403 break;
404 case V_BOUND:
swissChili7e1393c2021-07-07 12:59:12 -0700405 | mov eax, dword[ebp - ((v->number + 1) * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700406 break;
407 case V_FREE:
408 // edi is the closure context pointer
swissChili7e1393c2021-07-07 12:59:12 -0700409 | mov eax, dword[edi + (v->number * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700410 break;
411 default:
swissChili7e1393c2021-07-07 12:59:12 -0700412 err("Sorry, can only access V_ARGUMENT, V_FREE and V_BOUND variables "
413 "for now :(");
swissChiliddc97542021-07-04 11:47:42 -0700414 }
415}
416
swissChili53472e82021-05-08 16:06:32 -0700417void compile_expression(struct environment *env, struct local *local,
418 value_t val, dasm_State **Dst)
419{
swissChili7e1393c2021-07-07 12:59:12 -0700420 if (symstreq(val, "nil") || nilp(val))
swissChili53472e82021-05-08 16:06:32 -0700421 {
422 | mov eax, (nil);
423 }
swissChili923b5362021-05-09 20:31:43 -0700424 else if (symstreq(val, "t"))
425 {
426 | mov eax, (t);
427 }
428 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700429 {
430 | mov eax, val;
431 }
swissChili53472e82021-05-08 16:06:32 -0700432 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700433 {
swissChili53472e82021-05-08 16:06:32 -0700434 value_t fsym = car(val);
435 value_t args = cdr(val);
436 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700437
swissChili53472e82021-05-08 16:06:32 -0700438 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700439 {
swissChili7e1393c2021-07-07 12:59:12 -0700440 printval(val, 2);
441 err_at(val, "function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700442 }
443
swissChili53472e82021-05-08 16:06:32 -0700444 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700445 {
swissChili53472e82021-05-08 16:06:32 -0700446 if (nargs < 2 || nargs > 3)
447 err("Must give at least 2 arguments to if");
swissChilib3ca4fb2021-04-20 10:33:00 -0700448
swissChili53472e82021-05-08 16:06:32 -0700449 compile_expression(env, local, car(args), Dst);
450 int false_label = nextpc(local, Dst),
451 after_label = nextpc(local, Dst);
452
453 // result is in eax
454 | cmp eax, (nil);
swissChili484295d2021-07-09 21:25:55 -0700455 | je =>false_label;
swissChili53472e82021-05-08 16:06:32 -0700456
457 compile_expression(env, local, elt(args, 1), Dst);
swissChili484295d2021-07-09 21:25:55 -0700458 | jmp =>after_label;
459 |=>false_label:;
swissChili53472e82021-05-08 16:06:32 -0700460 if (nargs == 3)
swissChili7e1393c2021-07-07 12:59:12 -0700461 compile_expression(env, local, elt(args, 2), Dst);
swissChili484295d2021-07-09 21:25:55 -0700462 |=>after_label:;
swissChili53472e82021-05-08 16:06:32 -0700463 }
swissChilif68671f2021-07-05 14:14:44 -0700464 else if (symstreq(fsym, "progn"))
465 {
466 for (value_t val = args; !nilp(val); val = cdr(val))
467 {
468 compile_expression(env, local, car(val), Dst);
469 }
470 }
swissChili67bdf282021-06-06 18:46:08 -0700471 else if (symstreq(fsym, "let1"))
472 {
473 if (nargs < 2)
474 {
475 err("Must give at least 2 arguments to let1");
476 }
477 value_t binding = car(args);
478 value_t rest = cdr(args);
479
480 if (length(binding) != 2)
481 {
482 err("Binding list in let1 must contain exactly two entries");
483 }
484
485 value_t name = car(binding);
486 value_t value = car(cdr(binding));
487
488 compile_expression(env, local, value, Dst);
489
490 int i = local_alloc(local);
491
492 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
493
swissChili7e1393c2021-07-07 12:59:12 -0700494 | mov dword[ebp - ((i + 1) * value_size)], eax;
swissChili67bdf282021-06-06 18:46:08 -0700495
496 for (; !nilp(rest); rest = cdr(rest))
497 {
498 compile_expression(env, local, car(rest), Dst);
499 }
500
501 local_free(local, i);
502 }
swissChilie9fec8b2021-06-22 13:59:33 -0700503 else if (symstreq(fsym, "gc"))
504 {
505 if (nargs)
506 {
swissChili7e1393c2021-07-07 12:59:12 -0700507 err_at(val, "gc takes no arguments");
swissChilie9fec8b2021-06-22 13:59:33 -0700508 }
509
510 | run_gc;
511 }
swissChili6b47b6d2021-06-30 22:08:55 -0700512 else if (symstreq(fsym, "quote"))
513 {
514 if (nargs != 1)
515 err("quote should take exactly 1 argument");
516
517 // Simple!
518 | mov eax, (car(args));
519 }
520 else if (symstreq(fsym, "backquote"))
521 {
522 if (nargs != 1)
523 err("backquote should take exactly 1 argument");
524
525 compile_backquote(env, local, car(args), Dst);
526 }
swissChili74348422021-07-04 13:23:24 -0700527 else if (symstreq(fsym, "function"))
528 {
529 if (nargs != 1)
530 {
531 err("function should take exactly 1 argument");
532 }
533
534 if (!symbolp(car(args)))
535 {
swissChili7e1393c2021-07-07 12:59:12 -0700536 err("argument to function should be a symbol resolvable at "
537 "compile time");
swissChili74348422021-07-04 13:23:24 -0700538 }
539
swissChili7e1393c2021-07-07 12:59:12 -0700540 struct function *f =
541 find_function(env, (char *)(car(args) ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -0700542 value_t closure = create_closure(f->code_ptr, f->args, 0);
swissChili74348422021-07-04 13:23:24 -0700543
544 | mov eax, (closure);
545 }
swissChili6b47b6d2021-06-30 22:08:55 -0700546 else if (symstreq(fsym, "list"))
547 {
swissChili484295d2021-07-09 21:25:55 -0700548 | push (nil);
swissChili6b47b6d2021-06-30 22:08:55 -0700549
550 for (int i = nargs - 1; i >= 0; i--)
551 {
552 compile_expression(env, local, elt(args, i), Dst);
553
554 // push the ith item
555 | push eax;
556 // cons the top two stack items
557 | mov ebx, (cons);
558 | call ebx;
559 // remove the stack items from use
560 | add esp, (2 * value_size);
561 // put the new thing on the stack
562 | push eax;
563 }
564
565 | pop eax;
566 }
swissChiliddc97542021-07-04 11:47:42 -0700567 else if (symstreq(fsym, "lambda"))
568 {
569 // Compile the function with this as the parent scope
570 struct local new_local;
571 int nargs_out;
swissChili7e1393c2021-07-07 12:59:12 -0700572 dasm_State *d = compile_function(
573 args, NS_ANONYMOUS, env, &new_local, local, &nargs_out,
574 "recurse", local->current_file_path);
swissChiliddc97542021-07-04 11:47:42 -0700575
576 // Link the function
swissChilif68671f2021-07-05 14:14:44 -0700577 void *func_ptr = link_program(&d);
swissChiliddc97542021-07-04 11:47:42 -0700578
579 // Create a closure object with the correct number of captures at
580 // runtime
swissChili484295d2021-07-09 21:25:55 -0700581 | push (new_local.num_closure_slots);
582 | push (nargs_out);
583 | push (func_ptr);
swissChili74348422021-07-04 13:23:24 -0700584 | mov ebx, (create_closure);
swissChiliddc97542021-07-04 11:47:42 -0700585 | call ebx;
586 | add esp, 12;
587
588 // Walk the generated local scope for V_FREE variables, since each
589 // of these exists in our scope (or higher), evaluate it and set it
590 // as a member of the lambda capture.
591
592 for (struct variable *var = new_local.first; var; var = var->prev)
593 {
594 if (var->type == V_FREE)
595 {
596 // Closure in eax
597 | push eax;
598 // Variable now in eax
599 compile_variable(find_variable(local, var->name), Dst);
600 | push eax;
601
swissChiliddc97542021-07-04 11:47:42 -0700602 // The capture offset
swissChili484295d2021-07-09 21:25:55 -0700603 | push (var->number);
swissChili74348422021-07-04 13:23:24 -0700604 | mov ebx, (set_closure_capture_variable);
swissChiliddc97542021-07-04 11:47:42 -0700605 | call ebx;
606 // Skip the value and index
607 | add esp, 8;
608 // Pop the closure back in to eax
609 | pop eax;
610 }
611 }
612
613 // Closure is still in eax
614
615 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700616 del_local(&new_local);
swissChiliddc97542021-07-04 11:47:42 -0700617 }
swissChili7e1393c2021-07-07 12:59:12 -0700618 else if (symstreq(fsym, "eval"))
619 {
620 if (nargs != 1)
621 {
622 err("eval takes exactly 1 argument");
623 }
624
625 compile_expression(env, local, car(args), Dst);
626 | push eax;
swissChili484295d2021-07-09 21:25:55 -0700627 | push (env);
swissChili7e1393c2021-07-07 12:59:12 -0700628 | mov ebx, (eval);
629 | call ebx;
630 }
631 else if (symstreq(fsym, "load"))
632 {
633 if (nargs != 1)
634 {
635 err_at(val, "load takes exactly 1 argument, %d given", nargs);
636 }
637
638 compile_expression(env, local, car(args), Dst);
639 | push eax;
swissChili484295d2021-07-09 21:25:55 -0700640 | push (local->current_file_path);
641 | push (env);
swissChili7e1393c2021-07-07 12:59:12 -0700642 | mov ebx, (load_relative);
643 | call ebx;
644 }
swissChili53472e82021-05-08 16:06:32 -0700645 else
646 {
swissChili74348422021-07-04 13:23:24 -0700647 char *name = (char *)(fsym ^ SYMBOL_TAG);
648 struct function *func = find_function(env, name);
swissChili7e1393c2021-07-07 12:59:12 -0700649
swissChili74348422021-07-04 13:23:24 -0700650 bool is_recursive = false;
swissChili15f1cae2021-07-05 19:08:47 -0700651 struct args *nargs_needed = NULL;
swissChili53472e82021-05-08 16:06:32 -0700652
swissChili7e1393c2021-07-07 12:59:12 -0700653 if (local->current_function_name &&
654 symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700655 {
swissChili74348422021-07-04 13:23:24 -0700656 is_recursive = true;
swissChili15f1cae2021-07-05 19:08:47 -0700657 nargs_needed = local->args;
swissChili74348422021-07-04 13:23:24 -0700658 }
659 else
660 {
661 if (func == NULL)
662 {
swissChili7e1393c2021-07-07 12:59:12 -0700663 err_at(val, "Function %s undefined", name);
swissChili74348422021-07-04 13:23:24 -0700664 }
665
swissChili15f1cae2021-07-05 19:08:47 -0700666 nargs_needed = func->args;
swissChili74348422021-07-04 13:23:24 -0700667 }
668
swissChili15f1cae2021-07-05 19:08:47 -0700669 if (!are_args_acceptable(nargs_needed, nargs))
swissChili74348422021-07-04 13:23:24 -0700670 {
swissChili7e1393c2021-07-07 12:59:12 -0700671 err_at(val,
672 "wrong number of args in function call: %s at %s:%d, "
673 "want %d args but given %d\n",
674 name, cons_file(val), cons_line(val),
675 nargs_needed->num_required, nargs);
swissChilif1ba8c12021-07-02 18:45:38 -0700676 }
swissChili53472e82021-05-08 16:06:32 -0700677
swissChili74348422021-07-04 13:23:24 -0700678 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700679 {
swissChili15f1cae2021-07-05 19:08:47 -0700680 int nargs = length(args);
swissChili484295d2021-07-09 21:25:55 -0700681 int total_taken = nargs_needed->num_optional +
682 nargs_needed->num_required;
swissChili15f1cae2021-07-05 19:08:47 -0700683
swissChili484295d2021-07-09 21:25:55 -0700684 int line = cons_line(val);
685 char *file = cons_file(val);
686
687 if (nargs_needed->variadic)
swissChili15f1cae2021-07-05 19:08:47 -0700688 {
swissChili484295d2021-07-09 21:25:55 -0700689 | push (nil);
690 }
691
692 if (nargs > total_taken && nargs_needed->variadic)
693 {
694 // We are passing varargs, which means we need to make a list
695
696 for (int i = nargs - 1; i >= total_taken; i--)
697 {
698 compile_expression(env, local, elt(args, i), Dst);
699 | push eax;
700 | mov ebx, (cons);
701 | call ebx;
702 | add esp, 8;
703 | push eax;
704 }
swissChili15f1cae2021-07-05 19:08:47 -0700705 }
706
swissChili7e1393c2021-07-07 12:59:12 -0700707 for (int i = nargs_needed->num_optional - 1;
708 i >= nargs - nargs_needed->num_required; i--)
swissChili15f1cae2021-07-05 19:08:47 -0700709 {
710 // Push the default optional values
swissChili484295d2021-07-09 21:25:55 -0700711 | push (nargs_needed->optional_arguments[i].value);
swissChili15f1cae2021-07-05 19:08:47 -0700712 }
713
swissChili484295d2021-07-09 21:25:55 -0700714 int min = MIN(nargs, total_taken);
715
716 for (int i = min - 1; i >= 0; i--)
swissChili2999dd12021-07-02 14:19:53 -0700717 {
718 compile_expression(env, local, elt(args, i), Dst);
719 | push eax;
720 }
swissChili15f1cae2021-07-05 19:08:47 -0700721
swissChili74348422021-07-04 13:23:24 -0700722 if (is_recursive)
723 {
swissChili484295d2021-07-09 21:25:55 -0700724 | call ->function_start;
swissChili74348422021-07-04 13:23:24 -0700725 }
726 else
727 {
swissChili484295d2021-07-09 21:25:55 -0700728 // | mov ebx, (func->code_addr);
729 | call_extern func->code_addr;
swissChili74348422021-07-04 13:23:24 -0700730 }
swissChili2999dd12021-07-02 14:19:53 -0700731 | add esp, (nargs * value_size);
732 // result in eax
733 }
734 else if (func->namespace == NS_MACRO)
735 {
swissChili7e1393c2021-07-07 12:59:12 -0700736 // Make sure that the stuff allocated by the macro isn't in a
737 // pool
swissChilif68671f2021-07-05 14:14:44 -0700738 unsigned char pool = push_pool(0);
739
swissChili2999dd12021-07-02 14:19:53 -0700740 value_t expanded_to = call_list(func, args);
741
swissChilif68671f2021-07-05 14:14:44 -0700742 pop_pool(pool);
743
swissChili2999dd12021-07-02 14:19:53 -0700744 compile_expression(env, local, expanded_to, Dst);
745 }
swissChili53472e82021-05-08 16:06:32 -0700746 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700747 }
swissChili923b5362021-05-09 20:31:43 -0700748 else if (symbolp(val))
749 {
swissChili7e1393c2021-07-07 12:59:12 -0700750 if (symstreq(val, "+current-file+"))
swissChilie9fec8b2021-06-22 13:59:33 -0700751 {
swissChili7e1393c2021-07-07 12:59:12 -0700752 value_t file_name_val = strval(local->current_file_path);
753
754 | mov eax, (file_name_val);
swissChilie9fec8b2021-06-22 13:59:33 -0700755 }
swissChili7e1393c2021-07-07 12:59:12 -0700756 else
757 {
758 struct variable *v =
759 find_variable(local, (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700760
swissChili7e1393c2021-07-07 12:59:12 -0700761 if (!v)
762 {
763 fprintf(stderr, "var: %s\n", (char *)(val ^ SYMBOL_TAG));
764 err("Variable unbound");
765 }
766
767 compile_variable(v, Dst);
768 }
swissChili923b5362021-05-09 20:31:43 -0700769 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700770}
swissChilif3e7f182021-04-20 13:57:22 -0700771
swissChili923b5362021-05-09 20:31:43 -0700772struct variable *add_variable(struct local *local, enum var_type type,
773 char *name, int number)
774{
775 struct variable *var = malloc(sizeof(struct variable));
776 var->prev = local->first;
777 var->type = type;
778 var->name = name;
779 var->number = number;
780
781 local->first = var;
782
783 return var;
784}
785
786void destroy_local(struct local *local)
787{
788 for (struct variable *v = local->first; v;)
789 {
790 struct variable *t = v;
791 v = v->prev;
792 free(t);
793 }
794}
795
796struct variable *find_variable(struct local *local, char *name)
797{
798 struct variable *v = local->first;
799
800 for (; v && strcmp(v->name, name) != 0; v = v->prev)
swissChili7e1393c2021-07-07 12:59:12 -0700801 {
802 }
swissChili923b5362021-05-09 20:31:43 -0700803
swissChiliddc97542021-07-04 11:47:42 -0700804 if (!v)
805 {
806 if (local->parent)
807 {
808 v = find_variable(local->parent, name);
809
810 if (v)
811 {
swissChili15f1cae2021-07-05 19:08:47 -0700812 // We found this in a parent scope, add it as a V_FREE variable
813 // to skip the search.
swissChili7e1393c2021-07-07 12:59:12 -0700814 v = add_variable(local, V_FREE, name,
815 local->num_closure_slots++);
swissChiliddc97542021-07-04 11:47:42 -0700816 }
817 }
818 }
swissChili923b5362021-05-09 20:31:43 -0700819 return v;
820}
swissChili2999dd12021-07-02 14:19:53 -0700821
swissChiliddc97542021-07-04 11:47:42 -0700822extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -0700823
swissChili7e1393c2021-07-07 12:59:12 -0700824value_t call_list_args(void *code_ptr, struct args *args, value_t list,
825 void *data)
swissChili2999dd12021-07-02 14:19:53 -0700826{
swissChili15f1cae2021-07-05 19:08:47 -0700827 list = deep_copy(list);
swissChili484295d2021-07-09 21:25:55 -0700828
swissChili15f1cae2021-07-05 19:08:47 -0700829 int nargs = length(list);
830
swissChili484295d2021-07-09 21:25:55 -0700831 printf("IN call_list_args\n");
832 printval(list, 2);
833
834 value_t *val = &list;
swissChili15f1cae2021-07-05 19:08:47 -0700835
836 for (value_t i = list; !nilp(i); i = cdr(i))
837 {
838 val = cdrref(i);
839 }
840
841 int total_required = args->num_required + args->num_optional;
842
843 if (nargs > total_required)
844 {
845 // Take the remainder of the list and put it as the last item in the
846 // list.
847 value_t trailing = cxdr(list, total_required);
848 value_t last_item = cons(trailing, nil);
849
850 *cxdrref(&list, total_required) = last_item;
851 }
852 else if (nargs < total_required)
853 {
854 for (int i = nargs - args->num_required; i < args->num_optional; i++)
855 {
856 // Append the i-th defualt argument
857 value_t appended = cons(args->optional_arguments[i].value, nil);
858 *val = appended;
859 val = cdrref(appended);
860 }
861 }
862
863 // We want to call this if we pass the correct # of arguments or less, just
864 // not if we have already passed varargs. Appends a nil argument.
865 if (nargs <= total_required)
866 {
867 // Enough real arguments but no variadic arguments. Pass a nil list.
868 *val = cons(nil, nil);
869 }
870
871 return _call_list(code_ptr, list, data);
872}
873
874value_t call_list(struct function *fun, value_t list)
875{
876 return call_list_args(fun->code_ptr, fun->args, list, NULL);
swissChiliddc97542021-07-04 11:47:42 -0700877}
878
879value_t call_list_closure(struct closure *c, value_t list)
880{
swissChili15f1cae2021-07-05 19:08:47 -0700881 return call_list_args(c->function, c->args, list, c->data);
882}
883
884struct args *new_args()
885{
886 struct args *a = malloc(sizeof(struct args));
887 a->num_optional = 0;
888 a->num_required = 0;
889 a->variadic = false;
890
891 return a;
892}
893
swissChili7e1393c2021-07-07 12:59:12 -0700894struct args *add_optional_arg(struct args *args, value_t name, value_t value)
swissChili15f1cae2021-07-05 19:08:47 -0700895{
896 int i = args->num_optional++;
swissChili7e1393c2021-07-07 12:59:12 -0700897 args =
898 realloc(args, sizeof(struct args) + sizeof(struct optional_argument) *
899 args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -0700900
swissChili7e1393c2021-07-07 12:59:12 -0700901 args->optional_arguments[i] = (struct optional_argument){
902 .value = value,
903 .name = name,
swissChili15f1cae2021-07-05 19:08:47 -0700904 };
905
906 return args;
907}
908
909bool are_args_acceptable(struct args *args, int number)
910{
911 if (args->variadic)
912 {
913 return number >= args->num_required;
914 }
915 else
916 {
917 return number >= args->num_required &&
swissChili7e1393c2021-07-07 12:59:12 -0700918 number <= args->num_required + args->num_optional;
swissChili15f1cae2021-07-05 19:08:47 -0700919 }
920}
921
swissChili7e1393c2021-07-07 12:59:12 -0700922struct args *list_to_args(struct environment *env, value_t list,
923 struct local *local)
swissChili15f1cae2021-07-05 19:08:47 -0700924{
925 struct args *args = new_args();
926
927 bool in_optional = false;
928
929 for (value_t i = list; !nilp(i); i = cdr(i))
930 {
931 value_t val = car(i);
932 if (symbolp(val))
933 {
934 if (!args->variadic && symstreq(val, "&"))
935 {
936 i = cdr(i);
937 value_t name = car(i);
938
939 if (!symbolp(name))
940 {
swissChili7e1393c2021-07-07 12:59:12 -0700941 err("You must provide a symbol after & in an argument list "
942 "to bind the\n"
943 "variadic arguments to.");
swissChili15f1cae2021-07-05 19:08:47 -0700944 }
945
946 args->variadic = true;
947
948 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
swissChili7e1393c2021-07-07 12:59:12 -0700949 args->num_optional + args->num_required);
swissChili15f1cae2021-07-05 19:08:47 -0700950
951 continue;
952 }
953
954 if (!in_optional)
955 {
swissChili7e1393c2021-07-07 12:59:12 -0700956 add_variable(local, V_ARGUMENT, (char *)(val ^ SYMBOL_TAG),
957 args->num_required++);
swissChili15f1cae2021-07-05 19:08:47 -0700958 }
959 else
960 {
961 char *name = (char *)(val ^ SYMBOL_TAG);
962 if (name[0] == '&')
963 {
swissChili7e1393c2021-07-07 12:59:12 -0700964 err("Non-optional argument following optional arguments "
965 "starts with a &\n"
966 "did you mean to declare a variadic argument? If so "
967 "leave a space\n"
968 "between the & and name.");
swissChili15f1cae2021-07-05 19:08:47 -0700969 }
970 else
971 {
swissChili7e1393c2021-07-07 12:59:12 -0700972 err("Cannot define a non-optional argument after an "
973 "optional one.");
swissChili15f1cae2021-07-05 19:08:47 -0700974 }
975 }
976 }
977 else if (listp(val))
978 {
979 in_optional = true;
980 int len = length(val);
981
982 if (len != 2)
983 {
swissChili7e1393c2021-07-07 12:59:12 -0700984 err("A list defining an optional value must be structured like "
985 "(name expr)\n"
986 "with exactly two arguments.");
swissChili15f1cae2021-07-05 19:08:47 -0700987 }
988
989 value_t name = car(val);
990 value_t expr = car(cdr(val));
991
992 value_t function = cons(nil, cons(expr, nil));
993
swissChili7e1393c2021-07-07 12:59:12 -0700994 dasm_State *d =
995 compile_function(function, NS_ANONYMOUS, env, NULL, NULL, NULL,
996 NULL, local->current_file_path);
swissChili15f1cae2021-07-05 19:08:47 -0700997
998 // TODO: GC stack top!
999 value_t (*compiled)() = link_program(&d);
1000
1001 value_t value = compiled();
1002 args = add_optional_arg(args, name, value);
1003
swissChili7e1393c2021-07-07 12:59:12 -07001004 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
1005 args->num_required + args->num_optional - 1);
swissChili15f1cae2021-07-05 19:08:47 -07001006 }
1007 }
1008
1009 return args;
1010}
1011
1012void display_args(struct args *args)
1013{
1014 printf("Args object taking %d require arguments and %d optionals:\n",
swissChili7e1393c2021-07-07 12:59:12 -07001015 args->num_required, args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -07001016
1017 for (int i = 0; i < args->num_optional; i++)
1018 {
swissChili7e1393c2021-07-07 12:59:12 -07001019 printf(" %d\t%s\n", i,
1020 (char *)(args->optional_arguments[i].name ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -07001021 printval(args->optional_arguments[i].value, 2);
1022 }
swissChili2999dd12021-07-02 14:19:53 -07001023}