import std.stdio; import std.string; import chunk; import parser; //import value; //import obj; import dbg; enum InterpretResult { OK, COMPILE_ERROR, RUNTIME_ERROR, } class VM { int topOffset = 0; ubyte ip = 0; Value[] stack; //ObjFunction func; Function func; this(Function func) { this.func = func; } Value peek(int offset) { if (offset >= this.topOffset) { writefln("offset of %d greater than stack size %d", offset, topOffset); } return this.stack[topOffset - offset - 1]; } Value pop() { if (this.topOffset > 0) { this.topOffset--; } else { writeln("pop() on an empty stack!!"); } return this.stack[this.topOffset]; } //InterpretResult push(Value value) { void push(Value value) { if (this.stack.length > this.topOffset) { this.stack[topOffset] = value; } else { this.stack ~= value; } this.topOffset++; } ubyte readByte() { return this.func.chunk.code[this.ip++]; } bool isNumber(Value value) { return value.type == ValueType.NUMBER; } double asNumber(Value value) { return value.as.number; } InterpretResult run() { //int ip = 0; // TODO this is wrong while (true) { write(" "); //foreach (Value val; this.stack) { for (int i = 0; i < this.topOffset; i++) { writef("[ %s ]", printableValue(this.stack[i])); } writeln("\n--"); disassemble(this.func.chunk, this.ip); ubyte inst; switch (inst = this.readByte()) { case OpCode.OP_CONSTANT: Value constant = this.func.chunk.constants[this.readByte()]; this.push(constant); break; case OpCode.OP_NEGATE: if (!isNumber(peek(0))) { writeln("negate operand must be a number"); return InterpretResult.RUNTIME_ERROR; } double val = asNumber(pop()); push(makeNumberValue(val * -1)); break; case OpCode.OP_ADD: Value b = this.pop(); if (!isNumber(b)) { writeln("b is not a number!"); return InterpretResult.RUNTIME_ERROR; // TODO error } Value a = this.pop(); if (!isNumber(a)) { writeln("a is not a number!"); return InterpretResult.RUNTIME_ERROR; // TODO error } double bnum = asNumber(b); double anum = asNumber(a); push(makeNumberValue(anum + bnum)); break; case OpCode.OP_SUBTRACT: Value b = this.pop(); if (!isNumber(b)) { writeln("b is not a number!"); return InterpretResult.RUNTIME_ERROR; // TODO error } Value a = this.pop(); if (!isNumber(a)) { writeln("a is not a number!"); return InterpretResult.RUNTIME_ERROR; // TODO error } double bnum = asNumber(b); double anum = asNumber(a); push(makeNumberValue(anum - bnum)); break; case OpCode.OP_LESS: Value b = this.pop(); if (!isNumber(b)) { writeln("b is not a number!"); return InterpretResult.RUNTIME_ERROR; // TODO error } Value a = this.pop(); if (!isNumber(a)) { writeln("a is not a number!"); return InterpretResult.RUNTIME_ERROR; // TODO error } double bnum = asNumber(b); double anum = asNumber(a); push(makeBooleanValue(anum < bnum)); break; case OpCode.OP_RETURN: Value ret = this.pop(); writefln("returned %s", printableValue(ret)); return InterpretResult.OK; default: writeln("unknown opcode to run"); break; } } } }