typchk or smthng idk

This commit is contained in:
SimonFJ20 2025-02-03 15:04:06 +01:00
parent 1f9cbea832
commit 60efd931f5
11 changed files with 557 additions and 184 deletions

View File

@ -62,7 +62,9 @@ export type ItemKind =
| { tag: "type_alias" } & TypeAliasItem; | { tag: "type_alias" } & TypeAliasItem;
export type ModBlockItem = { block: Block }; export type ModBlockItem = { block: Block };
export type ModFileItem = { filePath: string; file?: CtxFile };
export type ModFileItem = { filePath: string; file?: CtxFile; ast?: File };
export type EnumItem = { variants: Variant[] }; export type EnumItem = { variants: Variant[] };
export type StructItem = { data: VariantData }; export type StructItem = { data: VariantData };

33
compiler/ast/to_string.ts Normal file
View File

@ -0,0 +1,33 @@
import { Ctx } from "../ctx.ts";
import { exhausted, todo } from "../util.ts";
import { Block, Item } from "./ast.ts";
export function itemToString(ctx: Ctx, item: Item): string {
const ident = ctx.identText(item.ident.id);
const k = item.kind;
switch (k.tag) {
case "error":
return `<error>`;
case "mod_block": {
const block = blockToString(ctx, k.block);
return `mod ${item} ${block}`;
}
case "mod_file":
return todo();
case "enum":
return todo();
case "struct":
return todo();
case "fn":
return todo();
case "use":
return todo();
case "type_alias":
return todo();
}
return exhausted(k);
}
export function blockToString(ctx: Ctx, block: Block): string {
return todo();
}

185
compiler/check/checker.ts Normal file
View File

@ -0,0 +1,185 @@
import * as ast from "../ast/mod.ts";
import { Ctx, File } from "../ctx.ts";
import { Span } from "../diagnostics.ts";
import { Resols } from "../resolve/resolver.ts";
import { tyToString } from "../ty/to_string.ts";
import { Ty } from "../ty/ty.ts";
import { exhausted, Res, todo } from "../util.ts";
export class Checker {
private itemTys = new Map<number, Ty>();
private exprTys = new Map<number, Ty>();
private tyTys = new Map<number, Ty>();
private currentFile: File;
public constructor(
private ctx: Ctx,
private entryFileAst: ast.File,
private resols: Resols,
) {
this.currentFile = ctx.entryFile();
}
private checkBlock(block: ast.Block, expected: Ty): Ty {
this.checkStmts(block.stmts);
return block.expr &&
this.checkExpr(block.expr, expected) ||
Ty({ tag: "null" });
}
private checkStmts(stmts: ast.Stmt[]) {
}
public fnItemTy(item: ast.Item, kind: ast.FnItem): Ty {
return this.itemTys.get(item.id) || this.checkFnItem(item, kind);
}
private checkFnItem(item: ast.Item, kind: ast.FnItem): Ty {
const params = kind.params.map((param) => this.tyTy(param.ty));
const returnTy = kind.returnTy && this.tyTy(kind.returnTy) ||
Ty({ tag: "null" });
return Ty({ tag: "fn", item, kind, params, returnTy });
}
public exprTy(expr: ast.Expr): Ty {
return this.exprTys.get(expr.id) ||
this.checkExpr(expr, Ty({ tag: "unknown" }));
}
private checkExpr(expr: ast.Expr, expected: Ty): Ty {
const k = expr.kind;
switch (k.tag) {
case "error":
return Ty({ tag: "error" });
case "path":
return this.checkPathExpr(expr, k, expected);
case "null":
return todo();
case "int":
return todo();
case "bool":
return todo();
case "str":
return todo();
case "group":
return todo();
case "array":
return todo();
case "repeat":
return todo();
case "struct":
return todo();
case "ref":
return todo();
case "deref":
return todo();
case "elem":
return todo();
case "field":
return todo();
case "index":
return todo();
case "call":
return todo();
case "unary":
return todo();
case "binary":
return todo();
case "block":
return todo();
case "if":
return todo();
case "loop":
return todo();
case "while":
return todo();
case "for":
return todo();
case "c_for":
return todo();
}
exhausted(k);
}
private checkPathExpr(
expr: ast.Expr,
kind: ast.PathExpr,
expected: Ty,
): Ty {
const res = this.resols.exprRes(expr.id);
switch (res.kind.tag) {
case "error":
return Ty({ tag: "error" });
case "fn": {
const fn = res.kind.item;
const ty = this.fnItemTy(fn, res.kind.kind);
const resu = this.resolveTys(ty, expected);
if (!resu.ok) {
this.report(resu.val, expr.span);
return Ty({ tag: "error" });
}
return resu.val;
}
case "local": {
const ty = this.exprTy(expr);
const resu = this.resolveTys(ty, expected);
if (!resu.ok) {
this.report(resu.val, expr.span);
return Ty({ tag: "error" });
}
return resu.val;
}
}
exhausted(res.kind);
}
private tyTy(ty: ast.Ty): Ty {
return this.tyTys.get(ty.id) ||
this.checkTy(ty);
}
private checkTy(ty: ast.Ty): Ty {
return todo();
}
private report(msg: string, span: Span) {
this.ctx.report({
severity: "error",
file: this.currentFile,
span,
msg,
});
}
private resolveTys(a: Ty, b: Ty): Res<Ty, string> {
const as = tyToString(this.ctx, a);
const bs = tyToString(this.ctx, b);
const incompat = () =>
Res.Err(
`type '${as}' not compatible with type '${bs}'`,
);
switch (a.kind.tag) {
case "error":
return Res.Ok(b);
case "unknown":
return Res.Ok(b);
case "null": {
if (b.kind.tag !== "null") {
return incompat();
}
return Res.Ok(a);
}
case "fn": {
if (b.kind.tag !== "fn") {
return incompat();
}
if (b.kind.item.id === a.kind.item.id) {
return incompat();
}
return Res.Ok(a);
}
}
exhausted(a.kind);
}
}

View File

@ -4,6 +4,7 @@ import * as ast from "./ast/mod.ts";
import { Ctx } from "./ctx.ts"; import { Ctx } from "./ctx.ts";
import { File } from "./ctx.ts"; import { File } from "./ctx.ts";
import { Resolver } from "./resolve/resolver.ts"; import { Resolver } from "./resolve/resolver.ts";
import { Checker } from "./check/checker.ts";
async function main() { async function main() {
const filePath = Deno.args[0]; const filePath = Deno.args[0];
@ -37,13 +38,11 @@ export class PackCompiler {
) {} ) {}
public async compile() { public async compile() {
await FileTreeAstCollector const [entryFile, entryFileAst] = await FileTreeAstCollector
.fromEntryFile(this.ctx, this.astCx, this.entryFilePath) .fromEntryFile(this.ctx, this.astCx, this.entryFilePath)
.collect(); .collect();
// this.ctx.printAsts(); const resols = new Resolver(this.ctx, entryFileAst).resolve();
const entryFile = this.ctx.entryFile(); const checker = new Checker(this.ctx, entryFileAst, resols);
const entryFileAst = this.ctx.fileInfo(entryFile).ast!;
new Resolver(this.ctx, entryFileAst).resolve();
} }
public enableDebug() { public enableDebug() {
@ -80,7 +79,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
); );
} }
public async collect(): Promise<File> { public async collect(): Promise<[File, ast.File]> {
const text = await Deno.readTextFile(this.absPath); const text = await Deno.readTextFile(this.absPath);
const file = this.ctx.addFile( const file = this.ctx.addFile(
this.ident, this.ident,
@ -93,7 +92,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
this.ctx.addFileAst(file, fileAst); this.ctx.addFileAst(file, fileAst);
ast.visitFile(this, fileAst, { file }); ast.visitFile(this, fileAst, { file });
await this.subFilePromise; await this.subFilePromise;
return file; return [file, fileAst];
} }
visitModFileItem( visitModFileItem(
@ -115,7 +114,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
}); });
Deno.exit(1); Deno.exit(1);
} }
const modFile = await new FileTreeAstCollector( const [modFile, modAst] = await new FileTreeAstCollector(
this.ctx, this.ctx,
this.astCx, this.astCx,
file, file,
@ -125,6 +124,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
) )
.collect(); .collect();
kind.file = modFile; kind.file = modFile;
kind.ast = modAst;
}); });
return "stop"; return "stop";
} }

40
compiler/middle/mir.ts Normal file
View File

@ -0,0 +1,40 @@
import { Span } from "../diagnostics.ts";
export type Stmt = {
kind: StmtKind;
};
export type StmtKind =
| { tag: "error" }
| { tag: "assign" } & AssignStmt
| { tag: "fake_read" } & FakeReadStmt
| { tag: "deinit" } & DeinitStmt
| { tag: "live" } & LiveStmt
| { tag: "dead" } & DeadStmt
| { tag: "mention" } & MentionStmt;
export type AssignStmt = { place: Place; rval: RVal };
export type FakeReadStmt = { place: Place };
export type DeinitStmt = { place: Place };
export type LiveStmt = { local: Local };
export type DeadStmt = { local: Local };
export type MentionStmt = { place: Place };
export type Place = {
local: Local;
proj: ProjElem[];
};
// https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/mir/type.PlaceElem.html
export type ProjElem =
| { tag: "deref" }
| { tag: "repeat" }
| { tag: "field"; fieldIdx: number }
| { tag: "index": local: Local }
| { tag: }
// https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/mir/enum.Rvalue.html
export type RVal = {};
export type Local = {};

View File

@ -9,3 +9,4 @@ fn main() {
let c = add(a, b); let c = add(a, b);
} }

View File

@ -1,94 +1,130 @@
import * as ast from "../ast/mod.ts";
import { IdentId, idKey, Key } from "../ctx.ts"; import { IdentId, idKey, Key } from "../ctx.ts";
import { Res } from "../util.ts";
type Ident = Key<IdentId>; export interface Syms {
getVal(ident: ast.Ident): Resolve;
getTy(ident: ast.Ident): Resolve;
export class Ribs { defVal(ident: ast.Ident, kind: ResolveKind): Res<void, Redef>;
private tyRibs: Rib[] = []; defTy(ident: ast.Ident, kind: ResolveKind): Res<void, Redef>;
private valRibs: Rib[] = []; }
private constructor() {} export type Resolve = {
ident: ast.Ident;
kind: ResolveKind;
};
public static withRootMod(): Ribs { export type ResolveKind =
const ribs = new Ribs(); | { tag: "error" }
ribs.pushRib({ tag: "mod", mod: { items: new Map() } }); | { tag: "fn"; item: ast.Item; kind: ast.FnItem }
return ribs; | { tag: "local" };
export const ResolveError = (ident: ast.Ident): Resolve => ({
ident,
kind: { tag: "error" },
});
export type Redef = {
ident: ast.Ident;
};
export class SymsOneNsTab {
private defs = new Map<Key<IdentId>, Resolve>();
public get(ident: ast.Ident): Resolve | undefined {
return this.defs.get(idKey(ident.id))!;
} }
public pushRib(kind: RibKind) { public def(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
this.tyRibs.push({ bindings: new Map(), kind }); if (this.defs.has(idKey(ident.id))) {
this.valRibs.push({ bindings: new Map(), kind }); return Res.Err({ ident: this.defs.get(idKey(ident.id))!.ident });
} }
this.defs.set(idKey(ident.id), { ident, kind });
public hasTy(ident: IdentId): boolean { return Res.Ok(undefined);
return this.tyRibs.at(-1)!.bindings.has(idKey(ident));
}
public defTy(ident: IdentId, res: Res) {
this.tyRibs.at(-1)!.bindings.set(idKey(ident), res);
}
public hasVal(ident: IdentId): boolean {
return this.valRibs.at(-1)!.bindings.has(idKey(ident));
}
public val(ident: IdentId) {
}
public defVal(ident: IdentId, res: Res) {
this.valRibs.at(-1)!.bindings.set(idKey(ident), res);
}
public checkpoint(): number {
return this.tyRibs.length;
}
public returnToCheckpoint(checkpoint: number) {
this.tyRibs = this.tyRibs.slice(checkpoint, this.tyRibs.length);
this.valRibs = this.valRibs.slice(checkpoint, this.valRibs.length);
}
public nearestMod(): Mod {
return [
this.tyRibs
.toReversed()
.find((r) => r.kind.tag === "mod")!,
]
.map((r) => (r.kind.tag === "mod" && r.kind.mod) as Mod)[0];
} }
} }
export type Mod = { export class SymsNsTab {
parent?: Mod; private vals = new SymsOneNsTab();
items: Map<Ident, Res>; private tys = new SymsOneNsTab();
};
export type Rib = { public getVal(ident: ast.Ident): Resolve | undefined {
bindings: Map<Ident, Res>; return this.vals.get(ident);
kind: RibKind; }
}; public getTy(ident: ast.Ident): Resolve | undefined {
return this.tys.get(ident);
}
export type RibKind = public defVal(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
| { tag: "normal" } return this.vals.def(ident, kind);
| { tag: "fn" } }
| { tag: "item" } public defTy(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
| { tag: "mod"; mod: Mod }; return this.tys.def(ident, kind);
}
}
export type Res = export class RootSyms implements Syms {
| { tag: "def"; def: Def } private syms = new SymsNsTab();
| { tag: "local"; id: number };
export type Def = { getVal(ident: ast.Ident): Resolve {
type: DefType; return this.syms.getVal(ident) || ResolveError(ident);
id: number; }
}; getTy(ident: ast.Ident): Resolve {
return this.syms.getTy(ident) || ResolveError(ident);
}
defVal(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
return this.syms.defVal(ident, kind);
}
defTy(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
return this.syms.defTy(ident, kind);
}
}
export class FnSyms implements Syms {
private syms = new SymsNsTab();
public constructor(
private parent: Syms,
) {}
getVal(ident: ast.Ident): Resolve {
const res = this.syms.getVal(ident) || this.parent.getVal(ident);
if (res.kind.tag === "local") {
return ResolveError(ident);
}
return res;
}
getTy(ident: ast.Ident): Resolve {
return this.syms.getTy(ident) || this.parent.getTy(ident);
}
defVal(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
return this.syms.defVal(ident, kind);
}
defTy(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
return this.syms.defTy(ident, kind);
}
}
export class LocalSyms implements Syms {
private syms = new SymsNsTab();
public constructor(
private parent: Syms,
) {}
getVal(ident: ast.Ident): Resolve {
return this.syms.getVal(ident) || this.parent.getVal(ident);
}
getTy(ident: ast.Ident): Resolve {
return this.syms.getTy(ident) || this.parent.getTy(ident);
}
defVal(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
return this.syms.defVal(ident, kind);
}
defTy(ident: ast.Ident, kind: ResolveKind): Res<void, Redef> {
return this.syms.defTy(ident, kind);
}
}
export type DefType =
| "mod"
| "enum"
| "struct"
| "variant"
| "ty_alias"
| "ty_param"
| "fn"
| "use"
| "field";

View File

@ -1,60 +1,67 @@
import * as ast from "../ast/mod.ts"; import * as ast from "../ast/mod.ts";
import { Ctx, File, IdentId, idKey, Key } from "../ctx.ts"; import { Ctx, File } from "../ctx.ts";
import { todo } from "../util.ts"; import { exhausted, todo } from "../util.ts";
import { Def, DefType, Mod, Res, Ribs } from "./cx.ts"; import {
FnSyms,
LocalSyms,
Resolve,
ResolveError,
RootSyms,
Syms,
} from "./cx.ts";
export class Resols {
public constructor(
private exprResols: Map<number, Resolve>,
) {}
public exprRes(id: number): Resolve {
if (!this.exprResols.has(id)) {
throw new Error();
}
return this.exprResols.get(id)!;
}
}
export class Resolver implements ast.Visitor { export class Resolver implements ast.Visitor {
private ribs = Ribs.withRootMod();
private currentFile!: File; private currentFile!: File;
private rootSyms = new RootSyms();
private syms: Syms = this.rootSyms;
private exprResols = new Map<number, Resolve>();
public constructor( public constructor(
private ctx: Ctx, private ctx: Ctx,
private entryFileAst: ast.File, private entryFileAst: ast.File,
) {} ) {}
public resolve() { public resolve(): Resols {
ast.visitFile(this, this.entryFileAst); ast.visitFile(this, this.entryFileAst);
return new Resols(
this.exprResols,
);
} }
visitFile(file: ast.File): ast.VisitRes { visitFile(file: ast.File): ast.VisitRes {
this.currentFile = this.entryFileAst.file; this.currentFile = file.file;
ast.visitStmts(this, file.stmts); ast.visitStmts(this, file.stmts);
this.resolveFnBlocks(); this.visitFnBodies();
} }
visitLetStmt(stmt: ast.Stmt, kind: ast.LetStmt): ast.VisitRes { visitLetStmt(stmt: ast.Stmt, kind: ast.LetStmt): ast.VisitRes {
kind.expr && ast.visitExpr(this, kind.expr);
kind.ty && ast.visitTy(this, kind.ty); kind.ty && ast.visitTy(this, kind.ty);
this.ribs.pushRib({ tag: "normal" }); kind.expr && ast.visitExpr(this, kind.expr);
this.syms = new LocalSyms(this.syms);
ast.visitPat(this, kind.pat); ast.visitPat(this, kind.pat);
return "stop";
} }
visitModBlockItem(item: ast.Item, kind: ast.ModBlockItem): ast.VisitRes { visitModBlockItem(item: ast.Item, kind: ast.ModBlockItem): ast.VisitRes {
const mod: Mod = { todo();
parent: this.ribs.nearestMod(),
items: new Map(),
};
const ribPoint = this.ribs.checkpoint();
ast.visitBlock(this, kind.block);
this.ribs.pushRib({ tag: "mod", mod });
this.ribs.returnToCheckpoint(ribPoint);
this.defineTy(item.ident, this.defMod(item.ident.id, item, mod));
return "stop";
} }
visitModFileItem(item: ast.Item, kind: ast.ModFileItem): ast.VisitRes { visitModFileItem(item: ast.Item, kind: ast.ModFileItem): ast.VisitRes {
const mod: Mod = { ast.visitFile(this, kind.ast!);
parent: this.ribs.nearestMod(), todo();
items: new Map(),
};
const ribPoint = this.ribs.checkpoint();
const fileAst = this.ctx.fileInfo(kind.file!).ast!;
ast.visitFile(this, fileAst);
this.ribs.pushRib({ tag: "mod", mod });
this.ribs.returnToCheckpoint(ribPoint);
this.defineTy(item.ident, this.defMod(item.ident.id, item, mod));
return "stop";
} }
visitEnumItem(item: ast.Item, kind: ast.EnumItem): ast.VisitRes { visitEnumItem(item: ast.Item, kind: ast.EnumItem): ast.VisitRes {
@ -65,29 +72,55 @@ export class Resolver implements ast.Visitor {
todo(); todo();
} }
private fnBlocksToResolve: [ast.Item, ast.FnItem][] = []; private fnBodiesToCheck: [ast.Item, ast.FnItem][] = [];
visitFnItem(item: ast.Item, kind: ast.FnItem): ast.VisitRes { visitFnItem(item: ast.Item, kind: ast.FnItem): ast.VisitRes {
this.defineVal(item.ident, this.defFn(item.ident.id, item, kind)); this.syms.defVal(item.ident, { tag: "fn", item, kind });
this.fnBlocksToResolve.push([item, kind]); this.fnBodiesToCheck.push([item, kind]);
return "stop"; return "stop";
} }
private resolveFnBlocks() { private visitFnBodies() {
for (const [item, kind] of this.fnBlocksToResolve) { for (const [_item, kind] of this.fnBodiesToCheck) {
const ribPoint = this.ribs.checkpoint(); const outerSyms = this.syms;
this.ribs.pushRib({ tag: "fn" }); this.syms = new FnSyms(this.syms);
this.syms = new LocalSyms(this.syms);
for (const param of kind.params) { for (const param of kind.params) {
ast.visitParam(this, param); ast.visitParam(this, param);
} }
ast.visitBlock(this, kind.body!); this.syms = outerSyms;
this.ribs.returnToCheckpoint(ribPoint);
} }
this.fnBlocksToResolve = []; this.fnBodiesToCheck = [];
} }
visitPathExpr(expr: ast.Expr, kind: ast.PathExpr): ast.VisitRes { visitPathExpr(expr: ast.Expr, kind: ast.PathExpr): ast.VisitRes {
todo(); if (kind.path.segments.length === 1) {
const res = this.syms.getVal(kind.path.segments[0].ident);
switch (res.kind.tag) {
case "error":
return "stop";
case "fn":
this.exprResols.set(expr.id, res);
return "stop";
case "local":
this.exprResols.set(expr.id, res);
return "stop";
}
exhausted(res.kind);
}
const pathRes = this.resolveInnerPath(kind.path);
switch (pathRes.kind.tag) {
case "error":
todo();
return "stop";
case "fn":
todo();
return "stop";
case "local":
todo();
return "stop";
}
exhausted(pathRes.kind);
} }
visitUseItem(item: ast.Item, kind: ast.UseItem): ast.VisitRes { visitUseItem(item: ast.Item, kind: ast.UseItem): ast.VisitRes {
@ -99,70 +132,70 @@ export class Resolver implements ast.Visitor {
} }
visitBindPat(pat: ast.Pat, kind: ast.BindPat): ast.VisitRes { visitBindPat(pat: ast.Pat, kind: ast.BindPat): ast.VisitRes {
this.ribs.defVal(kind.ident.id, { tag: "local", id: pat.id }); const res = this.syms.defVal(kind.ident, { tag: "local" });
return "stop"; 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}'`,
});
}
} }
visitPathPat(pat: ast.Pat, kind: ast.PathPat): ast.VisitRes { visitPathPat(pat: ast.Pat, kind: ast.PathPat): ast.VisitRes {
todo(); todo();
return "stop";
} }
visitBlock(block: ast.Block): ast.VisitRes { visitBlock(block: ast.Block): ast.VisitRes {
ast.visitStmts(this, block.stmts); ast.visitStmts(this, block.stmts);
this.visitFnBodies();
block.expr && ast.visitExpr(this, block.expr); block.expr && ast.visitExpr(this, block.expr);
this.resolveFnBlocks();
return "stop";
} }
private defIdCounter = 0; private resolveInnerPath(path: ast.Path): Resolve {
const res = path.segments.slice(1, path.segments.length)
private modDefs = new Map<number, [ast.Item, Mod]>(); .reduce((innerRes, seg) => {
private modDef(id: number): [ast.Item, Mod] { const k = innerRes.kind;
return this.modDefs.get(id)!; switch (k.tag) {
} case "error":
private defMod(_ident: IdentId, item: ast.Item, mod: Mod): Res { return innerRes;
const id = this.defIdCounter++; case "fn":
this.modDefs.set(id, [item, mod]); this.ctx.report({
return { tag: "def", def: { id, type: "mod" } }; severity: "error",
file: this.currentFile,
span: seg.ident.span,
msg: "function, not pathable",
});
return ResolveError(seg.ident);
case "local":
this.ctx.report({
severity: "error",
file: this.currentFile,
span: seg.ident.span,
msg: "local variable, not pathable",
});
return ResolveError(seg.ident);
}
exhausted(k);
}, this.syms.getTy(path.segments[0].ident));
return res;
} }
private fnDefs = new Map<number, [ast.Item, ast.FnItem]>(); // const text = this.ctx.identText(ident.id);
private fnDef(id: number): [ast.Item, ast.FnItem] { // this.ctx.report({
return this.fnDefs.get(id)!; // severity: "error",
} // file: this.currentFile,
private defFn(_ident: IdentId, item: ast.Item, kind: ast.FnItem): Res { // span: ident.span,
const id = this.defIdCounter++; // msg: `redefinition of type '${text}'`,
this.fnDefs.set(id, [item, kind]); // });
return { tag: "def", def: { id, type: "fn" } }; //
} // const text = this.ctx.identText(ident.id);
// this.ctx.report({
private defineTy(ident: ast.Ident, res: Res) { // severity: "error",
if (this.ribs.hasTy(ident.id)) { // file: this.currentFile,
const text = this.ctx.identText(ident.id); // span: ident.span,
this.ctx.report({ // msg: `redefinition of value '${text}'`,
severity: "error", // });
file: this.currentFile,
span: ident.span,
msg: `redefinition of type '${text}'`,
});
return;
}
this.ribs.defTy(ident.id, res);
}
private defineVal(ident: ast.Ident, res: Res) {
if (this.ribs.hasVal(ident.id)) {
console.log(this.ribs);
const text = this.ctx.identText(ident.id);
this.ctx.report({
severity: "error",
file: this.currentFile,
span: ident.span,
msg: `redefinition of value '${text}'`,
});
return;
}
this.ribs.defVal(ident.id, res);
}
} }

24
compiler/ty/to_string.ts Normal file
View File

@ -0,0 +1,24 @@
import { Ctx } from "../ctx.ts";
import { exhausted } from "../util.ts";
import { Ty } from "./ty.ts";
export function tyToString(ctx: Ctx, ty: Ty): string {
const k = ty.kind;
switch (k.tag) {
case "error":
return `<error>`;
case "unknown":
return `<unknown>`;
case "null":
return `null`;
case "fn": {
const identText = ctx.identText(k.item.ident.id);
const params = k.params
.map((param) => tyToString(ctx, param))
.join(", ");
const reTy = tyToString(ctx, k.returnTy);
return `fn ${identText}(${params}) -> ${reTy}`;
}
}
exhausted(k);
}

19
compiler/ty/ty.ts Normal file
View File

@ -0,0 +1,19 @@
import * as ast from "../ast/mod.ts";
export type Ty = {
kind: TyKind;
};
export const Ty = (kind: TyKind): Ty => ({ kind });
export type TyKind =
| { tag: "error" }
| { tag: "unknown" }
| { tag: "null" }
| {
tag: "fn";
item: ast.Item;
kind: ast.FnItem;
params: Ty[];
returnTy: Ty;
};

View File

@ -3,7 +3,7 @@ export function todo<T>(msg?: string): T {
throw new NotImplemented(msg); throw new NotImplemented(msg);
} }
export function exhausted(_: never) { export function exhausted<T>(_: never): T {
class Unexhausted extends Error {} class Unexhausted extends Error {}
throw new Unexhausted(); throw new Unexhausted();
} }