aboutsummaryrefslogtreecommitdiff
path: root/compiler.d
diff options
context:
space:
mode:
authorBen Winston2023-05-22 22:09:46 -0400
committerBen Winston2023-05-22 22:09:46 -0400
commit5b623d43c5681ed292a0d83a49255f035c40df91 (patch)
treead2a1ceee949b5067a83c8db39c79ebbecf049fc /compiler.d
parentab6deb5eb1244f566c8a8b22022c68d50d5eb4d7 (diff)
compile-time typechecking WIP
Diffstat (limited to 'compiler.d')
-rw-r--r--compiler.d189
1 files changed, 165 insertions, 24 deletions
diff --git a/compiler.d b/compiler.d
index 4b7775e..0125dc5 100644
--- a/compiler.d
+++ b/compiler.d
@@ -12,6 +12,12 @@ struct Local {
int depth;
}
+struct TC {
+ bool exact;
+ bool maybe;
+ OpCode op;
+}
+
class Compiler {
Function func;
@@ -44,15 +50,135 @@ class Compiler {
advance();
}
- void compileAtom(Form form) {
+ TC typeCheck(ValueType actual, ValueType expecting) {
+ TC ret = { false, false, OpCode.OP_NIL };
+ if (actual == expecting) {
+ writeln("good types");
+ ret.exact = true;
+ return ret;
+ } else if (actual == ValueType.ANY) {
+ OpCode op;
+ switch (expecting) {
+ case ValueType.NUMBER:
+ op = OpCode.OP_TYPE_CHECK_NUMBER;
+ break;
+ case ValueType.BOOLEAN:
+ op = OpCode.OP_TYPE_CHECK_BOOLEAN;
+ break;
+ default:
+ writeln("not sure what type to check :(");
+ break;
+ }
+ //func.chunk.writeOp(to!ubyte(op), atom.line);
+ //tc = { false, true, op };
+ ret.maybe = true;
+ ret.op = op;
+ return ret;
+ } else {
+ return ret;
+ }
+ /*
+ writeln("in typecheck");
+ ValueType[] types = [actual, expecting];
+ foreach (ValueType t ; types) {
+ switch (t) {
+ case ValueType.NUMBER:
+ writeln("number");
+ break;
+ case ValueType.BOOLEAN:
+ writeln("boolean");
+ break;
+ case ValueType.ANY:
+ writeln("any");
+ break;
+ default:
+ writeln("something else");
+ break;
+ }
+ }
+ */
+ }
+
+ void compileAtom(Form form, const ValueType expecting) {
+ Atom atom = cast(Atom)form;
+ /*
+ ValueType[] types = [expecting, atom.value.type];
+ foreach (ValueType t ; types) {
+ switch (t) {
+ case ValueType.NUMBER:
+ writeln("number");
+ break;
+ case ValueType.BOOLEAN:
+ writeln("boolean");
+ break;
+ case ValueType.ANY:
+ writeln("any");
+ break;
+ default:
+ writeln("something else");
+ break;
+ }
+ }
+ */
+ TC tc = typeCheck(atom.value.type, expecting);
form.compile(func);
+ //if (tc.exact) {
+ //} else if (tc.maybe) {
+
+ if (tc.maybe) {
+ form.compile(func);
+ func.chunk.writeOp(to!ubyte(tc.op), atom.line);
+ } else if (!tc.exact) {
+ writefln("COMPILE ERROR: typecheck on line %d", atom.line);
+ //form.compile(func); // don't do this later
+ }
advance();
+
+
+
+
+
+ /*
+ ValueType typ = atom.value.type;
+ switch (typ) {
+ case ValueType.ANY:
+ writeln("IN ANY");
+ OpCode op;
+ switch (expecting) {
+ case ValueType.NUMBER:
+ op = OpCode.OP_TYPE_CHECK_NUMBER;
+ break;
+ case ValueType.BOOLEAN:
+ op = OpCode.OP_TYPE_CHECK_BOOLEAN;
+ break;
+ default:
+ writeln("not sure what type to check :(");
+ break;
+ }
+ func.chunk.writeOp(to!ubyte(op), atom.line);
+ break;
+ case expecting:
+ form.compile(func);
+ break;
+ default:
+ writefln("COMPILE ERROR: typecheck on line %d", atom.line);
+ form.compile(func);
+ break;
+ }
+ */
+ /*
+ if (atom.value.type == expecting) {
+ writefln("COMPILE ERROR: typecheck on line %d", atom.line);
+ } else if (atom.value
+ */
+ //form.compile(func);
+ //advance();
}
- void compileAdd(Form[] args) {
+ void compileAdd(Form[] args, ValueType expecting) {
int line = args[0].line;
- resolve(args[0]);
- func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, line);
+ resolve(args[0], expecting);
+ //func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, line);
// (+ n) always returns n
if (args.length == 1) {
@@ -60,8 +186,8 @@ class Compiler {
}
for (int i = 1; i < args.length; i++) {
- resolve(args[i]);
- func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, line);
+ resolve(args[i], expecting);
+ //func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, line);
func.chunk.writeOp(OpCode.OP_ADD, line);
}
}
@@ -82,16 +208,22 @@ class Compiler {
}
}
- void compileLess(Form[] args) {
+ ValueType compileLess(Form[] args, ValueType expected = ValueType.ANY) {
if (args.length != 2) {
writeln("'<' requires 2 arguments");
- return;
+ advance();
+ return ValueType.NIL;
}
- resolve(args[0]);
- func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine);
- resolve(args[1]);
- func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine);
+ //ValueType vt1 = resolve(args[0], ValueType.NUMBER);
+ ValueType vt1 = resolve(args[0], expected);
+ //func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine);
+ //ValueType vt2 = resolve(args[1], ValueType.NUMBER);
+ ValueType vt2 = resolve(args[1], expected);
+ //func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine);
func.chunk.writeOp(OpCode.OP_LESS, currentLine);
+
+ // this should probably return a ValueType
+ return ValueType.BOOLEAN;
}
//int parseVariable(Def def) {
@@ -141,11 +273,11 @@ class Compiler {
localCount++;
}
- void compileDef(Form form) {
+ void compileDef(Form form, ValueType expecting) {
Def def = cast(Def)form;
// resolve the value
- resolve(def.val);
+ resolve(def.val, expecting);
// add the variable name to the chunk (if applicable)
int addr = parseVariable(def.name);
@@ -159,6 +291,13 @@ class Compiler {
defineVariable(addr);
}
+ /*
+ struct LV {
+ int i;
+ bool needsTypeCheck;
+ }
+ */
+
int resolveLocal(Symbol sym) {
for (int i = localCount - 1; i >= 0; i--) {
Local local = locals[i];
@@ -170,7 +309,7 @@ class Compiler {
return -1;
}
- void compileSymbol(Form form) {
+ void compileSymbol(Form form, ValueType expecting = ValueType.ANY) {
Symbol sym = cast(Symbol)form;
int arg = resolveLocal(sym);
@@ -351,18 +490,18 @@ class Compiler {
defineVariable(global);
}
- void compileCons(Form form) {
+ ValueType compileCons(Form form, ValueType returnType = ValueType.ANY) {
Cons cons = cast(Cons)form;
Form head = cons.head;
if (head.type != FormType.SYMBOL) {
writeln("cons must start with a symbol");
- return;
+ return ValueType.NIL;
}
Symbol sym = cast(Symbol)head;
switch (sym.name) {
case "+":
- compileAdd(cons.tail);
+ compileAdd(cons.tail, ValueType.NUMBER);
break;
case "-":
if (cons.tail.length == 1) {
@@ -372,7 +511,7 @@ class Compiler {
}
break;
case "<":
- compileLess(cons.tail);
+ return compileLess(cons.tail);
break;
default:
/*
@@ -384,27 +523,28 @@ class Compiler {
advance();
break;
}
+ return ValueType.NIL;
}
- void resolve(Form form) {
+ ValueType resolve(Form form, const ValueType expecting = ValueType.ANY) {
//printForm(form);
currentLine = form.line;
switch(form.type) {
case FormType.ATOM:
- this.compileAtom(form);
+ this.compileAtom(form, expecting);
break;
case FormType.CONS:
- this.compileCons(form);
+ return this.compileCons(form, expecting);
break;
case FormType.NIL:
this.compileNil(form);
break;
case FormType.DEF:
- this.compileDef(form);
+ this.compileDef(form, expecting);
break;
case FormType.SYMBOL:
- this.compileSymbol(form);
+ this.compileSymbol(form, expecting);
break;
case FormType.BLOCK:
this.compileBlock(form);
@@ -427,6 +567,7 @@ class Compiler {
advance();
break;
}
+ return ValueType.NIL;
}
Function compile() {