From 5af5bfed7f06b1bfab843218697ece885242dcab Mon Sep 17 00:00:00 2001 From: sfja Date: Mon, 16 Mar 2026 22:13:41 +0100 Subject: [PATCH] checker into tys --- src/front/check.ts | 73 +++++++++++++++++++++++++--------------------- src/main.ts | 4 +-- src/middle.ts | 36 +++++++++++------------ 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/front/check.ts b/src/front/check.ts index 2d7ca43..b0cdb2b 100644 --- a/src/front/check.ts +++ b/src/front/check.ts @@ -4,30 +4,35 @@ import { Ty } from "../ty.ts"; import { builtins } from "./builtins.ts"; import { ResolveMap } from "./resolve.ts"; -// export class Tys { -// private nodeTys = new Map(); -// -// expr(expr: ast.Node): Ty {} -// } - -export class Checker { +export class Tys { private nodeTys = new Map(); + private checker: Checker; constructor( private resols: ResolveMap, private reporter: FileReporter, - ) {} + ) { + this.checker = new Checker(this, this.resols, this.reporter); + } - check(node: ast.Node): Ty { + expr(node: ast.Node): Ty { if (this.nodeTys.has(node.id)) { return this.nodeTys.get(node.id)!; } - const ty = this.checkNode(node); + const ty = this.checker.checkExpr(node); this.nodeTys.set(node.id, ty); return ty; } +} - private checkNode(node: ast.Node): Ty { +class Checker { + constructor( + private tys: Tys, + private resols: ResolveMap, + private reporter: FileReporter, + ) {} + + checkExpr(node: ast.Node): Ty { const k = node.kind; if (node.is("FnStmt")) { @@ -38,9 +43,9 @@ export class Checker { const sym = this.resols.get(node); if (sym.tag === "Let") { - const exprTy = this.check(sym.stmt.kind.expr); + const exprTy = this.tys.expr(sym.stmt.kind.expr); if (node.kind.ty) { - const explicitTy = this.check(node.kind.ty); + const explicitTy = this.tys.expr(node.kind.ty); this.assertCompatible( exprTy, explicitTy, @@ -54,7 +59,7 @@ export class Checker { this.error(node.loc, `parameter must have a type`); this.fail(); } - return this.check(node.kind.ty); + return this.tys.expr(node.kind.ty); } throw new Error(`'${sym.tag}' not handled`); @@ -63,7 +68,7 @@ export class Checker { if (node.is("IdentExpr")) { const sym = this.resols.get(node); if (sym.tag === "Fn") { - return this.check(sym.stmt); + return this.tys.expr(sym.stmt); } if (sym.tag === "Bool") { return Ty.Bool; @@ -72,10 +77,10 @@ export class Checker { return builtins.find((s) => s.id === sym.id)!.ty; } if (sym.tag === "FnParam") { - return this.check(sym.param); + return this.tys.expr(sym.param); } if (sym.tag === "Let") { - return this.check(sym.param); + return this.tys.expr(sym.param); } throw new Error(`'${sym.tag}' not handled`); } @@ -87,7 +92,7 @@ export class Checker { if (node.is("ArrayExpr")) { let ty: Ty | null = null; for (const value of node.kind.values) { - const valueTy = this.check(value); + const valueTy = this.tys.expr(value); if (ty) { this.assertCompatible(ty, valueTy, value.loc); } else { @@ -103,8 +108,8 @@ export class Checker { } if (node.is("IndexExpr")) { - const exprTy = this.check(node.kind.expr); - const argTy = this.check(node.kind.arg); + const exprTy = this.tys.expr(node.kind.expr); + const argTy = this.tys.expr(node.kind.arg); if ( (exprTy.is("Array") || exprTy.is("Slice")) && argTy.compatibleWith(Ty.Int) @@ -129,7 +134,7 @@ export class Checker { } if (node.is("UnaryExpr")) { - const exprTy = this.check(node.kind.expr); + const exprTy = this.tys.expr(node.kind.expr); if (node.kind.op === "Negate" && exprTy.compatibleWith(Ty.Int)) { return Ty.Int; } @@ -155,8 +160,8 @@ export class Checker { } if (node.is("BinaryExpr")) { - const left = this.check(node.kind.left); - const right = this.check(node.kind.right); + const left = this.tys.expr(node.kind.left); + const right = this.tys.expr(node.kind.right); const binaryOp = binaryOpPatterns .find((pat) => pat.op === node.kind.op && @@ -175,7 +180,7 @@ export class Checker { if (node.is("RangeExpr")) { for (const operandExpr of [node.kind.begin, node.kind.end]) { - const operandTy = operandExpr && this.check(operandExpr); + const operandTy = operandExpr && this.tys.expr(operandExpr); if (operandTy && !operandTy.compatibleWith(Ty.Int)) { this.error( operandExpr.loc, @@ -201,17 +206,17 @@ export class Checker { } if (node.is("PtrTy")) { - const ty = this.check(node.kind.ty); + const ty = this.tys.expr(node.kind.ty); return Ty.create("Ptr", { ty }); } if (node.is("PtrMutTy")) { - const ty = this.check(node.kind.ty); + const ty = this.tys.expr(node.kind.ty); return Ty.create("PtrMut", { ty }); } if (node.is("ArrayTy")) { - const ty = this.check(node.kind.ty); - const lengthTy = this.check(node.kind.length); + const ty = this.tys.expr(node.kind.ty); + const lengthTy = this.tys.expr(node.kind.length); if (!lengthTy.compatibleWith(Ty.Int)) { this.error( node.kind.length.loc, @@ -231,7 +236,7 @@ export class Checker { } if (node.is("SliceTy")) { - const ty = this.check(node.kind.ty); + const ty = this.tys.expr(node.kind.ty); return Ty.create("Slice", { ty }); } @@ -241,14 +246,14 @@ export class Checker { private checkFnStmt(stmt: ast.NodeWithKind<"FnStmt">): Ty { const k = stmt.kind; - const params = k.params.map((param) => this.check(param)); - const retTy = k.retTy ? this.check(k.retTy) : Ty.Void; + const params = k.params.map((param) => this.tys.expr(param)); + const retTy = k.retTy ? this.tys.expr(k.retTy) : Ty.Void; k.body.visit({ visit: (node) => { if (node.is("ReturnStmt")) { const ty = node.kind.expr - ? this.check(node.kind.expr) + ? this.tys.expr(node.kind.expr) : Ty.Void; if (!ty.compatibleWith(retTy)) { this.error( @@ -270,7 +275,7 @@ export class Checker { } private checkCall(node: ast.NodeWithKind<"CallExpr">): Ty { - const calleeTy = this.check(node.kind.expr); + const calleeTy = this.tys.expr(node.kind.expr); const callableTy = calleeTy.is("Fn") ? calleeTy @@ -287,7 +292,7 @@ export class Checker { } const args = node.kind.args - .map((arg) => this.check(arg)); + .map((arg) => this.tys.expr(arg)); const params = callableTy.kind.params; if (args.length !== params.length) { this.error( diff --git a/src/main.ts b/src/main.ts index 2362ca9..002bdee 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,7 +13,7 @@ const fileRep = reporter.ofFile({ filename, text }); const fileAst = front.parse(text, fileRep); const resols = front.resolve(fileAst, fileRep); -const checker = new front.Checker(resols, fileRep); +const tys = new front.Tys(resols, fileRep); let mainFn: ast.NodeWithKind<"FnStmt"> | null = null; @@ -36,7 +36,7 @@ if (!mainFn) { Deno.exit(1); } -const m = new middle.MiddleLowerer(resols, checker); +const m = new middle.MiddleLowerer(resols, tys); const mainMiddleFn = m.lowerFn(mainFn); if (!Deno.args.includes("--test")) { diff --git a/src/middle.ts b/src/middle.ts index 144272a..0d7034b 100644 --- a/src/middle.ts +++ b/src/middle.ts @@ -1,5 +1,5 @@ import * as ast from "./ast.ts"; -import { Checker, ResolveMap } from "./front/mod.ts"; +import { ResolveMap, Tys } from "./front/mod.ts"; import { Ty } from "./ty.ts"; import { BasicBlock, BinaryOp, Fn, Inst, InstKind } from "./mir.ts"; @@ -8,14 +8,14 @@ export class MiddleLowerer { constructor( private resols: ResolveMap, - private checker: Checker, + private tys: Tys, ) {} lowerFn(stmt: ast.FnStmt): Fn { if (this.fns.has(stmt.id)) { return this.fns.get(stmt.id)!; } - const fn = new FnLowerer(this, this.resols, this.checker, stmt).lower(); + const fn = new FnLowerer(this, this.resols, this.tys, stmt).lower(); this.fns.set(stmt.id, fn); return fn; } @@ -29,12 +29,12 @@ class FnLowerer { constructor( private lowerer: MiddleLowerer, private resols: ResolveMap, - private checker: Checker, + private tys: Tys, private stmt: ast.FnStmt, ) {} lower(): Fn { - const ty = this.checker.check(this.stmt); + const ty = this.tys.expr(this.stmt); this.lowerBlock(this.stmt.kind.body.as("Block")); this.pushInst(Ty.Void, "Return", { source: this.makeVoid() }); this.bbs[0].insts.unshift(...this.allocs); @@ -49,7 +49,7 @@ class FnLowerer { private lowerStmt(stmt: ast.Node) { if (stmt.is("LetStmt")) { - const ty = this.checker.check(stmt.kind.param); + const ty = this.tys.expr(stmt.kind.param); const expr = this.lowerExpr(stmt.kind.expr); const local = new Inst(Ty.create("Ptr", { ty }), { tag: "Alloca" }); this.allocs.push(local); @@ -136,12 +136,12 @@ class FnLowerer { } if (place.is("IndexExpr")) { - const exprTy = this.checker.check(place.kind.expr); + const exprTy = this.tys.expr(place.kind.expr); if (!exprTy.is("Array") && !exprTy.is("Slice")) { throw new Error(exprTy.pretty()); } const arg = place.kind.arg; - const argTy = this.checker.check(arg); + const argTy = this.tys.expr(arg); const exprInst = this.lowerExpr(place.kind.expr); if (argTy.is("Int")) { const argInst = this.lowerExpr(arg); @@ -183,7 +183,7 @@ class FnLowerer { return this.pushInst(fn.ty, "Fn", { fn }); } if (sym.tag === "FnParam") { - const ty = this.checker.check(sym.param); + const ty = this.tys.expr(sym.param); return this.pushInst(ty, "Param", { idx: sym.idx }); } if (sym.tag === "Builtin") { @@ -205,19 +205,19 @@ class FnLowerer { return this.pushInst(Ty.Int, "Int", { value: expr.kind.value }); } if (expr.is("ArrayExpr")) { - const ty = this.checker.check(expr); + const ty = this.tys.expr(expr); const values = expr.kind.values .map((value) => this.lowerExpr(value)); return this.pushInst(ty, "Array", { values }); } if (expr.is("IndexExpr")) { - const ty = this.checker.check(expr.kind.expr); + const ty = this.tys.expr(expr.kind.expr); const arg = this.lowerExpr(expr.kind.arg); const value = this.lowerExpr(expr.kind.expr); return this.pushInst(ty, "Index", { value, arg }); } if (expr.is("CallExpr")) { - const ty = this.checker.check(expr); + const ty = this.tys.expr(expr); const args = expr.kind.args .map((arg) => this.lowerExpr(arg)); @@ -239,8 +239,8 @@ class FnLowerer { return this.pushInst(ty, "Call", { callee, args }); } if (expr.is("UnaryExpr")) { - const resultTy = this.checker.check(expr); - const operandTy = this.checker.check(expr.kind.expr); + const resultTy = this.tys.expr(expr); + const operandTy = this.tys.expr(expr.kind.expr); if ( expr.kind.op === "Negate" && operandTy.compatibleWith(Ty.Int) && @@ -273,7 +273,7 @@ class FnLowerer { ); } if (place.is("IndexExpr")) { - const placeTy = this.checker.check(place); + const placeTy = this.tys.expr(place); const placeInst = this.lowerPlace(place); if (placeTy.is("Slice")) { return placeInst; @@ -295,9 +295,9 @@ class FnLowerer { ); } if (expr.is("BinaryExpr")) { - const resultTy = this.checker.check(expr); - const leftTy = this.checker.check(expr.kind.left); - const rightTy = this.checker.check(expr.kind.right); + const resultTy = this.tys.expr(expr); + const leftTy = this.tys.expr(expr.kind.left); + const rightTy = this.tys.expr(expr.kind.right); const binaryOp = binaryOpPatterns .find((pat) => expr.kind.op === pat.op &&