blob: bfe74e14dbf22963bce300970eb792e9c4c3a023 [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;
swissChili53e7cd12021-08-02 21:55:53 -070022|1:;
swissChili484295d2021-07-09 21:25:55 -070023| 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;
swissChili53e7cd12021-08-02 21:55:53 -070035| call &address;
swissChili67bdf282021-06-06 18:46:08 -070036|.endmacro;
37
swissChilica107a02021-04-14 12:07:30 -070038dasm_State *d;
39unsigned int npc = 8;
40
swissChili9e57da42021-06-15 22:22:46 -070041|.macro run_gc;
swissChilie9fec8b2021-06-22 13:59:33 -070042| mov eax, esp;
swissChili9e57da42021-06-15 22:22:46 -070043| push ebp;
swissChilie9fec8b2021-06-22 13:59:33 -070044| push eax;
swissChili9e57da42021-06-15 22:22:46 -070045| mov eax, _do_gc;
46| call eax;
47|.endmacro;
swissChili6d6525e2021-06-15 21:20:53 -070048
swissChili53472e82021-05-08 16:06:32 -070049struct function *find_function(struct environment *env, char *name)
swissChilica107a02021-04-14 12:07:30 -070050{
swissChilif68671f2021-07-05 14:14:44 -070051 struct function *f;
swissChilica107a02021-04-14 12:07:30 -070052
swissChilif68671f2021-07-05 14:14:44 -070053 for (f = env->first; f && strcmp(f->name, name); f = f->prev)
swissChilica107a02021-04-14 12:07:30 -070054 {
swissChilica107a02021-04-14 12:07:30 -070055 }
56
57 return f;
58}
59
swissChili67bdf282021-06-06 18:46:08 -070060unsigned int local_alloc(struct local *local)
61{
62 for (int i = 0; i < local->num_stack_slots; i++)
63 {
64 if (local->stack_slots[i] == false)
65 {
66 local->stack_slots[i] = true;
67
68 if (i >= local->num_stack_entries)
69 local->num_stack_entries++;
70
71 return i;
72 }
73 }
74
75 int old_size = local->num_stack_slots;
76 local->num_stack_slots += 4;
swissChili7e1393c2021-07-07 12:59:12 -070077 local->stack_slots =
78 realloc(local->stack_slots, local->num_stack_slots * sizeof(bool));
swissChili67bdf282021-06-06 18:46:08 -070079 // unreadable: set the remaining slots to unused
80 memset(local->stack_slots + old_size, 0, local->num_stack_slots - old_size);
81 local->stack_slots[old_size] = true;
82
83 return old_size;
84}
85
86void local_free(struct local *local, unsigned int slot)
87{
88 local->stack_slots[slot] = false;
89}
90
swissChili708d4c42021-07-04 17:40:07 -070091void del_local(struct local *local)
92{
93 free(local->stack_slots);
94
95 for (struct variable *next, *f = local->first; f; f = next)
96 {
97 next = f->prev;
98 free(f);
99 }
100}
101
102void del_env(struct environment *env)
103{
104 for (struct function *next, *f = env->first; f; f = next)
105 {
106 next = f->prev;
107 // We're not gonna bother munmap()ing the function
108 free(f);
109 }
swissChilif68671f2021-07-05 14:14:44 -0700110
111 for (struct loaded_file *next, *l = env->first_loaded; l; l = next)
112 {
113 next = l->previous;
114 free(l->resolved_path);
115 free(l);
116 }
swissChili7e1393c2021-07-07 12:59:12 -0700117
118 free(env);
swissChilif68671f2021-07-05 14:14:44 -0700119}
120
121void add_load(struct environment *env, char *path)
122{
123 static char buffer[512];
124 long size = readlink(path, buffer, 512);
125 buffer[size] = '\0';
126 char *resolved = strdup(buffer);
127
128 struct loaded_file *f = malloc(sizeof(struct loaded_file));
129 f->resolved_path = resolved;
130 f->previous = env->first_loaded;
131 env->first_loaded = f;
swissChili708d4c42021-07-04 17:40:07 -0700132}
133
swissChili6d02af42021-08-05 19:49:01 -0700134struct error compile_function(value_t args, enum namespace namespace,
135 struct environment *env,
136 struct local *local_out,
137 struct local *local_parent,
138 struct args **args_out, char *name,
139 char *path,
140 dasm_State **state)
swissChilif1ba8c12021-07-02 18:45:38 -0700141{
swissChilia7568dc2021-08-08 16:52:52 -0700142 UNUSED(namespace);
143
swissChili6d02af42021-08-05 19:49:01 -0700144 E_INIT();
145
swissChilif1ba8c12021-07-02 18:45:38 -0700146 dasm_State *d;
147 dasm_State **Dst = &d;
148
swissChili484295d2021-07-09 21:25:55 -0700149 |.section code, imports;
swissChilif1ba8c12021-07-02 18:45:38 -0700150 dasm_init(&d, DASM_MAXSECTION);
151
152 |.globals lbl_;
153 void *labels[lbl__MAX];
154 dasm_setupglobal(&d, labels, lbl__MAX);
155
156 |.actionlist lisp_actions;
157 dasm_setup(&d, lisp_actions);
158
159 struct local local;
160 local.parent = NULL;
161 local.first = NULL;
162 local.num_vars = 0;
163 local.npc = 8;
164 local.nextpc = 0;
165 local.stack_slots = malloc(sizeof(bool) * 4);
166 memset(local.stack_slots, 0, sizeof(bool) * 4);
167 local.num_stack_slots = 4;
168 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700169 local.num_closure_slots = 0;
170 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700171 local.current_function_name = name;
swissChili7e1393c2021-07-07 12:59:12 -0700172 local.current_file_path = path;
swissChilif1ba8c12021-07-02 18:45:38 -0700173
174 dasm_growpc(&d, local.npc);
175
swissChilif1ba8c12021-07-02 18:45:38 -0700176 value_t arglist = car(args);
177 value_t body = cdr(args);
178
swissChili15f1cae2021-07-05 19:08:47 -0700179 // This will add the arguments to local too.
swissChili6d02af42021-08-05 19:49:01 -0700180 struct args *ar;
181 TRY(list_to_args(env, arglist, &local, &ar));
swissChili15f1cae2021-07-05 19:08:47 -0700182 local.args = ar;
swissChili74348422021-07-04 13:23:24 -0700183
swissChili15f1cae2021-07-05 19:08:47 -0700184 if (!ar)
swissChilif1ba8c12021-07-02 18:45:38 -0700185 {
swissChili6d02af42021-08-05 19:49:01 -0700186 NEARVAL(arglist);
187 THROW(EMALFORMED, "Malformed argument list");
swissChilif1ba8c12021-07-02 18:45:38 -0700188 }
189
190 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
191 {
swissChilifc5c9412021-08-08 19:08:26 -0700192 TRY(walk_and_alloc(env, &local, carref(body_), false));
swissChilif1ba8c12021-07-02 18:45:38 -0700193 }
194
swissChili484295d2021-07-09 21:25:55 -0700195 | setup (local.num_stack_entries);
swissChilif1ba8c12021-07-02 18:45:38 -0700196
197 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
198 local.num_stack_entries = 0;
199
200 for (; !nilp(body); body = cdr(body))
201 {
swissChilib51552c2021-08-03 10:23:37 -0700202 bool tail = nilp(cdr(body));
swissChili6d02af42021-08-05 19:49:01 -0700203 TRY(compile_expression(env, &local, car(body), tail, Dst));
swissChilif1ba8c12021-07-02 18:45:38 -0700204 }
205
206 | cleanup;
207
208 if (local_out)
209 *local_out = local;
210
swissChili15f1cae2021-07-05 19:08:47 -0700211 if (args_out)
212 *args_out = ar;
swissChilif1ba8c12021-07-02 18:45:38 -0700213
swissChili6d02af42021-08-05 19:49:01 -0700214 *state = d;
215
216 OKAY();
swissChilif1ba8c12021-07-02 18:45:38 -0700217}
218
swissChili6d02af42021-08-05 19:49:01 -0700219struct error compile_tl(value_t val, struct environment *env, char *fname)
swissChilica107a02021-04-14 12:07:30 -0700220{
swissChili6d02af42021-08-05 19:49:01 -0700221 E_INIT();
222
223 NEARVAL(val);
224
swissChili53472e82021-05-08 16:06:32 -0700225 if (!listp(val))
swissChili6d02af42021-08-05 19:49:01 -0700226 {
227 THROW(EEXPECTED, "Top level form must be a list");
228 }
swissChilica107a02021-04-14 12:07:30 -0700229
swissChili53472e82021-05-08 16:06:32 -0700230 value_t form = car(val);
231 value_t args = cdr(val);
232
swissChili2999dd12021-07-02 14:19:53 -0700233 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700234 {
swissChili2999dd12021-07-02 14:19:53 -0700235 enum namespace namespace = NS_FUNCTION;
236
237 if (symstreq(form, "defmacro"))
swissChilia89ee442021-08-04 20:54:51 -0700238 namespace = NS_MACRO;
swissChili2999dd12021-07-02 14:19:53 -0700239
swissChili8fc5e2f2021-04-22 13:45:10 -0700240 struct local local;
swissChili15f1cae2021-07-05 19:08:47 -0700241 struct args *a;
swissChili74348422021-07-04 13:23:24 -0700242 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChilif68671f2021-07-05 14:14:44 -0700243
swissChili6d02af42021-08-05 19:49:01 -0700244 dasm_State *d;
245 TRY(compile_function(cdr(args), namespace, env, &local,
246 NULL, &a, name, fname, &d));
swissChilia820dea2021-05-09 16:46:55 -0700247
swissChili7e1393c2021-07-07 12:59:12 -0700248 add_function(env, name, link_program(&d), a, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700249
swissChili53472e82021-05-08 16:06:32 -0700250 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700251 del_local(&local);
swissChili67bdf282021-06-06 18:46:08 -0700252 }
swissChilif68671f2021-07-05 14:14:44 -0700253 else if (symstreq(form, "progn"))
254 {
255 for (value_t val = args; !nilp(val); val = cdr(val))
256 {
swissChili6d02af42021-08-05 19:49:01 -0700257 TRY(compile_tl(car(val), env, fname));
swissChilif68671f2021-07-05 14:14:44 -0700258 }
259 }
swissChili484295d2021-07-09 21:25:55 -0700260 else if (symstreq(form, "load"))
261 {
262 if (length(args) != 1)
263 {
swissChili6d02af42021-08-05 19:49:01 -0700264 NEARVAL(args);
265 THROW(EARGS, "load expects exactly 1 argument, %d given",
266 length(args));
swissChili484295d2021-07-09 21:25:55 -0700267 }
268 load_relative(env, fname, car(args));
269 }
swissChili6d02af42021-08-05 19:49:01 -0700270
271 OKAY();
swissChili67bdf282021-06-06 18:46:08 -0700272}
273
swissChilifc5c9412021-08-08 19:08:26 -0700274struct error walk_and_alloc(struct environment *env, struct local *local, value_t *bp, bool quoted)
swissChili67bdf282021-06-06 18:46:08 -0700275{
swissChilifc5c9412021-08-08 19:08:26 -0700276 // Note: this kind of sucks. Some of the quote-handling code is
277 // duplicated here and compile_expression. TODO: refactor
278 // eventually.
279
swissChili36f2c692021-08-08 14:31:44 -0700280 E_INIT();
281
282 value_t body = *bp;
283
swissChili67bdf282021-06-06 18:46:08 -0700284 if (!listp(body))
swissChili36f2c692021-08-08 14:31:44 -0700285 OKAY();
swissChili67bdf282021-06-06 18:46:08 -0700286
287 value_t args = cdr(body);
288
swissChilifc5c9412021-08-08 19:08:26 -0700289 if (!quoted && symstreq(car(body), "let1"))
swissChili67bdf282021-06-06 18:46:08 -0700290 {
291 int slot = local_alloc(local);
292
293 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700294 for (; !nilp(expr); expr = cdr(expr))
295 {
swissChilifc5c9412021-08-08 19:08:26 -0700296 walk_and_alloc(env, local, carref(expr), false);
swissChilif1ba8c12021-07-02 18:45:38 -0700297 }
swissChili67bdf282021-06-06 18:46:08 -0700298
299 local_free(local, slot);
300 }
swissChilifc5c9412021-08-08 19:08:26 -0700301 else if (!quoted && symstreq(car(body), "lambda"))
swissChilif1ba8c12021-07-02 18:45:38 -0700302 {
303 // We don't want to walk the lambda because it's another function. When
304 // the lambda is compiled it will be walked.
swissChili36f2c692021-08-08 14:31:44 -0700305 OKAY();
swissChilif1ba8c12021-07-02 18:45:38 -0700306 }
swissChili67bdf282021-06-06 18:46:08 -0700307 else
308 {
swissChilifc5c9412021-08-08 19:08:26 -0700309 if (quoted)
swissChili67bdf282021-06-06 18:46:08 -0700310 {
swissChilifc5c9412021-08-08 19:08:26 -0700311 if (symstreq(car(body), "unquote") || symstreq(car(body), "unquote-splice"))
312 {
313 for (value_t b = cdr(body); !nilp(b); b = cdr(b))
314 {
315 walk_and_alloc(env, local, carref(b), false);
316 }
317 }
swissChili36f2c692021-08-08 14:31:44 -0700318 }
319 else
320 {
swissChilifc5c9412021-08-08 19:08:26 -0700321 // Is this a macro?
322
323 struct function *mac = NULL;
324
325 if (symbolp(car(body)))
326 mac = find_function(env, (char *)(car(body) ^ SYMBOL_TAG));
327 else if (consp(car(body))) // consp, not just listp, since we don't care about nil.
328 walk_and_alloc(env, local, carref(body), false);
329
330 if (mac && mac->namespace == NS_MACRO)
swissChili36f2c692021-08-08 14:31:44 -0700331 {
swissChilifc5c9412021-08-08 19:08:26 -0700332 unsigned char pool = push_pool(0);
333 value_t form = call_list(mac, args);
334 pop_pool(pool);
335
336 add_to_pool(form);
337 *bp = form;
338
339 walk_and_alloc(env, local, bp, false);
340 }
341 else
342 {
343 bool should_quote = symstreq(car(body), "quote") || symstreq(car(body), "backquote");
344
345 for (; !nilp(args); args = cdr(args))
346 {
347 walk_and_alloc(env, local, carref(args), should_quote);
348 }
swissChili36f2c692021-08-08 14:31:44 -0700349 }
swissChili67bdf282021-06-06 18:46:08 -0700350 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700351 }
swissChili36f2c692021-08-08 14:31:44 -0700352
353 OKAY();
swissChili8fc5e2f2021-04-22 13:45:10 -0700354}
355
swissChilif68671f2021-07-05 14:14:44 -0700356bool load(struct environment *env, char *path)
swissChili8fc5e2f2021-04-22 13:45:10 -0700357{
swissChilif68671f2021-07-05 14:14:44 -0700358 if (!file_exists(path))
359 return false;
360
361 add_load(env, path);
362
swissChilib8fd4712021-06-23 15:32:04 -0700363 unsigned char pool = make_pool();
364 unsigned char pop = push_pool(pool);
365
swissChilif68671f2021-07-05 14:14:44 -0700366 struct istream *is = new_fistream(path, false);
367 if (!is)
368 return false;
369
swissChili8fc5e2f2021-04-22 13:45:10 -0700370 value_t val;
swissChili53472e82021-05-08 16:06:32 -0700371
swissChilifc5c9412021-08-08 19:08:26 -0700372 struct error compile_error, read_error;
swissChili36f2c692021-08-08 14:31:44 -0700373
374 while (IS_OKAY((read_error = read1(is, &val))))
swissChili8fc5e2f2021-04-22 13:45:10 -0700375 {
swissChilifc5c9412021-08-08 19:08:26 -0700376 if (!IS_OKAY((compile_error = compile_tl(val, env, path))))
swissChili36f2c692021-08-08 14:31:44 -0700377 {
swissChilifc5c9412021-08-08 19:08:26 -0700378 ereport(compile_error);
swissChili36f2c692021-08-08 14:31:44 -0700379 goto failure;
380 }
381 }
382
383 if (!read_error.safe_state)
384 {
385 goto failure;
swissChili8fc5e2f2021-04-22 13:45:10 -0700386 }
swissChilif3e7f182021-04-20 13:57:22 -0700387
swissChilif68671f2021-07-05 14:14:44 -0700388 del_fistream(is);
swissChilib8fd4712021-06-23 15:32:04 -0700389 pop_pool(pop);
390
swissChilif68671f2021-07-05 14:14:44 -0700391 return true;
swissChili36f2c692021-08-08 14:31:44 -0700392
393failure:
394 del_fistream(is);
395 pop_pool(pool);
396
397 return false;
swissChilif68671f2021-07-05 14:14:44 -0700398}
399
swissChili7e1393c2021-07-07 12:59:12 -0700400value_t load_relative(struct environment *env, char *to, value_t name)
401{
402 if (!stringp(name))
403 return nil;
404
405 char *new_path = (char *)(name ^ STRING_TAG);
406 char *relative_to = strdup(to);
407 char full_path[512];
408
409 snprintf(full_path, 512, "%s/%s", dirname(relative_to), new_path);
410
411 if (load(env, full_path))
412 return t;
413 else
414 return nil;
415}
416
swissChili6d02af42021-08-05 19:49:01 -0700417struct error compile_file(char *filename, struct environment **e)
swissChilif68671f2021-07-05 14:14:44 -0700418{
swissChili6d02af42021-08-05 19:49:01 -0700419 E_INIT();
420
swissChilif68671f2021-07-05 14:14:44 -0700421 value_t val;
swissChili7e1393c2021-07-07 12:59:12 -0700422 struct environment *env = malloc(sizeof(struct environment));
423 env->first = NULL;
424 env->first_loaded = NULL;
swissChilif68671f2021-07-05 14:14:44 -0700425
swissChili7e1393c2021-07-07 12:59:12 -0700426 add_load(env, filename);
swissChili6d02af42021-08-05 19:49:01 -0700427 TRY(load_std(env));
swissChilif68671f2021-07-05 14:14:44 -0700428
swissChili7e1393c2021-07-07 12:59:12 -0700429 bool ok_ = load(env, filename);
swissChilif68671f2021-07-05 14:14:44 -0700430
swissChili6d02af42021-08-05 19:49:01 -0700431 if (!ok_)
432 {
433 free(env);
swissChili1e8b7562021-12-22 21:22:57 -0800434 NEARFL(filename, 1);
swissChili6d02af42021-08-05 19:49:01 -0700435 THROWSAFE(ENOTFOUND);
436 }
swissChilif68671f2021-07-05 14:14:44 -0700437
swissChili6d02af42021-08-05 19:49:01 -0700438 *e = env;
439
440 OKAY();
swissChilica107a02021-04-14 12:07:30 -0700441}
swissChilib3ca4fb2021-04-20 10:33:00 -0700442
swissChili53472e82021-05-08 16:06:32 -0700443int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700444{
swissChili53472e82021-05-08 16:06:32 -0700445 int n = local->nextpc++;
446 if (n > local->npc)
447 {
448 local->npc += 16;
449 dasm_growpc(Dst, local->npc);
450 }
451 return n;
452}
453
swissChili6d02af42021-08-05 19:49:01 -0700454struct error compile_backquote(struct environment *env, struct local *local,
455 value_t val, dasm_State **Dst)
swissChili6b47b6d2021-06-30 22:08:55 -0700456{
swissChili6d02af42021-08-05 19:49:01 -0700457 E_INIT();
458
swissChili6b47b6d2021-06-30 22:08:55 -0700459 if (!listp(val))
460 {
461 | mov eax, (val);
462 }
463 else
464 {
swissChili7e1393c2021-07-07 12:59:12 -0700465 value_t fsym = car(val), args = cdr(val);
swissChili9d151e62021-08-04 13:11:45 -0700466 int nargs = length(args),
467 n = length(val);
swissChili6b47b6d2021-06-30 22:08:55 -0700468
swissChili6d02af42021-08-05 19:49:01 -0700469 NEARVAL(val);
470
swissChili9d151e62021-08-04 13:11:45 -0700471 if (symstreq(fsym, "unquote"))
472 {
473 if (nargs != 1)
474 {
swissChili6d02af42021-08-05 19:49:01 -0700475 THROW(EARGS, "unquote (or ,) takes exactly 1 argument");
swissChili9d151e62021-08-04 13:11:45 -0700476 }
477
swissChili6d02af42021-08-05 19:49:01 -0700478 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili9d151e62021-08-04 13:11:45 -0700479 }
480 else
481 {
482 | push nil;
483
484 for (int i = n - 1; i >= 0; i--)
485 {
swissChilia7568dc2021-08-08 16:52:52 -0700486 value_t v = elt(val, i);
swissChili9d151e62021-08-04 13:11:45 -0700487
swissChilia7568dc2021-08-08 16:52:52 -0700488 if (listp(v) && symstreq(car(v), "unquote-splice"))
489 {
490 NEARVAL(v);
491
492 if (length(v) != 2)
493 {
494 THROW(EARGS, "unquote-splice (or ,@) takes exactly 1 argument");
495 }
496
497 value_t expr = car(cdr(v));
498
swissChilia7568dc2021-08-08 16:52:52 -0700499 TRY(compile_expression(env, local, expr, false, Dst));
500 | push eax;
501 | call_extern merge2;
502 | add esp, 8;
503 | push eax;
504 }
505 else
506 {
507 TRY(compile_backquote(env, local, v, Dst));
508 | push eax;
509 | call_extern cons;
510 | add esp, 8;
511
512 // Remove unnecessary pop
513 | push eax;
514 }
swissChili9d151e62021-08-04 13:11:45 -0700515 }
swissChilia89ee442021-08-04 20:54:51 -0700516 | pop eax;
swissChili9d151e62021-08-04 13:11:45 -0700517 }
swissChili6b47b6d2021-06-30 22:08:55 -0700518 }
swissChili6d02af42021-08-05 19:49:01 -0700519
520 OKAY();
swissChili6b47b6d2021-06-30 22:08:55 -0700521}
522
swissChili7e1393c2021-07-07 12:59:12 -0700523value_t eval(struct environment *env, value_t form)
524{
525 // Eval!
526 value_t function = cons(nil, cons(form, nil));
527
528 struct local local;
529 struct args *args;
530
swissChili6d02af42021-08-05 19:49:01 -0700531 dasm_State *d;
532 struct error err;
533
534 if (!IS_OKAY((err = compile_function(function, NS_ANONYMOUS, env, &local, NULL,
535 &args, NULL, "/", &d))))
536 {
537 ereport(err);
538 return nil;
539 }
swissChili7e1393c2021-07-07 12:59:12 -0700540
541 del_local(&local);
542
543 value_t (*f)() = link_program(&d);
544 return f();
545}
546
swissChili6d02af42021-08-05 19:49:01 -0700547struct error compile_variable(struct variable *v, dasm_State *Dst)
swissChiliddc97542021-07-04 11:47:42 -0700548{
swissChili6d02af42021-08-05 19:49:01 -0700549 E_INIT();
swissChiliddc97542021-07-04 11:47:42 -0700550 switch (v->type)
551 {
552 case V_ARGUMENT:
swissChili7e1393c2021-07-07 12:59:12 -0700553 | mov eax, dword[ebp + (value_size * (v->number + 2))];
swissChiliddc97542021-07-04 11:47:42 -0700554 break;
555 case V_BOUND:
swissChili7e1393c2021-07-07 12:59:12 -0700556 | mov eax, dword[ebp - ((v->number + 1) * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700557 break;
558 case V_FREE:
559 // edi is the closure context pointer
swissChili7e1393c2021-07-07 12:59:12 -0700560 | mov eax, dword[edi + (v->number * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700561 break;
562 default:
swissChili6d02af42021-08-05 19:49:01 -0700563 THROW(EUNIMPL, "Sorry, can only access V_ARGUMENT, V_BOUND, and V_FREE vars");
swissChiliddc97542021-07-04 11:47:42 -0700564 }
swissChili6d02af42021-08-05 19:49:01 -0700565 OKAY();
swissChiliddc97542021-07-04 11:47:42 -0700566}
567
swissChili6d02af42021-08-05 19:49:01 -0700568struct error compile_expression(struct environment *env, struct local *local,
569 value_t val, bool tail, dasm_State **Dst)
swissChili53472e82021-05-08 16:06:32 -0700570{
swissChili6d02af42021-08-05 19:49:01 -0700571 E_INIT();
572
573 NEARVAL(val);
574
swissChili7e1393c2021-07-07 12:59:12 -0700575 if (symstreq(val, "nil") || nilp(val))
swissChili53472e82021-05-08 16:06:32 -0700576 {
577 | mov eax, (nil);
578 }
swissChili923b5362021-05-09 20:31:43 -0700579 else if (symstreq(val, "t"))
580 {
581 | mov eax, (t);
582 }
583 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700584 {
585 | mov eax, val;
586 }
swissChili53472e82021-05-08 16:06:32 -0700587 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700588 {
swissChili53472e82021-05-08 16:06:32 -0700589 value_t fsym = car(val);
590 value_t args = cdr(val);
591 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700592
swissChili53472e82021-05-08 16:06:32 -0700593 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700594 {
swissChili6d02af42021-08-05 19:49:01 -0700595 THROW(EEXPECTED, "Function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700596 }
597
swissChili53472e82021-05-08 16:06:32 -0700598 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700599 {
swissChili53472e82021-05-08 16:06:32 -0700600 if (nargs < 2 || nargs > 3)
swissChili6d02af42021-08-05 19:49:01 -0700601 {
602 THROW(EARGS, "Must give at least 2 arguments to if");
603 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700604
swissChili6d02af42021-08-05 19:49:01 -0700605 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili53472e82021-05-08 16:06:32 -0700606 int false_label = nextpc(local, Dst),
607 after_label = nextpc(local, Dst);
608
609 // result is in eax
610 | cmp eax, (nil);
swissChili484295d2021-07-09 21:25:55 -0700611 | je =>false_label;
swissChili53472e82021-05-08 16:06:32 -0700612
swissChili6d02af42021-08-05 19:49:01 -0700613 TRY(compile_expression(env, local, elt(args, 1), tail, Dst));
swissChili484295d2021-07-09 21:25:55 -0700614 | jmp =>after_label;
615 |=>false_label:;
swissChili53472e82021-05-08 16:06:32 -0700616 if (nargs == 3)
swissChili6d02af42021-08-05 19:49:01 -0700617 TRY(compile_expression(env, local, elt(args, 2), tail, Dst));
swissChili484295d2021-07-09 21:25:55 -0700618 |=>after_label:;
swissChili53472e82021-05-08 16:06:32 -0700619 }
swissChilia89ee442021-08-04 20:54:51 -0700620 else if (symstreq(fsym, "and") || symstreq(fsym, "or"))
621 {
622 bool or = symstreq(fsym, "or"); // false == and
623
624 // Boolean and and or, short circuit like &&/||
625 if (nargs < 1)
626 {
swissChili6d02af42021-08-05 19:49:01 -0700627 THROW(EARGS, "and & or require at least 1 argument.");
swissChilia89ee442021-08-04 20:54:51 -0700628 }
629
630 int after = nextpc(local, Dst);
631
632 for (; !nilp(args); args = cdr(args))
633 {
swissChili6d02af42021-08-05 19:49:01 -0700634 NEARVAL(args);
635
636 TRY(compile_expression(env, local, car(args), false, Dst));
swissChilia89ee442021-08-04 20:54:51 -0700637 if (!nilp(cdr(args)))
638 {
639 | cmp eax, nil;
640 if (or)
641 {
swissChilifbf525f2021-08-04 21:28:07 -0700642 | jne =>after;
swissChilia89ee442021-08-04 20:54:51 -0700643 }
644 else
645 {
swissChilifbf525f2021-08-04 21:28:07 -0700646 | je =>after;
swissChilia89ee442021-08-04 20:54:51 -0700647 }
648 }
649 }
650
651 |=>after:;
652 }
swissChilif68671f2021-07-05 14:14:44 -0700653 else if (symstreq(fsym, "progn"))
654 {
655 for (value_t val = args; !nilp(val); val = cdr(val))
656 {
swissChili6d02af42021-08-05 19:49:01 -0700657 NEARVAL(args);
658
swissChilib51552c2021-08-03 10:23:37 -0700659 bool t = tail && nilp(cdr(val));
swissChili6d02af42021-08-05 19:49:01 -0700660 TRY(compile_expression(env, local, car(val), t, Dst));
swissChilif68671f2021-07-05 14:14:44 -0700661 }
662 }
swissChili67bdf282021-06-06 18:46:08 -0700663 else if (symstreq(fsym, "let1"))
664 {
665 if (nargs < 2)
666 {
swissChili6d02af42021-08-05 19:49:01 -0700667 THROW(EARGS, "Must give at least 2 arguments to let1");
swissChili67bdf282021-06-06 18:46:08 -0700668 }
669 value_t binding = car(args);
670 value_t rest = cdr(args);
671
swissChili6d02af42021-08-05 19:49:01 -0700672 NEARVAL(binding);
swissChili67bdf282021-06-06 18:46:08 -0700673 if (length(binding) != 2)
674 {
swissChili6d02af42021-08-05 19:49:01 -0700675 THROW(EARGS, "Binding list in let1 must contain exactly two entries");
swissChili67bdf282021-06-06 18:46:08 -0700676 }
677
swissChili6d02af42021-08-05 19:49:01 -0700678 NEARVAL(rest);
679
swissChili67bdf282021-06-06 18:46:08 -0700680 value_t name = car(binding);
681 value_t value = car(cdr(binding));
682
swissChili6d02af42021-08-05 19:49:01 -0700683 TRY(compile_expression(env, local, value, false, Dst));
swissChili67bdf282021-06-06 18:46:08 -0700684
685 int i = local_alloc(local);
686
687 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
688
swissChili7e1393c2021-07-07 12:59:12 -0700689 | mov dword[ebp - ((i + 1) * value_size)], eax;
swissChili67bdf282021-06-06 18:46:08 -0700690
691 for (; !nilp(rest); rest = cdr(rest))
692 {
swissChilib51552c2021-08-03 10:23:37 -0700693 bool t = tail && nilp(cdr(rest));
swissChili6d02af42021-08-05 19:49:01 -0700694 NEARVAL(rest);
695 TRY(compile_expression(env, local, car(rest), t, Dst));
swissChili67bdf282021-06-06 18:46:08 -0700696 }
697
698 local_free(local, i);
699 }
swissChilie9fec8b2021-06-22 13:59:33 -0700700 else if (symstreq(fsym, "gc"))
701 {
702 if (nargs)
703 {
swissChili6d02af42021-08-05 19:49:01 -0700704 THROW(EARGS, "gc takes no arguments");
swissChilie9fec8b2021-06-22 13:59:33 -0700705 }
706
707 | run_gc;
708 }
swissChili6b47b6d2021-06-30 22:08:55 -0700709 else if (symstreq(fsym, "quote"))
710 {
711 if (nargs != 1)
swissChili6d02af42021-08-05 19:49:01 -0700712 THROW(EARGS, "quote should take exactly 1 argument");
swissChili6b47b6d2021-06-30 22:08:55 -0700713
714 // Simple!
715 | mov eax, (car(args));
716 }
717 else if (symstreq(fsym, "backquote"))
718 {
719 if (nargs != 1)
swissChili6d02af42021-08-05 19:49:01 -0700720 THROW(EARGS, "backquote should take exactly 1 argument");
swissChili6b47b6d2021-06-30 22:08:55 -0700721
swissChili6d02af42021-08-05 19:49:01 -0700722 TRY(compile_backquote(env, local, car(args), Dst));
swissChili6b47b6d2021-06-30 22:08:55 -0700723 }
swissChili74348422021-07-04 13:23:24 -0700724 else if (symstreq(fsym, "function"))
725 {
726 if (nargs != 1)
727 {
swissChili6d02af42021-08-05 19:49:01 -0700728 THROW(EARGS, "function should take exactly 1 argument");
swissChili74348422021-07-04 13:23:24 -0700729 }
730
swissChili6d02af42021-08-05 19:49:01 -0700731 NEARVAL(args);
swissChili74348422021-07-04 13:23:24 -0700732 if (!symbolp(car(args)))
733 {
swissChili6d02af42021-08-05 19:49:01 -0700734 THROW(EINVALID, "argument to function should be a symbol resolvable at "
swissChili7e1393c2021-07-07 12:59:12 -0700735 "compile time");
swissChili74348422021-07-04 13:23:24 -0700736 }
737
swissChilia89ee442021-08-04 20:54:51 -0700738 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChili74348422021-07-04 13:23:24 -0700739
swissChilia89ee442021-08-04 20:54:51 -0700740 if (!strcmp(name, local->current_function_name))
741 {
742 | push 0;
743 | push local->args;
744 | push <1;
745 | call_extern create_closure;
746 }
747 else
748 {
749 struct function *f = find_function(env, name);
750
751 if (!f)
752 {
swissChili6d02af42021-08-05 19:49:01 -0700753 THROW(EINVALID, "Function `%s' does not exist", (char *)(car(args) ^ SYMBOL_TAG));
swissChilia89ee442021-08-04 20:54:51 -0700754 }
755 value_t closure = create_closure(f->code_ptr, f->args, 0);
756 | mov eax, (closure);
757 }
swissChili74348422021-07-04 13:23:24 -0700758 }
swissChili6b47b6d2021-06-30 22:08:55 -0700759 else if (symstreq(fsym, "list"))
760 {
swissChili484295d2021-07-09 21:25:55 -0700761 | push (nil);
swissChili6b47b6d2021-06-30 22:08:55 -0700762
763 for (int i = nargs - 1; i >= 0; i--)
764 {
swissChili6d02af42021-08-05 19:49:01 -0700765 TRY(compile_expression(env, local, elt(args, i), false, Dst));
swissChili6b47b6d2021-06-30 22:08:55 -0700766
swissChili6b47b6d2021-06-30 22:08:55 -0700767 | push eax;
swissChili53e7cd12021-08-02 21:55:53 -0700768 | call_extern cons;
swissChili6b47b6d2021-06-30 22:08:55 -0700769 | add esp, (2 * value_size);
swissChili6b47b6d2021-06-30 22:08:55 -0700770 | push eax;
771 }
swissChili6d02af42021-08-05 19:49:01 -0700772 | pop eax;
swissChili6b47b6d2021-06-30 22:08:55 -0700773 }
swissChiliddc97542021-07-04 11:47:42 -0700774 else if (symstreq(fsym, "lambda"))
775 {
776 // Compile the function with this as the parent scope
777 struct local new_local;
778 int nargs_out;
swissChili6d02af42021-08-05 19:49:01 -0700779 dasm_State *d;
780 TRY(compile_function(
781 args, NS_ANONYMOUS, env, &new_local, local, &nargs_out,
782 "recurse", local->current_file_path, &d));
swissChiliddc97542021-07-04 11:47:42 -0700783
784 // Link the function
swissChilif68671f2021-07-05 14:14:44 -0700785 void *func_ptr = link_program(&d);
swissChiliddc97542021-07-04 11:47:42 -0700786
787 // Create a closure object with the correct number of captures at
788 // runtime
swissChili484295d2021-07-09 21:25:55 -0700789 | push (new_local.num_closure_slots);
790 | push (nargs_out);
791 | push (func_ptr);
swissChili53e7cd12021-08-02 21:55:53 -0700792 | call_extern create_closure;
swissChiliddc97542021-07-04 11:47:42 -0700793 | add esp, 12;
794
795 // Walk the generated local scope for V_FREE variables, since each
796 // of these exists in our scope (or higher), evaluate it and set it
797 // as a member of the lambda capture.
798
799 for (struct variable *var = new_local.first; var; var = var->prev)
800 {
801 if (var->type == V_FREE)
802 {
803 // Closure in eax
804 | push eax;
805 // Variable now in eax
swissChili6d02af42021-08-05 19:49:01 -0700806 TRY(compile_variable(find_variable(local, var->name), Dst));
swissChiliddc97542021-07-04 11:47:42 -0700807 | push eax;
808
swissChiliddc97542021-07-04 11:47:42 -0700809 // The capture offset
swissChili484295d2021-07-09 21:25:55 -0700810 | push (var->number);
swissChili53e7cd12021-08-02 21:55:53 -0700811 | call_extern set_closure_capture_variable;
swissChiliddc97542021-07-04 11:47:42 -0700812 // Skip the value and index
813 | add esp, 8;
814 // Pop the closure back in to eax
815 | pop eax;
816 }
817 }
818
819 // Closure is still in eax
820
821 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700822 del_local(&new_local);
swissChiliddc97542021-07-04 11:47:42 -0700823 }
swissChili7e1393c2021-07-07 12:59:12 -0700824 else if (symstreq(fsym, "eval"))
825 {
826 if (nargs != 1)
827 {
swissChili6d02af42021-08-05 19:49:01 -0700828 THROW(EARGS, "eval takes exactly 1 argument");
swissChili7e1393c2021-07-07 12:59:12 -0700829 }
830
swissChili6d02af42021-08-05 19:49:01 -0700831 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili7e1393c2021-07-07 12:59:12 -0700832 | push eax;
swissChili484295d2021-07-09 21:25:55 -0700833 | push (env);
swissChili53e7cd12021-08-02 21:55:53 -0700834 | call_extern eval;
swissChili7e1393c2021-07-07 12:59:12 -0700835 }
836 else if (symstreq(fsym, "load"))
837 {
838 if (nargs != 1)
839 {
swissChili6d02af42021-08-05 19:49:01 -0700840 THROW(EARGS, "load takes exactly 1 argument, %d given", nargs);
swissChili7e1393c2021-07-07 12:59:12 -0700841 }
842
swissChili6d02af42021-08-05 19:49:01 -0700843 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili7e1393c2021-07-07 12:59:12 -0700844 | push eax;
swissChili484295d2021-07-09 21:25:55 -0700845 | push (local->current_file_path);
846 | push (env);
swissChili53e7cd12021-08-02 21:55:53 -0700847 | call_extern load_relative;
swissChili7e1393c2021-07-07 12:59:12 -0700848 }
swissChili53472e82021-05-08 16:06:32 -0700849 else
850 {
swissChili74348422021-07-04 13:23:24 -0700851 char *name = (char *)(fsym ^ SYMBOL_TAG);
852 struct function *func = find_function(env, name);
swissChili7e1393c2021-07-07 12:59:12 -0700853
swissChili74348422021-07-04 13:23:24 -0700854 bool is_recursive = false;
swissChili15f1cae2021-07-05 19:08:47 -0700855 struct args *nargs_needed = NULL;
swissChili53472e82021-05-08 16:06:32 -0700856
swissChili53e7cd12021-08-02 21:55:53 -0700857 // The number of arguments actually passed on the stack,
858 // i.e. all varargs are 1.
swissChilib51552c2021-08-03 10:23:37 -0700859 int real_nargs;
swissChili53e7cd12021-08-02 21:55:53 -0700860
swissChili7e1393c2021-07-07 12:59:12 -0700861 if (local->current_function_name &&
862 symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700863 {
swissChili74348422021-07-04 13:23:24 -0700864 is_recursive = true;
swissChili15f1cae2021-07-05 19:08:47 -0700865 nargs_needed = local->args;
swissChili74348422021-07-04 13:23:24 -0700866 }
867 else
868 {
869 if (func == NULL)
870 {
swissChili6d02af42021-08-05 19:49:01 -0700871 THROW(EINVALID, "Function %s undefined", name);
swissChili74348422021-07-04 13:23:24 -0700872 }
873
swissChili15f1cae2021-07-05 19:08:47 -0700874 nargs_needed = func->args;
swissChili74348422021-07-04 13:23:24 -0700875 }
876
swissChili15f1cae2021-07-05 19:08:47 -0700877 if (!are_args_acceptable(nargs_needed, nargs))
swissChili74348422021-07-04 13:23:24 -0700878 {
swissChili6d02af42021-08-05 19:49:01 -0700879 THROW(EARGS,
880 "wrong number of args in function call: %s, "
881 "want %d args but given %d\n",
882 name, nargs_needed->num_required, nargs);
swissChilif1ba8c12021-07-02 18:45:38 -0700883 }
swissChili53472e82021-05-08 16:06:32 -0700884
swissChili53e7cd12021-08-02 21:55:53 -0700885 int total_taken = nargs_needed->num_optional +
886 nargs_needed->num_required;
887
swissChilib51552c2021-08-03 10:23:37 -0700888 real_nargs = total_taken + (nargs_needed->variadic ? 1 : 0);
swissChili53e7cd12021-08-02 21:55:53 -0700889
swissChili74348422021-07-04 13:23:24 -0700890 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700891 {
swissChili15f1cae2021-07-05 19:08:47 -0700892 int nargs = length(args);
893
swissChili484295d2021-07-09 21:25:55 -0700894 int line = cons_line(val);
895 char *file = cons_file(val);
896
897 if (nargs_needed->variadic)
swissChili15f1cae2021-07-05 19:08:47 -0700898 {
swissChili484295d2021-07-09 21:25:55 -0700899 | push (nil);
900 }
901
902 if (nargs > total_taken && nargs_needed->variadic)
903 {
904 // We are passing varargs, which means we need to make a list
905
906 for (int i = nargs - 1; i >= total_taken; i--)
907 {
swissChili6d02af42021-08-05 19:49:01 -0700908 TRY(compile_expression(env, local, elt(args, i), false, Dst));
swissChili484295d2021-07-09 21:25:55 -0700909 | push eax;
swissChili53e7cd12021-08-02 21:55:53 -0700910 | call_extern cons;
swissChili484295d2021-07-09 21:25:55 -0700911 | add esp, 8;
912 | push eax;
913 }
swissChili15f1cae2021-07-05 19:08:47 -0700914 }
915
swissChili7e1393c2021-07-07 12:59:12 -0700916 for (int i = nargs_needed->num_optional - 1;
917 i >= nargs - nargs_needed->num_required; i--)
swissChili15f1cae2021-07-05 19:08:47 -0700918 {
919 // Push the default optional values
swissChili484295d2021-07-09 21:25:55 -0700920 | push (nargs_needed->optional_arguments[i].value);
swissChili15f1cae2021-07-05 19:08:47 -0700921 }
922
swissChili484295d2021-07-09 21:25:55 -0700923 int min = MIN(nargs, total_taken);
924
925 for (int i = min - 1; i >= 0; i--)
swissChili2999dd12021-07-02 14:19:53 -0700926 {
swissChili6d02af42021-08-05 19:49:01 -0700927 TRY(compile_expression(env, local, elt(args, i), false, Dst));
swissChili2999dd12021-07-02 14:19:53 -0700928 | push eax;
929 }
swissChili15f1cae2021-07-05 19:08:47 -0700930
swissChili74348422021-07-04 13:23:24 -0700931 if (is_recursive)
932 {
swissChilib51552c2021-08-03 10:23:37 -0700933 if (tail)
934 {
935 // Move all the arguments pushed to the stack
936 // back up to the argument bit of the stack.
937
938 for (int i = 0; i < real_nargs; i++)
939 {
940 | pop eax;
941 | mov dword[ebp + (value_size * (i + 2))], eax;
942 }
943
944 // Jmp back to start
945 | mov esp, ebp;
946 | pop ebp;
947 | jmp <1;
948 }
949 else
950 {
951 | call <1;
952 }
swissChili74348422021-07-04 13:23:24 -0700953 }
954 else
955 {
swissChili484295d2021-07-09 21:25:55 -0700956 // | mov ebx, (func->code_addr);
957 | call_extern func->code_addr;
swissChili74348422021-07-04 13:23:24 -0700958 }
swissChili53e7cd12021-08-02 21:55:53 -0700959 | add esp, (real_nargs * value_size);
swissChili2999dd12021-07-02 14:19:53 -0700960 // result in eax
961 }
962 else if (func->namespace == NS_MACRO)
963 {
swissChili7e1393c2021-07-07 12:59:12 -0700964 // Make sure that the stuff allocated by the macro isn't in a
965 // pool
swissChilif68671f2021-07-05 14:14:44 -0700966 unsigned char pool = push_pool(0);
967
swissChili2999dd12021-07-02 14:19:53 -0700968 value_t expanded_to = call_list(func, args);
969
swissChilif68671f2021-07-05 14:14:44 -0700970 pop_pool(pool);
971
swissChili6d02af42021-08-05 19:49:01 -0700972 TRY(compile_expression(env, local, expanded_to, false, Dst));
swissChili2999dd12021-07-02 14:19:53 -0700973 }
swissChili53472e82021-05-08 16:06:32 -0700974 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700975 }
swissChili923b5362021-05-09 20:31:43 -0700976 else if (symbolp(val))
977 {
swissChili7e1393c2021-07-07 12:59:12 -0700978 if (symstreq(val, "+current-file+"))
swissChilie9fec8b2021-06-22 13:59:33 -0700979 {
swissChili7e1393c2021-07-07 12:59:12 -0700980 value_t file_name_val = strval(local->current_file_path);
981
982 | mov eax, (file_name_val);
swissChilie9fec8b2021-06-22 13:59:33 -0700983 }
swissChili7e1393c2021-07-07 12:59:12 -0700984 else
985 {
986 struct variable *v =
987 find_variable(local, (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700988
swissChili7e1393c2021-07-07 12:59:12 -0700989 if (!v)
990 {
swissChili6d02af42021-08-05 19:49:01 -0700991 THROW(EINVALID, "Variable `%s' unbound", (char *)(val ^ SYMBOL_TAG));
swissChili7e1393c2021-07-07 12:59:12 -0700992 }
993
swissChili6d02af42021-08-05 19:49:01 -0700994 TRY(compile_variable(v, Dst));
swissChili7e1393c2021-07-07 12:59:12 -0700995 }
swissChili923b5362021-05-09 20:31:43 -0700996 }
swissChilia89ee442021-08-04 20:54:51 -0700997 else if (closurep(val))
998 {
999 | mov eax, val;
1000 }
1001 else
1002 {
1003 printval(val, 1);
swissChili6d02af42021-08-05 19:49:01 -07001004 THROW(EUNIMPL, "Don't know how to compile this, sorry.");
swissChilia89ee442021-08-04 20:54:51 -07001005 }
swissChili6d02af42021-08-05 19:49:01 -07001006
1007 OKAY();
swissChilib3ca4fb2021-04-20 10:33:00 -07001008}
swissChilif3e7f182021-04-20 13:57:22 -07001009
swissChili923b5362021-05-09 20:31:43 -07001010struct variable *add_variable(struct local *local, enum var_type type,
1011 char *name, int number)
1012{
1013 struct variable *var = malloc(sizeof(struct variable));
1014 var->prev = local->first;
1015 var->type = type;
1016 var->name = name;
1017 var->number = number;
1018
1019 local->first = var;
1020
1021 return var;
1022}
1023
1024void destroy_local(struct local *local)
1025{
1026 for (struct variable *v = local->first; v;)
1027 {
1028 struct variable *t = v;
1029 v = v->prev;
1030 free(t);
1031 }
1032}
1033
1034struct variable *find_variable(struct local *local, char *name)
1035{
1036 struct variable *v = local->first;
1037
1038 for (; v && strcmp(v->name, name) != 0; v = v->prev)
swissChili7e1393c2021-07-07 12:59:12 -07001039 {
1040 }
swissChili923b5362021-05-09 20:31:43 -07001041
swissChiliddc97542021-07-04 11:47:42 -07001042 if (!v)
1043 {
1044 if (local->parent)
1045 {
1046 v = find_variable(local->parent, name);
1047
1048 if (v)
1049 {
swissChili15f1cae2021-07-05 19:08:47 -07001050 // We found this in a parent scope, add it as a V_FREE variable
1051 // to skip the search.
swissChili7e1393c2021-07-07 12:59:12 -07001052 v = add_variable(local, V_FREE, name,
1053 local->num_closure_slots++);
swissChiliddc97542021-07-04 11:47:42 -07001054 }
1055 }
1056 }
swissChili923b5362021-05-09 20:31:43 -07001057 return v;
1058}
swissChili2999dd12021-07-02 14:19:53 -07001059
swissChiliddc97542021-07-04 11:47:42 -07001060extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -07001061
swissChili7e1393c2021-07-07 12:59:12 -07001062value_t call_list_args(void *code_ptr, struct args *args, value_t list,
1063 void *data)
swissChili2999dd12021-07-02 14:19:53 -07001064{
swissChili15f1cae2021-07-05 19:08:47 -07001065 list = deep_copy(list);
swissChili484295d2021-07-09 21:25:55 -07001066
swissChili15f1cae2021-07-05 19:08:47 -07001067 int nargs = length(list);
1068
swissChili484295d2021-07-09 21:25:55 -07001069 value_t *val = &list;
swissChili15f1cae2021-07-05 19:08:47 -07001070
1071 for (value_t i = list; !nilp(i); i = cdr(i))
1072 {
1073 val = cdrref(i);
1074 }
1075
1076 int total_required = args->num_required + args->num_optional;
1077
1078 if (nargs > total_required)
1079 {
1080 // Take the remainder of the list and put it as the last item in the
1081 // list.
1082 value_t trailing = cxdr(list, total_required);
1083 value_t last_item = cons(trailing, nil);
1084
1085 *cxdrref(&list, total_required) = last_item;
1086 }
1087 else if (nargs < total_required)
1088 {
1089 for (int i = nargs - args->num_required; i < args->num_optional; i++)
1090 {
1091 // Append the i-th defualt argument
1092 value_t appended = cons(args->optional_arguments[i].value, nil);
1093 *val = appended;
1094 val = cdrref(appended);
1095 }
1096 }
1097
1098 // We want to call this if we pass the correct # of arguments or less, just
1099 // not if we have already passed varargs. Appends a nil argument.
1100 if (nargs <= total_required)
1101 {
1102 // Enough real arguments but no variadic arguments. Pass a nil list.
1103 *val = cons(nil, nil);
1104 }
1105
1106 return _call_list(code_ptr, list, data);
1107}
1108
1109value_t call_list(struct function *fun, value_t list)
1110{
1111 return call_list_args(fun->code_ptr, fun->args, list, NULL);
swissChiliddc97542021-07-04 11:47:42 -07001112}
1113
1114value_t call_list_closure(struct closure *c, value_t list)
1115{
swissChili15f1cae2021-07-05 19:08:47 -07001116 return call_list_args(c->function, c->args, list, c->data);
1117}
1118
1119struct args *new_args()
1120{
1121 struct args *a = malloc(sizeof(struct args));
1122 a->num_optional = 0;
1123 a->num_required = 0;
1124 a->variadic = false;
1125
1126 return a;
1127}
1128
swissChili7e1393c2021-07-07 12:59:12 -07001129struct args *add_optional_arg(struct args *args, value_t name, value_t value)
swissChili15f1cae2021-07-05 19:08:47 -07001130{
1131 int i = args->num_optional++;
swissChili7e1393c2021-07-07 12:59:12 -07001132 args =
1133 realloc(args, sizeof(struct args) + sizeof(struct optional_argument) *
1134 args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -07001135
swissChili7e1393c2021-07-07 12:59:12 -07001136 args->optional_arguments[i] = (struct optional_argument){
1137 .value = value,
1138 .name = name,
swissChili15f1cae2021-07-05 19:08:47 -07001139 };
1140
1141 return args;
1142}
1143
1144bool are_args_acceptable(struct args *args, int number)
1145{
1146 if (args->variadic)
1147 {
1148 return number >= args->num_required;
1149 }
1150 else
1151 {
1152 return number >= args->num_required &&
swissChili7e1393c2021-07-07 12:59:12 -07001153 number <= args->num_required + args->num_optional;
swissChili15f1cae2021-07-05 19:08:47 -07001154 }
1155}
1156
swissChili6d02af42021-08-05 19:49:01 -07001157struct error list_to_args(struct environment *env, value_t list,
1158 struct local *local, struct args **a)
swissChili15f1cae2021-07-05 19:08:47 -07001159{
swissChili6d02af42021-08-05 19:49:01 -07001160 E_INIT();
1161
swissChili15f1cae2021-07-05 19:08:47 -07001162 struct args *args = new_args();
1163
1164 bool in_optional = false;
1165
1166 for (value_t i = list; !nilp(i); i = cdr(i))
1167 {
1168 value_t val = car(i);
swissChili6d02af42021-08-05 19:49:01 -07001169 NEARVAL(i);
1170
swissChili15f1cae2021-07-05 19:08:47 -07001171 if (symbolp(val))
1172 {
1173 if (!args->variadic && symstreq(val, "&"))
1174 {
1175 i = cdr(i);
1176 value_t name = car(i);
1177
1178 if (!symbolp(name))
1179 {
swissChili6d02af42021-08-05 19:49:01 -07001180 THROW(EEXPECTED, "You must provide a symbol after & in an argument list "
1181 "to bind the\n"
1182 "variadic arguments to.");
swissChili15f1cae2021-07-05 19:08:47 -07001183 }
1184
1185 args->variadic = true;
1186
1187 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
swissChili7e1393c2021-07-07 12:59:12 -07001188 args->num_optional + args->num_required);
swissChili15f1cae2021-07-05 19:08:47 -07001189
1190 continue;
1191 }
1192
1193 if (!in_optional)
1194 {
swissChili7e1393c2021-07-07 12:59:12 -07001195 add_variable(local, V_ARGUMENT, (char *)(val ^ SYMBOL_TAG),
1196 args->num_required++);
swissChili15f1cae2021-07-05 19:08:47 -07001197 }
1198 else
1199 {
1200 char *name = (char *)(val ^ SYMBOL_TAG);
1201 if (name[0] == '&')
1202 {
swissChili6d02af42021-08-05 19:49:01 -07001203 THROW(EINVALID, "Non-optional argument following optional arguments "
1204 "starts with a &\n"
1205 "did you mean to declare a variadic argument? If so "
1206 "leave a space\n"
1207 "between the & and name.");
swissChili15f1cae2021-07-05 19:08:47 -07001208 }
1209 else
1210 {
swissChili6d02af42021-08-05 19:49:01 -07001211 THROW(EINVALID, "Cannot define a non-optional argument after an "
1212 "optional one.");
swissChili15f1cae2021-07-05 19:08:47 -07001213 }
1214 }
1215 }
1216 else if (listp(val))
1217 {
swissChili6d02af42021-08-05 19:49:01 -07001218 NEARVAL(val);
1219
swissChili15f1cae2021-07-05 19:08:47 -07001220 in_optional = true;
1221 int len = length(val);
1222
1223 if (len != 2)
1224 {
swissChili6d02af42021-08-05 19:49:01 -07001225 THROW(EINVALID, "A list defining an optional value must be structured like "
1226 "(name expr)\n"
1227 "with exactly two arguments.");
swissChili15f1cae2021-07-05 19:08:47 -07001228 }
1229
1230 value_t name = car(val);
1231 value_t expr = car(cdr(val));
1232
1233 value_t function = cons(nil, cons(expr, nil));
1234
swissChili6d02af42021-08-05 19:49:01 -07001235 dasm_State *d;
1236 TRY(compile_function(function, NS_ANONYMOUS, env, NULL, NULL, NULL,
1237 NULL, local->current_file_path, &d));
swissChili15f1cae2021-07-05 19:08:47 -07001238
1239 // TODO: GC stack top!
1240 value_t (*compiled)() = link_program(&d);
1241
1242 value_t value = compiled();
1243 args = add_optional_arg(args, name, value);
1244
swissChili7e1393c2021-07-07 12:59:12 -07001245 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
1246 args->num_required + args->num_optional - 1);
swissChili15f1cae2021-07-05 19:08:47 -07001247 }
1248 }
1249
swissChili6d02af42021-08-05 19:49:01 -07001250 *a = args;
1251 OKAY();
swissChili15f1cae2021-07-05 19:08:47 -07001252}
1253
1254void display_args(struct args *args)
1255{
1256 printf("Args object taking %d require arguments and %d optionals:\n",
swissChili7e1393c2021-07-07 12:59:12 -07001257 args->num_required, args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -07001258
1259 for (int i = 0; i < args->num_optional; i++)
1260 {
swissChili7e1393c2021-07-07 12:59:12 -07001261 printf(" %d\t%s\n", i,
1262 (char *)(args->optional_arguments[i].name ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -07001263 printval(args->optional_arguments[i].value, 2);
1264 }
swissChili2999dd12021-07-02 14:19:53 -07001265}