aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Winston2023-05-21 19:55:04 -0400
committerBen Winston2023-05-21 19:55:04 -0400
commita26bfccdc52ab50a83b8f8d170c9e1a3be0164a5 (patch)
treeb12118bebf7e22a29fa4d953ee3a8b7085008612
parent618de4c70d8916f64781997f3ae538e3e6109d00 (diff)
'or' control statement
-rw-r--r--chunk.d1
-rw-r--r--compiler.d23
-rw-r--r--dbg.d2
-rw-r--r--parser.d37
-rw-r--r--vm.d12
5 files changed, 74 insertions, 1 deletions
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;