summaryrefslogtreecommitdiff
path: root/src/toys/godel/js/compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/toys/godel/js/compiler.js')
-rw-r--r--src/toys/godel/js/compiler.js226
1 files changed, 0 insertions, 226 deletions
diff --git a/src/toys/godel/js/compiler.js b/src/toys/godel/js/compiler.js
deleted file mode 100644
index d15c0f4..0000000
--- a/src/toys/godel/js/compiler.js
+++ /dev/null
@@ -1,226 +0,0 @@
-const INDENT_SIZE = 2;
-
-class CodeBuilder {
- constructor(indentSize = INDENT_SIZE) {
- this.indentSize = indentSize;
- this.indentLevel = 0;
- this.parts = [];
- }
-
- addLine(line = "") {
- const indent = " ".repeat(this.indentLevel * this.indentSize);
- this.parts.push(line ? `${indent}${line}` : "");
- }
-
- open(line) {
- if (line) {
- this.addLine(line);
- }
- this.indentLevel += 1;
- }
-
- close(line) {
- this.indentLevel = Math.max(0, this.indentLevel - 1);
- if (line) {
- this.addLine(line);
- }
- }
-
- toString() {
- return this.parts.join("\n");
- }
-}
-
-const compileGoto = (gotoNode, builder) => {
- builder.addLine(`this.followGoto("${gotoNode.label.symbol}");`);
- builder.addLine("return;");
-};
-
-const compileConditional = (conditionalNode, builder) => {
- const variable = conditionalNode.variable.symbol;
- builder.addLine(`if (this.get("${variable}") !== 0) {`);
- builder.open();
- compileGoto(conditionalNode.goto, builder);
- builder.close("}");
-};
-
-const compileAssignment = (assignmentNode, builder) => {
- const variable = assignmentNode.variable.symbol;
- const expr = assignmentNode.expr || {};
-
- if (expr.opr === "+") {
- builder.addLine(`this.addOne("${variable}");`);
- } else if (expr.opr === "-") {
- builder.addLine(`this.subtractOne("${variable}");`);
- } else {
- builder.addLine("// noop");
- }
-};
-
-const compileInstruction = (instruction, builder) => {
- if (instruction.goto) {
- compileGoto(instruction.goto, builder);
- return;
- }
-
- if (instruction.conditional) {
- compileConditional(instruction.conditional, builder);
- } else if (instruction.assignment) {
- compileAssignment(instruction.assignment, builder);
- }
-
- builder.addLine("this.instructionPointer++;");
-};
-
-const emitMethod = (builder, signature, bodyFn) => {
- builder.addLine(`${signature} {`);
- builder.open();
- bodyFn();
- builder.close("}");
- builder.addLine("");
-};
-
-const emitConstructor = (builder, ast, godelSequence, methodCatalog) => {
- emitMethod(builder, "constructor()", () => {
- builder.addLine("this.variables = new Map();");
- builder.addLine("this.labelInstructions = new Map();");
- builder.addLine("this.instructions = new Map();");
- builder.addLine("this.instructions.set(0, () => this.main());");
- builder.addLine("this.instructionPointer = 0;");
- builder.addLine('this.variables.set("Y", 0);');
- builder.addLine(`this.finalInstruction = ${ast.instructions.length + 1};`);
- builder.addLine('this.labelInstructions.set("E1", this.finalInstruction);');
- builder.addLine("");
- builder.addLine("// instruction bindings");
-
- ast.instructions.forEach((entry, index) => {
- const instructionNode = entry.instruction;
- const instructionIdx = index + 1;
- godelSequence.push(entry.godel);
-
- if (instructionNode.label) {
- const labelName = instructionNode.label.symbol;
- builder.addLine(
- `this.instructions.set(${instructionIdx}, () => this.${labelName}());`
- );
- builder.addLine(
- `this.labelInstructions.set("${labelName}", ${instructionIdx});`
- );
- methodCatalog.push({
- name: labelName,
- index: instructionIdx,
- node: instructionNode.instruction
- });
- } else {
- const methodName = `instruction${instructionIdx}`;
- builder.addLine(
- `this.instructions.set(${instructionIdx}, () => this.${methodName}());`
- );
- methodCatalog.push({
- name: methodName,
- index: instructionIdx,
- node: instructionNode
- });
- }
- });
- });
-};
-
-const emitRuntimeHelpers = (builder, instructionCount) => {
- emitMethod(builder, "get(variable)", () => {
- builder.addLine("if (!this.variables.has(variable)) {");
- builder.open();
- builder.addLine("this.variables.set(variable, 0);");
- builder.close("}");
- builder.addLine("return this.variables.get(variable);");
- });
-
- emitMethod(builder, "addOne(variable)", () => {
- builder.addLine("const val = this.get(variable);");
- builder.addLine("this.variables.set(variable, val + 1);");
- });
-
- emitMethod(builder, "subtractOne(variable)", () => {
- builder.addLine("const val = this.get(variable);");
- builder.addLine("this.variables.set(variable, val - 1);");
- });
-
- emitMethod(builder, "followGoto(label)", () => {
- builder.addLine("this.instructionPointer = this.labelInstructions.get(label);");
- });
-
- emitMethod(builder, "step()", () => {
- builder.addLine("if (!this.isCompleted()) {");
- builder.open();
- builder.addLine("const procedure = this.instructions.get(this.instructionPointer);");
- builder.addLine("procedure();");
- builder.close("}");
- builder.addLine("return this.instructionPointer;");
- });
-
- emitMethod(builder, "isCompleted()", () => {
- builder.addLine("return this.instructionPointer === this.finalInstruction;");
- });
-
- emitMethod(builder, "getResult()", () => {
- builder.addLine('return this.variables.get("Y");');
- });
-
- emitMethod(builder, "run(maxIter = 500_000)", () => {
- builder.addLine("let iter = 0;");
- builder.addLine("while (!this.isCompleted() && ++iter < maxIter) {");
- builder.open();
- builder.addLine("this.step();");
- builder.close("}");
- builder.addLine("if (iter < maxIter) {");
- builder.open();
- builder.addLine("return this.getResult();");
- builder.close("}");
- builder.addLine(
- 'throw new Error("Program exceeded iteration limit. Try optimizing your instructions or increasing the cap.");'
- );
- });
-
- emitMethod(builder, "main()", () => {
- if (instructionCount > 0) {
- builder.addLine("this.instructionPointer = 1;");
- } else {
- builder.addLine("this.instructionPointer = this.finalInstruction;");
- }
- });
-};
-
-const emitInstructionMethods = (builder, catalog) => {
- catalog.forEach((entry) => {
- emitMethod(builder, `${entry.name}()`, () => {
- builder.addLine(`this.instructionPointer = ${entry.index};`);
- compileInstruction(entry.node, builder);
- });
- });
-};
-
-export const compileProgram = (ast) => {
- const builder = new CodeBuilder();
- const godelSequence = [];
- const methodCatalog = [];
-
- builder.addLine("class Program {");
- builder.open();
- emitConstructor(builder, ast, godelSequence, methodCatalog);
- emitRuntimeHelpers(builder, ast.instructions.length);
- emitInstructionMethods(builder, methodCatalog);
- builder.close("}");
- builder.addLine("");
- builder.addLine("// bootstrap");
- builder.addLine("const program = new Program();");
- builder.addLine('// program.variables.set("X1", 2);');
- builder.addLine('// program.variables.set("X2", 3);');
- builder.addLine("program.run();");
- builder.addLine("console.log(program.variables);");
- builder.addLine("program.getResult();");
-
- return {
- js: builder.toString(),
- godelSequence
- };
-};