aboutsummaryrefslogtreecommitdiff
path: root/compiler.d
diff options
context:
space:
mode:
authorBen Winston2023-05-20 15:12:30 -0400
committerBen Winston2023-05-20 15:12:30 -0400
commit0c70372774297272dd14133d48e40e9a3624420a (patch)
tree4e66fb1b97a0fd537a20dca4ddcd26003f83c94d /compiler.d
parent6902cc5abe09da9f6f2d86f22d06684d97cfa9f3 (diff)
initial commit of compiler/VM with a couple basic instructions
Diffstat (limited to 'compiler.d')
-rw-r--r--compiler.d166
1 files changed, 166 insertions, 0 deletions
diff --git a/compiler.d b/compiler.d
new file mode 100644
index 0000000..51e45ba
--- /dev/null
+++ b/compiler.d
@@ -0,0 +1,166 @@
+import std.stdio;
+import std.string;
+
+import parser;
+import chunk;
+import dbg;
+
+enum FunctionType {
+ FUNCTION,
+ SCRIPT,
+}
+
+struct Local {
+ Symbol sym;
+ int depth;
+}
+
+class Compiler {
+
+ Function func;
+ FunctionType type;
+ Parser* parser;
+ Local[] locals;
+ int scopeDepth;
+ Form current;
+ Form previous;
+ Form outer;
+ int outerIdx;
+
+ void advance() {
+ previous = current;
+ /*
+ if (outer.type != FormType.EOF && outerIdx < outer) {
+ current = parser.parseForm();
+ } else {
+
+ }
+ */
+ current = parser.parseForm();
+ }
+
+ void compileNil(Form form) {
+ form.compile(func);
+ advance();
+ }
+
+ void compileAtom(Form form) {
+ form.compile(func);
+ advance();
+ }
+
+ void compileAdd(Form[] args) {
+ resolve(args[0]);
+
+ // (+ n) always returns n
+ if (args.length == 1) {
+ return;
+ }
+
+ for (int i = 1; i < args.length; i++) {
+ resolve(args[i]);
+ func.chunk.writeOp(OpCode.OP_ADD, current.line);
+ }
+ }
+
+ void compileNegate(Form arg) {
+ resolve(arg);
+ func.chunk.writeOp(OpCode.OP_NEGATE, current.line);
+ }
+
+ void compileSubtract(Form[] args) {
+ resolve(args[0]);
+ for (int i = 1; i < args.length; i++) {
+ resolve(args[i]);
+ func.chunk.writeOp(OpCode.OP_SUBTRACT, current.line);
+ }
+ }
+
+ void compileLess(Form[] args) {
+ if (args.length != 2) {
+ writeln("'<' requires 2 arguments");
+ return;
+ }
+ resolve(args[0]);
+ resolve(args[1]);
+ func.chunk.writeOp(OpCode.OP_LESS, current.line);
+ }
+
+ void compileCons(Form form) {
+ Cons cons = cast(Cons)form;
+ Form head = cons.head;
+ if (head.type != FormType.SYMBOL) {
+ writeln("cons must start with a symbol");
+ return;
+ }
+
+ Symbol sym = cast(Symbol)head;
+ switch (sym.name) {
+ case "+":
+ compileAdd(cons.tail);
+ break;
+ case "-":
+ if (cons.tail.length == 1) {
+ compileNegate(cons.tail[0]);
+ } else {
+ compileSubtract(cons.tail);
+ }
+ break;
+ case "<":
+ compileLess(cons.tail);
+ break;
+ default:
+ writefln("unsure how to compile %s", sym.name);
+ advance();
+ break;
+ }
+
+ }
+
+ void resolve(Form form) {
+ write("resolving: ");
+ printForm(form);
+ switch(form.type) {
+ case FormType.ATOM:
+ this.compileAtom(form);
+ break;
+ case FormType.CONS:
+ this.compileCons(form);
+ break;
+ case FormType.NIL:
+ this.compileNil(form);
+ break;
+ default:
+ write("not sure how to resolve: ");
+ printForm(form);
+ advance();
+ break;
+ }
+ }
+
+ Function compile() {
+ writeln("compiling");
+ advance();
+ while(current.type != FormType.EOF) {
+ resolve(current);
+ }
+
+ return finish();
+ }
+
+ Function finish() {
+ //emitReturn();
+ writeln("finishing the compiler!");
+
+ this.func.chunk.writeOp(OpCode.OP_RETURN, current.line);
+ writeln("wrote a return code");
+ return func;
+ }
+
+ this(FunctionType type, Parser* parser) {
+ this.parser = parser;
+ this.func = new Function();
+ this.type = type;
+ locals ~= Local(new Symbol("", -1), 0);
+ }
+}