aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chunk.d30
-rw-r--r--compiler.d27
-rw-r--r--dbg.d24
-rw-r--r--parser.d10
-rw-r--r--vm.d37
5 files changed, 110 insertions, 18 deletions
diff --git a/chunk.d b/chunk.d
index 0573687..70d7b1c 100644
--- a/chunk.d
+++ b/chunk.d
@@ -8,7 +8,6 @@ import dbg;
enum ObjType {
FUNCTION,
SCRIPT,
- LIST,
}
abstract class Obj {
@@ -37,18 +36,41 @@ class Function : Obj {
}
}
-class List : Obj {
+enum SeqType {
+ LIST,
+ STRING,
+}
+
+abstract class Seq {
+ SeqType type;
+ abstract Value first();
+ abstract Seq rest();
+}
+
+class List : Seq {
Value[] inner;
this(int length) {
this.inner = new Value[length];
- this.type = ObjType.LIST;
+ this.type = SeqType.LIST;
}
void addItemAtIndex(Value item, int idx) {
this.inner[idx] = item;
}
+ override Value first() {
+ return this.inner[0]; // this fails on NIL
+ }
+
+ override Seq rest() {
+ List ret = new List(to!int(this.inner.length) - 1);
+ for (int i = 1; i < this.inner.length; i++) {
+ ret.addItemAtIndex(this.inner[i], i - 1);
+ }
+ return ret;
+ }
+
override string toString() {
return format("list ('%s' + %d)", printableValue(this.inner[0]), this.inner.length - 1);
}
@@ -85,11 +107,13 @@ enum OpCode {
OP_CONCAT, // No?
OP_FIRST, // No?
+ OP_REST,
OP_TYPE_CHECK_NUMBER,
OP_TYPE_CHECK_BOOLEAN,
OP_TYPE_CHECK_STRING,
OP_TYPE_CHECK_LIST,
+ OP_TYPE_CHECK_SEQ,
}
class Chunk {
diff --git a/compiler.d b/compiler.d
index 6a1424d..6f5f0fd 100644
--- a/compiler.d
+++ b/compiler.d
@@ -345,9 +345,12 @@ class Compiler {
*/
int resolveLocal(Symbol sym) {
+ writefln("resolving local: %s", sym.name);
for (int i = this.localCount - 1; i >= 0; i--) {
Local local = this.locals[i];
+ writefln(" > [%d] %s (%s)", i, local.sym.name, local.depth);
if (local.sym.name == sym.name) {
+ writeln("got it!");
return i;
}
}
@@ -524,8 +527,8 @@ class Compiler {
writeln("COMPILE ERROR: 'first' expects exactly one argument");
return;
}
- ValueType vt = this.resolve(args[0], ValueType.OBJ); // TODO need a new type
- this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_LIST, args[0].line);
+ ValueType vt = this.resolve(args[0], ValueType.SEQ); // TODO need a new type
+ this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_SEQ, args[0].line);
// pop the value off the stack
// get the address of the first item in the list
@@ -535,6 +538,23 @@ class Compiler {
this.func.chunk.writeOp(OpCode.OP_FIRST, args[0].line);
}
+ void compileRest(Form[] args) {
+ // TODO how do we identify/propagate errors?
+ if (args.length != 1) {
+ writeln("COMPILE ERROR: 'first' expects exactly one argument");
+ return;
+ }
+ ValueType vt = this.resolve(args[0], ValueType.OBJ); // TODO need a new type
+ this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_SEQ, args[0].line);
+
+ this.func.chunk.writeOp(OpCode.OP_REST, args[0].line);
+
+ // there's probably a nicer way to copy
+ //List lst = new List();
+
+ // create a copy of the list
+ }
+
void compileFunc(Form form) {
Func f = cast(Func)form;
@@ -629,6 +649,9 @@ class Compiler {
//return compileList(cons.tail);
this.compileList(cons.tail);
break;
+ case "rest":
+ this.compileRest(cons.tail);
+ break;
default:
/*
writefln("unsure how to compile %s", sym.name);
diff --git a/dbg.d b/dbg.d
index 65c83af..64669ea 100644
--- a/dbg.d
+++ b/dbg.d
@@ -8,8 +8,8 @@ import parser;
//import dbg;
//import value;
-//bool DEBUG = true;
-bool DEBUG = false;
+bool DEBUG = true;
+//bool DEBUG = false;
void printForm(Form f, string prefix = "") {
@@ -85,11 +85,17 @@ string printableValue(Value val) {
return val.as.type;
case ValueType.NIL:
return "nil";
+ case ValueType.SEQ:
+ return printableSeq(val.as.seq);
default:
return "! unknown value type !";
}
}
+string printableSeq(Seq seq) {
+ return format("%s", seq);
+}
+
string printableFunction(Obj func) {
return format("%s", func);
}
@@ -119,6 +125,12 @@ int constantInstruction(string message, Chunk chunk, int offset) {
return offset + 2;
}
+int listInstruction(string message, Chunk chunk, int offset) {
+ ubyte idx = chunk.code[offset + 1];
+ writefln("%-16s %4d", message, idx);
+ return offset + 2;
+}
+
int simpleInstruction(string message, int offset) {
writeln(message);
return offset + 1;
@@ -147,6 +159,8 @@ int disassemble(Chunk chunk, int offset) {
return byteInstruction("OP_GET_LOCAL", chunk, offset);
case OpCode.OP_SET_LOCAL:
return byteInstruction("OP_SET_LOCAL", chunk, offset);
+ case OpCode.OP_LIST:
+ return listInstruction("OP_LIST", chunk, offset);
case OpCode.OP_ADD:
return simpleInstruction("OP_ADD", offset);
case OpCode.OP_LESS:
@@ -187,6 +201,12 @@ int disassemble(Chunk chunk, int offset) {
return simpleInstruction("OP_TYPE_CHECK_NUMBER", offset);
case OpCode.OP_TYPE_CHECK_BOOLEAN:
return simpleInstruction("OP_TYPE_CHECK_BOOLEAN", offset);
+ case OpCode.OP_TYPE_CHECK_SEQ:
+ return simpleInstruction("OP_TYPE_CHECK_SEQ", offset);
+ case OpCode.OP_FIRST:
+ return simpleInstruction("OP_FIRST", offset);
+ case OpCode.OP_REST:
+ return simpleInstruction("OP_REST", offset);
default:
writeln("unknown opcode?");
return offset + 1;
diff --git a/parser.d b/parser.d
index 97557ca..68f5093 100644
--- a/parser.d
+++ b/parser.d
@@ -270,6 +270,7 @@ enum ValueType {
NUMBER,
BOOLEAN,
TYPE,
+ SEQ,
OBJ,
ANY,
NIL,
@@ -281,6 +282,7 @@ union As {
string str;
string type;
Obj obj;
+ Seq seq;
}
@@ -313,6 +315,12 @@ Value makeObjValue(Obj obj) {
return val;
}
+Value makeSeqValue(Seq seq) {
+ As as = { seq: seq };
+ Value val = { ValueType.SEQ, as };
+ return val;
+}
+
Value makeTypeValue(string name) {
As as = { type: name };
Value val = { ValueType.TYPE, as };
@@ -464,7 +472,7 @@ class Parser {
if (next == ')') {
break;
}
- func.addToBody(parseForm());
+ func.addToBody(this.parseForm());
}
if (!peekable()) {
diff --git a/vm.d b/vm.d
index 468a0a5..5f1d889 100644
--- a/vm.d
+++ b/vm.d
@@ -168,14 +168,26 @@ class VM {
return value.type == ValueType.OBJ;
}
+ bool isSeq(Value value) {
+ return value.type == ValueType.SEQ;
+ }
+
bool isList(Value value) {
- return isObj(value) && objTypeOf(value) == ObjType.LIST;
+ return isSeq(value) && seqTypeOf(value) == SeqType.LIST;
}
ObjType objTypeOf(Value value) {
return value.as.obj.type;
}
+ SeqType seqTypeOf(Value value) {
+ return value.as.seq.type;
+ }
+
+ Seq asSeq(Value value) {
+ return value.as.seq;
+ }
+
double asNumber(Value value) {
return value.as.number;
}
@@ -228,6 +240,7 @@ class VM {
bool call(Function func, int argCount) {
//CallFrame frame = { func, 0, this.bStack, this.bTop - argCount - 1 }; // i need to do sthg with argCount
+ //CallFrame frame = { func, 0, 0, this.bTop - argCount - 1 }; // i need to do sthg with argCount
CallFrame frame = { func, 0, 0, this.bTop - argCount - 1 }; // i need to do sthg with argCount
//frames ~= frame;
//frameCount++;
@@ -329,7 +342,7 @@ class VM {
//lst.appendItem(this.popA());
lst.addItemAtIndex(this.popA(), i);
}
- this.pushA(makeObjValue(lst));
+ this.pushA(makeSeqValue(lst));
break;
case OpCode.OP_CONSTANT:
Value constant = this.current.func.chunk.constants[this.readByte()];
@@ -344,6 +357,12 @@ class VM {
double val = asNumber(this.popA());
this.pushA(makeNumberValue(val * -1));
break;
+ case OpCode.OP_TYPE_CHECK_SEQ:
+ if (!isSeq(this.peekA(0))) {
+ writeln("VM type check: not a seq!");
+ return InterpretResult.RUNTIME_ERROR; // TODO error
+ }
+ break;
case OpCode.OP_TYPE_CHECK_LIST:
if (!isList(this.peekA(0))) {
writeln("VM type check: not a list!");
@@ -368,16 +387,14 @@ class VM {
return InterpretResult.RUNTIME_ERROR; // TODO error
}
break;
- /*
case OpCode.OP_FIRST:
- Value val = this.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 = this.current.func.chunk.constants[to!ubyte(addr)];
- this.pushA(first);
+ Seq seq = asSeq(this.popA());
+ this.pushA(seq.first());
+ break;
+ case OpCode.OP_REST:
+ Seq seq = asSeq(this.popA());
+ this.pushA(makeSeqValue(seq.rest()));
break;
- */
case OpCode.OP_ADD:
Value b = this.popA();
/*