diff options
| -rw-r--r-- | chunk.d | 4 | ||||
| -rw-r--r-- | compiler.d | 134 | ||||
| -rw-r--r-- | dbg.d | 16 | ||||
| -rw-r--r-- | main.d | 9 | ||||
| -rw-r--r-- | parser.d | 38 | ||||
| -rw-r--r-- | vm.d | 34 |
6 files changed, 227 insertions, 8 deletions
@@ -38,8 +38,12 @@ enum OpCode { OP_RETURN, OP_CONSTANT, OP_DEFINE_GLOBAL, + OP_GET_LOCAL, + OP_SET_LOCAL, OP_GET_GLOBAL, + OP_SET_GLOBAL, OP_POP, + OP_POP_SCOPE, OP_SUBTRACT, OP_NIL, } @@ -23,9 +23,11 @@ class Compiler { FunctionType type; Parser* parser; Local[] locals; + int localCount; int scopeDepth; Form current; Form previous; + Form outer; int outerIdx; @@ -88,31 +90,142 @@ class Compiler { func.chunk.writeOp(OpCode.OP_LESS, current.line); } - void compileDef(Form form) { - Def def = cast(Def)form; + int parseVariable(Def def) { + declareVariable(def.name); + if (scopeDepth > 0) { + //return 0; + return localCount - 1; + //return localCount; + } - // add the variable name to the chunk int addr = func.chunk.addConstant(makeStringValue(def.name.name)); + return addr; + } + + void defineVariable(int addr) { + if (scopeDepth > 0) { + return; + } + func.chunk.writeOp(OpCode.OP_DEFINE_GLOBAL, current.line); + func.chunk.writeOp(to!ubyte(addr), current.line); + } + + void declareVariable(Symbol sym) { + + if (scopeDepth == 0) { + return; + } + + for (int i = localCount - 1; i >= 0; i--) { + Local local = locals[i]; + if (local.depth != -1 && local.depth < scopeDepth) { + break; + } + + if (sym.name == local.sym.name) { + writefln("ERROR: already a variable named '%s' in this scope", sym.name); + return; + } + } + + writefln("> > > creating a local at %d", scopeDepth); + Local loc = Local(sym, scopeDepth); + locals ~= loc; + localCount++; + writefln("localcount is now %d", localCount); + } + + void compileDef(Form form) { + Def def = cast(Def)form; // resolve the value resolve(def.val); + // add the variable name to the chunk (if applicable) + int addr = parseVariable(def); + + // are we setting a local? + if (scopeDepth > 0) { + func.chunk.writeOp(OpCode.OP_SET_LOCAL, current.line); + func.chunk.writeOp(to!ubyte(addr), current.line); + } + // define the variable + defineVariable(addr); + /* func.chunk.writeOp(OpCode.OP_DEFINE_GLOBAL, current.line); func.chunk.writeOp(to!ubyte(addr), current.line); + */ + + // is this right? + //func.chunk.writeOp(OpCode.OP_POP, def.line); + } + + int resolveLocal(Symbol sym) { + //for (int i = localCount - 1; i >= 0; i--) { + for (int i = localCount - 1; i >= 0; i--) { + Local local = locals[i]; + writefln(" > > looping, looking at '%s' (%d) (depth: %d)", local.sym.name, i, local.depth); + if (local.sym.name == sym.name) { + return i; + } + } + + return -1; } void compileSymbol(Form form) { Symbol sym = cast(Symbol)form; + OpCode getOp; + OpCode setOp; + int arg = resolveLocal(sym); + if (arg != -1) { + writeln("compiling a LOCAL symbol"); + getOp = OpCode.OP_GET_LOCAL; + setOp = OpCode.OP_SET_LOCAL; // do we need this here + } else { + writeln("compiling a GLOBAL symbol"); + arg = func.chunk.addConstant(makeStringValue(sym.name)); + getOp = OpCode.OP_GET_GLOBAL; + setOp = OpCode.OP_SET_GLOBAL; // do we need this here + } + // add the symbol name to the chunk - int addr = func.chunk.addConstant(makeStringValue(sym.name)); + //int addr = func.chunk.addConstant(makeStringValue(sym.name)); // get the variable - func.chunk.writeOp(OpCode.OP_GET_GLOBAL, sym.line); - func.chunk.writeOp(to!ubyte(addr), sym.line); + func.chunk.writeOp(to!ubyte(getOp), sym.line); + func.chunk.writeOp(to!ubyte(arg), sym.line); - advance(); + //advance(); + } + + void compileBlock(Form form) { + Block block = cast(Block)form; + beginScope(); + foreach (Form inner; block.blockBody) { + resolve(inner); + } + endScope(); + } + + void beginScope() { + scopeDepth++; + } + + void endScope() { + + writefln("> > ending scope at depth %d", scopeDepth); + scopeDepth--; + + while (localCount > 0 && + locals[localCount - 1].depth > scopeDepth) { + writeln("> > looping, gonna pop"); + func.chunk.writeOp(to!ubyte(OpCode.OP_POP_SCOPE), -1); + //func.chunk.writeOp(to!ubyte(OpCode.OP_POP), -1); + localCount--; + } } void compileCons(Form form) { @@ -168,6 +281,9 @@ class Compiler { case FormType.SYMBOL: this.compileSymbol(form); break; + case FormType.BLOCK: + this.compileBlock(form); + break; default: write("not sure how to resolve: "); printForm(form); @@ -199,6 +315,8 @@ class Compiler { this.parser = parser; this.func = new Function(); this.type = type; - locals ~= Local(new Symbol("", -1), 0); + localCount = 0; + //locals ~= Local(new Symbol("", -1), 0); + //localCount++; } } @@ -51,6 +51,10 @@ void printForm(Form f, string prefix = "") { Def def = cast(Def)f; writefln("%s var: %s", prefix, def.name.name); break; + case FormType.BLOCK: + Block block = cast(Block)f; + writefln("%s block of %d", prefix, block.blockBody.length); + break; default: writeln("printFormDefault"); break; @@ -79,6 +83,12 @@ string atomAsString(Atom a) { return printableValue(a.value); } +int byteInstruction(string message, Chunk chunk, int offset) { + ubyte slot = chunk.code[offset + 1]; + writefln("%-16s %4d", message, slot); + return offset + 2; +} + int constantInstruction(string message, Chunk chunk, int offset) { ubyte idx = chunk.code[offset + 1]; //writeln("dunno how to write a constant"); @@ -97,6 +107,10 @@ int disassemble(Chunk chunk, int offset) { ubyte inst = chunk.code[offset]; switch (inst) { + case OpCode.OP_GET_LOCAL: + return byteInstruction("OP_GET_LOCAL", chunk, offset); + case OpCode.OP_SET_LOCAL: + return byteInstruction("OP_SET_LOCAL", chunk, offset); case OpCode.OP_ADD: return simpleInstruction("OP_ADD", offset); case OpCode.OP_LESS: @@ -111,6 +125,8 @@ int disassemble(Chunk chunk, int offset) { return simpleInstruction("OP_NEGATE", offset); case OpCode.OP_POP: return simpleInstruction("OP_POP", offset); + case OpCode.OP_POP_SCOPE: + return simpleInstruction("OP_POP_SCOPE", offset); case OpCode.OP_RETURN: return simpleInstruction("OP_RETURN", offset); case OpCode.OP_NIL: @@ -31,6 +31,15 @@ void repl() { Compiler compiler = new Compiler(FunctionType.SCRIPT, &parser); Function func = compiler.compile(); + int cnt = 0; + writeln("== disassembly =="); + while(true) { + if (cnt >= func.chunk.code.length) { + break; + } + cnt = disassemble(func.chunk, cnt); + } + VM vm = new VM(func); vm.run(); @@ -13,6 +13,7 @@ enum FormType { SYMBOL, FUNC, DEF, + BLOCK, EOF, PARSE_ERROR @@ -79,6 +80,20 @@ class ParseError : Form { } } +class Block : Form { + + Form[] blockBody; + + this(int line) { + this.line = line; + this.type = FormType.BLOCK; + } + + void addToBody(Form f) { + this.blockBody ~= f; + } +} + class Cons : Form { Form head; @@ -376,6 +391,27 @@ class Parser { return func; } + Form parseBlock() { + Block block = new Block(line); + char next; + while(peekable()) { + next = peek(); + if (next == ')') { + break; + } + block.addToBody(parseForm()); + } + + if (!peekable()) { + return new ParseError("unterminated block", line); + } + + advance(); // consume closing paren + + return block; + + } + Form parseCons() { skipWhitespace(); @@ -395,6 +431,8 @@ class Parser { return parseFunc(); case "def": return parseDef(); + case "block": + return parseBlock(); default: break; } @@ -82,6 +82,15 @@ class VM { } writeln("\n--"); + /* + write(" globals >"); + //for (int i = 0; i < this.topOffset; i++) { + foreach (Value val; globals) { + writef("[ %s ]", printableValue(val)); + } + writeln("\n--"); + */ + disassemble(this.func.chunk, this.ip); ubyte inst; switch (inst = this.readByte()) { @@ -94,6 +103,23 @@ class VM { Value val = pop(); globals[asString(name)] = val; break; + case OpCode.OP_GET_LOCAL: + ubyte slot = readByte(); + writefln("getting local '%d' stackTop '%d'", slot, topOffset); + //push(stack[topOffset + slot - 2]); + //push(stack[topOffset + slot]); + push(stack[topOffset - 2 + slot]); + //push(stack[slot]); + break; + case OpCode.OP_SET_LOCAL: + //writeln("in SET_LOCAL"); + ubyte slot = readByte(); + //stack[slot] = peek(0); + stack[topOffset + slot - 1] = peek(0); + //pop(); + //stack[slot] = pop(); + writefln("setting local '%d' stackTop '%d'", slot, topOffset); + break; case OpCode.OP_GET_GLOBAL: writeln("in OP_GET_GLOBAL"); Value name = func.chunk.constants[readByte()]; @@ -171,6 +197,14 @@ class VM { Value ret = this.pop(); writefln("returned %s", printableValue(ret)); return InterpretResult.OK; + case OpCode.OP_POP: + pop(); + break; + case OpCode.OP_POP_SCOPE: // pop the n-1 position + Value val = pop(); + pop(); // throw this one away + push(val); + break; default: writeln("unknown opcode to run"); break; |
