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