mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 23:06:32 +00:00
resolver stuff
This commit is contained in:
parent
e9c70f71b7
commit
cc3d00c2c4
134
compiler/Syms.ts
Normal file
134
compiler/Syms.ts
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { Expr, Stmt, Sym } from "./ast.ts";
|
||||||
|
import { Pos } from "./Token.ts";
|
||||||
|
|
||||||
|
|
||||||
|
type Ident = string
|
||||||
|
|
||||||
|
|
||||||
|
type SymMap = { [ident: string]: Sym }
|
||||||
|
|
||||||
|
class Syms {
|
||||||
|
private syms: SymMap = {};
|
||||||
|
|
||||||
|
public constructor(private parent?: Syms) {}
|
||||||
|
|
||||||
|
public define(ident: string, sym: Sym) {
|
||||||
|
this.syms[ident] = sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
public definedLocally(ident: string): boolean {
|
||||||
|
return ident in this.syms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(ident: string): { ok: true, sym: Sym } | { ok: false } {
|
||||||
|
if (ident in this.syms)
|
||||||
|
return { ok: true, sym: this.syms[ident] };
|
||||||
|
if (this.parent)
|
||||||
|
return this.parent.get(ident);
|
||||||
|
return { ok: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapter 7 is generally fucked, remember to give feedback to Simon
|
||||||
|
class Resolver {
|
||||||
|
private root = new Syms();
|
||||||
|
|
||||||
|
private resolveIdentExpr(expr: Expr, syms: Syms) {
|
||||||
|
if (expr.kind.type !== "ident")
|
||||||
|
throw new Error("expected ident");
|
||||||
|
const ident = expr.kind;
|
||||||
|
const symResult = syms.get(ident.value);
|
||||||
|
if (!symResult.ok) {
|
||||||
|
this.reportUseOfUndefined(ident.value, expr.pos, syms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const sym = symResult.sym
|
||||||
|
expr.kind = {
|
||||||
|
type: "sym",
|
||||||
|
ident: ident.value,
|
||||||
|
defType: sym.type,
|
||||||
|
};
|
||||||
|
if (sym.stmt)
|
||||||
|
expr.kind.stmt = sym.stmt;
|
||||||
|
if (sym.param)
|
||||||
|
expr.kind.param = sym.param;
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveExpr(expr: Expr, syms: Syms) {
|
||||||
|
if (expr.kind.type === "error") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (expr.kind.type === "ident") {
|
||||||
|
this.resolveIdentexpr(expr, syms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
if (expr.kind.type === "binary") {
|
||||||
|
this.resolveExpr(expr.kind.left, syms);
|
||||||
|
this.resolveExpr(expr.kind.right, syms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
if (expr.kind.type === "block") {
|
||||||
|
const childSyms = new Syms(syms);
|
||||||
|
for (const stmt of expr.kind.stmts) {
|
||||||
|
this.resolveStmt(stmt, childSyms);
|
||||||
|
}
|
||||||
|
if (expr.kind.expr) {
|
||||||
|
this.resolveExpr(expr.kind.expr, childSyms);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
throw new Error(`unknown expression ${expr.kind.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveIdentexpr(expr: Expr, syms: Syms) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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") {
|
||||||
|
if (stmt.kind.expr)
|
||||||
|
this.resolveExpr(stmt.kind.expr, syms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
throw new Error(`unknown statement ${stmt.kind.type}`);
|
||||||
|
}
|
||||||
|
private resolveLetStmt(stmt: Stmt, syms: Syms) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveFnStmt(stmt: Stmt, syms: Syms) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private reportUseOfUndefined(ident: Ident, pos: Pos, syms: Syms) {
|
||||||
|
console.error(`use of undefined symbol '${ident}' at ${pos.line}${pos.col}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private reportAlreadyDefined(ident: Ident, pos: Pos, syms: Syms) {
|
||||||
|
console.error(`symbol already defined '${ident}', at ${pos.line}${pos.col}`);
|
||||||
|
const prev = syms.get(ident);
|
||||||
|
if (!prev.ok)
|
||||||
|
throw new Error("expected to be defined");
|
||||||
|
if (!prev.sym.pos)
|
||||||
|
return;
|
||||||
|
const { line: prevLine, col: prevCol } = prev.sym.pos;
|
||||||
|
console.error(`previous definition of '${ident}' at ${prevLine}:${prevCol}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -46,6 +46,7 @@ export type ExprKind =
|
|||||||
| { type: "null"}
|
| { type: "null"}
|
||||||
| { type: "loop", body: Expr }
|
| { type: "loop", body: Expr }
|
||||||
| { type: "block", stmts: Stmt[], expr?: Expr }
|
| { type: "block", stmts: Stmt[], expr?: Expr }
|
||||||
|
| { type: "sym", ident: string, defType: "let" | "fn" | "fn_param" | "builtin", stmt?: Stmt, param?: Param }
|
||||||
;
|
;
|
||||||
|
|
||||||
export type Sym = {
|
export type Sym = {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
|
|
||||||
//fn sum(a, b) {
|
fn sum(a, b) {
|
||||||
// + a b;
|
+ a b;
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//add(2,3); // -> 5
|
add(2,3); // -> 5
|
||||||
//
|
|
||||||
//let a = "Hello";
|
let a = "Hello";
|
||||||
//
|
|
||||||
//let b = "world";
|
let b = "world";
|
||||||
|
|
||||||
println(+ + + a " " b "!"); // -> "Hello world!"
|
println(+ + + a " " b "!"); // -> "Hello world!"
|
||||||
|
|
||||||
|
@ -19,8 +19,6 @@ else {
|
|||||||
println(":o");
|
println(":o");
|
||||||
}
|
}
|
||||||
|
|
||||||
oopjoipjioj
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user