From dd5210368634e2b322435385eaaaccaa5125b5a9 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sun, 24 Oct 2021 15:42:01 +0200 Subject: Add initial IF implementation --- src/bytecode/compiler.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ src/bytecode/debug.h | 3 +++ src/bytecode/ops.h | 3 +++ src/bytecode/vm.h | 10 ++++++++ 4 files changed, 82 insertions(+) (limited to 'src') diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h index b1cdfb9..559ad1c 100755 --- a/src/bytecode/compiler.h +++ b/src/bytecode/compiler.h @@ -231,6 +231,71 @@ compile_declare_op(Chunk *chunk, Visitor *vs, Token start, Ops op) { add_code(chunk, op, start.line, start.column); } +void +compile_if_op(Chunk *chunk, Visitor *vs, Token start) { + Token tok = peek_token(vs); + if (tok.type == TOKEN_EOF) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_UNBALANCED_PAREN, + .line = start.line, + .col = start.column, + }); + return; + } + if (tok.type == TOKEN_RPAREN) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_NOT_ENOUGH_ARGS, + .line = start.line, + .col = start.column, + }); + return; + } + + // Condition. + parse_tree(chunk, vs); + emit_constant(chunk, tok, FIXNUM_VAL(0xFF)); + size_t pos = array_size(chunk->code); + add_code(chunk, OP_JUMP_IF_FALSE, start.line, start.column); + + // Block true. + parse_tree(chunk, vs); + + // No else. + if (peek_token(vs).type == TOKEN_RPAREN) { + size_t false_block_start = array_size(chunk->code) - pos - 1; + size_t num_idx = add_constant(chunk, FIXNUM_VAL(false_block_start)); + chunk->code[pos - 1] = num_idx; + next_token(vs); + return; + } + + // Else. + emit_constant(chunk, tok, FIXNUM_VAL(0xFF)); + size_t else_pos = array_size(chunk->code); + add_code(chunk, OP_JUMP, start.line, start.column); + + size_t false_block_start = array_size(chunk->code) - pos - 1; + size_t num_idx = add_constant(chunk, FIXNUM_VAL(false_block_start)); + chunk->code[pos - 1] = num_idx; + parse_tree(chunk, vs); + false_block_start = array_size(chunk->code) - else_pos - 1; + num_idx = add_constant(chunk, FIXNUM_VAL(false_block_start)); + chunk->code[else_pos - 1] = num_idx; + + if (peek_token(vs).type != TOKEN_RPAREN) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_TOO_MANY_ARGS, + .line = start.line, + .col = start.column, + }); + return; + } + next_token(vs); +} + void parse_list(Chunk *chunk, Visitor *vs, Token start) { if (!has_next_token(vs)) { @@ -262,6 +327,7 @@ parse_list(Chunk *chunk, Visitor *vs, Token start) { case TOKEN_NEWLINE: { compile_list_simple_op(chunk, vs, start, OP_NEWLINE); } break; case TOKEN_DEF: { compile_declare_op(chunk, vs, start, OP_DEF); } break; case TOKEN_SET: { compile_declare_op(chunk, vs, start, OP_SET); } break; + case TOKEN_IF: { compile_if_op(chunk, vs, start); } break; default: { error_push((Error){ .type = ERR_TYPE_COMPILER, diff --git a/src/bytecode/debug.h b/src/bytecode/debug.h index 889ae03..674d469 100755 --- a/src/bytecode/debug.h +++ b/src/bytecode/debug.h @@ -28,6 +28,9 @@ static const char* ops_str[] = { [OP_GREATER] = "OP_GREATER", [OP_LESS_EQUAL] = "OP_LESS_EQUAL", [OP_GREATER_EQUAL] = "OP_GREATER_EQUAL", + // Jump/conditional ops. + [OP_JUMP] = "OP_JUMP", + [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", // Display ops. [OP_DISPLAY] = "OP_DISPLAY", [OP_PRINT] = "OP_PRINT", diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h index 50d12fe..5eacaea 100755 --- a/src/bytecode/ops.h +++ b/src/bytecode/ops.h @@ -23,6 +23,9 @@ typedef enum Ops { OP_GREATER, OP_LESS_EQUAL, OP_GREATER_EQUAL, + // Jump/conditional ops. + OP_JUMP, + OP_JUMP_IF_FALSE, // Display ops. OP_DISPLAY, OP_PRINT, diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index 51a6f44..b24a5fa 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h @@ -196,6 +196,16 @@ vm_interpret(VM *vm, Chunk *chunk) { case OP_GREATER: { FIXNUM_COMPARE_OP(>); } break; case OP_LESS_EQUAL: { FIXNUM_COMPARE_OP(<=); } break; case OP_GREATER_EQUAL: { FIXNUM_COMPARE_OP(>=); } break; + case OP_JUMP: { + ssize_t off = AS_FIXNUM(array_pop(vm->stack)); + vm->pc += off; + } break; + case OP_JUMP_IF_FALSE: { + ssize_t off = AS_FIXNUM(array_pop(vm->stack)); + if (IS_FALSE(array_pop(vm->stack))) { + vm->pc += off; + } + } break; case OP_DISPLAY: { display(array_pop(vm->stack)); } break; -- cgit v1.2.1