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