aboutsummaryrefslogtreecommitdiff
path: root/vm.d
diff options
context:
space:
mode:
Diffstat (limited to 'vm.d')
-rw-r--r--vm.d198
1 files changed, 174 insertions, 24 deletions
diff --git a/vm.d b/vm.d
index cc2b9ae..ef6efbf 100644
--- a/vm.d
+++ b/vm.d
@@ -4,6 +4,7 @@ import std.conv;
import chunk;
import parser;
+import compiler;
//import value;
//import obj;
import dbg;
@@ -14,20 +15,52 @@ enum InterpretResult {
RUNTIME_ERROR,
}
+struct CallFrame {
+ Function func;
+ ubyte ip;
+ Value[] slots;
+ int frameStart;
+}
+
class VM {
//int topOffset = 0;
+ /*
ubyte ip = 0;
+ */
+ CallFrame[] frames;
+ CallFrame* current;
+ int frameCount;
+
Value[] aStack;
- int aTop = 0;
+ int aTop;
Value[] bStack;
- int bTop = 0;
+ int bTop;
+
//ObjFunction func;
- Function func;
+ //Function func;
Value[string] globals;
+ /*
this(Function func) {
this.func = func;
}
+ */
+
+ this() {
+ this.aTop = 0;
+ this.bTop = 0;
+ this.frameCount = 0;
+ }
+
+ void pushFrame(CallFrame frame) {
+ if (this.frameCount < frames.length) {
+ this.frames[this.frameCount] = frame;
+ } else {
+ this.frames ~= frame;
+ }
+ current = &frames[this.frameCount];
+ frameCount++;
+ }
Value peekA(int offset) {
if (offset >= aTop) {
@@ -58,14 +91,28 @@ class VM {
Value popB() {
if (bTop > 0) {
bTop--;
+ //current.frameStart--;
} else {
writeln("popB() on an empty stack!!");
}
- return bStack[bTop];
+ //return bStack[bTop];
+ return current.slots[bTop - current.frameStart - 1];
}
void pushB(Value value) {
+
+ /*
+ writefln("length %d, bTop %d", current.slots.length, bTop);
+ if (current.slots.length > bTop) {
+ current.slots[bTop] = value;
+ } else {
+ current.slots ~= value;
+ }
+ bTop++;
+ current.frameStart++;
+ */
+
if (bStack.length > bTop) {
bStack[bTop] = value;
} else {
@@ -75,16 +122,15 @@ class VM {
}
ubyte readByte() {
- return this.func.chunk.code[this.ip++];
+ return current.func.chunk.code[current.ip++];
}
uint readShort() {
- ip += 2;
- uint high = this.func.chunk.code[ip - 2] << 8;
- uint low = this.func.chunk.code[ip - 1];
+ current.ip += 2;
+ uint high = current.func.chunk.code[current.ip - 2] << 8;
+ uint low = current.func.chunk.code[current.ip - 1];
return high | low;
-
//return 0;
}
@@ -100,6 +146,14 @@ class VM {
return value.type == ValueType.BOOLEAN;
}
+ bool isObj(Value value) {
+ return value.type == ValueType.OBJ;
+ }
+
+ ObjType objTypeOf(Value value) {
+ return value.as.obj.type;
+ }
+
double asNumber(Value value) {
return value.as.number;
}
@@ -112,15 +166,52 @@ class VM {
return value.as.boolean;
}
+ Function asFunction(Value value) {
+ return cast(Function)value.as.obj;
+ }
+
/*
bool isFalsey(Value val) {
return isBoolean(val) && val.as.boolean;
}
*/
+ /*
+ CallFrame currentFrame() {
+ return frames[frameCount - 1];
+ }
+ */
+
+ bool callValue(Value callee, int argCount) {
+ if (isObj(callee)) {
+ switch (callee.as.obj.type) {
+ case ObjType.FUNCTION:
+ return call(asFunction(callee), argCount);
+ case ObjType.SCRIPT:
+ writeln("trying to call the script?");
+ break;
+ default:
+ break;
+ }
+ } else {
+ writeln("callee is not an object :(");
+ }
+ writeln("can only call functions!");
+ return false;
+ }
+
+ bool call(Function func, int argCount) {
+ CallFrame frame = { func, 0, bStack, bTop - argCount - 1 }; // i need to do sthg with argCount
+ //frames ~= frame;
+ //frameCount++;
+ pushFrame(frame);
+ return true;
+ }
+
InterpretResult run() {
writeln("== VM running ==");
while (true) {
+ /*
writeln(" Stacks:");
write(" A> ");
for (int i = 0; i < aTop; i++) {
@@ -128,9 +219,11 @@ class VM {
}
write("\n B> ");
for (int i = 0; i < bTop; i++) {
- writef("[ %s ]", printableValue(bStack[i]));
+ //writef("[ %s ]", printableValue(bStack[i]));
+ writef("[ %s ]", printableValue(current.slots[i]));
}
writeln("\n--");
+ */
/*
write(" globals >");
@@ -141,11 +234,11 @@ class VM {
writeln("\n--");
*/
- disassemble(this.func.chunk, this.ip);
+ //disassemble(current.func.chunk, current.ip);
ubyte inst;
switch (inst = this.readByte()) {
case OpCode.OP_DEF_GLOBAL:
- Value name = func.chunk.constants[readByte()];
+ Value name = current.func.chunk.constants[readByte()];
if (!isString(name)) {
writefln("variables must be strings, got %s", printableValue(name));
return InterpretResult.RUNTIME_ERROR; // TODO error
@@ -154,8 +247,8 @@ class VM {
globals[asString(name)] = val;
break;
case OpCode.OP_GET_GLOBAL:
- Value name = func.chunk.constants[readByte()];
- writefln(asString(name));
+ Value name = current.func.chunk.constants[readByte()];
+ //writefln(asString(name));
if (!isString(name)) {
writefln("variables must be strings, got %s", printableValue(name));
return InterpretResult.RUNTIME_ERROR; // TODO error
@@ -170,18 +263,25 @@ class VM {
case OpCode.OP_DEF_LOCAL:
Value val = popA();
pushB(val);
+ //current.slots ~= val;
break;
case OpCode.OP_GET_LOCAL:
ubyte slot = readByte();
- pushA(bStack[bTop - slot - 1]);
+ //pushA(bStack[bTop - slot - 1]);
+ //pushA(current.slots[slot - 1]);
+ //pushA(current.slots[current.frameStart + slot + 1]);
+ pushA(current.slots[current.frameStart + slot]);
break;
case OpCode.OP_SET_LOCAL:
ubyte slot = readByte();
- bStack[bTop + slot - 1] = peekA(0);
+ //bStack[bTop + slot - 1] = peekA(0);
+ current.slots[slot] = peekA(0);
+ //bStack[bTop + slot - 1] = peekA(0);
popA();
break;
case OpCode.OP_CONSTANT:
- Value constant = this.func.chunk.constants[this.readByte()];
+ Value constant = current.func.chunk.constants[readByte()];
+ //Value constant = current.func.chunk.constants[b];
pushA(constant);
break;
case OpCode.OP_NEGATE:
@@ -238,9 +338,24 @@ class VM {
pushA(makeBooleanValue(anum < bnum));
break;
case OpCode.OP_RETURN:
+
Value ret = popA();
- writefln("returned %s", printableValue(ret));
- return InterpretResult.OK;
+ popA(); // function
+ this.frameCount--;
+ //writefln("frameCount: %d", frameCount);
+ //if (this.frameCount == 0) {
+ if (this.frameCount == 1) {
+ popA();
+ writefln("returned %s", printableValue(ret));
+ return InterpretResult.OK;
+ }
+ // do something with the stack top/frame slots??
+ while(bTop > current.frameStart + 1) {
+ popB();
+ }
+ pushA(ret);
+ current = &frames[this.frameCount -1];
+ break;
case OpCode.OP_POP:
popA();
break;
@@ -255,7 +370,8 @@ class VM {
case OpCode.OP_JUMP:
uint offset = readShort();
- ip += offset;
+ //ip += offset;
+ current.ip += offset;
break;
case OpCode.OP_JUMP_IF_FALSE:
@@ -265,7 +381,8 @@ class VM {
return InterpretResult.RUNTIME_ERROR; // TODO error
}
if (!asBoolean(peekA(0))) {
- ip += offset;
+ //ip += offset;
+ current.ip += offset;
}
break;
case OpCode.OP_JUMP_IF_TRUE:
@@ -275,9 +392,30 @@ class VM {
return InterpretResult.RUNTIME_ERROR; // TODO error
}
if (asBoolean(peekA(0))) {
- ip += offset;
+ current.ip += offset;
}
break;
+ case OpCode.OP_CALL:
+ ubyte argCount = readByte();
+
+ // TODO i think i need to move the arguments from stack A to stack B (preserving order)
+ int cnt = to!int(argCount) - 1;
+ Value[] tmp;
+ while (cnt >= 0) {
+ tmp ~= popA();
+ cnt--;
+ }
+
+ foreach (Value val ; tmp) {
+ pushB(val);
+ }
+
+ //if (!callValue(peekA(argCount), argCount)) { // i'm allocating variables wrong
+ if (!callValue(peekA(0), argCount)) { // i'm allocating variables wrong
+ return InterpretResult.RUNTIME_ERROR;
+ }
+ current = &frames[this.frameCount - 1];
+ break;
default:
writeln("unknown opcode to run");
break;
@@ -287,7 +425,19 @@ class VM {
}
}
-/*
InterpretResult interpret(string source) {
Parser parser = new Parser(source);
-*/
+ Compiler compiler = new Compiler(ObjType.SCRIPT, &parser);
+ Function func = compiler.compile();
+
+ VM vm = new VM();
+
+ vm.pushA(makeObjValue(func));
+ CallFrame frame = { func, 0, vm.bStack, 0 };
+ vm.pushFrame(frame);
+ vm.call(func, 0);
+
+ //InterpretResult result = run();
+ return vm.run();
+
+}