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