bleh
This commit is contained in:
parent
63d4406551
commit
7455f9d259
@ -1,4 +1,4 @@
|
||||
import { IdentId } from "../ctx.ts";
|
||||
import { File as CtxFile, IdentId } from "../ctx.ts";
|
||||
import { Span } from "../diagnostics.ts";
|
||||
|
||||
export type File = {
|
||||
@ -59,7 +59,7 @@ export type ItemKind =
|
||||
| { tag: "type_alias" } & TypeAliasItem;
|
||||
|
||||
export type ModBlockItem = { block: Block };
|
||||
export type ModFileItem = { filePath: string };
|
||||
export type ModFileItem = { filePath: string; file?: CtxFile };
|
||||
export type EnumItem = { variants: Variant[] };
|
||||
export type StructItem = { data: VariantData };
|
||||
|
||||
@ -67,7 +67,7 @@ export type FnItem = {
|
||||
generics?: Generics;
|
||||
params: Param[];
|
||||
returnTy?: Ty;
|
||||
body: Block;
|
||||
body?: Block;
|
||||
};
|
||||
|
||||
export type UseItem = { _: 0 };
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
Span,
|
||||
} from "./diagnostics.ts";
|
||||
import * as hir from "./middle/hir.ts";
|
||||
import { Mod } from "./middle/res.ts";
|
||||
import { DefKind, Mod, Res } from "./middle/res.ts";
|
||||
|
||||
export class Ctx {
|
||||
private fileIds = new Ids<File>();
|
||||
@ -94,6 +94,16 @@ export class Ctx {
|
||||
return v;
|
||||
}
|
||||
|
||||
private items = new Map<Key<HirId>, hir.Item>();
|
||||
|
||||
/// don't intern the same thing twice
|
||||
public internItem(item: Omit<hir.Item, "id">): hir.Item {
|
||||
const id = this.hirIds.nextThenStep();
|
||||
const v: hir.Item = { id, ...item };
|
||||
this.items.set(idKey(id), v);
|
||||
return v;
|
||||
}
|
||||
|
||||
private exprs = new Map<Key<HirId>, hir.Expr>();
|
||||
|
||||
/// don't intern the same thing twice
|
||||
@ -150,15 +160,17 @@ export class Ctx {
|
||||
return this.defs.get(idKey(id))!;
|
||||
}
|
||||
|
||||
private modDefs = new Map<Key<DefId>, Mod>();
|
||||
private modItemMaps = new Map<Key<DefId>, Map<Key<IdentId>, DefId>>();
|
||||
private mods = new Map<Key<DefId>, Mod>();
|
||||
|
||||
public modDef(id: DefId): Mod {
|
||||
return this.modDefs.get(idKey(id))!;
|
||||
public getMod(id: DefId): Mod {
|
||||
return this.mods.get(idKey(id))!;
|
||||
}
|
||||
|
||||
public mod(id: DefId, ident: IdentId): DefId | undefined {
|
||||
return this.modItemMaps.get(idKey(id))!.get(idKey(ident));
|
||||
public internMod(mod: Omit<Mod, "id">): Mod {
|
||||
const id = this.defIds.nextThenStep();
|
||||
const v: Mod = { id, ...mod };
|
||||
this.mods.set(idKey(id), mod);
|
||||
return v;
|
||||
}
|
||||
|
||||
//
|
||||
@ -219,6 +231,15 @@ export type FileInfo = {
|
||||
ast?: ast.File;
|
||||
};
|
||||
|
||||
export type Mod = {
|
||||
id: DefId;
|
||||
parent?: Mod;
|
||||
defKind: DefKind;
|
||||
ident: IdentId;
|
||||
items: Set<Key<DefId>>;
|
||||
defs: Map<Key<IdentId>, Res>;
|
||||
};
|
||||
|
||||
export type IdentId = IdBase & { readonly _: unique symbol };
|
||||
export type HirId = IdBase & { readonly _: unique symbol };
|
||||
export type DefId = IdBase & { readonly _: unique symbol };
|
||||
|
@ -72,7 +72,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
|
||||
);
|
||||
}
|
||||
|
||||
public async collect(): Promise<void> {
|
||||
public async collect(): Promise<File> {
|
||||
const text = await Deno.readTextFile(this.absPath);
|
||||
const file = this.ctx.addFile(
|
||||
this.ident,
|
||||
@ -85,6 +85,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
|
||||
this.ctx.addFileAst(file, fileAst);
|
||||
ast.visitFile(this, fileAst, { file });
|
||||
await this.subFilePromise;
|
||||
return file;
|
||||
}
|
||||
|
||||
visitModFileItem(
|
||||
@ -96,7 +97,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
|
||||
const { filePath: relPath } = kind;
|
||||
const absPath = path.join(path.dirname(this.absPath), relPath);
|
||||
this.subFilePromise = this.subFilePromise
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
if (this.ctx.fileHasChildWithIdent(file, ident)) {
|
||||
this.ctx.report({
|
||||
severity: "fatal",
|
||||
@ -106,7 +107,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
|
||||
});
|
||||
Deno.exit(1);
|
||||
}
|
||||
return new FileTreeAstCollector(
|
||||
const modFile = await new FileTreeAstCollector(
|
||||
this.ctx,
|
||||
file,
|
||||
ident,
|
||||
@ -114,6 +115,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
|
||||
relPath,
|
||||
)
|
||||
.collect();
|
||||
kind.file = modFile;
|
||||
});
|
||||
return "stop";
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { HirId, IdentId } from "../ctx.ts";
|
||||
import { Span } from "../diagnostics.ts";
|
||||
import { Res } from "./res.ts";
|
||||
import { Mod, Res } from "./res.ts";
|
||||
|
||||
export type Stmt = {
|
||||
id: HirId;
|
||||
@ -40,6 +40,7 @@ export type AssignType = "=" | "+=" | "-=";
|
||||
export type ExprStmt = { expr: Expr };
|
||||
|
||||
export type Item = {
|
||||
id: HirId;
|
||||
kind: ItemKind;
|
||||
span: Span;
|
||||
ident: Ident;
|
||||
@ -48,16 +49,14 @@ export type Item = {
|
||||
|
||||
export type ItemKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "mod_block" } & ModBlockItem
|
||||
| { tag: "mod_file" } & ModFileItem
|
||||
| { tag: "mod" } & ModItem
|
||||
| { tag: "enum" } & EnumItem
|
||||
| { tag: "struct" } & StructItem
|
||||
| { tag: "fn" } & FnItem
|
||||
| { tag: "use" } & UseItem
|
||||
| { tag: "type_alias" } & TypeAliasItem;
|
||||
|
||||
export type ModBlockItem = { block: Block };
|
||||
export type ModFileItem = { filePath: string };
|
||||
export type ModItem = { mod: Mod };
|
||||
export type EnumItem = { variants: Variant[] };
|
||||
export type StructItem = { data: VariantData };
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Ctx, DefId, IdentId } from "../ctx.ts";
|
||||
import { Ctx, DefId, File, IdentId, idKey, Mod } from "../ctx.ts";
|
||||
import * as ast from "../ast/ast.ts";
|
||||
import {
|
||||
Block,
|
||||
@ -13,11 +13,14 @@ import {
|
||||
Ty,
|
||||
} from "./hir.ts";
|
||||
import { exhausted, Res as Result, todo } from "../util.ts";
|
||||
import { Rib } from "./rib.ts";
|
||||
import { Rib, RibKind } from "./rib.ts";
|
||||
import { Res } from "./res.ts";
|
||||
|
||||
export class AstLowerer {
|
||||
private ribs: Rib[] = [];
|
||||
private tyRibs: Rib[] = [];
|
||||
private valRibs: Rib[] = [];
|
||||
private currentFile!: File;
|
||||
private currentMod!: Mod;
|
||||
|
||||
public constructor(
|
||||
private ctx: Ctx,
|
||||
@ -25,6 +28,13 @@ export class AstLowerer {
|
||||
|
||||
public lower() {
|
||||
const file = this.ctx.entryFile();
|
||||
this.currentFile = file;
|
||||
this.currentMod = this.ctx.internMod({
|
||||
defKind: { tag: "mod" },
|
||||
ident: this.ctx.internIdent("root"),
|
||||
items: new Set(),
|
||||
defs: new Map(),
|
||||
});
|
||||
const ast = this.ctx.fileInfo(file).ast!;
|
||||
this.lowerFile(ast);
|
||||
}
|
||||
@ -83,13 +93,87 @@ export class AstLowerer {
|
||||
private lowerLetStmt(stmt: ast.Stmt, kind: ast.LetStmt): Stmt {
|
||||
const expr = kind.expr && this.lowerExpr(kind.expr);
|
||||
const ty = kind.ty && this.lowerTy(kind.ty);
|
||||
this.pushRib({ kind: { tag: "normal" }, bindings: new Map() });
|
||||
this.pushRib({ tag: "normal" });
|
||||
const pat = this.lowerPat(kind.pat);
|
||||
return this.ctx.internStmt({ tag: "let", pat, ty, expr }, stmt.span);
|
||||
}
|
||||
|
||||
private lowerItem(item: ast.Item): Item {
|
||||
return todo();
|
||||
const { ident, kind, pub, span } = item;
|
||||
switch (kind.tag) {
|
||||
case "error":
|
||||
return this.ctx.internItem({ ident, kind, pub, span });
|
||||
case "mod_block": {
|
||||
const parent = this.currentMod;
|
||||
const mod = this.currentMod = this.ctx.internMod({
|
||||
parent,
|
||||
ident: ident.id,
|
||||
defKind: { tag: "mod" },
|
||||
items: new Set(),
|
||||
defs: new Map(),
|
||||
});
|
||||
const point = this.ribPoint();
|
||||
this.pushRib({ tag: "mod", mod });
|
||||
const _block = this.lowerBlock(kind.block);
|
||||
this.returnToRibPoint(point);
|
||||
this.currentMod = parent;
|
||||
return this.ctx.internItem({
|
||||
ident,
|
||||
kind: { tag: "mod", mod },
|
||||
pub,
|
||||
span,
|
||||
});
|
||||
}
|
||||
case "mod_file": {
|
||||
const parent = this.currentMod;
|
||||
const mod = this.currentMod = this.ctx.internMod({
|
||||
parent,
|
||||
ident: ident.id,
|
||||
defKind: { tag: "mod" },
|
||||
items: new Set(),
|
||||
defs: new Map(),
|
||||
});
|
||||
const point = this.ribPoint();
|
||||
this.pushRib({ tag: "mod", mod });
|
||||
const parentFile = this.currentFile;
|
||||
const fileInfo = this.ctx.fileInfo(kind.file!);
|
||||
this.lowerFile(fileInfo.ast!);
|
||||
this.returnToRibPoint(point);
|
||||
this.currentFile = parentFile;
|
||||
this.currentMod = parent;
|
||||
if (this.tyRib().bindings.has(idKey(ident.id))) {
|
||||
throw new Error();
|
||||
}
|
||||
this.tyRib().bindings.set(idKey(ident.id), {
|
||||
tag: "def",
|
||||
id: mod.id,
|
||||
kind: { tag: "mod" },
|
||||
});
|
||||
return this.ctx.internItem({
|
||||
ident,
|
||||
kind: { tag: "mod", mod },
|
||||
pub,
|
||||
span,
|
||||
});
|
||||
}
|
||||
case "enum":
|
||||
return todo();
|
||||
case "struct":
|
||||
return todo();
|
||||
case "fn": {
|
||||
return this.ctx.internItem({
|
||||
ident,
|
||||
kind: { ...todo() },
|
||||
pub,
|
||||
span,
|
||||
});
|
||||
}
|
||||
case "use":
|
||||
return todo();
|
||||
case "type_alias":
|
||||
return todo();
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
private lowerExpr(expr: ast.Expr): Expr {
|
||||
@ -221,7 +305,7 @@ export class AstLowerer {
|
||||
return this.ctx.internPat(kind, span);
|
||||
case "bind": {
|
||||
const v = this.ctx.internPat(kind, span);
|
||||
this.rib().bindings.set(kind.ident.id, {
|
||||
this.valRib().bindings.set(idKey(kind.ident.id), {
|
||||
tag: "local",
|
||||
id: v.id,
|
||||
});
|
||||
@ -293,10 +377,7 @@ export class AstLowerer {
|
||||
|
||||
private lowerBlock(block: ast.Block): Block {
|
||||
const point = this.ribPoint();
|
||||
this.pushRib({
|
||||
kind: { tag: "mod", mod: { kind: { tag: "block" } } },
|
||||
bindings: new Map(),
|
||||
});
|
||||
this.pushRib({ tag: "block" });
|
||||
const stmts = block.stmts.map((stmt) => this.lowerStmt(stmt));
|
||||
const expr = block.expr && this.lowerExpr(block.expr);
|
||||
this.returnToRibPoint(point);
|
||||
@ -356,27 +437,60 @@ export class AstLowerer {
|
||||
span: seg.span,
|
||||
}]];
|
||||
case "def": {
|
||||
const error = (): [
|
||||
Res,
|
||||
PathSegment[],
|
||||
] => [{ tag: "error" }, [...resSegs, {
|
||||
ident: seg.ident,
|
||||
res: innerRes,
|
||||
inferArgs: false,
|
||||
span: seg.span,
|
||||
}]];
|
||||
|
||||
const irk = innerRes.kind;
|
||||
switch (irk.tag) {
|
||||
case "mod": {
|
||||
const mod = this.ctx.modDef(innerRes.id);
|
||||
const def = this.ctx.modItem();
|
||||
return todo();
|
||||
const mod = this.ctx.getMod(innerRes.id);
|
||||
const res = mod.defs.get(seg.ident.id);
|
||||
if (!res) {
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
msg: `module does not contain definition for '${
|
||||
this.ctx.identText(seg.ident.id)
|
||||
}'`,
|
||||
span: seg.span,
|
||||
});
|
||||
return error();
|
||||
}
|
||||
return [res, [...resSegs, {
|
||||
ident: seg.ident,
|
||||
res: innerRes,
|
||||
inferArgs: false,
|
||||
span: seg.span,
|
||||
}]];
|
||||
}
|
||||
case "struct":
|
||||
return todo();
|
||||
case "enum":
|
||||
return todo();
|
||||
case "variant":
|
||||
case "ty_alias":
|
||||
return todo();
|
||||
case "fn":
|
||||
return todo();
|
||||
case "ctor":
|
||||
case "ty_param":
|
||||
return todo();
|
||||
case "use":
|
||||
return todo();
|
||||
case "fn":
|
||||
case "variant":
|
||||
case "ctor":
|
||||
case "field":
|
||||
return todo();
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
msg: `${irk.tag} contains zero members`,
|
||||
span: seg.span,
|
||||
});
|
||||
return error();
|
||||
}
|
||||
exhausted(irk);
|
||||
throw new Error();
|
||||
@ -388,28 +502,136 @@ export class AstLowerer {
|
||||
}
|
||||
|
||||
private resolveTyIdent(ident: Ident): Res {
|
||||
return this.findTyRibIdent(this.tyRibs.length - 1, ident);
|
||||
}
|
||||
|
||||
private findTyRibIdent(ribIdx: number, ident: Ident): Res {
|
||||
const rib = this.tyRibs[ribIdx];
|
||||
if (rib.bindings.has(idKey(ident.id))) {
|
||||
return rib.bindings.get(idKey(ident.id))!;
|
||||
}
|
||||
if (ribIdx === 0) {
|
||||
const text = this.ctx.identText(ident.id);
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
span: ident.span,
|
||||
msg: `no type with name '${text}' in module`,
|
||||
});
|
||||
return { tag: "error" };
|
||||
}
|
||||
const res = this.findTyRibIdent(ribIdx - 1, ident);
|
||||
const kind = rib.kind;
|
||||
switch (kind.tag) {
|
||||
case "normal":
|
||||
return res;
|
||||
case "fn":
|
||||
return res;
|
||||
case "item":
|
||||
if (res.tag === "local") {
|
||||
const text = this.ctx.identText(ident.id);
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
span: ident.span,
|
||||
msg: `cannot use local '${text}' here`,
|
||||
});
|
||||
return { tag: "error" };
|
||||
}
|
||||
return res;
|
||||
case "mod": {
|
||||
const text = this.ctx.identText(ident.id);
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
span: ident.span,
|
||||
msg: `no type with name '${text}' in module`,
|
||||
});
|
||||
return { tag: "error" };
|
||||
}
|
||||
case "block":
|
||||
return res;
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
private resolveValIdent(ident: Ident): Res {
|
||||
return this.findValRibIdent(this.valRibs.length - 1, ident);
|
||||
}
|
||||
|
||||
private rib(): Rib {
|
||||
return this.ribs.at(-1)!;
|
||||
private findValRibIdent(ribIdx: number, ident: Ident): Res {
|
||||
const rib = this.valRibs[ribIdx];
|
||||
if (rib.bindings.has(idKey(ident.id))) {
|
||||
return rib.bindings.get(idKey(ident.id))!;
|
||||
}
|
||||
if (ribIdx === 0) {
|
||||
const text = this.ctx.identText(ident.id);
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
span: ident.span,
|
||||
msg: `no value with name '${text}' in module`,
|
||||
});
|
||||
return { tag: "error" };
|
||||
}
|
||||
const res = this.findValRibIdent(ribIdx - 1, ident);
|
||||
const kind = rib.kind;
|
||||
switch (kind.tag) {
|
||||
case "normal":
|
||||
return res;
|
||||
case "fn":
|
||||
return res;
|
||||
case "item":
|
||||
if (res.tag === "local") {
|
||||
const text = this.ctx.identText(ident.id);
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
span: ident.span,
|
||||
msg: `cannot use local '${text}' here`,
|
||||
});
|
||||
return { tag: "error" };
|
||||
}
|
||||
return res;
|
||||
case "mod": {
|
||||
const text = this.ctx.identText(ident.id);
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
span: ident.span,
|
||||
msg: `no value with name '${text}' in module`,
|
||||
});
|
||||
return { tag: "error" };
|
||||
}
|
||||
case "block":
|
||||
return res;
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
private tyRib(): Rib {
|
||||
return this.tyRibs.at(-1)!;
|
||||
}
|
||||
|
||||
private pushRib(rib: Rib) {
|
||||
this.ribs.push(rib);
|
||||
private valRib(): Rib {
|
||||
return this.valRibs.at(-1)!;
|
||||
}
|
||||
|
||||
private pushRib(kind: RibKind) {
|
||||
this.tyRibs.push({ kind, bindings: new Map() });
|
||||
this.valRibs.push({ kind, bindings: new Map() });
|
||||
}
|
||||
|
||||
private popRib() {
|
||||
this.ribs.pop();
|
||||
this.tyRibs.pop();
|
||||
this.valRibs.pop();
|
||||
}
|
||||
|
||||
private ribPoint(): number {
|
||||
return this.ribs.length;
|
||||
return this.valRibs.length;
|
||||
}
|
||||
|
||||
private returnToRibPoint(point: number) {
|
||||
this.ribs = this.ribs.slice(0, point);
|
||||
this.tyRibs = this.tyRibs.slice(0, point);
|
||||
this.valRibs = this.valRibs.slice(0, point);
|
||||
}
|
||||
}
|
||||
|
20
compiler/middle/res.ts
Normal file
20
compiler/middle/res.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { DefId, HirId } from "../ctx.ts";
|
||||
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
|
||||
export type Res =
|
||||
| { tag: "error" }
|
||||
| { tag: "def"; kind: DefKind; id: DefId }
|
||||
| { tag: "local"; id: HirId };
|
||||
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.DefKind.html
|
||||
export type DefKind =
|
||||
| { tag: "mod" }
|
||||
| { tag: "struct" }
|
||||
| { tag: "enum" }
|
||||
| { tag: "variant" }
|
||||
| { tag: "ty_alias" }
|
||||
| { tag: "ty_param" }
|
||||
| { tag: "fn" }
|
||||
| { tag: "ctor" }
|
||||
| { tag: "use" }
|
||||
| { tag: "field" };
|
@ -1,10 +1,10 @@
|
||||
import { IdentId } from "../ctx.ts";
|
||||
import { DefKind, Mod, Res } from "./res.ts";
|
||||
import { IdentId, Key, Mod } from "../ctx.ts";
|
||||
import { DefKind, Res } from "./res.ts";
|
||||
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html
|
||||
export type Rib = {
|
||||
kind: RibKind;
|
||||
bindings: Map<IdentId, Res>;
|
||||
bindings: Map<Key<IdentId>, Res>;
|
||||
};
|
||||
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
|
||||
|
Loading…
Reference in New Issue
Block a user