diff options
| author | Ben Winston | 2023-05-22 22:09:46 -0400 |
|---|---|---|
| committer | Ben Winston | 2023-05-22 22:09:46 -0400 |
| commit | 5b623d43c5681ed292a0d83a49255f035c40df91 (patch) | |
| tree | ad2a1ceee949b5067a83c8db39c79ebbecf049fc /compiler.d | |
| parent | ab6deb5eb1244f566c8a8b22022c68d50d5eb4d7 (diff) | |
compile-time typechecking WIP
Diffstat (limited to 'compiler.d')
| -rw-r--r-- | compiler.d | 189 |
1 files changed, 165 insertions, 24 deletions
@@ -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() { |
