slige/compiler/resolver.ts

242 lines
7.1 KiB
TypeScript
Raw Normal View History

2024-12-11 11:36:19 +00:00
import { Builtins } from "./arch.ts";
2024-12-10 13:36:41 +00:00
import { Expr, Stmt } from "./ast.ts";
2024-12-11 11:36:19 +00:00
import { printStackTrace, Reporter } from "./info.ts";
2024-12-10 13:36:41 +00:00
import {
FnSyms,
GlobalSyms,
LeafSyms,
StaticSyms,
Syms,
} from "./resolver_syms.ts";
2024-12-10 20:42:15 +00:00
import { Pos } from "./token.ts";
2024-11-26 18:37:21 +00:00
2024-11-27 14:10:48 +00:00
export class Resolver {
2024-12-10 13:36:41 +00:00
private root = new GlobalSyms();
2024-11-26 18:37:21 +00:00
2024-12-11 11:36:19 +00:00
public constructor(private reporter: Reporter) {
this.root.define("print", {
type: "builtin",
ident: "print",
builtinId: Builtins.Print,
});
}
2024-12-11 02:11:00 +00:00
2024-11-27 14:10:48 +00:00
public resolve(stmts: Stmt[]) {
2024-12-10 13:36:41 +00:00
const scopeSyms = new StaticSyms(this.root);
this.scoutFnStmts(stmts, scopeSyms);
2024-11-27 14:10:48 +00:00
for (const stmt of stmts) {
this.resolveStmt(stmt, scopeSyms);
2024-11-26 18:37:21 +00:00
}
}
2024-12-10 13:36:41 +00:00
private scoutFnStmts(stmts: Stmt[], syms: Syms) {
for (const stmt of stmts) {
if (stmt.kind.type !== "fn") {
continue;
}
if (syms.definedLocally(stmt.kind.ident)) {
this.reportAlreadyDefined(stmt.kind.ident, stmt.pos, syms);
return;
}
const ident = stmt.kind.ident;
syms.define(ident, {
ident: stmt.kind.ident,
type: "fn",
pos: stmt.pos,
stmt,
});
}
}
2024-11-26 18:37:21 +00:00
private resolveExpr(expr: Expr, syms: Syms) {
if (expr.kind.type === "error") {
return;
}
if (expr.kind.type === "ident") {
2024-11-27 14:10:48 +00:00
this.resolveIdentExpr(expr, syms);
2024-11-26 18:37:21 +00:00
return;
}
if (expr.kind.type === "binary") {
this.resolveExpr(expr.kind.left, syms);
this.resolveExpr(expr.kind.right, syms);
return;
}
if (expr.kind.type === "block") {
2024-12-10 13:36:41 +00:00
const childSyms = new LeafSyms(syms);
this.scoutFnStmts(expr.kind.stmts, childSyms);
2024-11-26 18:37:21 +00:00
for (const stmt of expr.kind.stmts) {
this.resolveStmt(stmt, childSyms);
}
if (expr.kind.expr) {
this.resolveExpr(expr.kind.expr, childSyms);
}
return;
}
2024-12-06 11:21:57 +00:00
if (expr.kind.type === "group") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.expr, syms);
2024-12-06 11:21:57 +00:00
return;
}
if (expr.kind.type === "field") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.subject, syms);
2024-12-06 11:21:57 +00:00
return;
}
if (expr.kind.type === "index") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.subject, syms);
this.resolveExpr(expr.kind.value, syms);
2024-12-06 11:21:57 +00:00
return;
}
if (expr.kind.type === "call") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.subject, syms);
2024-12-06 11:21:57 +00:00
for (const e of expr.kind.args) {
2024-12-10 09:39:12 +00:00
this.resolveExpr(e, syms);
2024-12-06 11:21:57 +00:00
}
return;
}
if (expr.kind.type === "unary") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.subject, syms);
2024-12-06 11:21:57 +00:00
return;
}
if (expr.kind.type === "if") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.cond, syms);
this.resolveExpr(expr.kind.truthy, syms);
2024-12-06 11:21:57 +00:00
if (expr.kind.falsy !== undefined) {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.falsy, syms);
2024-12-06 11:21:57 +00:00
}
return;
}
if (expr.kind.type === "loop") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(expr.kind.body, syms);
2024-12-06 11:21:57 +00:00
return;
}
2024-12-10 09:39:12 +00:00
if (
expr.kind.type === "int" || expr.kind.type === "bool" ||
expr.kind.type === "null" || expr.kind.type === "string" ||
expr.kind.type === "sym"
) {
2024-12-06 11:21:57 +00:00
return;
}
2024-11-26 18:37:21 +00:00
}
2024-11-27 14:10:48 +00:00
private resolveIdentExpr(expr: Expr, syms: Syms) {
2024-12-10 09:39:12 +00:00
if (expr.kind.type !== "ident") {
2024-11-27 14:10:48 +00:00
throw new Error("expected ident");
2024-12-10 09:39:12 +00:00
}
2024-11-27 14:10:48 +00:00
const ident = expr.kind;
const symResult = syms.get(ident.value);
if (!symResult.ok) {
this.reportUseOfUndefined(ident.value, expr.pos, syms);
return;
}
2024-12-10 09:39:12 +00:00
const sym = symResult.sym;
2024-11-27 14:10:48 +00:00
expr.kind = {
type: "sym",
ident: ident.value,
2024-12-10 13:36:41 +00:00
sym,
2024-11-27 14:10:48 +00:00
};
2024-11-26 18:37:21 +00:00
}
private resolveStmt(stmt: Stmt, syms: Syms) {
if (stmt.kind.type === "error") {
return;
}
if (stmt.kind.type === "let") {
this.resolveLetStmt(stmt, syms);
return;
}
if (stmt.kind.type === "fn") {
this.resolveFnStmt(stmt, syms);
return;
}
if (stmt.kind.type === "return") {
2024-12-10 09:39:12 +00:00
if (stmt.kind.expr) {
2024-11-26 18:37:21 +00:00
this.resolveExpr(stmt.kind.expr, syms);
2024-12-10 09:39:12 +00:00
}
2024-11-26 18:37:21 +00:00
return;
}
2024-12-06 11:21:57 +00:00
if (stmt.kind.type === "break") {
if (stmt.kind.expr !== undefined) {
2024-12-10 09:39:12 +00:00
this.resolveExpr(stmt.kind.expr, syms);
2024-12-06 11:21:57 +00:00
}
return;
}
if (stmt.kind.type === "assign") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(stmt.kind.subject, syms);
this.resolveExpr(stmt.kind.value, syms);
2024-12-06 11:21:57 +00:00
return;
}
if (stmt.kind.type === "expr") {
2024-12-10 09:39:12 +00:00
this.resolveExpr(stmt.kind.expr, syms);
2024-12-06 11:21:57 +00:00
return;
}
2024-11-26 18:37:21 +00:00
}
2024-11-27 14:10:48 +00:00
private resolveLetStmt(stmt: Stmt, syms: Syms) {
2024-12-10 09:39:12 +00:00
if (stmt.kind.type !== "let") {
2024-11-27 14:10:48 +00:00
throw new Error("expected let statement");
2024-12-10 09:39:12 +00:00
}
2024-11-27 14:10:48 +00:00
this.resolveExpr(stmt.kind.value, syms);
const ident = stmt.kind.param.ident;
if (syms.definedLocally(ident)) {
this.reportAlreadyDefined(ident, stmt.pos, syms);
return;
}
syms.define(ident, {
ident,
type: "let",
pos: stmt.kind.param.pos,
stmt,
param: stmt.kind.param,
});
2024-11-26 18:37:21 +00:00
}
private resolveFnStmt(stmt: Stmt, syms: Syms) {
2024-12-10 09:39:12 +00:00
if (stmt.kind.type !== "fn") {
2024-11-27 14:10:48 +00:00
throw new Error("expected fn statement");
2024-12-10 09:39:12 +00:00
}
2024-12-10 13:36:41 +00:00
const fnScopeSyms = new FnSyms(syms);
2024-11-27 14:10:48 +00:00
for (const param of stmt.kind.params) {
if (fnScopeSyms.definedLocally(param.ident)) {
this.reportAlreadyDefined(param.ident, param.pos, syms);
continue;
}
fnScopeSyms.define(param.ident, {
ident: param.ident,
type: "fn_param",
pos: param.pos,
param,
});
}
this.resolveExpr(stmt.kind.body, fnScopeSyms);
2024-11-26 18:37:21 +00:00
}
2024-12-10 13:36:41 +00:00
private reportUseOfUndefined(ident: string, pos: Pos, _syms: Syms) {
2024-12-11 02:11:00 +00:00
this.reporter.reportError({
reporter: "Resolver",
msg: `use of undefined symbol '${ident}'`,
pos,
});
2024-12-11 11:36:19 +00:00
printStackTrace();
2024-11-26 18:37:21 +00:00
}
2024-12-10 09:39:12 +00:00
private reportAlreadyDefined(ident: string, pos: Pos, syms: Syms) {
2024-12-11 02:11:00 +00:00
this.reporter.reportError({
reporter: "Resolver",
msg: `symbol already defined '${ident}'`,
pos,
});
2024-11-26 18:37:21 +00:00
const prev = syms.get(ident);
2024-12-10 09:39:12 +00:00
if (!prev.ok) {
2024-11-26 18:37:21 +00:00
throw new Error("expected to be defined");
2024-12-10 09:39:12 +00:00
}
if (!prev.sym.pos) {
2024-11-26 18:37:21 +00:00
return;
2024-12-10 09:39:12 +00:00
}
2024-12-11 02:11:00 +00:00
this.reporter.addNote({
reporter: "Resolver",
msg: `previous definition of '${ident}'`,
pos: prev.sym.pos,
});
2024-12-11 11:36:19 +00:00
printStackTrace();
2024-11-26 18:37:21 +00:00
}
2024-12-10 09:39:12 +00:00
}