diff options
Diffstat (limited to 'compiler.d')
| -rw-r--r-- | compiler.d | 57 |
1 files changed, 48 insertions, 9 deletions
@@ -18,6 +18,15 @@ struct TC { OpCode op; } +struct CompileError { + string message; + int line; +} + +string printableCompilerError(CompileError err) { + return format("[line %d] %s", err.line, err.message); +} + class Compiler { Function func; @@ -30,6 +39,8 @@ class Compiler { int currentLine; + CompileError[] errors; + Form outer; int outerIdx; @@ -45,6 +56,11 @@ class Compiler { this.current = this.parser.parseForm(); } + void error(string message, int line) { + CompileError err = { message, line }; + this.errors ~= err; + } + void compileNil(Form form) { form.compile(this.func); this.advance(); @@ -227,7 +243,10 @@ class Compiler { //ValueType compileLess(Form[] args, ValueType expected = ValueType.ANY) { ValueType compileLess(Form[] args, ValueType expected) { if (args.length != 2) { + /* writeln("'<' requires 2 arguments"); + */ + this.error("'<' requires 2 arguments", -1); this.advance(); return ValueType.NIL; } @@ -266,8 +285,11 @@ class Compiler { ValueType compileGreater(Form[] args) { if (args.length != 2) { - writeln("'>' requires 2 arguments"); + this.error("'>' requires 2 arguments", -1); this.advance(); + /* + writeln("'>' requires 2 arguments"); + */ return ValueType.NIL; } ValueType vt1 = this.resolve(args[0], ValueType.NUMBER); @@ -316,7 +338,8 @@ class Compiler { } if (sym.name == local.sym.name) { - writefln("ERROR: already a variable named '%s' in this scope", sym.name); + this.error(format("already a variable named '%s' in this scope", sym.name), sym.line); + //writefln("ERROR: already a variable named '%s' in this scope", sym.name); return; } } @@ -356,12 +379,9 @@ 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; } } @@ -535,7 +555,9 @@ class Compiler { void compileLength(Form[] args) { // TODO how do we identify/propagate errors? if (args.length != 1) { - writeln("COMPILE ERROR: 'first' expects exactly one argument"); + this.error("'length': expected [1] argument, received 0", -1); + //writeln("COMPILE ERROR: 'first' expects exactly one argument"); + this.advance(); return; } ValueType vt = this.resolve(args[0], ValueType.SEQ); // TODO need a new type @@ -563,7 +585,9 @@ class Compiler { void compileFirst(Form[] args) { // TODO how do we identify/propagate errors? if (args.length != 1) { - writeln("COMPILE ERROR: 'first' expects exactly one argument"); + this.error("'first': expected [1] argument, received 0", -1); + this.advance(); + //writeln("COMPILE ERROR: 'first' expects exactly one argument"); return; } ValueType vt = this.resolve(args[0], ValueType.SEQ); // TODO need a new type @@ -580,7 +604,9 @@ class Compiler { void compileRest(Form[] args) { // TODO how do we identify/propagate errors? if (args.length != 1) { - writeln("COMPILE ERROR: 'first' expects exactly one argument"); + this.error("'rest': expected [1] argument, received ?", -1); + this.advance(); + //writeln("COMPILE ERROR: 'first' expects exactly one argument"); return; } ValueType vt = this.resolve(args[0], ValueType.OBJ); // TODO need a new type @@ -622,6 +648,11 @@ class Compiler { this.func.chunk.writeOp(OpCode.OP_CONSTANT, lamb.line); int funcAddr = this.func.chunk.addConstant(makeObjValue(outFunc)); this.func.chunk.writeOp(to!ubyte(funcAddr), lamb.line); + + // capture the errors + foreach (CompileError err ; compiler.errors) { + this.errors ~= err; + } } void compileFunc(Form form) { @@ -657,6 +688,11 @@ class Compiler { int funcAddr = this.func.chunk.addConstant(makeObjValue(outFunc)); this.func.chunk.writeOp(to!ubyte(funcAddr), f.line); + // capture the errors + foreach (CompileError err ; compiler.errors) { + this.errors ~= err; + } + // define the global variable this.defineVariable(global); } @@ -673,7 +709,7 @@ class Compiler { } if (head.type != FormType.SYMBOL) { - writeln("cons must start with a symbol"); + this.error("can't evaluate without a symbol or lambda", head.line); this.advance(); return ValueType.NIL; } @@ -712,6 +748,9 @@ class Compiler { return this.compileConcat(cons.tail); // LISTS + case "append": + this.compileAppend(cons.tail); + break; case "first": this.compileFirst(cons.tail); break; |
