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