this repo has no description
at trunk 3098 lines 103 kB view raw
1// vim: set tabstop=2 shiftwidth=2 textwidth=79 expandtab: 2// gcc -O2 -g -Wall -Wextra -pedantic -fno-strict-aliasing 3// assets/code/lisp/compiling-if.c 4 5// In general: https://course.ccs.neu.edu/cs4410sp20/#%28part._lectures%29 6// https://course.ccs.neu.edu/cs4410sp20/lec_let-and-stack_notes.html#%28part._let._.Growing_the_language__adding_let%29 7 8#define _GNU_SOURCE 9#include <assert.h> // for assert 10#include <stdbool.h> // for bool 11#include <stddef.h> // for NULL 12#include <stdint.h> // for int32_t, etc 13#include <stdio.h> // for getline, fprintf 14#include <string.h> // for memcpy 15#include <sys/mman.h> // for mmap 16#undef _GNU_SOURCE 17 18#include "greatest.h" 19 20#define WARN_UNUSED __attribute__((warn_unused_result)) 21 22// Objects 23 24typedef int64_t word; 25typedef uint64_t uword; 26 27// These constants are defined in a enum because the right hand side of a 28// statement like 29// static const int kFoo = ...; 30// must be a so-called "Integer Constant Expression". Compilers are required to 31// support a certain set of these expressions, but are not required to support 32// arbitrary arithmetic with other integer constants. Compilers such as gcc 33// before gcc-8 just decided not to play this game, while gcc-8+ and Clang play 34// just fine. 35// Since this arithmetic with constant values works just fine for enums, make 36// all these constants enum values instead. 37// See https://twitter.com/tekknolagi/status/1328449329472835586 for more info. 38enum { 39 kBitsPerByte = 8, // bits 40 kWordSize = sizeof(word), // bytes 41 kBitsPerWord = kWordSize * kBitsPerByte, // bits 42 43 kIntegerTag = 0x0, // 0b00 44 kIntegerTagMask = 0x3, // 0b11 45 kIntegerShift = 2, 46 kIntegerBits = kBitsPerWord - kIntegerShift, 47 48 kImmediateTagMask = 0x3f, 49 50 kCharTag = 0x0f, // 0b00001111 51 kCharMask = 0xff, // 0b11111111 52 kCharShift = 8, 53 54 kBoolTag = 0x1f, // 0b0011111 55 kBoolMask = 0x80, // 0b10000000 56 kBoolShift = 7, 57 58 kNilTag = 0x2f, // 0b101111 59 60 kErrorTag = 0x3f, // 0b111111 61 62 kPairTag = 0x1, // 0b001 63 kSymbolTag = 0x5, // 0b101 64 kClosureTag = 0x6, // 0b110 65 kHeapTagMask = ((uword)0x7), // 0b000...111 66 kHeapPtrMask = ~kHeapTagMask, // 0b1111...1000 67 68 kCarIndex = 0, 69 kCarOffset = kCarIndex * kWordSize, 70 kCdrIndex = kCarIndex + 1, 71 kCdrOffset = kCdrIndex * kWordSize, 72 kPairSize = kCdrOffset + kWordSize, 73}; 74 75// These are defined as macros because they will not work as static const int 76// constants (per above explanation), and enum constants are only required to 77// be an int wide (per ISO C). 78#define INTEGER_MAX ((1LL << (kIntegerBits - 1)) - 1) 79#define INTEGER_MIN (-(1LL << (kIntegerBits - 1))) 80 81uword Object_encode_integer(word value) { 82 assert(value < INTEGER_MAX && "too big"); 83 assert(value > INTEGER_MIN && "too small"); 84 return value << kIntegerShift; 85} 86 87word Object_decode_integer(uword value) { return (word)value >> kIntegerShift; } 88 89bool Object_is_integer(uword value) { 90 return (value & kIntegerTagMask) == kIntegerTag; 91} 92 93uword Object_encode_char(char value) { 94 return ((uword)value << kCharShift) | kCharTag; 95} 96 97char Object_decode_char(uword value) { 98 return (value >> kCharShift) & kCharMask; 99} 100 101bool Object_is_char(uword value) { 102 return (value & kImmediateTagMask) == kCharTag; 103} 104 105uword Object_encode_bool(bool value) { 106 return ((uword)value << kBoolShift) | kBoolTag; 107} 108 109bool Object_decode_bool(uword value) { return value & kBoolMask; } 110 111uword Object_true() { return Object_encode_bool(true); } 112 113uword Object_false() { return Object_encode_bool(false); } 114 115uword Object_nil() { return kNilTag; } 116 117uword Object_error() { return kErrorTag; } 118 119uword Object_address(void *obj) { return (uword)obj & kHeapPtrMask; } 120 121bool Object_is_pair(uword value) { return (value & kHeapTagMask) == kPairTag; } 122 123uword Object_pair_car(uword value) { 124 assert(Object_is_pair(value)); 125 return ((uword *)Object_address((void *)value))[kCarIndex]; 126} 127 128uword Object_pair_cdr(uword value) { 129 assert(Object_is_pair(value)); 130 return ((uword *)Object_address((void *)value))[kCdrIndex]; 131} 132 133// End Objects 134 135// Buffer 136 137typedef unsigned char byte; 138 139typedef enum { 140 kWritable, 141 kExecutable, 142} BufferState; 143 144typedef struct { 145 byte *address; 146 BufferState state; 147 word len; 148 word capacity; 149 uword entrypoint; 150} Buffer; 151 152byte *Buffer_alloc_writable(word capacity) { 153 byte *result = mmap(/*addr=*/NULL, capacity, PROT_READ | PROT_WRITE, 154 MAP_ANONYMOUS | MAP_PRIVATE, 155 /*filedes=*/-1, /*off=*/0); 156 assert(result != MAP_FAILED); 157 return result; 158} 159 160void Buffer_init(Buffer *result, word capacity) { 161 result->address = Buffer_alloc_writable(capacity); 162 assert(result->address != MAP_FAILED); 163 result->state = kWritable; 164 result->len = 0; 165 result->capacity = capacity; 166 result->entrypoint = 0; 167} 168 169word Buffer_len(Buffer *buf) { return buf->len; } 170 171uword Buffer_entrypoint(Buffer *buf) { return buf->entrypoint; } 172void Buffer_set_entrypoint(Buffer *buf, uword entrypoint) { 173 buf->entrypoint = entrypoint; 174} 175 176void Buffer_deinit(Buffer *buf) { 177 munmap(buf->address, buf->capacity); 178 buf->address = NULL; 179 buf->len = 0; 180 buf->capacity = 0; 181} 182 183int Buffer_make_executable(Buffer *buf) { 184 int result = mprotect(buf->address, buf->len, PROT_EXEC); 185 buf->state = kExecutable; 186 return result; 187} 188 189byte Buffer_at8(Buffer *buf, word pos) { return buf->address[pos]; } 190 191void Buffer_at_put8(Buffer *buf, word pos, byte b) { buf->address[pos] = b; } 192 193word max(word left, word right) { return left > right ? left : right; } 194 195void Buffer_ensure_capacity(Buffer *buf, word additional_capacity) { 196 if (buf->len + additional_capacity <= buf->capacity) { 197 return; 198 } 199 word new_capacity = 200 max(buf->capacity * 2, buf->capacity + additional_capacity); 201 byte *address = Buffer_alloc_writable(new_capacity); 202 memcpy(address, buf->address, buf->len); 203 int result = munmap(buf->address, buf->capacity); 204 assert(result == 0 && "munmap failed"); 205 buf->address = address; 206 buf->capacity = new_capacity; 207} 208 209void Buffer_write8(Buffer *buf, byte b) { 210 Buffer_ensure_capacity(buf, sizeof b); 211 Buffer_at_put8(buf, buf->len++, b); 212} 213 214void Buffer_write16(Buffer *buf, uint16_t value) { 215 for (uword i = 0; i < sizeof(value); i++) { 216 Buffer_write8(buf, (value >> (i * kBitsPerByte)) & 0xff); 217 } 218} 219 220void Buffer_write32(Buffer *buf, uint32_t value) { 221 for (uword i = 0; i < sizeof(value); i++) { 222 Buffer_write8(buf, (value >> (i * kBitsPerByte)) & 0xff); 223 } 224} 225 226void Buffer_write64(Buffer *buf, uint64_t value) { 227 for (uword i = 0; i < sizeof(value); i++) { 228 Buffer_write8(buf, (value >> (i * kBitsPerByte)) & 0xff); 229 } 230} 231 232void Buffer_at_put16(Buffer *buf, word offset, uint16_t value) { 233 for (uword i = 0; i < sizeof(value); i++) { 234 Buffer_at_put8(buf, offset + i, (value >> (i * kBitsPerByte)) & 0xff); 235 } 236} 237 238void Buffer_at_put32(Buffer *buf, word offset, uint32_t value) { 239 for (uword i = 0; i < sizeof(value); i++) { 240 Buffer_at_put8(buf, offset + i, (value >> (i * kBitsPerByte)) & 0xff); 241 } 242} 243 244void Buffer_at_put64(Buffer *buf, word offset, uint64_t value) { 245 for (uword i = 0; i < sizeof(value); i++) { 246 Buffer_at_put8(buf, offset + i, (value >> (i * kBitsPerByte)) & 0xff); 247 } 248} 249 250void Buffer_write_arr(Buffer *buf, const byte *arr, word arr_size) { 251 Buffer_ensure_capacity(buf, arr_size); 252 for (word i = 0; i < arr_size; i++) { 253 Buffer_write8(buf, arr[i]); 254 } 255} 256 257void Buffer_dump(Buffer *buf, FILE *fp) { 258 for (word i = 0; i < Buffer_len(buf); i++) { 259 fprintf(fp, "%.2x ", buf->address[i]); 260 } 261 fprintf(fp, "\n"); 262} 263 264// End Buffer 265 266// Emit 267 268typedef enum { 269 kRax = 0, 270 kRcx, 271 kRdx, 272 kRbx, 273 kRsp, 274 kRbp, 275 kRsi, 276 kRdi, 277} Register; 278 279typedef enum { 280 kAl = 0, 281 kCl, 282 kDl, 283 kBl, 284 kAh, 285 kCh, 286 kDh, 287 kBh, 288} PartialRegister; 289 290typedef enum { 291 kOverflow = 0, 292 kNotOverflow, 293 kBelow, 294 kCarry = kBelow, 295 kNotAboveOrEqual = kBelow, 296 kAboveOrEqual, 297 kNotBelow = kAboveOrEqual, 298 kNotCarry = kAboveOrEqual, 299 kEqual, 300 kZero = kEqual, 301 kLess = 0xc, 302 kNotGreaterOrEqual = kLess, 303 // TODO(max): Add more 304} Condition; 305 306typedef struct Indirect { 307 Register reg; 308 word disp; 309} Indirect; 310 311Indirect Ind(Register reg, word disp) { 312 return (Indirect){.reg = reg, .disp = disp}; 313} 314 315// [ Instruction Prefixes (1 byte, optional) ] 316// [ Opcode (1, 2, or 3 bytes) ] 317// [ ModR/M (1 byte, if required) ] 318// [ Scale-Index-Base (1 byte, if required) ] 319// [ Displacement (1, 2, or 4 bytes, if required) ] 320// [ Immediate data (1, 2, or 4 bytes, if required) ] 321 322// http://www.c-jump.com/CIS77/CPU/x86/lecture.html 323// https://wiki.osdev.org/X86-64_Instruction_Encoding 324 325enum { 326 kRexPrefix = 0x48, 327}; 328 329typedef enum { 330 Scale1 = 0, 331 Scale2, 332 Scale4, 333 Scale8, 334} Scale; 335 336typedef enum { 337 kIndexRax = 0, 338 kIndexRcx, 339 kIndexRdx, 340 kIndexRbx, 341 kIndexNone, 342 kIndexRbp, 343 kIndexRsi, 344 kIndexRdi 345} Index; 346 347byte modrm(byte mod, byte rm, byte reg) { 348 return ((mod & 0x3) << 6) | ((reg & 0x7) << 3) | (rm & 0x7); 349} 350 351byte sib(Register base, Index index, Scale scale) { 352 return ((scale & 0x3) << 6) | ((index & 0x7) << 3) | (base & 0x7); 353} 354 355void Emit_mov_reg_imm32(Buffer *buf, Register dst, int32_t src) { 356 Buffer_write8(buf, kRexPrefix); 357 Buffer_write8(buf, 0xc7); 358 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 0)); 359 Buffer_write32(buf, src); 360} 361 362void Emit_ret(Buffer *buf) { Buffer_write8(buf, 0xc3); } 363 364void Emit_add_reg_imm32(Buffer *buf, Register dst, int32_t src) { 365 Buffer_write8(buf, kRexPrefix); 366 if (dst == kRax) { 367 // Optimization: add eax, {imm32} can either be encoded as 05 {imm32} or 81 368 // c0 {imm32}. 369 Buffer_write8(buf, 0x05); 370 } else { 371 Buffer_write8(buf, 0x81); 372 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 0)); 373 } 374 Buffer_write32(buf, src); 375} 376 377void Emit_sub_reg_imm32(Buffer *buf, Register dst, int32_t src) { 378 Buffer_write8(buf, kRexPrefix); 379 if (dst == kRax) { 380 // Optimization: sub eax, {imm32} can either be encoded as 2d {imm32} or 81 381 // e8 {imm32}. 382 Buffer_write8(buf, 0x2d); 383 } else { 384 Buffer_write8(buf, 0x81); 385 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 5)); 386 } 387 Buffer_write32(buf, src); 388} 389 390void Emit_shl_reg_imm8(Buffer *buf, Register dst, int8_t bits) { 391 Buffer_write8(buf, kRexPrefix); 392 Buffer_write8(buf, 0xc1); 393 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 4)); 394 Buffer_write8(buf, bits); 395} 396 397void Emit_shr_reg_imm8(Buffer *buf, Register dst, int8_t bits) { 398 Buffer_write8(buf, kRexPrefix); 399 Buffer_write8(buf, 0xc1); 400 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 5)); 401 Buffer_write8(buf, bits); 402} 403 404void Emit_or_reg_imm8(Buffer *buf, Register dst, uint8_t tag) { 405 Buffer_write8(buf, kRexPrefix); 406 Buffer_write8(buf, 0x83); 407 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 1)); 408 Buffer_write8(buf, tag); 409} 410 411void Emit_and_reg_imm8(Buffer *buf, Register dst, uint8_t tag) { 412 Buffer_write8(buf, kRexPrefix); 413 Buffer_write8(buf, 0x83); 414 Buffer_write8(buf, modrm(/*direct*/ 3, dst, 4)); 415 Buffer_write8(buf, tag); 416} 417 418void Emit_cmp_reg_imm32(Buffer *buf, Register left, int32_t right) { 419 Buffer_write8(buf, kRexPrefix); 420 if (left == kRax) { 421 // Optimization: cmp rax, {imm32} can either be encoded as 3d {imm32} or 81 422 // f8 {imm32}. 423 Buffer_write8(buf, 0x3d); 424 } else { 425 Buffer_write8(buf, 0x81); 426 Buffer_write8(buf, modrm(/*direct*/ 3, left, 7)); 427 } 428 Buffer_write32(buf, right); 429} 430 431void Emit_setcc_imm8(Buffer *buf, Condition cond, PartialRegister dst) { 432 // TODO(max): Emit a REX prefix if we need anything above RDI. 433 Buffer_write8(buf, 0x0f); 434 Buffer_write8(buf, 0x90 + cond); 435 Buffer_write8(buf, 0xc0 + (dst & 0x7)); 436} 437 438uint8_t disp8(int8_t disp) { return disp >= 0 ? disp : 0x100 + disp; } 439 440void Emit_address_disp8(Buffer *buf, Register direct, Indirect indirect) { 441 if (indirect.reg == kRsp) { 442 Buffer_write8(buf, modrm(/*disp8*/ 1, kIndexNone, direct)); 443 Buffer_write8(buf, sib(kRsp, kIndexNone, Scale1)); 444 } else { 445 Buffer_write8(buf, modrm(/*disp8*/ 1, indirect.reg, direct)); 446 } 447 Buffer_write8(buf, disp8(indirect.disp)); 448} 449 450// mov [dst+disp], src 451// or 452// mov %src, disp(%dst) 453void Emit_store_reg_indirect(Buffer *buf, Indirect dst, Register src) { 454 Buffer_write8(buf, kRexPrefix); 455 Buffer_write8(buf, 0x89); 456 Emit_address_disp8(buf, src, dst); 457} 458 459// add dst, [src+disp] 460// or 461// add disp(%src), %dst 462void Emit_add_reg_indirect(Buffer *buf, Register dst, Indirect src) { 463 Buffer_write8(buf, kRexPrefix); 464 Buffer_write8(buf, 0x03); 465 Emit_address_disp8(buf, dst, src); 466} 467 468// sub dst, [src+disp] 469// or 470// sub disp(%src), %dst 471void Emit_sub_reg_indirect(Buffer *buf, Register dst, Indirect src) { 472 Buffer_write8(buf, kRexPrefix); 473 Buffer_write8(buf, 0x2b); 474 Emit_address_disp8(buf, dst, src); 475} 476 477// mul rax, [src+disp] 478// or 479// mul disp(%src), %rax 480void Emit_mul_reg_indirect(Buffer *buf, Indirect src) { 481 Buffer_write8(buf, kRexPrefix); 482 Buffer_write8(buf, 0xf7); 483 Emit_address_disp8(buf, /*subop*/ 4, src); 484} 485 486// cmp left, [right+disp] 487// or 488// cmp disp(%right), %left 489void Emit_cmp_reg_indirect(Buffer *buf, Register left, Indirect right) { 490 Buffer_write8(buf, kRexPrefix); 491 Buffer_write8(buf, 0x3b); 492 Emit_address_disp8(buf, left, right); 493} 494 495// mov dst, [src+disp] 496// or 497// mov disp(%src), %dst 498void Emit_load_reg_indirect(Buffer *buf, Register dst, Indirect src) { 499 Buffer_write8(buf, kRexPrefix); 500 Buffer_write8(buf, 0x8b); 501 Emit_address_disp8(buf, dst, src); 502} 503 504uint32_t disp32(int32_t disp) { return disp >= 0 ? disp : 0x100000000 + disp; } 505 506word Emit_jcc(Buffer *buf, Condition cond, int32_t offset) { 507 Buffer_write8(buf, 0x0f); 508 Buffer_write8(buf, 0x80 + cond); 509 word pos = Buffer_len(buf); 510 Buffer_write32(buf, disp32(offset)); 511 return pos; 512} 513 514word Emit_jmp(Buffer *buf, int32_t offset) { 515 Buffer_write8(buf, 0xe9); 516 word pos = Buffer_len(buf); 517 Buffer_write32(buf, disp32(offset)); 518 return pos; 519} 520 521void Emit_backpatch_imm32(Buffer *buf, int32_t target_pos) { 522 word current_pos = Buffer_len(buf); 523 word relative_pos = current_pos - target_pos - sizeof(int32_t); 524 Buffer_at_put32(buf, target_pos, disp32(relative_pos)); 525} 526 527void Emit_mov_reg_reg(Buffer *buf, Register dst, Register src) { 528 Buffer_write8(buf, kRexPrefix); 529 Buffer_write8(buf, 0x89); 530 Buffer_write8(buf, modrm(/*direct*/ 3, dst, src)); 531} 532 533void Emit_syscall(Buffer *buf) { 534 Buffer_write8(buf, 0x0f); 535 Buffer_write8(buf, 0x05); 536} 537 538// End Emit 539 540// AST 541 542typedef struct ASTNode ASTNode; 543 544typedef struct Pair { 545 ASTNode *car; 546 ASTNode *cdr; 547} Pair; 548 549typedef struct Symbol { 550 word length; 551 char cstr[]; 552} Symbol; 553 554bool AST_is_integer(ASTNode *node) { 555 return ((uword)node & kIntegerTagMask) == kIntegerTag; 556} 557 558word AST_get_integer(ASTNode *node) { 559 return Object_decode_integer((uword)node); 560} 561 562ASTNode *AST_new_integer(word value) { 563 return (ASTNode *)Object_encode_integer(value); 564} 565 566bool AST_is_char(ASTNode *node) { 567 return ((uword)node & kImmediateTagMask) == kCharTag; 568} 569 570char AST_get_char(ASTNode *node) { return Object_decode_char((uword)node); } 571 572ASTNode *AST_new_char(char value) { 573 return (ASTNode *)Object_encode_char(value); 574} 575 576bool AST_is_bool(ASTNode *node) { 577 return ((uword)node & kImmediateTagMask) == kBoolTag; 578} 579 580bool AST_get_bool(ASTNode *node) { return Object_decode_bool((uword)node); } 581 582ASTNode *AST_new_bool(bool value) { 583 return (ASTNode *)Object_encode_bool(value); 584} 585 586bool AST_is_nil(ASTNode *node) { return (uword)node == Object_nil(); } 587 588ASTNode *AST_nil() { return (ASTNode *)Object_nil(); } 589 590bool AST_is_error(ASTNode *node) { return (uword)node == Object_error(); } 591 592ASTNode *AST_error() { return (ASTNode *)Object_error(); } 593 594ASTNode *AST_heap_alloc(unsigned char tag, uword size) { 595 // Initialize to 0 596 uword address = (uword)calloc(size, 1); 597 return (ASTNode *)(address | tag); 598} 599 600bool AST_is_heap_object(ASTNode *node) { 601 // For some reason masking out the tag first and then doing the comparison 602 // makes this branchless 603 unsigned char tag = (uword)node & kHeapTagMask; 604 // Heap object tags are between 0b001 and 0b110 except for 0b100 (which is an 605 // integer) 606 return (tag & kIntegerTagMask) > 0 && (tag & kImmediateTagMask) != 0x7; 607} 608 609void AST_pair_set_car(ASTNode *node, ASTNode *car); 610void AST_pair_set_cdr(ASTNode *node, ASTNode *cdr); 611 612ASTNode *AST_new_pair(ASTNode *car, ASTNode *cdr) { 613 ASTNode *node = AST_heap_alloc(kPairTag, sizeof(Pair)); 614 AST_pair_set_car(node, car); 615 AST_pair_set_cdr(node, cdr); 616 return node; 617} 618 619bool AST_is_pair(ASTNode *node) { 620 return ((uword)node & kHeapTagMask) == kPairTag; 621} 622 623Pair *AST_as_pair(ASTNode *node) { 624 assert(AST_is_pair(node)); 625 return (Pair *)Object_address(node); 626} 627 628ASTNode *AST_pair_car(ASTNode *node) { return AST_as_pair(node)->car; } 629 630void AST_pair_set_car(ASTNode *node, ASTNode *car) { 631 AST_as_pair(node)->car = car; 632} 633 634ASTNode *AST_pair_cdr(ASTNode *node) { return AST_as_pair(node)->cdr; } 635 636void AST_pair_set_cdr(ASTNode *node, ASTNode *cdr) { 637 AST_as_pair(node)->cdr = cdr; 638} 639 640void AST_heap_free(ASTNode *node) { 641 if (!AST_is_heap_object(node)) { 642 return; 643 } 644 if (AST_is_pair(node)) { 645 AST_heap_free(AST_pair_car(node)); 646 AST_heap_free(AST_pair_cdr(node)); 647 } 648 free((void *)Object_address(node)); 649} 650 651Symbol *AST_as_symbol(ASTNode *node); 652 653ASTNode *AST_new_symbol(const char *str) { 654 word data_length = strlen(str) + 1; // for NUL 655 ASTNode *node = AST_heap_alloc(kSymbolTag, sizeof(Symbol) + data_length); 656 Symbol *s = AST_as_symbol(node); 657 s->length = data_length; 658 memcpy(s->cstr, str, data_length); 659 return node; 660} 661 662bool AST_is_symbol(ASTNode *node) { 663 return ((uword)node & kHeapTagMask) == kSymbolTag; 664} 665 666Symbol *AST_as_symbol(ASTNode *node) { 667 assert(AST_is_symbol(node)); 668 return (Symbol *)Object_address(node); 669} 670 671const char *AST_symbol_cstr(ASTNode *node) { 672 return (const char *)AST_as_symbol(node)->cstr; 673} 674 675bool AST_symbol_matches(ASTNode *node, const char *cstr) { 676 return strcmp(AST_symbol_cstr(node), cstr) == 0; 677} 678 679int node_to_str(ASTNode *node, char *buf, word size); 680 681int list_to_str(ASTNode *node, char *buf, word size) { 682 if (AST_is_pair(node)) { 683 word result = 0; 684 result += snprintf(buf + result, size, " "); 685 result += node_to_str(AST_pair_car(node), buf + result, size); 686 result += list_to_str(AST_pair_cdr(node), buf + result, size); 687 return result; 688 } 689 if (AST_is_nil(node)) { 690 return snprintf(buf, size, ")"); 691 } 692 word result = 0; 693 result += snprintf(buf + result, size, " . "); 694 result += node_to_str(node, buf + result, size); 695 result += snprintf(buf + result, size, ")"); 696 return result; 697} 698 699int node_to_str(ASTNode *node, char *buf, word size) { 700 if (AST_is_integer(node)) { 701 return snprintf(buf, size, "%ld", AST_get_integer(node)); 702 } 703 if (AST_is_char(node)) { 704 return snprintf(buf, size, "'%c'", AST_get_char(node)); 705 } 706 if (AST_is_bool(node)) { 707 return snprintf(buf, size, "%s", AST_get_bool(node) ? "true" : "false"); 708 } 709 if (AST_is_nil(node)) { 710 return snprintf(buf, size, "nil"); 711 } 712 if (AST_is_pair(node)) { 713 word result = 0; 714 result += snprintf(buf + result, size, "("); 715 result += node_to_str(AST_pair_car(node), buf + result, size); 716 result += list_to_str(AST_pair_cdr(node), buf + result, size); 717 return result; 718 } 719 if (AST_is_symbol(node)) { 720 return snprintf(buf, size, "%s", AST_symbol_cstr(node)); 721 } 722 assert(0 && "unknown ast"); 723} 724 725char *AST_to_cstr(ASTNode *node) { 726 int size = node_to_str(node, NULL, 0); 727 char *buf = malloc(size + 1); 728 assert(buf != NULL); 729 node_to_str(node, buf, size + 1); 730 buf[size] = '\0'; 731 return buf; 732} 733 734// End AST 735 736// Reader 737 738void advance(word *pos) { ++*pos; } 739 740char next(char *input, word *pos) { 741 advance(pos); 742 return input[*pos]; 743} 744 745ASTNode *read_integer(char *input, word *pos, int sign) { 746 word result = 0; 747 for (char c = input[*pos]; isdigit(c); c = next(input, pos)) { 748 result *= 10; 749 result += c - '0'; 750 } 751 return AST_new_integer(sign * result); 752} 753 754bool starts_symbol(char c) { 755 switch (c) { 756 case '+': 757 case '-': 758 case '*': 759 case '<': 760 case '>': 761 case '=': 762 case '?': 763 return true; 764 default: 765 return isalpha(c); 766 } 767} 768 769bool is_symbol_char(char c) { return starts_symbol(c) || isdigit(c); } 770 771const word ATOM_MAX = 32; 772 773ASTNode *read_symbol(char *input, word *pos) { 774 char buf[ATOM_MAX + 1]; // +1 for NUL 775 word length = 0; 776 for (length = 0; length < ATOM_MAX && is_symbol_char(input[*pos]); length++) { 777 buf[length] = input[*pos]; 778 advance(pos); 779 } 780 buf[length] = '\0'; 781 return AST_new_symbol(buf); 782} 783 784ASTNode *read_char(char *input, word *pos) { 785 char c = input[*pos]; 786 if (c == '\'') { 787 return AST_error(); 788 } 789 advance(pos); 790 if (input[*pos] != '\'') { 791 return AST_error(); 792 } 793 advance(pos); 794 return AST_new_char(c); 795} 796 797char skip_whitespace(char *input, word *pos) { 798 char c = '\0'; 799 for (c = input[*pos]; isspace(c); c = next(input, pos)) { 800 ; 801 } 802 return c; 803} 804 805ASTNode *read_rec(char *input, word *pos); 806 807ASTNode *read_list(char *input, word *pos) { 808 char c = skip_whitespace(input, pos); 809 if (c == ')') { 810 advance(pos); 811 return AST_nil(); 812 } 813 ASTNode *car = read_rec(input, pos); 814 assert(car != AST_error()); 815 ASTNode *cdr = read_list(input, pos); 816 assert(cdr != AST_error()); 817 return AST_new_pair(car, cdr); 818} 819 820ASTNode *read_rec(char *input, word *pos) { 821 char c = skip_whitespace(input, pos); 822 if (isdigit(c)) { 823 return read_integer(input, pos, /*sign=*/1); 824 } 825 if (c == '-' && isdigit(input[*pos + 1])) { 826 advance(pos); 827 return read_integer(input, pos, /*sign=*/-1); 828 } 829 if (c == '+' && isdigit(input[*pos + 1])) { 830 advance(pos); 831 return read_integer(input, pos, /*sign=*/1); 832 } 833 if (starts_symbol(c)) { 834 return read_symbol(input, pos); 835 } 836 if (c == '\'') { 837 advance(pos); // skip '\'' 838 return read_char(input, pos); 839 } 840 if (c == '#' && input[*pos + 1] == 't') { 841 advance(pos); // skip '#' 842 advance(pos); // skip 't' 843 return AST_new_bool(true); 844 } 845 if (c == '#' && input[*pos + 1] == 'f') { 846 advance(pos); // skip '#' 847 advance(pos); // skip 'f' 848 return AST_new_bool(false); 849 } 850 if (c == '(') { 851 advance(pos); // skip '(' 852 return read_list(input, pos); 853 } 854 return AST_error(); 855} 856 857ASTNode *Reader_read(char *input) { 858 word pos = 0; 859 return read_rec(input, &pos); 860} 861 862// End Reader 863 864// Env 865 866typedef struct Env { 867 const char *name; 868 word value; 869 struct Env *prev; 870} Env; 871 872Env Env_bind(const char *name, word value, Env *prev) { 873 return (Env){.name = name, .value = value, .prev = prev}; 874} 875 876bool Env_find(Env *env, const char *key, word *result) { 877 if (env == NULL) 878 return false; 879 if (strcmp(env->name, key) == 0) { 880 *result = env->value; 881 return true; 882 } 883 return Env_find(env->prev, key, result); 884} 885 886// End Env 887 888// Compile 889 890WARN_UNUSED int Compile_expr(Buffer *buf, ASTNode *node, word stack_index, 891 Env *varenv, Env *labels); 892 893ASTNode *operand1(ASTNode *args) { return AST_pair_car(args); } 894 895ASTNode *operand2(ASTNode *args) { return AST_pair_car(AST_pair_cdr(args)); } 896 897ASTNode *operand3(ASTNode *args) { 898 return AST_pair_car(AST_pair_cdr(AST_pair_cdr(args))); 899} 900 901#define _(exp) \ 902 do { \ 903 int result = exp; \ 904 if (result != 0) \ 905 return result; \ 906 } while (0) 907 908void Compile_compare_imm32(Buffer *buf, int32_t value) { 909 Emit_cmp_reg_imm32(buf, kRax, value); 910 Emit_mov_reg_imm32(buf, kRax, 0); 911 Emit_setcc_imm8(buf, kEqual, kAl); 912 Emit_shl_reg_imm8(buf, kRax, kBoolShift); 913 Emit_or_reg_imm8(buf, kRax, kBoolTag); 914} 915 916// This is let, not let*. Therefore we keep track of two environments -- the 917// parent environment, for evaluating the bindings, and the body environment, 918// which will have all of the bindings in addition to the parent. This makes 919// programs like (let ((a 1) (b a)) b) fail. 920WARN_UNUSED int Compile_let(Buffer *buf, ASTNode *bindings, ASTNode *body, 921 word stack_index, Env *binding_env, Env *body_env, 922 Env *labels) { 923 if (AST_is_nil(bindings)) { 924 // Base case: no bindings. Compile the body 925 _(Compile_expr(buf, body, stack_index, body_env, labels)); 926 return 0; 927 } 928 assert(AST_is_pair(bindings)); 929 // Get the next binding 930 ASTNode *binding = AST_pair_car(bindings); 931 ASTNode *name = AST_pair_car(binding); 932 assert(AST_is_symbol(name)); 933 ASTNode *binding_expr = AST_pair_car(AST_pair_cdr(binding)); 934 // Compile the binding expression 935 _(Compile_expr(buf, binding_expr, stack_index, binding_env, labels)); 936 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 937 /*src=*/kRax); 938 // Bind the name 939 Env entry = Env_bind(AST_symbol_cstr(name), stack_index, body_env); 940 _(Compile_let(buf, AST_pair_cdr(bindings), body, stack_index - kWordSize, 941 /*binding_env=*/binding_env, /*body_env=*/&entry, labels)); 942 return 0; 943} 944 945const int32_t kLabelPlaceholder = 0xdeadbeef; 946 947WARN_UNUSED int Compile_if(Buffer *buf, ASTNode *cond, ASTNode *consequent, 948 ASTNode *alternate, word stack_index, Env *varenv, 949 Env *labels) { 950 _(Compile_expr(buf, cond, stack_index, varenv, labels)); 951 Emit_cmp_reg_imm32(buf, kRax, Object_false()); 952 word alternate_pos = Emit_jcc(buf, kEqual, kLabelPlaceholder); // je alternate 953 _(Compile_expr(buf, consequent, stack_index, varenv, labels)); 954 word end_pos = Emit_jmp(buf, kLabelPlaceholder); // jmp end 955 Emit_backpatch_imm32(buf, alternate_pos); // alternate: 956 _(Compile_expr(buf, alternate, stack_index, varenv, labels)); 957 Emit_backpatch_imm32(buf, end_pos); // end: 958 return 0; 959} 960 961const Register kHeapPointer = kRsi; 962 963WARN_UNUSED int Compile_cons(Buffer *buf, ASTNode *car, ASTNode *cdr, 964 word stack_index, Env *varenv, Env *labels) { 965 // Compile and store car on the stack 966 _(Compile_expr(buf, car, stack_index, varenv, labels)); 967 Emit_store_reg_indirect(buf, 968 /*dst=*/Ind(kRsp, stack_index), 969 /*src=*/kRax); 970 // Compile and store cdr 971 _(Compile_expr(buf, cdr, stack_index - kWordSize, varenv, labels)); 972 Emit_store_reg_indirect(buf, /*dst=*/Ind(kHeapPointer, kCdrOffset), 973 /*src=*/kRax); 974 // Fetch car and store in the heap 975 Emit_load_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 976 Emit_store_reg_indirect(buf, /*dst=*/Ind(kHeapPointer, kCarOffset), 977 /*src=*/kRax); 978 // Store tagged pointer in rax 979 // TODO(max): Rewrite as lea rax, [rsi+kPairTag] 980 Emit_mov_reg_reg(buf, /*dst=*/kRax, /*src=*/kHeapPointer); 981 Emit_or_reg_imm8(buf, /*dst=*/kRax, kPairTag); 982 // Bump the heap pointer 983 Emit_add_reg_imm32(buf, /*dst=*/kHeapPointer, kPairSize); 984 return 0; 985} 986 987word list_length(ASTNode *node) { 988 if (AST_is_nil(node)) { 989 return 0; 990 } 991 assert(AST_is_pair(node)); 992 return 1 + list_length(AST_pair_cdr(node)); 993} 994 995void Emit_rsp_adjust(Buffer *buf, word adjust) { 996 if (adjust < 0) { 997 Emit_sub_reg_imm32(buf, kRsp, -adjust); 998 } else if (adjust > 0) { 999 Emit_add_reg_imm32(buf, kRsp, adjust); 1000 } 1001} 1002 1003void Emit_call_imm32(Buffer *buf, word absolute_address) { 1004 // 5 is length of call instruction 1005 word relative_address = absolute_address - (Buffer_len(buf) + 5); 1006 Buffer_write8(buf, 0xe8); 1007 Buffer_write32(buf, relative_address); 1008} 1009 1010WARN_UNUSED int Compile_labelcall(Buffer *buf, ASTNode *callable, ASTNode *args, 1011 word stack_index, Env *varenv, Env *labels, 1012 word nargs, word rsp_adjust) { 1013 if (AST_is_nil(args)) { 1014 const char *symbol = AST_symbol_cstr(callable); 1015 word code_address; 1016 if (!Env_find(labels, symbol, &code_address)) { 1017 return -1; 1018 } 1019 // TODO(max): Determine if we need to align the stack to 16 bytes 1020 // Save the locals 1021 Emit_rsp_adjust(buf, rsp_adjust); 1022 Emit_call_imm32(buf, code_address); 1023 // Unsave the locals 1024 Emit_rsp_adjust(buf, -rsp_adjust); 1025 return 0; 1026 } 1027 assert(AST_is_pair(args)); 1028 ASTNode *arg = AST_pair_car(args); 1029 _(Compile_expr(buf, arg, stack_index, varenv, labels)); 1030 Emit_store_reg_indirect(buf, Ind(kRsp, stack_index), kRax); 1031 return Compile_labelcall(buf, callable, AST_pair_cdr(args), 1032 stack_index - kWordSize, varenv, labels, nargs, 1033 rsp_adjust); 1034} 1035 1036WARN_UNUSED int Compile_call(Buffer *buf, ASTNode *callable, ASTNode *args, 1037 word stack_index, Env *varenv, Env *labels) { 1038 if (AST_is_symbol(callable)) { 1039 if (AST_symbol_matches(callable, "add1")) { 1040 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1041 Emit_add_reg_imm32(buf, kRax, Object_encode_integer(1)); 1042 return 0; 1043 } 1044 if (AST_symbol_matches(callable, "sub1")) { 1045 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1046 Emit_sub_reg_imm32(buf, kRax, Object_encode_integer(1)); 1047 return 0; 1048 } 1049 if (AST_symbol_matches(callable, "integer->char")) { 1050 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1051 Emit_shl_reg_imm8(buf, kRax, kCharShift - kIntegerShift); 1052 Emit_or_reg_imm8(buf, kRax, kCharTag); 1053 return 0; 1054 } 1055 if (AST_symbol_matches(callable, "char->integer")) { 1056 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1057 Emit_shr_reg_imm8(buf, kRax, kCharShift - kIntegerShift); 1058 return 0; 1059 } 1060 if (AST_symbol_matches(callable, "nil?")) { 1061 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1062 Compile_compare_imm32(buf, Object_nil()); 1063 return 0; 1064 } 1065 if (AST_symbol_matches(callable, "zero?")) { 1066 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1067 Compile_compare_imm32(buf, Object_encode_integer(0)); 1068 return 0; 1069 } 1070 if (AST_symbol_matches(callable, "not")) { 1071 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1072 // All non #f values are truthy 1073 // ...this might be a problem if we want to make nil falsey 1074 Compile_compare_imm32(buf, Object_false()); 1075 return 0; 1076 } 1077 if (AST_symbol_matches(callable, "integer?")) { 1078 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1079 Emit_and_reg_imm8(buf, kRax, kIntegerTagMask); 1080 Compile_compare_imm32(buf, kIntegerTag); 1081 return 0; 1082 } 1083 if (AST_symbol_matches(callable, "boolean?")) { 1084 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1085 Emit_and_reg_imm8(buf, kRax, kImmediateTagMask); 1086 Compile_compare_imm32(buf, kBoolTag); 1087 return 0; 1088 } 1089 if (AST_symbol_matches(callable, "+")) { 1090 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1091 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1092 /*src=*/kRax); 1093 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1094 labels)); 1095 Emit_add_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 1096 return 0; 1097 } 1098 if (AST_symbol_matches(callable, "-")) { 1099 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1100 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1101 /*src=*/kRax); 1102 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1103 labels)); 1104 Emit_sub_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 1105 return 0; 1106 } 1107 if (AST_symbol_matches(callable, "*")) { 1108 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1109 // Remove the tag so that the result is still only tagged with 0b00 1110 // instead of 0b0000 1111 Emit_shr_reg_imm8(buf, kRax, kIntegerShift); 1112 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1113 /*src=*/kRax); 1114 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1115 labels)); 1116 Emit_mul_reg_indirect(buf, /*src=*/Ind(kRsp, stack_index)); 1117 return 0; 1118 } 1119 if (AST_symbol_matches(callable, "=")) { 1120 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1121 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1122 /*src=*/kRax); 1123 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1124 labels)); 1125 Emit_cmp_reg_indirect(buf, kRax, Ind(kRsp, stack_index)); 1126 Emit_mov_reg_imm32(buf, kRax, 0); 1127 Emit_setcc_imm8(buf, kEqual, kAl); 1128 Emit_shl_reg_imm8(buf, kRax, kBoolShift); 1129 Emit_or_reg_imm8(buf, kRax, kBoolTag); 1130 return 0; 1131 } 1132 if (AST_symbol_matches(callable, "<")) { 1133 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1134 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1135 /*src=*/kRax); 1136 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1137 labels)); 1138 Emit_cmp_reg_indirect(buf, kRax, Ind(kRsp, stack_index)); 1139 Emit_mov_reg_imm32(buf, kRax, 0); 1140 Emit_setcc_imm8(buf, kLess, kAl); 1141 Emit_shl_reg_imm8(buf, kRax, kBoolShift); 1142 Emit_or_reg_imm8(buf, kRax, kBoolTag); 1143 return 0; 1144 } 1145 if (AST_symbol_matches(callable, "let")) { 1146 return Compile_let(buf, /*bindings=*/operand1(args), 1147 /*body=*/operand2(args), stack_index, 1148 /*binding_env=*/varenv, 1149 /*body_env=*/varenv, labels); 1150 } 1151 if (AST_symbol_matches(callable, "if")) { 1152 return Compile_if(buf, /*condition=*/operand1(args), 1153 /*consequent=*/operand2(args), 1154 /*alternate=*/operand3(args), stack_index, varenv, 1155 labels); 1156 } 1157 if (AST_symbol_matches(callable, "cons")) { 1158 return Compile_cons(buf, /*car=*/operand1(args), /*cdr=*/operand2(args), 1159 stack_index, varenv, labels); 1160 } 1161 if (AST_symbol_matches(callable, "car")) { 1162 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1163 Emit_load_reg_indirect(buf, /*dst=*/kRax, 1164 /*src=*/Ind(kRax, kCarOffset - kPairTag)); 1165 return 0; 1166 } 1167 if (AST_symbol_matches(callable, "cdr")) { 1168 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1169 Emit_load_reg_indirect(buf, /*dst=*/kRax, 1170 /*src=*/Ind(kRax, kCdrOffset - kPairTag)); 1171 return 0; 1172 } 1173 if (AST_symbol_matches(callable, "labelcall")) { 1174 ASTNode *label = operand1(args); 1175 assert(AST_is_symbol(label)); 1176 ASTNode *call_args = AST_pair_cdr(args); 1177 word nargs = list_length(call_args); 1178 // Skip a space on the stack to put the return address 1179 return Compile_labelcall(buf, label, call_args, stack_index - kWordSize, 1180 // TODO(max): Figure out the +kWordSize 1181 varenv, labels, nargs, stack_index + kWordSize); 1182 } 1183 } 1184 assert(0 && "unexpected call type"); 1185} 1186 1187WARN_UNUSED int Compile_expr(Buffer *buf, ASTNode *node, word stack_index, 1188 Env *varenv, Env *labels) { 1189 if (AST_is_integer(node)) { 1190 word value = AST_get_integer(node); 1191 Emit_mov_reg_imm32(buf, kRax, Object_encode_integer(value)); 1192 return 0; 1193 } 1194 if (AST_is_char(node)) { 1195 char value = AST_get_char(node); 1196 Emit_mov_reg_imm32(buf, kRax, Object_encode_char(value)); 1197 return 0; 1198 } 1199 if (AST_is_bool(node)) { 1200 bool value = AST_get_bool(node); 1201 Emit_mov_reg_imm32(buf, kRax, Object_encode_bool(value)); 1202 return 0; 1203 } 1204 if (AST_is_nil(node)) { 1205 Emit_mov_reg_imm32(buf, kRax, Object_nil()); 1206 return 0; 1207 } 1208 if (AST_is_pair(node)) { 1209 return Compile_call(buf, AST_pair_car(node), AST_pair_cdr(node), 1210 stack_index, varenv, labels); 1211 } 1212 if (AST_is_symbol(node)) { 1213 const char *symbol = AST_symbol_cstr(node); 1214 word value; 1215 if (Env_find(varenv, symbol, &value)) { 1216 Emit_load_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, value)); 1217 return 0; 1218 } 1219 return -1; 1220 } 1221 assert(0 && "unexpected node type"); 1222} 1223 1224const byte kEntryPrologue[] = { 1225 // Save the heap in rsi, our global heap pointer 1226 // mov rsi, rdi 1227 kRexPrefix, 1228 0x89, 1229 0xfe, 1230}; 1231 1232const byte kFunctionEpilogue[] = { 1233 // ret 1234 0xc3, 1235}; 1236 1237WARN_UNUSED int Compile_code_impl(Buffer *buf, ASTNode *formals, ASTNode *body, 1238 word stack_index, Env *varenv, Env *labels) { 1239 if (AST_is_nil(formals)) { 1240 _(Compile_expr(buf, body, stack_index, varenv, labels)); 1241 Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue); 1242 return 0; 1243 } 1244 assert(AST_is_pair(formals)); 1245 ASTNode *name = AST_pair_car(formals); 1246 assert(AST_is_symbol(name)); 1247 Env entry = Env_bind(AST_symbol_cstr(name), stack_index, varenv); 1248 return Compile_code_impl(buf, AST_pair_cdr(formals), body, 1249 stack_index - kWordSize, &entry, labels); 1250} 1251 1252WARN_UNUSED int Compile_code(Buffer *buf, ASTNode *code, Env *labels) { 1253 assert(AST_is_pair(code)); 1254 ASTNode *code_sym = AST_pair_car(code); 1255 assert(AST_is_symbol(code_sym)); 1256 assert(AST_symbol_matches(code_sym, "code")); 1257 ASTNode *args = AST_pair_cdr(code); 1258 ASTNode *formals = operand1(args); 1259 ASTNode *code_body = operand2(args); 1260 return Compile_code_impl(buf, formals, code_body, /*stack_index=*/-kWordSize, 1261 /*varenv=*/NULL, labels); 1262} 1263 1264WARN_UNUSED int Compile_labels(Buffer *buf, ASTNode *bindings, ASTNode *body, 1265 Env *labels, word body_pos) { 1266 if (AST_is_nil(bindings)) { 1267 Buffer_set_entrypoint(buf, Buffer_len(buf)); 1268 Emit_backpatch_imm32(buf, body_pos); 1269 // Base case: no bindings. Compile the body 1270 _(Compile_expr(buf, body, /*stack_index=*/-kWordSize, /*varenv=*/NULL, 1271 labels)); 1272 return 0; 1273 } 1274 assert(AST_is_pair(bindings)); 1275 // Get the next binding 1276 ASTNode *binding = AST_pair_car(bindings); 1277 ASTNode *name = AST_pair_car(binding); 1278 assert(AST_is_symbol(name)); 1279 ASTNode *binding_code = AST_pair_car(AST_pair_cdr(binding)); 1280 word function_location = Buffer_len(buf); 1281 // Bind the name to the location in the instruction stream 1282 Env entry = Env_bind(AST_symbol_cstr(name), function_location, labels); 1283 // Compile the binding function 1284 _(Compile_code(buf, binding_code, &entry)); 1285 _(Compile_labels(buf, AST_pair_cdr(bindings), body, &entry, body_pos)); 1286 return 0; 1287} 1288 1289WARN_UNUSED int Compile_entry(Buffer *buf, ASTNode *node) { 1290 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 1291 assert(AST_is_pair(node) && "program must have labels"); 1292 // Assume it's (labels ...) 1293 ASTNode *labels_sym = AST_pair_car(node); 1294 assert(AST_is_symbol(labels_sym) && "program must have labels"); 1295 assert(AST_symbol_matches(labels_sym, "labels") && 1296 "program must have labels"); 1297 // Jump to body 1298 word body_pos = Emit_jmp(buf, kLabelPlaceholder); 1299 ASTNode *args = AST_pair_cdr(node); 1300 ASTNode *bindings = operand1(args); 1301 assert(AST_is_pair(bindings) || AST_is_nil(bindings)); 1302 ASTNode *body = operand2(args); 1303 _(Compile_labels(buf, bindings, body, /*labels=*/NULL, body_pos)); 1304 Emit_shr_reg_imm8(buf, kRax, kIntegerShift); 1305 Emit_mov_reg_reg(buf, kRdi, kRax); // return code from result of body 1306 Emit_mov_reg_imm32(buf, kRax, 60); // exit 1307 Emit_syscall(buf); 1308 // Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue); 1309 return 0; 1310} 1311 1312WARN_UNUSED int Compile_to_file(ASTNode *node, const char *filename) { 1313 (void)node; 1314 Buffer buf; 1315 Buffer_init(&buf, 1); 1316 1317 word org = 0x08048000; 1318 1319 // BEGIN e_ident 1320 Buffer_write8(&buf, 0x7F); 1321 Buffer_write8(&buf, 'E'); 1322 Buffer_write8(&buf, 'L'); 1323 Buffer_write8(&buf, 'F'); 1324 Buffer_write8(&buf, 2); // 64-bit 1325 Buffer_write8(&buf, 1); // little-endian 1326 Buffer_write8(&buf, 1); // ??? 1327 Buffer_write8(&buf, 0); // ??? 1328 for (word i = 0; i < 8; i++) { 1329 Buffer_write8(&buf, 0); // unused e_ident 1330 } 1331 // END e_ident 1332 Buffer_write32(&buf, 0x003e0002); // e_machine_type 1333 Buffer_write32(&buf, 1); // e_version 1334 word e_entry_pos = Buffer_len(&buf); 1335 Buffer_write64(&buf, 0); // e_entry 1336 word e_phoff_pos = Buffer_len(&buf); 1337 Buffer_write64(&buf, 0); // e_phoff 1338 Buffer_write64(&buf, 0); // e_shoff 1339 Buffer_write32(&buf, 0); // e_flags 1340 word e_ehsize_pos = Buffer_len(&buf); 1341 Buffer_write16(&buf, 0); // e_ehsize 1342 word e_phentsize_pos = Buffer_len(&buf); 1343 Buffer_write16(&buf, 0); // e_phentsize 1344 Buffer_write16(&buf, 1); // e_phnum 1345 Buffer_write16(&buf, 0); // e_shentsize 1346 Buffer_write16(&buf, 0); // e_shnum 1347 Buffer_write16(&buf, 0); // e_shstrndx 1348 1349 // Backpatch e_ehsize 1350 Buffer_at_put32(&buf, e_ehsize_pos, Buffer_len(&buf)); 1351 1352 word phdr_start_pos = Buffer_len(&buf); 1353 // Backpatch e_phoff 1354 Buffer_at_put64(&buf, e_phoff_pos, phdr_start_pos); 1355 1356 Buffer_write32(&buf, 1); // p_type 1357 Buffer_write32(&buf, 5); // p_flags 1358 Buffer_write64(&buf, 0); // p_offset 1359 Buffer_write64(&buf, org); // p_vaddr 1360 Buffer_write64(&buf, org); // p_paddr 1361 word filesz_pos = Buffer_len(&buf); 1362 Buffer_write64(&buf, 0); // p_filesz 1363 word memsz_pos = Buffer_len(&buf); 1364 Buffer_write64(&buf, 0); // p_memsz 1365 Buffer_write64(&buf, 0x1000); // p_align 1366 1367 word phdrsize = Buffer_len(&buf) - phdr_start_pos; 1368 // Backpatch e_phentsize 1369 Buffer_at_put16(&buf, e_phentsize_pos, phdrsize); 1370 1371 _(Compile_entry(&buf, node)); 1372 1373 // Backpatch e_entry 1374 Buffer_at_put64(&buf, e_entry_pos, org + buf.entrypoint); 1375 1376 word filesize = Buffer_len(&buf); 1377 // Backpatch p_filesz 1378 Buffer_at_put64(&buf, filesz_pos, filesize); 1379 // Backpatch p_memsz 1380 Buffer_at_put64(&buf, memsz_pos, filesize); 1381 1382 FILE *fp = fopen(filename, "w+b"); 1383 assert(fp != NULL); 1384 size_t written = 1385 fwrite(buf.address, /*size=*/1, /*nmemb=*/Buffer_len(&buf), fp); 1386 assert(written == (size_t)Buffer_len(&buf)); 1387 fclose(fp); 1388 return 0; 1389} 1390 1391// End Compile 1392 1393typedef uword (*JitFunction)(uword *heap); 1394 1395// Testing 1396 1397uword Testing_execute_entry(Buffer *buf, uword *heap) { 1398 assert(buf != NULL); 1399 assert(buf->address != NULL); 1400 assert(buf->state == kExecutable); 1401 // The pointer-pointer cast is allowed but the underlying 1402 // data-to-function-pointer back-and-forth is only guaranteed to work on 1403 // POSIX systems (because of eg dlsym). 1404 JitFunction function = *(JitFunction *)(&buf->address); 1405 return function(heap); 1406} 1407 1408uword Testing_execute_expr(Buffer *buf) { 1409 return Testing_execute_entry(buf, /*heap=*/NULL); 1410} 1411 1412TEST Testing_expect_entry_has_contents(Buffer *buf, byte *arr, 1413 size_t arr_size) { 1414 word total_size = sizeof kEntryPrologue + arr_size + sizeof kFunctionEpilogue; 1415 ASSERT_EQ_FMT(total_size, Buffer_len(buf), "%ld"); 1416 1417 byte *ptr = buf->address; 1418 ASSERT_MEM_EQ(kEntryPrologue, ptr, sizeof kEntryPrologue); 1419 ptr += sizeof kEntryPrologue; 1420 ASSERT_MEM_EQ(arr, ptr, arr_size); 1421 ptr += arr_size; 1422 ASSERT_MEM_EQ(kFunctionEpilogue, ptr, sizeof kFunctionEpilogue); 1423 ptr += sizeof kFunctionEpilogue; 1424 PASS(); 1425} 1426 1427WARN_UNUSED int Testing_compile_expr_entry(Buffer *buf, ASTNode *node) { 1428 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 1429 _(Compile_expr(buf, node, /*stack_index=*/-kWordSize, /*varenv=*/NULL, 1430 /*labels=*/NULL)); 1431 Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue); 1432 return 0; 1433} 1434 1435#define EXPECT_EQUALS_BYTES(buf, arr) \ 1436 ASSERT_EQ_FMT(sizeof arr, Buffer_len(buf), "%ld"); \ 1437 ASSERT_MEM_EQ(arr, (buf)->address, sizeof arr) 1438 1439#define EXPECT_ENTRY_CONTAINS_CODE(buf, arr) \ 1440 CHECK_CALL(Testing_expect_entry_has_contents(buf, arr, sizeof arr)) 1441 1442#define RUN_BUFFER_TEST(test_name) \ 1443 do { \ 1444 Buffer buf; \ 1445 Buffer_init(&buf, 1); \ 1446 GREATEST_RUN_TEST1(test_name, &buf); \ 1447 Buffer_deinit(&buf); \ 1448 } while (0) 1449 1450#define RUN_HEAP_TEST(test_name) \ 1451 do { \ 1452 Buffer buf; \ 1453 Buffer_init(&buf, 1); \ 1454 uword *heap = malloc(1000 * kWordSize); \ 1455 GREATEST_RUN_TESTp(test_name, &buf, heap); \ 1456 free(heap); \ 1457 Buffer_deinit(&buf); \ 1458 } while (0) 1459 1460ASTNode *list1(ASTNode *item0) { return AST_new_pair(item0, AST_nil()); } 1461 1462ASTNode *list2(ASTNode *item0, ASTNode *item1) { 1463 return AST_new_pair(item0, list1(item1)); 1464} 1465 1466ASTNode *list3(ASTNode *item0, ASTNode *item1, ASTNode *item2) { 1467 return AST_new_pair(item0, list2(item1, item2)); 1468} 1469 1470ASTNode *new_unary_call(const char *name, ASTNode *arg) { 1471 return list2(AST_new_symbol(name), arg); 1472} 1473 1474ASTNode *new_binary_call(const char *name, ASTNode *arg0, ASTNode *arg1) { 1475 return list3(AST_new_symbol(name), arg0, arg1); 1476} 1477 1478// End Testing 1479 1480// Tests 1481 1482TEST encode_positive_integer(void) { 1483 ASSERT_EQ(Object_encode_integer(0), 0x0); 1484 ASSERT_EQ(Object_encode_integer(1), 0x4); 1485 ASSERT_EQ(Object_encode_integer(10), 0x28); 1486 PASS(); 1487} 1488 1489TEST encode_negative_integer(void) { 1490 ASSERT_EQ(Object_encode_integer(0), 0x0); 1491 ASSERT_EQ(Object_encode_integer(-1), 0xfffffffffffffffc); 1492 ASSERT_EQ(Object_encode_integer(-10), 0xffffffffffffffd8); 1493 PASS(); 1494} 1495 1496TEST encode_char(void) { 1497 ASSERT_EQ(Object_encode_char('\0'), 0xf); 1498 ASSERT_EQ(Object_encode_char('a'), 0x610f); 1499 PASS(); 1500} 1501 1502TEST decode_char(void) { 1503 ASSERT_EQ(Object_decode_char(0xf), '\0'); 1504 ASSERT_EQ(Object_decode_char(0x610f), 'a'); 1505 PASS(); 1506} 1507 1508TEST encode_bool(void) { 1509 ASSERT_EQ(Object_encode_bool(true), 0x9f); 1510 ASSERT_EQ(Object_encode_bool(false), 0x1f); 1511 ASSERT_EQ(Object_true(), 0x9f); 1512 ASSERT_EQ(Object_false(), 0x1f); 1513 PASS(); 1514} 1515 1516TEST decode_bool(void) { 1517 ASSERT_EQ(Object_decode_bool(0x9f), true); 1518 ASSERT_EQ(Object_decode_bool(0x1f), false); 1519 PASS(); 1520} 1521 1522TEST address(void) { 1523 ASSERT_EQ(Object_address((void *)0xFF01), 0xFF00); 1524 PASS(); 1525} 1526 1527TEST emit_mov_reg_imm32_emits_modrm(Buffer *buf) { 1528 Emit_mov_reg_imm32(buf, kRax, 100); 1529 byte expected[] = {0x48, 0xc7, 0xc0, 0x64, 0x00, 0x00, 0x00}; 1530 EXPECT_EQUALS_BYTES(buf, expected); 1531 ASSERT_EQ_FMT(modrm(/*direct*/ 3, kRax, 0), 0xc0, "0x%.2x"); 1532 PASS(); 1533} 1534 1535TEST emit_store_reg_indirect_emits_modrm_sib(Buffer *buf) { 1536 Emit_store_reg_indirect(buf, Ind(kRsp, -8), kRax); 1537 byte expected[] = {0x48, 0x89, 0x44, 0x24, 0xf8}; 1538 EXPECT_EQUALS_BYTES(buf, expected); 1539 ASSERT_EQ_FMT(modrm(/*disp8*/ 1, kIndexNone, kRax), 0x44, "0x%.2x"); 1540 ASSERT_EQ_FMT(sib(kRsp, kIndexNone, Scale1), 0x24, "0x%.2x"); 1541 PASS(); 1542} 1543 1544TEST ast_new_pair(void) { 1545 ASTNode *node = AST_new_pair(NULL, NULL); 1546 ASSERT(AST_is_pair(node)); 1547 AST_heap_free(node); 1548 PASS(); 1549} 1550 1551TEST ast_pair_car_returns_car(void) { 1552 ASTNode *node = AST_new_pair(AST_new_integer(123), NULL); 1553 ASTNode *car = AST_pair_car(node); 1554 ASSERT(AST_is_integer(car)); 1555 ASSERT_EQ(Object_decode_integer((uword)car), 123); 1556 AST_heap_free(node); 1557 PASS(); 1558} 1559 1560TEST ast_pair_cdr_returns_cdr(void) { 1561 ASTNode *node = AST_new_pair(NULL, AST_new_integer(123)); 1562 ASTNode *cdr = AST_pair_cdr(node); 1563 ASSERT(AST_is_integer(cdr)); 1564 ASSERT_EQ(Object_decode_integer((uword)cdr), 123); 1565 AST_heap_free(node); 1566 PASS(); 1567} 1568 1569TEST ast_new_symbol(void) { 1570 const char *value = "my symbol"; 1571 ASTNode *node = AST_new_symbol(value); 1572 ASSERT(AST_is_symbol(node)); 1573 ASSERT_STR_EQ(AST_symbol_cstr(node), value); 1574 AST_heap_free(node); 1575 PASS(); 1576} 1577 1578#define ASSERT_IS_CHAR_EQ(node, c) \ 1579 do { \ 1580 ASTNode *__tmp = node; \ 1581 if (AST_is_error(__tmp)) { \ 1582 fprintf(stderr, "Expected a char but got an error.\n"); \ 1583 } \ 1584 ASSERT(AST_is_char(__tmp)); \ 1585 ASSERT_EQ(AST_get_char(__tmp), c); \ 1586 } while (0); 1587 1588#define ASSERT_IS_INT_EQ(node, val) \ 1589 do { \ 1590 ASTNode *__tmp = node; \ 1591 if (AST_is_error(__tmp)) { \ 1592 fprintf(stderr, "Expected an int but got an error.\n"); \ 1593 } \ 1594 ASSERT(AST_is_integer(__tmp)); \ 1595 ASSERT_EQ(AST_get_integer(__tmp), val); \ 1596 } while (0); 1597 1598#define ASSERT_IS_SYM_EQ(node, cstr) \ 1599 do { \ 1600 ASTNode *__tmp = node; \ 1601 if (AST_is_error(__tmp)) { \ 1602 fprintf(stderr, "Expected a symbol but got an error.\n"); \ 1603 } \ 1604 ASSERT(AST_is_symbol(__tmp)); \ 1605 ASSERT_STR_EQ(AST_symbol_cstr(__tmp), cstr); \ 1606 } while (0); 1607 1608TEST read_with_integer_returns_integer(void) { 1609 char *input = "1234"; 1610 ASTNode *node = Reader_read(input); 1611 ASSERT_IS_INT_EQ(node, 1234); 1612 AST_heap_free(node); 1613 PASS(); 1614} 1615 1616TEST read_with_negative_integer_returns_integer(void) { 1617 char *input = "-1234"; 1618 ASTNode *node = Reader_read(input); 1619 ASSERT_IS_INT_EQ(node, -1234); 1620 AST_heap_free(node); 1621 PASS(); 1622} 1623 1624TEST read_with_positive_integer_returns_integer(void) { 1625 char *input = "+1234"; 1626 ASTNode *node = Reader_read(input); 1627 ASSERT_IS_INT_EQ(node, 1234); 1628 AST_heap_free(node); 1629 PASS(); 1630} 1631 1632TEST read_with_leading_whitespace_ignores_whitespace(void) { 1633 char *input = " \t \n 1234"; 1634 ASTNode *node = Reader_read(input); 1635 ASSERT_IS_INT_EQ(node, 1234); 1636 AST_heap_free(node); 1637 PASS(); 1638} 1639 1640TEST read_with_symbol_returns_symbol(void) { 1641 char *input = "hello?+-*=>"; 1642 ASTNode *node = Reader_read(input); 1643 ASSERT_IS_SYM_EQ(node, "hello?+-*=>"); 1644 AST_heap_free(node); 1645 PASS(); 1646} 1647 1648TEST read_with_symbol_with_trailing_digits(void) { 1649 char *input = "add1 1"; 1650 ASTNode *node = Reader_read(input); 1651 ASSERT_IS_SYM_EQ(node, "add1"); 1652 AST_heap_free(node); 1653 PASS(); 1654} 1655 1656TEST read_with_char_returns_char(void) { 1657 char *input = "'a'"; 1658 ASTNode *node = Reader_read(input); 1659 ASSERT_IS_CHAR_EQ(node, 'a'); 1660 ASSERT(AST_is_error(Reader_read("''"))); 1661 ASSERT(AST_is_error(Reader_read("'aa'"))); 1662 ASSERT(AST_is_error(Reader_read("'aa"))); 1663 AST_heap_free(node); 1664 PASS(); 1665} 1666 1667TEST read_with_bool_returns_bool(void) { 1668 ASSERT_EQ(Reader_read("#t"), AST_new_bool(true)); 1669 ASSERT_EQ(Reader_read("#f"), AST_new_bool(false)); 1670 ASSERT(AST_is_error(Reader_read("#"))); 1671 ASSERT(AST_is_error(Reader_read("#x"))); 1672 ASSERT(AST_is_error(Reader_read("##"))); 1673 PASS(); 1674} 1675 1676TEST read_with_nil_returns_nil(void) { 1677 char *input = "()"; 1678 ASTNode *node = Reader_read(input); 1679 ASSERT(AST_is_nil(node)); 1680 AST_heap_free(node); 1681 PASS(); 1682} 1683 1684TEST read_with_list_returns_list(void) { 1685 char *input = "( 1 2 0 )"; 1686 ASTNode *node = Reader_read(input); 1687 ASSERT(AST_is_pair(node)); 1688 ASSERT_IS_INT_EQ(AST_pair_car(node), 1); 1689 ASSERT_IS_INT_EQ(AST_pair_car(AST_pair_cdr(node)), 2); 1690 ASSERT_IS_INT_EQ(AST_pair_car(AST_pair_cdr(AST_pair_cdr(node))), 0); 1691 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(AST_pair_cdr(node))))); 1692 AST_heap_free(node); 1693 PASS(); 1694} 1695 1696TEST read_with_nested_list_returns_list(void) { 1697 char *input = "((hello world) (foo bar))"; 1698 ASTNode *node = Reader_read(input); 1699 ASSERT(AST_is_pair(node)); 1700 ASTNode *first = AST_pair_car(node); 1701 ASSERT(AST_is_pair(first)); 1702 ASSERT_IS_SYM_EQ(AST_pair_car(first), "hello"); 1703 ASSERT_IS_SYM_EQ(AST_pair_car(AST_pair_cdr(first)), "world"); 1704 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(first)))); 1705 ASTNode *second = AST_pair_car(AST_pair_cdr(node)); 1706 ASSERT(AST_is_pair(second)); 1707 ASSERT_IS_SYM_EQ(AST_pair_car(second), "foo"); 1708 ASSERT_IS_SYM_EQ(AST_pair_car(AST_pair_cdr(second)), "bar"); 1709 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(second)))); 1710 AST_heap_free(node); 1711 PASS(); 1712} 1713 1714TEST buffer_write8_increases_length(Buffer *buf) { 1715 ASSERT_EQ(Buffer_len(buf), 0); 1716 Buffer_write8(buf, 0xdb); 1717 ASSERT_EQ(Buffer_at8(buf, 0), 0xdb); 1718 ASSERT_EQ(Buffer_len(buf), 1); 1719 PASS(); 1720} 1721 1722TEST buffer_write8_expands_buffer(void) { 1723 Buffer buf; 1724 Buffer_init(&buf, 1); 1725 ASSERT_EQ(buf.capacity, 1); 1726 ASSERT_EQ(buf.len, 0); 1727 Buffer_write8(&buf, 0xdb); 1728 Buffer_write8(&buf, 0xef); 1729 ASSERT(buf.capacity > 1); 1730 ASSERT_EQ(buf.len, 2); 1731 Buffer_deinit(&buf); 1732 PASS(); 1733} 1734 1735TEST buffer_write32_expands_buffer(void) { 1736 Buffer buf; 1737 Buffer_init(&buf, 1); 1738 ASSERT_EQ(buf.capacity, 1); 1739 ASSERT_EQ(buf.len, 0); 1740 Buffer_write32(&buf, 0xdeadbeef); 1741 ASSERT(buf.capacity > 1); 1742 ASSERT_EQ(buf.len, 4); 1743 Buffer_deinit(&buf); 1744 PASS(); 1745} 1746 1747TEST buffer_write32_writes_little_endian(Buffer *buf) { 1748 Buffer_write32(buf, 0xdeadbeef); 1749 ASSERT_EQ(Buffer_at8(buf, 0), 0xef); 1750 ASSERT_EQ(Buffer_at8(buf, 1), 0xbe); 1751 ASSERT_EQ(Buffer_at8(buf, 2), 0xad); 1752 ASSERT_EQ(Buffer_at8(buf, 3), 0xde); 1753 PASS(); 1754} 1755 1756TEST compile_positive_integer(Buffer *buf) { 1757 word value = 123; 1758 ASTNode *node = AST_new_integer(value); 1759 int compile_result = Testing_compile_expr_entry(buf, node); 1760 ASSERT_EQ(compile_result, 0); 1761 // mov eax, imm(123) 1762 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00}; 1763 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1764 Buffer_make_executable(buf); 1765 uword result = Testing_execute_expr(buf); 1766 ASSERT_EQ(result, Object_encode_integer(value)); 1767 PASS(); 1768} 1769 1770TEST compile_negative_integer(Buffer *buf) { 1771 word value = -123; 1772 ASTNode *node = AST_new_integer(value); 1773 int compile_result = Testing_compile_expr_entry(buf, node); 1774 ASSERT_EQ(compile_result, 0); 1775 // mov eax, imm(-123) 1776 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0xfe, 0xff, 0xff}; 1777 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1778 Buffer_make_executable(buf); 1779 uword result = Testing_execute_expr(buf); 1780 ASSERT_EQ(result, Object_encode_integer(value)); 1781 PASS(); 1782} 1783 1784TEST compile_char(Buffer *buf) { 1785 char value = 'a'; 1786 ASTNode *node = AST_new_char(value); 1787 int compile_result = Testing_compile_expr_entry(buf, node); 1788 ASSERT_EQ(compile_result, 0); 1789 // mov eax, imm('a') 1790 byte expected[] = {0x48, 0xc7, 0xc0, 0x0f, 0x61, 0x00, 0x00}; 1791 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1792 Buffer_make_executable(buf); 1793 uword result = Testing_execute_expr(buf); 1794 ASSERT_EQ(result, Object_encode_char(value)); 1795 PASS(); 1796} 1797 1798TEST compile_true(Buffer *buf) { 1799 ASTNode *node = AST_new_bool(true); 1800 int compile_result = Testing_compile_expr_entry(buf, node); 1801 ASSERT_EQ(compile_result, 0); 1802 // mov eax, imm(true) 1803 byte expected[] = {0x48, 0xc7, 0xc0, 0x9f, 0x0, 0x0, 0x0}; 1804 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1805 Buffer_make_executable(buf); 1806 uword result = Testing_execute_expr(buf); 1807 ASSERT_EQ(result, Object_true()); 1808 PASS(); 1809} 1810 1811TEST compile_false(Buffer *buf) { 1812 ASTNode *node = AST_new_bool(false); 1813 int compile_result = Testing_compile_expr_entry(buf, node); 1814 ASSERT_EQ(compile_result, 0); 1815 // mov eax, imm(false) 1816 byte expected[] = {0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00}; 1817 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1818 Buffer_make_executable(buf); 1819 uword result = Testing_execute_expr(buf); 1820 ASSERT_EQ(result, Object_false()); 1821 PASS(); 1822} 1823 1824TEST compile_nil(Buffer *buf) { 1825 ASTNode *node = AST_nil(); 1826 int compile_result = Testing_compile_expr_entry(buf, node); 1827 ASSERT_EQ(compile_result, 0); 1828 // mov eax, imm(nil) 1829 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00}; 1830 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1831 Buffer_make_executable(buf); 1832 uword result = Testing_execute_expr(buf); 1833 ASSERT_EQ(result, Object_nil()); 1834 PASS(); 1835} 1836 1837TEST compile_unary_add1(Buffer *buf) { 1838 ASTNode *node = new_unary_call("add1", AST_new_integer(123)); 1839 int compile_result = Testing_compile_expr_entry(buf, node); 1840 ASSERT_EQ(compile_result, 0); 1841 // mov rax, imm(123); add rax, imm(1) 1842 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 1843 0x48, 0x05, 0x04, 0x00, 0x00, 0x00}; 1844 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1845 Buffer_make_executable(buf); 1846 uword result = Testing_execute_expr(buf); 1847 ASSERT_EQ(result, Object_encode_integer(124)); 1848 AST_heap_free(node); 1849 PASS(); 1850} 1851 1852TEST compile_unary_add1_nested(Buffer *buf) { 1853 ASTNode *node = 1854 new_unary_call("add1", new_unary_call("add1", AST_new_integer(123))); 1855 int compile_result = Testing_compile_expr_entry(buf, node); 1856 ASSERT_EQ(compile_result, 0); 1857 // mov rax, imm(123); add rax, imm(1); add rax, imm(1) 1858 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 0x48, 0x05, 0x04, 1859 0x00, 0x00, 0x00, 0x48, 0x05, 0x04, 0x00, 0x00, 0x00}; 1860 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1861 Buffer_make_executable(buf); 1862 uword result = Testing_execute_expr(buf); 1863 ASSERT_EQ(result, Object_encode_integer(125)); 1864 AST_heap_free(node); 1865 PASS(); 1866} 1867 1868TEST compile_unary_sub1(Buffer *buf) { 1869 ASTNode *node = new_unary_call("sub1", AST_new_integer(123)); 1870 int compile_result = Testing_compile_expr_entry(buf, node); 1871 ASSERT_EQ(compile_result, 0); 1872 // mov rax, imm(123); sub rax, imm(1) 1873 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 1874 0x48, 0x2d, 0x04, 0x00, 0x00, 0x00}; 1875 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1876 Buffer_make_executable(buf); 1877 uword result = Testing_execute_expr(buf); 1878 ASSERT_EQ(result, Object_encode_integer(122)); 1879 AST_heap_free(node); 1880 PASS(); 1881} 1882 1883TEST compile_unary_integer_to_char(Buffer *buf) { 1884 ASTNode *node = new_unary_call("integer->char", AST_new_integer(97)); 1885 int compile_result = Testing_compile_expr_entry(buf, node); 1886 ASSERT_EQ(compile_result, 0); 1887 // mov rax, imm(97); shl rax, 6; or rax, 0xf 1888 byte expected[] = {0x48, 0xc7, 0xc0, 0x84, 0x01, 0x00, 0x00, 0x48, 1889 0xc1, 0xe0, 0x06, 0x48, 0x83, 0xc8, 0x0f}; 1890 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1891 Buffer_make_executable(buf); 1892 uword result = Testing_execute_expr(buf); 1893 ASSERT_EQ(result, Object_encode_char('a')); 1894 AST_heap_free(node); 1895 PASS(); 1896} 1897 1898TEST compile_unary_char_to_integer(Buffer *buf) { 1899 ASTNode *node = new_unary_call("char->integer", AST_new_char('a')); 1900 int compile_result = Testing_compile_expr_entry(buf, node); 1901 ASSERT_EQ(compile_result, 0); 1902 // mov rax, imm('a'); shr rax, 6 1903 byte expected[] = {0x48, 0xc7, 0xc0, 0x0f, 0x61, 0x00, 1904 0x00, 0x48, 0xc1, 0xe8, 0x06}; 1905 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1906 Buffer_make_executable(buf); 1907 uword result = Testing_execute_expr(buf); 1908 ASSERT_EQ(result, Object_encode_integer(97)); 1909 AST_heap_free(node); 1910 PASS(); 1911} 1912 1913TEST compile_unary_nilp_with_nil_returns_true(Buffer *buf) { 1914 ASTNode *node = new_unary_call("nil?", AST_nil()); 1915 int compile_result = Testing_compile_expr_entry(buf, node); 1916 ASSERT_EQ(compile_result, 0); 1917 // 0: 48 c7 c0 2f 00 00 00 mov rax,0x2f 1918 // 7: 48 3d 2f 00 00 00 cmp rax,0x0000002f 1919 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 1920 // 14: 0f 94 c0 sete al 1921 // 17: 48 c1 e0 07 shl rax,0x7 1922 // 1b: 48 83 c8 1f or rax,0x1f 1923 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00, 0x48, 1924 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 1925 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 1926 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 1927 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1928 Buffer_make_executable(buf); 1929 uword result = Testing_execute_expr(buf); 1930 ASSERT_EQ(result, Object_true()); 1931 AST_heap_free(node); 1932 PASS(); 1933} 1934 1935TEST compile_unary_nilp_with_non_nil_returns_false(Buffer *buf) { 1936 ASTNode *node = new_unary_call("nil?", AST_new_integer(5)); 1937 int compile_result = Testing_compile_expr_entry(buf, node); 1938 ASSERT_EQ(compile_result, 0); 1939 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 1940 // 7: 48 3d 2f 00 00 00 cmp rax,0x0000002f 1941 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 1942 // 14: 0f 94 c0 sete al 1943 // 17: 48 c1 e0 07 shl rax,0x7 1944 // 1b: 48 83 c8 1f or rax,0x1f 1945 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 1946 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 1947 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 1948 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 1949 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1950 Buffer_make_executable(buf); 1951 uword result = Testing_execute_expr(buf); 1952 ASSERT_EQ(result, Object_false()); 1953 AST_heap_free(node); 1954 PASS(); 1955} 1956 1957TEST compile_unary_zerop_with_zero_returns_true(Buffer *buf) { 1958 ASTNode *node = new_unary_call("zero?", AST_new_integer(0)); 1959 int compile_result = Testing_compile_expr_entry(buf, node); 1960 ASSERT_EQ(compile_result, 0); 1961 // 0: 48 c7 c0 00 00 00 00 mov rax,0x0 1962 // 7: 48 3d 00 00 00 00 cmp rax,0x00000000 1963 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 1964 // 14: 0f 94 c0 sete al 1965 // 17: 48 c1 e0 07 shl rax,0x7 1966 // 1b: 48 83 c8 1f or rax,0x1f 1967 byte expected[] = {0x48, 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x48, 1968 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 1969 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 1970 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 1971 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1972 Buffer_make_executable(buf); 1973 uword result = Testing_execute_expr(buf); 1974 ASSERT_EQ(result, Object_true()); 1975 AST_heap_free(node); 1976 PASS(); 1977} 1978 1979TEST compile_unary_zerop_with_non_zero_returns_false(Buffer *buf) { 1980 ASTNode *node = new_unary_call("zero?", AST_new_integer(5)); 1981 int compile_result = Testing_compile_expr_entry(buf, node); 1982 ASSERT_EQ(compile_result, 0); 1983 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 1984 // 7: 48 3d 00 00 00 00 cmp rax,0x00000000 1985 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 1986 // 14: 0f 94 c0 sete al 1987 // 17: 48 c1 e0 07 shl rax,0x7 1988 // 1b: 48 83 c8 1f or rax,0x1f 1989 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 1990 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 1991 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 1992 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 1993 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1994 Buffer_make_executable(buf); 1995 uword result = Testing_execute_expr(buf); 1996 ASSERT_EQ(result, Object_false()); 1997 AST_heap_free(node); 1998 PASS(); 1999} 2000 2001TEST compile_unary_not_with_false_returns_true(Buffer *buf) { 2002 ASTNode *node = new_unary_call("not", AST_new_bool(false)); 2003 int compile_result = Testing_compile_expr_entry(buf, node); 2004 ASSERT_EQ(compile_result, 0); 2005 // 0: 48 c7 c0 1f 00 00 00 mov rax,0x1f 2006 // 7: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2007 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2008 // 14: 0f 94 c0 sete al 2009 // 17: 48 c1 e0 07 shl rax,0x7 2010 // 1b: 48 83 c8 1f or rax,0x1f 2011 byte expected[] = {0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x48, 2012 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2013 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2014 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2015 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2016 Buffer_make_executable(buf); 2017 uword result = Testing_execute_expr(buf); 2018 ASSERT_EQ(result, Object_true()); 2019 AST_heap_free(node); 2020 PASS(); 2021} 2022 2023TEST compile_unary_not_with_non_false_returns_false(Buffer *buf) { 2024 ASTNode *node = new_unary_call("not", AST_new_integer(5)); 2025 int compile_result = Testing_compile_expr_entry(buf, node); 2026 ASSERT_EQ(compile_result, 0); 2027 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2028 // 7: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2029 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2030 // 14: 0f 94 c0 sete al 2031 // 17: 48 c1 e0 07 shl rax,0x7 2032 // 1b: 48 83 c8 1f or rax,0x1f 2033 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 2034 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2035 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2036 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2037 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2038 Buffer_make_executable(buf); 2039 uword result = Testing_execute_expr(buf); 2040 ASSERT_EQ(result, Object_false()); 2041 AST_heap_free(node); 2042 PASS(); 2043} 2044 2045TEST compile_unary_integerp_with_integer_returns_true(Buffer *buf) { 2046 ASTNode *node = new_unary_call("integer?", AST_new_integer(5)); 2047 int compile_result = Testing_compile_expr_entry(buf, node); 2048 ASSERT_EQ(compile_result, 0); 2049 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2050 // 7: 48 83 e0 03 and rax,0x3 2051 // b: 48 3d 00 00 00 00 cmp rax,0x00000000 2052 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2053 // 18: 0f 94 c0 sete al 2054 // 1b: 48 c1 e0 07 shl rax,0x7 2055 // 1f: 48 83 c8 1f or rax,0x1f 2056 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 0x83, 2057 0xe0, 0x03, 0x48, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 2058 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2059 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2060 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2061 Buffer_make_executable(buf); 2062 uword result = Testing_execute_expr(buf); 2063 ASSERT_EQ(result, Object_true()); 2064 AST_heap_free(node); 2065 PASS(); 2066} 2067 2068TEST compile_unary_integerp_with_non_integer_returns_false(Buffer *buf) { 2069 ASTNode *node = new_unary_call("integer?", AST_nil()); 2070 int compile_result = Testing_compile_expr_entry(buf, node); 2071 ASSERT_EQ(compile_result, 0); 2072 // 0: 48 c7 c0 2f 00 00 00 mov rax,0x2f 2073 // 7: 48 83 e0 03 and rax,0x3 2074 // b: 48 3d 00 00 00 00 cmp rax,0x00000000 2075 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2076 // 18: 0f 94 c0 sete al 2077 // 1b: 48 c1 e0 07 shl rax,0x7 2078 // 1f: 48 83 c8 1f or rax,0x1f 2079 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00, 0x48, 0x83, 2080 0xe0, 0x03, 0x48, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 2081 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2082 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2083 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2084 Buffer_make_executable(buf); 2085 uword result = Testing_execute_expr(buf); 2086 ASSERT_EQ(result, Object_false()); 2087 AST_heap_free(node); 2088 PASS(); 2089} 2090 2091TEST compile_unary_booleanp_with_boolean_returns_true(Buffer *buf) { 2092 ASTNode *node = new_unary_call("boolean?", AST_new_bool(true)); 2093 int compile_result = Testing_compile_expr_entry(buf, node); 2094 ASSERT_EQ(compile_result, 0); 2095 // 0: 48 c7 c0 9f 00 00 00 mov rax,0x9f 2096 // 7: 48 83 e0 3f and rax,0x3f 2097 // b: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2098 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2099 // 18: 0f 94 c0 sete al 2100 // 1b: 48 c1 e0 07 shl rax,0x7 2101 // 1f: 48 83 c8 1f or rax,0x1f 2102 byte expected[] = {0x48, 0xc7, 0xc0, 0x9f, 0x00, 0x00, 0x00, 0x48, 0x83, 2103 0xe0, 0x3f, 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 2104 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2105 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2106 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2107 Buffer_make_executable(buf); 2108 uword result = Testing_execute_expr(buf); 2109 ASSERT_EQ(result, Object_true()); 2110 AST_heap_free(node); 2111 PASS(); 2112} 2113 2114TEST compile_unary_booleanp_with_non_boolean_returns_false(Buffer *buf) { 2115 ASTNode *node = new_unary_call("boolean?", AST_new_integer(5)); 2116 int compile_result = Testing_compile_expr_entry(buf, node); 2117 ASSERT_EQ(compile_result, 0); 2118 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2119 // 7: 48 83 e0 3f and rax,0x3f 2120 // b: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2121 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2122 // 18: 0f 94 c0 sete al 2123 // 1b: 48 c1 e0 07 shl rax,0x7 2124 // 1f: 48 83 c8 1f or rax,0x1f 2125 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 0x83, 2126 0xe0, 0x3f, 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 2127 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2128 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2129 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2130 Buffer_make_executable(buf); 2131 uword result = Testing_execute_expr(buf); 2132 ASSERT_EQ(result, Object_false()); 2133 AST_heap_free(node); 2134 PASS(); 2135} 2136 2137TEST compile_binary_plus(Buffer *buf) { 2138 ASTNode *node = new_binary_call("+", AST_new_integer(5), AST_new_integer(8)); 2139 int compile_result = Testing_compile_expr_entry(buf, node); 2140 ASSERT_EQ(compile_result, 0); 2141 byte expected[] = { 2142 // 0: 48 c7 c0 20 00 00 00 mov rax,0x20 2143 0x48, 0xc7, 0xc0, 0x20, 0x00, 0x00, 0x00, 2144 // 7: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2145 0x48, 0x89, 0x44, 0x24, 0xf8, 2146 // b: 48 c7 c0 14 00 00 00 mov rax,0x14 2147 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2148 // 12: 48 03 45 f8 add rax,QWORD PTR [rsp-0x8] 2149 0x48, 0x03, 0x44, 0x24, 0xf8}; 2150 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2151 Buffer_make_executable(buf); 2152 uword result = Testing_execute_expr(buf); 2153 ASSERT_EQ(result, Object_encode_integer(13)); 2154 AST_heap_free(node); 2155 PASS(); 2156} 2157 2158TEST compile_binary_plus_nested(Buffer *buf) { 2159 ASTNode *node = new_binary_call( 2160 "+", new_binary_call("+", AST_new_integer(1), AST_new_integer(2)), 2161 new_binary_call("+", AST_new_integer(3), AST_new_integer(4))); 2162 int compile_result = Testing_compile_expr_entry(buf, node); 2163 ASSERT_EQ(compile_result, 0); 2164 byte expected[] = { 2165 // 4: 48 c7 c0 10 00 00 00 mov rax,0x10 2166 0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00, 2167 // b: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2168 0x48, 0x89, 0x44, 0x24, 0xf8, 2169 // f: 48 c7 c0 0c 00 00 00 mov rax,0xc 2170 0x48, 0xc7, 0xc0, 0x0c, 0x00, 0x00, 0x00, 2171 // 16: 48 03 45 f8 add rax,QWORD PTR [rsp-0x8] 2172 0x48, 0x03, 0x44, 0x24, 0xf8, 2173 // 1a: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2174 0x48, 0x89, 0x44, 0x24, 0xf8, 2175 // 1e: 48 c7 c0 08 00 00 00 mov rax,0x8 2176 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2177 // 25: 48 89 45 f0 mov QWORD PTR [rsp-0x10],rax 2178 0x48, 0x89, 0x44, 0x24, 0xf0, 2179 // 29: 48 c7 c0 04 00 00 00 mov rax,0x4 2180 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2181 // 30: 48 03 45 f0 add rax,QWORD PTR [rsp-0x10] 2182 0x48, 0x03, 0x44, 0x24, 0xf0, 2183 // 34: 48 03 45 f8 add rax,QWORD PTR [rsp-0x8] 2184 0x48, 0x03, 0x44, 0x24, 0xf8}; 2185 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2186 Buffer_make_executable(buf); 2187 uword result = Testing_execute_expr(buf); 2188 ASSERT_EQ(result, Object_encode_integer(10)); 2189 AST_heap_free(node); 2190 PASS(); 2191} 2192 2193TEST compile_binary_minus(Buffer *buf) { 2194 ASTNode *node = new_binary_call("-", AST_new_integer(5), AST_new_integer(8)); 2195 int compile_result = Testing_compile_expr_entry(buf, node); 2196 ASSERT_EQ(compile_result, 0); 2197 byte expected[] = { 2198 // 0: 48 c7 c0 20 00 00 00 mov rax,0x20 2199 0x48, 0xc7, 0xc0, 0x20, 0x00, 0x00, 0x00, 2200 // 7: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2201 0x48, 0x89, 0x44, 0x24, 0xf8, 2202 // b: 48 c7 c0 14 00 00 00 mov rax,0x14 2203 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2204 // 12: 48 2b 45 f8 add rax,QWORD PTR [rsp-0x8] 2205 0x48, 0x2b, 0x44, 0x24, 0xf8}; 2206 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2207 Buffer_make_executable(buf); 2208 uword result = Testing_execute_expr(buf); 2209 ASSERT_EQ(result, Object_encode_integer(-3)); 2210 AST_heap_free(node); 2211 PASS(); 2212} 2213 2214TEST compile_binary_minus_nested(Buffer *buf) { 2215 ASTNode *node = new_binary_call( 2216 "-", new_binary_call("-", AST_new_integer(5), AST_new_integer(1)), 2217 new_binary_call("-", AST_new_integer(4), AST_new_integer(3))); 2218 int compile_result = Testing_compile_expr_entry(buf, node); 2219 ASSERT_EQ(compile_result, 0); 2220 byte expected[] = { 2221 // 4: 48 c7 c0 0c 00 00 00 mov rax,0xc 2222 0x48, 0xc7, 0xc0, 0x0c, 0x00, 0x00, 0x00, 2223 // b: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2224 0x48, 0x89, 0x44, 0x24, 0xf8, 2225 // f: 48 c7 c0 10 00 00 00 mov rax,0x10 2226 0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00, 2227 // 16: 48 2b 45 f8 add rax,QWORD PTR [rsp-0x8] 2228 0x48, 0x2b, 0x44, 0x24, 0xf8, 2229 // 1a: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2230 0x48, 0x89, 0x44, 0x24, 0xf8, 2231 // 1e: 48 c7 c0 04 00 00 00 mov rax,0x4 2232 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2233 // 25: 48 89 45 f0 mov QWORD PTR [rsp-0x10],rax 2234 0x48, 0x89, 0x44, 0x24, 0xf0, 2235 // 29: 48 c7 c0 14 00 00 00 mov rax,0x14 2236 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2237 // 30: 48 2b 45 f0 add rax,QWORD PTR [rsp-0x10] 2238 0x48, 0x2b, 0x44, 0x24, 0xf0, 2239 // 34: 48 2b 45 f8 add rax,QWORD PTR [rsp-0x8] 2240 0x48, 0x2b, 0x44, 0x24, 0xf8}; 2241 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2242 Buffer_make_executable(buf); 2243 uword result = Testing_execute_expr(buf); 2244 ASSERT_EQ(result, Object_encode_integer(3)); 2245 AST_heap_free(node); 2246 PASS(); 2247} 2248 2249TEST compile_binary_mul(Buffer *buf) { 2250 ASTNode *node = new_binary_call("*", AST_new_integer(5), AST_new_integer(8)); 2251 int compile_result = Testing_compile_expr_entry(buf, node); 2252 ASSERT_EQ(compile_result, 0); 2253 Buffer_make_executable(buf); 2254 uword result = Testing_execute_expr(buf); 2255 ASSERT_EQ_FMT(Object_encode_integer(40), result, "0x%lx"); 2256 AST_heap_free(node); 2257 PASS(); 2258} 2259 2260TEST compile_binary_mul_nested(Buffer *buf) { 2261 ASTNode *node = new_binary_call( 2262 "*", new_binary_call("*", AST_new_integer(1), AST_new_integer(2)), 2263 new_binary_call("*", AST_new_integer(3), AST_new_integer(4))); 2264 int compile_result = Testing_compile_expr_entry(buf, node); 2265 ASSERT_EQ(compile_result, 0); 2266 Buffer_make_executable(buf); 2267 uword result = Testing_execute_expr(buf); 2268 ASSERT_EQ_FMT(Object_encode_integer(24), result, "0x%lx"); 2269 AST_heap_free(node); 2270 PASS(); 2271} 2272 2273TEST compile_binary_eq_with_same_address_returns_true(Buffer *buf) { 2274 ASTNode *node = new_binary_call("=", AST_new_integer(5), AST_new_integer(5)); 2275 int compile_result = Testing_compile_expr_entry(buf, node); 2276 ASSERT_EQ(compile_result, 0); 2277 Buffer_make_executable(buf); 2278 uword result = Testing_execute_expr(buf); 2279 ASSERT_EQ_FMT(Object_true(), result, "0x%lx"); 2280 AST_heap_free(node); 2281 PASS(); 2282} 2283 2284TEST compile_binary_eq_with_different_address_returns_false(Buffer *buf) { 2285 ASTNode *node = new_binary_call("=", AST_new_integer(5), AST_new_integer(4)); 2286 int compile_result = Testing_compile_expr_entry(buf, node); 2287 ASSERT_EQ(compile_result, 0); 2288 Buffer_make_executable(buf); 2289 uword result = Testing_execute_expr(buf); 2290 ASSERT_EQ_FMT(Object_false(), result, "0x%lx"); 2291 AST_heap_free(node); 2292 PASS(); 2293} 2294 2295TEST compile_binary_lt_with_left_less_than_right_returns_true(Buffer *buf) { 2296 ASTNode *node = new_binary_call("<", AST_new_integer(-5), AST_new_integer(5)); 2297 int compile_result = Testing_compile_expr_entry(buf, node); 2298 ASSERT_EQ(compile_result, 0); 2299 Buffer_make_executable(buf); 2300 uword result = Testing_execute_expr(buf); 2301 ASSERT_EQ_FMT(Object_true(), result, "0x%lx"); 2302 AST_heap_free(node); 2303 PASS(); 2304} 2305 2306TEST compile_binary_lt_with_left_equal_to_right_returns_false(Buffer *buf) { 2307 ASTNode *node = new_binary_call("<", AST_new_integer(5), AST_new_integer(5)); 2308 int compile_result = Testing_compile_expr_entry(buf, node); 2309 ASSERT_EQ(compile_result, 0); 2310 Buffer_make_executable(buf); 2311 uword result = Testing_execute_expr(buf); 2312 ASSERT_EQ_FMT(Object_false(), result, "0x%lx"); 2313 AST_heap_free(node); 2314 PASS(); 2315} 2316 2317TEST compile_binary_lt_with_left_greater_than_right_returns_false(Buffer *buf) { 2318 ASTNode *node = new_binary_call("<", AST_new_integer(6), AST_new_integer(5)); 2319 int compile_result = Testing_compile_expr_entry(buf, node); 2320 ASSERT_EQ(compile_result, 0); 2321 Buffer_make_executable(buf); 2322 uword result = Testing_execute_expr(buf); 2323 ASSERT_EQ_FMT(Object_false(), result, "0x%lx"); 2324 AST_heap_free(node); 2325 PASS(); 2326} 2327 2328TEST compile_symbol_in_env_returns_value(Buffer *buf) { 2329 ASTNode *node = AST_new_symbol("hello"); 2330 Env env0 = Env_bind("hello", 33, /*prev=*/NULL); 2331 Env env1 = Env_bind("world", 66, &env0); 2332 int compile_result = 2333 Compile_expr(buf, node, -kWordSize, &env1, /*labels=*/NULL); 2334 ASSERT_EQ(compile_result, 0); 2335 byte expected[] = {// mov rax, [rsp+33] 2336 0x48, 0x8b, 0x44, 0x24, 33}; 2337 EXPECT_EQUALS_BYTES(buf, expected); 2338 AST_heap_free(node); 2339 PASS(); 2340} 2341 2342TEST compile_symbol_in_env_returns_first_value(Buffer *buf) { 2343 ASTNode *node = AST_new_symbol("hello"); 2344 Env env0 = Env_bind("hello", 55, /*prev=*/NULL); 2345 Env env1 = Env_bind("hello", 66, &env0); 2346 int compile_result = 2347 Compile_expr(buf, node, -kWordSize, &env1, /*labels=*/NULL); 2348 ASSERT_EQ(compile_result, 0); 2349 byte expected[] = {// mov rax, [rsp+66] 2350 0x48, 0x8b, 0x44, 0x24, 66}; 2351 EXPECT_EQUALS_BYTES(buf, expected); 2352 AST_heap_free(node); 2353 PASS(); 2354} 2355 2356TEST compile_symbol_not_in_env_raises_compile_error(Buffer *buf) { 2357 ASTNode *node = AST_new_symbol("hello"); 2358 int compile_result = 2359 Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL, /*labels=*/NULL); 2360 ASSERT_EQ(compile_result, -1); 2361 AST_heap_free(node); 2362 PASS(); 2363} 2364 2365TEST compile_let_with_no_bindings(Buffer *buf) { 2366 ASTNode *node = Reader_read("(let () (+ 1 2))"); 2367 int compile_result = Testing_compile_expr_entry(buf, node); 2368 ASSERT_EQ(compile_result, 0); 2369 Buffer_make_executable(buf); 2370 uword result = Testing_execute_expr(buf); 2371 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2372 AST_heap_free(node); 2373 PASS(); 2374} 2375 2376TEST compile_let_with_one_binding(Buffer *buf) { 2377 ASTNode *node = Reader_read("(let ((a 1)) (+ a 2))"); 2378 int compile_result = Testing_compile_expr_entry(buf, node); 2379 ASSERT_EQ(compile_result, 0); 2380 Buffer_make_executable(buf); 2381 uword result = Testing_execute_expr(buf); 2382 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2383 AST_heap_free(node); 2384 PASS(); 2385} 2386 2387TEST compile_let_with_multiple_bindings(Buffer *buf) { 2388 ASTNode *node = Reader_read("(let ((a 1) (b 2)) (+ a b))"); 2389 int compile_result = Testing_compile_expr_entry(buf, node); 2390 ASSERT_EQ(compile_result, 0); 2391 Buffer_make_executable(buf); 2392 uword result = Testing_execute_expr(buf); 2393 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2394 AST_heap_free(node); 2395 PASS(); 2396} 2397 2398TEST compile_nested_let(Buffer *buf) { 2399 ASTNode *node = Reader_read("(let ((a 1)) (let ((b 2)) (+ a b)))"); 2400 int compile_result = Testing_compile_expr_entry(buf, node); 2401 ASSERT_EQ(compile_result, 0); 2402 Buffer_make_executable(buf); 2403 uword result = Testing_execute_expr(buf); 2404 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2405 AST_heap_free(node); 2406 PASS(); 2407} 2408 2409TEST compile_let_is_not_let_star(Buffer *buf) { 2410 ASTNode *node = Reader_read("(let ((a 1) (b a)) a)"); 2411 int compile_result = Testing_compile_expr_entry(buf, node); 2412 ASSERT_EQ(compile_result, -1); 2413 AST_heap_free(node); 2414 PASS(); 2415} 2416 2417TEST compile_if_with_true_cond(Buffer *buf) { 2418 ASTNode *node = Reader_read("(if #t 1 2)"); 2419 int compile_result = Testing_compile_expr_entry(buf, node); 2420 ASSERT_EQ(compile_result, 0); 2421 byte expected[] = { 2422 // mov rax, 0x9f 2423 0x48, 0xc7, 0xc0, 0x9f, 0x00, 0x00, 0x00, 2424 // cmp rax, 0x1f 2425 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 2426 // je alternate 2427 0x0f, 0x84, 0x0c, 0x00, 0x00, 0x00, 2428 // mov rax, compile(1) 2429 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2430 // jmp end 2431 0xe9, 0x07, 0x00, 0x00, 0x00, 2432 // alternate: 2433 // mov rax, compile(2) 2434 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00 2435 // end: 2436 }; 2437 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2438 Buffer_make_executable(buf); 2439 uword result = Testing_execute_expr(buf); 2440 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2441 AST_heap_free(node); 2442 PASS(); 2443} 2444 2445TEST compile_if_with_false_cond(Buffer *buf) { 2446 ASTNode *node = Reader_read("(if #f 1 2)"); 2447 int compile_result = Testing_compile_expr_entry(buf, node); 2448 ASSERT_EQ(compile_result, 0); 2449 byte expected[] = { 2450 // mov rax, 0x1f 2451 0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00, 2452 // cmp rax, 0x1f 2453 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 2454 // je alternate 2455 0x0f, 0x84, 0x0c, 0x00, 0x00, 0x00, 2456 // mov rax, compile(1) 2457 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2458 // jmp end 2459 0xe9, 0x07, 0x00, 0x00, 0x00, 2460 // alternate: 2461 // mov rax, compile(2) 2462 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00 2463 // end: 2464 }; 2465 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2466 Buffer_make_executable(buf); 2467 uword result = Testing_execute_expr(buf); 2468 ASSERT_EQ_FMT(Object_encode_integer(2), result, "0x%lx"); 2469 AST_heap_free(node); 2470 PASS(); 2471} 2472 2473TEST compile_nested_if(Buffer *buf) { 2474 ASTNode *node = Reader_read("(if (< 1 2) (if #f 3 4) 5)"); 2475 int compile_result = Testing_compile_expr_entry(buf, node); 2476 ASSERT_EQ(compile_result, 0); 2477 Buffer_make_executable(buf); 2478 uword result = Testing_execute_expr(buf); 2479 ASSERT_EQ_FMT(Object_encode_integer(4), result, "0x%lx"); 2480 AST_heap_free(node); 2481 PASS(); 2482} 2483 2484TEST compile_cons(Buffer *buf, uword *heap) { 2485 ASTNode *node = Reader_read("(cons 1 2)"); 2486 int compile_result = Testing_compile_expr_entry(buf, node); 2487 ASSERT_EQ(compile_result, 0); 2488 // clang-format off 2489 byte expected[] = { 2490 // mov rax, 0x2 2491 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2492 // mov [rsp-8], rax 2493 0x48, 0x89, 0x44, 0x24, 0xf8, 2494 // mov rax, 0x4 2495 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2496 // mov [rsi+Cdr], rax 2497 0x48, 0x89, 0x46, 0x08, 2498 // mov rax, [rsp-8] 2499 0x48, 0x8b, 0x44, 0x24, 0xf8, 2500 // mov [rsi+Car], rax 2501 0x48, 0x89, 0x46, 0x00, 2502 // mov rax, rsi 2503 0x48, 0x89, 0xf0, 2504 // or rax, kPairTag 2505 0x48, 0x83, 0xc8, 0x01, 2506 // add rsi, 2*kWordSize 2507 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 2508 }; 2509 // clang-format on 2510 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2511 Buffer_make_executable(buf); 2512 uword result = Testing_execute_entry(buf, heap); 2513 ASSERT(Object_is_pair(result)); 2514 ASSERT_EQ_FMT(Object_encode_integer(1), Object_pair_car(result), "0x%lx"); 2515 ASSERT_EQ_FMT(Object_encode_integer(2), Object_pair_cdr(result), "0x%lx"); 2516 AST_heap_free(node); 2517 PASS(); 2518} 2519 2520TEST compile_two_cons(Buffer *buf, uword *heap) { 2521 ASTNode *node = Reader_read( 2522 "(let ((a (cons 1 2)) (b (cons 3 4))) (cons (cdr a) (cdr b)))"); 2523 int compile_result = Testing_compile_expr_entry(buf, node); 2524 ASSERT_EQ(compile_result, 0); 2525 Buffer_make_executable(buf); 2526 uword result = Testing_execute_entry(buf, heap); 2527 ASSERT(Object_is_pair(result)); 2528 ASSERT_EQ_FMT(Object_encode_integer(2), Object_pair_car(result), "0x%lx"); 2529 ASSERT_EQ_FMT(Object_encode_integer(4), Object_pair_cdr(result), "0x%lx"); 2530 AST_heap_free(node); 2531 PASS(); 2532} 2533 2534TEST compile_nested_cons(Buffer *buf, uword *heap) { 2535 ASTNode *node = Reader_read("(cons (cons 1 2) (cons 3 4))"); 2536 int compile_result = Testing_compile_expr_entry(buf, node); 2537 ASSERT_EQ(compile_result, 0); 2538 Buffer_make_executable(buf); 2539 uword result = Testing_execute_entry(buf, heap); 2540 ASSERT(Object_is_pair(result)); 2541 ASSERT(Object_is_pair(Object_pair_car(result))); 2542 ASSERT_EQ_FMT(Object_encode_integer(1), 2543 Object_pair_car(Object_pair_car(result)), "0x%lx"); 2544 ASSERT_EQ_FMT(Object_encode_integer(2), 2545 Object_pair_cdr(Object_pair_car(result)), "0x%lx"); 2546 ASSERT(Object_is_pair(Object_pair_cdr(result))); 2547 ASSERT_EQ_FMT(Object_encode_integer(3), 2548 Object_pair_car(Object_pair_cdr(result)), "0x%lx"); 2549 ASSERT_EQ_FMT(Object_encode_integer(4), 2550 Object_pair_cdr(Object_pair_cdr(result)), "0x%lx"); 2551 AST_heap_free(node); 2552 PASS(); 2553} 2554 2555TEST compile_car(Buffer *buf, uword *heap) { 2556 ASTNode *node = Reader_read("(car (cons 1 2))"); 2557 int compile_result = Testing_compile_expr_entry(buf, node); 2558 ASSERT_EQ(compile_result, 0); 2559 // clang-format off 2560 byte expected[] = { 2561 // mov rax, 0x2 2562 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2563 // mov [rsp-8], rax 2564 0x48, 0x89, 0x44, 0x24, 0xf8, 2565 // mov rax, 0x4 2566 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2567 // mov [rsi+Cdr], rax 2568 0x48, 0x89, 0x46, 0x08, 2569 // mov rax, [rsp-8] 2570 0x48, 0x8b, 0x44, 0x24, 0xf8, 2571 // mov [rsi+Car], rax 2572 0x48, 0x89, 0x46, 0x00, 2573 // mov rax, rsi 2574 0x48, 0x89, 0xf0, 2575 // or rax, kPairTag 2576 0x48, 0x83, 0xc8, 0x01, 2577 // add rsi, 2*kWordSize 2578 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 2579 // mov rax, [rax-1] 2580 0x48, 0x8b, 0x40, 0xff, 2581 }; 2582 // clang-format on 2583 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2584 Buffer_make_executable(buf); 2585 uword result = Testing_execute_entry(buf, heap); 2586 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2587 AST_heap_free(node); 2588 PASS(); 2589} 2590 2591TEST compile_cdr(Buffer *buf, uword *heap) { 2592 ASTNode *node = Reader_read("(cdr (cons 1 2))"); 2593 int compile_result = Testing_compile_expr_entry(buf, node); 2594 ASSERT_EQ(compile_result, 0); 2595 // clang-format off 2596 byte expected[] = { 2597 // mov rax, 0x2 2598 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2599 // mov [rsp-8], rax 2600 0x48, 0x89, 0x44, 0x24, 0xf8, 2601 // mov rax, 0x4 2602 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2603 // mov [rsi+Cdr], rax 2604 0x48, 0x89, 0x46, 0x08, 2605 // mov rax, [rsp-8] 2606 0x48, 0x8b, 0x44, 0x24, 0xf8, 2607 // mov [rsi+Car], rax 2608 0x48, 0x89, 0x46, 0x00, 2609 // mov rax, rsi 2610 0x48, 0x89, 0xf0, 2611 // or rax, kPairTag 2612 0x48, 0x83, 0xc8, 0x01, 2613 // add rsi, 2*kWordSize 2614 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 2615 // mov rax, [rax+7] 2616 0x48, 0x8b, 0x40, 0x07, 2617 }; 2618 // clang-format on 2619 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2620 Buffer_make_executable(buf); 2621 uword result = Testing_execute_entry(buf, heap); 2622 ASSERT_EQ_FMT(Object_encode_integer(2), result, "0x%lx"); 2623 AST_heap_free(node); 2624 PASS(); 2625} 2626 2627TEST compile_code_with_no_params(Buffer *buf) { 2628 ASTNode *node = Reader_read("(code () 1)"); 2629 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2630 ASSERT_EQ(compile_result, 0); 2631 // clang-format off 2632 byte expected[] = { 2633 // mov rax, 0x2 2634 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2635 // ret 2636 0xc3, 2637 }; 2638 // clang-format on 2639 EXPECT_EQUALS_BYTES(buf, expected); 2640 Buffer_make_executable(buf); 2641 uword result = Testing_execute_expr(buf); 2642 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2643 AST_heap_free(node); 2644 PASS(); 2645} 2646 2647TEST compile_code_with_one_param(Buffer *buf) { 2648 ASTNode *node = Reader_read("(code (x) x)"); 2649 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2650 ASSERT_EQ(compile_result, 0); 2651 // clang-format off 2652 byte expected[] = { 2653 // mov rax, [rsp-8] 2654 0x48, 0x8b, 0x44, 0x24, 0xf8, 2655 // ret 2656 0xc3, 2657 }; 2658 // clang-format on 2659 EXPECT_EQUALS_BYTES(buf, expected); 2660 AST_heap_free(node); 2661 PASS(); 2662} 2663 2664TEST compile_code_with_two_params(Buffer *buf) { 2665 ASTNode *node = Reader_read("(code (x y) (+ x y))"); 2666 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2667 ASSERT_EQ(compile_result, 0); 2668 // clang-format off 2669 byte expected[] = { 2670 // mov rax, [rsp-16] 2671 0x48, 0x8b, 0x44, 0x24, 0xf0, 2672 // mov [rsp-24], rax 2673 0x48, 0x89, 0x44, 0x24, 0xe8, 2674 // mov rax, [rsp-8] 2675 0x48, 0x8b, 0x44, 0x24, 0xf8, 2676 // add rax, [rsp-24] 2677 0x48, 0x03, 0x44, 0x24, 0xe8, 2678 // ret 2679 0xc3, 2680 }; 2681 // clang-format on 2682 EXPECT_EQUALS_BYTES(buf, expected); 2683 AST_heap_free(node); 2684 PASS(); 2685} 2686 2687TEST compile_labels_with_no_labels(Buffer *buf) { 2688 ASTNode *node = Reader_read("(labels () 1)"); 2689 int compile_result = Compile_entry(buf, node); 2690 ASSERT_EQ(compile_result, 0); 2691 // clang-format off 2692 byte expected[] = { 2693 // mov rsi, rdi 2694 0x48, 0x89, 0xfe, 2695 // jmp 0x00 2696 0xe9, 0x00, 0x00, 0x00, 0x00, 2697 // mov rax, 0x2 2698 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2699 // ret 2700 0xc3, 2701 }; 2702 // clang-format on 2703 EXPECT_EQUALS_BYTES(buf, expected); 2704 Buffer_make_executable(buf); 2705 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2706 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2707 AST_heap_free(node); 2708 PASS(); 2709} 2710 2711TEST compile_labels_with_one_label(Buffer *buf) { 2712 ASTNode *node = Reader_read("(labels ((const (code () 5))) 1)"); 2713 int compile_result = Compile_entry(buf, node); 2714 ASSERT_EQ(compile_result, 0); 2715 // clang-format off 2716 byte expected[] = { 2717 // mov rsi, rdi 2718 0x48, 0x89, 0xfe, 2719 // jmp 0x08 2720 0xe9, 0x08, 0x00, 0x00, 0x00, 2721 // mov rax, compile(5) 2722 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2723 // ret 2724 0xc3, 2725 // mov rax, 0x2 2726 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2727 // ret 2728 0xc3, 2729 }; 2730 // clang-format on 2731 EXPECT_EQUALS_BYTES(buf, expected); 2732 Buffer_make_executable(buf); 2733 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2734 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2735 AST_heap_free(node); 2736 PASS(); 2737} 2738 2739TEST compile_labelcall_with_no_params(Buffer *buf) { 2740 ASTNode *node = 2741 Reader_read("(labels ((const (code () 5))) (labelcall const))"); 2742 int compile_result = Compile_entry(buf, node); 2743 ASSERT_EQ(compile_result, 0); 2744 // clang-format off 2745 byte expected[] = { 2746 // mov rsi, rdi 2747 0x48, 0x89, 0xfe, 2748 // jmp 0x08 2749 0xe9, 0x08, 0x00, 0x00, 0x00, 2750 // mov rax, compile(5) 2751 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2752 // ret 2753 0xc3, 2754 // call `const` 2755 0xe8, 0xf3, 0xff, 0xff, 0xff, 2756 // ret 2757 0xc3, 2758 }; 2759 // clang-format on 2760 EXPECT_EQUALS_BYTES(buf, expected); 2761 Buffer_make_executable(buf); 2762 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2763 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 2764 AST_heap_free(node); 2765 PASS(); 2766} 2767 2768TEST compile_labelcall_with_no_params_and_locals(Buffer *buf) { 2769 ASTNode *node = Reader_read( 2770 "(labels ((const (code () 5))) (let ((a 1)) (labelcall const)))"); 2771 int compile_result = Compile_entry(buf, node); 2772 ASSERT_EQ(compile_result, 0); 2773 // clang-format off 2774 byte expected[] = { 2775 // mov rsi, rdi 2776 0x48, 0x89, 0xfe, 2777 // jmp 0x08 2778 0xe9, 0x08, 0x00, 0x00, 0x00, 2779 // mov rax, compile(5) 2780 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2781 // ret 2782 0xc3, 2783 // mov rax, compile(1) 2784 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2785 // mov [rsp-8], rax 2786 0x48, 0x89, 0x44, 0x24, 0xf8, 2787 // sub rsp, 8 2788 0x48, 0x81, 0xec, 0x08, 0x00, 0x00, 0x00, 2789 // call `const` 2790 0xe8, 0xe0, 0xff, 0xff, 0xff, 2791 // add rsp, 8 2792 0x48, 0x81, 0xc4, 0x08, 0x00, 0x00, 0x00, 2793 // ret 2794 0xc3, 2795 }; 2796 // clang-format on 2797 EXPECT_EQUALS_BYTES(buf, expected); 2798 Buffer_make_executable(buf); 2799 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2800 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 2801 AST_heap_free(node); 2802 PASS(); 2803} 2804 2805TEST compile_labelcall_with_one_param(Buffer *buf) { 2806 ASTNode *node = Reader_read("(labels ((id (code (x) x))) (labelcall id 5))"); 2807 int compile_result = Compile_entry(buf, node); 2808 ASSERT_EQ(compile_result, 0); 2809 // clang-format off 2810 byte expected[] = { 2811 // mov rsi, rdi 2812 0x48, 0x89, 0xfe, 2813 // jmp 0x06 2814 0xe9, 0x06, 0x00, 0x00, 0x00, 2815 // mov rax, [rsp-8] 2816 0x48, 0x8b, 0x44, 0x24, 0xf8, 2817 // ret 2818 0xc3, 2819 // mov rax, compile(5) 2820 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2821 // mov [rsp-16], rax 2822 0x48, 0x89, 0x44, 0x24, 0xf0, 2823 // call `id` 2824 0xe8, 0xe9, 0xff, 0xff, 0xff, 2825 // ret 2826 0xc3, 2827 }; 2828 // clang-format on 2829 EXPECT_EQUALS_BYTES(buf, expected); 2830 Buffer_make_executable(buf); 2831 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2832 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 2833 AST_heap_free(node); 2834 PASS(); 2835} 2836 2837SUITE(object_tests) { 2838 RUN_TEST(encode_positive_integer); 2839 RUN_TEST(encode_negative_integer); 2840 RUN_TEST(encode_char); 2841 RUN_TEST(decode_char); 2842 RUN_TEST(encode_bool); 2843 RUN_TEST(decode_bool); 2844 RUN_TEST(address); 2845} 2846 2847TEST compile_labelcall_with_one_param_and_locals(Buffer *buf) { 2848 ASTNode *node = Reader_read( 2849 "(labels ((id (code (x) x))) (let ((a 1)) (labelcall id 5)))"); 2850 int compile_result = Compile_entry(buf, node); 2851 ASSERT_EQ(compile_result, 0); 2852 // clang-format off 2853 byte expected[] = { 2854 // mov rsi, rdi 2855 0x48, 0x89, 0xfe, 2856 // jmp 0x06 2857 0xe9, 0x06, 0x00, 0x00, 0x00, 2858 // mov rax, [rsp-8] 2859 0x48, 0x8b, 0x44, 0x24, 0xf8, 2860 // ret 2861 0xc3, 2862 // mov rax, compile(1) 2863 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2864 // mov [rsp-8], rax 2865 0x48, 0x89, 0x44, 0x24, 0xf8, 2866 // mov rax, compile(5) 2867 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2868 // mov [rsp-24], rax 2869 0x48, 0x89, 0x44, 0x24, 0xe8, 2870 // sub rsp, 8 2871 0x48, 0x81, 0xec, 0x08, 0x00, 0x00, 0x00, 2872 // call `id` 2873 0xe8, 0xd6, 0xff, 0xff, 0xff, 2874 // add rsp, 8 2875 0x48, 0x81, 0xc4, 0x08, 0x00, 0x00, 0x00, 2876 // ret 2877 0xc3, 2878 }; 2879 // clang-format on 2880 EXPECT_EQUALS_BYTES(buf, expected); 2881 Buffer_make_executable(buf); 2882 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2883 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 2884 AST_heap_free(node); 2885 PASS(); 2886} 2887 2888TEST compile_labelcall_with_two_params_and_locals(Buffer *buf) { 2889 ASTNode *node = Reader_read("(labels ((add (code (x y) (+ x y)))) (let ((a " 2890 "1)) (labelcall add 5 a)))"); 2891 int compile_result = Compile_entry(buf, node); 2892 ASSERT_EQ(compile_result, 0); 2893 // clang-format off 2894 byte expected[] = { 2895 // mov rsi, rdi 2896 0x48, 0x89, 0xfe, 2897 // jmp 0x15 2898 0xe9, 0x15, 0x00, 0x00, 0x00, 2899 // mov rax, [rsp-16] 2900 0x48, 0x8b, 0x44, 0x24, 0xf0, 2901 // mov [rsp-24], rax 2902 0x48, 0x89, 0x44, 0x24, 0xe8, 2903 // mov rax, [rsp-8] 2904 0x48, 0x8b, 0x44, 0x24, 0xf8, 2905 // add rax, [rsp-24] 2906 0x48, 0x03, 0x44, 0x24, 0xe8, 2907 // ret 2908 0xc3, 2909 // mov rax, compile(1) 2910 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2911 // mov [rsp-8], rax 2912 0x48, 0x89, 0x44, 0x24, 0xf8, 2913 // mov rax, compile(5) 2914 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2915 // mov [rsp-24], rax 2916 0x48, 0x89, 0x44, 0x24, 0xe8, 2917 // mov rax, [rsp-8] 2918 0x48, 0x8b, 0x44, 0x24, 0xf8, 2919 // mov [rsp-32], rax 2920 0x48, 0x89, 0x44, 0x24, 0xe0, 2921 // sub rsp, 8 2922 0x48, 0x81, 0xec, 0x08, 0x00, 0x00, 0x00, 2923 // call `add` 2924 0xe8, 0xbd, 0xff, 0xff, 0xff, 2925 // add rsp, 8 2926 0x48, 0x81, 0xc4, 0x08, 0x00, 0x00, 0x00, 2927 // ret 2928 0xc3, 2929 }; 2930 // clang-format on 2931 EXPECT_EQUALS_BYTES(buf, expected); 2932 Buffer_make_executable(buf); 2933 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2934 ASSERT_EQ_FMT(Object_encode_integer(6), result, "0x%lx"); 2935 AST_heap_free(node); 2936 PASS(); 2937} 2938 2939TEST compile_nested_labelcall(Buffer *buf) { 2940 ASTNode *node = Reader_read("(labels ((add (code (x y) (+ x y)))" 2941 " (sub (code (x y) (- x y))))" 2942 " (labelcall sub 4 (labelcall add 1 2)))"); 2943 int compile_result = Compile_entry(buf, node); 2944 ASSERT_EQ(compile_result, 0); 2945 Buffer_make_executable(buf); 2946 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2947 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2948 AST_heap_free(node); 2949 PASS(); 2950} 2951 2952TEST compile_multilevel_labelcall(Buffer *buf) { 2953 ASTNode *node = 2954 Reader_read("(labels ((add (code (x y) (+ x y)))" 2955 " (add2 (code (x y) (labelcall add x y))))" 2956 " (labelcall add2 1 2))"); 2957 int compile_result = Compile_entry(buf, node); 2958 ASSERT_EQ(compile_result, 0); 2959 Buffer_make_executable(buf); 2960 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2961 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2962 AST_heap_free(node); 2963 PASS(); 2964} 2965 2966TEST compile_factorial_labelcall(Buffer *buf) { 2967 ASTNode *node = Reader_read( 2968 "(labels ((factorial (code (x) " 2969 " (if (< x 2) 1 (* x (labelcall factorial (- x 1)))))))" 2970 " (labelcall factorial 5))"); 2971 int compile_result = Compile_entry(buf, node); 2972 ASSERT_EQ(compile_result, 0); 2973 Buffer_make_executable(buf); 2974 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2975 ASSERT_EQ_FMT(Object_encode_integer(120), result, "0x%lx"); 2976 AST_heap_free(node); 2977 PASS(); 2978} 2979 2980SUITE(ast_tests) { 2981 RUN_TEST(ast_new_pair); 2982 RUN_TEST(ast_pair_car_returns_car); 2983 RUN_TEST(ast_pair_cdr_returns_cdr); 2984 RUN_TEST(ast_new_symbol); 2985} 2986 2987SUITE(reader_tests) { 2988 RUN_TEST(read_with_integer_returns_integer); 2989 RUN_TEST(read_with_negative_integer_returns_integer); 2990 RUN_TEST(read_with_positive_integer_returns_integer); 2991 RUN_TEST(read_with_leading_whitespace_ignores_whitespace); 2992 RUN_TEST(read_with_symbol_returns_symbol); 2993 RUN_TEST(read_with_symbol_with_trailing_digits); 2994 RUN_TEST(read_with_nil_returns_nil); 2995 RUN_TEST(read_with_list_returns_list); 2996 RUN_TEST(read_with_nested_list_returns_list); 2997 RUN_TEST(read_with_char_returns_char); 2998 RUN_TEST(read_with_bool_returns_bool); 2999} 3000 3001SUITE(buffer_tests) { 3002 RUN_BUFFER_TEST(buffer_write8_increases_length); 3003 RUN_TEST(buffer_write8_expands_buffer); 3004 RUN_TEST(buffer_write32_expands_buffer); 3005 RUN_BUFFER_TEST(buffer_write32_writes_little_endian); 3006 RUN_BUFFER_TEST(emit_mov_reg_imm32_emits_modrm); 3007 RUN_BUFFER_TEST(emit_store_reg_indirect_emits_modrm_sib); 3008} 3009 3010SUITE(compiler_tests) { 3011 RUN_BUFFER_TEST(compile_positive_integer); 3012 RUN_BUFFER_TEST(compile_negative_integer); 3013 RUN_BUFFER_TEST(compile_char); 3014 RUN_BUFFER_TEST(compile_true); 3015 RUN_BUFFER_TEST(compile_false); 3016 RUN_BUFFER_TEST(compile_nil); 3017 RUN_BUFFER_TEST(compile_unary_add1); 3018 RUN_BUFFER_TEST(compile_unary_add1_nested); 3019 RUN_BUFFER_TEST(compile_unary_sub1); 3020 RUN_BUFFER_TEST(compile_unary_integer_to_char); 3021 RUN_BUFFER_TEST(compile_unary_char_to_integer); 3022 RUN_BUFFER_TEST(compile_unary_nilp_with_nil_returns_true); 3023 RUN_BUFFER_TEST(compile_unary_nilp_with_non_nil_returns_false); 3024 RUN_BUFFER_TEST(compile_unary_zerop_with_zero_returns_true); 3025 RUN_BUFFER_TEST(compile_unary_zerop_with_non_zero_returns_false); 3026 RUN_BUFFER_TEST(compile_unary_not_with_false_returns_true); 3027 RUN_BUFFER_TEST(compile_unary_not_with_non_false_returns_false); 3028 RUN_BUFFER_TEST(compile_unary_integerp_with_integer_returns_true); 3029 RUN_BUFFER_TEST(compile_unary_integerp_with_non_integer_returns_false); 3030 RUN_BUFFER_TEST(compile_unary_booleanp_with_boolean_returns_true); 3031 RUN_BUFFER_TEST(compile_unary_booleanp_with_non_boolean_returns_false); 3032 RUN_BUFFER_TEST(compile_binary_plus); 3033 RUN_BUFFER_TEST(compile_binary_plus_nested); 3034 RUN_BUFFER_TEST(compile_binary_minus); 3035 RUN_BUFFER_TEST(compile_binary_minus_nested); 3036 RUN_BUFFER_TEST(compile_binary_mul); 3037 RUN_BUFFER_TEST(compile_binary_mul_nested); 3038 RUN_BUFFER_TEST(compile_binary_eq_with_same_address_returns_true); 3039 RUN_BUFFER_TEST(compile_binary_eq_with_different_address_returns_false); 3040 RUN_BUFFER_TEST(compile_binary_lt_with_left_less_than_right_returns_true); 3041 RUN_BUFFER_TEST(compile_binary_lt_with_left_equal_to_right_returns_false); 3042 RUN_BUFFER_TEST(compile_binary_lt_with_left_greater_than_right_returns_false); 3043 RUN_BUFFER_TEST(compile_symbol_in_env_returns_value); 3044 RUN_BUFFER_TEST(compile_symbol_in_env_returns_first_value); 3045 RUN_BUFFER_TEST(compile_symbol_not_in_env_raises_compile_error); 3046 RUN_BUFFER_TEST(compile_let_with_no_bindings); 3047 RUN_BUFFER_TEST(compile_let_with_one_binding); 3048 RUN_BUFFER_TEST(compile_let_with_multiple_bindings); 3049 RUN_BUFFER_TEST(compile_nested_let); 3050 RUN_BUFFER_TEST(compile_let_is_not_let_star); 3051 RUN_BUFFER_TEST(compile_if_with_true_cond); 3052 RUN_BUFFER_TEST(compile_if_with_false_cond); 3053 RUN_BUFFER_TEST(compile_nested_if); 3054 RUN_HEAP_TEST(compile_cons); 3055 RUN_HEAP_TEST(compile_two_cons); 3056 RUN_HEAP_TEST(compile_nested_cons); 3057 RUN_HEAP_TEST(compile_car); 3058 RUN_HEAP_TEST(compile_cdr); 3059 RUN_BUFFER_TEST(compile_code_with_no_params); 3060 RUN_BUFFER_TEST(compile_code_with_one_param); 3061 RUN_BUFFER_TEST(compile_code_with_two_params); 3062 RUN_BUFFER_TEST(compile_labels_with_no_labels); 3063 RUN_BUFFER_TEST(compile_labels_with_one_label); 3064 RUN_BUFFER_TEST(compile_labelcall_with_no_params); 3065 RUN_BUFFER_TEST(compile_labelcall_with_no_params_and_locals); 3066 RUN_BUFFER_TEST(compile_labelcall_with_one_param); 3067 RUN_BUFFER_TEST(compile_labelcall_with_one_param_and_locals); 3068 RUN_BUFFER_TEST(compile_labelcall_with_two_params_and_locals); 3069 RUN_BUFFER_TEST(compile_nested_labelcall); 3070 RUN_BUFFER_TEST(compile_multilevel_labelcall); 3071 RUN_BUFFER_TEST(compile_factorial_labelcall); 3072} 3073 3074// End Tests 3075 3076GREATEST_MAIN_DEFS(); 3077 3078int run_tests(int argc, char **argv) { 3079 GREATEST_MAIN_BEGIN(); 3080 RUN_SUITE(object_tests); 3081 RUN_SUITE(ast_tests); 3082 RUN_SUITE(reader_tests); 3083 RUN_SUITE(buffer_tests); 3084 RUN_SUITE(compiler_tests); 3085 GREATEST_MAIN_END(); 3086} 3087 3088int main(int argc, char **argv) { 3089 assert(argc == 2 && "need filename and only filename"); 3090 const char *filename = argv[1]; 3091 ASTNode *program = Reader_read( 3092 "(labels ((factorial (code (x) " 3093 " (if (< x 2) 1 (* x (labelcall factorial (- x 1)))))))" 3094 " (labelcall factorial 5))"); 3095 int code = Compile_to_file(program, filename); 3096 AST_heap_free(program); 3097 return code; 3098}