blob: 5810f69dd3fffb11329371be6628289528312f76 [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{
swissChili6d02af42021-08-05 19:49:01 -0700142 E_INIT();
143
swissChilif1ba8c12021-07-02 18:45:38 -0700144 dasm_State *d;
145 dasm_State **Dst = &d;
146
swissChili484295d2021-07-09 21:25:55 -0700147 |.section code, imports;
swissChilif1ba8c12021-07-02 18:45:38 -0700148 dasm_init(&d, DASM_MAXSECTION);
149
150 |.globals lbl_;
151 void *labels[lbl__MAX];
152 dasm_setupglobal(&d, labels, lbl__MAX);
153
154 |.actionlist lisp_actions;
155 dasm_setup(&d, lisp_actions);
156
157 struct local local;
158 local.parent = NULL;
159 local.first = NULL;
160 local.num_vars = 0;
161 local.npc = 8;
162 local.nextpc = 0;
163 local.stack_slots = malloc(sizeof(bool) * 4);
164 memset(local.stack_slots, 0, sizeof(bool) * 4);
165 local.num_stack_slots = 4;
166 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700167 local.num_closure_slots = 0;
168 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700169 local.current_function_name = name;
swissChili7e1393c2021-07-07 12:59:12 -0700170 local.current_file_path = path;
swissChilif1ba8c12021-07-02 18:45:38 -0700171
172 dasm_growpc(&d, local.npc);
173
swissChilif1ba8c12021-07-02 18:45:38 -0700174 value_t arglist = car(args);
175 value_t body = cdr(args);
176
swissChili15f1cae2021-07-05 19:08:47 -0700177 // This will add the arguments to local too.
swissChili6d02af42021-08-05 19:49:01 -0700178 struct args *ar;
179 TRY(list_to_args(env, arglist, &local, &ar));
swissChili15f1cae2021-07-05 19:08:47 -0700180 local.args = ar;
swissChili74348422021-07-04 13:23:24 -0700181
swissChili15f1cae2021-07-05 19:08:47 -0700182 if (!ar)
swissChilif1ba8c12021-07-02 18:45:38 -0700183 {
swissChili6d02af42021-08-05 19:49:01 -0700184 NEARVAL(arglist);
185 THROW(EMALFORMED, "Malformed argument list");
swissChilif1ba8c12021-07-02 18:45:38 -0700186 }
187
188 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
189 {
swissChili36f2c692021-08-08 14:31:44 -0700190 TRY(walk_and_alloc(env, &local, carref(body_)));
swissChilif1ba8c12021-07-02 18:45:38 -0700191 }
192
swissChili484295d2021-07-09 21:25:55 -0700193 | setup (local.num_stack_entries);
swissChilif1ba8c12021-07-02 18:45:38 -0700194
195 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
196 local.num_stack_entries = 0;
197
198 for (; !nilp(body); body = cdr(body))
199 {
swissChilib51552c2021-08-03 10:23:37 -0700200 bool tail = nilp(cdr(body));
swissChili6d02af42021-08-05 19:49:01 -0700201 TRY(compile_expression(env, &local, car(body), tail, Dst));
swissChilif1ba8c12021-07-02 18:45:38 -0700202 }
203
204 | cleanup;
205
206 if (local_out)
207 *local_out = local;
208
swissChili15f1cae2021-07-05 19:08:47 -0700209 if (args_out)
210 *args_out = ar;
swissChilif1ba8c12021-07-02 18:45:38 -0700211
swissChili6d02af42021-08-05 19:49:01 -0700212 *state = d;
213
214 OKAY();
swissChilif1ba8c12021-07-02 18:45:38 -0700215}
216
swissChili6d02af42021-08-05 19:49:01 -0700217struct error compile_tl(value_t val, struct environment *env, char *fname)
swissChilica107a02021-04-14 12:07:30 -0700218{
swissChili6d02af42021-08-05 19:49:01 -0700219 E_INIT();
220
221 NEARVAL(val);
222
swissChili53472e82021-05-08 16:06:32 -0700223 if (!listp(val))
swissChili6d02af42021-08-05 19:49:01 -0700224 {
225 THROW(EEXPECTED, "Top level form must be a list");
226 }
swissChilica107a02021-04-14 12:07:30 -0700227
swissChili53472e82021-05-08 16:06:32 -0700228 value_t form = car(val);
229 value_t args = cdr(val);
230
swissChili2999dd12021-07-02 14:19:53 -0700231 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700232 {
swissChili2999dd12021-07-02 14:19:53 -0700233 enum namespace namespace = NS_FUNCTION;
234
235 if (symstreq(form, "defmacro"))
swissChilia89ee442021-08-04 20:54:51 -0700236 namespace = NS_MACRO;
swissChili2999dd12021-07-02 14:19:53 -0700237
swissChili8fc5e2f2021-04-22 13:45:10 -0700238 struct local local;
swissChili15f1cae2021-07-05 19:08:47 -0700239 struct args *a;
swissChili74348422021-07-04 13:23:24 -0700240 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChilif68671f2021-07-05 14:14:44 -0700241
swissChili6d02af42021-08-05 19:49:01 -0700242 dasm_State *d;
243 TRY(compile_function(cdr(args), namespace, env, &local,
244 NULL, &a, name, fname, &d));
swissChilia820dea2021-05-09 16:46:55 -0700245
swissChili7e1393c2021-07-07 12:59:12 -0700246 add_function(env, name, link_program(&d), a, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700247
swissChili53472e82021-05-08 16:06:32 -0700248 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700249 del_local(&local);
swissChili67bdf282021-06-06 18:46:08 -0700250 }
swissChilif68671f2021-07-05 14:14:44 -0700251 else if (symstreq(form, "progn"))
252 {
253 for (value_t val = args; !nilp(val); val = cdr(val))
254 {
swissChili6d02af42021-08-05 19:49:01 -0700255 TRY(compile_tl(car(val), env, fname));
swissChilif68671f2021-07-05 14:14:44 -0700256 }
257 }
swissChili484295d2021-07-09 21:25:55 -0700258 else if (symstreq(form, "load"))
259 {
260 if (length(args) != 1)
261 {
swissChili6d02af42021-08-05 19:49:01 -0700262 NEARVAL(args);
263 THROW(EARGS, "load expects exactly 1 argument, %d given",
264 length(args));
swissChili484295d2021-07-09 21:25:55 -0700265 }
266 load_relative(env, fname, car(args));
267 }
swissChili6d02af42021-08-05 19:49:01 -0700268
269 OKAY();
swissChili67bdf282021-06-06 18:46:08 -0700270}
271
swissChili36f2c692021-08-08 14:31:44 -0700272struct error walk_and_alloc(struct environment *env, struct local *local, value_t *bp)
swissChili67bdf282021-06-06 18:46:08 -0700273{
swissChili36f2c692021-08-08 14:31:44 -0700274 E_INIT();
275
276 value_t body = *bp;
277
swissChilib51552c2021-08-03 10:23:37 -0700278 // TODO: handle macros
swissChili67bdf282021-06-06 18:46:08 -0700279 if (!listp(body))
swissChili36f2c692021-08-08 14:31:44 -0700280 OKAY();
swissChili67bdf282021-06-06 18:46:08 -0700281
282 value_t args = cdr(body);
283
284 if (symstreq(car(body), "let1"))
285 {
286 int slot = local_alloc(local);
287
288 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700289 for (; !nilp(expr); expr = cdr(expr))
290 {
swissChili36f2c692021-08-08 14:31:44 -0700291 walk_and_alloc(env, local, carref(expr));
swissChilif1ba8c12021-07-02 18:45:38 -0700292 }
swissChili67bdf282021-06-06 18:46:08 -0700293
294 local_free(local, slot);
295 }
swissChilif1ba8c12021-07-02 18:45:38 -0700296 else if (symstreq(car(body), "lambda"))
297 {
298 // We don't want to walk the lambda because it's another function. When
299 // the lambda is compiled it will be walked.
swissChili36f2c692021-08-08 14:31:44 -0700300 OKAY();
swissChilif1ba8c12021-07-02 18:45:38 -0700301 }
swissChili67bdf282021-06-06 18:46:08 -0700302 else
303 {
swissChili36f2c692021-08-08 14:31:44 -0700304 // Is this a macro?
305
306 struct function *mac = NULL;
307
308 if (symbolp(car(body)))
309 mac = find_function(env, (char *)(car(body) ^ SYMBOL_TAG));
310 else
311 walk_and_alloc(env, local, carref(body));
312
313 if (mac && mac->namespace == NS_MACRO)
swissChili67bdf282021-06-06 18:46:08 -0700314 {
swissChili36f2c692021-08-08 14:31:44 -0700315 unsigned char pool = push_pool(0);
316 value_t form = call_list(mac, args);
317 pop_pool(pool);
318
319 add_to_pool(form);
320 *bp = form;
321
322 walk_and_alloc(env, local, bp);
323 }
324 else
325 {
326 for (; !nilp(args); args = cdr(args))
327 {
328 walk_and_alloc(env, local, carref(args));
329 }
swissChili67bdf282021-06-06 18:46:08 -0700330 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700331 }
swissChili36f2c692021-08-08 14:31:44 -0700332
333 OKAY();
swissChili8fc5e2f2021-04-22 13:45:10 -0700334}
335
swissChilif68671f2021-07-05 14:14:44 -0700336bool load(struct environment *env, char *path)
swissChili8fc5e2f2021-04-22 13:45:10 -0700337{
swissChilif68671f2021-07-05 14:14:44 -0700338 if (!file_exists(path))
339 return false;
340
341 add_load(env, path);
342
swissChilib8fd4712021-06-23 15:32:04 -0700343 unsigned char pool = make_pool();
344 unsigned char pop = push_pool(pool);
345
swissChilif68671f2021-07-05 14:14:44 -0700346 struct istream *is = new_fistream(path, false);
347 if (!is)
348 return false;
349
swissChili8fc5e2f2021-04-22 13:45:10 -0700350 value_t val;
swissChili53472e82021-05-08 16:06:32 -0700351
swissChili36f2c692021-08-08 14:31:44 -0700352 struct error read_error;
353
354 while (IS_OKAY((read_error = read1(is, &val))))
swissChili8fc5e2f2021-04-22 13:45:10 -0700355 {
swissChili6d02af42021-08-05 19:49:01 -0700356 if (!IS_OKAY(compile_tl(val, env, path)))
swissChili36f2c692021-08-08 14:31:44 -0700357 {
358 goto failure;
359 }
360 }
361
362 if (!read_error.safe_state)
363 {
364 goto failure;
swissChili8fc5e2f2021-04-22 13:45:10 -0700365 }
swissChilif3e7f182021-04-20 13:57:22 -0700366
swissChilif68671f2021-07-05 14:14:44 -0700367 del_fistream(is);
swissChilib8fd4712021-06-23 15:32:04 -0700368 pop_pool(pop);
369
swissChilif68671f2021-07-05 14:14:44 -0700370 return true;
swissChili36f2c692021-08-08 14:31:44 -0700371
372failure:
373 del_fistream(is);
374 pop_pool(pool);
375
376 return false;
swissChilif68671f2021-07-05 14:14:44 -0700377}
378
swissChili7e1393c2021-07-07 12:59:12 -0700379value_t load_relative(struct environment *env, char *to, value_t name)
380{
381 if (!stringp(name))
382 return nil;
383
384 char *new_path = (char *)(name ^ STRING_TAG);
385 char *relative_to = strdup(to);
386 char full_path[512];
387
388 snprintf(full_path, 512, "%s/%s", dirname(relative_to), new_path);
389
390 if (load(env, full_path))
391 return t;
392 else
393 return nil;
394}
395
swissChili6d02af42021-08-05 19:49:01 -0700396struct error compile_file(char *filename, struct environment **e)
swissChilif68671f2021-07-05 14:14:44 -0700397{
swissChili6d02af42021-08-05 19:49:01 -0700398 E_INIT();
399
swissChilif68671f2021-07-05 14:14:44 -0700400 value_t val;
swissChili7e1393c2021-07-07 12:59:12 -0700401 struct environment *env = malloc(sizeof(struct environment));
402 env->first = NULL;
403 env->first_loaded = NULL;
swissChilif68671f2021-07-05 14:14:44 -0700404
swissChili7e1393c2021-07-07 12:59:12 -0700405 add_load(env, filename);
swissChili6d02af42021-08-05 19:49:01 -0700406 TRY(load_std(env));
swissChilif68671f2021-07-05 14:14:44 -0700407
swissChili7e1393c2021-07-07 12:59:12 -0700408 bool ok_ = load(env, filename);
swissChilif68671f2021-07-05 14:14:44 -0700409
swissChili6d02af42021-08-05 19:49:01 -0700410 if (!ok_)
411 {
412 free(env);
413 THROWSAFE(ENOTFOUND);
414 }
swissChilif68671f2021-07-05 14:14:44 -0700415
swissChili6d02af42021-08-05 19:49:01 -0700416 *e = env;
417
418 OKAY();
swissChilica107a02021-04-14 12:07:30 -0700419}
swissChilib3ca4fb2021-04-20 10:33:00 -0700420
swissChili53472e82021-05-08 16:06:32 -0700421int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700422{
swissChili53472e82021-05-08 16:06:32 -0700423 int n = local->nextpc++;
424 if (n > local->npc)
425 {
426 local->npc += 16;
427 dasm_growpc(Dst, local->npc);
428 }
429 return n;
430}
431
swissChili6d02af42021-08-05 19:49:01 -0700432struct error compile_backquote(struct environment *env, struct local *local,
433 value_t val, dasm_State **Dst)
swissChili6b47b6d2021-06-30 22:08:55 -0700434{
swissChili6d02af42021-08-05 19:49:01 -0700435 E_INIT();
436
swissChili6b47b6d2021-06-30 22:08:55 -0700437 if (!listp(val))
438 {
439 | mov eax, (val);
440 }
441 else
442 {
swissChili7e1393c2021-07-07 12:59:12 -0700443 value_t fsym = car(val), args = cdr(val);
swissChili9d151e62021-08-04 13:11:45 -0700444 int nargs = length(args),
445 n = length(val);
swissChili6b47b6d2021-06-30 22:08:55 -0700446
swissChili6d02af42021-08-05 19:49:01 -0700447 NEARVAL(val);
448
swissChili9d151e62021-08-04 13:11:45 -0700449 if (symstreq(fsym, "unquote"))
450 {
451 if (nargs != 1)
452 {
swissChili6d02af42021-08-05 19:49:01 -0700453 THROW(EARGS, "unquote (or ,) takes exactly 1 argument");
swissChili9d151e62021-08-04 13:11:45 -0700454 }
455
swissChili6d02af42021-08-05 19:49:01 -0700456 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili9d151e62021-08-04 13:11:45 -0700457 }
swissChili36f2c692021-08-08 14:31:44 -0700458 else if (symstreq(fsym, "unquote-splice"))
459 {
460
461 }
swissChili9d151e62021-08-04 13:11:45 -0700462 else
463 {
464 | push nil;
465
466 for (int i = n - 1; i >= 0; i--)
467 {
swissChili6d02af42021-08-05 19:49:01 -0700468 TRY(compile_backquote(env, local, elt(val, i), Dst));
swissChili9d151e62021-08-04 13:11:45 -0700469 | push eax;
470 | call_extern cons;
471 | add esp, 8;
472
473 // Remove unnecessary pop
474 | push eax;
475 }
swissChilia89ee442021-08-04 20:54:51 -0700476 | pop eax;
swissChili9d151e62021-08-04 13:11:45 -0700477 }
swissChili6b47b6d2021-06-30 22:08:55 -0700478 }
swissChili6d02af42021-08-05 19:49:01 -0700479
480 OKAY();
swissChili6b47b6d2021-06-30 22:08:55 -0700481}
482
swissChili7e1393c2021-07-07 12:59:12 -0700483value_t eval(struct environment *env, value_t form)
484{
485 // Eval!
486 value_t function = cons(nil, cons(form, nil));
487
488 struct local local;
489 struct args *args;
490
swissChili6d02af42021-08-05 19:49:01 -0700491 dasm_State *d;
492 struct error err;
493
494 if (!IS_OKAY((err = compile_function(function, NS_ANONYMOUS, env, &local, NULL,
495 &args, NULL, "/", &d))))
496 {
497 ereport(err);
498 return nil;
499 }
swissChili7e1393c2021-07-07 12:59:12 -0700500
501 del_local(&local);
502
503 value_t (*f)() = link_program(&d);
504 return f();
505}
506
swissChili6d02af42021-08-05 19:49:01 -0700507struct error compile_variable(struct variable *v, dasm_State *Dst)
swissChiliddc97542021-07-04 11:47:42 -0700508{
swissChili6d02af42021-08-05 19:49:01 -0700509 E_INIT();
swissChiliddc97542021-07-04 11:47:42 -0700510 switch (v->type)
511 {
512 case V_ARGUMENT:
swissChili7e1393c2021-07-07 12:59:12 -0700513 | mov eax, dword[ebp + (value_size * (v->number + 2))];
swissChiliddc97542021-07-04 11:47:42 -0700514 break;
515 case V_BOUND:
swissChili7e1393c2021-07-07 12:59:12 -0700516 | mov eax, dword[ebp - ((v->number + 1) * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700517 break;
518 case V_FREE:
519 // edi is the closure context pointer
swissChili7e1393c2021-07-07 12:59:12 -0700520 | mov eax, dword[edi + (v->number * value_size)];
swissChiliddc97542021-07-04 11:47:42 -0700521 break;
522 default:
swissChili6d02af42021-08-05 19:49:01 -0700523 THROW(EUNIMPL, "Sorry, can only access V_ARGUMENT, V_BOUND, and V_FREE vars");
swissChiliddc97542021-07-04 11:47:42 -0700524 }
swissChili6d02af42021-08-05 19:49:01 -0700525 OKAY();
swissChiliddc97542021-07-04 11:47:42 -0700526}
527
swissChili6d02af42021-08-05 19:49:01 -0700528struct error compile_expression(struct environment *env, struct local *local,
529 value_t val, bool tail, dasm_State **Dst)
swissChili53472e82021-05-08 16:06:32 -0700530{
swissChili6d02af42021-08-05 19:49:01 -0700531 E_INIT();
532
533 NEARVAL(val);
534
swissChili7e1393c2021-07-07 12:59:12 -0700535 if (symstreq(val, "nil") || nilp(val))
swissChili53472e82021-05-08 16:06:32 -0700536 {
537 | mov eax, (nil);
538 }
swissChili923b5362021-05-09 20:31:43 -0700539 else if (symstreq(val, "t"))
540 {
541 | mov eax, (t);
542 }
543 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700544 {
545 | mov eax, val;
546 }
swissChili53472e82021-05-08 16:06:32 -0700547 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700548 {
swissChili53472e82021-05-08 16:06:32 -0700549 value_t fsym = car(val);
550 value_t args = cdr(val);
551 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700552
swissChili53472e82021-05-08 16:06:32 -0700553 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700554 {
swissChili6d02af42021-08-05 19:49:01 -0700555 THROW(EEXPECTED, "Function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700556 }
557
swissChili53472e82021-05-08 16:06:32 -0700558 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700559 {
swissChili53472e82021-05-08 16:06:32 -0700560 if (nargs < 2 || nargs > 3)
swissChili6d02af42021-08-05 19:49:01 -0700561 {
562 THROW(EARGS, "Must give at least 2 arguments to if");
563 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700564
swissChili6d02af42021-08-05 19:49:01 -0700565 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili53472e82021-05-08 16:06:32 -0700566 int false_label = nextpc(local, Dst),
567 after_label = nextpc(local, Dst);
568
569 // result is in eax
570 | cmp eax, (nil);
swissChili484295d2021-07-09 21:25:55 -0700571 | je =>false_label;
swissChili53472e82021-05-08 16:06:32 -0700572
swissChili6d02af42021-08-05 19:49:01 -0700573 TRY(compile_expression(env, local, elt(args, 1), tail, Dst));
swissChili484295d2021-07-09 21:25:55 -0700574 | jmp =>after_label;
575 |=>false_label:;
swissChili53472e82021-05-08 16:06:32 -0700576 if (nargs == 3)
swissChili6d02af42021-08-05 19:49:01 -0700577 TRY(compile_expression(env, local, elt(args, 2), tail, Dst));
swissChili484295d2021-07-09 21:25:55 -0700578 |=>after_label:;
swissChili53472e82021-05-08 16:06:32 -0700579 }
swissChilia89ee442021-08-04 20:54:51 -0700580 else if (symstreq(fsym, "and") || symstreq(fsym, "or"))
581 {
582 bool or = symstreq(fsym, "or"); // false == and
583
584 // Boolean and and or, short circuit like &&/||
585 if (nargs < 1)
586 {
swissChili6d02af42021-08-05 19:49:01 -0700587 THROW(EARGS, "and & or require at least 1 argument.");
swissChilia89ee442021-08-04 20:54:51 -0700588 }
589
590 int after = nextpc(local, Dst);
591
592 for (; !nilp(args); args = cdr(args))
593 {
swissChili6d02af42021-08-05 19:49:01 -0700594 NEARVAL(args);
595
596 TRY(compile_expression(env, local, car(args), false, Dst));
swissChilia89ee442021-08-04 20:54:51 -0700597 if (!nilp(cdr(args)))
598 {
599 | cmp eax, nil;
600 if (or)
601 {
swissChilifbf525f2021-08-04 21:28:07 -0700602 | jne =>after;
swissChilia89ee442021-08-04 20:54:51 -0700603 }
604 else
605 {
swissChilifbf525f2021-08-04 21:28:07 -0700606 | je =>after;
swissChilia89ee442021-08-04 20:54:51 -0700607 }
608 }
609 }
610
611 |=>after:;
612 }
swissChilif68671f2021-07-05 14:14:44 -0700613 else if (symstreq(fsym, "progn"))
614 {
615 for (value_t val = args; !nilp(val); val = cdr(val))
616 {
swissChili6d02af42021-08-05 19:49:01 -0700617 NEARVAL(args);
618
swissChilib51552c2021-08-03 10:23:37 -0700619 bool t = tail && nilp(cdr(val));
swissChili6d02af42021-08-05 19:49:01 -0700620 TRY(compile_expression(env, local, car(val), t, Dst));
swissChilif68671f2021-07-05 14:14:44 -0700621 }
622 }
swissChili67bdf282021-06-06 18:46:08 -0700623 else if (symstreq(fsym, "let1"))
624 {
625 if (nargs < 2)
626 {
swissChili6d02af42021-08-05 19:49:01 -0700627 THROW(EARGS, "Must give at least 2 arguments to let1");
swissChili67bdf282021-06-06 18:46:08 -0700628 }
629 value_t binding = car(args);
630 value_t rest = cdr(args);
631
swissChili6d02af42021-08-05 19:49:01 -0700632 NEARVAL(binding);
swissChili67bdf282021-06-06 18:46:08 -0700633 if (length(binding) != 2)
634 {
swissChili6d02af42021-08-05 19:49:01 -0700635 THROW(EARGS, "Binding list in let1 must contain exactly two entries");
swissChili67bdf282021-06-06 18:46:08 -0700636 }
637
swissChili6d02af42021-08-05 19:49:01 -0700638 NEARVAL(rest);
639
swissChili67bdf282021-06-06 18:46:08 -0700640 value_t name = car(binding);
641 value_t value = car(cdr(binding));
642
swissChili6d02af42021-08-05 19:49:01 -0700643 TRY(compile_expression(env, local, value, false, Dst));
swissChili67bdf282021-06-06 18:46:08 -0700644
645 int i = local_alloc(local);
646
647 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
648
swissChili7e1393c2021-07-07 12:59:12 -0700649 | mov dword[ebp - ((i + 1) * value_size)], eax;
swissChili67bdf282021-06-06 18:46:08 -0700650
651 for (; !nilp(rest); rest = cdr(rest))
652 {
swissChilib51552c2021-08-03 10:23:37 -0700653 bool t = tail && nilp(cdr(rest));
swissChili6d02af42021-08-05 19:49:01 -0700654 NEARVAL(rest);
655 TRY(compile_expression(env, local, car(rest), t, Dst));
swissChili67bdf282021-06-06 18:46:08 -0700656 }
657
658 local_free(local, i);
659 }
swissChilie9fec8b2021-06-22 13:59:33 -0700660 else if (symstreq(fsym, "gc"))
661 {
662 if (nargs)
663 {
swissChili6d02af42021-08-05 19:49:01 -0700664 THROW(EARGS, "gc takes no arguments");
swissChilie9fec8b2021-06-22 13:59:33 -0700665 }
666
667 | run_gc;
668 }
swissChili6b47b6d2021-06-30 22:08:55 -0700669 else if (symstreq(fsym, "quote"))
670 {
671 if (nargs != 1)
swissChili6d02af42021-08-05 19:49:01 -0700672 THROW(EARGS, "quote should take exactly 1 argument");
swissChili6b47b6d2021-06-30 22:08:55 -0700673
674 // Simple!
675 | mov eax, (car(args));
676 }
677 else if (symstreq(fsym, "backquote"))
678 {
679 if (nargs != 1)
swissChili6d02af42021-08-05 19:49:01 -0700680 THROW(EARGS, "backquote should take exactly 1 argument");
swissChili6b47b6d2021-06-30 22:08:55 -0700681
swissChili6d02af42021-08-05 19:49:01 -0700682 TRY(compile_backquote(env, local, car(args), Dst));
swissChili6b47b6d2021-06-30 22:08:55 -0700683 }
swissChili74348422021-07-04 13:23:24 -0700684 else if (symstreq(fsym, "function"))
685 {
686 if (nargs != 1)
687 {
swissChili6d02af42021-08-05 19:49:01 -0700688 THROW(EARGS, "function should take exactly 1 argument");
swissChili74348422021-07-04 13:23:24 -0700689 }
690
swissChili6d02af42021-08-05 19:49:01 -0700691 NEARVAL(args);
swissChili74348422021-07-04 13:23:24 -0700692 if (!symbolp(car(args)))
693 {
swissChili6d02af42021-08-05 19:49:01 -0700694 THROW(EINVALID, "argument to function should be a symbol resolvable at "
swissChili7e1393c2021-07-07 12:59:12 -0700695 "compile time");
swissChili74348422021-07-04 13:23:24 -0700696 }
697
swissChilia89ee442021-08-04 20:54:51 -0700698 char *name = (char *)(car(args) ^ SYMBOL_TAG);
swissChili74348422021-07-04 13:23:24 -0700699
swissChilia89ee442021-08-04 20:54:51 -0700700 if (!strcmp(name, local->current_function_name))
701 {
702 | push 0;
703 | push local->args;
704 | push <1;
705 | call_extern create_closure;
706 }
707 else
708 {
709 struct function *f = find_function(env, name);
710
711 if (!f)
712 {
swissChili6d02af42021-08-05 19:49:01 -0700713 THROW(EINVALID, "Function `%s' does not exist", (char *)(car(args) ^ SYMBOL_TAG));
swissChilia89ee442021-08-04 20:54:51 -0700714 }
715 value_t closure = create_closure(f->code_ptr, f->args, 0);
716 | mov eax, (closure);
717 }
swissChili74348422021-07-04 13:23:24 -0700718 }
swissChili6b47b6d2021-06-30 22:08:55 -0700719 else if (symstreq(fsym, "list"))
720 {
swissChili484295d2021-07-09 21:25:55 -0700721 | push (nil);
swissChili6b47b6d2021-06-30 22:08:55 -0700722
723 for (int i = nargs - 1; i >= 0; i--)
724 {
swissChili6d02af42021-08-05 19:49:01 -0700725 TRY(compile_expression(env, local, elt(args, i), false, Dst));
swissChili6b47b6d2021-06-30 22:08:55 -0700726
swissChili6b47b6d2021-06-30 22:08:55 -0700727 | push eax;
swissChili53e7cd12021-08-02 21:55:53 -0700728 | call_extern cons;
swissChili6b47b6d2021-06-30 22:08:55 -0700729 | add esp, (2 * value_size);
swissChili6b47b6d2021-06-30 22:08:55 -0700730 | push eax;
731 }
swissChili6d02af42021-08-05 19:49:01 -0700732 | pop eax;
swissChili6b47b6d2021-06-30 22:08:55 -0700733 }
swissChiliddc97542021-07-04 11:47:42 -0700734 else if (symstreq(fsym, "lambda"))
735 {
736 // Compile the function with this as the parent scope
737 struct local new_local;
738 int nargs_out;
swissChili6d02af42021-08-05 19:49:01 -0700739 dasm_State *d;
740 TRY(compile_function(
741 args, NS_ANONYMOUS, env, &new_local, local, &nargs_out,
742 "recurse", local->current_file_path, &d));
swissChiliddc97542021-07-04 11:47:42 -0700743
744 // Link the function
swissChilif68671f2021-07-05 14:14:44 -0700745 void *func_ptr = link_program(&d);
swissChiliddc97542021-07-04 11:47:42 -0700746
747 // Create a closure object with the correct number of captures at
748 // runtime
swissChili484295d2021-07-09 21:25:55 -0700749 | push (new_local.num_closure_slots);
750 | push (nargs_out);
751 | push (func_ptr);
swissChili53e7cd12021-08-02 21:55:53 -0700752 | call_extern create_closure;
swissChiliddc97542021-07-04 11:47:42 -0700753 | add esp, 12;
754
755 // Walk the generated local scope for V_FREE variables, since each
756 // of these exists in our scope (or higher), evaluate it and set it
757 // as a member of the lambda capture.
758
759 for (struct variable *var = new_local.first; var; var = var->prev)
760 {
761 if (var->type == V_FREE)
762 {
763 // Closure in eax
764 | push eax;
765 // Variable now in eax
swissChili6d02af42021-08-05 19:49:01 -0700766 TRY(compile_variable(find_variable(local, var->name), Dst));
swissChiliddc97542021-07-04 11:47:42 -0700767 | push eax;
768
swissChiliddc97542021-07-04 11:47:42 -0700769 // The capture offset
swissChili484295d2021-07-09 21:25:55 -0700770 | push (var->number);
swissChili53e7cd12021-08-02 21:55:53 -0700771 | call_extern set_closure_capture_variable;
swissChiliddc97542021-07-04 11:47:42 -0700772 // Skip the value and index
773 | add esp, 8;
774 // Pop the closure back in to eax
775 | pop eax;
776 }
777 }
778
779 // Closure is still in eax
780
781 dasm_free(&d);
swissChili708d4c42021-07-04 17:40:07 -0700782 del_local(&new_local);
swissChiliddc97542021-07-04 11:47:42 -0700783 }
swissChili7e1393c2021-07-07 12:59:12 -0700784 else if (symstreq(fsym, "eval"))
785 {
786 if (nargs != 1)
787 {
swissChili6d02af42021-08-05 19:49:01 -0700788 THROW(EARGS, "eval takes exactly 1 argument");
swissChili7e1393c2021-07-07 12:59:12 -0700789 }
790
swissChili6d02af42021-08-05 19:49:01 -0700791 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili7e1393c2021-07-07 12:59:12 -0700792 | push eax;
swissChili484295d2021-07-09 21:25:55 -0700793 | push (env);
swissChili53e7cd12021-08-02 21:55:53 -0700794 | call_extern eval;
swissChili7e1393c2021-07-07 12:59:12 -0700795 }
796 else if (symstreq(fsym, "load"))
797 {
798 if (nargs != 1)
799 {
swissChili6d02af42021-08-05 19:49:01 -0700800 THROW(EARGS, "load takes exactly 1 argument, %d given", nargs);
swissChili7e1393c2021-07-07 12:59:12 -0700801 }
802
swissChili6d02af42021-08-05 19:49:01 -0700803 TRY(compile_expression(env, local, car(args), false, Dst));
swissChili7e1393c2021-07-07 12:59:12 -0700804 | push eax;
swissChili484295d2021-07-09 21:25:55 -0700805 | push (local->current_file_path);
806 | push (env);
swissChili53e7cd12021-08-02 21:55:53 -0700807 | call_extern load_relative;
swissChili7e1393c2021-07-07 12:59:12 -0700808 }
swissChili53472e82021-05-08 16:06:32 -0700809 else
810 {
swissChili74348422021-07-04 13:23:24 -0700811 char *name = (char *)(fsym ^ SYMBOL_TAG);
812 struct function *func = find_function(env, name);
swissChili7e1393c2021-07-07 12:59:12 -0700813
swissChili74348422021-07-04 13:23:24 -0700814 bool is_recursive = false;
swissChili15f1cae2021-07-05 19:08:47 -0700815 struct args *nargs_needed = NULL;
swissChili53472e82021-05-08 16:06:32 -0700816
swissChili53e7cd12021-08-02 21:55:53 -0700817 // The number of arguments actually passed on the stack,
818 // i.e. all varargs are 1.
swissChilib51552c2021-08-03 10:23:37 -0700819 int real_nargs;
swissChili53e7cd12021-08-02 21:55:53 -0700820
swissChili7e1393c2021-07-07 12:59:12 -0700821 if (local->current_function_name &&
822 symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700823 {
swissChili74348422021-07-04 13:23:24 -0700824 is_recursive = true;
swissChili15f1cae2021-07-05 19:08:47 -0700825 nargs_needed = local->args;
swissChili74348422021-07-04 13:23:24 -0700826 }
827 else
828 {
829 if (func == NULL)
830 {
swissChili6d02af42021-08-05 19:49:01 -0700831 THROW(EINVALID, "Function %s undefined", name);
swissChili74348422021-07-04 13:23:24 -0700832 }
833
swissChili15f1cae2021-07-05 19:08:47 -0700834 nargs_needed = func->args;
swissChili74348422021-07-04 13:23:24 -0700835 }
836
swissChili15f1cae2021-07-05 19:08:47 -0700837 if (!are_args_acceptable(nargs_needed, nargs))
swissChili74348422021-07-04 13:23:24 -0700838 {
swissChili6d02af42021-08-05 19:49:01 -0700839 THROW(EARGS,
840 "wrong number of args in function call: %s, "
841 "want %d args but given %d\n",
842 name, nargs_needed->num_required, nargs);
swissChilif1ba8c12021-07-02 18:45:38 -0700843 }
swissChili53472e82021-05-08 16:06:32 -0700844
swissChili53e7cd12021-08-02 21:55:53 -0700845 int total_taken = nargs_needed->num_optional +
846 nargs_needed->num_required;
847
swissChilib51552c2021-08-03 10:23:37 -0700848 real_nargs = total_taken + (nargs_needed->variadic ? 1 : 0);
swissChili53e7cd12021-08-02 21:55:53 -0700849
swissChili74348422021-07-04 13:23:24 -0700850 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700851 {
swissChili15f1cae2021-07-05 19:08:47 -0700852 int nargs = length(args);
853
swissChili484295d2021-07-09 21:25:55 -0700854 int line = cons_line(val);
855 char *file = cons_file(val);
856
857 if (nargs_needed->variadic)
swissChili15f1cae2021-07-05 19:08:47 -0700858 {
swissChili484295d2021-07-09 21:25:55 -0700859 | push (nil);
860 }
861
862 if (nargs > total_taken && nargs_needed->variadic)
863 {
864 // We are passing varargs, which means we need to make a list
865
866 for (int i = nargs - 1; i >= total_taken; i--)
867 {
swissChili6d02af42021-08-05 19:49:01 -0700868 TRY(compile_expression(env, local, elt(args, i), false, Dst));
swissChili484295d2021-07-09 21:25:55 -0700869 | push eax;
swissChili53e7cd12021-08-02 21:55:53 -0700870 | call_extern cons;
swissChili484295d2021-07-09 21:25:55 -0700871 | add esp, 8;
872 | push eax;
873 }
swissChili15f1cae2021-07-05 19:08:47 -0700874 }
875
swissChili7e1393c2021-07-07 12:59:12 -0700876 for (int i = nargs_needed->num_optional - 1;
877 i >= nargs - nargs_needed->num_required; i--)
swissChili15f1cae2021-07-05 19:08:47 -0700878 {
879 // Push the default optional values
swissChili484295d2021-07-09 21:25:55 -0700880 | push (nargs_needed->optional_arguments[i].value);
swissChili15f1cae2021-07-05 19:08:47 -0700881 }
882
swissChili484295d2021-07-09 21:25:55 -0700883 int min = MIN(nargs, total_taken);
884
885 for (int i = min - 1; i >= 0; i--)
swissChili2999dd12021-07-02 14:19:53 -0700886 {
swissChili6d02af42021-08-05 19:49:01 -0700887 TRY(compile_expression(env, local, elt(args, i), false, Dst));
swissChili2999dd12021-07-02 14:19:53 -0700888 | push eax;
889 }
swissChili15f1cae2021-07-05 19:08:47 -0700890
swissChili74348422021-07-04 13:23:24 -0700891 if (is_recursive)
892 {
swissChilib51552c2021-08-03 10:23:37 -0700893 if (tail)
894 {
895 // Move all the arguments pushed to the stack
896 // back up to the argument bit of the stack.
897
898 for (int i = 0; i < real_nargs; i++)
899 {
900 | pop eax;
901 | mov dword[ebp + (value_size * (i + 2))], eax;
902 }
903
904 // Jmp back to start
905 | mov esp, ebp;
906 | pop ebp;
907 | jmp <1;
908 }
909 else
910 {
911 | call <1;
912 }
swissChili74348422021-07-04 13:23:24 -0700913 }
914 else
915 {
swissChili484295d2021-07-09 21:25:55 -0700916 // | mov ebx, (func->code_addr);
917 | call_extern func->code_addr;
swissChili74348422021-07-04 13:23:24 -0700918 }
swissChili53e7cd12021-08-02 21:55:53 -0700919 | add esp, (real_nargs * value_size);
swissChili2999dd12021-07-02 14:19:53 -0700920 // result in eax
921 }
922 else if (func->namespace == NS_MACRO)
923 {
swissChili7e1393c2021-07-07 12:59:12 -0700924 // Make sure that the stuff allocated by the macro isn't in a
925 // pool
swissChilif68671f2021-07-05 14:14:44 -0700926 unsigned char pool = push_pool(0);
927
swissChili2999dd12021-07-02 14:19:53 -0700928 value_t expanded_to = call_list(func, args);
929
swissChilif68671f2021-07-05 14:14:44 -0700930 pop_pool(pool);
931
swissChili6d02af42021-08-05 19:49:01 -0700932 TRY(compile_expression(env, local, expanded_to, false, Dst));
swissChili2999dd12021-07-02 14:19:53 -0700933 }
swissChili53472e82021-05-08 16:06:32 -0700934 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700935 }
swissChili923b5362021-05-09 20:31:43 -0700936 else if (symbolp(val))
937 {
swissChili7e1393c2021-07-07 12:59:12 -0700938 if (symstreq(val, "+current-file+"))
swissChilie9fec8b2021-06-22 13:59:33 -0700939 {
swissChili7e1393c2021-07-07 12:59:12 -0700940 value_t file_name_val = strval(local->current_file_path);
941
942 | mov eax, (file_name_val);
swissChilie9fec8b2021-06-22 13:59:33 -0700943 }
swissChili7e1393c2021-07-07 12:59:12 -0700944 else
945 {
946 struct variable *v =
947 find_variable(local, (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700948
swissChili7e1393c2021-07-07 12:59:12 -0700949 if (!v)
950 {
swissChili6d02af42021-08-05 19:49:01 -0700951 THROW(EINVALID, "Variable `%s' unbound", (char *)(val ^ SYMBOL_TAG));
swissChili7e1393c2021-07-07 12:59:12 -0700952 }
953
swissChili6d02af42021-08-05 19:49:01 -0700954 TRY(compile_variable(v, Dst));
swissChili7e1393c2021-07-07 12:59:12 -0700955 }
swissChili923b5362021-05-09 20:31:43 -0700956 }
swissChilia89ee442021-08-04 20:54:51 -0700957 else if (closurep(val))
958 {
959 | mov eax, val;
960 }
961 else
962 {
963 printval(val, 1);
swissChili6d02af42021-08-05 19:49:01 -0700964 THROW(EUNIMPL, "Don't know how to compile this, sorry.");
swissChilia89ee442021-08-04 20:54:51 -0700965 }
swissChili6d02af42021-08-05 19:49:01 -0700966
967 OKAY();
swissChilib3ca4fb2021-04-20 10:33:00 -0700968}
swissChilif3e7f182021-04-20 13:57:22 -0700969
swissChili923b5362021-05-09 20:31:43 -0700970struct variable *add_variable(struct local *local, enum var_type type,
971 char *name, int number)
972{
973 struct variable *var = malloc(sizeof(struct variable));
974 var->prev = local->first;
975 var->type = type;
976 var->name = name;
977 var->number = number;
978
979 local->first = var;
980
981 return var;
982}
983
984void destroy_local(struct local *local)
985{
986 for (struct variable *v = local->first; v;)
987 {
988 struct variable *t = v;
989 v = v->prev;
990 free(t);
991 }
992}
993
994struct variable *find_variable(struct local *local, char *name)
995{
996 struct variable *v = local->first;
997
998 for (; v && strcmp(v->name, name) != 0; v = v->prev)
swissChili7e1393c2021-07-07 12:59:12 -0700999 {
1000 }
swissChili923b5362021-05-09 20:31:43 -07001001
swissChiliddc97542021-07-04 11:47:42 -07001002 if (!v)
1003 {
1004 if (local->parent)
1005 {
1006 v = find_variable(local->parent, name);
1007
1008 if (v)
1009 {
swissChili15f1cae2021-07-05 19:08:47 -07001010 // We found this in a parent scope, add it as a V_FREE variable
1011 // to skip the search.
swissChili7e1393c2021-07-07 12:59:12 -07001012 v = add_variable(local, V_FREE, name,
1013 local->num_closure_slots++);
swissChiliddc97542021-07-04 11:47:42 -07001014 }
1015 }
1016 }
swissChili923b5362021-05-09 20:31:43 -07001017 return v;
1018}
swissChili2999dd12021-07-02 14:19:53 -07001019
swissChiliddc97542021-07-04 11:47:42 -07001020extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -07001021
swissChili7e1393c2021-07-07 12:59:12 -07001022value_t call_list_args(void *code_ptr, struct args *args, value_t list,
1023 void *data)
swissChili2999dd12021-07-02 14:19:53 -07001024{
swissChili15f1cae2021-07-05 19:08:47 -07001025 list = deep_copy(list);
swissChili484295d2021-07-09 21:25:55 -07001026
swissChili15f1cae2021-07-05 19:08:47 -07001027 int nargs = length(list);
1028
swissChili484295d2021-07-09 21:25:55 -07001029 value_t *val = &list;
swissChili15f1cae2021-07-05 19:08:47 -07001030
1031 for (value_t i = list; !nilp(i); i = cdr(i))
1032 {
1033 val = cdrref(i);
1034 }
1035
1036 int total_required = args->num_required + args->num_optional;
1037
1038 if (nargs > total_required)
1039 {
1040 // Take the remainder of the list and put it as the last item in the
1041 // list.
1042 value_t trailing = cxdr(list, total_required);
1043 value_t last_item = cons(trailing, nil);
1044
1045 *cxdrref(&list, total_required) = last_item;
1046 }
1047 else if (nargs < total_required)
1048 {
1049 for (int i = nargs - args->num_required; i < args->num_optional; i++)
1050 {
1051 // Append the i-th defualt argument
1052 value_t appended = cons(args->optional_arguments[i].value, nil);
1053 *val = appended;
1054 val = cdrref(appended);
1055 }
1056 }
1057
1058 // We want to call this if we pass the correct # of arguments or less, just
1059 // not if we have already passed varargs. Appends a nil argument.
1060 if (nargs <= total_required)
1061 {
1062 // Enough real arguments but no variadic arguments. Pass a nil list.
1063 *val = cons(nil, nil);
1064 }
1065
1066 return _call_list(code_ptr, list, data);
1067}
1068
1069value_t call_list(struct function *fun, value_t list)
1070{
1071 return call_list_args(fun->code_ptr, fun->args, list, NULL);
swissChiliddc97542021-07-04 11:47:42 -07001072}
1073
1074value_t call_list_closure(struct closure *c, value_t list)
1075{
swissChili15f1cae2021-07-05 19:08:47 -07001076 return call_list_args(c->function, c->args, list, c->data);
1077}
1078
1079struct args *new_args()
1080{
1081 struct args *a = malloc(sizeof(struct args));
1082 a->num_optional = 0;
1083 a->num_required = 0;
1084 a->variadic = false;
1085
1086 return a;
1087}
1088
swissChili7e1393c2021-07-07 12:59:12 -07001089struct args *add_optional_arg(struct args *args, value_t name, value_t value)
swissChili15f1cae2021-07-05 19:08:47 -07001090{
1091 int i = args->num_optional++;
swissChili7e1393c2021-07-07 12:59:12 -07001092 args =
1093 realloc(args, sizeof(struct args) + sizeof(struct optional_argument) *
1094 args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -07001095
swissChili7e1393c2021-07-07 12:59:12 -07001096 args->optional_arguments[i] = (struct optional_argument){
1097 .value = value,
1098 .name = name,
swissChili15f1cae2021-07-05 19:08:47 -07001099 };
1100
1101 return args;
1102}
1103
1104bool are_args_acceptable(struct args *args, int number)
1105{
1106 if (args->variadic)
1107 {
1108 return number >= args->num_required;
1109 }
1110 else
1111 {
1112 return number >= args->num_required &&
swissChili7e1393c2021-07-07 12:59:12 -07001113 number <= args->num_required + args->num_optional;
swissChili15f1cae2021-07-05 19:08:47 -07001114 }
1115}
1116
swissChili6d02af42021-08-05 19:49:01 -07001117struct error list_to_args(struct environment *env, value_t list,
1118 struct local *local, struct args **a)
swissChili15f1cae2021-07-05 19:08:47 -07001119{
swissChili6d02af42021-08-05 19:49:01 -07001120 E_INIT();
1121
swissChili15f1cae2021-07-05 19:08:47 -07001122 struct args *args = new_args();
1123
1124 bool in_optional = false;
1125
1126 for (value_t i = list; !nilp(i); i = cdr(i))
1127 {
1128 value_t val = car(i);
swissChili6d02af42021-08-05 19:49:01 -07001129 NEARVAL(i);
1130
swissChili15f1cae2021-07-05 19:08:47 -07001131 if (symbolp(val))
1132 {
1133 if (!args->variadic && symstreq(val, "&"))
1134 {
1135 i = cdr(i);
1136 value_t name = car(i);
1137
1138 if (!symbolp(name))
1139 {
swissChili6d02af42021-08-05 19:49:01 -07001140 THROW(EEXPECTED, "You must provide a symbol after & in an argument list "
1141 "to bind the\n"
1142 "variadic arguments to.");
swissChili15f1cae2021-07-05 19:08:47 -07001143 }
1144
1145 args->variadic = true;
1146
1147 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
swissChili7e1393c2021-07-07 12:59:12 -07001148 args->num_optional + args->num_required);
swissChili15f1cae2021-07-05 19:08:47 -07001149
1150 continue;
1151 }
1152
1153 if (!in_optional)
1154 {
swissChili7e1393c2021-07-07 12:59:12 -07001155 add_variable(local, V_ARGUMENT, (char *)(val ^ SYMBOL_TAG),
1156 args->num_required++);
swissChili15f1cae2021-07-05 19:08:47 -07001157 }
1158 else
1159 {
1160 char *name = (char *)(val ^ SYMBOL_TAG);
1161 if (name[0] == '&')
1162 {
swissChili6d02af42021-08-05 19:49:01 -07001163 THROW(EINVALID, "Non-optional argument following optional arguments "
1164 "starts with a &\n"
1165 "did you mean to declare a variadic argument? If so "
1166 "leave a space\n"
1167 "between the & and name.");
swissChili15f1cae2021-07-05 19:08:47 -07001168 }
1169 else
1170 {
swissChili6d02af42021-08-05 19:49:01 -07001171 THROW(EINVALID, "Cannot define a non-optional argument after an "
1172 "optional one.");
swissChili15f1cae2021-07-05 19:08:47 -07001173 }
1174 }
1175 }
1176 else if (listp(val))
1177 {
swissChili6d02af42021-08-05 19:49:01 -07001178 NEARVAL(val);
1179
swissChili15f1cae2021-07-05 19:08:47 -07001180 in_optional = true;
1181 int len = length(val);
1182
1183 if (len != 2)
1184 {
swissChili6d02af42021-08-05 19:49:01 -07001185 THROW(EINVALID, "A list defining an optional value must be structured like "
1186 "(name expr)\n"
1187 "with exactly two arguments.");
swissChili15f1cae2021-07-05 19:08:47 -07001188 }
1189
1190 value_t name = car(val);
1191 value_t expr = car(cdr(val));
1192
1193 value_t function = cons(nil, cons(expr, nil));
1194
swissChili6d02af42021-08-05 19:49:01 -07001195 dasm_State *d;
1196 TRY(compile_function(function, NS_ANONYMOUS, env, NULL, NULL, NULL,
1197 NULL, local->current_file_path, &d));
swissChili15f1cae2021-07-05 19:08:47 -07001198
1199 // TODO: GC stack top!
1200 value_t (*compiled)() = link_program(&d);
1201
1202 value_t value = compiled();
1203 args = add_optional_arg(args, name, value);
1204
swissChili7e1393c2021-07-07 12:59:12 -07001205 add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
1206 args->num_required + args->num_optional - 1);
swissChili15f1cae2021-07-05 19:08:47 -07001207 }
1208 }
1209
swissChili6d02af42021-08-05 19:49:01 -07001210 *a = args;
1211 OKAY();
swissChili15f1cae2021-07-05 19:08:47 -07001212}
1213
1214void display_args(struct args *args)
1215{
1216 printf("Args object taking %d require arguments and %d optionals:\n",
swissChili7e1393c2021-07-07 12:59:12 -07001217 args->num_required, args->num_optional);
swissChili15f1cae2021-07-05 19:08:47 -07001218
1219 for (int i = 0; i < args->num_optional; i++)
1220 {
swissChili7e1393c2021-07-07 12:59:12 -07001221 printf(" %d\t%s\n", i,
1222 (char *)(args->optional_arguments[i].name ^ SYMBOL_TAG));
swissChili15f1cae2021-07-05 19:08:47 -07001223 printval(args->optional_arguments[i].value, 2);
1224 }
swissChili2999dd12021-07-02 14:19:53 -07001225}