compiler: make reasonable resolving

This commit is contained in:
SimonFJ20 2025-02-05 14:41:29 +01:00
parent 21484b9f8e
commit f09858a41d
5 changed files with 185 additions and 37 deletions

View File

@ -5,24 +5,28 @@ import {
exhausted,
File,
IdMap,
IdSet,
Ok,
Res,
Span,
todo,
} from "@slige/common";
import { Resols } from "@slige/resolve";
import * as resolve from "@slige/resolve";
import { Ty, tyToString } from "@slige/ty";
export class Checker {
private stmtChecked = new IdSet<AstId>();
private itemTys = new IdMap<AstId, Ty>();
private exprTys = new IdMap<AstId, Ty>();
private tyTys = new IdMap<AstId, Ty>();
private patTys = new IdMap<AstId, Ty>();
private currentFile: File;
public constructor(
private ctx: Ctx,
private entryFileAst: ast.File,
private resols: Resols,
private resols: resolve.Resols,
) {
this.currentFile = ctx.entryFile();
}
@ -37,8 +41,51 @@ export class Checker {
private checkStmts(stmts: ast.Stmt[]) {
}
private checkLetStmtTy(stmt: ast.Stmt, kind: ast.LetStmt) {
if (this.stmtChecked.has(stmt.id)) {
return;
}
const exprTy = kind.expr && Ok(this.exprTy(kind.expr));
const tyTy = kind.ty && Ok(this.tyTy(kind.ty));
const ty = exprTy && tyTy && this.resolveTys(exprTy.val, tyTy.val);
if (ty === undefined) {
this.report("type amfibious, specify type or value", stmt.span);
return Ty({ tag: "error" });
}
if (!ty.ok) {
this.report(ty.val, stmt.span);
return Ty({ tag: "error" });
}
const res = this.assignPatTy(kind.pat, ty.val);
if (!res.ok) {
this.report(res.val, stmt.span);
return Ty({ tag: "error" });
}
this.stmtChecked.add(stmt.id);
}
private assignPatTy(pat: ast.Pat, ty: Ty): Res<void, string> {
const k = pat.kind;
switch (k.tag) {
case "error":
// don't report, already reported
return Res.Ok(undefined);
case "bind":
this.patTys.set(pat.id, ty);
return Ok(undefined);
case "path":
return todo();
}
exhausted(k);
}
public fnItemTy(item: ast.Item, kind: ast.FnItem): Ty {
return this.itemTys.get(item.id) || this.checkFnItem(item, kind);
return this.itemTys.get(item.id) ?? this.checkFnItem(item, kind);
}
private checkFnItem(item: ast.Item, kind: ast.FnItem): Ty {
@ -128,7 +175,8 @@ export class Checker {
return resu.val;
}
case "local": {
const patResu = this.resols.patRes();
const patRes = this.resols.patRes(res.kind.id);
const ty = this.patTy(patRes.pat);
const resu = this.resolveTys(ty, expected);
if (!resu.ok) {
this.report(resu.val, expr.span);
@ -166,13 +214,23 @@ export class Checker {
exhausted(k);
}
private report(msg: string, span: Span) {
this.ctx.report({
severity: "error",
file: this.currentFile,
span,
msg,
});
public patTy(pat: ast.Pat): Ty {
return this.patTys.get(pat.id) ||
this.checkPat(pat);
}
private checkPat(pat: ast.Pat): Ty {
const patRes = this.resols.patRes(pat.id);
const k = pat.kind;
switch (k.tag) {
case "error":
return todo();
case "bind":
return todo();
case "path":
return todo();
}
exhausted(k);
}
private resolveTys(a: Ty, b: Ty): Res<Ty, string> {
@ -211,4 +269,13 @@ export class Checker {
}
exhausted(a.kind);
}
private report(msg: string, span: Span) {
this.ctx.report({
severity: "error",
file: this.currentFile,
span,
msg,
});
}
}

View File

@ -1,3 +1,5 @@
import { todo } from "./util.ts";
//
export type File = IdBase & { readonly _: unique symbol };
@ -27,6 +29,74 @@ export class Ids<IdType extends IdBase> {
return idFromRaw(rawId);
}
}
export class IdSet<Id extends IdBase> implements Set<Id> {
private set = new Set<IdRaw<Id>>();
add(value: Id): this {
this.set.add(idRaw(value));
return this;
}
clear(): void {
this.set.clear();
}
delete(value: Id): boolean {
return this.set.delete(idRaw(value));
}
forEach(
callbackfn: (value: Id, value2: Id, set: Set<Id>) => void,
thisArg?: unknown,
): void {
this.set.forEach(
(v1, v2) => callbackfn(idFromRaw(v1), idFromRaw(v2), this),
thisArg,
);
}
has(value: Id): boolean {
return this.set.has(idRaw(value));
}
get size(): number {
return this.set.size;
}
entries(): SetIterator<[Id, Id]> {
return this.set.entries()
.map(([v1, v2]) => [idFromRaw(v1), idFromRaw(v2)]);
}
keys(): SetIterator<Id> {
return this.set.keys()
.map((v) => idFromRaw(v));
}
values(): SetIterator<Id> {
return this.set.values()
.map((v) => idFromRaw(v));
}
union<U>(_other: ReadonlySetLike<U>): Set<Id | U> {
return todo();
}
intersection<U>(_other: ReadonlySetLike<U>): Set<Id & U> {
return todo();
}
difference<U>(_other: ReadonlySetLike<U>): Set<Id> {
return todo();
}
symmetricDifference<U>(_other: ReadonlySetLike<U>): Set<Id | U> {
return todo();
}
isSubsetOf(_other: ReadonlySetLike<unknown>): boolean {
return todo();
}
isSupersetOf(_other: ReadonlySetLike<unknown>): boolean {
return todo();
}
isDisjointFrom(_other: ReadonlySetLike<unknown>): boolean {
return todo();
}
[Symbol.iterator](): SetIterator<Id> {
return this.set[Symbol.iterator]().map((v) => idFromRaw(v));
}
get [Symbol.toStringTag](): string {
return this.set[Symbol.toStringTag];
}
}
export class IdMap<Id extends IdBase, V> implements Map<Id, V> {
private map = new Map<IdRaw<Id>, V>();

View File

@ -1,7 +1,7 @@
import * as ast from "@slige/ast";
import { Checker } from "@slige/check";
import { Ctx, exhausted, IdMap, Ids, Res, todo } from "@slige/common";
import { LocalId as ReLocalId, Resols } from "@slige/resolve";
import { AstId, Ctx, exhausted, IdMap, Ids, Res, todo } from "@slige/common";
import { Resols } from "@slige/resolve";
import { Ty } from "@slige/ty";
import { BinaryType, Operand, StmtKind, TerKind } from "./mir.ts";
import { Block, BlockId, Fn, Local, LocalId, RVal, Stmt, Ter } from "./mir.ts";
@ -32,7 +32,7 @@ export class FnLowerer {
private currentBlock?: Block;
private reLocals = new IdMap<ReLocalId, LocalId>();
private reLocals = new IdMap<AstId, LocalId>();
public constructor(
private ctx: Ctx,

View File

@ -17,16 +17,15 @@ export type Resolve = {
export type ResolveKind =
| { tag: "error" }
| { tag: "fn"; item: ast.Item; kind: ast.FnItem }
| { tag: "local"; id: LocalId };
| { tag: "local"; id: AstId };
export type PatResolve =
| { tag: "param"; paramIdx: number }
| { tag: "let"; stmt: ast.Stmt; kind: ast.LetStmt };
export type PatResolve = {
pat: ast.Pat;
kind: PatResolveKind;
};
export type LocalId = IdBase & { readonly _: unique symbol };
export type Local =
| { tag: "param"; paramIdx: number }
export type PatResolveKind =
| { tag: "fn_param"; paramIdx: number }
| { tag: "let"; stmt: ast.Stmt; kind: ast.LetStmt };
export const ResolveError = (ident: ast.Ident): Resolve => ({

View File

@ -1,16 +1,26 @@
import * as ast from "@slige/ast";
import { AstId, Ctx, exhausted, File, IdMap, Ids, todo } from "@slige/common";
import {
AstId,
Ctx,
exhausted,
File,
IdMap,
Ids,
Res,
Span,
todo,
} from "@slige/common";
import {
FnSyms,
LocalId,
LocalSyms,
PatResolve,
PatResolveKind,
Redef,
Resolve,
ResolveError,
RootSyms,
Syms,
} from "./cx.ts";
export { type LocalId } from "./cx.ts";
export class Resols {
public constructor(
@ -41,9 +51,7 @@ export class Resolver implements ast.Visitor {
private exprResols = new IdMap<AstId, Resolve>();
private patResols = new IdMap<AstId, PatResolve>();
private patResolveStack: PatResolve[] = [];
private localIds = new Ids<LocalId>();
private patResolveStack: PatResolveKind[] = [];
public constructor(
private ctx: Ctx,
@ -115,7 +123,7 @@ export class Resolver implements ast.Visitor {
this.syms = new FnSyms(this.syms);
this.syms = new LocalSyms(this.syms);
for (const [paramIdx, param] of kind.params.entries()) {
this.patResolveStack.push({ tag: "param", paramIdx });
this.patResolveStack.push({ tag: "fn_param", paramIdx });
ast.visitParam(this, param);
this.patResolveStack.pop();
}
@ -164,19 +172,14 @@ export class Resolver implements ast.Visitor {
}
visitBindPat(pat: ast.Pat, kind: ast.BindPat): ast.VisitRes {
this.patResols.set(pat.id, this.patResolveStack.at(-1)!);
this.patResols.set(pat.id, { pat, kind: this.patResolveStack.at(-1)! });
const res = this.syms.defVal(kind.ident, {
tag: "local",
id: this.localIds.nextThenStep(),
id: pat.id,
});
if (!res.ok) {
const text = this.ctx.identText(kind.ident.id);
this.ctx.report({
severity: "error",
file: this.currentFile,
span: kind.ident.span,
msg: `redefinition of value '${text}'`,
});
this.report(`redefinition of value '${text}'`, kind.ident.span);
}
return "stop";
}
@ -221,4 +224,13 @@ export class Resolver implements ast.Visitor {
}, this.syms.getTy(path.segments[0].ident));
return res;
}
private report(msg: string, span: Span) {
this.ctx.report({
severity: "error",
file: this.currentFile,
span,
msg,
});
}
}