resolver stuff

This commit is contained in:
Mikkel Kongsted 2024-11-27 15:10:48 +01:00
parent 03d68fa562
commit c44c4fb9a7
4 changed files with 88 additions and 49 deletions

View File

@ -12,8 +12,8 @@ export class Lexer {
if (this.done()) if (this.done())
return null; return null;
const pos = this.pos(); const pos = this.pos();
if (this.test(/[ \t\n]/)) { if (this.test(/[ \t\n\r]/)) {
while (!this.done() && this.test(/[ \t\n]/)) while (!this.done() && this.test(/[ \t\n\r]/))
this.step(); this.step();
return this.next(); return this.next();
} }

View File

@ -1,10 +1,6 @@
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 Ident = string
type SymMap = { [ident: string]: Sym } type SymMap = { [ident: string]: Sym }
class Syms { class Syms {
@ -29,10 +25,43 @@ class Syms {
} }
} }
// Chapter 7 is generally fucked, remember to give feedback to Simon export class Resolver {
class Resolver {
private root = new Syms(); private root = new Syms();
public resolve(stmts: Stmt[]) {
const scopeSyms = new Syms(this.root);
for (const stmt of stmts) {
this.resolveStmt(stmt, scopeSyms);
}
}
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 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");
@ -54,39 +83,6 @@ class Resolver {
expr.kind.param = 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) { private resolveStmt(stmt: Stmt, syms: Syms) {
if (stmt.kind.type === "error") { if (stmt.kind.type === "error") {
return; return;
@ -104,22 +100,62 @@ class Resolver {
this.resolveExpr(stmt.kind.expr, syms); this.resolveExpr(stmt.kind.expr, syms);
return; return;
} }
// ...
throw new Error(`unknown statement ${stmt.kind.type}`); throw new Error(`unknown statement ${stmt.kind.type}`);
} }
private resolveLetStmt(stmt: Stmt, syms: Syms) {
private resolveLetStmt(stmt: Stmt, syms: Syms) {
if (stmt.kind.type !== "let")
throw new Error("expected let statement");
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,
});
} }
private resolveFnStmt(stmt: Stmt, syms: Syms) { private resolveFnStmt(stmt: Stmt, syms: Syms) {
if (stmt.kind.type !== "fn")
throw new Error("expected fn statement");
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,
});
const fnScopeSyms = new Syms(syms);
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);
} }
private reportUseOfUndefined(ident: Ident, 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: Ident, 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)

View File

@ -1,6 +1,6 @@
import { Pos } from "./Token.ts"; import { Pos } from "./Token.ts";
type UnaryType = "not"; export type UnaryType = "not";
export type BinaryType = "+" | "*" | "==" | "-" | "/" | "!=" | "<" | ">" | "<=" | ">=" | "or" | "and"; export type BinaryType = "+" | "*" | "==" | "-" | "/" | "!=" | "<" | ">" | "<=" | ">=" | "or" | "and";
export type Param = { export type Param = {

View File

@ -1,5 +1,6 @@
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";
const text = await Deno.readTextFile("example-no-types.slg"); const text = await Deno.readTextFile("example-no-types.slg");
// const text = await Deno.readTextFile("example.slg"); // const text = await Deno.readTextFile("example.slg");
@ -13,5 +14,7 @@ const lexer = new Lexer(text);
// } // }
const parser = new Parser(lexer) const parser = new Parser(lexer)
const result = parser.parseStmts() const ast = parser.parseStmts()
console.log(JSON.stringify(result, null, 4)) // const resolver = new Resolver()
// const resolvedAst = resolver.resolve(ast)
console.log(JSON.stringify(ast, null, 4))