this repo has no description
1// vim: set tabstop=2 shiftwidth=2 textwidth=79 expandtab:
2// gcc -O2 -g -Wall -Wextra -pedantic -fno-strict-aliasing
3// assets/code/lisp/compiling-if.c
4
5// In general: https://course.ccs.neu.edu/cs4410sp20/#%28part._lectures%29
6// https://course.ccs.neu.edu/cs4410sp20/lec_let-and-stack_notes.html#%28part._let._.Growing_the_language__adding_let%29
7
8#define _GNU_SOURCE
9#include <assert.h> // for assert
10#include <stdbool.h> // for bool
11#include <stddef.h> // for NULL
12#include <stdint.h> // for int32_t, etc
13#include <stdio.h> // for getline, fprintf
14#include <string.h> // for memcpy
15#include <sys/mman.h> // for mmap
16#undef _GNU_SOURCE
17
18#include "greatest.h"
19
20#define WARN_UNUSED __attribute__((warn_unused_result))
21
22// Objects
23
24typedef int64_t word;
25typedef uint64_t uword;
26
27// These constants are defined in a enum because the right hand side of a
28// statement like
29// static const int kFoo = ...;
30// must be a so-called "Integer Constant Expression". Compilers are required to
31// support a certain set of these expressions, but are not required to support
32// arbitrary arithmetic with other integer constants. Compilers such as gcc
33// before gcc-8 just decided not to play this game, while gcc-8+ and Clang play
34// just fine.
35// Since this arithmetic with constant values works just fine for enums, make
36// all these constants enum values instead.
37// See https://twitter.com/tekknolagi/status/1328449329472835586 for more info.
38enum {
39 kBitsPerByte = 8, // bits
40 kWordSize = sizeof(word), // bytes
41 kBitsPerWord = kWordSize * kBitsPerByte, // bits
42
43 kIntegerTag = 0x0, // 0b00
44 kIntegerTagMask = 0x3, // 0b11
45 kIntegerShift = 2,
46 kIntegerBits = kBitsPerWord - kIntegerShift,
47
48 kImmediateTagMask = 0x3f,
49
50 kCharTag = 0x0f, // 0b00001111
51 kCharMask = 0xff, // 0b11111111
52 kCharShift = 8,
53
54 kBoolTag = 0x1f, // 0b0011111
55 kBoolMask = 0x80, // 0b10000000
56 kBoolShift = 7,
57
58 kNilTag = 0x2f, // 0b101111
59
60 kErrorTag = 0x3f, // 0b111111
61
62 kPairTag = 0x1, // 0b001
63 kSymbolTag = 0x5, // 0b101
64 kClosureTag = 0x6, // 0b110
65 kHeapTagMask = ((uword)0x7), // 0b000...111
66 kHeapPtrMask = ~kHeapTagMask, // 0b1111...1000
67};
68
69// These are defined as macros because they will not work as static const int
70// constants (per above explanation), and enum constants are only required to
71// be an int wide (per ISO C).
72#define INTEGER_MAX ((1LL << (kIntegerBits - 1)) - 1)
73#define INTEGER_MIN (-(1LL << (kIntegerBits - 1)))
74
75uword Object_encode_integer(word value) {
76 assert(value < INTEGER_MAX && "too big");
77 assert(value > INTEGER_MIN && "too small");
78 return value << kIntegerShift;
79}
80
81word Object_decode_integer(uword value) { return (word)value >> kIntegerShift; }
82
83bool Object_is_integer(uword value) {
84 return (value & kIntegerTagMask) == kIntegerTag;
85}
86
87uword Object_encode_char(char value) {
88 return ((uword)value << kCharShift) | kCharTag;
89}
90
91char Object_decode_char(uword value) {
92 return (value >> kCharShift) & kCharMask;
93}
94
95bool Object_is_char(uword value) {
96 return (value & kImmediateTagMask) == kCharTag;
97}
98
99uword Object_encode_bool(bool value) {
100 return ((uword)value << kBoolShift) | kBoolTag;
101}
102
103bool Object_decode_bool(uword value) { return value & kBoolMask; }
104
105uword Object_true() { return Object_encode_bool(true); }
106
107uword Object_false() { return Object_encode_bool(false); }
108
109uword Object_nil() { return kNilTag; }
110
111uword Object_error() { return kErrorTag; }
112
113uword Object_address(void *obj) { return (uword)obj & kHeapPtrMask; }
114
115// End Objects
116
117// Buffer
118
119typedef unsigned char byte;
120
121typedef enum {
122 kWritable,
123 kExecutable,
124} BufferState;
125
126typedef struct {
127 byte *address;
128 BufferState state;
129 word len;
130 word capacity;
131} Buffer;
132
133byte *Buffer_alloc_writable(word capacity) {
134 byte *result = mmap(/*addr=*/NULL, capacity, PROT_READ | PROT_WRITE,
135 MAP_ANONYMOUS | MAP_PRIVATE,
136 /*filedes=*/-1, /*off=*/0);
137 assert(result != MAP_FAILED);
138 return result;
139}
140
141void Buffer_init(Buffer *result, word capacity) {
142 result->address = Buffer_alloc_writable(capacity);
143 assert(result->address != MAP_FAILED);
144 result->state = kWritable;
145 result->len = 0;
146 result->capacity = capacity;
147}
148
149word Buffer_len(Buffer *buf) { return buf->len; }
150
151void Buffer_deinit(Buffer *buf) {
152 munmap(buf->address, buf->capacity);
153 buf->address = NULL;
154 buf->len = 0;
155 buf->capacity = 0;
156}
157
158int Buffer_make_executable(Buffer *buf) {
159 int result = mprotect(buf->address, buf->len, PROT_EXEC);
160 buf->state = kExecutable;
161 return result;
162}
163
164byte Buffer_at8(Buffer *buf, word pos) { return buf->address[pos]; }
165
166void Buffer_at_put8(Buffer *buf, word pos, byte b) { buf->address[pos] = b; }
167
168word max(word left, word right) { return left > right ? left : right; }
169
170void Buffer_ensure_capacity(Buffer *buf, word additional_capacity) {
171 if (buf->len + additional_capacity <= buf->capacity) {
172 return;
173 }
174 word new_capacity =
175 max(buf->capacity * 2, buf->capacity + additional_capacity);
176 byte *address = Buffer_alloc_writable(new_capacity);
177 memcpy(address, buf->address, buf->len);
178 int result = munmap(buf->address, buf->capacity);
179 assert(result == 0 && "munmap failed");
180 buf->address = address;
181 buf->capacity = new_capacity;
182}
183
184void Buffer_write8(Buffer *buf, byte b) {
185 Buffer_ensure_capacity(buf, sizeof b);
186 Buffer_at_put8(buf, buf->len++, b);
187}
188
189void Buffer_write32(Buffer *buf, int32_t value) {
190 for (uword i = 0; i < sizeof(value); i++) {
191 Buffer_write8(buf, (value >> (i * kBitsPerByte)) & 0xff);
192 }
193}
194
195void Buffer_at_put32(Buffer *buf, word offset, int32_t value) {
196 for (uword i = 0; i < sizeof(value); i++) {
197 Buffer_at_put8(buf, offset + i, (value >> (i * kBitsPerByte)) & 0xff);
198 }
199}
200
201void Buffer_write_arr(Buffer *buf, const byte *arr, word arr_size) {
202 Buffer_ensure_capacity(buf, arr_size);
203 for (word i = 0; i < arr_size; i++) {
204 Buffer_write8(buf, arr[i]);
205 }
206}
207
208// End Buffer
209
210// Emit
211
212typedef enum {
213 kRax = 0,
214 kRcx,
215 kRdx,
216 kRbx,
217 kRsp,
218 kRbp,
219 kRsi,
220 kRdi,
221} Register;
222
223typedef enum {
224 kAl = 0,
225 kCl,
226 kDl,
227 kBl,
228 kAh,
229 kCh,
230 kDh,
231 kBh,
232} PartialRegister;
233
234typedef enum {
235 kOverflow = 0,
236 kNotOverflow,
237 kBelow,
238 kCarry = kBelow,
239 kNotAboveOrEqual = kBelow,
240 kAboveOrEqual,
241 kNotBelow = kAboveOrEqual,
242 kNotCarry = kAboveOrEqual,
243 kEqual,
244 kZero = kEqual,
245 kLess = 0xc,
246 kNotGreaterOrEqual = kLess,
247 // TODO(max): Add more
248} Condition;
249
250typedef struct Indirect {
251 Register reg;
252 int8_t disp;
253} Indirect;
254
255Indirect Ind(Register reg, int8_t disp) {
256 return (Indirect){.reg = reg, .disp = disp};
257}
258
259enum {
260 kRexPrefix = 0x48,
261};
262
263void Emit_mov_reg_imm32(Buffer *buf, Register dst, int32_t src) {
264 Buffer_write8(buf, kRexPrefix);
265 Buffer_write8(buf, 0xc7);
266 Buffer_write8(buf, 0xc0 + dst);
267 Buffer_write32(buf, src);
268}
269
270void Emit_ret(Buffer *buf) { Buffer_write8(buf, 0xc3); }
271
272void Emit_add_reg_imm32(Buffer *buf, Register dst, int32_t src) {
273 Buffer_write8(buf, kRexPrefix);
274 if (dst == kRax) {
275 // Optimization: add eax, {imm32} can either be encoded as 05 {imm32} or 81
276 // c0 {imm32}.
277 Buffer_write8(buf, 0x05);
278 } else {
279 Buffer_write8(buf, 0x81);
280 Buffer_write8(buf, 0xc0 + dst);
281 }
282 Buffer_write32(buf, src);
283}
284
285void Emit_sub_reg_imm32(Buffer *buf, Register dst, int32_t src) {
286 Buffer_write8(buf, kRexPrefix);
287 if (dst == kRax) {
288 // Optimization: sub eax, {imm32} can either be encoded as 2d {imm32} or 81
289 // e8 {imm32}.
290 Buffer_write8(buf, 0x2d);
291 } else {
292 Buffer_write8(buf, 0x81);
293 Buffer_write8(buf, 0xe8 + dst);
294 }
295 Buffer_write32(buf, src);
296}
297
298void Emit_shl_reg_imm8(Buffer *buf, Register dst, int8_t bits) {
299 Buffer_write8(buf, kRexPrefix);
300 Buffer_write8(buf, 0xc1);
301 Buffer_write8(buf, 0xe0 + dst);
302 Buffer_write8(buf, bits);
303}
304
305void Emit_shr_reg_imm8(Buffer *buf, Register dst, int8_t bits) {
306 Buffer_write8(buf, kRexPrefix);
307 Buffer_write8(buf, 0xc1);
308 Buffer_write8(buf, 0xe8 + dst);
309 Buffer_write8(buf, bits);
310}
311
312void Emit_or_reg_imm8(Buffer *buf, Register dst, uint8_t tag) {
313 Buffer_write8(buf, kRexPrefix);
314 Buffer_write8(buf, 0x83);
315 Buffer_write8(buf, 0xc8 + dst);
316 Buffer_write8(buf, tag);
317}
318
319void Emit_and_reg_imm8(Buffer *buf, Register dst, uint8_t tag) {
320 Buffer_write8(buf, kRexPrefix);
321 Buffer_write8(buf, 0x83);
322 Buffer_write8(buf, 0xe0 + dst);
323 Buffer_write8(buf, tag);
324}
325
326void Emit_cmp_reg_imm32(Buffer *buf, Register left, int32_t right) {
327 Buffer_write8(buf, kRexPrefix);
328 if (left == kRax) {
329 // Optimization: cmp rax, {imm32} can either be encoded as 3d {imm32} or 81
330 // f8 {imm32}.
331 Buffer_write8(buf, 0x3d);
332 } else {
333 Buffer_write8(buf, 0x81);
334 Buffer_write8(buf, 0xf8 + left);
335 }
336 Buffer_write32(buf, right);
337}
338
339void Emit_setcc_imm8(Buffer *buf, Condition cond, PartialRegister dst) {
340 Buffer_write8(buf, 0x0f);
341 Buffer_write8(buf, 0x90 + cond);
342 Buffer_write8(buf, 0xc0 + dst);
343}
344
345uint8_t disp8(int8_t disp) { return disp >= 0 ? disp : 0x100 + disp; }
346
347// mov [dst+disp], src
348// or
349// mov %src, disp(%dst)
350void Emit_store_reg_indirect(Buffer *buf, Indirect dst, Register src) {
351 Buffer_write8(buf, kRexPrefix);
352 Buffer_write8(buf, 0x89);
353 Buffer_write8(buf, 0x40 + src * 8 + dst.reg);
354 Buffer_write8(buf, disp8(dst.disp));
355}
356
357// add dst, [src+disp]
358// or
359// add disp(%src), %dst
360void Emit_add_reg_indirect(Buffer *buf, Register dst, Indirect src) {
361 Buffer_write8(buf, kRexPrefix);
362 Buffer_write8(buf, 0x03);
363 Buffer_write8(buf, 0x40 + dst * 8 + src.reg);
364 Buffer_write8(buf, disp8(src.disp));
365}
366
367// sub dst, [src+disp]
368// or
369// sub disp(%src), %dst
370void Emit_sub_reg_indirect(Buffer *buf, Register dst, Indirect src) {
371 Buffer_write8(buf, kRexPrefix);
372 Buffer_write8(buf, 0x2b);
373 Buffer_write8(buf, 0x40 + dst * 8 + src.reg);
374 Buffer_write8(buf, disp8(src.disp));
375}
376
377// mul rax, [src+disp]
378// or
379// mul disp(%src), %rax
380void Emit_mul_reg_indirect(Buffer *buf, Indirect src) {
381 Buffer_write8(buf, kRexPrefix);
382 Buffer_write8(buf, 0xf7);
383 Buffer_write8(buf, 0x60 + src.reg);
384 Buffer_write8(buf, disp8(src.disp));
385}
386
387// cmp left, [right+disp]
388// or
389// cmp disp(%right), %left
390void Emit_cmp_reg_indirect(Buffer *buf, Register left, Indirect right) {
391 Buffer_write8(buf, kRexPrefix);
392 Buffer_write8(buf, 0x3b);
393 Buffer_write8(buf, 0x40 + left * 8 + right.reg);
394 Buffer_write8(buf, disp8(right.disp));
395}
396
397// mov dst, [src+disp]
398// or
399// mov disp(%src), %dst
400void Emit_load_reg_indirect(Buffer *buf, Register dst, Indirect src) {
401 Buffer_write8(buf, kRexPrefix);
402 Buffer_write8(buf, 0x8b);
403 Buffer_write8(buf, 0x40 + dst * 8 + src.reg);
404 Buffer_write8(buf, disp8(src.disp));
405}
406
407static uint32_t disp32(int32_t disp) {
408 return disp >= 0 ? disp : 0x100000000 + disp;
409}
410
411word Emit_jcc(Buffer *buf, Condition cond, int32_t offset) {
412 Buffer_write8(buf, 0x0f);
413 Buffer_write8(buf, 0x80 + cond);
414 word pos = Buffer_len(buf);
415 Buffer_write32(buf, disp32(offset));
416 return pos;
417}
418
419word Emit_jmp(Buffer *buf, int32_t offset) {
420 Buffer_write8(buf, 0xe9);
421 word pos = Buffer_len(buf);
422 Buffer_write32(buf, disp32(offset));
423 return pos;
424}
425
426void Emit_backpatch_imm32(Buffer *buf, int32_t target_pos) {
427 word current_pos = Buffer_len(buf);
428 word relative_pos = current_pos - target_pos - sizeof(int32_t);
429 Buffer_at_put32(buf, target_pos, disp32(relative_pos));
430}
431
432// End Emit
433
434// AST
435
436typedef struct ASTNode ASTNode;
437
438typedef struct Pair {
439 ASTNode *car;
440 ASTNode *cdr;
441} Pair;
442
443typedef struct Symbol {
444 word length;
445 char cstr[];
446} Symbol;
447
448bool AST_is_integer(ASTNode *node) {
449 return ((uword)node & kIntegerTagMask) == kIntegerTag;
450}
451
452word AST_get_integer(ASTNode *node) {
453 return Object_decode_integer((uword)node);
454}
455
456ASTNode *AST_new_integer(word value) {
457 return (ASTNode *)Object_encode_integer(value);
458}
459
460bool AST_is_char(ASTNode *node) {
461 return ((uword)node & kImmediateTagMask) == kCharTag;
462}
463
464char AST_get_char(ASTNode *node) { return Object_decode_char((uword)node); }
465
466ASTNode *AST_new_char(char value) {
467 return (ASTNode *)Object_encode_char(value);
468}
469
470bool AST_is_bool(ASTNode *node) {
471 return ((uword)node & kImmediateTagMask) == kBoolTag;
472}
473
474bool AST_get_bool(ASTNode *node) { return Object_decode_bool((uword)node); }
475
476ASTNode *AST_new_bool(bool value) {
477 return (ASTNode *)Object_encode_bool(value);
478}
479
480bool AST_is_nil(ASTNode *node) { return (uword)node == Object_nil(); }
481
482ASTNode *AST_nil() { return (ASTNode *)Object_nil(); }
483
484bool AST_is_error(ASTNode *node) { return (uword)node == Object_error(); }
485
486ASTNode *AST_error() { return (ASTNode *)Object_error(); }
487
488ASTNode *AST_heap_alloc(unsigned char tag, uword size) {
489 // Initialize to 0
490 uword address = (uword)calloc(size, 1);
491 return (ASTNode *)(address | tag);
492}
493
494bool AST_is_heap_object(ASTNode *node) {
495 // For some reason masking out the tag first and then doing the comparison
496 // makes this branchless
497 unsigned char tag = (uword)node & kHeapTagMask;
498 // Heap object tags are between 0b001 and 0b110 except for 0b100 (which is an
499 // integer)
500 return (tag & kIntegerTagMask) > 0 && (tag & kImmediateTagMask) != 0x7;
501}
502
503void AST_pair_set_car(ASTNode *node, ASTNode *car);
504void AST_pair_set_cdr(ASTNode *node, ASTNode *cdr);
505
506ASTNode *AST_new_pair(ASTNode *car, ASTNode *cdr) {
507 ASTNode *node = AST_heap_alloc(kPairTag, sizeof(Pair));
508 AST_pair_set_car(node, car);
509 AST_pair_set_cdr(node, cdr);
510 return node;
511}
512
513bool AST_is_pair(ASTNode *node) {
514 return ((uword)node & kHeapTagMask) == kPairTag;
515}
516
517Pair *AST_as_pair(ASTNode *node) {
518 assert(AST_is_pair(node));
519 return (Pair *)Object_address(node);
520}
521
522ASTNode *AST_pair_car(ASTNode *node) { return AST_as_pair(node)->car; }
523
524void AST_pair_set_car(ASTNode *node, ASTNode *car) {
525 AST_as_pair(node)->car = car;
526}
527
528ASTNode *AST_pair_cdr(ASTNode *node) { return AST_as_pair(node)->cdr; }
529
530void AST_pair_set_cdr(ASTNode *node, ASTNode *cdr) {
531 AST_as_pair(node)->cdr = cdr;
532}
533
534void AST_heap_free(ASTNode *node) {
535 if (!AST_is_heap_object(node)) {
536 return;
537 }
538 if (AST_is_pair(node)) {
539 AST_heap_free(AST_pair_car(node));
540 AST_heap_free(AST_pair_cdr(node));
541 }
542 free((void *)Object_address(node));
543}
544
545Symbol *AST_as_symbol(ASTNode *node);
546
547ASTNode *AST_new_symbol(const char *str) {
548 word data_length = strlen(str) + 1; // for NUL
549 ASTNode *node = AST_heap_alloc(kSymbolTag, sizeof(Symbol) + data_length);
550 Symbol *s = AST_as_symbol(node);
551 s->length = data_length;
552 memcpy(s->cstr, str, data_length);
553 return node;
554}
555
556bool AST_is_symbol(ASTNode *node) {
557 return ((uword)node & kHeapTagMask) == kSymbolTag;
558}
559
560Symbol *AST_as_symbol(ASTNode *node) {
561 assert(AST_is_symbol(node));
562 return (Symbol *)Object_address(node);
563}
564
565const char *AST_symbol_cstr(ASTNode *node) {
566 return (const char *)AST_as_symbol(node)->cstr;
567}
568
569bool AST_symbol_matches(ASTNode *node, const char *cstr) {
570 return strcmp(AST_symbol_cstr(node), cstr) == 0;
571}
572
573int node_to_str(ASTNode *node, char *buf, word size);
574
575int list_to_str(ASTNode *node, char *buf, word size) {
576 if (AST_is_pair(node)) {
577 word result = 0;
578 result += snprintf(buf + result, size, " ");
579 result += node_to_str(AST_pair_car(node), buf + result, size);
580 result += list_to_str(AST_pair_cdr(node), buf + result, size);
581 return result;
582 }
583 if (AST_is_nil(node)) {
584 return snprintf(buf, size, ")");
585 }
586 word result = 0;
587 result += snprintf(buf + result, size, " . ");
588 result += node_to_str(node, buf + result, size);
589 result += snprintf(buf + result, size, ")");
590 return result;
591}
592
593int node_to_str(ASTNode *node, char *buf, word size) {
594 if (AST_is_integer(node)) {
595 return snprintf(buf, size, "%ld", AST_get_integer(node));
596 }
597 if (AST_is_char(node)) {
598 return snprintf(buf, size, "'%c'", AST_get_char(node));
599 }
600 if (AST_is_bool(node)) {
601 return snprintf(buf, size, "%s", AST_get_bool(node) ? "true" : "false");
602 }
603 if (AST_is_nil(node)) {
604 return snprintf(buf, size, "nil");
605 }
606 if (AST_is_pair(node)) {
607 word result = 0;
608 result += snprintf(buf + result, size, "(");
609 result += node_to_str(AST_pair_car(node), buf + result, size);
610 result += list_to_str(AST_pair_cdr(node), buf + result, size);
611 return result;
612 }
613 if (AST_is_symbol(node)) {
614 return snprintf(buf, size, "%s", AST_symbol_cstr(node));
615 }
616 assert(0 && "unknown ast");
617}
618
619char *AST_to_cstr(ASTNode *node) {
620 int size = node_to_str(node, NULL, 0);
621 char *buf = malloc(size + 1);
622 assert(buf != NULL);
623 node_to_str(node, buf, size + 1);
624 buf[size] = '\0';
625 return buf;
626}
627
628// End AST
629
630// Reader
631
632void advance(word *pos) { ++*pos; }
633
634char next(char *input, word *pos) {
635 advance(pos);
636 return input[*pos];
637}
638
639ASTNode *read_integer(char *input, word *pos, int sign) {
640 word result = 0;
641 for (char c = input[*pos]; isdigit(c); c = next(input, pos)) {
642 result *= 10;
643 result += c - '0';
644 }
645 return AST_new_integer(sign * result);
646}
647
648bool starts_symbol(char c) {
649 switch (c) {
650 case '+':
651 case '-':
652 case '*':
653 case '<':
654 case '>':
655 case '=':
656 case '?':
657 return true;
658 default:
659 return isalpha(c);
660 }
661}
662
663bool is_symbol_char(char c) { return starts_symbol(c) || isdigit(c); }
664
665const word ATOM_MAX = 32;
666
667ASTNode *read_symbol(char *input, word *pos) {
668 char buf[ATOM_MAX + 1]; // +1 for NUL
669 word length = 0;
670 for (length = 0; length < ATOM_MAX && is_symbol_char(input[*pos]); length++) {
671 buf[length] = input[*pos];
672 advance(pos);
673 }
674 buf[length] = '\0';
675 return AST_new_symbol(buf);
676}
677
678ASTNode *read_char(char *input, word *pos) {
679 char c = input[*pos];
680 if (c == '\'') {
681 return AST_error();
682 }
683 advance(pos);
684 if (input[*pos] != '\'') {
685 return AST_error();
686 }
687 advance(pos);
688 return AST_new_char(c);
689}
690
691char skip_whitespace(char *input, word *pos) {
692 char c = '\0';
693 for (c = input[*pos]; isspace(c); c = next(input, pos)) {
694 ;
695 }
696 return c;
697}
698
699ASTNode *read_rec(char *input, word *pos);
700
701ASTNode *read_list(char *input, word *pos) {
702 char c = skip_whitespace(input, pos);
703 if (c == ')') {
704 advance(pos);
705 return AST_nil();
706 }
707 ASTNode *car = read_rec(input, pos);
708 assert(car != AST_error());
709 ASTNode *cdr = read_list(input, pos);
710 assert(cdr != AST_error());
711 return AST_new_pair(car, cdr);
712}
713
714ASTNode *read_rec(char *input, word *pos) {
715 char c = skip_whitespace(input, pos);
716 if (isdigit(c)) {
717 return read_integer(input, pos, /*sign=*/1);
718 }
719 if (c == '-' && isdigit(input[*pos + 1])) {
720 advance(pos);
721 return read_integer(input, pos, /*sign=*/-1);
722 }
723 if (c == '+' && isdigit(input[*pos + 1])) {
724 advance(pos);
725 return read_integer(input, pos, /*sign=*/1);
726 }
727 if (starts_symbol(c)) {
728 return read_symbol(input, pos);
729 }
730 if (c == '\'') {
731 advance(pos); // skip '\''
732 return read_char(input, pos);
733 }
734 if (c == '#' && input[*pos + 1] == 't') {
735 advance(pos); // skip '#'
736 advance(pos); // skip 't'
737 return AST_new_bool(true);
738 }
739 if (c == '#' && input[*pos + 1] == 'f') {
740 advance(pos); // skip '#'
741 advance(pos); // skip 'f'
742 return AST_new_bool(false);
743 }
744 if (c == '(') {
745 advance(pos); // skip '('
746 return read_list(input, pos);
747 }
748 return AST_error();
749}
750
751ASTNode *Reader_read(char *input) {
752 word pos = 0;
753 return read_rec(input, &pos);
754}
755
756// End Reader
757
758// Env
759
760typedef struct Env {
761 const char *name;
762 word value;
763 struct Env *prev;
764} Env;
765
766Env Env_bind(const char *name, word value, Env *prev) {
767 return (Env){.name = name, .value = value, .prev = prev};
768}
769
770bool Env_find(Env *env, const char *key, word *result) {
771 if (env == NULL)
772 return false;
773 if (strcmp(env->name, key) == 0) {
774 *result = env->value;
775 return true;
776 }
777 return Env_find(env->prev, key, result);
778}
779
780// End Env
781
782// Compile
783
784WARN_UNUSED int Compile_expr(Buffer *buf, ASTNode *node, word stack_index,
785 Env *varenv);
786
787ASTNode *operand1(ASTNode *args) { return AST_pair_car(args); }
788
789ASTNode *operand2(ASTNode *args) { return AST_pair_car(AST_pair_cdr(args)); }
790
791ASTNode *operand3(ASTNode *args) {
792 return AST_pair_car(AST_pair_cdr(AST_pair_cdr(args)));
793}
794
795#define _(exp) \
796 do { \
797 int result = exp; \
798 if (result != 0) \
799 return result; \
800 } while (0)
801
802void Compile_compare_imm32(Buffer *buf, int32_t value) {
803 Emit_cmp_reg_imm32(buf, kRax, value);
804 Emit_mov_reg_imm32(buf, kRax, 0);
805 Emit_setcc_imm8(buf, kEqual, kAl);
806 Emit_shl_reg_imm8(buf, kRax, kBoolShift);
807 Emit_or_reg_imm8(buf, kRax, kBoolTag);
808}
809
810// This is let, not let*. Therefore we keep track of two environments -- the
811// parent environment, for evaluating the bindings, and the body environment,
812// which will have all of the bindings in addition to the parent. This makes
813// programs like (let ((a 1) (b a)) b) fail.
814WARN_UNUSED int Compile_let(Buffer *buf, ASTNode *bindings, ASTNode *body,
815 word stack_index, Env *binding_env, Env *body_env) {
816 if (AST_is_nil(bindings)) {
817 // Base case: no bindings. Compile the body
818 _(Compile_expr(buf, body, stack_index, body_env));
819 return 0;
820 }
821 assert(AST_is_pair(bindings));
822 // Get the next binding
823 ASTNode *binding = AST_pair_car(bindings);
824 ASTNode *name = AST_pair_car(binding);
825 assert(AST_is_symbol(name));
826 ASTNode *binding_expr = AST_pair_car(AST_pair_cdr(binding));
827 // Compile the binding expression
828 _(Compile_expr(buf, binding_expr, stack_index, binding_env));
829 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRbp, stack_index),
830 /*src=*/kRax);
831 // Bind the name
832 Env entry = Env_bind(AST_symbol_cstr(name), stack_index, body_env);
833 _(Compile_let(buf, AST_pair_cdr(bindings), body, stack_index - kWordSize,
834 /*binding_env=*/binding_env, /*body_env=*/&entry));
835 return 0;
836}
837
838const word kLabelPlaceholder = 0xdeadbeef;
839
840WARN_UNUSED int Compile_if(Buffer *buf, ASTNode *cond, ASTNode *consequent,
841 ASTNode *alternate, word stack_index, Env *varenv) {
842 _(Compile_expr(buf, cond, stack_index, varenv));
843 Emit_cmp_reg_imm32(buf, kRax, Object_false());
844 word alternate_pos = Emit_jcc(buf, kEqual, kLabelPlaceholder); // je alternate
845 _(Compile_expr(buf, consequent, stack_index, varenv));
846 word end_pos = Emit_jmp(buf, kLabelPlaceholder); // jmp end
847 Emit_backpatch_imm32(buf, alternate_pos); // alternate:
848 _(Compile_expr(buf, alternate, stack_index, varenv));
849 Emit_backpatch_imm32(buf, end_pos); // end:
850 return 0;
851}
852
853WARN_UNUSED int Compile_call(Buffer *buf, ASTNode *callable, ASTNode *args,
854 word stack_index, Env *varenv) {
855 if (AST_is_symbol(callable)) {
856 if (AST_symbol_matches(callable, "add1")) {
857 _(Compile_expr(buf, operand1(args), stack_index, varenv));
858 Emit_add_reg_imm32(buf, kRax, Object_encode_integer(1));
859 return 0;
860 }
861 if (AST_symbol_matches(callable, "sub1")) {
862 _(Compile_expr(buf, operand1(args), stack_index, varenv));
863 Emit_sub_reg_imm32(buf, kRax, Object_encode_integer(1));
864 return 0;
865 }
866 if (AST_symbol_matches(callable, "integer->char")) {
867 _(Compile_expr(buf, operand1(args), stack_index, varenv));
868 Emit_shl_reg_imm8(buf, kRax, kCharShift - kIntegerShift);
869 Emit_or_reg_imm8(buf, kRax, kCharTag);
870 return 0;
871 }
872 if (AST_symbol_matches(callable, "char->integer")) {
873 _(Compile_expr(buf, operand1(args), stack_index, varenv));
874 Emit_shr_reg_imm8(buf, kRax, kCharShift - kIntegerShift);
875 return 0;
876 }
877 if (AST_symbol_matches(callable, "nil?")) {
878 _(Compile_expr(buf, operand1(args), stack_index, varenv));
879 Compile_compare_imm32(buf, Object_nil());
880 return 0;
881 }
882 if (AST_symbol_matches(callable, "zero?")) {
883 _(Compile_expr(buf, operand1(args), stack_index, varenv));
884 Compile_compare_imm32(buf, Object_encode_integer(0));
885 return 0;
886 }
887 if (AST_symbol_matches(callable, "not")) {
888 _(Compile_expr(buf, operand1(args), stack_index, varenv));
889 // All non #f values are truthy
890 // ...this might be a problem if we want to make nil falsey
891 Compile_compare_imm32(buf, Object_false());
892 return 0;
893 }
894 if (AST_symbol_matches(callable, "integer?")) {
895 _(Compile_expr(buf, operand1(args), stack_index, varenv));
896 Emit_and_reg_imm8(buf, kRax, kIntegerTagMask);
897 Compile_compare_imm32(buf, kIntegerTag);
898 return 0;
899 }
900 if (AST_symbol_matches(callable, "boolean?")) {
901 _(Compile_expr(buf, operand1(args), stack_index, varenv));
902 Emit_and_reg_imm8(buf, kRax, kImmediateTagMask);
903 Compile_compare_imm32(buf, kBoolTag);
904 return 0;
905 }
906 if (AST_symbol_matches(callable, "+")) {
907 _(Compile_expr(buf, operand2(args), stack_index, varenv));
908 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRbp, stack_index),
909 /*src=*/kRax);
910 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv));
911 Emit_add_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRbp, stack_index));
912 return 0;
913 }
914 if (AST_symbol_matches(callable, "-")) {
915 _(Compile_expr(buf, operand2(args), stack_index, varenv));
916 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRbp, stack_index),
917 /*src=*/kRax);
918 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv));
919 Emit_sub_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRbp, stack_index));
920 return 0;
921 }
922 if (AST_symbol_matches(callable, "*")) {
923 _(Compile_expr(buf, operand2(args), stack_index, varenv));
924 // Remove the tag so that the result is still only tagged with 0b00
925 // instead of 0b0000
926 Emit_shr_reg_imm8(buf, kRax, kIntegerShift);
927 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRbp, stack_index),
928 /*src=*/kRax);
929 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv));
930 Emit_mul_reg_indirect(buf, /*src=*/Ind(kRbp, stack_index));
931 return 0;
932 }
933 if (AST_symbol_matches(callable, "=")) {
934 _(Compile_expr(buf, operand2(args), stack_index, varenv));
935 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRbp, stack_index),
936 /*src=*/kRax);
937 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv));
938 Emit_cmp_reg_indirect(buf, kRax, Ind(kRbp, stack_index));
939 Emit_mov_reg_imm32(buf, kRax, 0);
940 Emit_setcc_imm8(buf, kEqual, kAl);
941 Emit_shl_reg_imm8(buf, kRax, kBoolShift);
942 Emit_or_reg_imm8(buf, kRax, kBoolTag);
943 return 0;
944 }
945 if (AST_symbol_matches(callable, "<")) {
946 _(Compile_expr(buf, operand2(args), stack_index, varenv));
947 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRbp, stack_index),
948 /*src=*/kRax);
949 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv));
950 Emit_cmp_reg_indirect(buf, kRax, Ind(kRbp, stack_index));
951 Emit_mov_reg_imm32(buf, kRax, 0);
952 Emit_setcc_imm8(buf, kLess, kAl);
953 Emit_shl_reg_imm8(buf, kRax, kBoolShift);
954 Emit_or_reg_imm8(buf, kRax, kBoolTag);
955 return 0;
956 }
957 if (AST_symbol_matches(callable, "let")) {
958 return Compile_let(buf, /*bindings=*/operand1(args),
959 /*body=*/operand2(args), stack_index,
960 /*binding_env=*/varenv,
961 /*body_env=*/varenv);
962 }
963 if (AST_symbol_matches(callable, "if")) {
964 return Compile_if(buf, /*condition=*/operand1(args),
965 /*consequent=*/operand2(args),
966 /*alternate=*/operand3(args), stack_index, varenv);
967 }
968 }
969 assert(0 && "unexpected call type");
970}
971
972WARN_UNUSED int Compile_expr(Buffer *buf, ASTNode *node, word stack_index,
973 Env *varenv) {
974 if (AST_is_integer(node)) {
975 word value = AST_get_integer(node);
976 Emit_mov_reg_imm32(buf, kRax, Object_encode_integer(value));
977 return 0;
978 }
979 if (AST_is_char(node)) {
980 char value = AST_get_char(node);
981 Emit_mov_reg_imm32(buf, kRax, Object_encode_char(value));
982 return 0;
983 }
984 if (AST_is_bool(node)) {
985 bool value = AST_get_bool(node);
986 Emit_mov_reg_imm32(buf, kRax, Object_encode_bool(value));
987 return 0;
988 }
989 if (AST_is_nil(node)) {
990 Emit_mov_reg_imm32(buf, kRax, Object_nil());
991 return 0;
992 }
993 if (AST_is_pair(node)) {
994 return Compile_call(buf, AST_pair_car(node), AST_pair_cdr(node),
995 stack_index, varenv);
996 }
997 if (AST_is_symbol(node)) {
998 const char *symbol = AST_symbol_cstr(node);
999 word value;
1000 if (Env_find(varenv, symbol, &value)) {
1001 Emit_load_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRbp, value));
1002 return 0;
1003 }
1004 return -1;
1005 }
1006 assert(0 && "unexpected node type");
1007}
1008
1009static const byte kFunctionPrologue[] = {
1010 // push rbp
1011 0x55,
1012 // mov rbp, rsp
1013 kRexPrefix,
1014 0x89,
1015 0xe5,
1016};
1017
1018static const byte kFunctionEpilogue[] = {
1019 // pop rbp
1020 0x5d,
1021 // ret
1022 0xc3,
1023};
1024
1025WARN_UNUSED int Compile_function(Buffer *buf, ASTNode *node) {
1026 Buffer_write_arr(buf, kFunctionPrologue, sizeof kFunctionPrologue);
1027 _(Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL));
1028 Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue);
1029 return 0;
1030}
1031
1032// End Compile
1033
1034typedef int (*JitFunction)();
1035
1036// Testing
1037
1038uword Testing_execute_expr(Buffer *buf) {
1039 assert(buf != NULL);
1040 assert(buf->address != NULL);
1041 assert(buf->state == kExecutable);
1042 // The pointer-pointer cast is allowed but the underlying
1043 // data-to-function-pointer back-and-forth is only guaranteed to work on
1044 // POSIX systems (because of eg dlsym).
1045 JitFunction function = *(JitFunction *)(&buf->address);
1046 return function();
1047}
1048
1049TEST Testing_expect_function_has_contents(Buffer *buf, byte *arr,
1050 word arr_size) {
1051 word total_size =
1052 sizeof kFunctionPrologue + arr_size + sizeof kFunctionEpilogue;
1053 ASSERT_EQ_FMT(total_size, Buffer_len(buf), "%ld");
1054
1055 byte *ptr = buf->address;
1056 ASSERT_MEM_EQ(kFunctionPrologue, ptr, sizeof kFunctionPrologue);
1057 ptr += sizeof kFunctionPrologue;
1058 ASSERT_MEM_EQ(arr, ptr, arr_size);
1059 ptr += arr_size;
1060 ASSERT_MEM_EQ(kFunctionEpilogue, ptr, sizeof kFunctionEpilogue);
1061 ptr += sizeof kFunctionEpilogue;
1062 PASS();
1063}
1064
1065#define EXPECT_EQUALS_BYTES(buf, arr) \
1066 ASSERT_MEM_EQ(arr, (buf)->address, sizeof arr)
1067
1068#define EXPECT_FUNCTION_CONTAINS_CODE(buf, arr) \
1069 CHECK_CALL(Testing_expect_function_has_contents(buf, arr, sizeof arr))
1070
1071#define RUN_BUFFER_TEST(test_name) \
1072 do { \
1073 Buffer buf; \
1074 Buffer_init(&buf, 1); \
1075 GREATEST_RUN_TEST1(test_name, &buf); \
1076 Buffer_deinit(&buf); \
1077 } while (0)
1078
1079ASTNode *list1(ASTNode *item0) { return AST_new_pair(item0, AST_nil()); }
1080
1081ASTNode *list2(ASTNode *item0, ASTNode *item1) {
1082 return AST_new_pair(item0, list1(item1));
1083}
1084
1085ASTNode *list3(ASTNode *item0, ASTNode *item1, ASTNode *item2) {
1086 return AST_new_pair(item0, list2(item1, item2));
1087}
1088
1089ASTNode *new_unary_call(const char *name, ASTNode *arg) {
1090 return list2(AST_new_symbol(name), arg);
1091}
1092
1093ASTNode *new_binary_call(const char *name, ASTNode *arg0, ASTNode *arg1) {
1094 return list3(AST_new_symbol(name), arg0, arg1);
1095}
1096
1097// End Testing
1098
1099// Tests
1100
1101TEST encode_positive_integer(void) {
1102 ASSERT_EQ(Object_encode_integer(0), 0x0);
1103 ASSERT_EQ(Object_encode_integer(1), 0x4);
1104 ASSERT_EQ(Object_encode_integer(10), 0x28);
1105 PASS();
1106}
1107
1108TEST encode_negative_integer(void) {
1109 ASSERT_EQ(Object_encode_integer(0), 0x0);
1110 ASSERT_EQ(Object_encode_integer(-1), 0xfffffffffffffffc);
1111 ASSERT_EQ(Object_encode_integer(-10), 0xffffffffffffffd8);
1112 PASS();
1113}
1114
1115TEST encode_char(void) {
1116 ASSERT_EQ(Object_encode_char('\0'), 0xf);
1117 ASSERT_EQ(Object_encode_char('a'), 0x610f);
1118 PASS();
1119}
1120
1121TEST decode_char(void) {
1122 ASSERT_EQ(Object_decode_char(0xf), '\0');
1123 ASSERT_EQ(Object_decode_char(0x610f), 'a');
1124 PASS();
1125}
1126
1127TEST encode_bool(void) {
1128 ASSERT_EQ(Object_encode_bool(true), 0x9f);
1129 ASSERT_EQ(Object_encode_bool(false), 0x1f);
1130 ASSERT_EQ(Object_true(), 0x9f);
1131 ASSERT_EQ(Object_false(), 0x1f);
1132 PASS();
1133}
1134
1135TEST decode_bool(void) {
1136 ASSERT_EQ(Object_decode_bool(0x9f), true);
1137 ASSERT_EQ(Object_decode_bool(0x1f), false);
1138 PASS();
1139}
1140
1141TEST address(void) {
1142 ASSERT_EQ(Object_address((void *)0xFF01), 0xFF00);
1143 PASS();
1144}
1145
1146TEST ast_new_pair(void) {
1147 ASTNode *node = AST_new_pair(NULL, NULL);
1148 ASSERT(AST_is_pair(node));
1149 AST_heap_free(node);
1150 PASS();
1151}
1152
1153TEST ast_pair_car_returns_car(void) {
1154 ASTNode *node = AST_new_pair(AST_new_integer(123), NULL);
1155 ASTNode *car = AST_pair_car(node);
1156 ASSERT(AST_is_integer(car));
1157 ASSERT_EQ(Object_decode_integer((uword)car), 123);
1158 AST_heap_free(node);
1159 PASS();
1160}
1161
1162TEST ast_pair_cdr_returns_cdr(void) {
1163 ASTNode *node = AST_new_pair(NULL, AST_new_integer(123));
1164 ASTNode *cdr = AST_pair_cdr(node);
1165 ASSERT(AST_is_integer(cdr));
1166 ASSERT_EQ(Object_decode_integer((uword)cdr), 123);
1167 AST_heap_free(node);
1168 PASS();
1169}
1170
1171TEST ast_new_symbol(void) {
1172 const char *value = "my symbol";
1173 ASTNode *node = AST_new_symbol(value);
1174 ASSERT(AST_is_symbol(node));
1175 ASSERT_STR_EQ(AST_symbol_cstr(node), value);
1176 AST_heap_free(node);
1177 PASS();
1178}
1179
1180#define ASSERT_IS_CHAR_EQ(node, c) \
1181 do { \
1182 ASTNode *__tmp = node; \
1183 if (AST_is_error(__tmp)) { \
1184 fprintf(stderr, "Expected a char but got an error.\n"); \
1185 } \
1186 ASSERT(AST_is_char(__tmp)); \
1187 ASSERT_EQ(AST_get_char(__tmp), c); \
1188 } while (0);
1189
1190#define ASSERT_IS_INT_EQ(node, val) \
1191 do { \
1192 ASTNode *__tmp = node; \
1193 if (AST_is_error(__tmp)) { \
1194 fprintf(stderr, "Expected an int but got an error.\n"); \
1195 } \
1196 ASSERT(AST_is_integer(__tmp)); \
1197 ASSERT_EQ(AST_get_integer(__tmp), val); \
1198 } while (0);
1199
1200#define ASSERT_IS_SYM_EQ(node, cstr) \
1201 do { \
1202 ASTNode *__tmp = node; \
1203 if (AST_is_error(__tmp)) { \
1204 fprintf(stderr, "Expected a symbol but got an error.\n"); \
1205 } \
1206 ASSERT(AST_is_symbol(__tmp)); \
1207 ASSERT_STR_EQ(AST_symbol_cstr(__tmp), cstr); \
1208 } while (0);
1209
1210TEST read_with_integer_returns_integer(void) {
1211 char *input = "1234";
1212 ASTNode *node = Reader_read(input);
1213 ASSERT_IS_INT_EQ(node, 1234);
1214 AST_heap_free(node);
1215 PASS();
1216}
1217
1218TEST read_with_negative_integer_returns_integer(void) {
1219 char *input = "-1234";
1220 ASTNode *node = Reader_read(input);
1221 ASSERT_IS_INT_EQ(node, -1234);
1222 AST_heap_free(node);
1223 PASS();
1224}
1225
1226TEST read_with_positive_integer_returns_integer(void) {
1227 char *input = "+1234";
1228 ASTNode *node = Reader_read(input);
1229 ASSERT_IS_INT_EQ(node, 1234);
1230 AST_heap_free(node);
1231 PASS();
1232}
1233
1234TEST read_with_leading_whitespace_ignores_whitespace(void) {
1235 char *input = " \t \n 1234";
1236 ASTNode *node = Reader_read(input);
1237 ASSERT_IS_INT_EQ(node, 1234);
1238 AST_heap_free(node);
1239 PASS();
1240}
1241
1242TEST read_with_symbol_returns_symbol(void) {
1243 char *input = "hello?+-*=>";
1244 ASTNode *node = Reader_read(input);
1245 ASSERT_IS_SYM_EQ(node, "hello?+-*=>");
1246 AST_heap_free(node);
1247 PASS();
1248}
1249
1250TEST read_with_symbol_with_trailing_digits(void) {
1251 char *input = "add1 1";
1252 ASTNode *node = Reader_read(input);
1253 ASSERT_IS_SYM_EQ(node, "add1");
1254 AST_heap_free(node);
1255 PASS();
1256}
1257
1258TEST read_with_char_returns_char(void) {
1259 char *input = "'a'";
1260 ASTNode *node = Reader_read(input);
1261 ASSERT_IS_CHAR_EQ(node, 'a');
1262 ASSERT(AST_is_error(Reader_read("''")));
1263 ASSERT(AST_is_error(Reader_read("'aa'")));
1264 ASSERT(AST_is_error(Reader_read("'aa")));
1265 AST_heap_free(node);
1266 PASS();
1267}
1268
1269TEST read_with_bool_returns_bool(void) {
1270 ASSERT_EQ(Reader_read("#t"), AST_new_bool(true));
1271 ASSERT_EQ(Reader_read("#f"), AST_new_bool(false));
1272 ASSERT(AST_is_error(Reader_read("#")));
1273 ASSERT(AST_is_error(Reader_read("#x")));
1274 ASSERT(AST_is_error(Reader_read("##")));
1275 PASS();
1276}
1277
1278TEST read_with_nil_returns_nil(void) {
1279 char *input = "()";
1280 ASTNode *node = Reader_read(input);
1281 ASSERT(AST_is_nil(node));
1282 AST_heap_free(node);
1283 PASS();
1284}
1285
1286TEST read_with_list_returns_list(void) {
1287 char *input = "( 1 2 0 )";
1288 ASTNode *node = Reader_read(input);
1289 ASSERT(AST_is_pair(node));
1290 ASSERT_IS_INT_EQ(AST_pair_car(node), 1);
1291 ASSERT_IS_INT_EQ(AST_pair_car(AST_pair_cdr(node)), 2);
1292 ASSERT_IS_INT_EQ(AST_pair_car(AST_pair_cdr(AST_pair_cdr(node))), 0);
1293 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(AST_pair_cdr(node)))));
1294 AST_heap_free(node);
1295 PASS();
1296}
1297
1298TEST read_with_nested_list_returns_list(void) {
1299 char *input = "((hello world) (foo bar))";
1300 ASTNode *node = Reader_read(input);
1301 ASSERT(AST_is_pair(node));
1302 ASTNode *first = AST_pair_car(node);
1303 ASSERT(AST_is_pair(first));
1304 ASSERT_IS_SYM_EQ(AST_pair_car(first), "hello");
1305 ASSERT_IS_SYM_EQ(AST_pair_car(AST_pair_cdr(first)), "world");
1306 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(first))));
1307 ASTNode *second = AST_pair_car(AST_pair_cdr(node));
1308 ASSERT(AST_is_pair(second));
1309 ASSERT_IS_SYM_EQ(AST_pair_car(second), "foo");
1310 ASSERT_IS_SYM_EQ(AST_pair_car(AST_pair_cdr(second)), "bar");
1311 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(second))));
1312 AST_heap_free(node);
1313 PASS();
1314}
1315
1316TEST buffer_write8_increases_length(Buffer *buf) {
1317 ASSERT_EQ(Buffer_len(buf), 0);
1318 Buffer_write8(buf, 0xdb);
1319 ASSERT_EQ(Buffer_at8(buf, 0), 0xdb);
1320 ASSERT_EQ(Buffer_len(buf), 1);
1321 PASS();
1322}
1323
1324TEST buffer_write8_expands_buffer(void) {
1325 Buffer buf;
1326 Buffer_init(&buf, 1);
1327 ASSERT_EQ(buf.capacity, 1);
1328 ASSERT_EQ(buf.len, 0);
1329 Buffer_write8(&buf, 0xdb);
1330 Buffer_write8(&buf, 0xef);
1331 ASSERT(buf.capacity > 1);
1332 ASSERT_EQ(buf.len, 2);
1333 Buffer_deinit(&buf);
1334 PASS();
1335}
1336
1337TEST buffer_write32_expands_buffer(void) {
1338 Buffer buf;
1339 Buffer_init(&buf, 1);
1340 ASSERT_EQ(buf.capacity, 1);
1341 ASSERT_EQ(buf.len, 0);
1342 Buffer_write32(&buf, 0xdeadbeef);
1343 ASSERT(buf.capacity > 1);
1344 ASSERT_EQ(buf.len, 4);
1345 Buffer_deinit(&buf);
1346 PASS();
1347}
1348
1349TEST buffer_write32_writes_little_endian(Buffer *buf) {
1350 Buffer_write32(buf, 0xdeadbeef);
1351 ASSERT_EQ(Buffer_at8(buf, 0), 0xef);
1352 ASSERT_EQ(Buffer_at8(buf, 1), 0xbe);
1353 ASSERT_EQ(Buffer_at8(buf, 2), 0xad);
1354 ASSERT_EQ(Buffer_at8(buf, 3), 0xde);
1355 PASS();
1356}
1357
1358TEST compile_positive_integer(Buffer *buf) {
1359 word value = 123;
1360 ASTNode *node = AST_new_integer(value);
1361 int compile_result = Compile_function(buf, node);
1362 ASSERT_EQ(compile_result, 0);
1363 // mov eax, imm(123)
1364 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00};
1365 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1366 Buffer_make_executable(buf);
1367 uword result = Testing_execute_expr(buf);
1368 ASSERT_EQ(result, Object_encode_integer(value));
1369 PASS();
1370}
1371
1372TEST compile_negative_integer(Buffer *buf) {
1373 word value = -123;
1374 ASTNode *node = AST_new_integer(value);
1375 int compile_result = Compile_function(buf, node);
1376 ASSERT_EQ(compile_result, 0);
1377 // mov eax, imm(-123)
1378 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0xfe, 0xff, 0xff};
1379 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1380 Buffer_make_executable(buf);
1381 uword result = Testing_execute_expr(buf);
1382 ASSERT_EQ(result, Object_encode_integer(value));
1383 PASS();
1384}
1385
1386TEST compile_char(Buffer *buf) {
1387 char value = 'a';
1388 ASTNode *node = AST_new_char(value);
1389 int compile_result = Compile_function(buf, node);
1390 ASSERT_EQ(compile_result, 0);
1391 // mov eax, imm('a')
1392 byte expected[] = {0x48, 0xc7, 0xc0, 0x0f, 0x61, 0x00, 0x00};
1393 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1394 Buffer_make_executable(buf);
1395 uword result = Testing_execute_expr(buf);
1396 ASSERT_EQ(result, Object_encode_char(value));
1397 PASS();
1398}
1399
1400TEST compile_true(Buffer *buf) {
1401 ASTNode *node = AST_new_bool(true);
1402 int compile_result = Compile_function(buf, node);
1403 ASSERT_EQ(compile_result, 0);
1404 // mov eax, imm(true)
1405 byte expected[] = {0x48, 0xc7, 0xc0, 0x9f, 0x0, 0x0, 0x0};
1406 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1407 Buffer_make_executable(buf);
1408 uword result = Testing_execute_expr(buf);
1409 ASSERT_EQ(result, Object_true());
1410 PASS();
1411}
1412
1413TEST compile_false(Buffer *buf) {
1414 ASTNode *node = AST_new_bool(false);
1415 int compile_result = Compile_function(buf, node);
1416 ASSERT_EQ(compile_result, 0);
1417 // mov eax, imm(false)
1418 byte expected[] = {0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00};
1419 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1420 Buffer_make_executable(buf);
1421 uword result = Testing_execute_expr(buf);
1422 ASSERT_EQ(result, Object_false());
1423 PASS();
1424}
1425
1426TEST compile_nil(Buffer *buf) {
1427 ASTNode *node = AST_nil();
1428 int compile_result = Compile_function(buf, node);
1429 ASSERT_EQ(compile_result, 0);
1430 // mov eax, imm(nil)
1431 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00};
1432 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1433 Buffer_make_executable(buf);
1434 uword result = Testing_execute_expr(buf);
1435 ASSERT_EQ(result, Object_nil());
1436 PASS();
1437}
1438
1439TEST compile_unary_add1(Buffer *buf) {
1440 ASTNode *node = new_unary_call("add1", AST_new_integer(123));
1441 int compile_result = Compile_function(buf, node);
1442 ASSERT_EQ(compile_result, 0);
1443 // mov rax, imm(123); add rax, imm(1)
1444 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00,
1445 0x48, 0x05, 0x04, 0x00, 0x00, 0x00};
1446 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1447 Buffer_make_executable(buf);
1448 uword result = Testing_execute_expr(buf);
1449 ASSERT_EQ(result, Object_encode_integer(124));
1450 AST_heap_free(node);
1451 PASS();
1452}
1453
1454TEST compile_unary_add1_nested(Buffer *buf) {
1455 ASTNode *node =
1456 new_unary_call("add1", new_unary_call("add1", AST_new_integer(123)));
1457 int compile_result = Compile_function(buf, node);
1458 ASSERT_EQ(compile_result, 0);
1459 // mov rax, imm(123); add rax, imm(1); add rax, imm(1)
1460 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 0x48, 0x05, 0x04,
1461 0x00, 0x00, 0x00, 0x48, 0x05, 0x04, 0x00, 0x00, 0x00};
1462 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1463 Buffer_make_executable(buf);
1464 uword result = Testing_execute_expr(buf);
1465 ASSERT_EQ(result, Object_encode_integer(125));
1466 AST_heap_free(node);
1467 PASS();
1468}
1469
1470TEST compile_unary_sub1(Buffer *buf) {
1471 ASTNode *node = new_unary_call("sub1", AST_new_integer(123));
1472 int compile_result = Compile_function(buf, node);
1473 ASSERT_EQ(compile_result, 0);
1474 // mov rax, imm(123); sub rax, imm(1)
1475 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00,
1476 0x48, 0x2d, 0x04, 0x00, 0x00, 0x00};
1477 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1478 Buffer_make_executable(buf);
1479 uword result = Testing_execute_expr(buf);
1480 ASSERT_EQ(result, Object_encode_integer(122));
1481 AST_heap_free(node);
1482 PASS();
1483}
1484
1485TEST compile_unary_integer_to_char(Buffer *buf) {
1486 ASTNode *node = new_unary_call("integer->char", AST_new_integer(97));
1487 int compile_result = Compile_function(buf, node);
1488 ASSERT_EQ(compile_result, 0);
1489 // mov rax, imm(97); shl rax, 6; or rax, 0xf
1490 byte expected[] = {0x48, 0xc7, 0xc0, 0x84, 0x01, 0x00, 0x00, 0x48,
1491 0xc1, 0xe0, 0x06, 0x48, 0x83, 0xc8, 0x0f};
1492 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1493 Buffer_make_executable(buf);
1494 uword result = Testing_execute_expr(buf);
1495 ASSERT_EQ(result, Object_encode_char('a'));
1496 AST_heap_free(node);
1497 PASS();
1498}
1499
1500TEST compile_unary_char_to_integer(Buffer *buf) {
1501 ASTNode *node = new_unary_call("char->integer", AST_new_char('a'));
1502 int compile_result = Compile_function(buf, node);
1503 ASSERT_EQ(compile_result, 0);
1504 // mov rax, imm('a'); shr rax, 6
1505 byte expected[] = {0x48, 0xc7, 0xc0, 0x0f, 0x61, 0x00,
1506 0x00, 0x48, 0xc1, 0xe8, 0x06};
1507 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1508 Buffer_make_executable(buf);
1509 uword result = Testing_execute_expr(buf);
1510 ASSERT_EQ(result, Object_encode_integer(97));
1511 AST_heap_free(node);
1512 PASS();
1513}
1514
1515TEST compile_unary_nilp_with_nil_returns_true(Buffer *buf) {
1516 ASTNode *node = new_unary_call("nil?", AST_nil());
1517 int compile_result = Compile_function(buf, node);
1518 ASSERT_EQ(compile_result, 0);
1519 // 0: 48 c7 c0 2f 00 00 00 mov rax,0x2f
1520 // 7: 48 3d 2f 00 00 00 cmp rax,0x0000002f
1521 // d: 48 c7 c0 00 00 00 00 mov rax,0x0
1522 // 14: 0f 94 c0 sete al
1523 // 17: 48 c1 e0 07 shl rax,0x7
1524 // 1b: 48 83 c8 1f or rax,0x1f
1525 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00, 0x48,
1526 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0,
1527 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48,
1528 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1529 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1530 Buffer_make_executable(buf);
1531 uword result = Testing_execute_expr(buf);
1532 ASSERT_EQ(result, Object_true());
1533 AST_heap_free(node);
1534 PASS();
1535}
1536
1537TEST compile_unary_nilp_with_non_nil_returns_false(Buffer *buf) {
1538 ASTNode *node = new_unary_call("nil?", AST_new_integer(5));
1539 int compile_result = Compile_function(buf, node);
1540 ASSERT_EQ(compile_result, 0);
1541 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14
1542 // 7: 48 3d 2f 00 00 00 cmp rax,0x0000002f
1543 // d: 48 c7 c0 00 00 00 00 mov rax,0x0
1544 // 14: 0f 94 c0 sete al
1545 // 17: 48 c1 e0 07 shl rax,0x7
1546 // 1b: 48 83 c8 1f or rax,0x1f
1547 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48,
1548 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0,
1549 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48,
1550 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1551 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1552 Buffer_make_executable(buf);
1553 uword result = Testing_execute_expr(buf);
1554 ASSERT_EQ(result, Object_false());
1555 AST_heap_free(node);
1556 PASS();
1557}
1558
1559TEST compile_unary_zerop_with_zero_returns_true(Buffer *buf) {
1560 ASTNode *node = new_unary_call("zero?", AST_new_integer(0));
1561 int compile_result = Compile_function(buf, node);
1562 ASSERT_EQ(compile_result, 0);
1563 // 0: 48 c7 c0 00 00 00 00 mov rax,0x0
1564 // 7: 48 3d 00 00 00 00 cmp rax,0x00000000
1565 // d: 48 c7 c0 00 00 00 00 mov rax,0x0
1566 // 14: 0f 94 c0 sete al
1567 // 17: 48 c1 e0 07 shl rax,0x7
1568 // 1b: 48 83 c8 1f or rax,0x1f
1569 byte expected[] = {0x48, 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x48,
1570 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0,
1571 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48,
1572 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1573 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1574 Buffer_make_executable(buf);
1575 uword result = Testing_execute_expr(buf);
1576 ASSERT_EQ(result, Object_true());
1577 AST_heap_free(node);
1578 PASS();
1579}
1580
1581TEST compile_unary_zerop_with_non_zero_returns_false(Buffer *buf) {
1582 ASTNode *node = new_unary_call("zero?", AST_new_integer(5));
1583 int compile_result = Compile_function(buf, node);
1584 ASSERT_EQ(compile_result, 0);
1585 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14
1586 // 7: 48 3d 00 00 00 00 cmp rax,0x00000000
1587 // d: 48 c7 c0 00 00 00 00 mov rax,0x0
1588 // 14: 0f 94 c0 sete al
1589 // 17: 48 c1 e0 07 shl rax,0x7
1590 // 1b: 48 83 c8 1f or rax,0x1f
1591 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48,
1592 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0,
1593 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48,
1594 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1595 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1596 Buffer_make_executable(buf);
1597 uword result = Testing_execute_expr(buf);
1598 ASSERT_EQ(result, Object_false());
1599 AST_heap_free(node);
1600 PASS();
1601}
1602
1603TEST compile_unary_not_with_false_returns_true(Buffer *buf) {
1604 ASTNode *node = new_unary_call("not", AST_new_bool(false));
1605 int compile_result = Compile_function(buf, node);
1606 ASSERT_EQ(compile_result, 0);
1607 // 0: 48 c7 c0 1f 00 00 00 mov rax,0x1f
1608 // 7: 48 3d 1f 00 00 00 cmp rax,0x0000001f
1609 // d: 48 c7 c0 00 00 00 00 mov rax,0x0
1610 // 14: 0f 94 c0 sete al
1611 // 17: 48 c1 e0 07 shl rax,0x7
1612 // 1b: 48 83 c8 1f or rax,0x1f
1613 byte expected[] = {0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x48,
1614 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0,
1615 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48,
1616 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1617 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1618 Buffer_make_executable(buf);
1619 uword result = Testing_execute_expr(buf);
1620 ASSERT_EQ(result, Object_true());
1621 AST_heap_free(node);
1622 PASS();
1623}
1624
1625TEST compile_unary_not_with_non_false_returns_false(Buffer *buf) {
1626 ASTNode *node = new_unary_call("not", AST_new_integer(5));
1627 int compile_result = Compile_function(buf, node);
1628 ASSERT_EQ(compile_result, 0);
1629 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14
1630 // 7: 48 3d 1f 00 00 00 cmp rax,0x0000001f
1631 // d: 48 c7 c0 00 00 00 00 mov rax,0x0
1632 // 14: 0f 94 c0 sete al
1633 // 17: 48 c1 e0 07 shl rax,0x7
1634 // 1b: 48 83 c8 1f or rax,0x1f
1635 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48,
1636 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0,
1637 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48,
1638 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1639 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1640 Buffer_make_executable(buf);
1641 uword result = Testing_execute_expr(buf);
1642 ASSERT_EQ(result, Object_false());
1643 AST_heap_free(node);
1644 PASS();
1645}
1646
1647TEST compile_unary_integerp_with_integer_returns_true(Buffer *buf) {
1648 ASTNode *node = new_unary_call("integer?", AST_new_integer(5));
1649 int compile_result = Compile_function(buf, node);
1650 ASSERT_EQ(compile_result, 0);
1651 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14
1652 // 7: 48 83 e0 03 and rax,0x3
1653 // b: 48 3d 00 00 00 00 cmp rax,0x00000000
1654 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0
1655 // 18: 0f 94 c0 sete al
1656 // 1b: 48 c1 e0 07 shl rax,0x7
1657 // 1f: 48 83 c8 1f or rax,0x1f
1658 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 0x83,
1659 0xe0, 0x03, 0x48, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48,
1660 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0,
1661 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1662 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1663 Buffer_make_executable(buf);
1664 uword result = Testing_execute_expr(buf);
1665 ASSERT_EQ(result, Object_true());
1666 AST_heap_free(node);
1667 PASS();
1668}
1669
1670TEST compile_unary_integerp_with_non_integer_returns_false(Buffer *buf) {
1671 ASTNode *node = new_unary_call("integer?", AST_nil());
1672 int compile_result = Compile_function(buf, node);
1673 ASSERT_EQ(compile_result, 0);
1674 // 0: 48 c7 c0 2f 00 00 00 mov rax,0x2f
1675 // 7: 48 83 e0 03 and rax,0x3
1676 // b: 48 3d 00 00 00 00 cmp rax,0x00000000
1677 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0
1678 // 18: 0f 94 c0 sete al
1679 // 1b: 48 c1 e0 07 shl rax,0x7
1680 // 1f: 48 83 c8 1f or rax,0x1f
1681 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00, 0x48, 0x83,
1682 0xe0, 0x03, 0x48, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48,
1683 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0,
1684 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1685 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1686 Buffer_make_executable(buf);
1687 uword result = Testing_execute_expr(buf);
1688 ASSERT_EQ(result, Object_false());
1689 AST_heap_free(node);
1690 PASS();
1691}
1692
1693TEST compile_unary_booleanp_with_boolean_returns_true(Buffer *buf) {
1694 ASTNode *node = new_unary_call("boolean?", AST_new_bool(true));
1695 int compile_result = Compile_function(buf, node);
1696 ASSERT_EQ(compile_result, 0);
1697 // 0: 48 c7 c0 9f 00 00 00 mov rax,0x9f
1698 // 7: 48 83 e0 3f and rax,0x3f
1699 // b: 48 3d 1f 00 00 00 cmp rax,0x0000001f
1700 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0
1701 // 18: 0f 94 c0 sete al
1702 // 1b: 48 c1 e0 07 shl rax,0x7
1703 // 1f: 48 83 c8 1f or rax,0x1f
1704 byte expected[] = {0x48, 0xc7, 0xc0, 0x9f, 0x00, 0x00, 0x00, 0x48, 0x83,
1705 0xe0, 0x3f, 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48,
1706 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0,
1707 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1708 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1709 Buffer_make_executable(buf);
1710 uword result = Testing_execute_expr(buf);
1711 ASSERT_EQ(result, Object_true());
1712 AST_heap_free(node);
1713 PASS();
1714}
1715
1716TEST compile_unary_booleanp_with_non_boolean_returns_false(Buffer *buf) {
1717 ASTNode *node = new_unary_call("boolean?", AST_new_integer(5));
1718 int compile_result = Compile_function(buf, node);
1719 ASSERT_EQ(compile_result, 0);
1720 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14
1721 // 7: 48 83 e0 3f and rax,0x3f
1722 // b: 48 3d 1f 00 00 00 cmp rax,0x0000001f
1723 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0
1724 // 18: 0f 94 c0 sete al
1725 // 1b: 48 c1 e0 07 shl rax,0x7
1726 // 1f: 48 83 c8 1f or rax,0x1f
1727 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 0x83,
1728 0xe0, 0x3f, 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48,
1729 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0,
1730 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f};
1731 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1732 Buffer_make_executable(buf);
1733 uword result = Testing_execute_expr(buf);
1734 ASSERT_EQ(result, Object_false());
1735 AST_heap_free(node);
1736 PASS();
1737}
1738
1739TEST compile_binary_plus(Buffer *buf) {
1740 ASTNode *node = new_binary_call("+", AST_new_integer(5), AST_new_integer(8));
1741 int compile_result = Compile_function(buf, node);
1742 ASSERT_EQ(compile_result, 0);
1743 byte expected[] = {
1744 // 0: 48 c7 c0 20 00 00 00 mov rax,0x20
1745 0x48, 0xc7, 0xc0, 0x20, 0x00, 0x00, 0x00,
1746 // 7: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
1747 0x48, 0x89, 0x45, 0xf8,
1748 // b: 48 c7 c0 14 00 00 00 mov rax,0x14
1749 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00,
1750 // 12: 48 03 45 f8 add rax,QWORD PTR [rbp-0x8]
1751 0x48, 0x03, 0x45, 0xf8};
1752 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1753 Buffer_make_executable(buf);
1754 uword result = Testing_execute_expr(buf);
1755 ASSERT_EQ(result, Object_encode_integer(13));
1756 AST_heap_free(node);
1757 PASS();
1758}
1759
1760TEST compile_binary_plus_nested(Buffer *buf) {
1761 ASTNode *node = new_binary_call(
1762 "+", new_binary_call("+", AST_new_integer(1), AST_new_integer(2)),
1763 new_binary_call("+", AST_new_integer(3), AST_new_integer(4)));
1764 int compile_result = Compile_function(buf, node);
1765 ASSERT_EQ(compile_result, 0);
1766 byte expected[] = {
1767 // 4: 48 c7 c0 10 00 00 00 mov rax,0x10
1768 0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00,
1769 // b: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
1770 0x48, 0x89, 0x45, 0xf8,
1771 // f: 48 c7 c0 0c 00 00 00 mov rax,0xc
1772 0x48, 0xc7, 0xc0, 0x0c, 0x00, 0x00, 0x00,
1773 // 16: 48 03 45 f8 add rax,QWORD PTR [rbp-0x8]
1774 0x48, 0x03, 0x45, 0xf8,
1775 // 1a: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
1776 0x48, 0x89, 0x45, 0xf8,
1777 // 1e: 48 c7 c0 08 00 00 00 mov rax,0x8
1778 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00,
1779 // 25: 48 89 45 f0 mov QWORD PTR [rbp-0x10],rax
1780 0x48, 0x89, 0x45, 0xf0,
1781 // 29: 48 c7 c0 04 00 00 00 mov rax,0x4
1782 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00,
1783 // 30: 48 03 45 f0 add rax,QWORD PTR [rbp-0x10]
1784 0x48, 0x03, 0x45, 0xf0,
1785 // 34: 48 03 45 f8 add rax,QWORD PTR [rbp-0x8]
1786 0x48, 0x03, 0x45, 0xf8};
1787 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1788 Buffer_make_executable(buf);
1789 uword result = Testing_execute_expr(buf);
1790 ASSERT_EQ(result, Object_encode_integer(10));
1791 AST_heap_free(node);
1792 PASS();
1793}
1794
1795TEST compile_binary_minus(Buffer *buf) {
1796 ASTNode *node = new_binary_call("-", AST_new_integer(5), AST_new_integer(8));
1797 int compile_result = Compile_function(buf, node);
1798 ASSERT_EQ(compile_result, 0);
1799 byte expected[] = {
1800 // 0: 48 c7 c0 20 00 00 00 mov rax,0x20
1801 0x48, 0xc7, 0xc0, 0x20, 0x00, 0x00, 0x00,
1802 // 7: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
1803 0x48, 0x89, 0x45, 0xf8,
1804 // b: 48 c7 c0 14 00 00 00 mov rax,0x14
1805 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00,
1806 // 12: 48 2b 45 f8 add rax,QWORD PTR [rbp-0x8]
1807 0x48, 0x2b, 0x45, 0xf8};
1808 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1809 Buffer_make_executable(buf);
1810 uword result = Testing_execute_expr(buf);
1811 ASSERT_EQ(result, Object_encode_integer(-3));
1812 AST_heap_free(node);
1813 PASS();
1814}
1815
1816TEST compile_binary_minus_nested(Buffer *buf) {
1817 ASTNode *node = new_binary_call(
1818 "-", new_binary_call("-", AST_new_integer(5), AST_new_integer(1)),
1819 new_binary_call("-", AST_new_integer(4), AST_new_integer(3)));
1820 int compile_result = Compile_function(buf, node);
1821 ASSERT_EQ(compile_result, 0);
1822 byte expected[] = {
1823 // 4: 48 c7 c0 0c 00 00 00 mov rax,0xc
1824 0x48, 0xc7, 0xc0, 0x0c, 0x00, 0x00, 0x00,
1825 // b: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
1826 0x48, 0x89, 0x45, 0xf8,
1827 // f: 48 c7 c0 10 00 00 00 mov rax,0x10
1828 0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00,
1829 // 16: 48 2b 45 f8 add rax,QWORD PTR [rbp-0x8]
1830 0x48, 0x2b, 0x45, 0xf8,
1831 // 1a: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
1832 0x48, 0x89, 0x45, 0xf8,
1833 // 1e: 48 c7 c0 04 00 00 00 mov rax,0x4
1834 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00,
1835 // 25: 48 89 45 f0 mov QWORD PTR [rbp-0x10],rax
1836 0x48, 0x89, 0x45, 0xf0,
1837 // 29: 48 c7 c0 14 00 00 00 mov rax,0x14
1838 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00,
1839 // 30: 48 2b 45 f0 add rax,QWORD PTR [rbp-0x10]
1840 0x48, 0x2b, 0x45, 0xf0,
1841 // 34: 48 2b 45 f8 add rax,QWORD PTR [rbp-0x8]
1842 0x48, 0x2b, 0x45, 0xf8};
1843 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
1844 Buffer_make_executable(buf);
1845 uword result = Testing_execute_expr(buf);
1846 ASSERT_EQ(result, Object_encode_integer(3));
1847 AST_heap_free(node);
1848 PASS();
1849}
1850
1851TEST compile_binary_mul(Buffer *buf) {
1852 ASTNode *node = new_binary_call("*", AST_new_integer(5), AST_new_integer(8));
1853 int compile_result = Compile_function(buf, node);
1854 ASSERT_EQ(compile_result, 0);
1855 Buffer_make_executable(buf);
1856 uword result = Testing_execute_expr(buf);
1857 ASSERT_EQ_FMT(Object_encode_integer(40), result, "0x%lx");
1858 AST_heap_free(node);
1859 PASS();
1860}
1861
1862TEST compile_binary_mul_nested(Buffer *buf) {
1863 ASTNode *node = new_binary_call(
1864 "*", new_binary_call("*", AST_new_integer(1), AST_new_integer(2)),
1865 new_binary_call("*", AST_new_integer(3), AST_new_integer(4)));
1866 int compile_result = Compile_function(buf, node);
1867 ASSERT_EQ(compile_result, 0);
1868 Buffer_make_executable(buf);
1869 uword result = Testing_execute_expr(buf);
1870 ASSERT_EQ_FMT(Object_encode_integer(24), result, "0x%lx");
1871 AST_heap_free(node);
1872 PASS();
1873}
1874
1875TEST compile_binary_eq_with_same_address_returns_true(Buffer *buf) {
1876 ASTNode *node = new_binary_call("=", AST_new_integer(5), AST_new_integer(5));
1877 int compile_result = Compile_function(buf, node);
1878 ASSERT_EQ(compile_result, 0);
1879 Buffer_make_executable(buf);
1880 uword result = Testing_execute_expr(buf);
1881 ASSERT_EQ_FMT(Object_true(), result, "0x%lx");
1882 AST_heap_free(node);
1883 PASS();
1884}
1885
1886TEST compile_binary_eq_with_different_address_returns_false(Buffer *buf) {
1887 ASTNode *node = new_binary_call("=", AST_new_integer(5), AST_new_integer(4));
1888 int compile_result = Compile_function(buf, node);
1889 ASSERT_EQ(compile_result, 0);
1890 Buffer_make_executable(buf);
1891 uword result = Testing_execute_expr(buf);
1892 ASSERT_EQ_FMT(Object_false(), result, "0x%lx");
1893 AST_heap_free(node);
1894 PASS();
1895}
1896
1897TEST compile_binary_lt_with_left_less_than_right_returns_true(Buffer *buf) {
1898 ASTNode *node = new_binary_call("<", AST_new_integer(-5), AST_new_integer(5));
1899 int compile_result = Compile_function(buf, node);
1900 ASSERT_EQ(compile_result, 0);
1901 Buffer_make_executable(buf);
1902 uword result = Testing_execute_expr(buf);
1903 ASSERT_EQ_FMT(Object_true(), result, "0x%lx");
1904 AST_heap_free(node);
1905 PASS();
1906}
1907
1908TEST compile_binary_lt_with_left_equal_to_right_returns_false(Buffer *buf) {
1909 ASTNode *node = new_binary_call("<", AST_new_integer(5), AST_new_integer(5));
1910 int compile_result = Compile_function(buf, node);
1911 ASSERT_EQ(compile_result, 0);
1912 Buffer_make_executable(buf);
1913 uword result = Testing_execute_expr(buf);
1914 ASSERT_EQ_FMT(Object_false(), result, "0x%lx");
1915 AST_heap_free(node);
1916 PASS();
1917}
1918
1919TEST compile_binary_lt_with_left_greater_than_right_returns_false(Buffer *buf) {
1920 ASTNode *node = new_binary_call("<", AST_new_integer(6), AST_new_integer(5));
1921 int compile_result = Compile_function(buf, node);
1922 ASSERT_EQ(compile_result, 0);
1923 Buffer_make_executable(buf);
1924 uword result = Testing_execute_expr(buf);
1925 ASSERT_EQ_FMT(Object_false(), result, "0x%lx");
1926 AST_heap_free(node);
1927 PASS();
1928}
1929
1930TEST compile_symbol_in_env_returns_value(Buffer *buf) {
1931 ASTNode *node = AST_new_symbol("hello");
1932 Env env0 = Env_bind("hello", 33, /*prev=*/NULL);
1933 Env env1 = Env_bind("world", 66, &env0);
1934 int compile_result = Compile_expr(buf, node, -kWordSize, &env1);
1935 ASSERT_EQ(compile_result, 0);
1936 byte expected[] = {// mov rax, [rbp+33]
1937 0x48, 0x8b, 0x45, 33};
1938 EXPECT_EQUALS_BYTES(buf, expected);
1939 AST_heap_free(node);
1940 PASS();
1941}
1942
1943TEST compile_symbol_in_env_returns_first_value(Buffer *buf) {
1944 ASTNode *node = AST_new_symbol("hello");
1945 Env env0 = Env_bind("hello", 55, /*prev=*/NULL);
1946 Env env1 = Env_bind("hello", 66, &env0);
1947 int compile_result = Compile_expr(buf, node, -kWordSize, &env1);
1948 ASSERT_EQ(compile_result, 0);
1949 byte expected[] = {// mov rax, [rbp+66]
1950 0x48, 0x8b, 0x45, 66};
1951 EXPECT_EQUALS_BYTES(buf, expected);
1952 AST_heap_free(node);
1953 PASS();
1954}
1955
1956TEST compile_symbol_not_in_env_raises_compile_error(Buffer *buf) {
1957 ASTNode *node = AST_new_symbol("hello");
1958 int compile_result = Compile_expr(buf, node, -kWordSize, NULL);
1959 ASSERT_EQ(compile_result, -1);
1960 AST_heap_free(node);
1961 PASS();
1962}
1963
1964TEST compile_let_with_no_bindings(Buffer *buf) {
1965 ASTNode *node = Reader_read("(let () (+ 1 2))");
1966 int compile_result = Compile_function(buf, node);
1967 ASSERT_EQ(compile_result, 0);
1968 Buffer_make_executable(buf);
1969 uword result = Testing_execute_expr(buf);
1970 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx");
1971 AST_heap_free(node);
1972 PASS();
1973}
1974
1975TEST compile_let_with_one_binding(Buffer *buf) {
1976 ASTNode *node = Reader_read("(let ((a 1)) (+ a 2))");
1977 int compile_result = Compile_function(buf, node);
1978 ASSERT_EQ(compile_result, 0);
1979 Buffer_make_executable(buf);
1980 uword result = Testing_execute_expr(buf);
1981 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx");
1982 AST_heap_free(node);
1983 PASS();
1984}
1985
1986TEST compile_let_with_multiple_bindings(Buffer *buf) {
1987 ASTNode *node = Reader_read("(let ((a 1) (b 2)) (+ a b))");
1988 int compile_result = Compile_function(buf, node);
1989 ASSERT_EQ(compile_result, 0);
1990 Buffer_make_executable(buf);
1991 uword result = Testing_execute_expr(buf);
1992 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx");
1993 AST_heap_free(node);
1994 PASS();
1995}
1996
1997TEST compile_nested_let(Buffer *buf) {
1998 ASTNode *node = Reader_read("(let ((a 1)) (let ((b 2)) (+ a b)))");
1999 int compile_result = Compile_function(buf, node);
2000 ASSERT_EQ(compile_result, 0);
2001 Buffer_make_executable(buf);
2002 uword result = Testing_execute_expr(buf);
2003 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx");
2004 AST_heap_free(node);
2005 PASS();
2006}
2007
2008TEST compile_let_is_not_let_star(Buffer *buf) {
2009 ASTNode *node = Reader_read("(let ((a 1) (b a)) a)");
2010 int compile_result = Compile_function(buf, node);
2011 ASSERT_EQ(compile_result, -1);
2012 AST_heap_free(node);
2013 PASS();
2014}
2015
2016TEST compile_if_with_true_cond(Buffer *buf) {
2017 ASTNode *node = Reader_read("(if #t 1 2)");
2018 int compile_result = Compile_function(buf, node);
2019 ASSERT_EQ(compile_result, 0);
2020 byte expected[] = {
2021 // mov rax, 0x9f
2022 0x48, 0xc7, 0xc0, 0x9f, 0x00, 0x00, 0x00,
2023 // cmp rax, 0x1f
2024 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00,
2025 // je alternate
2026 0x0f, 0x84, 0x0c, 0x00, 0x00, 0x00,
2027 // mov rax, compile(1)
2028 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00,
2029 // jmp end
2030 0xe9, 0x07, 0x00, 0x00, 0x00,
2031 // alternate:
2032 // mov rax, compile(2)
2033 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00
2034 // end:
2035 };
2036 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
2037 Buffer_make_executable(buf);
2038 uword result = Testing_execute_expr(buf);
2039 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx");
2040 AST_heap_free(node);
2041 PASS();
2042}
2043
2044TEST compile_if_with_false_cond(Buffer *buf) {
2045 ASTNode *node = Reader_read("(if #f 1 2)");
2046 int compile_result = Compile_function(buf, node);
2047 ASSERT_EQ(compile_result, 0);
2048 byte expected[] = {
2049 // mov rax, 0x1f
2050 0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00,
2051 // cmp rax, 0x1f
2052 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00,
2053 // je alternate
2054 0x0f, 0x84, 0x0c, 0x00, 0x00, 0x00,
2055 // mov rax, compile(1)
2056 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00,
2057 // jmp end
2058 0xe9, 0x07, 0x00, 0x00, 0x00,
2059 // alternate:
2060 // mov rax, compile(2)
2061 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00
2062 // end:
2063 };
2064 EXPECT_FUNCTION_CONTAINS_CODE(buf, expected);
2065 Buffer_make_executable(buf);
2066 uword result = Testing_execute_expr(buf);
2067 ASSERT_EQ_FMT(Object_encode_integer(2), result, "0x%lx");
2068 AST_heap_free(node);
2069 PASS();
2070}
2071
2072TEST compile_nested_if(Buffer *buf) {
2073 ASTNode *node = Reader_read("(if (< 1 2) (if #f 3 4) 5)");
2074 int compile_result = Compile_function(buf, node);
2075 ASSERT_EQ(compile_result, 0);
2076 Buffer_make_executable(buf);
2077 uword result = Testing_execute_expr(buf);
2078 ASSERT_EQ_FMT(Object_encode_integer(4), result, "0x%lx");
2079 AST_heap_free(node);
2080 PASS();
2081}
2082
2083SUITE(object_tests) {
2084 RUN_TEST(encode_positive_integer);
2085 RUN_TEST(encode_negative_integer);
2086 RUN_TEST(encode_char);
2087 RUN_TEST(decode_char);
2088 RUN_TEST(encode_bool);
2089 RUN_TEST(decode_bool);
2090 RUN_TEST(address);
2091}
2092
2093SUITE(ast_tests) {
2094 RUN_TEST(ast_new_pair);
2095 RUN_TEST(ast_pair_car_returns_car);
2096 RUN_TEST(ast_pair_cdr_returns_cdr);
2097 RUN_TEST(ast_new_symbol);
2098}
2099
2100SUITE(reader_tests) {
2101 RUN_TEST(read_with_integer_returns_integer);
2102 RUN_TEST(read_with_negative_integer_returns_integer);
2103 RUN_TEST(read_with_positive_integer_returns_integer);
2104 RUN_TEST(read_with_leading_whitespace_ignores_whitespace);
2105 RUN_TEST(read_with_symbol_returns_symbol);
2106 RUN_TEST(read_with_symbol_with_trailing_digits);
2107 RUN_TEST(read_with_nil_returns_nil);
2108 RUN_TEST(read_with_list_returns_list);
2109 RUN_TEST(read_with_nested_list_returns_list);
2110 RUN_TEST(read_with_char_returns_char);
2111 RUN_TEST(read_with_bool_returns_bool);
2112}
2113
2114SUITE(buffer_tests) {
2115 RUN_BUFFER_TEST(buffer_write8_increases_length);
2116 RUN_TEST(buffer_write8_expands_buffer);
2117 RUN_TEST(buffer_write32_expands_buffer);
2118 RUN_BUFFER_TEST(buffer_write32_writes_little_endian);
2119}
2120
2121SUITE(compiler_tests) {
2122 RUN_BUFFER_TEST(compile_positive_integer);
2123 RUN_BUFFER_TEST(compile_negative_integer);
2124 RUN_BUFFER_TEST(compile_char);
2125 RUN_BUFFER_TEST(compile_true);
2126 RUN_BUFFER_TEST(compile_false);
2127 RUN_BUFFER_TEST(compile_nil);
2128 RUN_BUFFER_TEST(compile_unary_add1);
2129 RUN_BUFFER_TEST(compile_unary_add1_nested);
2130 RUN_BUFFER_TEST(compile_unary_sub1);
2131 RUN_BUFFER_TEST(compile_unary_integer_to_char);
2132 RUN_BUFFER_TEST(compile_unary_char_to_integer);
2133 RUN_BUFFER_TEST(compile_unary_nilp_with_nil_returns_true);
2134 RUN_BUFFER_TEST(compile_unary_nilp_with_non_nil_returns_false);
2135 RUN_BUFFER_TEST(compile_unary_zerop_with_zero_returns_true);
2136 RUN_BUFFER_TEST(compile_unary_zerop_with_non_zero_returns_false);
2137 RUN_BUFFER_TEST(compile_unary_not_with_false_returns_true);
2138 RUN_BUFFER_TEST(compile_unary_not_with_non_false_returns_false);
2139 RUN_BUFFER_TEST(compile_unary_integerp_with_integer_returns_true);
2140 RUN_BUFFER_TEST(compile_unary_integerp_with_non_integer_returns_false);
2141 RUN_BUFFER_TEST(compile_unary_booleanp_with_boolean_returns_true);
2142 RUN_BUFFER_TEST(compile_unary_booleanp_with_non_boolean_returns_false);
2143 RUN_BUFFER_TEST(compile_binary_plus);
2144 RUN_BUFFER_TEST(compile_binary_plus_nested);
2145 RUN_BUFFER_TEST(compile_binary_minus);
2146 RUN_BUFFER_TEST(compile_binary_minus_nested);
2147 RUN_BUFFER_TEST(compile_binary_mul);
2148 RUN_BUFFER_TEST(compile_binary_mul_nested);
2149 RUN_BUFFER_TEST(compile_binary_eq_with_same_address_returns_true);
2150 RUN_BUFFER_TEST(compile_binary_eq_with_different_address_returns_false);
2151 RUN_BUFFER_TEST(compile_binary_lt_with_left_less_than_right_returns_true);
2152 RUN_BUFFER_TEST(compile_binary_lt_with_left_equal_to_right_returns_false);
2153 RUN_BUFFER_TEST(compile_binary_lt_with_left_greater_than_right_returns_false);
2154 RUN_BUFFER_TEST(compile_symbol_in_env_returns_value);
2155 RUN_BUFFER_TEST(compile_symbol_in_env_returns_first_value);
2156 RUN_BUFFER_TEST(compile_symbol_not_in_env_raises_compile_error);
2157 RUN_BUFFER_TEST(compile_let_with_no_bindings);
2158 RUN_BUFFER_TEST(compile_let_with_one_binding);
2159 RUN_BUFFER_TEST(compile_let_with_multiple_bindings);
2160 RUN_BUFFER_TEST(compile_nested_let);
2161 RUN_BUFFER_TEST(compile_let_is_not_let_star);
2162 RUN_BUFFER_TEST(compile_if_with_true_cond);
2163 RUN_BUFFER_TEST(compile_if_with_false_cond);
2164 RUN_BUFFER_TEST(compile_nested_if);
2165}
2166
2167// End Tests
2168
2169typedef void (*REPL_Callback)(char *);
2170
2171void print_value(uword object) {
2172 if (Object_is_integer(object)) {
2173 fprintf(stderr, "%ld", Object_decode_integer(object));
2174 return;
2175 }
2176 fprintf(stderr, "Unexpected value.");
2177}
2178
2179void print_assembly(char *line) {
2180 // Parse the line
2181 ASTNode *node = Reader_read(line);
2182 if (AST_is_error(node)) {
2183 fprintf(stderr, "Parse error.\n");
2184 return;
2185 }
2186
2187 // Compile the line
2188 Buffer buf;
2189 Buffer_init(&buf, 1);
2190 int result =
2191 Compile_expr(&buf, node, /*stack_index=*/-kWordSize, /*varenv=*/NULL);
2192 AST_heap_free(node);
2193 if (result < 0) {
2194 fprintf(stderr, "Compile error.\n");
2195 Buffer_deinit(&buf);
2196 return;
2197 }
2198
2199 // Print the assembled code
2200 for (word i = 0; i < buf.len; i++) {
2201 fprintf(stderr, "%.02x ", buf.address[i]);
2202 }
2203 fprintf(stderr, "\n");
2204
2205 // Clean up
2206 Buffer_deinit(&buf);
2207}
2208
2209void evaluate_expr(char *line) {
2210 // Parse the line
2211 ASTNode *node = Reader_read(line);
2212 if (AST_is_error(node)) {
2213 fprintf(stderr, "Parse error.\n");
2214 return;
2215 }
2216
2217 // Compile the line
2218 Buffer buf;
2219 Buffer_init(&buf, 1);
2220 int compile_result = Compile_function(&buf, node);
2221 AST_heap_free(node);
2222 if (compile_result < 0) {
2223 fprintf(stderr, "Compile error.\n");
2224 Buffer_deinit(&buf);
2225 return;
2226 }
2227
2228 // Execute the code
2229 Buffer_make_executable(&buf);
2230 uword result = Testing_execute_expr(&buf);
2231
2232 // Print the result
2233 print_value(result);
2234 fprintf(stderr, "\n");
2235
2236 // Clean up
2237 Buffer_deinit(&buf);
2238}
2239
2240int repl(REPL_Callback callback) {
2241 do {
2242 // Read a line
2243 fprintf(stdout, "lisp> ");
2244 char *line = NULL;
2245 size_t size = 0;
2246 ssize_t nchars = getline(&line, &size, stdin);
2247 if (nchars < 0) {
2248 fprintf(stderr, "Goodbye.\n");
2249 free(line);
2250 break;
2251 }
2252
2253 callback(line);
2254 free(line);
2255 } while (true);
2256 return 0;
2257}
2258
2259GREATEST_MAIN_DEFS();
2260
2261int run_tests(int argc, char **argv) {
2262 GREATEST_MAIN_BEGIN();
2263 RUN_SUITE(object_tests);
2264 RUN_SUITE(ast_tests);
2265 RUN_SUITE(reader_tests);
2266 RUN_SUITE(buffer_tests);
2267 RUN_SUITE(compiler_tests);
2268 GREATEST_MAIN_END();
2269}
2270
2271int main(int argc, char **argv) {
2272 if (argc == 2) {
2273 if (strcmp(argv[1], "--repl-assembly") == 0) {
2274 return repl(print_assembly);
2275 }
2276 if (strcmp(argv[1], "--repl-eval") == 0) {
2277 return repl(evaluate_expr);
2278 }
2279 }
2280 return run_tests(argc, argv);
2281}