aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Winston2023-05-21 23:50:04 -0400
committerBen Winston2023-05-21 23:50:04 -0400
commit03b4987afc5e32ec560fac6f74c153d592f75259 (patch)
treeca29375c89260d7678e7b173bd663327170533f5
parent8e1f84b1369909745859777d07a5e8e74b5df334 (diff)
functionsgit add *.d!
-rw-r--r--chunk.d6
-rw-r--r--compiler.d94
-rw-r--r--dbg.d8
-rw-r--r--main.d39
-rw-r--r--vm.d198
5 files changed, 298 insertions, 47 deletions
diff --git a/chunk.d b/chunk.d
index c512f14..96e4f76 100644
--- a/chunk.d
+++ b/chunk.d
@@ -19,11 +19,11 @@ class Function : Obj {
string name;
ObjType type;
- this(ObjType type) {
+ this(ObjType type, string name = "") {
this.type = type;
this.chunk = new Chunk();
this.arity = 0;
- this.name = "";
+ this.name = name;
}
override string toString() {
@@ -56,6 +56,8 @@ enum OpCode {
OP_JUMP,
OP_JUMP_IF_FALSE,
OP_JUMP_IF_TRUE,
+
+ OP_CALL,
}
class Chunk {
diff --git a/compiler.d b/compiler.d
index ae4cb4a..0c6611c 100644
--- a/compiler.d
+++ b/compiler.d
@@ -84,19 +84,20 @@ class Compiler {
func.chunk.writeOp(OpCode.OP_LESS, current.line);
}
- int parseVariable(Def def) {
+ //int parseVariable(Def def) {
+ int parseVariable(Symbol sym) {
- declareVariable(def.name);
- if (scopeDepth > 0) {
+ declareVariable(sym);
+ if (this.scopeDepth > 0) {
return 0;
}
- int addr = func.chunk.addConstant(makeStringValue(def.name.name));
+ int addr = func.chunk.addConstant(makeStringValue(sym.name));
return addr;
}
void defineVariable(int addr) {
- if (scopeDepth > 0) {
+ if (this.scopeDepth > 0) {
return;
}
func.chunk.writeOp(OpCode.OP_DEF_GLOBAL, current.line);
@@ -105,13 +106,13 @@ class Compiler {
void declareVariable(Symbol sym) {
- if (scopeDepth == 0) {
+ if (this.scopeDepth == 0) {
return;
}
for (int i = localCount - 1; i >= 0; i--) {
Local local = locals[i];
- if (local.depth != -1 && local.depth < scopeDepth) {
+ if (local.depth != -1 && local.depth < this.scopeDepth) {
break;
}
@@ -121,7 +122,7 @@ class Compiler {
}
}
- Local loc = Local(sym, scopeDepth);
+ Local loc = Local(sym, this.scopeDepth);
if (localCount == locals.length) {
locals ~= loc;
} else {
@@ -137,10 +138,10 @@ class Compiler {
resolve(def.val);
// add the variable name to the chunk (if applicable)
- int addr = parseVariable(def);
+ int addr = parseVariable(def.name);
// are we setting a local?
- if (scopeDepth > 0) {
+ if (this.scopeDepth > 0) {
func.chunk.writeOp(OpCode.OP_DEF_LOCAL, current.line);
}
@@ -266,20 +267,74 @@ class Compiler {
}
void beginScope() {
- scopeDepth++;
+ this.scopeDepth++;
}
void endScope() {
- scopeDepth--;
+ this.scopeDepth--;
while (localCount > 0 &&
- locals[localCount - 1].depth > scopeDepth) {
+ locals[localCount - 1].depth > this.scopeDepth) {
func.chunk.writeOp(OpCode.OP_POPB, -1);
localCount--;
}
}
+ void call(Form[] args) {
+ //ubyte argCount = argumentList();
+ foreach (Form f ; args) {
+ resolve(f);
+ }
+ func.chunk.writeOp(OpCode.OP_CALL, -1);
+ //func.chunk.writeOp(argCount, -1);
+ func.chunk.writeOp(to!ubyte(args.length), -1);
+ }
+
+ void compileFunc(Form form) {
+ Func f = cast(Func)form;
+
+ // name the function
+ int global = parseVariable(f.name);
+
+ Compiler compiler = new Compiler(ObjType.FUNCTION, parser, f.name.name);
+ compiler.beginScope();
+
+ if (f.args.type != FormType.NIL) {
+ Symbol sym = cast(Symbol)f.args.head;
+ int constant = compiler.parseVariable(sym);
+ compiler.defineVariable(constant);
+
+ foreach (Form inner ; f.args.tail) {
+ sym = cast(Symbol)inner;
+ constant = compiler.parseVariable(sym);
+ compiler.defineVariable(constant);
+ }
+ }
+
+ /*
+ // compile each inner Form
+ foreach (Form inner; f.funcBody) {
+ compiler.resolve(inner);
+ }
+ */
+
+ advance(); // ??
+
+ Block b = new Block(f.line);
+ b.blockBody = f.funcBody;
+ compiler.compileBlock(b);
+
+ // write the function as a Value
+ Function outFunc = compiler.finish();
+ func.chunk.writeOp(OpCode.OP_CONSTANT, f.line);
+ int funcAddr = func.chunk.addConstant(makeObjValue(outFunc));
+ func.chunk.writeOp(to!ubyte(funcAddr), f.line);
+
+ // define the global variable
+ defineVariable(global);
+ }
+
void compileCons(Form form) {
Cons cons = cast(Cons)form;
Form head = cons.head;
@@ -309,6 +364,8 @@ class Compiler {
advance();
*/
resolve(head);
+ call(cons.tail);
+ advance();
break;
}
@@ -344,6 +401,9 @@ class Compiler {
case FormType.OR:
this.compileOr(form);
break;
+ case FormType.FUNC:
+ this.compileFunc(form);
+ break;
default:
write("not sure how to resolve: ");
printForm(form);
@@ -363,13 +423,13 @@ class Compiler {
Function finish() {
this.func.chunk.writeOp(OpCode.OP_RETURN, current.line);
- disassembleChunk(func.chunk, to!string(func));
- return func;
+ //disassembleChunk(func.chunk, to!string(func));
+ return this.func;
}
- this(ObjType type, Parser* parser) {
+ this(ObjType type, Parser* parser, string name = "") {
this.parser = parser;
- this.func = new Function(type);
+ this.func = new Function(type, name);
//localCount = 0;
locals ~= Local(new Symbol("", -1), 0);
diff --git a/dbg.d b/dbg.d
index b32c431..f131226 100644
--- a/dbg.d
+++ b/dbg.d
@@ -75,12 +75,14 @@ string printableValue(Value val) {
} else {
return "false";
}
+ case ValueType.OBJ:
+ return printableFunction(val.as.obj);
default:
return "! unknown value type !";
}
}
-string printableFunction(Function func) {
+string printableFunction(Obj func) {
return format("%s", func);
}
@@ -147,6 +149,8 @@ int disassemble(Chunk chunk, int offset) {
return constantInstruction("OP_CONSTANT", chunk, offset);
case OpCode.OP_DEF_GLOBAL:
return constantInstruction("OP_DEF_GLOBAL", chunk, offset);
+ case OpCode.OP_GET_GLOBAL:
+ return constantInstruction("OP_GET_GLOBAL", chunk, offset);
case OpCode.OP_NEGATE:
return simpleInstruction("OP_NEGATE", offset);
case OpCode.OP_POP:
@@ -165,6 +169,8 @@ int disassemble(Chunk chunk, int offset) {
return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
case OpCode.OP_JUMP_IF_TRUE:
return jumpInstruction("OP_JUMP_IF_TRUE", 1, chunk, offset);
+ case OpCode.OP_CALL:
+ return byteInstruction("OP_CALL", chunk, offset);
default:
writeln("unknown opcode?");
diff --git a/main.d b/main.d
index c497283..eeff97d 100644
--- a/main.d
+++ b/main.d
@@ -1,10 +1,14 @@
import std.stdio;
import std.string;
+import std.file;
+import std.conv;
+/*
import parser;
import dbg;
import chunk;
import compiler;
+*/
import vm;
/*
@@ -26,18 +30,47 @@ void repl() {
continue;
}
+ /*
Parser parser = new Parser(input);
Compiler compiler = new Compiler(ObjType.SCRIPT, &parser);
Function func = compiler.compile();
+ */
+ /*
VM vm = new VM(func);
vm.run();
-
+ */
+ interpret(input);
}
}
+string readFile(string fname) {
+
+ File f = File(fname, "r");
+
+ char[] ret = [];
+ while (!f.eof()) {
+ ret = ret ~ f.readln();
+ }
+ f.close();
+ return to!string(ret);
+}
+
+int main(string[] args) {
+ if (args.length <= 1) {
+ repl();
+ } else {
+ string fname = args[1];
+
+ if (!exists(fname)) {
+ writeln("file doesn't exist: ", fname);
+ return 1;
+ }
+
+ string data = readFile(fname);
-void main() {
- repl();
+ interpret(data);
+ }
+ return 0;
}
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();
+
+}