diff options
| author | Ben Winston | 2023-05-21 23:50:04 -0400 |
|---|---|---|
| committer | Ben Winston | 2023-05-21 23:50:04 -0400 |
| commit | 03b4987afc5e32ec560fac6f74c153d592f75259 (patch) | |
| tree | ca29375c89260d7678e7b173bd663327170533f5 /vm.d | |
| parent | 8e1f84b1369909745859777d07a5e8e74b5df334 (diff) | |
functionsgit add *.d!
Diffstat (limited to 'vm.d')
| -rw-r--r-- | vm.d | 198 |
1 files changed, 174 insertions, 24 deletions
@@ -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(); + +} |
