mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 12:46:31 +00:00
lowerer
This commit is contained in:
parent
6ab45ffbed
commit
b9c174d96a
142
compiler/Lowerer.ts
Normal file
142
compiler/Lowerer.ts
Normal file
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user