From b9c174d96a9c7f45686f27927a639004381dd504 Mon Sep 17 00:00:00 2001 From: Mikkel Kongsted Date: Tue, 10 Dec 2024 09:03:03 +0100 Subject: [PATCH] lowerer --- compiler/Lowerer.ts | 142 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 compiler/Lowerer.ts diff --git a/compiler/Lowerer.ts b/compiler/Lowerer.ts new file mode 100644 index 0000000..87021bd --- /dev/null +++ b/compiler/Lowerer.ts @@ -0,0 +1,142 @@ +import { Expr, Stmt } from "./ast.ts"; +import { Ops } from "./mod.ts"; + +class Locals { + private localIdCounter = 0; + private symLocalMap: {[key: string]: number} = {} + + constructor (private parent?: Locals) {} + + defineSym(ident: string) { + this.symLocalMap[ident] = this.localIdCounter + this.localIdCounter++ + } + + symLocalId(ident: string): number { + if (ident in this.symLocalMap) { + return this.symLocalMap[ident] + } + if (!this.parent) { + throw new Error(`Could not find syn local id with ident ${ident}`) + } + else { + return this.parent.symLocalId(ident) + } + } +} + +export class Lowerer { + private program: number[] = [] + private locals = new Locals() + + + lower(stmts: Stmt[]) { + for(const stmt of stmts) { + this.lowerStmt(stmt) + } + } + + lowerStmt(stmt: Stmt) { + switch (stmt.kind.type) { + case "error": + case "break": + case "return": + case "fn": + break; + case "let": + return this.lowerLetStmt(stmt); + case "assign": + case "expr": + } + throw new Error(`Unhandled stmt ${stmt.kind.type}`) + + } + + lowerLetStmt(stmt: Stmt) { + if (stmt.kind.type !== "let") { + throw new Error(); + } + this.lowerExpr(stmt.kind.value) + this.locals.defineSym(stmt.kind.param.ident), + this.program.push(Ops.StoreLocal) + this.program.push(this.locals.symLocalId(stmt.kind.param.ident)) + } + + lowerExpr(expr: Expr) { + switch (expr.kind.type) { + case "string": + case "error": + break; + case "int": + return this.lowerInt(expr) + case "ident": + case "group": + case "field": + case "index": + case "call": + case "unary": + break; + case "binary": + return this.lowerBinaryExpr(expr) + case "if": + case "bool": + case "null": + case "loop": + case "block": + break; + case "sym": + return this.lowerSym(expr) + } + throw new Error(`Unhandled expr ${expr.kind.type}`) + } + + lowerInt(expr: Expr) { + if (expr.kind.type !== "int") { + throw new Error(); + } + this.program.push(Ops.PushInt) + this.program.push(expr.kind.value) + } + + lowerSym(expr: Expr) { + if (expr.kind.type !== "sym") { + throw new Error(); + } + if (expr.kind.defType == "let") { + this.program.push(Ops.LoadLocal) + this.program.push(this.locals.symLocalId(expr.kind.ident)); + return; + } + throw new Error(`Unhandled sym deftype ${expr.kind.defType}`); + } + + lowerBinaryExpr(expr: Expr) { + if (expr.kind.type !== "binary") { + throw new Error(); + } + this.lowerExpr(expr.kind.left); + this.lowerExpr(expr.kind.right); + if (expr.vtype?.type == "int") { + switch (expr.kind.binaryType) { + case "+": + this.program.push(Ops.Add); + return + case "*": + this.program.push(Ops.Multiply); + return + case "==": + case "-": + case "/": + case "!=": + case "<": + case ">": + case "<=": + case ">=": + case "or": + case "and": + } + throw new Error("Unhandled binary type") + } + } + +} \ No newline at end of file