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())
return null;
const pos = this.pos();
if (this.test(/[ \t\n]/)) {
while (!this.done() && this.test(/[ \t\n]/))
if (this.test(/[ \t\n\r]/)) {
while (!this.done() && this.test(/[ \t\n\r]/))
this.step();
return this.next();
}

View File

@ -1,10 +1,6 @@
import { Expr, Stmt, Sym } from "./ast.ts";
import { Pos } from "./Token.ts";
type Ident = string
type SymMap = { [ident: string]: Sym }
class Syms {
@ -29,10 +25,43 @@ class Syms {
}
}
// Chapter 7 is generally fucked, remember to give feedback to Simon
class Resolver {
export class Resolver {
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) {
if (expr.kind.type !== "ident")
throw new Error("expected ident");
@ -54,39 +83,6 @@ class Resolver {
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;
@ -104,22 +100,62 @@ class Resolver {
this.resolveExpr(stmt.kind.expr, syms);
return;
}
// ...
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) {
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}`);
}
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}`);
const prev = syms.get(ident);
if (!prev.ok)

View File

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

View File

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