aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chunk.d27
-rw-r--r--compiler.d80
-rw-r--r--vm.d40
3 files changed, 138 insertions, 9 deletions
diff --git a/chunk.d b/chunk.d
index afaba8b..ad5774c 100644
--- a/chunk.d
+++ b/chunk.d
@@ -7,6 +7,7 @@ import parser;
enum ObjType {
FUNCTION,
SCRIPT,
+ LIST,
}
abstract class Obj {
@@ -35,6 +36,26 @@ class Function : Obj {
}
}
+class List : Obj {
+ int[] addresses;
+
+ this() {
+ this.type = ObjType.LIST;
+ }
+
+ void addItem(int addr) {
+ addresses ~= addr;
+ }
+
+ int first() {
+ return addresses[0]; // TODO this fails on empty lists
+ }
+
+ override string toString() {
+ return format("list (%d)", addresses.length);
+ }
+}
+
enum OpCode {
OP_ADD,
OP_LESS,
@@ -61,8 +82,14 @@ enum OpCode {
OP_CALL,
+ OP_CONCAT, // No?
+
+ OP_FIRST, // No?
+
OP_TYPE_CHECK_NUMBER,
OP_TYPE_CHECK_BOOLEAN,
+ OP_TYPE_CHECK_STRING,
+ OP_TYPE_CHECK_LIST,
}
class Chunk {
diff --git a/compiler.d b/compiler.d
index 1920ae0..119414c 100644
--- a/compiler.d
+++ b/compiler.d
@@ -356,20 +356,27 @@ class Compiler {
}
void compileSymbol(Form form, ValueType expecting = ValueType.ANY) {
+ if (form.type != FormType.SYMBOL) {
+ writeln("NOT A SYMBOL!");
+ } else {
+ writeln("it's a symbol");
+ }
Symbol sym = cast(Symbol)form;
int arg = resolveLocal(sym);
if (arg != -1) {
- func.chunk.writeOp(OpCode.OP_GET_LOCAL, sym.line);
+ this.func.chunk.writeOp(OpCode.OP_GET_LOCAL, sym.line);
} else {
- arg = func.chunk.addConstant(makeStringValue(sym.name));
- func.chunk.writeOp(OpCode.OP_GET_GLOBAL, sym.line);
+ arg = this.func.chunk.addConstant(makeStringValue(sym.name));
+ this.func.chunk.writeOp(OpCode.OP_GET_GLOBAL, sym.line);
}
+ writefln("this is the addr: %d", arg);
+
// get the variable
- func.chunk.writeOp(to!ubyte(arg), sym.line);
+ this.func.chunk.writeOp(to!ubyte(arg), sym.line);
- //advance();
+ advance();
}
int jump(OpCode type) {
@@ -465,6 +472,16 @@ class Compiler {
return vt;
}
+ ValueType compileConcat(Form[] args) {
+ ValueType vt = resolve(args[0], ValueType.STRING);
+ for (int i = 1; i < args.length; i++) {
+ vt = resolve(args[i], ValueType.STRING);
+ func.chunk.writeOp(OpCode.OP_TYPE_CHECK_STRING, currentLine);
+ func.chunk.writeOp(OpCode.OP_CONCAT, currentLine);
+ }
+ return ValueType.STRING;
+ }
+
void compileBlock(Form form) {
Block block = cast(Block)form;
beginScope();
@@ -499,6 +516,44 @@ class Compiler {
func.chunk.writeOp(to!ubyte(args.length), -1);
}
+ void compileList(Form[] args) {
+ List lst = new List();
+ ValueType vt;
+ int addr;
+ foreach (Form arg ; args) {
+ vt = resolve(arg, ValueType.ANY);
+ // how do we get at the address?
+ addr = to!int(this.func.chunk.constants.length) - 1; // this is probably often wrong
+ lst.addItem(addr);
+ this.func.chunk.writeOp(OpCode.OP_POP, arg.line); // shouldn't use the stack for this (but how?)
+ }
+
+ this.func.chunk.writeOp(OpCode.OP_CONSTANT, args[0].line);
+ int idx = this.func.chunk.addConstant(makeObjValue(lst));
+ this.func.chunk.writeOp(to!ubyte(idx), args[0].line);
+ //return ValueType.OBJ;
+
+
+ //advance(); // ??
+ }
+
+ void compileFirst(Form[] args) {
+ // TODO how do we identify/propagate errors?
+ if (args.length != 1) {
+ writeln("COMPILE ERROR: 'first' expects exactly one argument");
+ return;
+ }
+ ValueType vt = resolve(args[0], ValueType.OBJ); // TODO need a new type
+ this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_LIST, args[0].line);
+
+ // pop the value off the stack
+ // get the address of the first item in the list
+ // push that item onto the stack
+
+ // or, use a special instruction
+ this.func.chunk.writeOp(OpCode.OP_FIRST, args[0].line);
+ }
+
void compileFunc(Form form) {
Func f = cast(Func)form;
@@ -580,6 +635,19 @@ class Compiler {
return vt;
case "not":
return compileNot(cons.tail);
+
+ // STRINGS
+ case "concat":
+ return compileConcat(cons.tail);
+
+ // LISTS
+ case "first":
+ compileFirst(cons.tail);
+ break;
+ case "list":
+ //return compileList(cons.tail);
+ compileList(cons.tail);
+ break;
default:
/*
writefln("unsure how to compile %s", sym.name);
@@ -648,7 +716,7 @@ class Compiler {
Function finish() {
this.func.chunk.writeOp(OpCode.OP_RETURN, current.line);
- disassembleChunk(func.chunk, to!string(func));
+ disassembleChunk(this.func.chunk, to!string(func));
return this.func;
}
diff --git a/vm.d b/vm.d
index 2f6de06..d2968a3 100644
--- a/vm.d
+++ b/vm.d
@@ -155,6 +155,10 @@ class VM {
return value.type == ValueType.OBJ;
}
+ bool isList(Value value) {
+ return isObj(value) && objTypeOf(value) == ObjType.LIST;
+ }
+
ObjType objTypeOf(Value value) {
return value.as.obj.type;
}
@@ -220,7 +224,6 @@ class VM {
InterpretResult run() {
writeln("== VM running ==");
while (true) {
- /*
writeln(" Stacks:");
write(" A> ");
for (int i = 0; i < aTop; i++) {
@@ -231,8 +234,12 @@ class VM {
//writef("[ %s ]", printableValue(bStack[i]));
writef("[ %s ]", printableValue(current.slots[i]));
}
+
+ write("\n constants> ");
+ for (int i = 0; i < current.func.chunk.constants.length; i++) {
+ writef("[ %s ]", printableValue(current.func.chunk.constants[i]));
+ }
writeln("\n--");
- */
/*
write(" globals >");
@@ -243,7 +250,7 @@ class VM {
writeln("\n--");
*/
- //disassemble(current.func.chunk, current.ip);
+ disassemble(current.func.chunk, current.ip);
ubyte inst;
switch (inst = this.readByte()) {
case OpCode.OP_DEF_GLOBAL:
@@ -301,6 +308,18 @@ class VM {
double val = asNumber(popA());
pushA(makeNumberValue(val * -1));
break;
+ case OpCode.OP_TYPE_CHECK_LIST:
+ if (!isList(peekA(0))) {
+ writeln("VM type check: not a list!");
+ return InterpretResult.RUNTIME_ERROR; // TODO error
+ }
+ break;
+ case OpCode.OP_TYPE_CHECK_STRING:
+ if (!isString(peekA(0))) {
+ writeln("VM type check: not a string!");
+ return InterpretResult.RUNTIME_ERROR; // TODO error
+ }
+ break;
case OpCode.OP_TYPE_CHECK_NUMBER:
if (!isNumber(peekA(0))) {
writeln("VM type check: not a number!");
@@ -313,6 +332,14 @@ class VM {
return InterpretResult.RUNTIME_ERROR; // TODO error
}
break;
+ case OpCode.OP_FIRST:
+ Value val = popA();
+ List lst = cast(List)val.as.obj; // TODO this needs better checking
+ int addr = lst.first();
+ writefln("got this address: %d", addr);
+ Value first = current.func.chunk.constants[to!ubyte(addr)];
+ pushA(first);
+ break;
case OpCode.OP_ADD:
Value b = popA();
/*
@@ -356,6 +383,13 @@ class VM {
bool bval = asBoolean(val);
pushA(makeBooleanValue(!bval));
break;
+ case OpCode.OP_CONCAT:
+ Value b = popA();
+ Value a = popA();
+ string bstr = asString(b);
+ string astr = asString(a);
+ pushA(makeStringValue(astr ~ bstr));
+ break;
case OpCode.OP_GREATER:
Value b = popA();
Value a = popA();