delete middle
This commit is contained in:
parent
7455f9d259
commit
19efd900fd
@ -1,277 +0,0 @@
|
||||
import { HirId, IdentId } from "../ctx.ts";
|
||||
import { Span } from "../diagnostics.ts";
|
||||
import { Mod, Res } from "./res.ts";
|
||||
|
||||
export type Stmt = {
|
||||
id: HirId;
|
||||
kind: StmtKind;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type StmtKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "item" } & ItemStmt
|
||||
| { tag: "let" } & LetStmt
|
||||
| { tag: "return" } & ReturnStmt
|
||||
| { tag: "break" } & BreakStmt
|
||||
| { tag: "continue" }
|
||||
| { tag: "assign" } & AssignStmt
|
||||
| { tag: "expr" } & ExprStmt;
|
||||
|
||||
export type ItemStmt = { item: Item };
|
||||
|
||||
export type LetStmt = {
|
||||
pat: Pat;
|
||||
ty?: Ty;
|
||||
expr?: Expr;
|
||||
};
|
||||
|
||||
export type ReturnStmt = { expr?: Expr };
|
||||
export type BreakStmt = { expr?: Expr };
|
||||
|
||||
export type AssignStmt = {
|
||||
assignType: AssignType;
|
||||
subject: Expr;
|
||||
value: Expr;
|
||||
};
|
||||
|
||||
export type AssignType = "=" | "+=" | "-=";
|
||||
|
||||
export type ExprStmt = { expr: Expr };
|
||||
|
||||
export type Item = {
|
||||
id: HirId;
|
||||
kind: ItemKind;
|
||||
span: Span;
|
||||
ident: Ident;
|
||||
pub: boolean;
|
||||
};
|
||||
|
||||
export type ItemKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "mod" } & ModItem
|
||||
| { tag: "enum" } & EnumItem
|
||||
| { tag: "struct" } & StructItem
|
||||
| { tag: "fn" } & FnItem
|
||||
| { tag: "use" } & UseItem
|
||||
| { tag: "type_alias" } & TypeAliasItem;
|
||||
|
||||
export type ModItem = { mod: Mod };
|
||||
export type EnumItem = { variants: Variant[] };
|
||||
export type StructItem = { data: VariantData };
|
||||
|
||||
export type FnItem = {
|
||||
generics?: Generics;
|
||||
params: Param[];
|
||||
returnTy?: Ty;
|
||||
body: Block;
|
||||
};
|
||||
|
||||
export type UseItem = { _: 0 };
|
||||
export type TypeAliasItem = { ty: Ty };
|
||||
|
||||
export type Variant = {
|
||||
ident: Ident;
|
||||
data: VariantData;
|
||||
pub: boolean;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type VariantData = {
|
||||
kind: VariantDataKind;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type VariantDataKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "unit" }
|
||||
| { tag: "tuple" } & TupleVariantData
|
||||
| { tag: "struct" } & StructVariantData;
|
||||
|
||||
export type TupleVariantData = { elems: VariantData[] };
|
||||
export type StructVariantData = { fields: FieldDef[] };
|
||||
|
||||
export type FieldDef = {
|
||||
ident: Ident;
|
||||
ty: Ty;
|
||||
pub: boolean;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Param = {
|
||||
pat: Pat;
|
||||
ty: Ty;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Generics = {
|
||||
params: GenericParam[];
|
||||
};
|
||||
|
||||
export type GenericParam = {
|
||||
ident: Ident;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Expr = {
|
||||
id: HirId;
|
||||
kind: ExprKind;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type ExprKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "path" } & PathExpr
|
||||
| { tag: "null" }
|
||||
| { tag: "int" } & IntExpr
|
||||
| { tag: "bool" } & BoolExpr
|
||||
| { tag: "str" } & StringExpr
|
||||
| { tag: "group" } & GroupExpr
|
||||
| { tag: "array" } & ArrayExpr
|
||||
| { tag: "repeat" } & RepeatExpr
|
||||
| { tag: "struct" } & StructExpr
|
||||
| { tag: "ref" } & RefExpr
|
||||
| { tag: "deref" } & DerefExpr
|
||||
| { tag: "elem" } & ElemExpr
|
||||
| { tag: "field" } & FieldExpr
|
||||
| { tag: "index" } & IndexExpr
|
||||
| { tag: "call" } & CallExpr
|
||||
| { tag: "unary" } & UnaryExpr
|
||||
| { tag: "binary" } & BinaryExpr
|
||||
| { tag: "block" } & BlockExpr
|
||||
| { tag: "if" } & IfExpr
|
||||
| { tag: "loop" } & LoopExpr
|
||||
| { tag: "while" } & WhileExpr
|
||||
| { tag: "for" } & ForExpr
|
||||
| { tag: "c_for" } & CForExpr;
|
||||
|
||||
export type PathExpr = { path: QPath };
|
||||
export type IntExpr = { value: number };
|
||||
export type BoolExpr = { value: boolean };
|
||||
export type StringExpr = { value: string };
|
||||
export type GroupExpr = { expr: Expr };
|
||||
export type ArrayExpr = { exprs: Expr[] };
|
||||
export type RepeatExpr = { expr: Expr; length: Expr };
|
||||
export type StructExpr = { path?: QPath; fields: ExprField[] };
|
||||
export type RefExpr = { expr: Expr; refType: RefType; mut: boolean };
|
||||
export type DerefExpr = { expr: Expr };
|
||||
export type ElemExpr = { expr: Expr; elem: number };
|
||||
export type FieldExpr = { expr: Expr; ident: Ident };
|
||||
export type IndexExpr = { expr: Expr; index: Expr };
|
||||
export type CallExpr = { expr: Expr; args: Expr[] };
|
||||
export type UnaryExpr = { unaryType: UnaryType; expr: Expr };
|
||||
export type BinaryExpr = {
|
||||
binaryType: BinaryType;
|
||||
left: Expr;
|
||||
right: Expr;
|
||||
};
|
||||
export type BlockExpr = { block: Block };
|
||||
export type IfExpr = { cond: Expr; truthy: Block; falsy?: Expr };
|
||||
export type LoopExpr = { body: Block };
|
||||
export type WhileExpr = { cond: Expr; body: Block };
|
||||
export type ForExpr = { pat: Pat; expr: Expr; body: Block };
|
||||
export type CForExpr = {
|
||||
decl?: Stmt;
|
||||
cond?: Expr;
|
||||
incr?: Stmt;
|
||||
body: Block;
|
||||
};
|
||||
|
||||
export type RefType = "ref" | "ptr";
|
||||
export type UnaryType = "not" | "-";
|
||||
export type BinaryType =
|
||||
| "+"
|
||||
| "*"
|
||||
| "=="
|
||||
| "-"
|
||||
| "/"
|
||||
| "!="
|
||||
| "<"
|
||||
| ">"
|
||||
| "<="
|
||||
| ">="
|
||||
| "or"
|
||||
| "and";
|
||||
|
||||
export type ExprField = {
|
||||
ident: Ident;
|
||||
expr: Expr;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Pat = {
|
||||
id: HirId;
|
||||
kind: PatKind;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type PatKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "bind" } & BindPat
|
||||
| { tag: "path" } & PathPat;
|
||||
|
||||
export type BindPat = { ident: Ident; mut: boolean };
|
||||
export type PathPat = { path: QPath };
|
||||
|
||||
export type Ty = {
|
||||
id: HirId;
|
||||
kind: TyKind;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type TyKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "null" }
|
||||
| { tag: "int" }
|
||||
| { tag: "bool" }
|
||||
| { tag: "str" }
|
||||
| { tag: "path" } & PathTy
|
||||
| { tag: "ref" } & RefTy
|
||||
| { tag: "ptr" } & PtrTy
|
||||
| { tag: "slice" } & SliceTy
|
||||
| { tag: "array" } & ArrayTy
|
||||
| { tag: "anon_struct" } & AnonStructTy;
|
||||
|
||||
export type PathTy = { path: QPath };
|
||||
export type RefTy = { ty: Ty; mut: boolean };
|
||||
export type PtrTy = { ty: Ty; mut: boolean };
|
||||
export type SliceTy = { ty: Ty };
|
||||
export type ArrayTy = { ty: Ty; length: Expr };
|
||||
export type TupleTy = { elems: Ty[] };
|
||||
export type AnonStructTy = { fields: AnonFieldDef[] };
|
||||
|
||||
export type AnonFieldDef = {
|
||||
ident: Ident;
|
||||
ty: Ty;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Block = {
|
||||
id: HirId;
|
||||
stmts: Stmt[];
|
||||
expr?: Expr;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type QPath =
|
||||
| { tag: "resolved"; path: Path }
|
||||
| { tag: "type_relative"; ty: Ty; seg: PathSegment };
|
||||
|
||||
export type Path = {
|
||||
segments: PathSegment[];
|
||||
res: Res;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type PathSegment = {
|
||||
ident: Ident;
|
||||
res: Res;
|
||||
genericArgs?: Ty[];
|
||||
inferArgs: boolean;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Ident = {
|
||||
id: IdentId;
|
||||
span: Span;
|
||||
};
|
@ -1,80 +0,0 @@
|
||||
import { arrayEq, exhausted } from "../util.ts";
|
||||
import { Ident, Item, Stmt, VariantData } from "./hir.ts";
|
||||
|
||||
/// Shallow equality
|
||||
export function stmtEq(a: Stmt, b: Stmt): boolean {
|
||||
const [ak, bk] = [a.kind, b.kind];
|
||||
switch (ak.tag) {
|
||||
case "error":
|
||||
return ak.tag === bk.tag;
|
||||
case "item":
|
||||
return ak.tag === bk.tag && ak.item === bk.item;
|
||||
case "let":
|
||||
return ak.tag === bk.tag && ak.pat === bk.pat && ak.ty === bk.ty &&
|
||||
ak.expr === bk.expr;
|
||||
case "return":
|
||||
return ak.tag === bk.tag && ak.expr === bk.expr;
|
||||
case "break":
|
||||
return ak.tag === bk.tag && ak.expr === bk.expr;
|
||||
case "continue":
|
||||
return ak.tag === bk.tag;
|
||||
case "assign":
|
||||
return ak.tag === bk.tag && ak.assignType === bk.assignType &&
|
||||
ak.subject === bk.subject && ak.value === bk.value;
|
||||
case "expr":
|
||||
return ak.tag === bk.tag && ak.expr === bk.expr;
|
||||
}
|
||||
exhausted(ak);
|
||||
}
|
||||
|
||||
/// Shallow equality
|
||||
export function itemEq(a: Item, b: Item): boolean {
|
||||
const [ak, bk] = [a.kind, b.kind];
|
||||
switch (ak.tag) {
|
||||
case "error":
|
||||
return ak.tag === bk.tag;
|
||||
case "mod_block":
|
||||
return ak.tag === bk.tag && ak.block === bk.block;
|
||||
case "mod_file":
|
||||
return ak.tag === bk.tag && ak.filePath === bk.filePath;
|
||||
case "enum":
|
||||
return ak.tag === bk.tag &&
|
||||
arrayEq(ak.variants, bk.variants);
|
||||
case "struct":
|
||||
return ak.tag === bk.tag && variantDataEq(ak.data, bk.data);
|
||||
case "fn":
|
||||
return ak.tag === bk.tag;
|
||||
case "use":
|
||||
return ak.tag === bk.tag;
|
||||
case "type_alias":
|
||||
return ak.tag === bk.tag;
|
||||
}
|
||||
exhausted(ak);
|
||||
}
|
||||
|
||||
export function variantDataEq(a: VariantData, b: VariantData): boolean {
|
||||
const [ak, bk] = [a.kind, b.kind];
|
||||
switch (ak.tag) {
|
||||
case "error":
|
||||
return ak.tag === bk.tag;
|
||||
case "unit":
|
||||
return ak.tag === bk.tag;
|
||||
case "tuple":
|
||||
return ak.tag === bk.tag &&
|
||||
arrayEq(ak.elems, bk.elems, variantDataEq);
|
||||
case "struct":
|
||||
return ak.tag === bk.tag &&
|
||||
arrayEq(
|
||||
ak.fields,
|
||||
bk.fields,
|
||||
(a, b) =>
|
||||
identEq(a.ident, b.ident) && a.ty === b.ty &&
|
||||
a.pub === b.pub && a.span === b.span,
|
||||
);
|
||||
}
|
||||
exhausted(ak);
|
||||
}
|
||||
|
||||
export function identEq(a: Ident, b: Ident): boolean {
|
||||
return a.id === b.id;
|
||||
}
|
@ -1,637 +0,0 @@
|
||||
import { Ctx, DefId, File, IdentId, idKey, Mod } from "../ctx.ts";
|
||||
import * as ast from "../ast/ast.ts";
|
||||
import {
|
||||
Block,
|
||||
Expr,
|
||||
Ident,
|
||||
Item,
|
||||
Pat,
|
||||
Path,
|
||||
PathSegment,
|
||||
QPath,
|
||||
Stmt,
|
||||
Ty,
|
||||
} from "./hir.ts";
|
||||
import { exhausted, Res as Result, todo } from "../util.ts";
|
||||
import { Rib, RibKind } from "./rib.ts";
|
||||
import { Res } from "./res.ts";
|
||||
|
||||
export class AstLowerer {
|
||||
private tyRibs: Rib[] = [];
|
||||
private valRibs: Rib[] = [];
|
||||
private currentFile!: File;
|
||||
private currentMod!: Mod;
|
||||
|
||||
public constructor(
|
||||
private ctx: Ctx,
|
||||
) {}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private lowerFile(file: ast.File) {
|
||||
this.lowerStmts(file.stmts);
|
||||
}
|
||||
|
||||
private lowerStmts(stmts: ast.Stmt[]): Stmt[] {
|
||||
return stmts.map((stmt) => this.lowerStmt(stmt));
|
||||
}
|
||||
|
||||
private lowerStmt(stmt: ast.Stmt): Stmt {
|
||||
const span = stmt.span;
|
||||
const kind = stmt.kind;
|
||||
switch (kind.tag) {
|
||||
case "error":
|
||||
return this.ctx.internStmt(kind, span);
|
||||
case "item":
|
||||
return this.ctx.internStmt({
|
||||
tag: "item",
|
||||
item: this.lowerItem(kind.item),
|
||||
}, span);
|
||||
case "let":
|
||||
return this.lowerLetStmt(stmt, kind);
|
||||
case "return":
|
||||
return this.ctx.internStmt({
|
||||
tag: "return",
|
||||
expr: kind.expr && this.lowerExpr(kind.expr),
|
||||
}, span);
|
||||
case "break":
|
||||
return this.ctx.internStmt({
|
||||
tag: "break",
|
||||
expr: kind.expr && this.lowerExpr(kind.expr),
|
||||
}, span);
|
||||
case "continue":
|
||||
return this.ctx.internStmt({
|
||||
tag: "continue",
|
||||
}, span);
|
||||
case "assign":
|
||||
return this.ctx.internStmt({
|
||||
tag: "assign",
|
||||
assignType: kind.assignType,
|
||||
subject: this.lowerExpr(kind.subject),
|
||||
value: this.lowerExpr(kind.value),
|
||||
}, span);
|
||||
case "expr":
|
||||
return this.ctx.internStmt({
|
||||
tag: "expr",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
}, span);
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
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({ 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 {
|
||||
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 {
|
||||
const span = expr.span;
|
||||
const kind = expr.kind;
|
||||
switch (kind.tag) {
|
||||
case "error":
|
||||
return this.ctx.internExpr(kind, span);
|
||||
case "path":
|
||||
return this.ctx.internExpr({
|
||||
tag: "path",
|
||||
path: this.lowerPath(kind.path, kind.qty),
|
||||
}, span);
|
||||
case "null":
|
||||
return this.ctx.internExpr(kind, span);
|
||||
case "int":
|
||||
return this.ctx.internExpr(kind, span);
|
||||
case "bool":
|
||||
return this.ctx.internExpr(kind, span);
|
||||
case "str":
|
||||
return this.ctx.internExpr(kind, span);
|
||||
case "group":
|
||||
return this.ctx.internExpr({
|
||||
tag: "group",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
}, span);
|
||||
case "array":
|
||||
return this.ctx.internExpr({
|
||||
tag: "array",
|
||||
exprs: kind.exprs.map((expr) => this.lowerExpr(expr)),
|
||||
}, span);
|
||||
case "repeat":
|
||||
return this.ctx.internExpr({
|
||||
tag: "repeat",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
length: this.lowerExpr(kind.length),
|
||||
}, span);
|
||||
case "struct":
|
||||
return this.ctx.internExpr({
|
||||
tag: "struct",
|
||||
path: kind.path && this.lowerPath(kind.path),
|
||||
fields: kind.fields.map(({ ident, expr, span }) => ({
|
||||
ident,
|
||||
expr: this.lowerExpr(expr),
|
||||
span,
|
||||
})),
|
||||
}, span);
|
||||
case "ref":
|
||||
return this.ctx.internExpr({
|
||||
tag: "ref",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
refType: kind.refType,
|
||||
mut: kind.mut,
|
||||
}, span);
|
||||
case "deref":
|
||||
return this.ctx.internExpr({
|
||||
tag: "deref",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
}, span);
|
||||
case "elem":
|
||||
return this.ctx.internExpr({
|
||||
tag: "elem",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
elem: kind.elem,
|
||||
}, span);
|
||||
case "field":
|
||||
return this.ctx.internExpr({
|
||||
tag: "field",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
ident: kind.ident,
|
||||
}, span);
|
||||
case "index":
|
||||
return this.ctx.internExpr({
|
||||
tag: "index",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
index: this.lowerExpr(kind.index),
|
||||
}, span);
|
||||
case "call":
|
||||
return this.ctx.internExpr({
|
||||
tag: "call",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
args: kind.args.map((arg) => this.lowerExpr(arg)),
|
||||
}, span);
|
||||
case "unary":
|
||||
return this.ctx.internExpr({
|
||||
tag: "unary",
|
||||
expr: this.lowerExpr(kind.expr),
|
||||
unaryType: kind.unaryType,
|
||||
}, span);
|
||||
case "binary":
|
||||
return this.ctx.internExpr({
|
||||
tag: "binary",
|
||||
left: this.lowerExpr(kind.left),
|
||||
right: this.lowerExpr(kind.right),
|
||||
binaryType: kind.binaryType,
|
||||
}, span);
|
||||
case "block":
|
||||
return this.ctx.internExpr({
|
||||
tag: "block",
|
||||
block: this.lowerBlock(kind.block),
|
||||
}, span);
|
||||
case "if":
|
||||
return this.ctx.internExpr({
|
||||
tag: "if",
|
||||
cond: this.lowerExpr(kind.cond),
|
||||
truthy: this.lowerBlock(kind.truthy),
|
||||
falsy: kind.falsy && this.lowerExpr(kind.falsy),
|
||||
}, span);
|
||||
case "loop":
|
||||
return this.ctx.internExpr({
|
||||
tag: "loop",
|
||||
body: this.lowerBlock(kind.body),
|
||||
}, span);
|
||||
case "while":
|
||||
throw new Error("not implemented");
|
||||
case "for":
|
||||
throw new Error("not implemented");
|
||||
case "c_for":
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
private lowerPat(pat: ast.Pat): Pat {
|
||||
const span = pat.span;
|
||||
const kind = pat.kind;
|
||||
switch (kind.tag) {
|
||||
case "error":
|
||||
return this.ctx.internPat(kind, span);
|
||||
case "bind": {
|
||||
const v = this.ctx.internPat(kind, span);
|
||||
this.valRib().bindings.set(idKey(kind.ident.id), {
|
||||
tag: "local",
|
||||
id: v.id,
|
||||
});
|
||||
return v;
|
||||
}
|
||||
case "path":
|
||||
return this.ctx.internPat({
|
||||
tag: "path",
|
||||
path: this.lowerPath(kind.path, kind.qty),
|
||||
}, span);
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
private lowerTy(ty: ast.Ty): Ty {
|
||||
const span = ty.span;
|
||||
const kind = ty.kind;
|
||||
switch (kind.tag) {
|
||||
case "error":
|
||||
return this.ctx.internTy(kind, span);
|
||||
case "null":
|
||||
return this.ctx.internTy(kind, span);
|
||||
case "int":
|
||||
return this.ctx.internTy(kind, span);
|
||||
case "bool":
|
||||
return this.ctx.internTy(kind, span);
|
||||
case "str":
|
||||
return this.ctx.internTy(kind, span);
|
||||
case "path":
|
||||
return this.ctx.internTy({
|
||||
tag: "path",
|
||||
path: this.lowerPath(kind.path, kind.qty),
|
||||
}, span);
|
||||
case "ref":
|
||||
return this.ctx.internTy({
|
||||
tag: "ref",
|
||||
ty: this.lowerTy(kind.ty),
|
||||
mut: kind.mut,
|
||||
}, span);
|
||||
case "ptr":
|
||||
return this.ctx.internTy({
|
||||
tag: "ptr",
|
||||
ty: this.lowerTy(kind.ty),
|
||||
mut: kind.mut,
|
||||
}, span);
|
||||
case "slice":
|
||||
return this.ctx.internTy({
|
||||
tag: "slice",
|
||||
ty: this.lowerTy(kind.ty),
|
||||
}, span);
|
||||
case "array":
|
||||
return this.ctx.internTy({
|
||||
tag: "array",
|
||||
ty: this.lowerTy(kind.ty),
|
||||
length: this.lowerExpr(kind.length),
|
||||
}, span);
|
||||
case "anon_struct":
|
||||
return this.ctx.internTy({
|
||||
tag: "anon_struct",
|
||||
fields: kind.fields.map(({ ident, ty, span }) => ({
|
||||
ident,
|
||||
ty: this.lowerTy(ty),
|
||||
span,
|
||||
})),
|
||||
}, span);
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
private lowerBlock(block: ast.Block): Block {
|
||||
const point = this.ribPoint();
|
||||
this.pushRib({ tag: "block" });
|
||||
const stmts = block.stmts.map((stmt) => this.lowerStmt(stmt));
|
||||
const expr = block.expr && this.lowerExpr(block.expr);
|
||||
this.returnToRibPoint(point);
|
||||
return this.ctx.internBlock({ stmts, expr, span: block.span });
|
||||
}
|
||||
|
||||
private lowerPath(path: ast.Path, qty?: ast.Ty): QPath {
|
||||
if (qty) {
|
||||
const ty = this.lowerTy(qty);
|
||||
if (path.segments.length !== 1) {
|
||||
throw new Error();
|
||||
}
|
||||
const seg = path.segments[0];
|
||||
return {
|
||||
tag: "type_relative",
|
||||
ty,
|
||||
seg: {
|
||||
ident: seg.ident,
|
||||
res: todo(),
|
||||
genericArgs: seg.genericArgs &&
|
||||
seg.genericArgs.map((ty) => this.lowerTy(ty)),
|
||||
inferArgs: false,
|
||||
span: path.span,
|
||||
},
|
||||
};
|
||||
}
|
||||
const [res, segments] = this.resolvePathSegs(path.segments);
|
||||
return {
|
||||
tag: "resolved",
|
||||
path: { segments, res, span: path.span },
|
||||
};
|
||||
}
|
||||
|
||||
private resolvePathSegs(segs: ast.PathSegment[]): [Res, PathSegment[]] {
|
||||
if (segs.length <= 1) {
|
||||
const seg = segs[0];
|
||||
const res = this.resolveTyIdent(seg.ident);
|
||||
return [res, [{
|
||||
ident: seg.ident,
|
||||
res,
|
||||
genericArgs: seg.genericArgs &&
|
||||
seg.genericArgs.map((ty) => this.lowerTy(ty)),
|
||||
inferArgs: false,
|
||||
span: seg.span,
|
||||
}]];
|
||||
}
|
||||
const seg = segs.at(-1)!;
|
||||
const [innerRes, resSegs] = this.resolvePathSegs(
|
||||
segs.slice(0, segs.length - 1),
|
||||
);
|
||||
switch (innerRes.tag) {
|
||||
case "error":
|
||||
return [innerRes, [...resSegs, {
|
||||
ident: seg.ident,
|
||||
res: innerRes,
|
||||
inferArgs: false,
|
||||
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.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 "ty_alias":
|
||||
return todo();
|
||||
case "ty_param":
|
||||
return todo();
|
||||
case "use":
|
||||
return todo();
|
||||
case "fn":
|
||||
case "variant":
|
||||
case "ctor":
|
||||
case "field":
|
||||
this.ctx.report({
|
||||
severity: "error",
|
||||
file: this.currentFile,
|
||||
msg: `${irk.tag} contains zero members`,
|
||||
span: seg.span,
|
||||
});
|
||||
return error();
|
||||
}
|
||||
exhausted(irk);
|
||||
throw new Error();
|
||||
}
|
||||
case "local":
|
||||
throw new Error("should not be possible");
|
||||
}
|
||||
exhausted(innerRes);
|
||||
}
|
||||
|
||||
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 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 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.tyRibs.pop();
|
||||
this.valRibs.pop();
|
||||
}
|
||||
|
||||
private ribPoint(): number {
|
||||
return this.valRibs.length;
|
||||
}
|
||||
|
||||
private returnToRibPoint(point: number) {
|
||||
this.tyRibs = this.tyRibs.slice(0, point);
|
||||
this.valRibs = this.valRibs.slice(0, point);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
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,21 +0,0 @@
|
||||
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<Key<IdentId>, Res>;
|
||||
};
|
||||
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
|
||||
export type RibKind =
|
||||
/// No restriction needs to be applied.
|
||||
| { tag: "normal" }
|
||||
/// We passed through a function, closure or coroutine signature. Disallow labels.
|
||||
| { tag: "fn" }
|
||||
/// We passed through an item scope. Disallow upvars.
|
||||
| { tag: "item"; defKind: DefKind }
|
||||
/// We passed through a module.
|
||||
| { tag: "mod"; mod: Mod }
|
||||
/// We passed through a block (same as module, see Rust).
|
||||
| { tag: "block" };
|
Loading…
Reference in New Issue
Block a user