more ast lower
This commit is contained in:
parent
188c2d806d
commit
b02c5e223f
@ -147,7 +147,7 @@ export type ExprKind =
|
|||||||
| { tag: "for" } & ForExpr
|
| { tag: "for" } & ForExpr
|
||||||
| { tag: "c_for" } & CForExpr;
|
| { tag: "c_for" } & CForExpr;
|
||||||
|
|
||||||
export type PathExpr = { path: Path };
|
export type PathExpr = { qty?: Ty; path: Path };
|
||||||
export type IntExpr = { value: number };
|
export type IntExpr = { value: number };
|
||||||
export type BoolExpr = { value: boolean };
|
export type BoolExpr = { value: boolean };
|
||||||
export type StringExpr = { value: string };
|
export type StringExpr = { value: string };
|
||||||
@ -205,12 +205,11 @@ export type Pat = {
|
|||||||
|
|
||||||
export type PatKind =
|
export type PatKind =
|
||||||
| { tag: "error" }
|
| { tag: "error" }
|
||||||
| { tag: "bind" } & BindPat;
|
| { tag: "bind" } & BindPat
|
||||||
|
| { tag: "path" } & PathPat;
|
||||||
|
|
||||||
export type BindPat = {
|
export type BindPat = { ident: Ident; mut: boolean };
|
||||||
ident: Ident;
|
export type PathPat = { qty?: Ty; path: Path };
|
||||||
mut: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Ty = {
|
export type Ty = {
|
||||||
kind: TyKind;
|
kind: TyKind;
|
||||||
@ -230,7 +229,7 @@ export type TyKind =
|
|||||||
| { tag: "array" } & ArrayTy
|
| { tag: "array" } & ArrayTy
|
||||||
| { tag: "anon_struct" } & AnonStructTy;
|
| { tag: "anon_struct" } & AnonStructTy;
|
||||||
|
|
||||||
export type PathTy = { path: Path };
|
export type PathTy = { qty?: Ty; path: Path };
|
||||||
export type RefTy = { ty: Ty; mut: boolean };
|
export type RefTy = { ty: Ty; mut: boolean };
|
||||||
export type PtrTy = { ty: Ty; mut: boolean };
|
export type PtrTy = { ty: Ty; mut: boolean };
|
||||||
export type SliceTy = { ty: Ty };
|
export type SliceTy = { ty: Ty };
|
||||||
|
@ -59,6 +59,8 @@ export class Ctx {
|
|||||||
.map((key) => keyId(key));
|
.map((key) => keyId(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
private identIds = new Ids<IdentId>();
|
private identIds = new Ids<IdentId>();
|
||||||
private identStringToId = new Map<string, IdentId>();
|
private identStringToId = new Map<string, IdentId>();
|
||||||
private identIdToString = new Map<Key<IdentId>, string>();
|
private identIdToString = new Map<Key<IdentId>, string>();
|
||||||
@ -77,15 +79,78 @@ export class Ctx {
|
|||||||
return this.identIdToString.get(idKey(ident))!;
|
return this.identIdToString.get(idKey(ident))!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private stmtIds = new Ids<hir.StmtId>();
|
//
|
||||||
private stmts = new Map<Key<hir.StmtId>, hir.Stmt>();
|
|
||||||
|
|
||||||
public internStmt(kind: hir.StmtKind, span: Span): hir.StmtId {
|
private hirIds = new Ids<hir.HirId>();
|
||||||
const id = this.stmtIds.nextThenStep();
|
|
||||||
this.stmts.set(idKey(id), { kind, span });
|
private stmts = new Map<Key<hir.HirId>, hir.Stmt>();
|
||||||
|
|
||||||
|
/// don't intern the same thing twice
|
||||||
|
public internStmt(kind: hir.StmtKind, span: Span): hir.Stmt {
|
||||||
|
const id = this.hirIds.nextThenStep();
|
||||||
|
const v: hir.Stmt = { id, kind, span };
|
||||||
|
this.stmts.set(idKey(id), v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private exprs = new Map<Key<hir.HirId>, hir.Expr>();
|
||||||
|
|
||||||
|
/// don't intern the same thing twice
|
||||||
|
public internExpr(kind: hir.ExprKind, span: Span): hir.Expr {
|
||||||
|
const id = this.hirIds.nextThenStep();
|
||||||
|
const v: hir.Expr = { id, kind, span };
|
||||||
|
this.exprs.set(idKey(id), v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private pats = new Map<Key<hir.HirId>, hir.Pat>();
|
||||||
|
|
||||||
|
/// don't intern the same thing twice
|
||||||
|
public internPat(kind: hir.PatKind, span: Span): hir.Pat {
|
||||||
|
const id = this.hirIds.nextThenStep();
|
||||||
|
const v: hir.Pat = { id, kind, span };
|
||||||
|
this.pats.set(idKey(id), v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private tys = new Map<Key<hir.HirId>, hir.Ty>();
|
||||||
|
|
||||||
|
/// don't intern the same thing twice
|
||||||
|
public internTy(kind: hir.TyKind, span: Span): hir.Ty {
|
||||||
|
const id = this.hirIds.nextThenStep();
|
||||||
|
const v: hir.Ty = { id, kind, span };
|
||||||
|
this.tys.set(idKey(id), v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private blocks = new Map<Key<hir.HirId>, hir.Block>();
|
||||||
|
|
||||||
|
/// don't intern the same thing twice
|
||||||
|
public internBlock(block: Omit<hir.Block, "id">): hir.Block {
|
||||||
|
const id = this.hirIds.nextThenStep();
|
||||||
|
const v: hir.Block = { id, ...block };
|
||||||
|
this.blocks.set(idKey(id), v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
private defIds = new Ids<hir.DefId>();
|
||||||
|
|
||||||
|
private defs = new Map<Key<hir.DefId>, hir.HirId>();
|
||||||
|
|
||||||
|
public addHirIdDef(hirId: hir.HirId): hir.DefId {
|
||||||
|
const id = this.defIds.nextThenStep();
|
||||||
|
this.defs.set(idKey(id), hirId);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public defHirId(id: hir.DefId): hir.HirId {
|
||||||
|
return this.defs.get(idKey(id))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
public filePosLineText(file: File, pos: Pos): string {
|
public filePosLineText(file: File, pos: Pos): string {
|
||||||
const fileTextLines = this.fileInfo(file).text.split("\n");
|
const fileTextLines = this.fileInfo(file).text.split("\n");
|
||||||
return fileTextLines[pos.line - 1];
|
return fileTextLines[pos.line - 1];
|
||||||
@ -143,6 +208,7 @@ export type FileInfo = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type IdentId = IdBase & { readonly _: unique symbol };
|
export type IdentId = IdBase & { readonly _: unique symbol };
|
||||||
|
export type HirId = IdBase & { readonly _: unique symbol };
|
||||||
export type DefId = IdBase & { readonly _: unique symbol };
|
export type DefId = IdBase & { readonly _: unique symbol };
|
||||||
|
|
||||||
export type IdBase = { key: number };
|
export type IdBase = { key: number };
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
export type { DefId, HirId } from "../ctx.ts";
|
||||||
|
import { HirId, IdentId } from "../ctx.ts";
|
||||||
import { Span } from "../diagnostics.ts";
|
import { Span } from "../diagnostics.ts";
|
||||||
|
import { Res } from "./rib.ts";
|
||||||
export type StmtId = { key: number; readonly unique: unique symbol };
|
|
||||||
|
|
||||||
export type Stmt = {
|
export type Stmt = {
|
||||||
|
id: HirId;
|
||||||
kind: StmtKind;
|
kind: StmtKind;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
@ -17,28 +19,26 @@ export type StmtKind =
|
|||||||
| { tag: "assign" } & AssignStmt
|
| { tag: "assign" } & AssignStmt
|
||||||
| { tag: "expr" } & ExprStmt;
|
| { tag: "expr" } & ExprStmt;
|
||||||
|
|
||||||
export type ItemStmt = { item: ItemId };
|
export type ItemStmt = { item: Item };
|
||||||
|
|
||||||
export type LetStmt = {
|
export type LetStmt = {
|
||||||
pat: PatId;
|
pat: Pat;
|
||||||
ty?: TyId;
|
ty?: Ty;
|
||||||
expr?: ExprId;
|
expr?: Expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReturnStmt = { expr?: ExprId };
|
export type ReturnStmt = { expr?: Expr };
|
||||||
export type BreakStmt = { expr?: ExprId };
|
export type BreakStmt = { expr?: Expr };
|
||||||
|
|
||||||
export type AssignStmt = {
|
export type AssignStmt = {
|
||||||
assignType: AssignType;
|
assignType: AssignType;
|
||||||
subject: ExprId;
|
subject: Expr;
|
||||||
value: ExprId;
|
value: Expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AssignType = "=" | "+=" | "-=";
|
export type AssignType = "=" | "+=" | "-=";
|
||||||
|
|
||||||
export type ExprStmt = { expr: ExprId };
|
export type ExprStmt = { expr: Expr };
|
||||||
|
|
||||||
export type ItemId = { key: number; readonly unique: unique symbol };
|
|
||||||
|
|
||||||
export type Item = {
|
export type Item = {
|
||||||
kind: ItemKind;
|
kind: ItemKind;
|
||||||
@ -57,7 +57,7 @@ export type ItemKind =
|
|||||||
| { tag: "use" } & UseItem
|
| { tag: "use" } & UseItem
|
||||||
| { tag: "type_alias" } & TypeAliasItem;
|
| { tag: "type_alias" } & TypeAliasItem;
|
||||||
|
|
||||||
export type ModBlockItem = { block: BlockId };
|
export type ModBlockItem = { block: Block };
|
||||||
export type ModFileItem = { filePath: string };
|
export type ModFileItem = { filePath: string };
|
||||||
export type EnumItem = { variants: Variant[] };
|
export type EnumItem = { variants: Variant[] };
|
||||||
export type StructItem = { data: VariantData };
|
export type StructItem = { data: VariantData };
|
||||||
@ -65,12 +65,12 @@ export type StructItem = { data: VariantData };
|
|||||||
export type FnItem = {
|
export type FnItem = {
|
||||||
generics?: Generics;
|
generics?: Generics;
|
||||||
params: Param[];
|
params: Param[];
|
||||||
returnTy?: TyId;
|
returnTy?: Ty;
|
||||||
body: BlockId;
|
body: Block;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UseItem = { _: 0 };
|
export type UseItem = { _: 0 };
|
||||||
export type TypeAliasItem = { ty: TyId };
|
export type TypeAliasItem = { ty: Ty };
|
||||||
|
|
||||||
export type Variant = {
|
export type Variant = {
|
||||||
ident: Ident;
|
ident: Ident;
|
||||||
@ -95,14 +95,14 @@ export type StructVariantData = { fields: FieldDef[] };
|
|||||||
|
|
||||||
export type FieldDef = {
|
export type FieldDef = {
|
||||||
ident: Ident;
|
ident: Ident;
|
||||||
ty: TyId;
|
ty: Ty;
|
||||||
pub: boolean;
|
pub: boolean;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Param = {
|
export type Param = {
|
||||||
pat: PatId;
|
pat: Pat;
|
||||||
ty: TyId;
|
ty: Ty;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,9 +115,8 @@ export type GenericParam = {
|
|||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExprId = { key: number; readonly unique: unique symbol };
|
|
||||||
|
|
||||||
export type Expr = {
|
export type Expr = {
|
||||||
|
id: HirId;
|
||||||
kind: ExprKind;
|
kind: ExprKind;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
@ -148,36 +147,36 @@ export type ExprKind =
|
|||||||
| { tag: "for" } & ForExpr
|
| { tag: "for" } & ForExpr
|
||||||
| { tag: "c_for" } & CForExpr;
|
| { tag: "c_for" } & CForExpr;
|
||||||
|
|
||||||
export type PathExpr = { path: Path };
|
export type PathExpr = { path: QPath };
|
||||||
export type IntExpr = { value: number };
|
export type IntExpr = { value: number };
|
||||||
export type BoolExpr = { value: boolean };
|
export type BoolExpr = { value: boolean };
|
||||||
export type StringExpr = { value: string };
|
export type StringExpr = { value: string };
|
||||||
export type GroupExpr = { expr: ExprId };
|
export type GroupExpr = { expr: Expr };
|
||||||
export type ArrayExpr = { exprs: ExprId[] };
|
export type ArrayExpr = { exprs: Expr[] };
|
||||||
export type RepeatExpr = { expr: ExprId; length: ExprId };
|
export type RepeatExpr = { expr: Expr; length: Expr };
|
||||||
export type StructExpr = { path?: Path; fields: ExprField[] };
|
export type StructExpr = { path?: QPath; fields: ExprField[] };
|
||||||
export type RefExpr = { expr: ExprId; refType: RefType; mut: boolean };
|
export type RefExpr = { expr: Expr; refType: RefType; mut: boolean };
|
||||||
export type DerefExpr = { expr: ExprId };
|
export type DerefExpr = { expr: Expr };
|
||||||
export type ElemExpr = { expr: ExprId; elem: number };
|
export type ElemExpr = { expr: Expr; elem: number };
|
||||||
export type FieldExpr = { expr: ExprId; ident: Ident };
|
export type FieldExpr = { expr: Expr; ident: Ident };
|
||||||
export type IndexExpr = { expr: ExprId; index: ExprId };
|
export type IndexExpr = { expr: Expr; index: Expr };
|
||||||
export type CallExpr = { expr: ExprId; args: ExprId[] };
|
export type CallExpr = { expr: Expr; args: Expr[] };
|
||||||
export type UnaryExpr = { unaryType: UnaryType; expr: ExprId };
|
export type UnaryExpr = { unaryType: UnaryType; expr: Expr };
|
||||||
export type BinaryExpr = {
|
export type BinaryExpr = {
|
||||||
binaryType: BinaryType;
|
binaryType: BinaryType;
|
||||||
left: ExprId;
|
left: Expr;
|
||||||
right: ExprId;
|
right: Expr;
|
||||||
};
|
};
|
||||||
export type BlockExpr = { block: BlockId };
|
export type BlockExpr = { block: Block };
|
||||||
export type IfExpr = { cond: ExprId; truthy: BlockId; falsy?: ExprId };
|
export type IfExpr = { cond: Expr; truthy: Block; falsy?: Expr };
|
||||||
export type LoopExpr = { body: BlockId };
|
export type LoopExpr = { body: Block };
|
||||||
export type WhileExpr = { cond: ExprId; body: BlockId };
|
export type WhileExpr = { cond: Expr; body: Block };
|
||||||
export type ForExpr = { pat: PatId; expr: ExprId; body: BlockId };
|
export type ForExpr = { pat: Pat; expr: Expr; body: Block };
|
||||||
export type CForExpr = {
|
export type CForExpr = {
|
||||||
decl?: StmtId;
|
decl?: Stmt;
|
||||||
cond?: ExprId;
|
cond?: Expr;
|
||||||
incr?: StmtId;
|
incr?: Stmt;
|
||||||
body: BlockId;
|
body: Block;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RefType = "ref" | "ptr";
|
export type RefType = "ref" | "ptr";
|
||||||
@ -198,37 +197,26 @@ export type BinaryType =
|
|||||||
|
|
||||||
export type ExprField = {
|
export type ExprField = {
|
||||||
ident: Ident;
|
ident: Ident;
|
||||||
expr: ExprId;
|
expr: Expr;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BlockId = { key: number; readonly unique: unique symbol };
|
|
||||||
|
|
||||||
export type Block = {
|
|
||||||
stmts: StmtId[];
|
|
||||||
expr?: ExprId;
|
|
||||||
span: Span;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PatId = { key: number; readonly unique: unique symbol };
|
|
||||||
|
|
||||||
export type Pat = {
|
export type Pat = {
|
||||||
|
id: HirId;
|
||||||
kind: PatKind;
|
kind: PatKind;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PatKind =
|
export type PatKind =
|
||||||
| { tag: "error" }
|
| { tag: "error" }
|
||||||
| { tag: "bind" } & BindPat;
|
| { tag: "bind" } & BindPat
|
||||||
|
| { tag: "path" } & PathPat;
|
||||||
|
|
||||||
export type BindPat = {
|
export type BindPat = { ident: Ident; mut: boolean };
|
||||||
ident: Ident;
|
export type PathPat = { path: QPath };
|
||||||
mut: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TyId = { key: number; readonly unique: unique symbol };
|
|
||||||
|
|
||||||
export type Ty = {
|
export type Ty = {
|
||||||
|
id: HirId;
|
||||||
kind: TyKind;
|
kind: TyKind;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
@ -246,20 +234,31 @@ export type TyKind =
|
|||||||
| { tag: "array" } & ArrayTy
|
| { tag: "array" } & ArrayTy
|
||||||
| { tag: "anon_struct" } & AnonStructTy;
|
| { tag: "anon_struct" } & AnonStructTy;
|
||||||
|
|
||||||
export type PathTy = { path: Path };
|
export type PathTy = { path: QPath };
|
||||||
export type RefTy = { ty: TyId; mut: boolean };
|
export type RefTy = { ty: Ty; mut: boolean };
|
||||||
export type PtrTy = { ty: TyId; mut: boolean };
|
export type PtrTy = { ty: Ty; mut: boolean };
|
||||||
export type SliceTy = { ty: TyId };
|
export type SliceTy = { ty: Ty };
|
||||||
export type ArrayTy = { ty: TyId; length: ExprId };
|
export type ArrayTy = { ty: Ty; length: Expr };
|
||||||
export type TupleTy = { elems: TyId[] };
|
export type TupleTy = { elems: Ty[] };
|
||||||
export type AnonStructTy = { fields: AnonFieldDef[] };
|
export type AnonStructTy = { fields: AnonFieldDef[] };
|
||||||
|
|
||||||
export type AnonFieldDef = {
|
export type AnonFieldDef = {
|
||||||
ident: Ident;
|
ident: Ident;
|
||||||
ty: TyId;
|
ty: Ty;
|
||||||
span: Span;
|
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 = {
|
export type Path = {
|
||||||
segments: PathSegment[];
|
segments: PathSegment[];
|
||||||
span: Span;
|
span: Span;
|
||||||
@ -267,12 +266,13 @@ export type Path = {
|
|||||||
|
|
||||||
export type PathSegment = {
|
export type PathSegment = {
|
||||||
ident: Ident;
|
ident: Ident;
|
||||||
genericArgs?: TyId[];
|
res: Res;
|
||||||
|
genericArgs?: Ty[];
|
||||||
|
inferArgs: boolean;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Ident = {
|
export type Ident = {
|
||||||
internId: number;
|
id: IdentId;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
80
compiler/middle/hir_eq.ts
Normal file
80
compiler/middle/hir_eq.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
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,7 +1,19 @@
|
|||||||
import { Ctx, DefId, IdentId } from "../ctx.ts";
|
import { Ctx, DefId, IdentId } from "../ctx.ts";
|
||||||
import * as ast from "../ast/ast.ts";
|
import * as ast from "../ast/ast.ts";
|
||||||
import { ExprId, Ident, ItemId, PatId, StmtId, TyId } from "./hir.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 { exhausted, Res as Result, todo } from "../util.ts";
|
||||||
|
import { Res, Rib } from "./rib.ts";
|
||||||
|
|
||||||
export class AstLowerer {
|
export class AstLowerer {
|
||||||
private ribs: Rib[] = [];
|
private ribs: Rib[] = [];
|
||||||
@ -20,74 +32,367 @@ export class AstLowerer {
|
|||||||
this.lowerStmts(file.stmts);
|
this.lowerStmts(file.stmts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerStmts(stmts: ast.Stmt[]): StmtId[] {
|
private lowerStmts(stmts: ast.Stmt[]): Stmt[] {
|
||||||
return stmts.map((stmt) => this.lowerStmt(stmt));
|
return stmts.map((stmt) => this.lowerStmt(stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerStmt(stmt: ast.Stmt): StmtId {
|
private lowerStmt(stmt: ast.Stmt): Stmt {
|
||||||
|
const span = stmt.span;
|
||||||
const kind = stmt.kind;
|
const kind = stmt.kind;
|
||||||
switch (kind.tag) {
|
switch (kind.tag) {
|
||||||
case "error":
|
case "error":
|
||||||
return this.ctx.internStmt(kind, stmt.span);
|
return this.ctx.internStmt(kind, span);
|
||||||
case "item":
|
case "item":
|
||||||
return this.ctx.internStmt({
|
return this.ctx.internStmt({
|
||||||
tag: "item",
|
tag: "item",
|
||||||
item: this.lowerItem(kind.item),
|
item: this.lowerItem(kind.item),
|
||||||
}, stmt.span);
|
}, span);
|
||||||
case "let":
|
case "let":
|
||||||
return this.lowerLetStmt(stmt, kind);
|
return this.lowerLetStmt(stmt, kind);
|
||||||
case "return":
|
case "return":
|
||||||
return this.ctx.internStmt({
|
return this.ctx.internStmt({
|
||||||
tag: "return",
|
tag: "return",
|
||||||
expr: kind.expr && this.lowerExpr(kind.expr),
|
expr: kind.expr && this.lowerExpr(kind.expr),
|
||||||
}, stmt.span);
|
}, span);
|
||||||
case "break":
|
case "break":
|
||||||
return this.ctx.internStmt({
|
return this.ctx.internStmt({
|
||||||
tag: "break",
|
tag: "break",
|
||||||
expr: kind.expr && this.lowerExpr(kind.expr),
|
expr: kind.expr && this.lowerExpr(kind.expr),
|
||||||
}, stmt.span);
|
}, span);
|
||||||
case "continue":
|
case "continue":
|
||||||
return this.ctx.internStmt({
|
return this.ctx.internStmt({
|
||||||
tag: "continue",
|
tag: "continue",
|
||||||
}, stmt.span);
|
}, span);
|
||||||
case "assign":
|
case "assign":
|
||||||
return this.ctx.internStmt({
|
return this.ctx.internStmt({
|
||||||
tag: "assign",
|
tag: "assign",
|
||||||
assignType: kind.assignType,
|
assignType: kind.assignType,
|
||||||
subject: this.lowerExpr(kind.subject),
|
subject: this.lowerExpr(kind.subject),
|
||||||
value: this.lowerExpr(kind.value),
|
value: this.lowerExpr(kind.value),
|
||||||
}, stmt.span);
|
}, span);
|
||||||
case "expr":
|
case "expr":
|
||||||
return this.ctx.internStmt({
|
return this.ctx.internStmt({
|
||||||
tag: "expr",
|
tag: "expr",
|
||||||
expr: this.lowerExpr(kind.expr),
|
expr: this.lowerExpr(kind.expr),
|
||||||
}, stmt.span);
|
}, span);
|
||||||
}
|
}
|
||||||
exhausted(kind);
|
exhausted(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerLetStmt(stmt: ast.Stmt, kind: ast.LetStmt): StmtId {
|
private lowerLetStmt(stmt: ast.Stmt, kind: ast.LetStmt): Stmt {
|
||||||
return this.ctx.internStmt({
|
const expr = kind.expr && this.lowerExpr(kind.expr);
|
||||||
tag: "let",
|
const ty = kind.ty && this.lowerTy(kind.ty);
|
||||||
pat: this.lowerPat(kind.pat),
|
this.pushRib({ kind: { tag: "normal" }, bindings: new Map() });
|
||||||
ty: kind.ty && this.lowerTy(kind.ty),
|
const pat = this.lowerPat(kind.pat);
|
||||||
expr: kind.expr && this.lowerExpr(kind.expr),
|
return this.ctx.internStmt({ tag: "let", pat, ty, expr }, stmt.span);
|
||||||
}, stmt.span);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerItem(item: ast.Item): ItemId {
|
private lowerItem(item: ast.Item): Item {
|
||||||
return todo();
|
return todo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerPat(pat: ast.Pat): PatId {
|
private lowerExpr(expr: ast.Expr): Expr {
|
||||||
return todo();
|
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 lowerTy(ty: ast.Ty): TyId {
|
private lowerPat(pat: ast.Pat): Pat {
|
||||||
return todo();
|
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.rib().bindings.set(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 lowerExpr(expr: ast.Expr): ExprId {
|
private lowerTy(ty: ast.Ty): Ty {
|
||||||
return todo();
|
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();
|
||||||
|
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 = this.resolvePathSegs(path.segments);
|
||||||
|
return {
|
||||||
|
path: {
|
||||||
|
segments
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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: }]]
|
||||||
|
}
|
||||||
|
const innerRes = this.resolvePathSegs(segs.slice(1));
|
||||||
|
switch (innerRes.tag) {
|
||||||
|
case "error":
|
||||||
|
return innerRes;
|
||||||
|
case "def": {
|
||||||
|
const irk = innerRes.kind;
|
||||||
|
switch (irk.tag) {
|
||||||
|
case "mod":
|
||||||
|
return todo();
|
||||||
|
case "struct":
|
||||||
|
return todo();
|
||||||
|
case "enum":
|
||||||
|
return todo();
|
||||||
|
case "variant":
|
||||||
|
return todo();
|
||||||
|
case "ty_alias":
|
||||||
|
return todo();
|
||||||
|
case "ty_param":
|
||||||
|
return todo();
|
||||||
|
case "fn":
|
||||||
|
return todo();
|
||||||
|
case "ctor":
|
||||||
|
return todo();
|
||||||
|
case "use":
|
||||||
|
return todo();
|
||||||
|
case "field":
|
||||||
|
return todo();
|
||||||
|
}
|
||||||
|
exhausted(irk);
|
||||||
|
return todo();
|
||||||
|
}
|
||||||
|
case "local":
|
||||||
|
throw new Error("should not be possible");
|
||||||
|
}
|
||||||
|
exhausted(innerRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveTyIdent(ident: Ident): Res {
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveValIdent(ident: Ident): Res {
|
||||||
|
}
|
||||||
|
|
||||||
|
private rib(): Rib {
|
||||||
|
return this.ribs.at(-1)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private pushRib(rib: Rib) {
|
||||||
|
this.ribs.push(rib);
|
||||||
|
}
|
||||||
|
|
||||||
|
private popRib() {
|
||||||
|
this.ribs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ribPoint(): number {
|
||||||
|
return this.ribs.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private returnToRibPoint(point: number) {
|
||||||
|
this.ribs = this.ribs.slice(0, point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { DefId, IdentId } from "../ctx.ts";
|
import { DefId, HirId, IdentId } from "../ctx.ts";
|
||||||
|
import { Mod } from "../main.ts";
|
||||||
|
|
||||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html
|
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html
|
||||||
export type Rib = {
|
export type Rib = {
|
||||||
@ -11,23 +12,23 @@ export type RibKind =
|
|||||||
| { tag: "normal" }
|
| { tag: "normal" }
|
||||||
| { tag: "fn" }
|
| { tag: "fn" }
|
||||||
| { tag: "item"; defKind: DefKind }
|
| { tag: "item"; defKind: DefKind }
|
||||||
| { tag: "mod" };
|
| { tag: "mod"; mod: Mod };
|
||||||
|
|
||||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
|
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
|
||||||
export type Res =
|
export type Res =
|
||||||
| { tag: "error" }
|
| { tag: "error" }
|
||||||
| { tag: "def"; kind: DefKind; id: DefId }
|
| { tag: "def"; kind: DefKind; id: DefId }
|
||||||
| { tag: "local"; id: DefId };
|
| { tag: "local"; id: HirId };
|
||||||
|
|
||||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.DefKind.html
|
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.DefKind.html
|
||||||
export type DefKind =
|
export type DefKind =
|
||||||
| { type: "mod" }
|
| { tag: "mod" }
|
||||||
| { type: "struct" }
|
| { tag: "struct" }
|
||||||
| { type: "enum" }
|
| { tag: "enum" }
|
||||||
| { type: "variant" }
|
| { tag: "variant" }
|
||||||
| { type: "ty_alias" }
|
| { tag: "ty_alias" }
|
||||||
| { type: "ty_param" }
|
| { tag: "ty_param" }
|
||||||
| { type: "fn" }
|
| { tag: "fn" }
|
||||||
| { type: "ctor" }
|
| { tag: "ctor" }
|
||||||
| { type: "use" }
|
| { tag: "use" }
|
||||||
| { type: "field" };
|
| { tag: "field" };
|
||||||
|
@ -31,3 +31,21 @@ export const ControlFlow = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const range = (length: number) => (new Array(length).fill(0));
|
export const range = (length: number) => (new Array(length).fill(0));
|
||||||
|
|
||||||
|
export const strictEq = <T>(a: T, b: T): boolean => a === b;
|
||||||
|
|
||||||
|
export function arrayEq<T>(
|
||||||
|
a: T[],
|
||||||
|
b: T[],
|
||||||
|
elemCmp: (a: T, b: T) => boolean = strictEq,
|
||||||
|
): boolean {
|
||||||
|
if (a.length !== b.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < a.length; ++i) {
|
||||||
|
if (!elemCmp(a[i], b[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user