diff options
author | Bad Diode <bd@badd10de.dev> | 2024-07-04 20:45:27 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-07-04 20:45:27 +0200 |
commit | 1ea4d6f2aab4157dbe7da328b11ef6bb0a1fc5a0 (patch) | |
tree | b66d3ca5237426a100dc8688e2aefee82ef21723 /src | |
parent | 81aca08fa680c8747ad3afff0594c4e8830b0ec8 (diff) | |
download | bdl-1ea4d6f2aab4157dbe7da328b11ef6bb0a1fc5a0.tar.gz bdl-1ea4d6f2aab4157dbe7da328b11ef6bb0a1fc5a0.zip |
Add storage of Str values on locals/globals
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler.c | 184 | ||||
-rw-r--r-- | src/main.c | 10 | ||||
-rw-r--r-- | src/vm.c | 13 |
3 files changed, 132 insertions, 75 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 | ||
329 | CompResult compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post); | 332 | CompResult compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post); |
330 | 333 | ||
331 | #define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ | 334 | void |
332 | do { \ | 335 | emit_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 | ||
348 | CompResult | 350 | CompResult |
349 | compile_binary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) { | 351 | compile_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) { | |||
798 | CompResult | 800 | CompResult |
799 | compile_break(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) { | 801 | compile_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 | ||
805 | CompResult | 807 | CompResult |
806 | compile_continue(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) { | 808 | compile_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: |
@@ -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 | ||
29 | typedef enum ExecMode { | 35 | typedef 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); |
@@ -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; |