aboutsummaryrefslogtreecommitdiff
path: root/compiler.d
diff options
context:
space:
mode:
authormryouse2023-05-26 02:27:02 +0000
committermryouse2023-05-26 02:27:02 +0000
commit11e9f1d854602aae7cb895cfb2f9fc5dd338e6f8 (patch)
treed56db3e93a918b3a3cbb9b31d65245e6660b9417 /compiler.d
parent46a9b83a118207f414f2f7e4c0391785dc440fa4 (diff)
start making errors a bit nicer
Diffstat (limited to 'compiler.d')
-rw-r--r--compiler.d57
1 files changed, 48 insertions, 9 deletions
diff --git a/compiler.d b/compiler.d
index 992e36b..eccc4ce 100644
--- a/compiler.d
+++ b/compiler.d
@@ -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;