mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
compiler: make reasonable resolving
This commit is contained in:
parent
21484b9f8e
commit
f09858a41d
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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>();
|
||||
|
@ -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,
|
||||
|
@ -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 => ({
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user