this repo has no description
at trunk 3895 lines 129 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-closures.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// _GNU_SOURCE is used for MAP_ANONYMOUS in sys/mman.h and strdup in string.h 9#define _GNU_SOURCE 10#include <assert.h> // for assert 11#include <stdarg.h> 12#include <stdbool.h> // for bool 13#include <stddef.h> // for NULL 14#include <stdint.h> // for int32_t, etc 15#include <stdio.h> // for getline, fprintf 16#include <string.h> // for memcpy 17#include <sys/mman.h> // for mmap 18#undef _GNU_SOURCE 19 20#include "greatest.h" 21 22#define WARN_UNUSED __attribute__((warn_unused_result)) 23 24// Objects 25 26typedef intptr_t word; 27typedef uintptr_t uword; 28 29// These constants are defined in a enum because the right hand side of a 30// statement like 31// static const int kFoo = ...; 32// must be a so-called "Integer Constant Expression". Compilers are required to 33// support a certain set of these expressions, but are not required to support 34// arbitrary arithmetic with other integer constants. Compilers such as gcc 35// before gcc-8 just decided not to play this game, while gcc-8+ and Clang play 36// just fine. 37// Since this arithmetic with constant values works just fine for enums, make 38// all these constants enum values instead. 39// See https://twitter.com/tekknolagi/status/1328449329472835586 for more info. 40enum { 41 kBitsPerByte = 8, // bits 42 kWordSize = sizeof(word), // bytes 43 kBitsPerWord = kWordSize * kBitsPerByte, // bits 44 45 kIntegerTag = 0x0, // 0b00 46 kIntegerTagMask = 0x3, // 0b11 47 kIntegerShift = 2, 48 kIntegerBits = kBitsPerWord - kIntegerShift, 49 50 kImmediateTagMask = 0x3f, 51 52 kCharTag = 0x0f, // 0b00001111 53 kCharMask = 0xff, // 0b11111111 54 kCharShift = 8, 55 56 kBoolTag = 0x1f, // 0b0011111 57 kBoolMask = 0x80, // 0b10000000 58 kBoolShift = 7, 59 60 kNilTag = 0x2f, // 0b101111 61 62 kErrorTag = 0x3f, // 0b111111 63 64 kPairTag = 0x1, // 0b001 65 kSymbolTag = 0x5, // 0b101 66 kClosureTag = 0x6, // 0b110 67 kHeapTagMask = ((uword)0x7), // 0b000...111 68 kHeapPtrMask = ~kHeapTagMask, // 0b1111...1000 69 70 kCarIndex = 0, 71 kCarOffset = kCarIndex * kWordSize, 72 kCdrIndex = kCarIndex + 1, 73 kCdrOffset = kCdrIndex * kWordSize, 74 kPairSize = kCdrOffset + kWordSize, 75 76 kClosureLabelIndex = 0, 77 kClosureLabelOffset = kClosureLabelIndex * kWordSize, 78}; 79 80// These are defined as macros because they will not work as static const int 81// constants (per above explanation), and enum constants are only required to 82// be an int wide (per ISO C). 83#define INTEGER_MAX ((1LL << (kIntegerBits - 1)) - 1) 84#define INTEGER_MIN (-(1LL << (kIntegerBits - 1))) 85 86uword Object_encode_integer(word value) { 87 assert(value < INTEGER_MAX && "too big"); 88 assert(value > INTEGER_MIN && "too small"); 89 return value << kIntegerShift; 90} 91 92word Object_decode_integer(uword value) { return (word)value >> kIntegerShift; } 93 94bool Object_is_integer(uword value) { 95 return (value & kIntegerTagMask) == kIntegerTag; 96} 97 98uword Object_encode_char(char value) { 99 return ((uword)value << kCharShift) | kCharTag; 100} 101 102char Object_decode_char(uword value) { 103 return (value >> kCharShift) & kCharMask; 104} 105 106bool Object_is_char(uword value) { 107 return (value & kImmediateTagMask) == kCharTag; 108} 109 110uword Object_encode_bool(bool value) { 111 return ((uword)value << kBoolShift) | kBoolTag; 112} 113 114bool Object_decode_bool(uword value) { return value & kBoolMask; } 115 116uword Object_true() { return Object_encode_bool(true); } 117 118uword Object_false() { return Object_encode_bool(false); } 119 120uword Object_nil() { return kNilTag; } 121 122uword Object_error() { return kErrorTag; } 123 124uword Object_address(const void *obj) { return (uword)obj & kHeapPtrMask; } 125 126bool Object_is_pair(uword value) { return (value & kHeapTagMask) == kPairTag; } 127 128uword Object_pair_car(uword value) { 129 assert(Object_is_pair(value)); 130 return ((uword *)Object_address((void *)value))[kCarIndex]; 131} 132 133uword Object_pair_cdr(uword value) { 134 assert(Object_is_pair(value)); 135 return ((uword *)Object_address((void *)value))[kCdrIndex]; 136} 137 138bool Object_is_closure(uword value) { 139 return (value & kHeapTagMask) == kClosureTag; 140} 141 142uword Object_closure_label(uword value) { 143 assert(Object_is_closure(value)); 144 return ((uword *)Object_address((void *)value))[kClosureLabelIndex]; 145} 146 147uword Object_closure_freevar(uword value, word n) { 148 assert(Object_is_closure(value)); 149 // +1 for label 150 return ((uword *)Object_address((void *)value))[n + 1]; 151} 152 153// End Objects 154 155// Buffer 156 157typedef unsigned char byte; 158 159typedef enum { 160 kWritable, 161 kExecutable, 162} BufferState; 163 164typedef struct { 165 byte *address; 166 BufferState state; 167 word len; 168 word capacity; 169 word entrypoint; 170} Buffer; 171 172byte *Buffer_alloc_writable(word capacity) { 173 byte *result = mmap(/*addr=*/NULL, capacity, PROT_READ | PROT_WRITE, 174 MAP_ANONYMOUS | MAP_PRIVATE, 175 /*filedes=*/-1, /*off=*/0); 176 assert(result != MAP_FAILED); 177 return result; 178} 179 180void Buffer_init(Buffer *result, word capacity) { 181 result->address = Buffer_alloc_writable(capacity); 182 assert(result->address != MAP_FAILED); 183 result->state = kWritable; 184 result->len = 0; 185 result->capacity = capacity; 186 result->entrypoint = 0; 187} 188 189word Buffer_len(Buffer *buf) { return buf->len; } 190 191void Buffer_deinit(Buffer *buf) { 192 munmap(buf->address, buf->capacity); 193 buf->address = NULL; 194 buf->len = 0; 195 buf->capacity = 0; 196 buf->entrypoint = 0; 197} 198 199int Buffer_make_executable(Buffer *buf) { 200 int result = mprotect(buf->address, buf->len, PROT_EXEC); 201 buf->state = kExecutable; 202 return result; 203} 204 205byte Buffer_at8(Buffer *buf, word pos) { return buf->address[pos]; } 206 207void Buffer_at_put8(Buffer *buf, word pos, byte b) { buf->address[pos] = b; } 208 209word max(word left, word right) { return left > right ? left : right; } 210 211void Buffer_ensure_capacity(Buffer *buf, word additional_capacity) { 212 if (buf->len + additional_capacity <= buf->capacity) { 213 return; 214 } 215 word new_capacity = 216 max(buf->capacity * 2, buf->capacity + additional_capacity); 217 byte *address = Buffer_alloc_writable(new_capacity); 218 memcpy(address, buf->address, buf->len); 219 int result = munmap(buf->address, buf->capacity); 220 assert(result == 0 && "munmap failed"); 221 buf->address = address; 222 buf->capacity = new_capacity; 223} 224 225void Buffer_write8(Buffer *buf, byte b) { 226 Buffer_ensure_capacity(buf, sizeof b); 227 Buffer_at_put8(buf, buf->len++, b); 228} 229 230void Buffer_write32(Buffer *buf, int32_t value) { 231 for (uword i = 0; i < sizeof(value); i++) { 232 Buffer_write8(buf, (value >> (i * kBitsPerByte)) & 0xff); 233 } 234} 235 236void Buffer_at_put32(Buffer *buf, word offset, int32_t value) { 237 for (uword i = 0; i < sizeof(value); i++) { 238 Buffer_at_put8(buf, offset + i, (value >> (i * kBitsPerByte)) & 0xff); 239 } 240} 241 242void Buffer_write_arr(Buffer *buf, const byte *arr, word arr_size) { 243 Buffer_ensure_capacity(buf, arr_size); 244 for (word i = 0; i < arr_size; i++) { 245 Buffer_write8(buf, arr[i]); 246 } 247} 248 249void Buffer_dump(Buffer *buf, FILE *fp) { 250 for (word i = 0; i < Buffer_len(buf); i++) { 251 fprintf(fp, "%.2x ", buf->address[i]); 252 } 253 fprintf(fp, "\n"); 254} 255 256// End Buffer 257 258// Emit 259 260typedef enum { 261 kRax = 0, 262 kRcx, 263 kRdx, 264 kRbx, 265 kRsp, 266 kRbp, 267 kRsi, 268 kRdi, 269} Register; 270 271typedef enum { 272 kAl = 0, 273 kCl, 274 kDl, 275 kBl, 276 kAh, 277 kCh, 278 kDh, 279 kBh, 280} PartialRegister; 281 282typedef enum { 283 kOverflow = 0, 284 kNotOverflow, 285 kBelow, 286 kCarry = kBelow, 287 kNotAboveOrEqual = kBelow, 288 kAboveOrEqual, 289 kNotBelow = kAboveOrEqual, 290 kNotCarry = kAboveOrEqual, 291 kEqual, 292 kZero = kEqual, 293 kLess = 0xc, 294 kNotGreaterOrEqual = kLess, 295 // TODO(max): Add more 296} Condition; 297 298typedef enum { 299 kModDeref = 0, 300 kModDisp8, 301 kModDisp32, 302 kModDirect, 303} Mod; 304 305typedef enum { 306 kNear = 2, 307 kFar = 3, 308} CallDistance; 309 310typedef struct Indirect { 311 Register reg; 312 word disp; 313} Indirect; 314 315Indirect Ind(Register reg, word disp) { 316 return (Indirect){.reg = reg, .disp = disp}; 317} 318 319// [ Instruction Prefixes (1 byte, optional) ] 320// [ Opcode (1, 2, or 3 bytes) ] 321// [ ModR/M (1 byte, if required) ] 322// [ Scale-Index-Base (1 byte, if required) ] 323// [ Displacement (1, 2, or 4 bytes, if required) ] 324// [ Immediate data (1, 2, or 4 bytes, if required) ] 325 326// http://www.c-jump.com/CIS77/CPU/x86/lecture.html 327// https://wiki.osdev.org/X86-64_Instruction_Encoding 328 329enum { 330 kRexPrefix = 0x48, 331}; 332 333typedef enum { 334 Scale1 = 0, 335 Scale2, 336 Scale4, 337 Scale8, 338} Scale; 339 340typedef enum { 341 kIndexRax = 0, 342 kIndexRcx, 343 kIndexRdx, 344 kIndexRbx, 345 kIndexNone, 346 kIndexRbp, 347 kIndexRsi, 348 kIndexRdi 349} Index; 350 351byte modrm(byte mod, byte rm, byte reg) { 352 return ((mod & 0x3) << 6) | ((reg & 0x7) << 3) | (rm & 0x7); 353} 354 355byte sib(Register base, Index index, Scale scale) { 356 return ((scale & 0x3) << 6) | ((index & 0x7) << 3) | (base & 0x7); 357} 358 359void Emit_mov_reg_imm32(Buffer *buf, Register dst, int32_t src) { 360 Buffer_write8(buf, kRexPrefix); 361 Buffer_write8(buf, 0xc7); 362 Buffer_write8(buf, modrm(kModDirect, dst, 0)); 363 Buffer_write32(buf, src); 364} 365 366void Emit_ret(Buffer *buf) { Buffer_write8(buf, 0xc3); } 367 368void Emit_add_reg_imm32(Buffer *buf, Register dst, int32_t src) { 369 Buffer_write8(buf, kRexPrefix); 370 if (dst == kRax) { 371 // Optimization: add eax, {imm32} can either be encoded as 05 {imm32} or 81 372 // c0 {imm32}. 373 Buffer_write8(buf, 0x05); 374 } else { 375 Buffer_write8(buf, 0x81); 376 Buffer_write8(buf, modrm(kModDirect, dst, 0)); 377 } 378 Buffer_write32(buf, src); 379} 380 381void Emit_sub_reg_imm32(Buffer *buf, Register dst, int32_t src) { 382 Buffer_write8(buf, kRexPrefix); 383 if (dst == kRax) { 384 // Optimization: sub eax, {imm32} can either be encoded as 2d {imm32} or 81 385 // e8 {imm32}. 386 Buffer_write8(buf, 0x2d); 387 } else { 388 Buffer_write8(buf, 0x81); 389 Buffer_write8(buf, modrm(kModDirect, dst, 5)); 390 } 391 Buffer_write32(buf, src); 392} 393 394void Emit_shl_reg_imm8(Buffer *buf, Register dst, int8_t bits) { 395 Buffer_write8(buf, kRexPrefix); 396 Buffer_write8(buf, 0xc1); 397 Buffer_write8(buf, modrm(kModDirect, dst, 4)); 398 Buffer_write8(buf, bits); 399} 400 401void Emit_shr_reg_imm8(Buffer *buf, Register dst, int8_t bits) { 402 Buffer_write8(buf, kRexPrefix); 403 Buffer_write8(buf, 0xc1); 404 Buffer_write8(buf, modrm(kModDirect, dst, 5)); 405 Buffer_write8(buf, bits); 406} 407 408void Emit_or_reg_imm8(Buffer *buf, Register dst, uint8_t tag) { 409 Buffer_write8(buf, kRexPrefix); 410 Buffer_write8(buf, 0x83); 411 Buffer_write8(buf, modrm(kModDirect, dst, 1)); 412 Buffer_write8(buf, tag); 413} 414 415void Emit_and_reg_imm8(Buffer *buf, Register dst, uint8_t tag) { 416 Buffer_write8(buf, kRexPrefix); 417 Buffer_write8(buf, 0x83); 418 Buffer_write8(buf, modrm(kModDirect, dst, 4)); 419 Buffer_write8(buf, tag); 420} 421 422void Emit_cmp_reg_imm32(Buffer *buf, Register left, int32_t right) { 423 Buffer_write8(buf, kRexPrefix); 424 if (left == kRax) { 425 // Optimization: cmp rax, {imm32} can either be encoded as 3d {imm32} or 81 426 // f8 {imm32}. 427 Buffer_write8(buf, 0x3d); 428 } else { 429 Buffer_write8(buf, 0x81); 430 Buffer_write8(buf, modrm(kModDirect, left, 7)); 431 } 432 Buffer_write32(buf, right); 433} 434 435void Emit_setcc_imm8(Buffer *buf, Condition cond, PartialRegister dst) { 436 // TODO(max): Emit a REX prefix if we need anything above RDI. 437 Buffer_write8(buf, 0x0f); 438 Buffer_write8(buf, 0x90 + cond); 439 Buffer_write8(buf, 0xc0 + (dst & 0x7)); 440} 441 442uint8_t disp8(int8_t disp) { return disp >= 0 ? disp : 0x100 + disp; } 443 444void Emit_address_disp8(Buffer *buf, Register direct, Indirect indirect) { 445 if (indirect.reg == kRsp) { 446 Buffer_write8(buf, modrm(kModDisp8, kIndexNone, direct)); 447 Buffer_write8(buf, sib(kRsp, kIndexNone, Scale1)); 448 } else { 449 Buffer_write8(buf, modrm(kModDisp8, indirect.reg, direct)); 450 } 451 Buffer_write8(buf, disp8(indirect.disp)); 452} 453 454// mov [dst+disp], src 455// or 456// mov %src, disp(%dst) 457void Emit_store_reg_indirect(Buffer *buf, Indirect dst, Register src) { 458 Buffer_write8(buf, kRexPrefix); 459 Buffer_write8(buf, 0x89); 460 Emit_address_disp8(buf, src, dst); 461} 462 463// add dst, [src+disp] 464// or 465// add disp(%src), %dst 466void Emit_add_reg_indirect(Buffer *buf, Register dst, Indirect src) { 467 Buffer_write8(buf, kRexPrefix); 468 Buffer_write8(buf, 0x03); 469 Emit_address_disp8(buf, dst, src); 470} 471 472// sub dst, [src+disp] 473// or 474// sub disp(%src), %dst 475void Emit_sub_reg_indirect(Buffer *buf, Register dst, Indirect src) { 476 Buffer_write8(buf, kRexPrefix); 477 Buffer_write8(buf, 0x2b); 478 Emit_address_disp8(buf, dst, src); 479} 480 481// mul rax, [src+disp] 482// or 483// mul disp(%src), %rax 484void Emit_mul_reg_indirect(Buffer *buf, Indirect src) { 485 Buffer_write8(buf, kRexPrefix); 486 Buffer_write8(buf, 0xf7); 487 Emit_address_disp8(buf, /*subop*/ 4, src); 488} 489 490// cmp left, [right+disp] 491// or 492// cmp disp(%right), %left 493void Emit_cmp_reg_indirect(Buffer *buf, Register left, Indirect right) { 494 Buffer_write8(buf, kRexPrefix); 495 Buffer_write8(buf, 0x3b); 496 Emit_address_disp8(buf, left, right); 497} 498 499// mov dst, [src+disp] 500// or 501// mov disp(%src), %dst 502void Emit_load_reg_indirect(Buffer *buf, Register dst, Indirect src) { 503 Buffer_write8(buf, kRexPrefix); 504 Buffer_write8(buf, 0x8b); 505 Emit_address_disp8(buf, dst, src); 506} 507 508uint32_t disp32(int32_t disp) { return disp >= 0 ? disp : 0x100000000 + disp; } 509 510word Emit_jcc(Buffer *buf, Condition cond, int32_t offset) { 511 Buffer_write8(buf, 0x0f); 512 Buffer_write8(buf, 0x80 + cond); 513 word pos = Buffer_len(buf); 514 Buffer_write32(buf, disp32(offset)); 515 return pos; 516} 517 518word Emit_jmp(Buffer *buf, int32_t offset) { 519 Buffer_write8(buf, 0xe9); 520 word pos = Buffer_len(buf); 521 Buffer_write32(buf, disp32(offset)); 522 return pos; 523} 524 525void Emit_backpatch_imm32(Buffer *buf, int32_t target_pos) { 526 word current_pos = Buffer_len(buf); 527 word relative_pos = current_pos - target_pos - sizeof(int32_t); 528 Buffer_at_put32(buf, target_pos, disp32(relative_pos)); 529} 530 531void Emit_mov_reg_reg(Buffer *buf, Register dst, Register src) { 532 Buffer_write8(buf, kRexPrefix); 533 Buffer_write8(buf, 0x89); 534 Buffer_write8(buf, modrm(kModDirect, dst, src)); 535} 536 537// mov [dst+disp], imm32 538// or 539// mov imm32, disp(%dst) 540void Emit_store_indirect_imm32(Buffer *buf, Indirect dst, int32_t src) { 541 Buffer_write8(buf, kRexPrefix); 542 Buffer_write8(buf, 0xc7); 543 Emit_address_disp8(buf, /*/0*/ 0, dst); 544 Buffer_write32(buf, src); 545} 546 547void Emit_rsp_adjust(Buffer *buf, word adjust) { 548 if (adjust < 0) { 549 Emit_sub_reg_imm32(buf, kRsp, -adjust); 550 } else if (adjust > 0) { 551 Emit_add_reg_imm32(buf, kRsp, adjust); 552 } 553} 554 555void Emit_call_imm32(Buffer *buf, word absolute_address) { 556 // 5 is length of call instruction 557 word relative_address = absolute_address - (Buffer_len(buf) + 5); 558 Buffer_write8(buf, 0xe8); 559 Buffer_write32(buf, relative_address); 560} 561 562void Emit_call_indirect(Buffer *buf, Indirect target) { 563 assert(target.reg != kRsp); 564 Buffer_write8(buf, 0xff); 565 Buffer_write8(buf, modrm(kModDisp32, target.reg, kNear)); 566 Buffer_write32(buf, target.disp); 567} 568 569void Emit_call_reg(Buffer *buf, Register reg) { 570 assert(reg != kRsp); 571 Buffer_write8(buf, 0xff); 572 Buffer_write8(buf, modrm(kModDirect, reg, kNear)); 573} 574 575// End Emit 576 577// AST 578 579typedef struct ASTNode ASTNode; 580 581typedef struct Pair { 582 ASTNode *car; 583 ASTNode *cdr; 584} Pair; 585 586typedef struct Symbol { 587 word length; 588 char cstr[]; 589} Symbol; 590 591bool AST_is_integer(ASTNode *node) { 592 return ((uword)node & kIntegerTagMask) == kIntegerTag; 593} 594 595word AST_get_integer(ASTNode *node) { 596 return Object_decode_integer((uword)node); 597} 598 599ASTNode *AST_new_integer(word value) { 600 return (ASTNode *)Object_encode_integer(value); 601} 602 603bool AST_is_char(ASTNode *node) { 604 return ((uword)node & kImmediateTagMask) == kCharTag; 605} 606 607char AST_get_char(ASTNode *node) { return Object_decode_char((uword)node); } 608 609ASTNode *AST_new_char(char value) { 610 return (ASTNode *)Object_encode_char(value); 611} 612 613bool AST_is_bool(ASTNode *node) { 614 return ((uword)node & kImmediateTagMask) == kBoolTag; 615} 616 617bool AST_get_bool(ASTNode *node) { return Object_decode_bool((uword)node); } 618 619ASTNode *AST_new_bool(bool value) { 620 return (ASTNode *)Object_encode_bool(value); 621} 622 623bool AST_is_nil(ASTNode *node) { return (uword)node == Object_nil(); } 624 625ASTNode *AST_nil() { return (ASTNode *)Object_nil(); } 626 627bool AST_is_error(ASTNode *node) { return (uword)node == Object_error(); } 628 629ASTNode *AST_error() { return (ASTNode *)Object_error(); } 630 631ASTNode *AST_heap_alloc(unsigned char tag, uword size) { 632 // Initialize to 0 633 void *address = calloc(size, 1); 634 assert(address != NULL && "allocation failed"); 635 return (ASTNode *)((uword)address | tag); 636} 637 638bool AST_is_heap_object(ASTNode *node) { 639 // For some reason masking out the tag first and then doing the comparison 640 // makes this branchless 641 unsigned char tag = (uword)node & kHeapTagMask; 642 // Heap object tags are between 0b001 and 0b110 except for 0b100 (which is an 643 // integer) 644 return (tag & kIntegerTagMask) > 0 && (tag & kImmediateTagMask) != 0x7; 645} 646 647void AST_pair_set_car(ASTNode *node, ASTNode *car); 648void AST_pair_set_cdr(ASTNode *node, ASTNode *cdr); 649 650ASTNode *AST_new_pair(ASTNode *car, ASTNode *cdr) { 651 ASTNode *node = AST_heap_alloc(kPairTag, sizeof(Pair)); 652 AST_pair_set_car(node, car); 653 AST_pair_set_cdr(node, cdr); 654 return node; 655} 656 657bool AST_is_pair(ASTNode *node) { 658 return ((uword)node & kHeapTagMask) == kPairTag; 659} 660 661Pair *AST_as_pair(ASTNode *node) { 662 assert(AST_is_pair(node)); 663 return (Pair *)Object_address(node); 664} 665 666ASTNode *AST_pair_car(ASTNode *node) { return AST_as_pair(node)->car; } 667 668void AST_pair_set_car(ASTNode *node, ASTNode *car) { 669 AST_as_pair(node)->car = car; 670} 671 672ASTNode *AST_pair_cdr(ASTNode *node) { return AST_as_pair(node)->cdr; } 673 674void AST_pair_set_cdr(ASTNode *node, ASTNode *cdr) { 675 AST_as_pair(node)->cdr = cdr; 676} 677 678void AST_heap_free(ASTNode *node) { 679 if (!AST_is_heap_object(node)) { 680 return; 681 } 682 if (AST_is_pair(node)) { 683 AST_heap_free(AST_pair_car(node)); 684 AST_heap_free(AST_pair_cdr(node)); 685 } 686 free((void *)Object_address(node)); 687} 688 689Symbol *AST_as_symbol(ASTNode *node); 690 691ASTNode *AST_new_symbol(const char *str) { 692 word data_length = strlen(str) + 1; // for NUL 693 ASTNode *node = AST_heap_alloc(kSymbolTag, sizeof(Symbol) + data_length); 694 Symbol *s = AST_as_symbol(node); 695 s->length = data_length; 696 memcpy(s->cstr, str, data_length); 697 return node; 698} 699 700bool AST_is_symbol(ASTNode *node) { 701 return ((uword)node & kHeapTagMask) == kSymbolTag; 702} 703 704Symbol *AST_as_symbol(ASTNode *node) { 705 assert(AST_is_symbol(node)); 706 return (Symbol *)Object_address(node); 707} 708 709const char *AST_symbol_cstr(ASTNode *node) { 710 return (const char *)AST_as_symbol(node)->cstr; 711} 712 713bool AST_symbol_matches(ASTNode *node, const char *cstr) { 714 return strcmp(AST_symbol_cstr(node), cstr) == 0; 715} 716 717int node_to_str(ASTNode *node, char *buf, word size); 718 719int list_to_str(ASTNode *node, char *buf, word size) { 720 if (AST_is_pair(node)) { 721 word result = 0; 722 result += snprintf(buf + result, size, " "); 723 result += node_to_str(AST_pair_car(node), buf + result, size); 724 result += list_to_str(AST_pair_cdr(node), buf + result, size); 725 return result; 726 } 727 if (AST_is_nil(node)) { 728 return snprintf(buf, size, ")"); 729 } 730 word result = 0; 731 result += snprintf(buf + result, size, " . "); 732 result += node_to_str(node, buf + result, size); 733 result += snprintf(buf + result, size, ")"); 734 return result; 735} 736 737int node_to_str(ASTNode *node, char *buf, word size) { 738 if (AST_is_integer(node)) { 739 return snprintf(buf, size, "%ld", AST_get_integer(node)); 740 } 741 if (AST_is_char(node)) { 742 return snprintf(buf, size, "'%c'", AST_get_char(node)); 743 } 744 if (AST_is_bool(node)) { 745 return snprintf(buf, size, "%s", AST_get_bool(node) ? "true" : "false"); 746 } 747 if (AST_is_nil(node)) { 748 return snprintf(buf, size, "nil"); 749 } 750 if (AST_is_pair(node)) { 751 word result = 0; 752 result += snprintf(buf + result, size, "("); 753 result += node_to_str(AST_pair_car(node), buf + result, size); 754 result += list_to_str(AST_pair_cdr(node), buf + result, size); 755 return result; 756 } 757 if (AST_is_symbol(node)) { 758 return snprintf(buf, size, "%s", AST_symbol_cstr(node)); 759 } 760 assert(0 && "unknown ast"); 761} 762 763char *AST_to_cstr(ASTNode *node) { 764 int size = node_to_str(node, NULL, 0); 765 char *buf = malloc(size + 1); 766 assert(buf != NULL); 767 node_to_str(node, buf, size + 1); 768 buf[size] = '\0'; 769 return buf; 770} 771 772// End AST 773 774// Reader 775 776void advance(word *pos) { ++*pos; } 777 778char next(char *input, word *pos) { 779 advance(pos); 780 return input[*pos]; 781} 782 783ASTNode *read_integer(char *input, word *pos, int sign) { 784 word result = 0; 785 for (char c = input[*pos]; isdigit(c); c = next(input, pos)) { 786 result *= 10; 787 result += c - '0'; 788 } 789 return AST_new_integer(sign * result); 790} 791 792bool starts_symbol(char c) { 793 switch (c) { 794 case '+': 795 case '-': 796 case '*': 797 case '<': 798 case '>': 799 case '=': 800 case '?': 801 return true; 802 default: 803 return isalpha(c); 804 } 805} 806 807bool is_symbol_char(char c) { return starts_symbol(c) || isdigit(c); } 808 809const word ATOM_MAX = 32; 810 811ASTNode *read_symbol(char *input, word *pos) { 812 char buf[ATOM_MAX + 1]; // +1 for NUL 813 word length = 0; 814 for (length = 0; length < ATOM_MAX && is_symbol_char(input[*pos]); length++) { 815 buf[length] = input[*pos]; 816 advance(pos); 817 } 818 buf[length] = '\0'; 819 return AST_new_symbol(buf); 820} 821 822ASTNode *read_char(char *input, word *pos) { 823 char c = input[*pos]; 824 if (c == '\'') { 825 return AST_error(); 826 } 827 advance(pos); 828 if (input[*pos] != '\'') { 829 return AST_error(); 830 } 831 advance(pos); 832 return AST_new_char(c); 833} 834 835char skip_whitespace(char *input, word *pos) { 836 char c = '\0'; 837 for (c = input[*pos]; isspace(c); c = next(input, pos)) { 838 ; 839 } 840 return c; 841} 842 843ASTNode *read_rec(char *input, word *pos); 844 845ASTNode *read_list(char *input, word *pos) { 846 char c = skip_whitespace(input, pos); 847 if (c == ')') { 848 advance(pos); 849 return AST_nil(); 850 } 851 ASTNode *car = read_rec(input, pos); 852 assert(car != AST_error()); 853 ASTNode *cdr = read_list(input, pos); 854 assert(cdr != AST_error()); 855 return AST_new_pair(car, cdr); 856} 857 858ASTNode *read_rec(char *input, word *pos) { 859 char c = skip_whitespace(input, pos); 860 if (isdigit(c)) { 861 return read_integer(input, pos, /*sign=*/1); 862 } 863 if (c == '-' && isdigit(input[*pos + 1])) { 864 advance(pos); 865 return read_integer(input, pos, /*sign=*/-1); 866 } 867 if (c == '+' && isdigit(input[*pos + 1])) { 868 advance(pos); 869 return read_integer(input, pos, /*sign=*/1); 870 } 871 if (starts_symbol(c)) { 872 return read_symbol(input, pos); 873 } 874 if (c == '\'') { 875 advance(pos); // skip '\'' 876 return read_char(input, pos); 877 } 878 if (c == '#' && input[*pos + 1] == 't') { 879 advance(pos); // skip '#' 880 advance(pos); // skip 't' 881 return AST_new_bool(true); 882 } 883 if (c == '#' && input[*pos + 1] == 'f') { 884 advance(pos); // skip '#' 885 advance(pos); // skip 'f' 886 return AST_new_bool(false); 887 } 888 if (c == '(') { 889 advance(pos); // skip '(' 890 return read_list(input, pos); 891 } 892 return AST_error(); 893} 894 895ASTNode *Reader_read(char *input) { 896 word pos = 0; 897 return read_rec(input, &pos); 898} 899 900// End Reader 901 902// Transformer 903 904ASTNode *operand1(ASTNode *args) { return AST_pair_car(args); } 905 906ASTNode *operand2(ASTNode *args) { return AST_pair_car(AST_pair_cdr(args)); } 907 908ASTNode *operand3(ASTNode *args) { 909 return AST_pair_car(AST_pair_cdr(AST_pair_cdr(args))); 910} 911 912static word gensym_idx = 0; 913 914word gensym_next() { return gensym_idx++; } 915 916void gensym_reset() { gensym_idx = 0; } 917 918const char *gensym() { 919 char buf[128]; 920 snprintf(buf, sizeof buf, "f%ld", gensym_next()); 921 return strdup(buf); 922} 923 924bool set_contains(ASTNode *set, const char *name) { 925 if (AST_is_nil(set)) { 926 return false; 927 } 928 assert(AST_is_pair(set)); 929 ASTNode *elt = AST_pair_car(set); 930 if (AST_symbol_matches(elt, name)) { 931 return true; 932 } 933 return set_contains(AST_pair_cdr(set), name); 934} 935 936ASTNode *set_merge(ASTNode *left, ASTNode *right) { 937 if (AST_is_nil(left)) { 938 return right; 939 } 940 ASTNode *elt = AST_pair_car(left); 941 ASTNode *rest = AST_pair_cdr(left); 942 const char *name = AST_symbol_cstr(elt); 943 if (set_contains(rest, name) || set_contains(right, name)) { 944 return set_merge(rest, right); 945 } 946 return AST_new_pair(elt, set_merge(AST_pair_cdr(left), right)); 947} 948 949typedef ASTNode *MapFunction(ASTNode *node); 950 951ASTNode *map(MapFunction fn, ASTNode *node) { 952 if (AST_is_nil(node)) { 953 return node; 954 } 955 ASTNode *elt = AST_pair_car(node); 956 return AST_new_pair((*fn)(elt), map(fn, AST_pair_cdr(node))); 957} 958 959ASTNode *free_in_rec(ASTNode *node, ASTNode *bound) { 960 if (AST_is_integer(node) || AST_is_char(node) || AST_is_bool(node) || 961 AST_is_nil(node)) { 962 // Nothing free; nothing referenced 963 return AST_nil(); 964 } 965 if (AST_is_symbol(node)) { 966 if (AST_symbol_matches(node, "if") || AST_symbol_matches(node, "let") || 967 AST_symbol_matches(node, "lambda") || 968 AST_symbol_matches(node, "closure") || 969 AST_symbol_matches(node, "quote") || AST_symbol_matches(node, "+") || 970 AST_symbol_matches(node, "apply")) { 971 // Nothing free; special names are not variable references 972 return AST_nil(); 973 } 974 if (set_contains(bound, AST_symbol_cstr(node))) { 975 // Nothing free; name is bound 976 return AST_nil(); 977 } 978 return AST_new_pair(node, AST_nil()); 979 } 980 assert(AST_is_pair(node)); 981 ASTNode *callable = AST_pair_car(node); 982 ASTNode *args = AST_pair_cdr(node); 983 if (AST_is_symbol(callable)) { 984 // Handle special forms that bind variables 985 if (AST_symbol_matches(callable, "let")) { 986 ASTNode *bindings = operand1(args); 987 ASTNode *freevars_bindings = AST_nil(); 988 ASTNode *bindings_names = map(AST_pair_car, bindings); 989 while (!AST_is_nil(bindings)) { 990 ASTNode *binding_value = AST_pair_cdr(AST_pair_car(bindings)); 991 freevars_bindings = 992 set_merge(freevars_bindings, free_in_rec(binding_value, bound)); 993 bindings = AST_pair_cdr(bindings); 994 } 995 ASTNode *body = operand2(args); 996 ASTNode *new_bound = set_merge(bindings_names, bound); 997 ASTNode *freevars_body = free_in_rec(body, new_bound); 998 return set_merge(freevars_bindings, freevars_body); 999 } 1000 if (AST_symbol_matches(callable, "lambda")) { 1001 ASTNode *params = operand1(args); 1002 ASTNode *body = operand2(args); 1003 return free_in_rec(body, set_merge(bound, params)); 1004 } 1005 } 1006 // Handle some call (fn arg0 arg1 ...) 1007 ASTNode *freevars = free_in_rec(callable, bound); 1008 while (!AST_is_nil(args)) { 1009 assert(AST_is_pair(args)); 1010 ASTNode *arg = AST_pair_car(args); 1011 freevars = set_merge(freevars, free_in_rec(arg, bound)); 1012 args = AST_pair_cdr(args); 1013 } 1014 return freevars; 1015} 1016 1017ASTNode *free_in(ASTNode *node) { return free_in_rec(node, AST_nil()); } 1018 1019ASTNode *list1(ASTNode *item0) { return AST_new_pair(item0, AST_nil()); } 1020 1021ASTNode *list2(ASTNode *item0, ASTNode *item1) { 1022 return AST_new_pair(item0, list1(item1)); 1023} 1024 1025ASTNode *list3(ASTNode *item0, ASTNode *item1, ASTNode *item2) { 1026 return AST_new_pair(item0, list2(item1, item2)); 1027} 1028 1029ASTNode *list4(ASTNode *item0, ASTNode *item1, ASTNode *item2, ASTNode *item3) { 1030 return AST_new_pair(item0, list3(item1, item2, item3)); 1031} 1032 1033bool is_tagged_with(ASTNode *node, const char *expected) { 1034 if (!AST_is_pair(node)) { 1035 return false; 1036 } 1037 ASTNode *tag = AST_pair_car(node); 1038 if (!AST_is_symbol(tag)) { 1039 return false; 1040 } 1041 return AST_symbol_matches(tag, expected); 1042} 1043 1044ASTNode *Transform(ASTNode *node); 1045 1046ASTNode *Transform_lambda(ASTNode *node) { 1047 assert(is_tagged_with(node, "lambda")); 1048 ASTNode *args = AST_pair_cdr(node); 1049 ASTNode *params = operand1(args); 1050 ASTNode *body = operand2(args); 1051 ASTNode *freevars = free_in_rec(body, params); 1052 return list4(AST_new_symbol("lambda"), params, freevars, Transform(body)); 1053} 1054 1055ASTNode *Transform_binding(ASTNode *binding) { 1056 ASTNode *name = AST_pair_car(binding); 1057 ASTNode *value = AST_pair_car(AST_pair_cdr(binding)); 1058 return list2(name, Transform(value)); 1059} 1060 1061ASTNode *Transform(ASTNode *node) { 1062 if (AST_is_integer(node) || AST_is_char(node) || AST_is_bool(node) || 1063 AST_is_nil(node) || AST_is_symbol(node)) { 1064 // Nothing to traverse and transform 1065 return node; 1066 } 1067 if (is_tagged_with(node, "lambda")) { 1068 return Transform_lambda(node); 1069 } 1070 if (is_tagged_with(node, "let")) { 1071 ASTNode *args = AST_pair_cdr(node); 1072 ASTNode *bindings = operand1(args); 1073 ASTNode *body = operand2(args); 1074 return list3(AST_pair_car(node), map(Transform_binding, (bindings)), 1075 Transform(body)); 1076 } 1077 return map(Transform, node); 1078} 1079 1080// End Transformer 1081 1082// Env 1083 1084typedef struct Env { 1085 const char *name; 1086 word value; 1087 struct Env *prev; 1088} Env; 1089 1090Env Env_bind(const char *name, word value, Env *prev) { 1091 return (Env){.name = name, .value = value, .prev = prev}; 1092} 1093 1094bool Env_find(Env *env, const char *key, word *result) { 1095 if (env == NULL) 1096 return false; 1097 if (strcmp(env->name, key) == 0) { 1098 *result = env->value; 1099 return true; 1100 } 1101 return Env_find(env->prev, key, result); 1102} 1103 1104// End Env 1105 1106// Compile 1107 1108WARN_UNUSED int Compile_expr(Buffer *buf, ASTNode *node, word stack_index, 1109 Env *varenv, Env *labels); 1110 1111#define _(exp) \ 1112 do { \ 1113 int result = exp; \ 1114 if (result != 0) \ 1115 return result; \ 1116 } while (0) 1117 1118void Compile_compare_imm32(Buffer *buf, int32_t value) { 1119 Emit_cmp_reg_imm32(buf, kRax, value); 1120 Emit_mov_reg_imm32(buf, kRax, 0); 1121 Emit_setcc_imm8(buf, kEqual, kAl); 1122 Emit_shl_reg_imm8(buf, kRax, kBoolShift); 1123 Emit_or_reg_imm8(buf, kRax, kBoolTag); 1124} 1125 1126// This is let, not let*. Therefore we keep track of two environments -- the 1127// parent environment, for evaluating the bindings, and the body environment, 1128// which will have all of the bindings in addition to the parent. This makes 1129// programs like (let ((a 1) (b a)) b) fail. 1130WARN_UNUSED int Compile_let(Buffer *buf, ASTNode *bindings, ASTNode *body, 1131 word stack_index, Env *binding_env, Env *body_env, 1132 Env *labels) { 1133 if (AST_is_nil(bindings)) { 1134 // Base case: no bindings. Compile the body 1135 _(Compile_expr(buf, body, stack_index, body_env, labels)); 1136 return 0; 1137 } 1138 assert(AST_is_pair(bindings)); 1139 // Get the next binding 1140 ASTNode *binding = AST_pair_car(bindings); 1141 ASTNode *name = AST_pair_car(binding); 1142 assert(AST_is_symbol(name)); 1143 ASTNode *binding_expr = AST_pair_car(AST_pair_cdr(binding)); 1144 // Compile the binding expression 1145 _(Compile_expr(buf, binding_expr, stack_index, binding_env, labels)); 1146 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1147 /*src=*/kRax); 1148 // Bind the name 1149 Env entry = Env_bind(AST_symbol_cstr(name), stack_index, body_env); 1150 _(Compile_let(buf, AST_pair_cdr(bindings), body, stack_index - kWordSize, 1151 /*binding_env=*/binding_env, /*body_env=*/&entry, labels)); 1152 return 0; 1153} 1154 1155const int32_t kLabelPlaceholder = 0xdeadbeef; 1156 1157WARN_UNUSED int Compile_if(Buffer *buf, ASTNode *cond, ASTNode *consequent, 1158 ASTNode *alternate, word stack_index, Env *varenv, 1159 Env *labels) { 1160 _(Compile_expr(buf, cond, stack_index, varenv, labels)); 1161 Emit_cmp_reg_imm32(buf, kRax, Object_false()); 1162 word alternate_pos = Emit_jcc(buf, kEqual, kLabelPlaceholder); // je alternate 1163 _(Compile_expr(buf, consequent, stack_index, varenv, labels)); 1164 word end_pos = Emit_jmp(buf, kLabelPlaceholder); // jmp end 1165 Emit_backpatch_imm32(buf, alternate_pos); // alternate: 1166 _(Compile_expr(buf, alternate, stack_index, varenv, labels)); 1167 Emit_backpatch_imm32(buf, end_pos); // end: 1168 return 0; 1169} 1170 1171const Register kHeapPointer = kRsi; 1172const Register kClosurePointer = kRdi; 1173const Register kCodePointer = kRcx; 1174 1175WARN_UNUSED int Compile_cons(Buffer *buf, ASTNode *car, ASTNode *cdr, 1176 word stack_index, Env *varenv, Env *labels) { 1177 // Compile and store car on the stack 1178 _(Compile_expr(buf, car, stack_index, varenv, labels)); 1179 Emit_store_reg_indirect(buf, 1180 /*dst=*/Ind(kRsp, stack_index), 1181 /*src=*/kRax); 1182 // Compile and store cdr 1183 _(Compile_expr(buf, cdr, stack_index - kWordSize, varenv, labels)); 1184 Emit_store_reg_indirect(buf, /*dst=*/Ind(kHeapPointer, kCdrOffset), 1185 /*src=*/kRax); 1186 // Fetch car and store in the heap 1187 Emit_load_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 1188 Emit_store_reg_indirect(buf, /*dst=*/Ind(kHeapPointer, kCarOffset), 1189 /*src=*/kRax); 1190 // Store tagged pointer in rax 1191 // TODO(max): Rewrite as lea rax, [Heap+kPairTag] 1192 Emit_mov_reg_reg(buf, /*dst=*/kRax, /*src=*/kHeapPointer); 1193 Emit_or_reg_imm8(buf, /*dst=*/kRax, kPairTag); 1194 // Bump the heap pointer 1195 Emit_add_reg_imm32(buf, /*dst=*/kHeapPointer, kPairSize); 1196 return 0; 1197} 1198 1199word list_length(ASTNode *node) { 1200 if (AST_is_nil(node)) { 1201 return 0; 1202 } 1203 assert(AST_is_pair(node)); 1204 return 1 + list_length(AST_pair_cdr(node)); 1205} 1206 1207WARN_UNUSED int Compile_funcall(Buffer *buf, ASTNode *callable, ASTNode *args, 1208 word stack_index, Env *varenv, Env *labels, 1209 word closure_index) { 1210 if (AST_is_nil(args)) { 1211 // This should result in a closure 1212 return Compile_expr(buf, callable, stack_index, varenv, labels); 1213 } 1214 assert(AST_is_pair(args)); 1215 ASTNode *arg = AST_pair_car(args); 1216 _(Compile_expr(buf, arg, stack_index, varenv, labels)); 1217 Emit_store_reg_indirect(buf, Ind(kRsp, stack_index), kRax); 1218 return Compile_funcall(buf, callable, AST_pair_cdr(args), 1219 stack_index - kWordSize, varenv, labels, 1220 closure_index); 1221} 1222 1223WARN_UNUSED int Compile_closure(Buffer *buf, ASTNode *freevars, 1224 word stack_index, word closure_index, 1225 Env *varenv, Env *labels) { 1226 if (AST_is_nil(freevars)) { 1227 return 0; 1228 } 1229 assert(AST_is_pair(freevars)); 1230 ASTNode *freevar = AST_pair_car(freevars); 1231 _(Compile_expr(buf, freevar, stack_index, varenv, labels)); 1232 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), /*src=*/kRax); 1233 _(Compile_closure(buf, AST_pair_cdr(freevars), stack_index - kWordSize, 1234 closure_index + kWordSize, varenv, labels)); 1235 Emit_load_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 1236 Emit_store_reg_indirect(buf, /*dst=*/Ind(kHeapPointer, closure_index), 1237 /*src=*/kRax); 1238 return 0; 1239} 1240 1241WARN_UNUSED int Compile_call(Buffer *buf, ASTNode *callable, ASTNode *args, 1242 word stack_index, Env *varenv, Env *labels) { 1243 if (AST_is_symbol(callable)) { 1244 if (AST_symbol_matches(callable, "add1")) { 1245 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1246 Emit_add_reg_imm32(buf, kRax, Object_encode_integer(1)); 1247 return 0; 1248 } 1249 if (AST_symbol_matches(callable, "sub1")) { 1250 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1251 Emit_sub_reg_imm32(buf, kRax, Object_encode_integer(1)); 1252 return 0; 1253 } 1254 if (AST_symbol_matches(callable, "integer->char")) { 1255 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1256 Emit_shl_reg_imm8(buf, kRax, kCharShift - kIntegerShift); 1257 Emit_or_reg_imm8(buf, kRax, kCharTag); 1258 return 0; 1259 } 1260 if (AST_symbol_matches(callable, "char->integer")) { 1261 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1262 Emit_shr_reg_imm8(buf, kRax, kCharShift - kIntegerShift); 1263 return 0; 1264 } 1265 if (AST_symbol_matches(callable, "nil?")) { 1266 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1267 Compile_compare_imm32(buf, Object_nil()); 1268 return 0; 1269 } 1270 if (AST_symbol_matches(callable, "zero?")) { 1271 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1272 Compile_compare_imm32(buf, Object_encode_integer(0)); 1273 return 0; 1274 } 1275 if (AST_symbol_matches(callable, "not")) { 1276 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1277 // All non #f values are truthy 1278 // ...this might be a problem if we want to make nil falsey 1279 Compile_compare_imm32(buf, Object_false()); 1280 return 0; 1281 } 1282 if (AST_symbol_matches(callable, "integer?")) { 1283 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1284 Emit_and_reg_imm8(buf, kRax, kIntegerTagMask); 1285 Compile_compare_imm32(buf, kIntegerTag); 1286 return 0; 1287 } 1288 if (AST_symbol_matches(callable, "boolean?")) { 1289 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1290 Emit_and_reg_imm8(buf, kRax, kImmediateTagMask); 1291 Compile_compare_imm32(buf, kBoolTag); 1292 return 0; 1293 } 1294 if (AST_symbol_matches(callable, "+")) { 1295 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1296 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1297 /*src=*/kRax); 1298 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1299 labels)); 1300 Emit_add_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 1301 return 0; 1302 } 1303 if (AST_symbol_matches(callable, "-")) { 1304 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1305 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1306 /*src=*/kRax); 1307 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1308 labels)); 1309 Emit_sub_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(kRsp, stack_index)); 1310 return 0; 1311 } 1312 if (AST_symbol_matches(callable, "*")) { 1313 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1314 // Remove the tag so that the result is still only tagged with 0b00 1315 // instead of 0b0000 1316 Emit_shr_reg_imm8(buf, kRax, kIntegerShift); 1317 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1318 /*src=*/kRax); 1319 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1320 labels)); 1321 Emit_mul_reg_indirect(buf, /*src=*/Ind(kRsp, stack_index)); 1322 return 0; 1323 } 1324 if (AST_symbol_matches(callable, "=")) { 1325 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1326 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1327 /*src=*/kRax); 1328 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1329 labels)); 1330 Emit_cmp_reg_indirect(buf, kRax, Ind(kRsp, stack_index)); 1331 Emit_mov_reg_imm32(buf, kRax, 0); 1332 Emit_setcc_imm8(buf, kEqual, kAl); 1333 Emit_shl_reg_imm8(buf, kRax, kBoolShift); 1334 Emit_or_reg_imm8(buf, kRax, kBoolTag); 1335 return 0; 1336 } 1337 if (AST_symbol_matches(callable, "<")) { 1338 _(Compile_expr(buf, operand2(args), stack_index, varenv, labels)); 1339 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, stack_index), 1340 /*src=*/kRax); 1341 _(Compile_expr(buf, operand1(args), stack_index - kWordSize, varenv, 1342 labels)); 1343 Emit_cmp_reg_indirect(buf, kRax, Ind(kRsp, stack_index)); 1344 Emit_mov_reg_imm32(buf, kRax, 0); 1345 Emit_setcc_imm8(buf, kLess, kAl); 1346 Emit_shl_reg_imm8(buf, kRax, kBoolShift); 1347 Emit_or_reg_imm8(buf, kRax, kBoolTag); 1348 return 0; 1349 } 1350 if (AST_symbol_matches(callable, "let")) { 1351 return Compile_let(buf, /*bindings=*/operand1(args), 1352 /*body=*/operand2(args), stack_index, 1353 /*binding_env=*/varenv, 1354 /*body_env=*/varenv, labels); 1355 } 1356 if (AST_symbol_matches(callable, "if")) { 1357 return Compile_if(buf, /*condition=*/operand1(args), 1358 /*consequent=*/operand2(args), 1359 /*alternate=*/operand3(args), stack_index, varenv, 1360 labels); 1361 } 1362 if (AST_symbol_matches(callable, "cons")) { 1363 return Compile_cons(buf, /*car=*/operand1(args), /*cdr=*/operand2(args), 1364 stack_index, varenv, labels); 1365 } 1366 if (AST_symbol_matches(callable, "car")) { 1367 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1368 Emit_load_reg_indirect(buf, /*dst=*/kRax, 1369 /*src=*/Ind(kRax, kCarOffset - kPairTag)); 1370 return 0; 1371 } 1372 if (AST_symbol_matches(callable, "cdr")) { 1373 _(Compile_expr(buf, operand1(args), stack_index, varenv, labels)); 1374 Emit_load_reg_indirect(buf, /*dst=*/kRax, 1375 /*src=*/Ind(kRax, kCdrOffset - kPairTag)); 1376 return 0; 1377 } 1378 if (AST_symbol_matches(callable, "closure")) { 1379 // Closures look like (closure label freevar0 freevar1 freevar2 ...) 1380 ASTNode *label = operand1(args); 1381 assert(AST_is_symbol(label)); 1382 word code_address; 1383 if (!Env_find(labels, AST_symbol_cstr(label), &code_address)) { 1384 return -1; 1385 } 1386 ASTNode *freevars = AST_pair_cdr(args); 1387 word num_freevars = list_length(freevars); 1388 // TODO(max): Decide if the entire heap should be parseable, and 1389 // code_address should be encoded as an integer, or if it should just 1390 // be output as-is. 1391 _(Compile_closure(buf, freevars, stack_index, /*closure_index=*/kWordSize, 1392 varenv, labels)); 1393 // Add the code section address to the section offset of the code 1394 Emit_mov_reg_reg(buf, /*dst=*/kRax, /*src=*/kCodePointer); 1395 Emit_add_reg_imm32(buf, /*dst=*/kRax, code_address); 1396 // Closure is now in kHeapPointer; store the code 1397 Emit_store_reg_indirect(buf, 1398 /*dst=*/Ind(kHeapPointer, kClosureLabelOffset), 1399 /*src=*/kRax); 1400 // Tag the pointer in rax 1401 Emit_mov_reg_reg(buf, /*dst=*/kRax, /*src=*/kHeapPointer); 1402 Emit_or_reg_imm8(buf, /*dst=*/kRax, kClosureTag); 1403 Emit_add_reg_imm32(buf, /*dst=*/kHeapPointer, 1404 (num_freevars + 1) * kWordSize); 1405 return 0; 1406 } 1407 } 1408 1409 // * Evaluate all the arguments and save to the stack 1410 // * Save two stack locations: closure pointer, return point 1411 // * Evaluate the callable/operator 1412 // * Save the old value to the stack in current frame (?) 1413 // * Move the callable's closure pointer to rdi 1414 // * Adjust rsp; make sure return point is at [rsp-0] 1415 // * Call closure[label] 1416 // * Adjust rsp 1417 // * Restore calling frame's rdi from stack 1418 1419 // Skip two spaces on the stack to put the return address and closure 1420 // pointer 1421 word closure_stack_index = stack_index; 1422 word return_point_index = closure_stack_index - kWordSize; 1423 word arg_stack_index = return_point_index - kWordSize; 1424 // Compile arguments and callable 1425 _(Compile_funcall(buf, callable, args, arg_stack_index, varenv, labels, 1426 closure_stack_index)); 1427 // Save the current closure pointer to the stack so that it can be restored 1428 // after the call 1429 Emit_store_reg_indirect(buf, /*dst=*/Ind(kRsp, closure_stack_index), 1430 /*src=*/kClosurePointer); 1431 // Set the closure pointer for the new call frame with tag removed 1432 Emit_mov_reg_reg(buf, /*dst=*/kClosurePointer, /*src=*/kRax); 1433 Emit_sub_reg_imm32(buf, kClosurePointer, kClosureTag); 1434 // Put the code pointer in rax so that it can be called 1435 Emit_load_reg_indirect(buf, /*dst=*/kRax, 1436 /*src=*/Ind(kClosurePointer, kClosureLabelOffset)); 1437 // We enter Compile_call with a stack_index pointing to the next 1438 // available spot on the stack, where we will put the closure pointer. We 1439 // need to save the locals on the stack as well as the closure pointer. So 1440 // save everything up to *and* including stack_index. 1441 // [ 24: next available ] <-- closure pointer going here 1442 // [ 16: local ] 1443 // [ 8: local ] 1444 // [ 0: return point ] 1445 // stack_index is at 24 and rsp is at 0. Save all three slots. 1446 Emit_rsp_adjust(buf, stack_index); 1447 Emit_call_reg(buf, kRax); 1448 Emit_rsp_adjust(buf, -stack_index); 1449 // Load the saved closure pointer 1450 Emit_load_reg_indirect(buf, /*dst=*/kClosurePointer, 1451 /*src=*/Ind(kRsp, closure_stack_index)); 1452 return 0; 1453} 1454 1455WARN_UNUSED int Compile_expr(Buffer *buf, ASTNode *node, word stack_index, 1456 Env *varenv, Env *labels) { 1457 if (AST_is_integer(node)) { 1458 word value = AST_get_integer(node); 1459 Emit_mov_reg_imm32(buf, kRax, Object_encode_integer(value)); 1460 return 0; 1461 } 1462 if (AST_is_char(node)) { 1463 char value = AST_get_char(node); 1464 Emit_mov_reg_imm32(buf, kRax, Object_encode_char(value)); 1465 return 0; 1466 } 1467 if (AST_is_bool(node)) { 1468 bool value = AST_get_bool(node); 1469 Emit_mov_reg_imm32(buf, kRax, Object_encode_bool(value)); 1470 return 0; 1471 } 1472 if (AST_is_nil(node)) { 1473 Emit_mov_reg_imm32(buf, kRax, Object_nil()); 1474 return 0; 1475 } 1476 if (AST_is_pair(node)) { 1477 return Compile_call(buf, AST_pair_car(node), AST_pair_cdr(node), 1478 stack_index, varenv, labels); 1479 } 1480 if (AST_is_symbol(node)) { 1481 const char *symbol = AST_symbol_cstr(node); 1482 word offset; 1483 if (Env_find(varenv, symbol, &offset)) { 1484 assert(offset != 0 && "neither stack variables nor closure variables " 1485 "should be at offset 0"); 1486 // If the offset is negative, this is a stack-allocated variable. 1487 // Otherwise, it is a closure-allocated variable. 1488 Register reg = offset < 0 ? kRsp : kClosurePointer; 1489 Emit_load_reg_indirect(buf, /*dst=*/kRax, /*src=*/Ind(reg, offset)); 1490 return 0; 1491 } 1492 return -1; 1493 } 1494 assert(0 && "unexpected node type"); 1495} 1496 1497const byte kEntryPrologue[] = { 1498 // Save the code pointer in rcx, our global code pointer 1499 // mov kCodePointer, rsi 1500 kRexPrefix, 1501 0x8b, 1502 0xce, 1503 // Save the heap in rsi, our global heap pointer 1504 // mov kHeapPointer, rdi 1505 kRexPrefix, 1506 0x89, 1507 0xfe, 1508}; 1509 1510const byte kFunctionEpilogue[] = { 1511 // ret 1512 0xc3, 1513}; 1514 1515WARN_UNUSED int Compile_code_freevars(Buffer *buf, ASTNode *freevars, 1516 ASTNode *body, word stack_index, 1517 word freevar_index, Env *varenv, 1518 Env *labels) { 1519 if (AST_is_nil(freevars)) { 1520 _(Compile_expr(buf, body, stack_index, varenv, labels)); 1521 Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue); 1522 return 0; 1523 } 1524 assert(AST_is_pair(freevars)); 1525 ASTNode *name = AST_pair_car(freevars); 1526 assert(AST_is_symbol(name)); 1527 Env entry = Env_bind(AST_symbol_cstr(name), freevar_index, varenv); 1528 return Compile_code_freevars(buf, AST_pair_cdr(freevars), body, stack_index, 1529 freevar_index + kWordSize, &entry, labels); 1530} 1531 1532WARN_UNUSED int Compile_code_formals(Buffer *buf, ASTNode *formals, 1533 ASTNode *freevars, ASTNode *body, 1534 word stack_index, Env *varenv, 1535 Env *labels) { 1536 if (AST_is_nil(formals)) { 1537 word freevar_index = kWordSize; 1538 return Compile_code_freevars(buf, freevars, body, stack_index, 1539 freevar_index, varenv, labels); 1540 } 1541 assert(AST_is_pair(formals)); 1542 ASTNode *name = AST_pair_car(formals); 1543 assert(AST_is_symbol(name)); 1544 Env entry = Env_bind(AST_symbol_cstr(name), stack_index, varenv); 1545 return Compile_code_formals(buf, AST_pair_cdr(formals), freevars, body, 1546 stack_index - kWordSize, &entry, labels); 1547} 1548 1549WARN_UNUSED int Compile_code(Buffer *buf, ASTNode *code, Env *labels) { 1550 assert(AST_is_pair(code)); 1551 ASTNode *code_sym = AST_pair_car(code); 1552 assert(AST_is_symbol(code_sym)); 1553 assert(AST_symbol_matches(code_sym, "code")); 1554 ASTNode *args = AST_pair_cdr(code); 1555 ASTNode *formals = operand1(args); 1556 ASTNode *freevars = operand2(args); 1557 ASTNode *code_body = operand3(args); 1558 return Compile_code_formals(buf, formals, freevars, code_body, 1559 /*stack_index=*/-kWordSize, 1560 /*varenv=*/NULL, labels); 1561} 1562 1563WARN_UNUSED int Compile_labels(Buffer *buf, ASTNode *bindings, ASTNode *body, 1564 Env *labels) { 1565 if (AST_is_nil(bindings)) { 1566 buf->entrypoint = Buffer_len(buf); 1567 // Base case: no bindings. Compile the body 1568 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 1569 _(Compile_expr(buf, body, /*stack_index=*/-kWordSize, /*varenv=*/NULL, 1570 labels)); 1571 Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue); 1572 return 0; 1573 } 1574 assert(AST_is_pair(bindings)); 1575 // Get the next binding 1576 ASTNode *binding = AST_pair_car(bindings); 1577 ASTNode *name = AST_pair_car(binding); 1578 assert(AST_is_symbol(name)); 1579 ASTNode *binding_code = AST_pair_car(AST_pair_cdr(binding)); 1580 word function_location = Buffer_len(buf); 1581 // Bind the name to the location in the instruction stream 1582 Env entry = Env_bind(AST_symbol_cstr(name), function_location, labels); 1583 // Compile the binding function 1584 _(Compile_code(buf, binding_code, &entry)); 1585 return Compile_labels(buf, AST_pair_cdr(bindings), body, &entry); 1586} 1587 1588WARN_UNUSED int Compile_entry(Buffer *buf, ASTNode *node) { 1589 assert(AST_is_pair(node) && "program must have labels"); 1590 // Assume it's (labels ...) 1591 ASTNode *labels_sym = AST_pair_car(node); 1592 assert(AST_is_symbol(labels_sym) && "program must have labels"); 1593 assert(AST_symbol_matches(labels_sym, "labels") && 1594 "program must have labels"); 1595 ASTNode *args = AST_pair_cdr(node); 1596 ASTNode *bindings = operand1(args); 1597 assert(AST_is_pair(bindings) || AST_is_nil(bindings)); 1598 ASTNode *body = operand2(args); 1599 return Compile_labels(buf, bindings, body, /*labels=*/NULL); 1600} 1601 1602// End Compile 1603 1604typedef uword (*JitFunction)(uword *heap, byte *code); 1605 1606// Testing 1607 1608uword Testing_execute_entry(Buffer *buf, uword *heap) { 1609 assert(buf != NULL); 1610 assert(buf->address != NULL); 1611 assert(buf->state == kExecutable); 1612 // The pointer-pointer cast is allowed but the underlying 1613 // data-to-function-pointer back-and-forth is only guaranteed to work on 1614 // POSIX systems (because of eg dlsym). 1615 byte *start_address = buf->address + buf->entrypoint; 1616 JitFunction function = *(JitFunction *)(&start_address); 1617 return function(heap, buf->address); 1618} 1619 1620uword Testing_execute_expr(Buffer *buf) { 1621 return Testing_execute_entry(buf, /*heap=*/NULL); 1622} 1623 1624TEST Testing_expect_entry_has_contents(Buffer *buf, byte *arr, 1625 size_t arr_size) { 1626 word total_size = sizeof kEntryPrologue + arr_size + sizeof kFunctionEpilogue; 1627 ASSERT_EQ_FMT(total_size, Buffer_len(buf), "%ld"); 1628 1629 byte *ptr = buf->address; 1630 ASSERT_MEM_EQ(kEntryPrologue, ptr, sizeof kEntryPrologue); 1631 ptr += sizeof kEntryPrologue; 1632 ASSERT_MEM_EQ(arr, ptr, arr_size); 1633 ptr += arr_size; 1634 ASSERT_MEM_EQ(kFunctionEpilogue, ptr, sizeof kFunctionEpilogue); 1635 ptr += sizeof kFunctionEpilogue; 1636 PASS(); 1637} 1638 1639WARN_UNUSED int Testing_compile_expr_entry(Buffer *buf, ASTNode *node) { 1640 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 1641 _(Compile_expr(buf, node, /*stack_index=*/-kWordSize, /*varenv=*/NULL, 1642 /*labels=*/NULL)); 1643 Buffer_write_arr(buf, kFunctionEpilogue, sizeof kFunctionEpilogue); 1644 return 0; 1645} 1646 1647#define EXPECT_EQUALS_BYTES(buf, arr) \ 1648 ASSERT_EQ_FMT(sizeof arr, Buffer_len(buf), "%ld"); \ 1649 ASSERT_MEM_EQ(arr, (buf)->address, sizeof arr) 1650 1651#define EXPECT_ENTRY_CONTAINS_CODE(buf, arr) \ 1652 CHECK_CALL(Testing_expect_entry_has_contents(buf, arr, sizeof arr)) 1653 1654#define RUN_BUFFER_TEST(test_name) \ 1655 do { \ 1656 Buffer buf; \ 1657 Buffer_init(&buf, 1); \ 1658 GREATEST_RUN_TEST1(test_name, &buf); \ 1659 Buffer_deinit(&buf); \ 1660 } while (0) 1661 1662#define RUN_HEAP_TEST(test_name) \ 1663 do { \ 1664 Buffer buf; \ 1665 Buffer_init(&buf, 1); \ 1666 uword *heap = malloc(1000 * kWordSize); \ 1667 GREATEST_RUN_TESTp(test_name, &buf, heap); \ 1668 free(heap); \ 1669 Buffer_deinit(&buf); \ 1670 } while (0) 1671 1672ASTNode *new_unary_call(const char *name, ASTNode *arg) { 1673 return list2(AST_new_symbol(name), arg); 1674} 1675 1676ASTNode *new_binary_call(const char *name, ASTNode *arg0, ASTNode *arg1) { 1677 return list3(AST_new_symbol(name), arg0, arg1); 1678} 1679 1680// End Testing 1681 1682// Tests 1683 1684TEST encode_positive_integer(void) { 1685 ASSERT_EQ(Object_encode_integer(0), 0x0); 1686 ASSERT_EQ(Object_encode_integer(1), 0x4); 1687 ASSERT_EQ(Object_encode_integer(10), 0x28); 1688 PASS(); 1689} 1690 1691TEST encode_negative_integer(void) { 1692 ASSERT_EQ(Object_encode_integer(0), 0x0); 1693 ASSERT_EQ(Object_encode_integer(-1), 0xfffffffffffffffc); 1694 ASSERT_EQ(Object_encode_integer(-10), 0xffffffffffffffd8); 1695 PASS(); 1696} 1697 1698TEST encode_char(void) { 1699 ASSERT_EQ(Object_encode_char('\0'), 0xf); 1700 ASSERT_EQ(Object_encode_char('a'), 0x610f); 1701 PASS(); 1702} 1703 1704TEST decode_char(void) { 1705 ASSERT_EQ(Object_decode_char(0xf), '\0'); 1706 ASSERT_EQ(Object_decode_char(0x610f), 'a'); 1707 PASS(); 1708} 1709 1710TEST encode_bool(void) { 1711 ASSERT_EQ(Object_encode_bool(true), 0x9f); 1712 ASSERT_EQ(Object_encode_bool(false), 0x1f); 1713 ASSERT_EQ(Object_true(), 0x9f); 1714 ASSERT_EQ(Object_false(), 0x1f); 1715 PASS(); 1716} 1717 1718TEST decode_bool(void) { 1719 ASSERT_EQ(Object_decode_bool(0x9f), true); 1720 ASSERT_EQ(Object_decode_bool(0x1f), false); 1721 PASS(); 1722} 1723 1724TEST address(void) { 1725 ASSERT_EQ(Object_address((void *)0xFF01), 0xFF00); 1726 PASS(); 1727} 1728 1729TEST emit_mov_reg_imm32_emits_modrm(Buffer *buf) { 1730 Emit_mov_reg_imm32(buf, kRax, 100); 1731 byte expected[] = {0x48, 0xc7, 0xc0, 0x64, 0x00, 0x00, 0x00}; 1732 EXPECT_EQUALS_BYTES(buf, expected); 1733 ASSERT_EQ_FMT(modrm(kModDirect, kRax, 0), 0xc0, "0x%.2x"); 1734 PASS(); 1735} 1736 1737TEST emit_store_reg_indirect_emits_modrm_sib(Buffer *buf) { 1738 Emit_store_reg_indirect(buf, Ind(kRsp, -8), kRax); 1739 byte expected[] = {0x48, 0x89, 0x44, 0x24, 0xf8}; 1740 EXPECT_EQUALS_BYTES(buf, expected); 1741 ASSERT_EQ_FMT(modrm(kModDisp8, kIndexNone, kRax), 0x44, "0x%.2x"); 1742 ASSERT_EQ_FMT(sib(kRsp, kIndexNone, Scale1), 0x24, "0x%.2x"); 1743 PASS(); 1744} 1745 1746TEST ast_new_pair(void) { 1747 ASTNode *node = AST_new_pair(NULL, NULL); 1748 ASSERT(AST_is_pair(node)); 1749 AST_heap_free(node); 1750 PASS(); 1751} 1752 1753TEST ast_pair_car_returns_car(void) { 1754 ASTNode *node = AST_new_pair(AST_new_integer(123), NULL); 1755 ASTNode *car = AST_pair_car(node); 1756 ASSERT(AST_is_integer(car)); 1757 ASSERT_EQ(Object_decode_integer((uword)car), 123); 1758 AST_heap_free(node); 1759 PASS(); 1760} 1761 1762TEST ast_pair_cdr_returns_cdr(void) { 1763 ASTNode *node = AST_new_pair(NULL, AST_new_integer(123)); 1764 ASTNode *cdr = AST_pair_cdr(node); 1765 ASSERT(AST_is_integer(cdr)); 1766 ASSERT_EQ(Object_decode_integer((uword)cdr), 123); 1767 AST_heap_free(node); 1768 PASS(); 1769} 1770 1771TEST ast_new_symbol(void) { 1772 const char *value = "my symbol"; 1773 ASTNode *node = AST_new_symbol(value); 1774 ASSERT(AST_is_symbol(node)); 1775 ASSERT_STR_EQ(AST_symbol_cstr(node), value); 1776 AST_heap_free(node); 1777 PASS(); 1778} 1779 1780#define ASSERT_IS_CHAR_EQ(node, c) \ 1781 do { \ 1782 ASTNode *__tmp = node; \ 1783 if (AST_is_error(__tmp)) { \ 1784 fprintf(stderr, "Expected a char but got an error.\n"); \ 1785 } \ 1786 ASSERT(AST_is_char(__tmp)); \ 1787 ASSERT_EQ(AST_get_char(__tmp), c); \ 1788 } while (0); 1789 1790#define ASSERT_IS_INT_EQ(node, val) \ 1791 do { \ 1792 ASTNode *__tmp = node; \ 1793 if (AST_is_error(__tmp)) { \ 1794 fprintf(stderr, "Expected an int but got an error.\n"); \ 1795 } \ 1796 ASSERT(AST_is_integer(__tmp)); \ 1797 ASSERT_EQ(AST_get_integer(__tmp), val); \ 1798 } while (0); 1799 1800#define ASSERT_IS_SYM_EQ(node, cstr) \ 1801 do { \ 1802 ASTNode *__tmp = node; \ 1803 if (AST_is_error(__tmp)) { \ 1804 fprintf(stderr, "Expected a symbol but got an error.\n"); \ 1805 } \ 1806 ASSERT(AST_is_symbol(__tmp)); \ 1807 ASSERT_STR_EQ(AST_symbol_cstr(__tmp), cstr); \ 1808 } while (0); 1809 1810TEST read_with_integer_returns_integer(void) { 1811 char *input = "1234"; 1812 ASTNode *node = Reader_read(input); 1813 ASSERT_IS_INT_EQ(node, 1234); 1814 AST_heap_free(node); 1815 PASS(); 1816} 1817 1818TEST read_with_negative_integer_returns_integer(void) { 1819 char *input = "-1234"; 1820 ASTNode *node = Reader_read(input); 1821 ASSERT_IS_INT_EQ(node, -1234); 1822 AST_heap_free(node); 1823 PASS(); 1824} 1825 1826TEST read_with_positive_integer_returns_integer(void) { 1827 char *input = "+1234"; 1828 ASTNode *node = Reader_read(input); 1829 ASSERT_IS_INT_EQ(node, 1234); 1830 AST_heap_free(node); 1831 PASS(); 1832} 1833 1834TEST read_with_leading_whitespace_ignores_whitespace(void) { 1835 char *input = " \t \n 1234"; 1836 ASTNode *node = Reader_read(input); 1837 ASSERT_IS_INT_EQ(node, 1234); 1838 AST_heap_free(node); 1839 PASS(); 1840} 1841 1842TEST read_with_symbol_returns_symbol(void) { 1843 char *input = "hello?+-*=>"; 1844 ASTNode *node = Reader_read(input); 1845 ASSERT_IS_SYM_EQ(node, "hello?+-*=>"); 1846 AST_heap_free(node); 1847 PASS(); 1848} 1849 1850TEST read_with_symbol_with_trailing_digits(void) { 1851 char *input = "add1 1"; 1852 ASTNode *node = Reader_read(input); 1853 ASSERT_IS_SYM_EQ(node, "add1"); 1854 AST_heap_free(node); 1855 PASS(); 1856} 1857 1858TEST read_with_char_returns_char(void) { 1859 char *input = "'a'"; 1860 ASTNode *node = Reader_read(input); 1861 ASSERT_IS_CHAR_EQ(node, 'a'); 1862 ASSERT(AST_is_error(Reader_read("''"))); 1863 ASSERT(AST_is_error(Reader_read("'aa'"))); 1864 ASSERT(AST_is_error(Reader_read("'aa"))); 1865 AST_heap_free(node); 1866 PASS(); 1867} 1868 1869TEST read_with_bool_returns_bool(void) { 1870 ASSERT_EQ(Reader_read("#t"), AST_new_bool(true)); 1871 ASSERT_EQ(Reader_read("#f"), AST_new_bool(false)); 1872 ASSERT(AST_is_error(Reader_read("#"))); 1873 ASSERT(AST_is_error(Reader_read("#x"))); 1874 ASSERT(AST_is_error(Reader_read("##"))); 1875 PASS(); 1876} 1877 1878TEST read_with_nil_returns_nil(void) { 1879 char *input = "()"; 1880 ASTNode *node = Reader_read(input); 1881 ASSERT(AST_is_nil(node)); 1882 AST_heap_free(node); 1883 PASS(); 1884} 1885 1886TEST read_with_list_returns_list(void) { 1887 char *input = "( 1 2 0 )"; 1888 ASTNode *node = Reader_read(input); 1889 ASSERT(AST_is_pair(node)); 1890 ASSERT_IS_INT_EQ(AST_pair_car(node), 1); 1891 ASSERT_IS_INT_EQ(AST_pair_car(AST_pair_cdr(node)), 2); 1892 ASSERT_IS_INT_EQ(AST_pair_car(AST_pair_cdr(AST_pair_cdr(node))), 0); 1893 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(AST_pair_cdr(node))))); 1894 AST_heap_free(node); 1895 PASS(); 1896} 1897 1898TEST read_with_nested_list_returns_list(void) { 1899 char *input = "((hello world) (foo bar))"; 1900 ASTNode *node = Reader_read(input); 1901 ASSERT(AST_is_pair(node)); 1902 ASTNode *first = AST_pair_car(node); 1903 ASSERT(AST_is_pair(first)); 1904 ASSERT_IS_SYM_EQ(AST_pair_car(first), "hello"); 1905 ASSERT_IS_SYM_EQ(AST_pair_car(AST_pair_cdr(first)), "world"); 1906 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(first)))); 1907 ASTNode *second = AST_pair_car(AST_pair_cdr(node)); 1908 ASSERT(AST_is_pair(second)); 1909 ASSERT_IS_SYM_EQ(AST_pair_car(second), "foo"); 1910 ASSERT_IS_SYM_EQ(AST_pair_car(AST_pair_cdr(second)), "bar"); 1911 ASSERT(AST_is_nil(AST_pair_cdr(AST_pair_cdr(second)))); 1912 AST_heap_free(node); 1913 PASS(); 1914} 1915 1916TEST buffer_write8_increases_length(Buffer *buf) { 1917 ASSERT_EQ(Buffer_len(buf), 0); 1918 Buffer_write8(buf, 0xdb); 1919 ASSERT_EQ(Buffer_at8(buf, 0), 0xdb); 1920 ASSERT_EQ(Buffer_len(buf), 1); 1921 PASS(); 1922} 1923 1924TEST buffer_write8_expands_buffer(void) { 1925 Buffer buf; 1926 Buffer_init(&buf, 1); 1927 ASSERT_EQ(buf.capacity, 1); 1928 ASSERT_EQ(buf.len, 0); 1929 Buffer_write8(&buf, 0xdb); 1930 Buffer_write8(&buf, 0xef); 1931 ASSERT(buf.capacity > 1); 1932 ASSERT_EQ(buf.len, 2); 1933 Buffer_deinit(&buf); 1934 PASS(); 1935} 1936 1937TEST buffer_write32_expands_buffer(void) { 1938 Buffer buf; 1939 Buffer_init(&buf, 1); 1940 ASSERT_EQ(buf.capacity, 1); 1941 ASSERT_EQ(buf.len, 0); 1942 Buffer_write32(&buf, 0xdeadbeef); 1943 ASSERT(buf.capacity > 1); 1944 ASSERT_EQ(buf.len, 4); 1945 Buffer_deinit(&buf); 1946 PASS(); 1947} 1948 1949TEST buffer_write32_writes_little_endian(Buffer *buf) { 1950 Buffer_write32(buf, 0xdeadbeef); 1951 ASSERT_EQ(Buffer_at8(buf, 0), 0xef); 1952 ASSERT_EQ(Buffer_at8(buf, 1), 0xbe); 1953 ASSERT_EQ(Buffer_at8(buf, 2), 0xad); 1954 ASSERT_EQ(Buffer_at8(buf, 3), 0xde); 1955 PASS(); 1956} 1957 1958TEST compile_positive_integer(Buffer *buf) { 1959 word value = 123; 1960 ASTNode *node = AST_new_integer(value); 1961 int compile_result = Testing_compile_expr_entry(buf, node); 1962 ASSERT_EQ(compile_result, 0); 1963 // mov eax, imm(123) 1964 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00}; 1965 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1966 Buffer_make_executable(buf); 1967 uword result = Testing_execute_expr(buf); 1968 ASSERT_EQ(result, Object_encode_integer(value)); 1969 PASS(); 1970} 1971 1972TEST compile_negative_integer(Buffer *buf) { 1973 word value = -123; 1974 ASTNode *node = AST_new_integer(value); 1975 int compile_result = Testing_compile_expr_entry(buf, node); 1976 ASSERT_EQ(compile_result, 0); 1977 // mov eax, imm(-123) 1978 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0xfe, 0xff, 0xff}; 1979 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1980 Buffer_make_executable(buf); 1981 uword result = Testing_execute_expr(buf); 1982 ASSERT_EQ(result, Object_encode_integer(value)); 1983 PASS(); 1984} 1985 1986TEST compile_char(Buffer *buf) { 1987 char value = 'a'; 1988 ASTNode *node = AST_new_char(value); 1989 int compile_result = Testing_compile_expr_entry(buf, node); 1990 ASSERT_EQ(compile_result, 0); 1991 // mov eax, imm('a') 1992 byte expected[] = {0x48, 0xc7, 0xc0, 0x0f, 0x61, 0x00, 0x00}; 1993 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 1994 Buffer_make_executable(buf); 1995 uword result = Testing_execute_expr(buf); 1996 ASSERT_EQ(result, Object_encode_char(value)); 1997 PASS(); 1998} 1999 2000TEST compile_true(Buffer *buf) { 2001 ASTNode *node = AST_new_bool(true); 2002 int compile_result = Testing_compile_expr_entry(buf, node); 2003 ASSERT_EQ(compile_result, 0); 2004 // mov eax, imm(true) 2005 byte expected[] = {0x48, 0xc7, 0xc0, 0x9f, 0x0, 0x0, 0x0}; 2006 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2007 Buffer_make_executable(buf); 2008 uword result = Testing_execute_expr(buf); 2009 ASSERT_EQ(result, Object_true()); 2010 PASS(); 2011} 2012 2013TEST compile_false(Buffer *buf) { 2014 ASTNode *node = AST_new_bool(false); 2015 int compile_result = Testing_compile_expr_entry(buf, node); 2016 ASSERT_EQ(compile_result, 0); 2017 // mov eax, imm(false) 2018 byte expected[] = {0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00}; 2019 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2020 Buffer_make_executable(buf); 2021 uword result = Testing_execute_expr(buf); 2022 ASSERT_EQ(result, Object_false()); 2023 PASS(); 2024} 2025 2026TEST compile_nil(Buffer *buf) { 2027 ASTNode *node = AST_nil(); 2028 int compile_result = Testing_compile_expr_entry(buf, node); 2029 ASSERT_EQ(compile_result, 0); 2030 // mov eax, imm(nil) 2031 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00}; 2032 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2033 Buffer_make_executable(buf); 2034 uword result = Testing_execute_expr(buf); 2035 ASSERT_EQ(result, Object_nil()); 2036 PASS(); 2037} 2038 2039TEST compile_unary_add1(Buffer *buf) { 2040 ASTNode *node = new_unary_call("add1", AST_new_integer(123)); 2041 int compile_result = Testing_compile_expr_entry(buf, node); 2042 ASSERT_EQ(compile_result, 0); 2043 // mov rax, imm(123); add rax, imm(1) 2044 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 2045 0x48, 0x05, 0x04, 0x00, 0x00, 0x00}; 2046 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2047 Buffer_make_executable(buf); 2048 uword result = Testing_execute_expr(buf); 2049 ASSERT_EQ(result, Object_encode_integer(124)); 2050 AST_heap_free(node); 2051 PASS(); 2052} 2053 2054TEST compile_unary_add1_nested(Buffer *buf) { 2055 ASTNode *node = 2056 new_unary_call("add1", new_unary_call("add1", AST_new_integer(123))); 2057 int compile_result = Testing_compile_expr_entry(buf, node); 2058 ASSERT_EQ(compile_result, 0); 2059 // mov rax, imm(123); add rax, imm(1); add rax, imm(1) 2060 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 0x48, 0x05, 0x04, 2061 0x00, 0x00, 0x00, 0x48, 0x05, 0x04, 0x00, 0x00, 0x00}; 2062 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2063 Buffer_make_executable(buf); 2064 uword result = Testing_execute_expr(buf); 2065 ASSERT_EQ(result, Object_encode_integer(125)); 2066 AST_heap_free(node); 2067 PASS(); 2068} 2069 2070TEST compile_unary_sub1(Buffer *buf) { 2071 ASTNode *node = new_unary_call("sub1", AST_new_integer(123)); 2072 int compile_result = Testing_compile_expr_entry(buf, node); 2073 ASSERT_EQ(compile_result, 0); 2074 // mov rax, imm(123); sub rax, imm(1) 2075 byte expected[] = {0x48, 0xc7, 0xc0, 0xec, 0x01, 0x00, 0x00, 2076 0x48, 0x2d, 0x04, 0x00, 0x00, 0x00}; 2077 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2078 Buffer_make_executable(buf); 2079 uword result = Testing_execute_expr(buf); 2080 ASSERT_EQ(result, Object_encode_integer(122)); 2081 AST_heap_free(node); 2082 PASS(); 2083} 2084 2085TEST compile_unary_integer_to_char(Buffer *buf) { 2086 ASTNode *node = new_unary_call("integer->char", AST_new_integer(97)); 2087 int compile_result = Testing_compile_expr_entry(buf, node); 2088 ASSERT_EQ(compile_result, 0); 2089 // mov rax, imm(97); shl rax, 6; or rax, 0xf 2090 byte expected[] = {0x48, 0xc7, 0xc0, 0x84, 0x01, 0x00, 0x00, 0x48, 2091 0xc1, 0xe0, 0x06, 0x48, 0x83, 0xc8, 0x0f}; 2092 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2093 Buffer_make_executable(buf); 2094 uword result = Testing_execute_expr(buf); 2095 ASSERT_EQ(result, Object_encode_char('a')); 2096 AST_heap_free(node); 2097 PASS(); 2098} 2099 2100TEST compile_unary_char_to_integer(Buffer *buf) { 2101 ASTNode *node = new_unary_call("char->integer", AST_new_char('a')); 2102 int compile_result = Testing_compile_expr_entry(buf, node); 2103 ASSERT_EQ(compile_result, 0); 2104 // mov rax, imm('a'); shr rax, 6 2105 byte expected[] = {0x48, 0xc7, 0xc0, 0x0f, 0x61, 0x00, 2106 0x00, 0x48, 0xc1, 0xe8, 0x06}; 2107 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2108 Buffer_make_executable(buf); 2109 uword result = Testing_execute_expr(buf); 2110 ASSERT_EQ(result, Object_encode_integer(97)); 2111 AST_heap_free(node); 2112 PASS(); 2113} 2114 2115TEST compile_unary_nilp_with_nil_returns_true(Buffer *buf) { 2116 ASTNode *node = new_unary_call("nil?", AST_nil()); 2117 int compile_result = Testing_compile_expr_entry(buf, node); 2118 ASSERT_EQ(compile_result, 0); 2119 // 0: 48 c7 c0 2f 00 00 00 mov rax,0x2f 2120 // 7: 48 3d 2f 00 00 00 cmp rax,0x0000002f 2121 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2122 // 14: 0f 94 c0 sete al 2123 // 17: 48 c1 e0 07 shl rax,0x7 2124 // 1b: 48 83 c8 1f or rax,0x1f 2125 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00, 0x48, 2126 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2127 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2128 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_true()); 2133 AST_heap_free(node); 2134 PASS(); 2135} 2136 2137TEST compile_unary_nilp_with_non_nil_returns_false(Buffer *buf) { 2138 ASTNode *node = new_unary_call("nil?", AST_new_integer(5)); 2139 int compile_result = Testing_compile_expr_entry(buf, node); 2140 ASSERT_EQ(compile_result, 0); 2141 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2142 // 7: 48 3d 2f 00 00 00 cmp rax,0x0000002f 2143 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2144 // 14: 0f 94 c0 sete al 2145 // 17: 48 c1 e0 07 shl rax,0x7 2146 // 1b: 48 83 c8 1f or rax,0x1f 2147 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 2148 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2149 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2150 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2151 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2152 Buffer_make_executable(buf); 2153 uword result = Testing_execute_expr(buf); 2154 ASSERT_EQ(result, Object_false()); 2155 AST_heap_free(node); 2156 PASS(); 2157} 2158 2159TEST compile_unary_zerop_with_zero_returns_true(Buffer *buf) { 2160 ASTNode *node = new_unary_call("zero?", AST_new_integer(0)); 2161 int compile_result = Testing_compile_expr_entry(buf, node); 2162 ASSERT_EQ(compile_result, 0); 2163 // 0: 48 c7 c0 00 00 00 00 mov rax,0x0 2164 // 7: 48 3d 00 00 00 00 cmp rax,0x00000000 2165 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2166 // 14: 0f 94 c0 sete al 2167 // 17: 48 c1 e0 07 shl rax,0x7 2168 // 1b: 48 83 c8 1f or rax,0x1f 2169 byte expected[] = {0x48, 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x48, 2170 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2171 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2172 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2173 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2174 Buffer_make_executable(buf); 2175 uword result = Testing_execute_expr(buf); 2176 ASSERT_EQ(result, Object_true()); 2177 AST_heap_free(node); 2178 PASS(); 2179} 2180 2181TEST compile_unary_zerop_with_non_zero_returns_false(Buffer *buf) { 2182 ASTNode *node = new_unary_call("zero?", AST_new_integer(5)); 2183 int compile_result = Testing_compile_expr_entry(buf, node); 2184 ASSERT_EQ(compile_result, 0); 2185 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2186 // 7: 48 3d 00 00 00 00 cmp rax,0x00000000 2187 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2188 // 14: 0f 94 c0 sete al 2189 // 17: 48 c1 e0 07 shl rax,0x7 2190 // 1b: 48 83 c8 1f or rax,0x1f 2191 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 2192 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2193 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2194 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2195 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2196 Buffer_make_executable(buf); 2197 uword result = Testing_execute_expr(buf); 2198 ASSERT_EQ(result, Object_false()); 2199 AST_heap_free(node); 2200 PASS(); 2201} 2202 2203TEST compile_unary_not_with_false_returns_true(Buffer *buf) { 2204 ASTNode *node = new_unary_call("not", AST_new_bool(false)); 2205 int compile_result = Testing_compile_expr_entry(buf, node); 2206 ASSERT_EQ(compile_result, 0); 2207 // 0: 48 c7 c0 1f 00 00 00 mov rax,0x1f 2208 // 7: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2209 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2210 // 14: 0f 94 c0 sete al 2211 // 17: 48 c1 e0 07 shl rax,0x7 2212 // 1b: 48 83 c8 1f or rax,0x1f 2213 byte expected[] = {0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x48, 2214 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2215 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2216 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2217 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2218 Buffer_make_executable(buf); 2219 uword result = Testing_execute_expr(buf); 2220 ASSERT_EQ(result, Object_true()); 2221 AST_heap_free(node); 2222 PASS(); 2223} 2224 2225TEST compile_unary_not_with_non_false_returns_false(Buffer *buf) { 2226 ASTNode *node = new_unary_call("not", AST_new_integer(5)); 2227 int compile_result = Testing_compile_expr_entry(buf, node); 2228 ASSERT_EQ(compile_result, 0); 2229 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2230 // 7: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2231 // d: 48 c7 c0 00 00 00 00 mov rax,0x0 2232 // 14: 0f 94 c0 sete al 2233 // 17: 48 c1 e0 07 shl rax,0x7 2234 // 1b: 48 83 c8 1f or rax,0x1f 2235 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 2236 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 2237 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 0x48, 2238 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2239 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2240 Buffer_make_executable(buf); 2241 uword result = Testing_execute_expr(buf); 2242 ASSERT_EQ(result, Object_false()); 2243 AST_heap_free(node); 2244 PASS(); 2245} 2246 2247TEST compile_unary_integerp_with_integer_returns_true(Buffer *buf) { 2248 ASTNode *node = new_unary_call("integer?", AST_new_integer(5)); 2249 int compile_result = Testing_compile_expr_entry(buf, node); 2250 ASSERT_EQ(compile_result, 0); 2251 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2252 // 7: 48 83 e0 03 and rax,0x3 2253 // b: 48 3d 00 00 00 00 cmp rax,0x00000000 2254 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2255 // 18: 0f 94 c0 sete al 2256 // 1b: 48 c1 e0 07 shl rax,0x7 2257 // 1f: 48 83 c8 1f or rax,0x1f 2258 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 0x83, 2259 0xe0, 0x03, 0x48, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 2260 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2261 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2262 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2263 Buffer_make_executable(buf); 2264 uword result = Testing_execute_expr(buf); 2265 ASSERT_EQ(result, Object_true()); 2266 AST_heap_free(node); 2267 PASS(); 2268} 2269 2270TEST compile_unary_integerp_with_non_integer_returns_false(Buffer *buf) { 2271 ASTNode *node = new_unary_call("integer?", AST_nil()); 2272 int compile_result = Testing_compile_expr_entry(buf, node); 2273 ASSERT_EQ(compile_result, 0); 2274 // 0: 48 c7 c0 2f 00 00 00 mov rax,0x2f 2275 // 7: 48 83 e0 03 and rax,0x3 2276 // b: 48 3d 00 00 00 00 cmp rax,0x00000000 2277 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2278 // 18: 0f 94 c0 sete al 2279 // 1b: 48 c1 e0 07 shl rax,0x7 2280 // 1f: 48 83 c8 1f or rax,0x1f 2281 byte expected[] = {0x48, 0xc7, 0xc0, 0x2f, 0x00, 0x00, 0x00, 0x48, 0x83, 2282 0xe0, 0x03, 0x48, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x48, 2283 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2284 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2285 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2286 Buffer_make_executable(buf); 2287 uword result = Testing_execute_expr(buf); 2288 ASSERT_EQ(result, Object_false()); 2289 AST_heap_free(node); 2290 PASS(); 2291} 2292 2293TEST compile_unary_booleanp_with_boolean_returns_true(Buffer *buf) { 2294 ASTNode *node = new_unary_call("boolean?", AST_new_bool(true)); 2295 int compile_result = Testing_compile_expr_entry(buf, node); 2296 ASSERT_EQ(compile_result, 0); 2297 // 0: 48 c7 c0 9f 00 00 00 mov rax,0x9f 2298 // 7: 48 83 e0 3f and rax,0x3f 2299 // b: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2300 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2301 // 18: 0f 94 c0 sete al 2302 // 1b: 48 c1 e0 07 shl rax,0x7 2303 // 1f: 48 83 c8 1f or rax,0x1f 2304 byte expected[] = {0x48, 0xc7, 0xc0, 0x9f, 0x00, 0x00, 0x00, 0x48, 0x83, 2305 0xe0, 0x3f, 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 2306 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2307 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2308 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2309 Buffer_make_executable(buf); 2310 uword result = Testing_execute_expr(buf); 2311 ASSERT_EQ(result, Object_true()); 2312 AST_heap_free(node); 2313 PASS(); 2314} 2315 2316TEST compile_unary_booleanp_with_non_boolean_returns_false(Buffer *buf) { 2317 ASTNode *node = new_unary_call("boolean?", AST_new_integer(5)); 2318 int compile_result = Testing_compile_expr_entry(buf, node); 2319 ASSERT_EQ(compile_result, 0); 2320 // 0: 48 c7 c0 14 00 00 00 mov rax,0x14 2321 // 7: 48 83 e0 3f and rax,0x3f 2322 // b: 48 3d 1f 00 00 00 cmp rax,0x0000001f 2323 // 11: 48 c7 c0 00 00 00 00 mov rax,0x0 2324 // 18: 0f 94 c0 sete al 2325 // 1b: 48 c1 e0 07 shl rax,0x7 2326 // 1f: 48 83 c8 1f or rax,0x1f 2327 byte expected[] = {0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 0x48, 0x83, 2328 0xe0, 0x3f, 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 0x48, 2329 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x94, 0xc0, 2330 0x48, 0xc1, 0xe0, 0x07, 0x48, 0x83, 0xc8, 0x1f}; 2331 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2332 Buffer_make_executable(buf); 2333 uword result = Testing_execute_expr(buf); 2334 ASSERT_EQ(result, Object_false()); 2335 AST_heap_free(node); 2336 PASS(); 2337} 2338 2339TEST compile_binary_plus(Buffer *buf) { 2340 ASTNode *node = new_binary_call("+", AST_new_integer(5), AST_new_integer(8)); 2341 int compile_result = Testing_compile_expr_entry(buf, node); 2342 ASSERT_EQ(compile_result, 0); 2343 byte expected[] = { 2344 // 0: 48 c7 c0 20 00 00 00 mov rax,0x20 2345 0x48, 0xc7, 0xc0, 0x20, 0x00, 0x00, 0x00, 2346 // 7: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2347 0x48, 0x89, 0x44, 0x24, 0xf8, 2348 // b: 48 c7 c0 14 00 00 00 mov rax,0x14 2349 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2350 // 12: 48 03 45 f8 add rax,QWORD PTR [rsp-0x8] 2351 0x48, 0x03, 0x44, 0x24, 0xf8}; 2352 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2353 Buffer_make_executable(buf); 2354 uword result = Testing_execute_expr(buf); 2355 ASSERT_EQ(result, Object_encode_integer(13)); 2356 AST_heap_free(node); 2357 PASS(); 2358} 2359 2360TEST compile_binary_plus_nested(Buffer *buf) { 2361 ASTNode *node = new_binary_call( 2362 "+", new_binary_call("+", AST_new_integer(1), AST_new_integer(2)), 2363 new_binary_call("+", AST_new_integer(3), AST_new_integer(4))); 2364 int compile_result = Testing_compile_expr_entry(buf, node); 2365 ASSERT_EQ(compile_result, 0); 2366 byte expected[] = { 2367 // 4: 48 c7 c0 10 00 00 00 mov rax,0x10 2368 0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00, 2369 // b: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2370 0x48, 0x89, 0x44, 0x24, 0xf8, 2371 // f: 48 c7 c0 0c 00 00 00 mov rax,0xc 2372 0x48, 0xc7, 0xc0, 0x0c, 0x00, 0x00, 0x00, 2373 // 16: 48 03 45 f8 add rax,QWORD PTR [rsp-0x8] 2374 0x48, 0x03, 0x44, 0x24, 0xf8, 2375 // 1a: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2376 0x48, 0x89, 0x44, 0x24, 0xf8, 2377 // 1e: 48 c7 c0 08 00 00 00 mov rax,0x8 2378 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2379 // 25: 48 89 45 f0 mov QWORD PTR [rsp-0x10],rax 2380 0x48, 0x89, 0x44, 0x24, 0xf0, 2381 // 29: 48 c7 c0 04 00 00 00 mov rax,0x4 2382 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2383 // 30: 48 03 45 f0 add rax,QWORD PTR [rsp-0x10] 2384 0x48, 0x03, 0x44, 0x24, 0xf0, 2385 // 34: 48 03 45 f8 add rax,QWORD PTR [rsp-0x8] 2386 0x48, 0x03, 0x44, 0x24, 0xf8}; 2387 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2388 Buffer_make_executable(buf); 2389 uword result = Testing_execute_expr(buf); 2390 ASSERT_EQ(result, Object_encode_integer(10)); 2391 AST_heap_free(node); 2392 PASS(); 2393} 2394 2395TEST compile_binary_minus(Buffer *buf) { 2396 ASTNode *node = new_binary_call("-", AST_new_integer(5), AST_new_integer(8)); 2397 int compile_result = Testing_compile_expr_entry(buf, node); 2398 ASSERT_EQ(compile_result, 0); 2399 byte expected[] = { 2400 // 0: 48 c7 c0 20 00 00 00 mov rax,0x20 2401 0x48, 0xc7, 0xc0, 0x20, 0x00, 0x00, 0x00, 2402 // 7: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2403 0x48, 0x89, 0x44, 0x24, 0xf8, 2404 // b: 48 c7 c0 14 00 00 00 mov rax,0x14 2405 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2406 // 12: 48 2b 45 f8 add rax,QWORD PTR [rsp-0x8] 2407 0x48, 0x2b, 0x44, 0x24, 0xf8}; 2408 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2409 Buffer_make_executable(buf); 2410 uword result = Testing_execute_expr(buf); 2411 ASSERT_EQ(result, Object_encode_integer(-3)); 2412 AST_heap_free(node); 2413 PASS(); 2414} 2415 2416TEST compile_binary_minus_nested(Buffer *buf) { 2417 ASTNode *node = new_binary_call( 2418 "-", new_binary_call("-", AST_new_integer(5), AST_new_integer(1)), 2419 new_binary_call("-", AST_new_integer(4), AST_new_integer(3))); 2420 int compile_result = Testing_compile_expr_entry(buf, node); 2421 ASSERT_EQ(compile_result, 0); 2422 byte expected[] = { 2423 // 4: 48 c7 c0 0c 00 00 00 mov rax,0xc 2424 0x48, 0xc7, 0xc0, 0x0c, 0x00, 0x00, 0x00, 2425 // b: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2426 0x48, 0x89, 0x44, 0x24, 0xf8, 2427 // f: 48 c7 c0 10 00 00 00 mov rax,0x10 2428 0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00, 2429 // 16: 48 2b 45 f8 add rax,QWORD PTR [rsp-0x8] 2430 0x48, 0x2b, 0x44, 0x24, 0xf8, 2431 // 1a: 48 89 45 f8 mov QWORD PTR [rsp-0x8],rax 2432 0x48, 0x89, 0x44, 0x24, 0xf8, 2433 // 1e: 48 c7 c0 04 00 00 00 mov rax,0x4 2434 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2435 // 25: 48 89 45 f0 mov QWORD PTR [rsp-0x10],rax 2436 0x48, 0x89, 0x44, 0x24, 0xf0, 2437 // 29: 48 c7 c0 14 00 00 00 mov rax,0x14 2438 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2439 // 30: 48 2b 45 f0 add rax,QWORD PTR [rsp-0x10] 2440 0x48, 0x2b, 0x44, 0x24, 0xf0, 2441 // 34: 48 2b 45 f8 add rax,QWORD PTR [rsp-0x8] 2442 0x48, 0x2b, 0x44, 0x24, 0xf8}; 2443 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2444 Buffer_make_executable(buf); 2445 uword result = Testing_execute_expr(buf); 2446 ASSERT_EQ(result, Object_encode_integer(3)); 2447 AST_heap_free(node); 2448 PASS(); 2449} 2450 2451TEST compile_binary_mul(Buffer *buf) { 2452 ASTNode *node = new_binary_call("*", AST_new_integer(5), AST_new_integer(8)); 2453 int compile_result = Testing_compile_expr_entry(buf, node); 2454 ASSERT_EQ(compile_result, 0); 2455 Buffer_make_executable(buf); 2456 uword result = Testing_execute_expr(buf); 2457 ASSERT_EQ_FMT(Object_encode_integer(40), result, "0x%lx"); 2458 AST_heap_free(node); 2459 PASS(); 2460} 2461 2462TEST compile_binary_mul_nested(Buffer *buf) { 2463 ASTNode *node = new_binary_call( 2464 "*", new_binary_call("*", AST_new_integer(1), AST_new_integer(2)), 2465 new_binary_call("*", AST_new_integer(3), AST_new_integer(4))); 2466 int compile_result = Testing_compile_expr_entry(buf, node); 2467 ASSERT_EQ(compile_result, 0); 2468 Buffer_make_executable(buf); 2469 uword result = Testing_execute_expr(buf); 2470 ASSERT_EQ_FMT(Object_encode_integer(24), result, "0x%lx"); 2471 AST_heap_free(node); 2472 PASS(); 2473} 2474 2475TEST compile_binary_eq_with_same_address_returns_true(Buffer *buf) { 2476 ASTNode *node = new_binary_call("=", AST_new_integer(5), AST_new_integer(5)); 2477 int compile_result = Testing_compile_expr_entry(buf, node); 2478 ASSERT_EQ(compile_result, 0); 2479 Buffer_make_executable(buf); 2480 uword result = Testing_execute_expr(buf); 2481 ASSERT_EQ_FMT(Object_true(), result, "0x%lx"); 2482 AST_heap_free(node); 2483 PASS(); 2484} 2485 2486TEST compile_binary_eq_with_different_address_returns_false(Buffer *buf) { 2487 ASTNode *node = new_binary_call("=", AST_new_integer(5), AST_new_integer(4)); 2488 int compile_result = Testing_compile_expr_entry(buf, node); 2489 ASSERT_EQ(compile_result, 0); 2490 Buffer_make_executable(buf); 2491 uword result = Testing_execute_expr(buf); 2492 ASSERT_EQ_FMT(Object_false(), result, "0x%lx"); 2493 AST_heap_free(node); 2494 PASS(); 2495} 2496 2497TEST compile_binary_lt_with_left_less_than_right_returns_true(Buffer *buf) { 2498 ASTNode *node = new_binary_call("<", AST_new_integer(-5), AST_new_integer(5)); 2499 int compile_result = Testing_compile_expr_entry(buf, node); 2500 ASSERT_EQ(compile_result, 0); 2501 Buffer_make_executable(buf); 2502 uword result = Testing_execute_expr(buf); 2503 ASSERT_EQ_FMT(Object_true(), result, "0x%lx"); 2504 AST_heap_free(node); 2505 PASS(); 2506} 2507 2508TEST compile_binary_lt_with_left_equal_to_right_returns_false(Buffer *buf) { 2509 ASTNode *node = new_binary_call("<", AST_new_integer(5), AST_new_integer(5)); 2510 int compile_result = Testing_compile_expr_entry(buf, node); 2511 ASSERT_EQ(compile_result, 0); 2512 Buffer_make_executable(buf); 2513 uword result = Testing_execute_expr(buf); 2514 ASSERT_EQ_FMT(Object_false(), result, "0x%lx"); 2515 AST_heap_free(node); 2516 PASS(); 2517} 2518 2519TEST compile_binary_lt_with_left_greater_than_right_returns_false(Buffer *buf) { 2520 ASTNode *node = new_binary_call("<", AST_new_integer(6), AST_new_integer(5)); 2521 int compile_result = Testing_compile_expr_entry(buf, node); 2522 ASSERT_EQ(compile_result, 0); 2523 Buffer_make_executable(buf); 2524 uword result = Testing_execute_expr(buf); 2525 ASSERT_EQ_FMT(Object_false(), result, "0x%lx"); 2526 AST_heap_free(node); 2527 PASS(); 2528} 2529 2530TEST compile_symbol_in_env_returns_value(Buffer *buf) { 2531 ASTNode *node = AST_new_symbol("hello"); 2532 Env env0 = Env_bind("hello", -33, /*prev=*/NULL); 2533 Env env1 = Env_bind("world", -66, &env0); 2534 int compile_result = 2535 Compile_expr(buf, node, -kWordSize, &env1, /*labels=*/NULL); 2536 ASSERT_EQ(compile_result, 0); 2537 byte expected[] = {// mov rax, [rsp-33] 2538 0x48, 0x8b, 0x44, 0x24, 0x100 - 33}; 2539 EXPECT_EQUALS_BYTES(buf, expected); 2540 AST_heap_free(node); 2541 PASS(); 2542} 2543 2544TEST compile_symbol_in_closure_returns_value(Buffer *buf) { 2545 ASTNode *node = AST_new_symbol("hello"); 2546 Env env0 = Env_bind("hello", 33, /*prev=*/NULL); 2547 Env env1 = Env_bind("world", 66, &env0); 2548 int compile_result = 2549 Compile_expr(buf, node, -kWordSize, &env1, /*labels=*/NULL); 2550 ASSERT_EQ(compile_result, 0); 2551 byte expected[] = {// mov rax, [Closure+33] 2552 0x48, 0x8b, 0x47, 33}; 2553 EXPECT_EQUALS_BYTES(buf, expected); 2554 AST_heap_free(node); 2555 PASS(); 2556} 2557 2558TEST compile_symbol_in_env_returns_first_value(Buffer *buf) { 2559 ASTNode *node = AST_new_symbol("hello"); 2560 Env env0 = Env_bind("hello", -55, /*prev=*/NULL); 2561 Env env1 = Env_bind("hello", -66, &env0); 2562 int compile_result = 2563 Compile_expr(buf, node, -kWordSize, &env1, /*labels=*/NULL); 2564 ASSERT_EQ(compile_result, 0); 2565 byte expected[] = {// mov rax, [rsp-66] 2566 0x48, 0x8b, 0x44, 0x24, 0x100 - 66}; 2567 EXPECT_EQUALS_BYTES(buf, expected); 2568 AST_heap_free(node); 2569 PASS(); 2570} 2571 2572TEST compile_symbol_not_in_env_raises_compile_error(Buffer *buf) { 2573 ASTNode *node = AST_new_symbol("hello"); 2574 int compile_result = 2575 Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL, /*labels=*/NULL); 2576 ASSERT_EQ(compile_result, -1); 2577 AST_heap_free(node); 2578 PASS(); 2579} 2580 2581TEST compile_let_with_no_bindings(Buffer *buf) { 2582 ASTNode *node = Reader_read("(let () (+ 1 2))"); 2583 int compile_result = Testing_compile_expr_entry(buf, node); 2584 ASSERT_EQ(compile_result, 0); 2585 Buffer_make_executable(buf); 2586 uword result = Testing_execute_expr(buf); 2587 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2588 AST_heap_free(node); 2589 PASS(); 2590} 2591 2592TEST compile_let_with_one_binding(Buffer *buf) { 2593 ASTNode *node = Reader_read("(let ((a 1)) (+ a 2))"); 2594 int compile_result = Testing_compile_expr_entry(buf, node); 2595 ASSERT_EQ(compile_result, 0); 2596 Buffer_make_executable(buf); 2597 uword result = Testing_execute_expr(buf); 2598 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2599 AST_heap_free(node); 2600 PASS(); 2601} 2602 2603TEST compile_let_with_multiple_bindings(Buffer *buf) { 2604 ASTNode *node = Reader_read("(let ((a 1) (b 2)) (+ a b))"); 2605 int compile_result = Testing_compile_expr_entry(buf, node); 2606 ASSERT_EQ(compile_result, 0); 2607 Buffer_make_executable(buf); 2608 uword result = Testing_execute_expr(buf); 2609 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2610 AST_heap_free(node); 2611 PASS(); 2612} 2613 2614TEST compile_nested_let(Buffer *buf) { 2615 ASTNode *node = Reader_read("(let ((a 1)) (let ((b 2)) (+ a b)))"); 2616 int compile_result = Testing_compile_expr_entry(buf, node); 2617 ASSERT_EQ(compile_result, 0); 2618 Buffer_make_executable(buf); 2619 uword result = Testing_execute_expr(buf); 2620 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 2621 AST_heap_free(node); 2622 PASS(); 2623} 2624 2625TEST compile_let_is_not_let_star(Buffer *buf) { 2626 ASTNode *node = Reader_read("(let ((a 1) (b a)) a)"); 2627 int compile_result = Testing_compile_expr_entry(buf, node); 2628 ASSERT_EQ(compile_result, -1); 2629 AST_heap_free(node); 2630 PASS(); 2631} 2632 2633TEST compile_if_with_true_cond(Buffer *buf) { 2634 ASTNode *node = Reader_read("(if #t 1 2)"); 2635 int compile_result = Testing_compile_expr_entry(buf, node); 2636 ASSERT_EQ(compile_result, 0); 2637 byte expected[] = { 2638 // mov rax, 0x9f 2639 0x48, 0xc7, 0xc0, 0x9f, 0x00, 0x00, 0x00, 2640 // cmp rax, 0x1f 2641 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 2642 // je alternate 2643 0x0f, 0x84, 0x0c, 0x00, 0x00, 0x00, 2644 // mov rax, compile(1) 2645 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2646 // jmp end 2647 0xe9, 0x07, 0x00, 0x00, 0x00, 2648 // alternate: 2649 // mov rax, compile(2) 2650 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00 2651 // end: 2652 }; 2653 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2654 Buffer_make_executable(buf); 2655 uword result = Testing_execute_expr(buf); 2656 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2657 AST_heap_free(node); 2658 PASS(); 2659} 2660 2661TEST compile_if_with_false_cond(Buffer *buf) { 2662 ASTNode *node = Reader_read("(if #f 1 2)"); 2663 int compile_result = Testing_compile_expr_entry(buf, node); 2664 ASSERT_EQ(compile_result, 0); 2665 byte expected[] = { 2666 // mov rax, 0x1f 2667 0x48, 0xc7, 0xc0, 0x1f, 0x00, 0x00, 0x00, 2668 // cmp rax, 0x1f 2669 0x48, 0x3d, 0x1f, 0x00, 0x00, 0x00, 2670 // je alternate 2671 0x0f, 0x84, 0x0c, 0x00, 0x00, 0x00, 2672 // mov rax, compile(1) 2673 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2674 // jmp end 2675 0xe9, 0x07, 0x00, 0x00, 0x00, 2676 // alternate: 2677 // mov rax, compile(2) 2678 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00 2679 // end: 2680 }; 2681 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2682 Buffer_make_executable(buf); 2683 uword result = Testing_execute_expr(buf); 2684 ASSERT_EQ_FMT(Object_encode_integer(2), result, "0x%lx"); 2685 AST_heap_free(node); 2686 PASS(); 2687} 2688 2689TEST compile_nested_if(Buffer *buf) { 2690 ASTNode *node = Reader_read("(if (< 1 2) (if #f 3 4) 5)"); 2691 int compile_result = Testing_compile_expr_entry(buf, node); 2692 ASSERT_EQ(compile_result, 0); 2693 Buffer_make_executable(buf); 2694 uword result = Testing_execute_expr(buf); 2695 ASSERT_EQ_FMT(Object_encode_integer(4), result, "0x%lx"); 2696 AST_heap_free(node); 2697 PASS(); 2698} 2699 2700TEST compile_cons(Buffer *buf, uword *heap) { 2701 ASTNode *node = Reader_read("(cons 1 2)"); 2702 int compile_result = Testing_compile_expr_entry(buf, node); 2703 ASSERT_EQ(compile_result, 0); 2704 // clang-format off 2705 byte expected[] = { 2706 // mov rax, 0x2 2707 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2708 // mov [rsp-8], rax 2709 0x48, 0x89, 0x44, 0x24, 0xf8, 2710 // mov rax, 0x4 2711 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2712 // mov [Heap+Cdr], rax 2713 0x48, 0x89, 0x46, 0x08, 2714 // mov rax, [rsp-8] 2715 0x48, 0x8b, 0x44, 0x24, 0xf8, 2716 // mov [Heap+Car], rax 2717 0x48, 0x89, 0x46, 0x00, 2718 // mov rax, Heap 2719 0x48, 0x89, 0xf0, 2720 // or rax, kPairTag 2721 0x48, 0x83, 0xc8, 0x01, 2722 // add Heap, 2*kWordSize 2723 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 2724 }; 2725 // clang-format on 2726 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2727 Buffer_make_executable(buf); 2728 uword result = Testing_execute_entry(buf, heap); 2729 ASSERT(Object_is_pair(result)); 2730 ASSERT_EQ_FMT(Object_encode_integer(1), Object_pair_car(result), "0x%lx"); 2731 ASSERT_EQ_FMT(Object_encode_integer(2), Object_pair_cdr(result), "0x%lx"); 2732 AST_heap_free(node); 2733 PASS(); 2734} 2735 2736TEST compile_two_cons(Buffer *buf, uword *heap) { 2737 ASTNode *node = Reader_read( 2738 "(let ((a (cons 1 2)) (b (cons 3 4))) (cons (cdr a) (cdr b)))"); 2739 int compile_result = Testing_compile_expr_entry(buf, node); 2740 ASSERT_EQ(compile_result, 0); 2741 Buffer_make_executable(buf); 2742 uword result = Testing_execute_entry(buf, heap); 2743 ASSERT(Object_is_pair(result)); 2744 ASSERT_EQ_FMT(Object_encode_integer(2), Object_pair_car(result), "0x%lx"); 2745 ASSERT_EQ_FMT(Object_encode_integer(4), Object_pair_cdr(result), "0x%lx"); 2746 AST_heap_free(node); 2747 PASS(); 2748} 2749 2750TEST compile_nested_cons(Buffer *buf, uword *heap) { 2751 ASTNode *node = Reader_read("(cons (cons 1 2) (cons 3 4))"); 2752 int compile_result = Testing_compile_expr_entry(buf, node); 2753 ASSERT_EQ(compile_result, 0); 2754 Buffer_make_executable(buf); 2755 uword result = Testing_execute_entry(buf, heap); 2756 ASSERT(Object_is_pair(result)); 2757 ASSERT(Object_is_pair(Object_pair_car(result))); 2758 ASSERT_EQ_FMT(Object_encode_integer(1), 2759 Object_pair_car(Object_pair_car(result)), "0x%lx"); 2760 ASSERT_EQ_FMT(Object_encode_integer(2), 2761 Object_pair_cdr(Object_pair_car(result)), "0x%lx"); 2762 ASSERT(Object_is_pair(Object_pair_cdr(result))); 2763 ASSERT_EQ_FMT(Object_encode_integer(3), 2764 Object_pair_car(Object_pair_cdr(result)), "0x%lx"); 2765 ASSERT_EQ_FMT(Object_encode_integer(4), 2766 Object_pair_cdr(Object_pair_cdr(result)), "0x%lx"); 2767 AST_heap_free(node); 2768 PASS(); 2769} 2770 2771TEST compile_car(Buffer *buf, uword *heap) { 2772 ASTNode *node = Reader_read("(car (cons 1 2))"); 2773 int compile_result = Testing_compile_expr_entry(buf, node); 2774 ASSERT_EQ(compile_result, 0); 2775 // clang-format off 2776 byte expected[] = { 2777 // mov rax, 0x2 2778 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2779 // mov [rsp-8], rax 2780 0x48, 0x89, 0x44, 0x24, 0xf8, 2781 // mov rax, 0x4 2782 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2783 // mov [Heap+Cdr], rax 2784 0x48, 0x89, 0x46, 0x08, 2785 // mov rax, [rsp-8] 2786 0x48, 0x8b, 0x44, 0x24, 0xf8, 2787 // mov [Heap+Car], rax 2788 0x48, 0x89, 0x46, 0x00, 2789 // mov rax, Heap 2790 0x48, 0x89, 0xf0, 2791 // or rax, kPairTag 2792 0x48, 0x83, 0xc8, 0x01, 2793 // add Heap, 2*kWordSize 2794 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 2795 // mov rax, [rax-1] 2796 0x48, 0x8b, 0x40, 0xff, 2797 }; 2798 // clang-format on 2799 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2800 Buffer_make_executable(buf); 2801 uword result = Testing_execute_entry(buf, heap); 2802 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2803 AST_heap_free(node); 2804 PASS(); 2805} 2806 2807TEST compile_cdr(Buffer *buf, uword *heap) { 2808 ASTNode *node = Reader_read("(cdr (cons 1 2))"); 2809 int compile_result = Testing_compile_expr_entry(buf, node); 2810 ASSERT_EQ(compile_result, 0); 2811 // clang-format off 2812 byte expected[] = { 2813 // mov rax, 0x2 2814 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2815 // mov [rsp-8], rax 2816 0x48, 0x89, 0x44, 0x24, 0xf8, 2817 // mov rax, 0x4 2818 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 2819 // mov [Heap+Cdr], rax 2820 0x48, 0x89, 0x46, 0x08, 2821 // mov rax, [rsp-8] 2822 0x48, 0x8b, 0x44, 0x24, 0xf8, 2823 // mov [Heap+Car], rax 2824 0x48, 0x89, 0x46, 0x00, 2825 // mov rax, Heap 2826 0x48, 0x89, 0xf0, 2827 // or rax, kPairTag 2828 0x48, 0x83, 0xc8, 0x01, 2829 // add Heap, 2*kWordSize 2830 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 2831 // mov rax, [rax+7] 2832 0x48, 0x8b, 0x40, 0x07, 2833 }; 2834 // clang-format on 2835 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 2836 Buffer_make_executable(buf); 2837 uword result = Testing_execute_entry(buf, heap); 2838 ASSERT_EQ_FMT(Object_encode_integer(2), result, "0x%lx"); 2839 AST_heap_free(node); 2840 PASS(); 2841} 2842 2843TEST compile_code_with_no_params(Buffer *buf) { 2844 ASTNode *node = Reader_read("(code () () 1)"); 2845 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2846 ASSERT_EQ(compile_result, 0); 2847 // clang-format off 2848 byte expected[] = { 2849 // mov rax, 0x2 2850 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2851 // ret 2852 0xc3, 2853 }; 2854 // clang-format on 2855 EXPECT_EQUALS_BYTES(buf, expected); 2856 Buffer_make_executable(buf); 2857 uword result = Testing_execute_expr(buf); 2858 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2859 AST_heap_free(node); 2860 PASS(); 2861} 2862 2863TEST compile_code_with_one_param(Buffer *buf) { 2864 ASTNode *node = Reader_read("(code (x) () x)"); 2865 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2866 ASSERT_EQ(compile_result, 0); 2867 // clang-format off 2868 byte expected[] = { 2869 // mov rax, [rsp-8] 2870 0x48, 0x8b, 0x44, 0x24, 0xf8, 2871 // ret 2872 0xc3, 2873 }; 2874 // clang-format on 2875 EXPECT_EQUALS_BYTES(buf, expected); 2876 AST_heap_free(node); 2877 PASS(); 2878} 2879 2880TEST compile_code_with_one_freevar(Buffer *buf) { 2881 ASTNode *node = Reader_read("(code () (x) x)"); 2882 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2883 ASSERT_EQ(compile_result, 0); 2884 // clang-format off 2885 byte expected[] = { 2886 // mov rax, [Closure+8] 2887 0x48, 0x8b, 0x47, 0x08, 2888 // ret 2889 0xc3, 2890 }; 2891 // clang-format on 2892 EXPECT_EQUALS_BYTES(buf, expected); 2893 AST_heap_free(node); 2894 PASS(); 2895} 2896 2897TEST compile_code_with_two_params(Buffer *buf) { 2898 ASTNode *node = Reader_read("(code (x y) () (+ x y))"); 2899 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2900 ASSERT_EQ(compile_result, 0); 2901 // clang-format off 2902 byte expected[] = { 2903 // mov rax, [rsp-16] 2904 0x48, 0x8b, 0x44, 0x24, 0xf0, 2905 // mov [rsp-24], rax 2906 0x48, 0x89, 0x44, 0x24, 0xe8, 2907 // mov rax, [rsp-8] 2908 0x48, 0x8b, 0x44, 0x24, 0xf8, 2909 // add rax, [rsp-24] 2910 0x48, 0x03, 0x44, 0x24, 0xe8, 2911 // ret 2912 0xc3, 2913 }; 2914 // clang-format on 2915 EXPECT_EQUALS_BYTES(buf, expected); 2916 AST_heap_free(node); 2917 PASS(); 2918} 2919 2920TEST compile_code_with_two_freevars(Buffer *buf) { 2921 ASTNode *node = Reader_read("(code () (x y) (+ x y))"); 2922 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2923 ASSERT_EQ(compile_result, 0); 2924 // clang-format off 2925 byte expected[] = { 2926 // mov rax, [Closure+16] 2927 0x48, 0x8b, 0x47, 0x10, 2928 // mov [rsp-8], rax 2929 0x48, 0x89, 0x44, 0x24, 0xf8, 2930 // mov rax, [Closure+8] 2931 0x48, 0x8b, 0x47, 0x08, 2932 // add rax, [rsp-8] 2933 0x48, 0x03, 0x44, 0x24, 0xf8, 2934 // ret 2935 0xc3, 2936 }; 2937 // clang-format on 2938 EXPECT_EQUALS_BYTES(buf, expected); 2939 AST_heap_free(node); 2940 PASS(); 2941} 2942 2943TEST compile_code_with_params_and_freevars(Buffer *buf) { 2944 ASTNode *node = Reader_read("(code (x) (y) (+ x y))"); 2945 int compile_result = Compile_code(buf, node, /*labels=*/NULL); 2946 ASSERT_EQ(compile_result, 0); 2947 // clang-format off 2948 byte expected[] = { 2949 // mov rax, [Closure+8] 2950 0x48, 0x8b, 0x47, 0x08, 2951 // mov [rsp-16], rax 2952 0x48, 0x89, 0x44, 0x24, 0xf0, 2953 // mov rax, [rsp-8] 2954 0x48, 0x8b, 0x44, 0x24, 0xf8, 2955 // add rax, [rsp-16] 2956 0x48, 0x03, 0x44, 0x24, 0xf0, 2957 // ret 2958 0xc3, 2959 }; 2960 // clang-format on 2961 EXPECT_EQUALS_BYTES(buf, expected); 2962 AST_heap_free(node); 2963 PASS(); 2964} 2965 2966TEST compile_labels_with_no_labels(Buffer *buf) { 2967 ASTNode *node = Reader_read("(labels () 1)"); 2968 int compile_result = Compile_entry(buf, node); 2969 ASSERT_EQ(compile_result, 0); 2970 // clang-format off 2971 byte expected[] = { 2972 // mov Code, rsi 2973 0x48, 0x8b, 0xce, 2974 // mov Heap, rdi 2975 0x48, 0x89, 0xfe, 2976 // mov rax, 0x2 2977 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 2978 // ret 2979 0xc3, 2980 }; 2981 // clang-format on 2982 EXPECT_EQUALS_BYTES(buf, expected); 2983 Buffer_make_executable(buf); 2984 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 2985 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 2986 AST_heap_free(node); 2987 PASS(); 2988} 2989 2990TEST compile_labels_with_one_label(Buffer *buf) { 2991 ASTNode *node = Reader_read("(labels ((const (code () () 5))) 1)"); 2992 int compile_result = Compile_entry(buf, node); 2993 ASSERT_EQ(compile_result, 0); 2994 // clang-format off 2995 byte expected[] = { 2996 // mov rax, compile(5) 2997 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 2998 // ret 2999 0xc3, 3000 // mov Code, rsi 3001 0x48, 0x8b, 0xce, 3002 // mov Heap, rdi 3003 0x48, 0x89, 0xfe, 3004 // mov rax, 0x2 3005 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 3006 // ret 3007 0xc3, 3008 }; 3009 // clang-format on 3010 EXPECT_EQUALS_BYTES(buf, expected); 3011 Buffer_make_executable(buf); 3012 uword result = Testing_execute_entry(buf, /*heap=*/NULL); 3013 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 3014 AST_heap_free(node); 3015 PASS(); 3016} 3017 3018TEST compile_funcall_with_no_params(Buffer *buf, uword *heap) { 3019 ASTNode *node = 3020 Reader_read("(labels ((const (code () () 5))) ((closure const)))"); 3021 int compile_result = Compile_entry(buf, node); 3022 ASSERT_EQ(compile_result, 0); 3023 // clang-format off 3024 byte expected[] = { 3025 // mov rax, compile(5) 3026 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 3027 // ret 3028 0xc3, 3029 // mov Code, rsi 3030 0x48, 0x8b, 0xce, 3031 // mov Heap, rdi 3032 0x48, 0x89, 0xfe, 3033 // mov rax, Code 3034 0x48, 0x89, 0xc8, 3035 // add rax, 0 (code offset) 3036 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, 3037 // mov qword [Heap], rax 3038 0x48, 0x89, 0x46, 0x00, 3039 // mov rax, Heap 3040 0x48, 0x89, 0xf0, 3041 // or rax, 6 3042 0x48, 0x83, 0xc8, 0x06, 3043 // add Heap, 0x8 (label + 0 freevars) 3044 0x48, 0x81, 0xc6, 0x08, 0x00, 0x00, 0x00, 3045 // mov [rsp-8], rdi save closure 3046 0x48, 0x89, 0x7c, 0x24, 0xf8, 3047 // mov rdi, rax 3048 0x48, 0x89, 0xc7, 3049 // sub rdi, 0x6 3050 0x48, 0x81, 0xef, 0x06, 0x00, 0x00, 0x00, 3051 // mov rax, [Closure] closure[label] 3052 0x48, 0x8b, 0x47, 0x00, 3053 // sub rsp, 8 3054 0x48, 0x81, 0xec, 0x08, 0x00, 0x00, 0x00, 3055 // call near rax (const) 3056 0xff, 0xd0, 3057 // add rsp, 8 3058 0x48, 0x81, 0xc4, 0x08, 0x00, 0x00, 0x00, 3059 // mov rdi, [rsp-8] reload closure 3060 0x48, 0x8b, 0x7c, 0x24, 0xf8, 3061 // ret 3062 0xc3, 3063 }; 3064 // clang-format on 3065 EXPECT_EQUALS_BYTES(buf, expected); 3066 Buffer_make_executable(buf); 3067 uword result = Testing_execute_entry(buf, heap); 3068 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 3069 AST_heap_free(node); 3070 PASS(); 3071} 3072 3073TEST compile_funcall_with_no_params_and_locals(Buffer *buf, uword *heap) { 3074 ASTNode *node = Reader_read( 3075 "(labels ((const (code () () 5))) (let ((a 1)) ((closure const))))"); 3076 int compile_result = Compile_entry(buf, node); 3077 ASSERT_EQ(compile_result, 0); 3078 // clang-format off 3079 byte expected[] = { 3080 // mov rax, compile(5) 3081 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 3082 // ret 3083 0xc3, 3084 // mov Code, rsi 3085 0x48, 0x8b, 0xce, 3086 // mov Heap, rdi 3087 0x48, 0x89, 0xfe, 3088 // mov rax, compile(1) 3089 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 3090 // mov [rsp-8], rax 3091 0x48, 0x89, 0x44, 0x24, 0xf8, 3092 // mov rax, Code 3093 0x48, 0x89, 0xc8, 3094 // add rax, 0 (code offset) 3095 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, 3096 // mov qword [Heap], rax 3097 0x48, 0x89, 0x46, 0x00, 3098 // mov rax, Heap 3099 0x48, 0x89, 0xf0, 3100 // or rax, 6 3101 0x48, 0x83, 0xc8, 0x06, 3102 // add Heap, 0x8 (label + 0 freevars) 3103 0x48, 0x81, 0xc6, 0x08, 0x00, 0x00, 0x00, 3104 // mov [rsp-16], rdi save closure 3105 0x48, 0x89, 0x7c, 0x24, 0xf0, 3106 // mov rdi, rax 3107 0x48, 0x89, 0xc7, 3108 // sub rdi, 0x6 3109 0x48, 0x81, 0xef, 0x06, 0x00, 0x00, 0x00, 3110 // mov rax, [Closure] closure[label] 3111 0x48, 0x8b, 0x47, 0x00, 3112 // sub rsp, 16 3113 0x48, 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, 3114 // call near rax (const) 3115 0xff, 0xd0, 3116 // add rsp, 16 3117 0x48, 0x81, 0xc4, 0x10, 0x00, 0x00, 0x00, 3118 // mov rdi, [rsp-16] reload closure 3119 0x48, 0x8b, 0x7c, 0x24, 0xf0, 3120 // ret 3121 0xc3, 3122 }; 3123 // clang-format on 3124 EXPECT_EQUALS_BYTES(buf, expected); 3125 Buffer_make_executable(buf); 3126 uword result = Testing_execute_entry(buf, heap); 3127 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 3128 AST_heap_free(node); 3129 PASS(); 3130} 3131 3132TEST compile_funcall_with_one_param(Buffer *buf, uword *heap) { 3133 ASTNode *node = 3134 Reader_read("(labels ((id (code (x) () x))) ((closure id) 5))"); 3135 int compile_result = Compile_entry(buf, node); 3136 ASSERT_EQ(compile_result, 0); 3137 // clang-format off 3138 byte expected[] = { 3139 // mov rax, [rsp-8] 3140 0x48, 0x8b, 0x44, 0x24, 0xf8, 3141 // ret 3142 0xc3, 3143 // mov Code, rsi 3144 0x48, 0x8b, 0xce, 3145 // mov Heap, rdi 3146 0x48, 0x89, 0xfe, 3147 // mov rax, compile(5) 3148 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 3149 // mov [rsp-24], rax 3150 0x48, 0x89, 0x44, 0x24, 0xe8, 3151 // mov rax, Code 3152 0x48, 0x89, 0xc8, 3153 // add rax, 0 (code offset) 3154 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, 3155 // mov qword [Heap], rax 3156 0x48, 0x89, 0x46, 0x00, 3157 // mov rax, Heap 3158 0x48, 0x89, 0xf0, 3159 // or rax, 6 3160 0x48, 0x83, 0xc8, 0x06, 3161 // add Heap, 0x8 (label + 0 freevars) 3162 0x48, 0x81, 0xc6, 0x08, 0x00, 0x00, 0x00, 3163 // mov [rsp-8], rdi save closure 3164 0x48, 0x89, 0x7c, 0x24, 0xf8, 3165 // mov rdi, rax 3166 0x48, 0x89, 0xc7, 3167 // sub rdi, 0x6 3168 0x48, 0x81, 0xef, 0x06, 0x00, 0x00, 0x00, 3169 // mov rax, [Closure] closure[label] 3170 0x48, 0x8b, 0x47, 0x00, 3171 // sub rsp, 8 3172 0x48, 0x81, 0xec, 0x08, 0x00, 0x00, 0x00, 3173 // call near rax (const) 3174 0xff, 0xd0, 3175 // add rsp, 8 3176 0x48, 0x81, 0xc4, 0x08, 0x00, 0x00, 0x00, 3177 // mov rdi, [rsp-8] reload closure 3178 0x48, 0x8b, 0x7c, 0x24, 0xf8, 3179 // ret 3180 0xc3, 3181 }; 3182 // clang-format on 3183 EXPECT_EQUALS_BYTES(buf, expected); 3184 Buffer_make_executable(buf); 3185 uword result = Testing_execute_entry(buf, heap); 3186 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 3187 AST_heap_free(node); 3188 PASS(); 3189} 3190 3191SUITE(object_tests) { 3192 RUN_TEST(encode_positive_integer); 3193 RUN_TEST(encode_negative_integer); 3194 RUN_TEST(encode_char); 3195 RUN_TEST(decode_char); 3196 RUN_TEST(encode_bool); 3197 RUN_TEST(decode_bool); 3198 RUN_TEST(address); 3199} 3200 3201TEST compile_funcall_with_one_param_and_locals(Buffer *buf, uword *heap) { 3202 ASTNode *node = Reader_read( 3203 "(labels ((id (code (x) () x))) (let ((a 1)) ((closure id) 5)))"); 3204 int compile_result = Compile_entry(buf, node); 3205 ASSERT_EQ(compile_result, 0); 3206 // clang-format off 3207 byte expected[] = { 3208 // mov rax, [rsp-8] 3209 0x48, 0x8b, 0x44, 0x24, 0xf8, 3210 // ret 3211 0xc3, 3212 // mov Code, rsi 3213 0x48, 0x8b, 0xce, 3214 // mov Heap, rdi 3215 0x48, 0x89, 0xfe, 3216 // mov rax, compile(1) 3217 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 3218 // mov [rsp-8], rax 3219 0x48, 0x89, 0x44, 0x24, 0xf8, 3220 // mov rax, compile(5) 3221 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 3222 // mov [rsp-32], rax 3223 0x48, 0x89, 0x44, 0x24, 0xe0, 3224 // mov rax, Code 3225 0x48, 0x89, 0xc8, 3226 // add rax, 0 (code offset) 3227 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, 3228 // mov qword [Heap], rax 3229 0x48, 0x89, 0x46, 0x00, 3230 // mov rax, Heap 3231 0x48, 0x89, 0xf0, 3232 // or rax, 6 3233 0x48, 0x83, 0xc8, 0x06, 3234 // add Heap, 0x8 (label + 0 freevars) 3235 0x48, 0x81, 0xc6, 0x08, 0x00, 0x00, 0x00, 3236 // mov [rsp-16], rdi save closure 3237 0x48, 0x89, 0x7c, 0x24, 0xf0, 3238 // mov rdi, rax 3239 0x48, 0x89, 0xc7, 3240 // sub rdi, 0x6 3241 0x48, 0x81, 0xef, 0x06, 0x00, 0x00, 0x00, 3242 // mov rax, [Closure] closure[label] 3243 0x48, 0x8b, 0x47, 0x00, 3244 // sub rsp, 16 3245 0x48, 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, 3246 // call near rax (const) 3247 0xff, 0xd0, 3248 // add rsp, 16 3249 0x48, 0x81, 0xc4, 0x10, 0x00, 0x00, 0x00, 3250 // mov rdi, [rsp-16] reload closure 3251 0x48, 0x8b, 0x7c, 0x24, 0xf0, 3252 // ret 3253 0xc3, 3254 }; 3255 // clang-format on 3256 EXPECT_EQUALS_BYTES(buf, expected); 3257 Buffer_make_executable(buf); 3258 uword result = Testing_execute_entry(buf, heap); 3259 ASSERT_EQ_FMT(Object_encode_integer(5), result, "0x%lx"); 3260 AST_heap_free(node); 3261 PASS(); 3262} 3263 3264TEST compile_funcall_with_two_params_and_locals(Buffer *buf, uword *heap) { 3265 ASTNode *node = 3266 Reader_read("(labels ((add (code (x y) () (+ x y)))) (let ((a " 3267 "1)) ((closure add) 5 a)))"); 3268 int compile_result = Compile_entry(buf, node); 3269 ASSERT_EQ(compile_result, 0); 3270 // clang-format off 3271 byte expected[] = { 3272 // mov rax, [rsp-8] 3273 0x48, 0x8b, 0x44, 0x24, 0xf0, 3274 // mov [rsp-24], rax 3275 0x48, 0x89, 0x44, 0x24, 0xe8, 3276 // mov rax, [rsp-8] 3277 0x48, 0x8b, 0x44, 0x24, 0xf8, 3278 // add rax, [rsp-24] 3279 0x48, 0x03, 0x44, 0x24, 0xe8, 3280 // ret 3281 0xc3, 3282 3283 // mov Code, rsi 3284 0x48, 0x8b, 0xce, 3285 // mov Heap, rdi 3286 0x48, 0x89, 0xfe, 3287 // mov rax, compile(1) 3288 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 3289 // mov [rsp-8], rax 3290 0x48, 0x89, 0x44, 0x24, 0xf8, 3291 // mov rax, compile(5) 3292 0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, 3293 // mov [rsp-32], rax 3294 0x48, 0x89, 0x44, 0x24, 0xe0, 3295 // mov rax, [rsp-8] 3296 0x48, 0x8b, 0x44, 0x24, 0xf8, 3297 // mov [rsp-40], rax 3298 0x48, 0x89, 0x44, 0x24, 0xd8, 3299 // mov rax, Code 3300 0x48, 0x89, 0xc8, 3301 // add rax, 0 (code offset) 3302 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, 3303 // mov qword [Heap], rax 3304 0x48, 0x89, 0x46, 0x00, 3305 // mov rax, Heap 3306 0x48, 0x89, 0xf0, 3307 // or rax, 6 3308 0x48, 0x83, 0xc8, 0x06, 3309 // add Heap, 0x8 (label + 0 freevars) 3310 0x48, 0x81, 0xc6, 0x08, 0x00, 0x00, 0x00, 3311 // mov [rsp-16], rdi save closure 3312 0x48, 0x89, 0x7c, 0x24, 0xf0, 3313 // mov rdi, rax 3314 0x48, 0x89, 0xc7, 3315 // sub rdi, 0x6 3316 0x48, 0x81, 0xef, 0x06, 0x00, 0x00, 0x00, 3317 // mov rax, [Closure] closure[label] 3318 0x48, 0x8b, 0x47, 0x00, 3319 // sub rsp, 16 3320 0x48, 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, 3321 // call near rax (const) 3322 0xff, 0xd0, 3323 // add rsp, 16 3324 0x48, 0x81, 0xc4, 0x10, 0x00, 0x00, 0x00, 3325 // mov rdi, [rsp-16] reload closure 3326 0x48, 0x8b, 0x7c, 0x24, 0xf0, 3327 // ret 3328 0xc3, 3329 }; 3330 // clang-format on 3331 EXPECT_EQUALS_BYTES(buf, expected); 3332 Buffer_make_executable(buf); 3333 uword result = Testing_execute_entry(buf, heap); 3334 ASSERT_EQ_FMT(Object_encode_integer(6), result, "0x%lx"); 3335 AST_heap_free(node); 3336 PASS(); 3337} 3338 3339TEST compile_nested_funcall(Buffer *buf, uword *heap) { 3340 ASTNode *node = Reader_read("(labels ((add (code (x y) () (+ x y)))" 3341 " (sub (code (x y) () (- x y))))" 3342 " ((closure sub) 4 ((closure add) 1 2)))"); 3343 int compile_result = Compile_entry(buf, node); 3344 ASSERT_EQ(compile_result, 0); 3345 Buffer_make_executable(buf); 3346 uword result = Testing_execute_entry(buf, heap); 3347 ASSERT_EQ_FMT(Object_encode_integer(1), result, "0x%lx"); 3348 AST_heap_free(node); 3349 PASS(); 3350} 3351 3352TEST compile_multilevel_funcall(Buffer *buf, uword *heap) { 3353 ASTNode *node = 3354 Reader_read("(labels ((add (code (x y) () (+ x y)))" 3355 " (add2 (code (x y) () ((closure add) x y))))" 3356 " ((closure add2) 1 2))"); 3357 int compile_result = Compile_entry(buf, node); 3358 ASSERT_EQ(compile_result, 0); 3359 Buffer_make_executable(buf); 3360 uword result = Testing_execute_entry(buf, heap); 3361 ASSERT_EQ_FMT(Object_encode_integer(3), result, "0x%lx"); 3362 AST_heap_free(node); 3363 PASS(); 3364} 3365 3366TEST compile_factorial_funcall(Buffer *buf, uword *heap) { 3367 ASTNode *node = Reader_read( 3368 "(labels ((factorial (code (x) ()" 3369 " (if (< x 2) 1 (* x ((closure factorial) (- x 1)))))))" 3370 " ((closure factorial) 5))"); 3371 int compile_result = Compile_entry(buf, node); 3372 ASSERT_EQ(compile_result, 0); 3373 Buffer_make_executable(buf); 3374 uword result = Testing_execute_entry(buf, heap); 3375 ASSERT_EQ_FMT(Object_encode_integer(120), result, "0x%lx"); 3376 AST_heap_free(node); 3377 PASS(); 3378} 3379 3380TEST compile_closure_undefined_label(Buffer *buf) { 3381 ASTNode *node = Reader_read("(closure nonexistent)"); 3382 int compile_result = 3383 Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL, /*labels=*/NULL); 3384 ASSERT_EQ(compile_result, -1); 3385 AST_heap_free(node); 3386 PASS(); 3387} 3388 3389TEST compile_closure_no_freevars(Buffer *buf, uword *heap) { 3390 ASTNode *node = Reader_read("(closure foo)"); 3391 uword closure_ptr = 0xe3; 3392 Env labels = Env_bind("foo", closure_ptr, NULL); 3393 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 3394 int compile_result = 3395 Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL, &labels); 3396 ASSERT_EQ(compile_result, 0); 3397 Emit_ret(buf); 3398 // clang-format off 3399 byte expected[] = { 3400 // mov Code, rsi 3401 0x48, 0x8b, 0xce, 3402 // mov Heap, rdi 3403 0x48, 0x89, 0xfe, 3404 // mov rax, Code 3405 0x48, 0x89, 0xc8, 3406 // add rax, 0xe3 (code offset) 3407 0x48, 0x05, 0xe3, 0x00, 0x00, 0x00, 3408 // mov qword [Heap], rax 3409 0x48, 0x89, 0x46, 0x00, 3410 // mov rax, Heap 3411 0x48, 0x89, 0xf0, 3412 // or rax, 6 3413 0x48, 0x83, 0xc8, 0x06, 3414 // add Heap, 0x8 (label + 0 freevars) 3415 0x48, 0x81, 0xc6, 0x08, 0x00, 0x00, 0x00, 3416 // ret 3417 0xc3, 3418 }; 3419 // clang-format on 3420 EXPECT_EQUALS_BYTES(buf, expected); 3421 Buffer_make_executable(buf); 3422 uword result = Testing_execute_entry(buf, heap); 3423 ASSERT(Object_is_closure(result)); 3424 ASSERT_EQ_FMT((uword)(buf->address + closure_ptr), 3425 Object_closure_label(result), "%ld"); 3426 AST_heap_free(node); 3427 PASS(); 3428} 3429 3430TEST compile_closure_one_freevar(Buffer *buf, uword *heap) { 3431 ASTNode *node = Reader_read("(closure foo 1)"); 3432 uword closure_ptr = 0xe3; 3433 Env labels = Env_bind("foo", closure_ptr, NULL); 3434 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 3435 int compile_result = 3436 Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL, &labels); 3437 ASSERT_EQ(compile_result, 0); 3438 Emit_ret(buf); 3439 // clang-format off 3440 byte expected[] = { 3441 // mov rax, compile(1) 3442 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 3443 // mov [rsp-8], rax 3444 0x48, 0x89, 0x44, 0x24, 0xf8, 3445 // mov rax, [rsp - 8] 3446 0x48, 0x8b, 0x44, 0x24, 0xf8, 3447 // mov [Heap + 8], rax 3448 0x48, 0x89, 0x46, 0x08, 3449 // mov rax, Code 3450 0x48, 0x89, 0xc8, 3451 // add rax, 0xe3 (code offset) 3452 0x48, 0x05, 0xe3, 0x00, 0x00, 0x00, 3453 // mov qword [Heap], rax 3454 0x48, 0x89, 0x46, 0x00, 3455 // mov rax, Heap 3456 0x48, 0x89, 0xf0, 3457 // or rax, 6 3458 0x48, 0x83, 0xc8, 0x06, 3459 // add Heap, 0x10 (label + 1 freevar) 3460 0x48, 0x81, 0xc6, 0x10, 0x00, 0x00, 0x00, 3461 }; 3462 // clang-format on 3463 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 3464 Buffer_make_executable(buf); 3465 uword result = Testing_execute_entry(buf, heap); 3466 ASSERT(Object_is_closure(result)); 3467 ASSERT_EQ_FMT((uword)(buf->address + closure_ptr), 3468 Object_closure_label(result), "%ld"); 3469 ASSERT_EQ_FMT(Object_encode_integer(1), Object_closure_freevar(result, 0), 3470 "%ld"); 3471 AST_heap_free(node); 3472 PASS(); 3473} 3474 3475TEST compile_closure_two_freevars(Buffer *buf, uword *heap) { 3476 ASTNode *node = Reader_read("(closure foo 1 2)"); 3477 uword closure_ptr = 0xe3; 3478 Env labels = Env_bind("foo", closure_ptr, NULL); 3479 Buffer_write_arr(buf, kEntryPrologue, sizeof kEntryPrologue); 3480 int compile_result = 3481 Compile_expr(buf, node, -kWordSize, /*varenv=*/NULL, &labels); 3482 ASSERT_EQ(compile_result, 0); 3483 Emit_ret(buf); 3484 // clang-format off 3485 byte expected[] = { 3486 // mov rax, compile(1) 3487 0x48, 0xc7, 0xc0, 0x04, 0x00, 0x00, 0x00, 3488 // mov [rsp-8], rax 3489 0x48, 0x89, 0x44, 0x24, 0xf8, 3490 // mov rax, compile(2) 3491 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 3492 // mov [rsp-16], rax 3493 0x48, 0x89, 0x44, 0x24, 0xf0, 3494 // mov rax, [rsp - 16] 3495 0x48, 0x8b, 0x44, 0x24, 0xf0, 3496 // mov [Heap + 16], rax 3497 0x48, 0x89, 0x46, 0x10, 3498 // mov rax, [rsp - 8] 3499 0x48, 0x8b, 0x44, 0x24, 0xf8, 3500 // mov [Heap + 8], rax 3501 0x48, 0x89, 0x46, 0x08, 3502 // mov rax, Code 3503 0x48, 0x89, 0xc8, 3504 // add rax, 0xe3 (code offset) 3505 0x48, 0x05, 0xe3, 0x00, 0x00, 0x00, 3506 // mov qword [Heap], rax 3507 0x48, 0x89, 0x46, 0x00, 3508 // mov rax, Heap 3509 0x48, 0x89, 0xf0, 3510 // or rax, 6 3511 0x48, 0x83, 0xc8, 0x06, 3512 // add Heap, 0x18 (label + 2 freevars) 3513 0x48, 0x81, 0xc6, 0x18, 0x00, 0x00, 0x00, 3514 }; 3515 // clang-format on 3516 EXPECT_ENTRY_CONTAINS_CODE(buf, expected); 3517 Buffer_make_executable(buf); 3518 uword result = Testing_execute_entry(buf, heap); 3519 ASSERT(Object_is_closure(result)); 3520 ASSERT_EQ_FMT((uword)(buf->address + closure_ptr), 3521 Object_closure_label(result), "%ld"); 3522 ASSERT_EQ_FMT(Object_encode_integer(1), Object_closure_freevar(result, 0), 3523 "%ld"); 3524 ASSERT_EQ_FMT(Object_encode_integer(2), Object_closure_freevar(result, 1), 3525 "%ld"); 3526 AST_heap_free(node); 3527 PASS(); 3528} 3529 3530SUITE(ast_tests) { 3531 RUN_TEST(ast_new_pair); 3532 RUN_TEST(ast_pair_car_returns_car); 3533 RUN_TEST(ast_pair_cdr_returns_cdr); 3534 RUN_TEST(ast_new_symbol); 3535} 3536 3537SUITE(reader_tests) { 3538 RUN_TEST(read_with_integer_returns_integer); 3539 RUN_TEST(read_with_negative_integer_returns_integer); 3540 RUN_TEST(read_with_positive_integer_returns_integer); 3541 RUN_TEST(read_with_leading_whitespace_ignores_whitespace); 3542 RUN_TEST(read_with_symbol_returns_symbol); 3543 RUN_TEST(read_with_symbol_with_trailing_digits); 3544 RUN_TEST(read_with_nil_returns_nil); 3545 RUN_TEST(read_with_list_returns_list); 3546 RUN_TEST(read_with_nested_list_returns_list); 3547 RUN_TEST(read_with_char_returns_char); 3548 RUN_TEST(read_with_bool_returns_bool); 3549} 3550 3551SUITE(buffer_tests) { 3552 RUN_BUFFER_TEST(buffer_write8_increases_length); 3553 RUN_TEST(buffer_write8_expands_buffer); 3554 RUN_TEST(buffer_write32_expands_buffer); 3555 RUN_BUFFER_TEST(buffer_write32_writes_little_endian); 3556 RUN_BUFFER_TEST(emit_mov_reg_imm32_emits_modrm); 3557 RUN_BUFFER_TEST(emit_store_reg_indirect_emits_modrm_sib); 3558} 3559 3560TEST free_in_with_immediate_returns_nil() { 3561 ASSERT(AST_is_nil(free_in(AST_new_integer(5)))); 3562 ASSERT(AST_is_nil(free_in(AST_new_char('a')))); 3563 ASSERT(AST_is_nil(free_in(AST_new_bool(true)))); 3564 ASSERT(AST_is_nil(free_in(AST_nil()))); 3565 PASS(); 3566} 3567 3568TEST is_list_with_names(ASTNode *list, word n, ...) { 3569 if (!AST_is_pair(list)) { 3570 FAILm("Not a list"); 3571 } 3572 va_list vl; 3573 va_start(vl, n); 3574 for (word i = 0; i < n; i++) { 3575 if (AST_is_nil(list)) { 3576 FAILm("List smaller than expected"); 3577 } 3578 ASTNode *elt = AST_pair_car(list); 3579 if (!AST_is_symbol(elt)) { 3580 FAILm("List had non-symbol element"); 3581 } 3582 const char *expected = va_arg(vl, const char *); 3583 if (!AST_symbol_matches(elt, expected)) { 3584 FAILm("List element does not match expected"); 3585 } 3586 list = AST_pair_cdr(list); 3587 } 3588 if (!AST_is_nil(list)) { 3589 abort(); 3590 FAILm("List larger than expected"); 3591 } 3592 PASS(); 3593} 3594 3595TEST free_in_with_symbol_returns_list() { 3596 { 3597 ASTNode *result = free_in(AST_new_symbol("foo")); 3598 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3599 } 3600 PASS(); 3601} 3602 3603TEST free_in_with_if() { 3604 { 3605 ASTNode *result = free_in(Reader_read("(if 1 2 3)")); 3606 ASSERT(AST_is_nil(result)); 3607 } 3608 { 3609 ASTNode *result = free_in(Reader_read("(if foo 2 3)")); 3610 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3611 } 3612 { 3613 ASTNode *result = free_in(Reader_read("(if 1 foo 3)")); 3614 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3615 } 3616 { 3617 ASTNode *result = free_in(Reader_read("(if 1 2 foo)")); 3618 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3619 } 3620 { 3621 ASTNode *result = free_in(Reader_read("(if foo 2 bar)")); 3622 CHECK_CALL(is_list_with_names(result, 2, "foo", "bar")); 3623 } 3624 { 3625 ASTNode *result = free_in(Reader_read("(if foo 2 foo)")); 3626 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3627 } 3628 PASS(); 3629} 3630 3631TEST free_in_with_let() { 3632 { 3633 ASTNode *result = free_in(Reader_read("(let () 1)")); 3634 ASSERT(AST_is_nil(result)); 3635 } 3636 { 3637 ASTNode *result = free_in(Reader_read("(let () foo)")); 3638 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3639 } 3640 { 3641 ASTNode *result = free_in(Reader_read("(let ((foo 1)) 1)")); 3642 ASSERT(AST_is_nil(result)); 3643 } 3644 { 3645 ASTNode *result = free_in(Reader_read("(let ((foo 1) (bar 2)) foo)")); 3646 ASSERT(AST_is_nil(result)); 3647 } 3648 { 3649 ASTNode *result = free_in(Reader_read("(let ((foo foo)) foo)")); 3650 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3651 } 3652 { 3653 ASTNode *result = free_in(Reader_read("(let ((foo bar) (bar 3)) foo)")); 3654 CHECK_CALL(is_list_with_names(result, 1, "bar")); 3655 } 3656 { 3657 ASTNode *result = 3658 free_in(Reader_read("(let ((foo 1)) (let ((bar 2)) (+ foo bar)))")); 3659 ASSERT(AST_is_nil(result)); 3660 } 3661 { 3662 ASTNode *result = 3663 free_in(Reader_read("(let ((foo 1)) (let ((baz 2)) (+ foo bar)))")); 3664 CHECK_CALL(is_list_with_names(result, 1, "bar")); 3665 } 3666 PASS(); 3667} 3668 3669TEST free_in_with_lambda() { 3670 { 3671 ASTNode *result = free_in(Reader_read("(lambda () 1)")); 3672 ASSERT(AST_is_nil(result)); 3673 } 3674 { 3675 ASTNode *result = free_in(Reader_read("(lambda () (+ foo 1))")); 3676 CHECK_CALL(is_list_with_names(result, 1, "foo")); 3677 } 3678 { 3679 ASTNode *result = free_in(Reader_read("(lambda (foo) 1)")); 3680 ASSERT(AST_is_nil(result)); 3681 } 3682 { 3683 ASTNode *result = free_in(Reader_read("(lambda (foo bar) foo)")); 3684 ASSERT(AST_is_nil(result)); 3685 } 3686 { 3687 ASTNode *result = free_in(Reader_read("(lambda (foo) foo)")); 3688 ASSERT(AST_is_nil(result)); 3689 } 3690 { 3691 ASTNode *result = free_in(Reader_read("(lambda (foo) (+ foo bar))")); 3692 CHECK_CALL(is_list_with_names(result, 1, "bar")); 3693 } 3694 { 3695 ASTNode *result = 3696 free_in(Reader_read("(lambda (foo) (lambda (bar) (+ foo bar)))")); 3697 ASSERT(AST_is_nil(result)); 3698 } 3699 { 3700 ASTNode *result = 3701 free_in(Reader_read("(lambda (foo) (lambda (baz) (+ foo bar)))")); 3702 CHECK_CALL(is_list_with_names(result, 1, "bar")); 3703 } 3704 PASS(); 3705} 3706 3707TEST is_lambda_with_freevars(ASTNode *node, word n, ...) { 3708 if (!is_tagged_with(node, "lambda")) { 3709 FAILm("Not a lambda"); 3710 } 3711 ASTNode *args = AST_pair_cdr(node); 3712 ASTNode *freevars = operand2(args); 3713 if (AST_is_nil(freevars) != (n == 0)) { 3714 FAILm("Expected freevars to be nil only when n == 0"); 3715 } 3716 if (!AST_is_pair(freevars)) { 3717 FAILm("Freevars is not a list"); 3718 } 3719 va_list vl; 3720 va_start(vl, n); 3721 for (word i = 0; i < n; i++) { 3722 if (AST_is_nil(freevars)) { 3723 FAILm("Freevars smaller than expected"); 3724 } 3725 ASTNode *elt = AST_pair_car(freevars); 3726 if (!AST_is_symbol(elt)) { 3727 FAILm("Freevars had non-symbol element"); 3728 } 3729 const char *expected = va_arg(vl, const char *); 3730 if (!AST_symbol_matches(elt, expected)) { 3731 FAILm("Freevars element does not match expected"); 3732 } 3733 freevars = AST_pair_cdr(freevars); 3734 } 3735 if (!AST_is_nil(freevars)) { 3736 abort(); 3737 FAILm("Freevars larger than expected"); 3738 } 3739 PASS(); 3740} 3741 3742TEST transform_lambda_adds_freevars() { 3743 { 3744 ASTNode *result = Transform_lambda(Reader_read("(lambda () a)")); 3745 CHECK_CALL(is_lambda_with_freevars(result, 1, "a")); 3746 } 3747 { 3748 ASTNode *result = Transform_lambda(Reader_read("(lambda () (+ a b))")); 3749 CHECK_CALL(is_lambda_with_freevars(result, 2, "a", "b")); 3750 } 3751 { 3752 ASTNode *result = 3753 Transform_lambda(Reader_read("(lambda (y) (lambda () (+ x y)))")); 3754 CHECK_CALL(is_lambda_with_freevars(result, 1, "x")); 3755 } 3756 PASS(); 3757} 3758 3759TEST transform_let() { 3760 { 3761 ASTNode *result = Transform(Reader_read("(let () (lambda () a))")); 3762 ASSERT(is_tagged_with(result, "let")); 3763 ASTNode *bindings = AST_pair_car(AST_pair_cdr(result)); 3764 ASSERT(AST_is_nil(bindings)); 3765 ASTNode *body = AST_pair_car(AST_pair_cdr(AST_pair_cdr(result))); 3766 CHECK_CALL(is_lambda_with_freevars(body, 1, "a")); 3767 } 3768 { 3769 ASTNode *result = Transform(Reader_read("(let ((a (lambda () a))) 1)")); 3770 ASSERT(is_tagged_with(result, "let")); 3771 ASTNode *bindings = AST_pair_car(AST_pair_cdr(result)); 3772 ASSERT(AST_is_pair(bindings)); 3773 ASTNode *binding = AST_pair_car(bindings); 3774 ASTNode *value = AST_pair_car(AST_pair_cdr(binding)); 3775 CHECK_CALL(is_lambda_with_freevars(value, 1, "a")); 3776 } 3777 PASS(); 3778} 3779 3780TEST transform_arbitrary_call() { 3781 { 3782 ASTNode *result = Transform(Reader_read("((lambda () x) 1)")); 3783 ASTNode *lambda = AST_pair_car(result); 3784 CHECK_CALL(is_lambda_with_freevars(lambda, 1, "x")); 3785 } 3786 { 3787 ASTNode *result = Transform(Reader_read("(foo (lambda () x) 1)")); 3788 ASTNode *lambda = AST_pair_car(AST_pair_cdr(result)); 3789 CHECK_CALL(is_lambda_with_freevars(lambda, 1, "x")); 3790 } 3791 PASS(); 3792} 3793 3794SUITE(transform_tests) { 3795 RUN_TEST(free_in_with_immediate_returns_nil); 3796 RUN_TEST(free_in_with_symbol_returns_list); 3797 RUN_TEST(free_in_with_if); 3798 RUN_TEST(free_in_with_let); 3799 RUN_TEST(free_in_with_lambda); 3800 RUN_TEST(transform_lambda_adds_freevars); 3801 RUN_TEST(transform_let); 3802 RUN_TEST(transform_arbitrary_call); 3803} 3804 3805SUITE(compiler_tests) { 3806 RUN_BUFFER_TEST(compile_positive_integer); 3807 RUN_BUFFER_TEST(compile_negative_integer); 3808 RUN_BUFFER_TEST(compile_char); 3809 RUN_BUFFER_TEST(compile_true); 3810 RUN_BUFFER_TEST(compile_false); 3811 RUN_BUFFER_TEST(compile_nil); 3812 RUN_BUFFER_TEST(compile_unary_add1); 3813 RUN_BUFFER_TEST(compile_unary_add1_nested); 3814 RUN_BUFFER_TEST(compile_unary_sub1); 3815 RUN_BUFFER_TEST(compile_unary_integer_to_char); 3816 RUN_BUFFER_TEST(compile_unary_char_to_integer); 3817 RUN_BUFFER_TEST(compile_unary_nilp_with_nil_returns_true); 3818 RUN_BUFFER_TEST(compile_unary_nilp_with_non_nil_returns_false); 3819 RUN_BUFFER_TEST(compile_unary_zerop_with_zero_returns_true); 3820 RUN_BUFFER_TEST(compile_unary_zerop_with_non_zero_returns_false); 3821 RUN_BUFFER_TEST(compile_unary_not_with_false_returns_true); 3822 RUN_BUFFER_TEST(compile_unary_not_with_non_false_returns_false); 3823 RUN_BUFFER_TEST(compile_unary_integerp_with_integer_returns_true); 3824 RUN_BUFFER_TEST(compile_unary_integerp_with_non_integer_returns_false); 3825 RUN_BUFFER_TEST(compile_unary_booleanp_with_boolean_returns_true); 3826 RUN_BUFFER_TEST(compile_unary_booleanp_with_non_boolean_returns_false); 3827 RUN_BUFFER_TEST(compile_binary_plus); 3828 RUN_BUFFER_TEST(compile_binary_plus_nested); 3829 RUN_BUFFER_TEST(compile_binary_minus); 3830 RUN_BUFFER_TEST(compile_binary_minus_nested); 3831 RUN_BUFFER_TEST(compile_binary_mul); 3832 RUN_BUFFER_TEST(compile_binary_mul_nested); 3833 RUN_BUFFER_TEST(compile_binary_eq_with_same_address_returns_true); 3834 RUN_BUFFER_TEST(compile_binary_eq_with_different_address_returns_false); 3835 RUN_BUFFER_TEST(compile_binary_lt_with_left_less_than_right_returns_true); 3836 RUN_BUFFER_TEST(compile_binary_lt_with_left_equal_to_right_returns_false); 3837 RUN_BUFFER_TEST(compile_binary_lt_with_left_greater_than_right_returns_false); 3838 RUN_BUFFER_TEST(compile_symbol_in_env_returns_value); 3839 RUN_BUFFER_TEST(compile_symbol_in_closure_returns_value); 3840 RUN_BUFFER_TEST(compile_symbol_in_env_returns_first_value); 3841 RUN_BUFFER_TEST(compile_symbol_not_in_env_raises_compile_error); 3842 RUN_BUFFER_TEST(compile_let_with_no_bindings); 3843 RUN_BUFFER_TEST(compile_let_with_one_binding); 3844 RUN_BUFFER_TEST(compile_let_with_multiple_bindings); 3845 RUN_BUFFER_TEST(compile_nested_let); 3846 RUN_BUFFER_TEST(compile_let_is_not_let_star); 3847 RUN_BUFFER_TEST(compile_if_with_true_cond); 3848 RUN_BUFFER_TEST(compile_if_with_false_cond); 3849 RUN_BUFFER_TEST(compile_nested_if); 3850 RUN_HEAP_TEST(compile_cons); 3851 RUN_HEAP_TEST(compile_two_cons); 3852 RUN_HEAP_TEST(compile_nested_cons); 3853 RUN_HEAP_TEST(compile_car); 3854 RUN_HEAP_TEST(compile_cdr); 3855 RUN_BUFFER_TEST(compile_code_with_no_params); 3856 RUN_BUFFER_TEST(compile_code_with_one_param); 3857 RUN_BUFFER_TEST(compile_code_with_one_freevar); 3858 RUN_BUFFER_TEST(compile_code_with_two_params); 3859 RUN_BUFFER_TEST(compile_code_with_two_freevars); 3860 RUN_BUFFER_TEST(compile_code_with_params_and_freevars); 3861 RUN_BUFFER_TEST(compile_labels_with_no_labels); 3862 RUN_BUFFER_TEST(compile_labels_with_one_label); 3863 RUN_HEAP_TEST(compile_funcall_with_no_params); 3864 RUN_HEAP_TEST(compile_funcall_with_no_params_and_locals); 3865 RUN_HEAP_TEST(compile_funcall_with_one_param); 3866 RUN_HEAP_TEST(compile_funcall_with_one_param_and_locals); 3867 RUN_HEAP_TEST(compile_funcall_with_two_params_and_locals); 3868 RUN_HEAP_TEST(compile_nested_funcall); 3869 RUN_HEAP_TEST(compile_multilevel_funcall); 3870 RUN_HEAP_TEST(compile_factorial_funcall); 3871 RUN_BUFFER_TEST(compile_closure_undefined_label); 3872 RUN_HEAP_TEST(compile_closure_no_freevars); 3873 RUN_HEAP_TEST(compile_closure_one_freevar); 3874 RUN_HEAP_TEST(compile_closure_two_freevars); 3875} 3876 3877// End Tests 3878 3879GREATEST_MAIN_DEFS(); 3880 3881int run_tests(int argc, char **argv) { 3882 GREATEST_MAIN_BEGIN(); 3883 RUN_SUITE(object_tests); 3884 RUN_SUITE(ast_tests); 3885 RUN_SUITE(reader_tests); 3886 RUN_SUITE(buffer_tests); 3887 RUN_SUITE(transform_tests); 3888 RUN_SUITE(compiler_tests); 3889 GREATEST_MAIN_END(); 3890} 3891 3892int main(int argc, char **argv) { 3893 assert(sizeof(word) == 8); 3894 return run_tests(argc, argv); 3895}