diff --git a/compiler/Lexer.ts b/compiler/Lexer.ts index fd0f74d..1752ee4 100644 --- a/compiler/Lexer.ts +++ b/compiler/Lexer.ts @@ -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(); } diff --git a/compiler/Syms.ts b/compiler/Syms.ts index a2ed8da..86dc70c 100644 --- a/compiler/Syms.ts +++ b/compiler/Syms.ts @@ -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) diff --git a/compiler/ast.ts b/compiler/ast.ts index 49029f0..464ff14 100644 --- a/compiler/ast.ts +++ b/compiler/ast.ts @@ -1,6 +1,6 @@ import { Pos } from "./Token.ts"; -type UnaryType = "not"; +export type UnaryType = "not"; export type BinaryType = "+" | "*" | "==" | "-" | "/" | "!=" | "<" | ">" | "<=" | ">=" | "or" | "and"; export type Param = { diff --git a/compiler/main.ts b/compiler/main.ts index 536b495..00131f7 100644 --- a/compiler/main.ts +++ b/compiler/main.ts @@ -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))