aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler.c184
-rw-r--r--src/main.c10
-rw-r--r--src/vm.c13
-rw-r--r--tests/compilation.bad40
4 files changed, 156 insertions, 91 deletions
diff --git a/src/compiler.c b/src/compiler.c
index a860a58..aeb6793 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -96,6 +96,7 @@ typedef enum OpCode {
96 OP_STLVAR, // stlvar vx, ra 96 OP_STLVAR, // stlvar vx, ra
97 OP_LDLVAR, // ldlvar rx, va 97 OP_LDLVAR, // ldlvar rx, va
98 OP_LDLADDR, // ldladdr rx, va 98 OP_LDLADDR, // ldladdr rx, va
99 OP_LDSTR, // ldstr rx, sa ; Stores the address of the string sa into rx
99 // Functions. 100 // Functions.
100 OP_CALL, // call fx ; Bumps the stack pointer by cx 101 OP_CALL, // call fx ; Bumps the stack pointer by cx
101 OP_RET, // ret ; Returns from current function 102 OP_RET, // ret ; Returns from current function
@@ -107,6 +108,7 @@ typedef enum OpCode {
107 OP_PUTRETI, // putreti cx ; Put cx into the return value memory. 108 OP_PUTRETI, // putreti cx ; Put cx into the return value memory.
108 // Printing values with builtin print/println functions. 109 // Printing values with builtin print/println functions.
109 OP_PRINTSTR, // p rx 110 OP_PRINTSTR, // p rx
111 OP_PRINTSTRI, // p rx
110 OP_PRINTS64, // p rx 112 OP_PRINTS64, // p rx
111 OP_PRINTF64, // p rx 113 OP_PRINTF64, // p rx
112 OP_PRINTS64I, // p cx 114 OP_PRINTS64I, // p cx
@@ -210,6 +212,7 @@ Str op_str[] = {
210 [OP_STLVARI] = cstr("STLVARI "), 212 [OP_STLVARI] = cstr("STLVARI "),
211 [OP_LDLVAR] = cstr("LDLVAR "), 213 [OP_LDLVAR] = cstr("LDLVAR "),
212 [OP_LDLADDR] = cstr("LDLADDR "), 214 [OP_LDLADDR] = cstr("LDLADDR "),
215 [OP_LDSTR] = cstr("LDSTR "),
213 [OP_PRINTSTR] = cstr("PRNTSTR "), 216 [OP_PRINTSTR] = cstr("PRNTSTR "),
214 [OP_PRINTS64] = cstr("PRNTS64 "), 217 [OP_PRINTS64] = cstr("PRNTS64 "),
215 [OP_PRINTF64] = cstr("PRNTF64 "), 218 [OP_PRINTF64] = cstr("PRNTF64 "),
@@ -328,22 +331,21 @@ typedef struct CompResult {
328 331
329CompResult compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post); 332CompResult compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post);
330 333
331#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 334void
332 do { \ 335emit_op(OpCode op, sz dst, sz a, sz b, Node *node, Chunk *chunk) {
333 Instruction inst = (Instruction){ \ 336 Instruction inst = (Instruction){
334 .op = (OP), \ 337 .op = op,
335 .dst = (DST), \ 338 .dst = dst,
336 .a = (A), \ 339 .a = a,
337 .b = (B), \ 340 .b = b,
338 }; \ 341 };
339 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 342 array_push(chunk->code, inst, chunk->storage);
340 LineCol linecol = (LineCol){0}; \ 343 LineCol linecol = (LineCol){0};
341 if (NODE) { \ 344 if (node) {
342 Node *_node = (NODE); \ 345 linecol = (LineCol){.line = node->line, .col = node->col};
343 linecol = (LineCol){.line = _node->line, .col = _node->col}; \ 346 }
344 } \ 347 array_push(chunk->linecol, linecol, chunk->storage);
345 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ 348}
346 } while (0)
347 349
348CompResult 350CompResult
349compile_binary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) { 351compile_binary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
@@ -462,7 +464,7 @@ compile_binary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
462 switch (comp_a.type) { 464 switch (comp_a.type) {
463 case COMP_CONST: { 465 case COMP_CONST: {
464 reg_a = chunk->reg_idx++; 466 reg_a = chunk->reg_idx++;
465 EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); 467 emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk);
466 } break; 468 } break;
467 case COMP_REG: { 469 case COMP_REG: {
468 reg_a = comp_a.idx; 470 reg_a = comp_a.idx;
@@ -484,7 +486,7 @@ compile_binary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
484 } break; 486 } break;
485 } 487 }
486 sz reg_dst = chunk->reg_idx++; // Better for optimization 488 sz reg_dst = chunk->reg_idx++; // Better for optimization
487 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); 489 emit_op(op, reg_dst, reg_a, reg_b, node, chunk);
488 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 490 return (CompResult){.type = COMP_REG, .idx = reg_dst};
489} 491}
490 492
@@ -519,7 +521,7 @@ compile_unary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
519 } break; 521 } break;
520 } 522 }
521 sz reg_dst = chunk->reg_idx++; 523 sz reg_dst = chunk->reg_idx++;
522 EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); 524 emit_op(op, reg_dst, reg_a, 0, node, chunk);
523 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 525 return (CompResult){.type = COMP_REG, .idx = reg_dst};
524} 526}
525 527
@@ -602,18 +604,18 @@ compile_if(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
602 604
603 // Jump to the `false` branch. 605 // Jump to the `false` branch.
604 sz lab0 = chunk->labels_idx++; 606 sz lab0 = chunk->labels_idx++;
605 EMIT_OP(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); 607 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
606 608
607 // Condition is true. 609 // Condition is true.
608 CompResult then_expr = 610 CompResult then_expr =
609 compile_expr(chunk, node->ifelse.expr_true, lab_pre, lab_post); 611 compile_expr(chunk, node->ifelse.expr_true, lab_pre, lab_post);
610 switch (then_expr.type) { 612 switch (then_expr.type) {
611 case COMP_CONST: { 613 case COMP_CONST: {
612 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->ifelse.cond, 614 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0, node->ifelse.cond,
613 chunk); 615 chunk);
614 } break; 616 } break;
615 case COMP_REG: { 617 case COMP_REG: {
616 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond, 618 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond,
617 chunk); 619 chunk);
618 } break; 620 } break;
619 case COMP_RET: break; 621 case COMP_RET: break;
@@ -625,18 +627,18 @@ compile_if(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
625 // Jump to the end of the expression. 627 // Jump to the end of the expression.
626 sz pos0 = array_size(chunk->code); 628 sz pos0 = array_size(chunk->code);
627 sz lab1 = chunk->labels_idx++; 629 sz lab1 = chunk->labels_idx++;
628 EMIT_OP(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); 630 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
629 631
630 // Else expression. 632 // Else expression.
631 CompResult else_expr = 633 CompResult else_expr =
632 compile_expr(chunk, node->ifelse.expr_else, lab_pre, lab_post); 634 compile_expr(chunk, node->ifelse.expr_else, lab_pre, lab_post);
633 switch (else_expr.type) { 635 switch (else_expr.type) {
634 case COMP_CONST: { 636 case COMP_CONST: {
635 EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, 637 emit_op(OP_LD64K, reg_dst, else_expr.idx, 0,
636 node->ifelse.expr_else, chunk); 638 node->ifelse.expr_else, chunk);
637 } break; 639 } break;
638 case COMP_REG: { 640 case COMP_REG: {
639 EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, 641 emit_op(OP_MOV64, reg_dst, else_expr.idx, 0,
640 node->ifelse.expr_else, chunk); 642 node->ifelse.expr_else, chunk);
641 } break; 643 } break;
642 case COMP_RET: break; 644 case COMP_RET: break;
@@ -654,7 +656,7 @@ compile_if(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
654 656
655 // Jump to the `false` branch. 657 // Jump to the `false` branch.
656 sz lab0 = chunk->labels_idx++; 658 sz lab0 = chunk->labels_idx++;
657 EMIT_OP(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); 659 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
658 660
659 // Condition is true. 661 // Condition is true.
660 compile_expr(chunk, node->ifelse.expr_true, lab_pre, lab_post); 662 compile_expr(chunk, node->ifelse.expr_true, lab_pre, lab_post);
@@ -662,7 +664,7 @@ compile_if(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
662 // Jump to the end of the expression. 664 // Jump to the end of the expression.
663 sz pos0 = array_size(chunk->code); 665 sz pos0 = array_size(chunk->code);
664 sz lab1 = chunk->labels_idx++; 666 sz lab1 = chunk->labels_idx++;
665 EMIT_OP(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); 667 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
666 668
667 // Else expression. 669 // Else expression.
668 if (node->ifelse.expr_else) { 670 if (node->ifelse.expr_else) {
@@ -701,14 +703,14 @@ compile_cond(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
701 } 703 }
702 // Jump to the `next` branch. 704 // Jump to the `next` branch.
703 sz lab0 = chunk->labels_idx++; 705 sz lab0 = chunk->labels_idx++;
704 EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); 706 emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk);
705 707
706 // Condition is true. 708 // Condition is true.
707 compile_expr(chunk, expr->case_entry.expr, lab_pre, lab_post); 709 compile_expr(chunk, expr->case_entry.expr, lab_pre, lab_post);
708 if (i != array_size(node->match.cases) - 1) { 710 if (i != array_size(node->match.cases) - 1) {
709 // Jump to the end of the expression. 711 // Jump to the end of the expression.
710 sz pos0 = array_size(chunk->code); 712 sz pos0 = array_size(chunk->code);
711 EMIT_OP(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); 713 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
712 intintmap_insert(&chunk->labels, lab0, pos0 + 1, 714 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
713 chunk->storage); 715 chunk->storage);
714 } 716 }
@@ -744,18 +746,18 @@ compile_cond(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
744 } 746 }
745 // Jump to the `next` branch. 747 // Jump to the `next` branch.
746 sz lab0 = chunk->labels_idx++; 748 sz lab0 = chunk->labels_idx++;
747 EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); 749 emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk);
748 750
749 // Condition is true. 751 // Condition is true.
750 CompResult then_expr = 752 CompResult then_expr =
751 compile_expr(chunk, expr->case_entry.expr, lab_pre, lab_post); 753 compile_expr(chunk, expr->case_entry.expr, lab_pre, lab_post);
752 switch (then_expr.type) { 754 switch (then_expr.type) {
753 case COMP_CONST: { 755 case COMP_CONST: {
754 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, 756 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0,
755 expr->case_entry.expr, chunk); 757 expr->case_entry.expr, chunk);
756 } break; 758 } break;
757 case COMP_REG: { 759 case COMP_REG: {
758 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, 760 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0,
759 expr->case_entry.expr, chunk); 761 expr->case_entry.expr, chunk);
760 } break; 762 } break;
761 case COMP_RET: break; 763 case COMP_RET: break;
@@ -766,7 +768,7 @@ compile_cond(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
766 if (i != array_size(node->match.cases) - 1) { 768 if (i != array_size(node->match.cases) - 1) {
767 // Jump to the end of the expression. 769 // Jump to the end of the expression.
768 sz pos0 = array_size(chunk->code); 770 sz pos0 = array_size(chunk->code);
769 EMIT_OP(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); 771 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
770 intintmap_insert(&chunk->labels, lab0, pos0 + 1, 772 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
771 chunk->storage); 773 chunk->storage);
772 } 774 }
@@ -775,11 +777,11 @@ compile_cond(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
775 compile_expr(chunk, expr->case_entry.expr, lab_pre, lab_post); 777 compile_expr(chunk, expr->case_entry.expr, lab_pre, lab_post);
776 switch (then_expr.type) { 778 switch (then_expr.type) {
777 case COMP_CONST: { 779 case COMP_CONST: {
778 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, 780 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0,
779 expr->case_entry.expr, chunk); 781 expr->case_entry.expr, chunk);
780 } break; 782 } break;
781 case COMP_REG: { 783 case COMP_REG: {
782 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, 784 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0,
783 expr->case_entry.expr, chunk); 785 expr->case_entry.expr, chunk);
784 } break; 786 } break;
785 case COMP_RET: break; 787 case COMP_RET: break;
@@ -798,14 +800,14 @@ compile_cond(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
798CompResult 800CompResult
799compile_break(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) { 801compile_break(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
800 (void)lab_pre; 802 (void)lab_pre;
801 EMIT_OP(OP_JMP, lab_post, 0, 0, node, chunk); 803 emit_op(OP_JMP, lab_post, 0, 0, node, chunk);
802 return (CompResult){.type = COMP_NIL}; 804 return (CompResult){.type = COMP_NIL};
803} 805}
804 806
805CompResult 807CompResult
806compile_continue(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) { 808compile_continue(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
807 (void)lab_post; 809 (void)lab_post;
808 EMIT_OP(OP_JMP, lab_pre, 0, 0, node, chunk); 810 emit_op(OP_JMP, lab_pre, 0, 0, node, chunk);
809 return (CompResult){.type = COMP_NIL}; 811 return (CompResult){.type = COMP_NIL};
810} 812}
811 813
@@ -829,12 +831,12 @@ compile_while(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
829 } 831 }
830 832
831 // Jump to the `end of the loop` branch. 833 // Jump to the `end of the loop` branch.
832 EMIT_OP(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk); 834 emit_op(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk);
833 835
834 // Condition is true. 836 // Condition is true.
835 compile_expr(chunk, node->loop.expr, lab1, lab0); 837 compile_expr(chunk, node->loop.expr, lab1, lab0);
836 sz pos0 = array_size(chunk->code); 838 sz pos0 = array_size(chunk->code);
837 EMIT_OP(OP_JMP, lab1, 0, 0, node, chunk); 839 emit_op(OP_JMP, lab1, 0, 0, node, chunk);
838 840
839 // Update labels. 841 // Update labels.
840 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); 842 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
@@ -856,10 +858,10 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
856 if (str_eq(expr->type, cstr("int"))) { 858 if (str_eq(expr->type, cstr("int"))) {
857 switch (result.type) { 859 switch (result.type) {
858 case COMP_CONST: { 860 case COMP_CONST: {
859 EMIT_OP(OP_PRINTS64I, result.idx, 0, 0, expr, chunk); 861 emit_op(OP_PRINTS64I, result.idx, 0, 0, expr, chunk);
860 } break; 862 } break;
861 case COMP_REG: { 863 case COMP_REG: {
862 EMIT_OP(OP_PRINTS64, result.idx, 0, 0, expr, chunk); 864 emit_op(OP_PRINTS64, result.idx, 0, 0, expr, chunk);
863 } break; 865 } break;
864 default: { 866 default: {
865 return (CompResult){.type = COMP_ERR}; 867 return (CompResult){.type = COMP_ERR};
@@ -868,10 +870,10 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
868 } else if (str_eq(expr->type, cstr("f64"))) { 870 } else if (str_eq(expr->type, cstr("f64"))) {
869 switch (result.type) { 871 switch (result.type) {
870 case COMP_CONST: { 872 case COMP_CONST: {
871 EMIT_OP(OP_PRINTF64I, result.idx, 0, 0, expr, chunk); 873 emit_op(OP_PRINTF64I, result.idx, 0, 0, expr, chunk);
872 } break; 874 } break;
873 case COMP_REG: { 875 case COMP_REG: {
874 EMIT_OP(OP_PRINTF64, result.idx, 0, 0, expr, chunk); 876 emit_op(OP_PRINTF64, result.idx, 0, 0, expr, chunk);
875 } break; 877 } break;
876 default: { 878 default: {
877 return (CompResult){.type = COMP_ERR}; 879 return (CompResult){.type = COMP_ERR};
@@ -880,7 +882,10 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
880 } else if (str_eq(expr->type, cstr("str"))) { 882 } else if (str_eq(expr->type, cstr("str"))) {
881 switch (result.type) { 883 switch (result.type) {
882 case COMP_STRING: { 884 case COMP_STRING: {
883 EMIT_OP(OP_PRINTSTR, result.idx, 0, 0, expr, chunk); 885 emit_op(OP_PRINTSTRI, result.idx, 0, 0, expr, chunk);
886 } break;
887 case COMP_REG: {
888 emit_op(OP_PRINTSTR, result.idx, 0, 0, expr, chunk);
884 } break; 889 } break;
885 default: { 890 default: {
886 return (CompResult){.type = COMP_ERR}; 891 return (CompResult){.type = COMP_ERR};
@@ -890,7 +895,7 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
890 } 895 }
891 if (str_eq(name, cstr("println"))) { 896 if (str_eq(name, cstr("println"))) {
892 sz idx = add_string(chunk, cstr("\n")); 897 sz idx = add_string(chunk, cstr("\n"));
893 EMIT_OP(OP_PRINTSTR, idx, 0, 0, node, chunk); 898 emit_op(OP_PRINTSTRI, idx, 0, 0, node, chunk);
894 } 899 }
895 return (CompResult){.type = COMP_NIL}; 900 return (CompResult){.type = COMP_NIL};
896 } 901 }
@@ -911,7 +916,7 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
911 if (fun.return_arity > 0) { 916 if (fun.return_arity > 0) {
912 // Put the return data into a register 917 // Put the return data into a register
913 sz ret_size = add_constant(chunk, 8); 918 sz ret_size = add_constant(chunk, 8);
914 EMIT_OP(OP_RESERVE, ret_size, 0, 0, node, chunk); 919 emit_op(OP_RESERVE, ret_size, 0, 0, node, chunk);
915 } 920 }
916 921
917 // Send parameters to the stack. 922 // Send parameters to the stack.
@@ -921,10 +926,10 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
921 // TODO: Assuming all values are 8 bytes... again. 926 // TODO: Assuming all values are 8 bytes... again.
922 switch (result.type) { 927 switch (result.type) {
923 case COMP_CONST: { 928 case COMP_CONST: {
924 EMIT_OP(OP_PUSHI, result.idx, 0, 0, expr, chunk); 929 emit_op(OP_PUSHI, result.idx, 0, 0, expr, chunk);
925 } break; 930 } break;
926 case COMP_REG: { 931 case COMP_REG: {
927 EMIT_OP(OP_PUSH, result.idx, 0, 0, expr, chunk); 932 emit_op(OP_PUSH, result.idx, 0, 0, expr, chunk);
928 } break; 933 } break;
929 default: { 934 default: {
930 return (CompResult){.type = COMP_ERR}; 935 return (CompResult){.type = COMP_ERR};
@@ -932,13 +937,13 @@ compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
932 } 937 }
933 } 938 }
934 939
935 EMIT_OP(OP_CALL, fun.index, 0, 0, node, chunk); 940 emit_op(OP_CALL, fun.index, 0, 0, node, chunk);
936 941
937 // Only one return parameter for now. 942 // Only one return parameter for now.
938 if (fun.return_arity > 0) { 943 if (fun.return_arity > 0) {
939 // Put the return data into a register 944 // Put the return data into a register
940 sz reg_dst = chunk->reg_idx++; 945 sz reg_dst = chunk->reg_idx++;
941 EMIT_OP(OP_POP, reg_dst, 0, 0, node, chunk); 946 emit_op(OP_POP, reg_dst, 0, 0, node, chunk);
942 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 947 return (CompResult){.type = COMP_REG, .idx = reg_dst};
943 } 948 }
944 949
@@ -955,10 +960,10 @@ compile_return(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
955 // Put return values into memory. 960 // Put return values into memory.
956 switch (res.type) { 961 switch (res.type) {
957 case COMP_CONST: { 962 case COMP_CONST: {
958 EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, chunk); 963 emit_op(OP_PUTRETI, res.idx, 0, 0, node, chunk);
959 } break; 964 } break;
960 case COMP_REG: { 965 case COMP_REG: {
961 EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, chunk); 966 emit_op(OP_PUTRET, res.idx, 0, 0, node, chunk);
962 } break; 967 } break;
963 default: { 968 default: {
964 return (CompResult){.type = COMP_ERR}; 969 return (CompResult){.type = COMP_ERR};
@@ -967,7 +972,7 @@ compile_return(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
967 break; 972 break;
968 } 973 }
969 974
970 EMIT_OP(OP_RET, 0, 0, 0, node, chunk); 975 emit_op(OP_RET, 0, 0, 0, node, chunk);
971 return (CompResult){.type = COMP_RET}; 976 return (CompResult){.type = COMP_RET};
972} 977}
973 978
@@ -1054,15 +1059,15 @@ compile_function(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1054 // Put return values into memory. 1059 // Put return values into memory.
1055 switch (res.type) { 1060 switch (res.type) {
1056 case COMP_CONST: { 1061 case COMP_CONST: {
1057 EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, func); 1062 emit_op(OP_PUTRETI, res.idx, 0, 0, node, func);
1058 } break; 1063 } break;
1059 case COMP_REG: { 1064 case COMP_REG: {
1060 EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, func); 1065 emit_op(OP_PUTRET, res.idx, 0, 0, node, func);
1061 } break; 1066 } break;
1062 default: break; 1067 default: break;
1063 } 1068 }
1064 1069
1065 EMIT_OP(OP_RET, 0, 0, 0, node, func); 1070 emit_op(OP_RET, 0, 0, 0, node, func);
1066 verify_chunk(func); 1071 verify_chunk(func);
1067 return (CompResult){.type = COMP_NIL}; 1072 return (CompResult){.type = COMP_NIL};
1068} 1073}
@@ -1130,9 +1135,11 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1130 }; 1135 };
1131 } break; 1136 } break;
1132 case NODE_LET: { 1137 case NODE_LET: {
1138 u8 op_ldaddr = OP_LDGADDR;
1133 u8 op_stvari = OP_STGVARI; 1139 u8 op_stvari = OP_STGVARI;
1134 u8 op_stvar = OP_STGVAR; 1140 u8 op_stvar = OP_STGVAR;
1135 if (!str_eq(chunk->name, cstr(".main"))) { 1141 if (!str_eq(chunk->name, cstr(".main"))) {
1142 op_ldaddr = OP_LDLADDR;
1136 op_stvari = OP_STLVARI; 1143 op_stvari = OP_STLVARI;
1137 op_stvar = OP_STLVAR; 1144 op_stvar = OP_STLVAR;
1138 } 1145 }
@@ -1154,12 +1161,39 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1154 compile_expr(chunk, node->var.val, lab_pre, lab_post); 1161 compile_expr(chunk, node->var.val, lab_pre, lab_post);
1155 switch (res.type) { 1162 switch (res.type) {
1156 case COMP_CONST: { 1163 case COMP_CONST: {
1157 EMIT_OP(op_stvari, idx, res.idx, 0, node->var.val, 1164 emit_op(op_stvari, idx, res.idx, 0, node->var.val,
1158 chunk); 1165 chunk);
1159 } break; 1166 } break;
1160 case COMP_REG: { 1167 case COMP_REG: {
1161 EMIT_OP(op_stvar, idx, res.idx, 0, node->var.val, 1168 emit_op(op_stvar, idx, res.idx, 0, node->var.val,
1169 chunk);
1170 } break;
1171 case COMP_STRING: {
1172 sz reg_addr = chunk->reg_idx++;
1173 sz reg_str = chunk->reg_idx++;
1174 sz reg_val = chunk->reg_idx++;
1175
1176 // Get the address for the local/global storage
1177 // variable.
1178 emit_op(op_ldaddr, reg_addr, idx, 0, node->var.name,
1179 chunk);
1180
1181 // Get the address for the string value variable.
1182 emit_op(OP_LDSTR, reg_str, res.idx, 0, node->var.val,
1183 chunk);
1184
1185 // Store the fat string pointer into the variable.
1186 sz zero = add_constant(chunk, 0);
1187 sz one = add_constant(chunk, 1);
1188
1189 // Get the value for the first word of the string
1190 // pointer.
1191 emit_op(OP_LD64I, reg_val, reg_str, zero, node->var.val,
1192 chunk);
1193 emit_op(OP_ST64I, reg_val, reg_addr, zero, node, chunk);
1194 emit_op(OP_LD64I, reg_val, reg_str, one, node->var.val,
1162 chunk); 1195 chunk);
1196 emit_op(OP_ST64I, reg_val, reg_addr, one, node, chunk);
1163 } break; 1197 } break;
1164 default: { 1198 default: {
1165 return (CompResult){.type = COMP_ERR}; 1199 return (CompResult){.type = COMP_ERR};
@@ -1202,7 +1236,7 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1202 switch (res.type) { 1236 switch (res.type) {
1203 case COMP_CONST: { 1237 case COMP_CONST: {
1204 reg_val = chunk->reg_idx++; 1238 reg_val = chunk->reg_idx++;
1205 EMIT_OP(OP_LD64K, reg_val, res.idx, 0, node, chunk); 1239 emit_op(OP_LD64K, reg_val, res.idx, 0, node, chunk);
1206 } break; 1240 } break;
1207 case COMP_REG: { 1241 case COMP_REG: {
1208 reg_val = res.idx; 1242 reg_val = res.idx;
@@ -1216,10 +1250,10 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1216 sz reg_addr = chunk->reg_idx++; 1250 sz reg_addr = chunk->reg_idx++;
1217 // Is this a pointer access or an array access? 1251 // Is this a pointer access or an array access?
1218 if (str_has_prefix(map->val.type, cstr("[]"))) { 1252 if (str_has_prefix(map->val.type, cstr("[]"))) {
1219 EMIT_OP(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, 1253 emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val,
1220 chunk); 1254 chunk);
1221 } else { 1255 } else {
1222 EMIT_OP(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, 1256 emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val,
1223 chunk); 1257 chunk);
1224 } 1258 }
1225 1259
@@ -1228,11 +1262,11 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1228 chunk, node->var.name->sym.arr_size, lab_pre, lab_post); 1262 chunk, node->var.name->sym.arr_size, lab_pre, lab_post);
1229 switch (idx.type) { 1263 switch (idx.type) {
1230 case COMP_CONST: { 1264 case COMP_CONST: {
1231 EMIT_OP(OP_ST64I, reg_val, reg_addr, idx.idx, node, 1265 emit_op(OP_ST64I, reg_val, reg_addr, idx.idx, node,
1232 chunk); 1266 chunk);
1233 } break; 1267 } break;
1234 case COMP_REG: { 1268 case COMP_REG: {
1235 EMIT_OP(OP_ST64, reg_val, reg_addr, idx.idx, node, 1269 emit_op(OP_ST64, reg_val, reg_addr, idx.idx, node,
1236 chunk); 1270 chunk);
1237 } break; 1271 } break;
1238 default: { 1272 default: {
@@ -1245,11 +1279,11 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1245 } 1279 }
1246 switch (res.type) { 1280 switch (res.type) {
1247 case COMP_CONST: { 1281 case COMP_CONST: {
1248 EMIT_OP(op_stvari, map->val.idx, res.idx, 0, node->var.val, 1282 emit_op(op_stvari, map->val.idx, res.idx, 0, node->var.val,
1249 chunk); 1283 chunk);
1250 } break; 1284 } break;
1251 case COMP_REG: { 1285 case COMP_REG: {
1252 EMIT_OP(op_stvar, map->val.idx, res.idx, 0, node->var.val, 1286 emit_op(op_stvar, map->val.idx, res.idx, 0, node->var.val,
1253 chunk); 1287 chunk);
1254 } break; 1288 } break;
1255 default: { 1289 default: {
@@ -1282,10 +1316,11 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1282 } 1316 }
1283 Variable var = map->val; 1317 Variable var = map->val;
1284 u8 reg_dst = chunk->reg_idx++; 1318 u8 reg_dst = chunk->reg_idx++;
1285 if (node->is_ptr || str_has_prefix(var.type, cstr("[]"))) { 1319 if (node->is_ptr || str_has_prefix(var.type, cstr("[]")) ||
1286 EMIT_OP(op_ldaddr, reg_dst, var.idx, 0, node, chunk); 1320 str_eq(var.type, cstr("str"))) {
1321 emit_op(op_ldaddr, reg_dst, var.idx, 0, node, chunk);
1287 } else { 1322 } else {
1288 EMIT_OP(op_ldvar, reg_dst, var.idx, 0, node, chunk); 1323 emit_op(op_ldvar, reg_dst, var.idx, 0, node, chunk);
1289 } 1324 }
1290 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 1325 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1291 } break; 1326 } break;
@@ -1317,10 +1352,10 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1317 // Address. 1352 // Address.
1318 sz reg_addr = chunk->reg_idx++; 1353 sz reg_addr = chunk->reg_idx++;
1319 if (str_has_prefix(map->val.type, cstr("[]"))) { 1354 if (str_has_prefix(map->val.type, cstr("[]"))) {
1320 EMIT_OP(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, 1355 emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val,
1321 chunk); 1356 chunk);
1322 } else { 1357 } else {
1323 EMIT_OP(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, 1358 emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val,
1324 chunk); 1359 chunk);
1325 } 1360 }
1326 1361
@@ -1329,10 +1364,10 @@ compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
1329 compile_expr(chunk, node->sym.arr_size, lab_pre, lab_post); 1364 compile_expr(chunk, node->sym.arr_size, lab_pre, lab_post);
1330 switch (idx.type) { 1365 switch (idx.type) {
1331 case COMP_CONST: { 1366 case COMP_CONST: {
1332 EMIT_OP(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk); 1367 emit_op(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk);
1333 } break; 1368 } break;
1334 case COMP_REG: { 1369 case COMP_REG: {
1335 EMIT_OP(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk); 1370 emit_op(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk);
1336 } break; 1371 } break;
1337 default: { 1372 default: {
1338 return (CompResult){.type = COMP_ERR}; 1373 return (CompResult){.type = COMP_ERR};
@@ -1459,6 +1494,10 @@ disassemble_instruction(Instruction instruction) {
1459 println("%s r%d, v%d", op_str[instruction.op], instruction.dst, 1494 println("%s r%d, v%d", op_str[instruction.op], instruction.dst,
1460 instruction.a, instruction.b); 1495 instruction.a, instruction.b);
1461 break; 1496 break;
1497 case OP_LDSTR:
1498 println("%s r%d, s%d", op_str[instruction.op], instruction.dst,
1499 instruction.a, instruction.b);
1500 break;
1462 case OP_STGVAR: 1501 case OP_STGVAR:
1463 case OP_STLVAR: 1502 case OP_STLVAR:
1464 println("%s v%d, r%d", op_str[instruction.op], instruction.dst, 1503 println("%s v%d, r%d", op_str[instruction.op], instruction.dst,
@@ -1491,6 +1530,7 @@ disassemble_instruction(Instruction instruction) {
1491 case OP_PRINTS64: 1530 case OP_PRINTS64:
1492 case OP_PRINTF64: 1531 case OP_PRINTF64:
1493 case OP_PRINTSTR: 1532 case OP_PRINTSTR:
1533 case OP_PRINTSTRI:
1494 case OP_PUSH: 1534 case OP_PUSH:
1495 case OP_POP: 1535 case OP_POP:
1496 case OP_PUTRET: 1536 case OP_PUTRET:
diff --git a/src/main.c b/src/main.c
index 9f687ff..8e6b6c6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,7 +24,13 @@
24// add(12, 34) == 12.add(34) 24// add(12, 34) == 12.add(34)
25// concat(str, str): str 25// concat(str, str): str
26// "hello ".concat("world") ; "hello world" 26// "hello ".concat("world") ; "hello world"
27// TODO: more types 27// TODO: more integer types
28// TODO: string types
29// TODO: structs and user defined types
30// TODO: tail-call optimization.
31// TODO: constant folding
32// TODO: constexpr evaluation
33// TODO: shortcircuit evaluation for && and || operators.
28 34
29typedef enum ExecMode { 35typedef enum ExecMode {
30 RUN_NORMAL, 36 RUN_NORMAL,
@@ -227,7 +233,7 @@ process_file(Str path) {
227 } break; 233 } break;
228 default: break; 234 default: break;
229 } 235 }
230 EMIT_OP(OP_HALT, res_reg, !is_nil, 0, NULL, &chunk); 236 emit_op(OP_HALT, res_reg, !is_nil, 0, NULL, &chunk);
231 verify_chunk(&chunk); 237 verify_chunk(&chunk);
232 238
233 disassemble_chunk(chunk); 239 disassemble_chunk(chunk);
diff --git a/src/vm.c b/src/vm.c
index f363e26..404f410 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -196,8 +196,14 @@ vm_run(VM *vm) {
196 Variable var = vm->chunk->vars[src]; 196 Variable var = vm->chunk->vars[src];
197 vm->regs[dst].i = (ptrsize)&vm->fp[var.offset / 8]; 197 vm->regs[dst].i = (ptrsize)&vm->fp[var.offset / 8];
198 } break; 198 } break;
199 case OP_LDSTR: {
200 u8 dst = instruction.dst;
201 u8 src = instruction.a;
202 Str *str = &vm->chunk->strings[src];
203 vm->regs[dst].ptr = (ptrsize)str;
204 } break;
199 case OP_ST64I: { 205 case OP_ST64I: {
200 sz value = vm->regs[instruction.dst].i; 206 sz value = vm->regs[instruction.dst].ptr;
201 s64 *addr = (s64 *)vm->regs[instruction.a].ptr; 207 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
202 sz offset = vm->chunk->constants[instruction.b].i; 208 sz offset = vm->chunk->constants[instruction.b].i;
203 addr[offset] = value; 209 addr[offset] = value;
@@ -293,6 +299,11 @@ vm_run(VM *vm) {
293 } break; 299 } break;
294 case OP_PRINTSTR: { 300 case OP_PRINTSTR: {
295 u8 idx = instruction.dst; 301 u8 idx = instruction.dst;
302 Str *string = (Str*)vm->regs[idx].ptr;
303 print("%s", *string);
304 } break;
305 case OP_PRINTSTRI: {
306 u8 idx = instruction.dst;
296 Str string = vm->chunk->strings[idx]; 307 Str string = vm->chunk->strings[idx];
297 print("%s", string); 308 print("%s", string);
298 } break; 309 } break;
diff --git a/tests/compilation.bad b/tests/compilation.bad
index 09bfa3c..b1fec85 100644
--- a/tests/compilation.bad
+++ b/tests/compilation.bad
@@ -1,18 +1,26 @@
1fun printer(): nil println("hey!") 1let name = "hello"
2; let wow = name
3; let greeting = "yomama"
2 4
3let y = 4 5println(name wow)
4fun nested(): nil {
5 fun adder(a: int b: int): int {
6 fun printer(): nil println("ho!")
7 printer()
8 printer()
9 printer()
10 y + a + b
11 }
12 for let i = 0, i < 10, set i += 1 {
13 println("i: " i " " adder(i, 2))
14 }
15}
16 6
17nested() 7; fun greet(name: str): nil println("hello " name "!")
18printer() 8
9; greet(name)
10
11; let y = 4
12; fun nested(): nil {
13; fun adder(a: int b: int): int {
14; fun printer(): nil println("ho!")
15; printer()
16; printer()
17; printer()
18; y + a + b
19; }
20; for let i = 0, i < 10, set i += 1 {
21; println("i: " i " " adder(i, 2))
22; }
23; }
24
25; nested()
26; printer()