rename syms

This commit is contained in:
SimonFJ20 2024-12-10 10:39:12 +01:00
parent b9c174d96a
commit fa81c17c25
3 changed files with 135 additions and 81 deletions

View File

@ -1,38 +1,72 @@
import { Expr, Stmt } from "./ast.ts"; import { BinaryType, Expr, Stmt } from "./ast.ts";
import { Ops } from "./mod.ts"; import { Ops } from "./mod.ts";
import { VType } from "./vtypes.ts";
class Locals { interface Locals {
reserveId(id: number): void;
allocSym(ident: string): void;
symId(ident: string): number;
}
class LocalsFnRoot implements Locals {
private localsAmount = 0;
private localIdCounter = 0; private localIdCounter = 0;
private symLocalMap: {[key: string]: number} = {} private symLocalMap: { [key: string]: number } = {};
constructor (private parent?: Locals) {} constructor(private parent?: Locals) {
defineSym(ident: string) {
this.symLocalMap[ident] = this.localIdCounter
this.localIdCounter++
} }
symLocalId(ident: string): number { reserveId(id: number): void {
this.localsAmount = Math.max(id + 1, this.localsAmount);
}
allocSym(ident: string) {
this.symLocalMap[ident] = this.localIdCounter;
this.localIdCounter++;
}
symId(ident: string): number {
if (ident in this.symLocalMap) { if (ident in this.symLocalMap) {
return this.symLocalMap[ident] return this.symLocalMap[ident];
} }
if (!this.parent) { if (this.parent) {
throw new Error(`Could not find syn local id with ident ${ident}`) return this.parent.symId(ident);
} }
else { throw new Error(`undefined symbol '${ident}'`);
return this.parent.symLocalId(ident) }
}
class LocalLeaf implements Locals {
private localIdCounter = 0;
private symLocalMap: { [key: string]: number } = {};
constructor(private parent: Locals) {
}
reserveId(id: number): void {
this.parent.reserveId(id);
}
allocSym(ident: string) {
this.symLocalMap[ident] = this.localIdCounter;
this.localIdCounter++;
}
symId(ident: string): number {
if (ident in this.symLocalMap) {
return this.symLocalMap[ident];
} }
return this.parent.symId(ident);
} }
} }
export class Lowerer { export class Lowerer {
private program: number[] = [] private program: number[] = [];
private locals = new Locals() private locals = new LocalsFnRoot();
lower(stmts: Stmt[]) { lower(stmts: Stmt[]) {
for(const stmt of stmts) { for (const stmt of stmts) {
this.lowerStmt(stmt) this.lowerStmt(stmt);
} }
} }
@ -47,19 +81,18 @@ export class Lowerer {
return this.lowerLetStmt(stmt); return this.lowerLetStmt(stmt);
case "assign": case "assign":
case "expr": case "expr":
} }
throw new Error(`Unhandled stmt ${stmt.kind.type}`) throw new Error(`Unhandled stmt ${stmt.kind.type}`);
} }
lowerLetStmt(stmt: Stmt) { lowerLetStmt(stmt: Stmt) {
if (stmt.kind.type !== "let") { if (stmt.kind.type !== "let") {
throw new Error(); throw new Error();
} }
this.lowerExpr(stmt.kind.value) this.lowerExpr(stmt.kind.value);
this.locals.defineSym(stmt.kind.param.ident), this.locals.allocSym(stmt.kind.param.ident),
this.program.push(Ops.StoreLocal) this.program.push(Ops.StoreLocal);
this.program.push(this.locals.symLocalId(stmt.kind.param.ident)) this.program.push(this.locals.symId(stmt.kind.param.ident));
} }
lowerExpr(expr: Expr) { lowerExpr(expr: Expr) {
@ -68,7 +101,7 @@ export class Lowerer {
case "error": case "error":
break; break;
case "int": case "int":
return this.lowerInt(expr) return this.lowerInt(expr);
case "ident": case "ident":
case "group": case "group":
case "field": case "field":
@ -77,7 +110,7 @@ export class Lowerer {
case "unary": case "unary":
break; break;
case "binary": case "binary":
return this.lowerBinaryExpr(expr) return this.lowerBinaryExpr(expr);
case "if": case "if":
case "bool": case "bool":
case "null": case "null":
@ -85,17 +118,17 @@ export class Lowerer {
case "block": case "block":
break; break;
case "sym": case "sym":
return this.lowerSym(expr) return this.lowerSym(expr);
} }
throw new Error(`Unhandled expr ${expr.kind.type}`) throw new Error(`Unhandled expr ${expr.kind.type}`);
} }
lowerInt(expr: Expr) { lowerInt(expr: Expr) {
if (expr.kind.type !== "int") { if (expr.kind.type !== "int") {
throw new Error(); throw new Error();
} }
this.program.push(Ops.PushInt) this.program.push(Ops.PushInt);
this.program.push(expr.kind.value) this.program.push(expr.kind.value);
} }
lowerSym(expr: Expr) { lowerSym(expr: Expr) {
@ -103,8 +136,8 @@ export class Lowerer {
throw new Error(); throw new Error();
} }
if (expr.kind.defType == "let") { if (expr.kind.defType == "let") {
this.program.push(Ops.LoadLocal) this.program.push(Ops.LoadLocal);
this.program.push(this.locals.symLocalId(expr.kind.ident)); this.program.push(this.locals.symId(expr.kind.ident));
return; return;
} }
throw new Error(`Unhandled sym deftype ${expr.kind.defType}`); throw new Error(`Unhandled sym deftype ${expr.kind.defType}`);
@ -116,14 +149,14 @@ export class Lowerer {
} }
this.lowerExpr(expr.kind.left); this.lowerExpr(expr.kind.left);
this.lowerExpr(expr.kind.right); this.lowerExpr(expr.kind.right);
if (expr.vtype?.type == "int") { if (expr.vtype!.type === "int") {
switch (expr.kind.binaryType) { switch (expr.kind.binaryType) {
case "+": case "+":
this.program.push(Ops.Add); this.program.push(Ops.Add);
return return;
case "*": case "*":
this.program.push(Ops.Multiply); this.program.push(Ops.Multiply);
return return;
case "==": case "==":
case "-": case "-":
case "/": case "/":
@ -135,8 +168,12 @@ export class Lowerer {
case "or": case "or":
case "and": case "and":
} }
throw new Error("Unhandled binary type")
} }
throw new Error(
`Unhandled vtype/binaryType '${
expr.vtype!.type
}/${expr.kind.binaryType}'`,
);
} }
} }

View File

@ -1,7 +1,7 @@
import { Expr, Stmt, Sym } from "./ast.ts"; import { Expr, Stmt, Sym } from "./ast.ts";
import { Pos } from "./Token.ts"; import { Pos } from "./Token.ts";
type SymMap = { [ident: string]: Sym } type SymMap = { [ident: string]: Sym };
class Syms { class Syms {
private syms: SymMap = {}; private syms: SymMap = {};
@ -16,11 +16,13 @@ class Syms {
return ident in this.syms; return ident in this.syms;
} }
public get(ident: string): { ok: true, sym: Sym } | { ok: false } { public get(ident: string): { ok: true; sym: Sym } | { ok: false } {
if (ident in this.syms) if (ident in this.syms) {
return { ok: true, sym: this.syms[ident] }; return { ok: true, sym: this.syms[ident] };
if (this.parent) }
if (this.parent) {
return this.parent.get(ident); return this.parent.get(ident);
}
return { ok: false }; return { ok: false };
} }
} }
@ -35,7 +37,6 @@ export class Resolver {
} }
} }
private resolveExpr(expr: Expr, syms: Syms) { private resolveExpr(expr: Expr, syms: Syms) {
if (expr.kind.type === "error") { if (expr.kind.type === "error") {
return; return;
@ -60,65 +61,72 @@ export class Resolver {
return; return;
} }
if (expr.kind.type === "group") { if (expr.kind.type === "group") {
this.resolveExpr(expr.kind.expr, syms) this.resolveExpr(expr.kind.expr, syms);
return; return;
} }
if (expr.kind.type === "field") { if (expr.kind.type === "field") {
this.resolveExpr(expr.kind.subject, syms) this.resolveExpr(expr.kind.subject, syms);
return; return;
} }
if (expr.kind.type === "index") { if (expr.kind.type === "index") {
this.resolveExpr(expr.kind.subject, syms) this.resolveExpr(expr.kind.subject, syms);
this.resolveExpr(expr.kind.value, syms) this.resolveExpr(expr.kind.value, syms);
return; return;
} }
if (expr.kind.type === "call") { if (expr.kind.type === "call") {
this.resolveExpr(expr.kind.subject, syms) this.resolveExpr(expr.kind.subject, syms);
for (const e of expr.kind.args) { for (const e of expr.kind.args) {
this.resolveExpr(e, syms) this.resolveExpr(e, syms);
} }
return; return;
} }
if (expr.kind.type === "unary") { if (expr.kind.type === "unary") {
this.resolveExpr(expr.kind.subject, syms) this.resolveExpr(expr.kind.subject, syms);
return; return;
} }
if (expr.kind.type === "if") { if (expr.kind.type === "if") {
this.resolveExpr(expr.kind.cond, syms) this.resolveExpr(expr.kind.cond, syms);
this.resolveExpr(expr.kind.truthy, syms) this.resolveExpr(expr.kind.truthy, syms);
if (expr.kind.falsy !== undefined) { if (expr.kind.falsy !== undefined) {
this.resolveExpr(expr.kind.falsy, syms) this.resolveExpr(expr.kind.falsy, syms);
} }
return; return;
} }
if (expr.kind.type === "loop") { if (expr.kind.type === "loop") {
this.resolveExpr(expr.kind.body, syms) this.resolveExpr(expr.kind.body, syms);
return; return;
} }
if (expr.kind.type === "int" || expr.kind.type === "bool" || expr.kind.type === "null" || expr.kind.type === "string" || expr.kind.type === "sym") { if (
expr.kind.type === "int" || expr.kind.type === "bool" ||
expr.kind.type === "null" || expr.kind.type === "string" ||
expr.kind.type === "sym"
) {
return; return;
} }
} }
private resolveIdentExpr(expr: Expr, syms: Syms) { private resolveIdentExpr(expr: Expr, syms: Syms) {
if (expr.kind.type !== "ident") if (expr.kind.type !== "ident") {
throw new Error("expected ident"); throw new Error("expected ident");
}
const ident = expr.kind; const ident = expr.kind;
const symResult = syms.get(ident.value); const symResult = syms.get(ident.value);
if (!symResult.ok) { if (!symResult.ok) {
this.reportUseOfUndefined(ident.value, expr.pos, syms); this.reportUseOfUndefined(ident.value, expr.pos, syms);
return; return;
} }
const sym = symResult.sym const sym = symResult.sym;
expr.kind = { expr.kind = {
type: "sym", type: "sym",
ident: ident.value, ident: ident.value,
defType: sym.type, defType: sym.type,
}; };
if (sym.stmt) if (sym.stmt) {
expr.kind.stmt = sym.stmt; expr.kind.stmt = sym.stmt;
if (sym.param) }
if (sym.param) {
expr.kind.param = sym.param; expr.kind.param = sym.param;
}
} }
private resolveStmt(stmt: Stmt, syms: Syms) { private resolveStmt(stmt: Stmt, syms: Syms) {
@ -134,30 +142,32 @@ export class Resolver {
return; return;
} }
if (stmt.kind.type === "return") { if (stmt.kind.type === "return") {
if (stmt.kind.expr) if (stmt.kind.expr) {
this.resolveExpr(stmt.kind.expr, syms); this.resolveExpr(stmt.kind.expr, syms);
}
return; return;
} }
if (stmt.kind.type === "break") { if (stmt.kind.type === "break") {
if (stmt.kind.expr !== undefined) { if (stmt.kind.expr !== undefined) {
this.resolveExpr(stmt.kind.expr, syms) this.resolveExpr(stmt.kind.expr, syms);
} }
return; return;
} }
if (stmt.kind.type === "assign") { if (stmt.kind.type === "assign") {
this.resolveExpr(stmt.kind.subject, syms) this.resolveExpr(stmt.kind.subject, syms);
this.resolveExpr(stmt.kind.value, syms) this.resolveExpr(stmt.kind.value, syms);
return; return;
} }
if (stmt.kind.type === "expr") { if (stmt.kind.type === "expr") {
this.resolveExpr(stmt.kind.expr, syms) this.resolveExpr(stmt.kind.expr, syms);
return; return;
} }
} }
private resolveLetStmt(stmt: Stmt, syms: Syms) { private resolveLetStmt(stmt: Stmt, syms: Syms) {
if (stmt.kind.type !== "let") if (stmt.kind.type !== "let") {
throw new Error("expected let statement"); throw new Error("expected let statement");
}
this.resolveExpr(stmt.kind.value, syms); this.resolveExpr(stmt.kind.value, syms);
const ident = stmt.kind.param.ident; const ident = stmt.kind.param.ident;
if (syms.definedLocally(ident)) { if (syms.definedLocally(ident)) {
@ -174,8 +184,9 @@ export class Resolver {
} }
private resolveFnStmt(stmt: Stmt, syms: Syms) { private resolveFnStmt(stmt: Stmt, syms: Syms) {
if (stmt.kind.type !== "fn") if (stmt.kind.type !== "fn") {
throw new Error("expected fn statement"); throw new Error("expected fn statement");
}
if (syms.definedLocally(stmt.kind.ident)) { if (syms.definedLocally(stmt.kind.ident)) {
this.reportAlreadyDefined(stmt.kind.ident, stmt.pos, syms); this.reportAlreadyDefined(stmt.kind.ident, stmt.pos, syms);
return; return;
@ -204,19 +215,25 @@ export class Resolver {
} }
private reportUseOfUndefined(ident: string, pos: Pos, syms: Syms) { private reportUseOfUndefined(ident: string, pos: Pos, syms: Syms) {
console.error(`use of undefined symbol '${ident}' at ${pos.line}${pos.col}`); console.error(
`use of undefined symbol '${ident}' at ${pos.line}${pos.col}`,
);
} }
private reportAlreadyDefined(ident: string, pos: Pos, syms: Syms) { private reportAlreadyDefined(ident: string, pos: Pos, syms: Syms) {
console.error(`symbol already defined '${ident}', at ${pos.line}${pos.col}`); console.error(
`symbol already defined '${ident}', at ${pos.line}${pos.col}`,
);
const prev = syms.get(ident); const prev = syms.get(ident);
if (!prev.ok) if (!prev.ok) {
throw new Error("expected to be defined"); throw new Error("expected to be defined");
if (!prev.sym.pos) }
if (!prev.sym.pos) {
return; return;
}
const { line: prevLine, col: prevCol } = prev.sym.pos; const { line: prevLine, col: prevCol } = prev.sym.pos;
console.error(`previous definition of '${ident}' at ${prevLine}:${prevCol}`); console.error(
`previous definition of '${ident}' at ${prevLine}:${prevCol}`,
);
} }
} }

View File

@ -1,7 +1,7 @@
import { Checker } from "./Checker.ts"; import { Checker } from "./Checker.ts";
import { Lexer } from "./Lexer.ts"; import { Lexer } from "./Lexer.ts";
import { Parser } from "./Parser.ts"; import { Parser } from "./Parser.ts";
import { Resolver } from "./Syms.ts"; import { Resolver } from "./Resolver.ts";
const text = await Deno.readTextFile("example.slg"); const text = await Deno.readTextFile("example.slg");
// const text = await Deno.readTextFile("example.slg"); // const text = await Deno.readTextFile("example.slg");
@ -14,8 +14,8 @@ const lexer = new Lexer(text);
// token = lexer.next(); // token = lexer.next();
// } // }
const parser = new Parser(lexer) const parser = new Parser(lexer);
const ast = parser.parseStmts() const ast = parser.parseStmts();
new Resolver().resolve(ast) new Resolver().resolve(ast);
new Checker().check(ast) new Checker().check(ast);
// console.log(JSON.stringify(ast, null, 4)) // console.log(JSON.stringify(ast, null, 4))