From a26bfccdc52ab50a83b8f8d170c9e1a3be0164a5 Mon Sep 17 00:00:00 2001 From: Ben Winston Date: Sun, 21 May 2023 19:55:04 -0400 Subject: 'or' control statement --- chunk.d | 1 + compiler.d | 23 +++++++++++++++++++++++ dbg.d | 2 ++ parser.d | 37 +++++++++++++++++++++++++++++++++++++ vm.d | 12 +++++++++++- 5 files changed, 74 insertions(+), 1 deletion(-) diff --git a/chunk.d b/chunk.d index b3209a8..87c9fb6 100644 --- a/chunk.d +++ b/chunk.d @@ -51,6 +51,7 @@ enum OpCode { OP_JUMP, OP_JUMP_IF_FALSE, + OP_JUMP_IF_TRUE, } class Chunk { diff --git a/compiler.d b/compiler.d index c05aeaa..6482f50 100644 --- a/compiler.d +++ b/compiler.d @@ -242,6 +242,26 @@ class Compiler { } } + void compileOr(Form form) { + Or or_ = cast(Or)form; + + resolve(or_.clauses[0]); + int[] jumps; + jumps ~= jump(OpCode.OP_JUMP_IF_TRUE); + int count = 1; + while (count < or_.clauses.length) { + this.func.chunk.writeOp(OpCode.OP_POP, or_.line); + resolve(or_.clauses[count]); + jumps ~= jump(OpCode.OP_JUMP_IF_TRUE); + count++; + } + + // patch all the jumps + foreach (int jmp; jumps) { + patchJump(jmp); + } + } + void compileBlock(Form form) { Block block = cast(Block)form; beginScope(); @@ -327,6 +347,9 @@ class Compiler { case FormType.AND: this.compileAnd(form); break; + case FormType.OR: + this.compileOr(form); + break; default: write("not sure how to resolve: "); printForm(form); diff --git a/dbg.d b/dbg.d index e14e9fe..defa8ef 100644 --- a/dbg.d +++ b/dbg.d @@ -147,6 +147,8 @@ int disassemble(Chunk chunk, int offset) { return jumpInstruction("OP_JUMP", 1, chunk, offset); case OpCode.OP_JUMP_IF_FALSE: return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset); + case OpCode.OP_JUMP_IF_TRUE: + return jumpInstruction("OP_JUMP_IF_TRUE", 1, chunk, offset); default: writeln("unknown opcode?"); diff --git a/parser.d b/parser.d index 3dd32ef..0b8f863 100644 --- a/parser.d +++ b/parser.d @@ -16,6 +16,7 @@ enum FormType { BLOCK, IF, AND, + OR, EOF, PARSE_ERROR @@ -176,6 +177,20 @@ class And : Form { } } +class Or : Form { + + Form[] clauses; + + this(int line) { + this.line = line; + this.type = FormType.OR; + } + + void addClause(Form clause) { + clauses ~= clause; + } +} + class Func : Form { Symbol name; @@ -480,6 +495,26 @@ class Parser { } + Form parseOr() { + Or or_ = new Or(line); + char next; + while(peekable()) { + next = peek(); + if (next == ')') { + break; + } + or_.addClause(parseForm()); + } + + if (!peekable()) { + return new ParseError("unterminated or", line); + } + + advance(); // consume closing paren + + return or_; + } + Form parseBlock() { Block block = new Block(line); char next; @@ -526,6 +561,8 @@ class Parser { return parseIf(); case "and": return parseAnd(); + case "or": + return parseOr(); default: break; } diff --git a/vm.d b/vm.d index 45f3742..cc2b9ae 100644 --- a/vm.d +++ b/vm.d @@ -261,13 +261,23 @@ class VM { case OpCode.OP_JUMP_IF_FALSE: uint offset = readShort(); if (!isBoolean(peekA(0))) { - writeln("if expects a boolean condition"); + writeln("expecting a boolean condition"); return InterpretResult.RUNTIME_ERROR; // TODO error } if (!asBoolean(peekA(0))) { ip += offset; } break; + case OpCode.OP_JUMP_IF_TRUE: + uint offset = readShort(); + if (!isBoolean(peekA(0))) { + writeln("expecting a boolean condition"); + return InterpretResult.RUNTIME_ERROR; // TODO error + } + if (asBoolean(peekA(0))) { + ip += offset; + } + break; default: writeln("unknown opcode to run"); break; -- cgit v1.2.3