aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-29 19:49:56 +0200
committerBad Diode <bd@badd10de.dev>2024-06-29 19:49:56 +0200
commitc9a2dab875784262069ecb17ba146e8b0619317a (patch)
tree04a600f7385bbb74f38fdac33a4563fb1929f0bf /src
parentb643366c0ef18c27aa1ac52e1dd035f1d6efa45e (diff)
downloadbdl-c9a2dab875784262069ecb17ba146e8b0619317a.tar.gz
bdl-c9a2dab875784262069ecb17ba146e8b0619317a.zip
Add if/else expressions
Diffstat (limited to 'src')
-rw-r--r--src/compiler.c136
-rw-r--r--src/vm.c60
2 files changed, 185 insertions, 11 deletions
diff --git a/src/compiler.c b/src/compiler.c
index 84cc99a..5bddcb6 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -148,6 +148,13 @@ typedef enum OpCode {
148 OP_BITAND, // band rx, ra, rb 148 OP_BITAND, // band rx, ra, rb
149 OP_BITOR, // bor rx, ra, rb 149 OP_BITOR, // bor rx, ra, rb
150 OP_BITNOT, // bnot rx, ra 150 OP_BITNOT, // bnot rx, ra
151 // Jump instructions.
152 OP_JMPI, // jmp cx ; cx := signed offset
153 OP_JMPFI, // jmpf cx, ca ; rx := condition, ca := offset
154 OP_JMPTI, // jmpt cx, ca ; rx := condition, ca := offset
155 OP_JMP, // jmp rx ; rx := signed offset
156 OP_JMPF, // jmpf rx, ca ; rx := condition, ca := offset
157 OP_JMPT, // jmpt rx, ca ; rx := condition, ca := offset
151} OpCode; 158} OpCode;
152 159
153Str op_str[] = { 160Str op_str[] = {
@@ -233,6 +240,13 @@ Str op_str[] = {
233 [OP_BITAND] = cstr("BAND "), 240 [OP_BITAND] = cstr("BAND "),
234 [OP_BITOR] = cstr("BOR "), 241 [OP_BITOR] = cstr("BOR "),
235 [OP_BITNOT] = cstr("BNOT "), 242 [OP_BITNOT] = cstr("BNOT "),
243 // Jump instructions.
244 [OP_JMPI] = cstr("JMPI "),
245 [OP_JMPFI] = cstr("JMPFI "),
246 [OP_JMPTI] = cstr("JMPTI "),
247 [OP_JMP] = cstr("JMP "),
248 [OP_JMPF] = cstr("JMPF "),
249 [OP_JMPT] = cstr("JMPT "),
236}; 250};
237 251
238typedef enum { 252typedef enum {
@@ -434,9 +448,105 @@ compile_unary(Chunk *chunk, Node *node) {
434 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 448 return (CompResult){.type = COMP_REG, .idx = reg_dst};
435} 449}
436 450
451sz
452add_constant(Chunk *chunk, sz value) {
453 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
454 // Make sure we don't have duplicated constants.
455 if (!map) {
456 map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++,
457 chunk->storage);
458 Constant c = (Constant){.i = value};
459 array_push(chunk->constants, c, chunk->storage);
460 }
461 return map->val;
462}
463
464CompResult
465compile_if(Chunk *chunk, Node *node) {
466 CompResult cond = compile_expr(chunk, node->cond_if);
467 OpCode jmpop;
468 switch (cond.type) {
469 case COMP_CONST: {
470 jmpop = OP_JMPFI;
471 } break;
472 case COMP_REG: {
473 jmpop = OP_JMPF;
474 } break;
475 default: {
476 return (CompResult){.type = COMP_ERR};
477 } break;
478 }
479 sz jump_a = array_size(chunk->code);
480 sz reg_dst = 255;
481 bool has_value = !str_eq(node->type, cstr("nil"));
482 if (has_value) {
483 reg_dst = chunk->reg_idx++;
484 }
485
486 // Jump to the `false` branch.
487 EMIT_OP(jmpop, cond.idx, 0xff, 0, node->cond_if, chunk);
488
489 // Condition is true.
490 CompResult then_expr = compile_expr(chunk, node->cond_expr);
491 if (has_value) {
492 switch (then_expr.type) {
493 case COMP_CONST: {
494 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if,
495 chunk);
496 } break;
497 case COMP_REG: {
498 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if,
499 chunk);
500 } break;
501 default: {
502 return (CompResult){.type = COMP_ERR};
503 } break;
504 }
505 }
506
507 // Jump to the end of the expression.
508 sz jump_b = array_size(chunk->code);
509 EMIT_OP(OP_JMPI, 0xff, 0, 0, node->cond_if, chunk);
510
511 // Else expression.
512 CompResult else_expr = compile_expr(chunk, node->cond_else);
513 if (has_value) {
514 switch (else_expr.type) {
515 case COMP_CONST: {
516 EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, node->cond_if,
517 chunk);
518 } break;
519 case COMP_REG: {
520 EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, node->cond_if,
521 chunk);
522 } break;
523 default: {
524 return (CompResult){.type = COMP_ERR};
525 } break;
526 }
527 }
528 sz end_expr = array_size(chunk->code);
529
530 // Backpatch jumps.
531 sz const_a = add_constant(chunk, jump_b + 1 - jump_a);
532 sz const_b = add_constant(chunk, end_expr - jump_b);
533 chunk->code[jump_a].a = const_a;
534 chunk->code[jump_b].dst = const_b;
535 // TODO: does it has an else or not? Moreover, should we enforce on the
536 // semantic level that if the `if` expression returns a value we must add an
537 // else?
538
539 // Return.
540 if (has_value) {
541 return (CompResult){.type = COMP_REG, .idx = reg_dst};
542 }
543 return (CompResult){.type = COMP_NIL};
544}
545
437CompResult 546CompResult
438compile_expr(Chunk *chunk, Node *node) { 547compile_expr(Chunk *chunk, Node *node) {
439 switch (node->kind) { 548 switch (node->kind) {
549 case NODE_IF: return compile_if(chunk, node);
440 // Logic. 550 // Logic.
441 // case NODE_XOR: 551 // case NODE_XOR:
442 case NODE_BITNOT: 552 case NODE_BITNOT:
@@ -466,17 +576,10 @@ compile_expr(Chunk *chunk, Node *node) {
466 case NODE_NUM_UINT: 576 case NODE_NUM_UINT:
467 case NODE_NUM_INT: { 577 case NODE_NUM_INT: {
468 sz value = node->value.i; 578 sz value = node->value.i;
469 // Make sure we don't have duplicated constants. 579 sz const_idx = add_constant(chunk, value);
470 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
471 if (!map) {
472 map = intintmap_insert(&chunk->intmap, value,
473 chunk->const_idx++, chunk->storage);
474 Constant c = (Constant){.i = node->value.i};
475 array_push(chunk->constants, c, chunk->storage);
476 }
477 return (CompResult){ 580 return (CompResult){
478 .type = COMP_CONST, 581 .type = COMP_CONST,
479 .idx = map->val, 582 .idx = const_idx,
480 }; 583 };
481 } break; 584 } break;
482 case NODE_STRING: { 585 case NODE_STRING: {
@@ -577,6 +680,8 @@ disassemble_instruction(Instruction instruction) {
577 case OP_LD16K: 680 case OP_LD16K:
578 case OP_LD32K: 681 case OP_LD32K:
579 case OP_LD64K: 682 case OP_LD64K:
683 case OP_JMPF:
684 case OP_JMPT:
580 println("%s r%d, c%d", op_str[instruction.op], instruction.dst, 685 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
581 instruction.a, instruction.b); 686 instruction.a, instruction.b);
582 break; 687 break;
@@ -668,6 +773,19 @@ disassemble_instruction(Instruction instruction) {
668 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 773 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
669 instruction.a, instruction.b); 774 instruction.a, instruction.b);
670 break; 775 break;
776 case OP_JMPI:
777 println("%s c%d", op_str[instruction.op], instruction.dst,
778 instruction.a, instruction.b);
779 break;
780 case OP_JMP:
781 println("%s r%d", op_str[instruction.op], instruction.dst,
782 instruction.a, instruction.b);
783 break;
784 case OP_JMPFI:
785 case OP_JMPTI:
786 println("%s c%d, c%d", op_str[instruction.op], instruction.dst,
787 instruction.a, instruction.b);
788 break;
671 case OP_HALT: println("%s", op_str[instruction.op]); break; 789 case OP_HALT: println("%s", op_str[instruction.op]); break;
672 default: println("Unknown opcode %d", instruction.op); break; 790 default: println("Unknown opcode %d", instruction.op); break;
673 } 791 }
diff --git a/src/vm.c b/src/vm.c
index 4e15bee..205c15a 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -137,7 +137,6 @@ vm_run(VM *vm) {
137 case OP_LDGVAR: { 137 case OP_LDGVAR: {
138 u8 dst = instruction.dst; 138 u8 dst = instruction.dst;
139 u8 src = instruction.a; 139 u8 src = instruction.a;
140 println("dst: %d src: %d", dst, src);
141 Variable var = vm->chunk->vars[src]; 140 Variable var = vm->chunk->vars[src];
142 s64 *stack = (s64 *)&vm->stack[var.offset]; 141 s64 *stack = (s64 *)&vm->stack[var.offset];
143 vm->regs[dst].i = *stack; 142 vm->regs[dst].i = *stack;
@@ -156,6 +155,62 @@ vm_run(VM *vm) {
156 s64 *stack = (s64 *)&vm->stack[var.offset]; 155 s64 *stack = (s64 *)&vm->stack[var.offset];
157 *stack = vm->chunk->constants[src].i; 156 *stack = vm->chunk->constants[src].i;
158 } break; 157 } break;
158 case OP_JMPI: {
159 sz offset = vm->chunk->constants[instruction.dst].i;
160 vm->ip += offset - 1;
161 } break;
162 case OP_JMPFI: {
163 bool cond = vm->chunk->constants[instruction.dst].i;
164 sz offset = vm->chunk->constants[instruction.a].i;
165 if (!cond) {
166 vm->ip += offset - 1;
167 }
168 } break;
169 case OP_JMPTI: {
170 bool cond = vm->chunk->constants[instruction.dst].i;
171 sz offset = vm->chunk->constants[instruction.a].i;
172 if (cond) {
173 vm->ip += offset - 1;
174 }
175 } break;
176 case OP_JMP: {
177 sz offset = vm->chunk->constants[instruction.dst].i;
178 vm->ip += offset - 1;
179 } break;
180 case OP_JMPF: {
181 bool cond = vm->regs[instruction.dst].i;
182 sz offset = vm->chunk->constants[instruction.a].i;
183 if (!cond) {
184 vm->ip += offset - 1;
185 }
186 } break;
187 case OP_JMPT: {
188 bool cond = vm->regs[instruction.dst].i;
189 sz offset = vm->chunk->constants[instruction.a].i;
190 if (cond) {
191 vm->ip += offset - 1;
192 }
193 } break;
194 case OP_MOV64: {
195 u8 dst = instruction.dst;
196 u8 src = instruction.a;
197 vm->regs[dst] = vm->regs[src];
198 } break;
199 case OP_MOV32: {
200 u8 dst = instruction.dst;
201 u8 src = instruction.a;
202 vm->regs[dst].i = vm->regs[src].i & 0xFFFFFFFF;
203 } break;
204 case OP_MOV16: {
205 u8 dst = instruction.dst;
206 u8 src = instruction.a;
207 vm->regs[dst].i = vm->regs[src].i & 0xFFFF;
208 } break;
209 case OP_MOV8: {
210 u8 dst = instruction.dst;
211 u8 src = instruction.a;
212 vm->regs[dst].i = vm->regs[src].i & 0xFF;
213 } break;
159 case OP_HALT: { 214 case OP_HALT: {
160 println("VM HALT (int) -> %d", vm->regs[instruction.dst]); 215 println("VM HALT (int) -> %d", vm->regs[instruction.dst]);
161 println("VM HALT (float) -> %f", vm->regs[instruction.dst]); 216 println("VM HALT (float) -> %f", vm->regs[instruction.dst]);
@@ -163,7 +218,8 @@ vm_run(VM *vm) {
163 return; 218 return;
164 } 219 }
165 default: { 220 default: {
166 eprintln("unimplemented OP code: %d", instruction.op); 221 // eprintln("unimplemented OP code: %d", instruction.op);
222 eprintln("unimplemented OP code: %s", op_str[instruction.op]);
167 return; 223 return;
168 } 224 }
169 } 225 }