diff options
| -rw-r--r-- | chunk.d | 2 | ||||
| -rw-r--r-- | compiler.d | 38 | ||||
| -rw-r--r-- | dbg.d | 6 | ||||
| -rw-r--r-- | main.d | 34 | ||||
| -rw-r--r-- | parser.d | 33 | ||||
| -rw-r--r-- | vm.d | 44 |
6 files changed, 122 insertions, 35 deletions
@@ -37,6 +37,8 @@ enum OpCode { OP_NEGATE, OP_RETURN, OP_CONSTANT, + OP_DEFINE_GLOBAL, + OP_GET_GLOBAL, OP_POP, OP_SUBTRACT, OP_NIL, @@ -1,5 +1,7 @@ import std.stdio; import std.string; +import std.conv; +import std.algorithm : canFind; import parser; import chunk; @@ -86,6 +88,33 @@ class Compiler { func.chunk.writeOp(OpCode.OP_LESS, current.line); } + void compileDef(Form form) { + Def def = cast(Def)form; + + // add the variable name to the chunk + int addr = func.chunk.addConstant(makeStringValue(def.name.name)); + + // resolve the value + resolve(def.val); + + // define the variable + func.chunk.writeOp(OpCode.OP_DEFINE_GLOBAL, current.line); + func.chunk.writeOp(to!ubyte(addr), current.line); + } + + void compileSymbol(Form form) { + Symbol sym = cast(Symbol)form; + + // add the symbol name to the chunk + 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); + + advance(); + } + void compileCons(Form form) { Cons cons = cast(Cons)form; Form head = cons.head; @@ -110,8 +139,11 @@ class Compiler { compileLess(cons.tail); break; default: + /* writefln("unsure how to compile %s", sym.name); advance(); + */ + resolve(head); break; } @@ -130,6 +162,12 @@ class Compiler { case FormType.NIL: this.compileNil(form); break; + case FormType.DEF: + this.compileDef(form); + break; + case FormType.SYMBOL: + this.compileSymbol(form); + break; default: write("not sure how to resolve: "); printForm(form); @@ -47,6 +47,10 @@ void printForm(Form f, string prefix = "") { writefln("%s with %d body lines", prefix, func.funcBody.length); writefln("%s <end fn %s>", prefix, func.name.name); break; + case FormType.DEF: + Def def = cast(Def)f; + writefln("%s var: %s", prefix, def.name.name); + break; default: writeln("printFormDefault"); break; @@ -101,6 +105,8 @@ int disassemble(Chunk chunk, int offset) { return simpleInstruction("OP_SUBTRACT", offset); case OpCode.OP_CONSTANT: return constantInstruction("OP_CONSTANT", chunk, offset); + case OpCode.OP_DEFINE_GLOBAL: + return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset); case OpCode.OP_NEGATE: return simpleInstruction("OP_NEGATE", offset); case OpCode.OP_POP: @@ -18,6 +18,7 @@ import vm; void repl() { while(true) { + write("> "); string input = strip(stdin.readln()); @@ -27,45 +28,12 @@ void repl() { Parser parser = new Parser(input); - /* - Chunk chunk = new Chunk(); - Form f; - while (true) { - f = parser.parseForm(); - printForm(f, ""); - - f.compile(chunk); - - - if (f.type == FormType.EOF) { - break; - } - } - */ - Compiler compiler = new Compiler(FunctionType.SCRIPT, &parser); Function func = compiler.compile(); VM vm = new VM(func); vm.run(); - /* - writeln("== disassembling chunk =="); - int off = 0; - while (off < func.chunk.code.length) { - off = disassemble(func.chunk, off); - } - */ - - /* - Compiler compiler = new Compiler(lex); - - ObjFunction func = compiler.compile(); - - VM vm = new VM(func); - vm.run(); - */ - } } @@ -12,6 +12,7 @@ enum FormType { NIL, SYMBOL, FUNC, + DEF, EOF, PARSE_ERROR @@ -134,6 +135,19 @@ class Func : Form { } } +class Def : Form { + + Symbol name; + Form val; + + this(Symbol name, Form val, int line) { + this.name = name; + this.val = val; + this.line = line; + this.type = FormType.DEF; + } +} + class Atom : Form { Value value; @@ -310,6 +324,23 @@ class Parser { return new Atom(to!double(to!string(acc)), line); } + Form parseDef() { + // we've parsed `def`, but not the symbol yet + Form sym = parseForm(); + if (sym.type != FormType.SYMBOL) { + return new ParseError("func definitions expect a symbol name", line); + } + + // get the value + Form val = parseForm(); + + Def def = new Def(cast(Symbol)sym, val, line); + + advance(); // closing paren + + return def; + } + Form parseFunc() { // we've parsed `func`, but not the symbol yet Form sym = parseForm(); @@ -362,6 +393,8 @@ class Parser { switch (s.name) { case "func": return parseFunc(); + case "def": + return parseDef(); default: break; } @@ -1,5 +1,6 @@ import std.stdio; import std.string; +import std.conv; import chunk; import parser; @@ -19,6 +20,7 @@ class VM { Value[] stack; //ObjFunction func; Function func; + Value[string] globals; this(Function func) { this.func = func; @@ -26,6 +28,7 @@ class VM { Value peek(int offset) { if (offset >= this.topOffset) { + //if (offset > this.topOffset) { writefln("offset of %d greater than stack size %d", offset, topOffset); } return this.stack[topOffset - offset - 1]; @@ -58,22 +61,55 @@ class VM { return value.type == ValueType.NUMBER; } + bool isString(Value value) { + return value.type == ValueType.STRING; + } + double asNumber(Value value) { return value.as.number; } + string asString(Value value) { + return value.as.str; + } + InterpretResult run() { //int ip = 0; // TODO this is wrong while (true) { write(" "); - //foreach (Value val; this.stack) { for (int i = 0; i < this.topOffset; i++) { writef("[ %s ]", printableValue(this.stack[i])); } writeln("\n--"); + disassemble(this.func.chunk, this.ip); ubyte inst; switch (inst = this.readByte()) { + case OpCode.OP_DEFINE_GLOBAL: + Value name = func.chunk.constants[readByte()]; + if (!isString(name)) { + writefln("variables must be strings, got %s", printableValue(name)); + return InterpretResult.RUNTIME_ERROR; // TODO error + } + Value val = pop(); + globals[asString(name)] = val; + break; + case OpCode.OP_GET_GLOBAL: + writeln("in OP_GET_GLOBAL"); + Value name = 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 + } + writefln(asString(name)); + Value* member = asString(name) in globals; + if (member is null) { + writefln("no such variable: %s", printableValue(name)); + return InterpretResult.RUNTIME_ERROR; // TODO error + } + push(*member); // do i need to dereference? + break; case OpCode.OP_CONSTANT: Value constant = this.func.chunk.constants[this.readByte()]; this.push(constant); @@ -142,5 +178,9 @@ class VM { } } - } + +/* +InterpretResult interpret(string source) { + Parser parser = new Parser(source); +*/ |
