lower ast
This commit is contained in:
		
							parent
							
								
									15c70e4840
								
							
						
					
					
						commit
						493a11a93b
					
				@ -1,3 +1,4 @@
 | 
			
		||||
import { IdentId } from "../ctx.ts";
 | 
			
		||||
import { Span } from "../diagnostics.ts";
 | 
			
		||||
 | 
			
		||||
export type File = {
 | 
			
		||||
@ -126,7 +127,7 @@ export type ExprKind =
 | 
			
		||||
    | { tag: "null" }
 | 
			
		||||
    | { tag: "int" } & IntExpr
 | 
			
		||||
    | { tag: "bool" } & BoolExpr
 | 
			
		||||
    | { tag: "string" } & StringExpr
 | 
			
		||||
    | { tag: "str" } & StringExpr
 | 
			
		||||
    | { tag: "group" } & GroupExpr
 | 
			
		||||
    | { tag: "array" } & ArrayExpr
 | 
			
		||||
    | { tag: "repeat" } & RepeatExpr
 | 
			
		||||
@ -221,7 +222,7 @@ export type TyKind =
 | 
			
		||||
    | { tag: "null" }
 | 
			
		||||
    | { tag: "int" }
 | 
			
		||||
    | { tag: "bool" }
 | 
			
		||||
    | { tag: "string" }
 | 
			
		||||
    | { tag: "str" }
 | 
			
		||||
    | { tag: "path" } & PathTy
 | 
			
		||||
    | { tag: "ref" } & RefTy
 | 
			
		||||
    | { tag: "ptr" } & PtrTy
 | 
			
		||||
@ -255,6 +256,6 @@ export type PathSegment = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Ident = {
 | 
			
		||||
    text: string;
 | 
			
		||||
    id: IdentId;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -116,7 +116,7 @@ export interface Visitor<
 | 
			
		||||
    visitNullTy?(ty: Ty, ...p: P): R;
 | 
			
		||||
    visitIntTy?(ty: Ty, ...p: P): R;
 | 
			
		||||
    visitBoolTy?(ty: Ty, ...p: P): R;
 | 
			
		||||
    visitStringTy?(ty: Ty, ...p: P): R;
 | 
			
		||||
    visitStrTy?(ty: Ty, ...p: P): R;
 | 
			
		||||
    visitPathTy?(ty: Ty, kind: PathTy, ...p: P): R;
 | 
			
		||||
    visitRefTy?(ty: Ty, kind: RefTy, ...p: P): R;
 | 
			
		||||
    visitPtrTy?(ty: Ty, kind: PtrTy, ...p: P): R;
 | 
			
		||||
@ -267,7 +267,7 @@ export function visitExpr<
 | 
			
		||||
        case "int":
 | 
			
		||||
            if (v.visitIntExpr?.(expr, kind, ...p) === "stop") return;
 | 
			
		||||
            return;
 | 
			
		||||
        case "string":
 | 
			
		||||
        case "str":
 | 
			
		||||
            if (v.visitStringExpr?.(expr, kind, ...p) === "stop") return;
 | 
			
		||||
            return;
 | 
			
		||||
        case "bool":
 | 
			
		||||
@ -419,8 +419,8 @@ export function visitTy<
 | 
			
		||||
        case "bool":
 | 
			
		||||
            if (v.visitBoolTy?.(ty, ...p) === "stop") return;
 | 
			
		||||
            return;
 | 
			
		||||
        case "string":
 | 
			
		||||
            if (v.visitStringTy?.(ty, ...p) === "stop") return;
 | 
			
		||||
        case "str":
 | 
			
		||||
            if (v.visitStrTy?.(ty, ...p) === "stop") return;
 | 
			
		||||
            return;
 | 
			
		||||
        case "path":
 | 
			
		||||
            if (v.visitPathTy?.(ty, kind, ...p) === "stop") return;
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,16 @@ import {
 | 
			
		||||
    Report,
 | 
			
		||||
    Span,
 | 
			
		||||
} from "./diagnostics.ts";
 | 
			
		||||
import * as hir from "./middle/hir.ts";
 | 
			
		||||
 | 
			
		||||
export class Ctx {
 | 
			
		||||
    private fileIds = new Ids();
 | 
			
		||||
    private files = new Map<Id<File>, FileInfo>();
 | 
			
		||||
    private fileIds = new Ids<File>();
 | 
			
		||||
    private files = new Map<Key<File>, FileInfo>();
 | 
			
		||||
 | 
			
		||||
    private reports: Report[] = [];
 | 
			
		||||
 | 
			
		||||
    public fileHasChildWithIdent(file: File, childIdent: string): boolean {
 | 
			
		||||
        return this.files.get(id(file))!
 | 
			
		||||
        return this.files.get(idKey(file))!
 | 
			
		||||
            .subFiles.has(childIdent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -26,7 +27,7 @@ export class Ctx {
 | 
			
		||||
        text: string,
 | 
			
		||||
    ): File {
 | 
			
		||||
        const file = this.fileIds.nextThenStep();
 | 
			
		||||
        this.files.set(id(file), {
 | 
			
		||||
        this.files.set(idKey(file), {
 | 
			
		||||
            ident,
 | 
			
		||||
            absPath,
 | 
			
		||||
            relPath,
 | 
			
		||||
@ -35,18 +36,54 @@ export class Ctx {
 | 
			
		||||
            text,
 | 
			
		||||
        });
 | 
			
		||||
        if (superFile) {
 | 
			
		||||
            this.files.get(id(superFile))!
 | 
			
		||||
            this.files.get(idKey(superFile))!
 | 
			
		||||
                .subFiles.set(ident, file);
 | 
			
		||||
        }
 | 
			
		||||
        return file;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public addFileAst(file: File, ast: ast.File) {
 | 
			
		||||
        this.files.get(id(file))!.ast = ast;
 | 
			
		||||
        this.files.get(idKey(file))!.ast = ast;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public fileInfo(file: File): FileInfo {
 | 
			
		||||
        return this.files.get(id(file))!;
 | 
			
		||||
        return this.files.get(idKey(file))!;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public entryFile(): File {
 | 
			
		||||
        return keyId(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public iterFiles(): Iterator<File> {
 | 
			
		||||
        return this.files.keys()
 | 
			
		||||
            .map((key) => keyId(key));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private identIds = new Ids<IdentId>();
 | 
			
		||||
    private identStringToId = new Map<string, IdentId>();
 | 
			
		||||
    private identIdToString = new Map<Key<IdentId>, string>();
 | 
			
		||||
 | 
			
		||||
    public internIdent(ident: string): IdentId {
 | 
			
		||||
        if (this.identStringToId.has(ident)) {
 | 
			
		||||
            return this.identStringToId.get(ident)!;
 | 
			
		||||
        }
 | 
			
		||||
        const id = this.identIds.nextThenStep();
 | 
			
		||||
        this.identStringToId.set(ident, id);
 | 
			
		||||
        this.identIdToString.set(idKey(id), ident);
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public identText(ident: IdentId): string {
 | 
			
		||||
        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 {
 | 
			
		||||
        const id = this.stmtIds.nextThenStep();
 | 
			
		||||
        this.stmts.set(idKey(id), { kind, span });
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public filePosLineText(file: File, pos: Pos): string {
 | 
			
		||||
@ -93,7 +130,7 @@ export class Ctx {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type File = IdBase;
 | 
			
		||||
export type File = IdBase & { readonly _: unique symbol };
 | 
			
		||||
 | 
			
		||||
export type FileInfo = {
 | 
			
		||||
    ident: string;
 | 
			
		||||
@ -105,16 +142,22 @@ export type FileInfo = {
 | 
			
		||||
    ast?: ast.File;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type IdBase = { id: number };
 | 
			
		||||
export type IdentId = IdBase & { readonly _: unique symbol };
 | 
			
		||||
export type DefId = IdBase & { readonly _: unique symbol };
 | 
			
		||||
 | 
			
		||||
export type Id<IdType extends IdBase> = IdType["id"];
 | 
			
		||||
export const id = <IdType extends IdBase>(id: IdType): Id<IdType> => id.id;
 | 
			
		||||
export type IdBase = { key: number };
 | 
			
		||||
 | 
			
		||||
export type Key<IdType extends IdBase> = IdType["key"];
 | 
			
		||||
export const idKey = <IdType extends IdBase>(id: IdType): Key<IdType> => id.key;
 | 
			
		||||
export const keyId = <IdType extends IdBase>(
 | 
			
		||||
    key: Key<IdType>,
 | 
			
		||||
): IdType => ({ key } as IdType);
 | 
			
		||||
 | 
			
		||||
export class Ids<IdType extends IdBase> {
 | 
			
		||||
    private next = 0;
 | 
			
		||||
    public nextThenStep(): IdType {
 | 
			
		||||
        const id = this.next;
 | 
			
		||||
        const key = this.next;
 | 
			
		||||
        this.next += 1;
 | 
			
		||||
        return { id } as IdType;
 | 
			
		||||
        return { key } as IdType;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@ export class FileTreeAstCollector implements ast.Visitor<[_P]> {
 | 
			
		||||
        kind: ast.ModFileItem,
 | 
			
		||||
        { file }: _P,
 | 
			
		||||
    ): ast.VisitRes {
 | 
			
		||||
        const { ident: { text: ident } } = item;
 | 
			
		||||
        const ident = this.ctx.identText(item.ident.id);
 | 
			
		||||
        const { filePath: relPath } = kind;
 | 
			
		||||
        const absPath = path.join(path.dirname(this.absPath), relPath);
 | 
			
		||||
        this.subFilePromise = this.subFilePromise
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										278
									
								
								compiler/middle/hir.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								compiler/middle/hir.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,278 @@
 | 
			
		||||
import { Span } from "../diagnostics.ts";
 | 
			
		||||
 | 
			
		||||
export type StmtId = { key: number; readonly unique: unique symbol };
 | 
			
		||||
 | 
			
		||||
export type Stmt = {
 | 
			
		||||
    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: ItemId };
 | 
			
		||||
 | 
			
		||||
export type LetStmt = {
 | 
			
		||||
    pat: PatId;
 | 
			
		||||
    ty?: TyId;
 | 
			
		||||
    expr?: ExprId;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ReturnStmt = { expr?: ExprId };
 | 
			
		||||
export type BreakStmt = { expr?: ExprId };
 | 
			
		||||
 | 
			
		||||
export type AssignStmt = {
 | 
			
		||||
    assignType: AssignType;
 | 
			
		||||
    subject: ExprId;
 | 
			
		||||
    value: ExprId;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type AssignType = "=" | "+=" | "-=";
 | 
			
		||||
 | 
			
		||||
export type ExprStmt = { expr: ExprId };
 | 
			
		||||
 | 
			
		||||
export type ItemId = { key: number; readonly unique: unique symbol };
 | 
			
		||||
 | 
			
		||||
export type Item = {
 | 
			
		||||
    kind: ItemKind;
 | 
			
		||||
    span: Span;
 | 
			
		||||
    ident: Ident;
 | 
			
		||||
    pub: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ItemKind =
 | 
			
		||||
    | { tag: "error" }
 | 
			
		||||
    | { tag: "mod_block" } & ModBlockItem
 | 
			
		||||
    | { tag: "mod_file" } & ModFileItem
 | 
			
		||||
    | { tag: "enum" } & EnumItem
 | 
			
		||||
    | { tag: "struct" } & StructItem
 | 
			
		||||
    | { tag: "fn" } & FnItem
 | 
			
		||||
    | { tag: "use" } & UseItem
 | 
			
		||||
    | { tag: "type_alias" } & TypeAliasItem;
 | 
			
		||||
 | 
			
		||||
export type ModBlockItem = { block: BlockId };
 | 
			
		||||
export type ModFileItem = { filePath: string };
 | 
			
		||||
export type EnumItem = { variants: Variant[] };
 | 
			
		||||
export type StructItem = { data: VariantData };
 | 
			
		||||
 | 
			
		||||
export type FnItem = {
 | 
			
		||||
    generics?: Generics;
 | 
			
		||||
    params: Param[];
 | 
			
		||||
    returnTy?: TyId;
 | 
			
		||||
    body: BlockId;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type UseItem = { _: 0 };
 | 
			
		||||
export type TypeAliasItem = { ty: TyId };
 | 
			
		||||
 | 
			
		||||
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: TyId;
 | 
			
		||||
    pub: boolean;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Param = {
 | 
			
		||||
    pat: PatId;
 | 
			
		||||
    ty: TyId;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Generics = {
 | 
			
		||||
    params: GenericParam[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type GenericParam = {
 | 
			
		||||
    ident: Ident;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ExprId = { key: number; readonly unique: unique symbol };
 | 
			
		||||
 | 
			
		||||
export type Expr = {
 | 
			
		||||
    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: Path };
 | 
			
		||||
export type IntExpr = { value: number };
 | 
			
		||||
export type BoolExpr = { value: boolean };
 | 
			
		||||
export type StringExpr = { value: string };
 | 
			
		||||
export type GroupExpr = { expr: ExprId };
 | 
			
		||||
export type ArrayExpr = { exprs: ExprId[] };
 | 
			
		||||
export type RepeatExpr = { expr: ExprId; length: ExprId };
 | 
			
		||||
export type StructExpr = { path?: Path; fields: ExprField[] };
 | 
			
		||||
export type RefExpr = { expr: ExprId; refType: RefType; mut: boolean };
 | 
			
		||||
export type DerefExpr = { expr: ExprId };
 | 
			
		||||
export type ElemExpr = { expr: ExprId; elem: number };
 | 
			
		||||
export type FieldExpr = { expr: ExprId; ident: Ident };
 | 
			
		||||
export type IndexExpr = { expr: ExprId; index: ExprId };
 | 
			
		||||
export type CallExpr = { expr: ExprId; args: ExprId[] };
 | 
			
		||||
export type UnaryExpr = { unaryType: UnaryType; expr: ExprId };
 | 
			
		||||
export type BinaryExpr = {
 | 
			
		||||
    binaryType: BinaryType;
 | 
			
		||||
    left: ExprId;
 | 
			
		||||
    right: ExprId;
 | 
			
		||||
};
 | 
			
		||||
export type BlockExpr = { block: BlockId };
 | 
			
		||||
export type IfExpr = { cond: ExprId; truthy: BlockId; falsy?: ExprId };
 | 
			
		||||
export type LoopExpr = { body: BlockId };
 | 
			
		||||
export type WhileExpr = { cond: ExprId; body: BlockId };
 | 
			
		||||
export type ForExpr = { pat: PatId; expr: ExprId; body: BlockId };
 | 
			
		||||
export type CForExpr = {
 | 
			
		||||
    decl?: StmtId;
 | 
			
		||||
    cond?: ExprId;
 | 
			
		||||
    incr?: StmtId;
 | 
			
		||||
    body: BlockId;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type RefType = "ref" | "ptr";
 | 
			
		||||
export type UnaryType = "not" | "-";
 | 
			
		||||
export type BinaryType =
 | 
			
		||||
    | "+"
 | 
			
		||||
    | "*"
 | 
			
		||||
    | "=="
 | 
			
		||||
    | "-"
 | 
			
		||||
    | "/"
 | 
			
		||||
    | "!="
 | 
			
		||||
    | "<"
 | 
			
		||||
    | ">"
 | 
			
		||||
    | "<="
 | 
			
		||||
    | ">="
 | 
			
		||||
    | "or"
 | 
			
		||||
    | "and";
 | 
			
		||||
 | 
			
		||||
export type ExprField = {
 | 
			
		||||
    ident: Ident;
 | 
			
		||||
    expr: ExprId;
 | 
			
		||||
    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 = {
 | 
			
		||||
    kind: PatKind;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type PatKind =
 | 
			
		||||
    | { tag: "error" }
 | 
			
		||||
    | { tag: "bind" } & BindPat;
 | 
			
		||||
 | 
			
		||||
export type BindPat = {
 | 
			
		||||
    ident: Ident;
 | 
			
		||||
    mut: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type TyId = { key: number; readonly unique: unique symbol };
 | 
			
		||||
 | 
			
		||||
export type Ty = {
 | 
			
		||||
    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: Path };
 | 
			
		||||
export type RefTy = { ty: TyId; mut: boolean };
 | 
			
		||||
export type PtrTy = { ty: TyId; mut: boolean };
 | 
			
		||||
export type SliceTy = { ty: TyId };
 | 
			
		||||
export type ArrayTy = { ty: TyId; length: ExprId };
 | 
			
		||||
export type TupleTy = { elems: TyId[] };
 | 
			
		||||
export type AnonStructTy = { fields: AnonFieldDef[] };
 | 
			
		||||
 | 
			
		||||
export type AnonFieldDef = {
 | 
			
		||||
    ident: Ident;
 | 
			
		||||
    ty: TyId;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Path = {
 | 
			
		||||
    segments: PathSegment[];
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type PathSegment = {
 | 
			
		||||
    ident: Ident;
 | 
			
		||||
    genericArgs?: TyId[];
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type Ident = {
 | 
			
		||||
    internId: number;
 | 
			
		||||
    span: Span;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										125
									
								
								compiler/middle/lower_ast.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								compiler/middle/lower_ast.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
import { Ctx, DefId, IdentId } from "../ctx.ts";
 | 
			
		||||
import * as ast from "../ast/ast.ts";
 | 
			
		||||
import { ExprId, Ident, ItemId, PatId, StmtId, TyId } from "./hir.ts";
 | 
			
		||||
import { exhausted, Res as Result, todo } from "../util.ts";
 | 
			
		||||
 | 
			
		||||
export class AstLowerer {
 | 
			
		||||
    private ribs: Rib[] = [];
 | 
			
		||||
 | 
			
		||||
    public constructor(
 | 
			
		||||
        private ctx: Ctx,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public lower() {
 | 
			
		||||
        const file = this.ctx.entryFile();
 | 
			
		||||
        const ast = this.ctx.fileInfo(file).ast!;
 | 
			
		||||
        this.lowerFile(ast);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerFile(file: ast.File) {
 | 
			
		||||
        this.lowerStmts(file.stmts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerStmts(stmts: ast.Stmt[]): StmtId[] {
 | 
			
		||||
        return stmts.map((stmt) => this.lowerStmt(stmt));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerStmt(stmt: ast.Stmt): StmtId {
 | 
			
		||||
        const kind = stmt.kind;
 | 
			
		||||
        switch (kind.tag) {
 | 
			
		||||
            case "error":
 | 
			
		||||
                return this.ctx.internStmt(kind, stmt.span);
 | 
			
		||||
            case "item":
 | 
			
		||||
                return this.ctx.internStmt({
 | 
			
		||||
                    tag: "item",
 | 
			
		||||
                    item: this.lowerItem(kind.item),
 | 
			
		||||
                }, stmt.span);
 | 
			
		||||
            case "let":
 | 
			
		||||
                return this.lowerLetStmt(stmt, kind);
 | 
			
		||||
            case "return":
 | 
			
		||||
                return this.ctx.internStmt({
 | 
			
		||||
                    tag: "return",
 | 
			
		||||
                    expr: kind.expr && this.lowerExpr(kind.expr),
 | 
			
		||||
                }, stmt.span);
 | 
			
		||||
            case "break":
 | 
			
		||||
                return this.ctx.internStmt({
 | 
			
		||||
                    tag: "break",
 | 
			
		||||
                    expr: kind.expr && this.lowerExpr(kind.expr),
 | 
			
		||||
                }, stmt.span);
 | 
			
		||||
            case "continue":
 | 
			
		||||
                return this.ctx.internStmt({
 | 
			
		||||
                    tag: "continue",
 | 
			
		||||
                }, stmt.span);
 | 
			
		||||
            case "assign":
 | 
			
		||||
                return this.ctx.internStmt({
 | 
			
		||||
                    tag: "assign",
 | 
			
		||||
                    assignType: kind.assignType,
 | 
			
		||||
                    subject: this.lowerExpr(kind.subject),
 | 
			
		||||
                    value: this.lowerExpr(kind.value),
 | 
			
		||||
                }, stmt.span);
 | 
			
		||||
            case "expr":
 | 
			
		||||
                return this.ctx.internStmt({
 | 
			
		||||
                    tag: "expr",
 | 
			
		||||
                    expr: this.lowerExpr(kind.expr),
 | 
			
		||||
                }, stmt.span);
 | 
			
		||||
        }
 | 
			
		||||
        exhausted(kind);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerLetStmt(stmt: ast.Stmt, kind: ast.LetStmt): StmtId {
 | 
			
		||||
        return this.ctx.internStmt({
 | 
			
		||||
            tag: "let",
 | 
			
		||||
            pat: this.lowerPat(kind.pat),
 | 
			
		||||
            ty: kind.ty && this.lowerTy(kind.ty),
 | 
			
		||||
            expr: kind.expr && this.lowerExpr(kind.expr),
 | 
			
		||||
        }, stmt.span);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerItem(item: ast.Item): ItemId {
 | 
			
		||||
        return todo();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerPat(pat: ast.Pat): PatId {
 | 
			
		||||
        return todo();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerTy(ty: ast.Ty): TyId {
 | 
			
		||||
        return todo();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lowerExpr(expr: ast.Expr): ExprId {
 | 
			
		||||
        return todo();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html
 | 
			
		||||
type Rib = {
 | 
			
		||||
    kind: RibKind;
 | 
			
		||||
    bindings: Map<IdentId, Res>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
 | 
			
		||||
type RibKind =
 | 
			
		||||
    | { tag: "normal" }
 | 
			
		||||
    | { tag: "fn" }
 | 
			
		||||
    | { tag: "item"; defKind: DefKind }
 | 
			
		||||
    | { tag: "mod" };
 | 
			
		||||
 | 
			
		||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/enum.RibKind.html
 | 
			
		||||
type Res =
 | 
			
		||||
    | { tag: "error" }
 | 
			
		||||
    | { tag: "def"; kind: DefKind; id: DefId }
 | 
			
		||||
    | { tag: "local"; id: DefId };
 | 
			
		||||
 | 
			
		||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.DefKind.html
 | 
			
		||||
type DefKind =
 | 
			
		||||
    | { type: "mod" }
 | 
			
		||||
    | { type: "struct" }
 | 
			
		||||
    | { type: "enum" }
 | 
			
		||||
    | { type: "variant" }
 | 
			
		||||
    | { type: "ty_alias" }
 | 
			
		||||
    | { type: "ty_param" }
 | 
			
		||||
    | { type: "fn" }
 | 
			
		||||
    | { type: "ctor" }
 | 
			
		||||
    | { type: "use" }
 | 
			
		||||
    | { type: "field" };
 | 
			
		||||
@ -56,7 +56,7 @@ export class Lexer {
 | 
			
		||||
            if (keywords.includes(value)) {
 | 
			
		||||
                return this.token(value, pos);
 | 
			
		||||
            } else {
 | 
			
		||||
                return { ...this.token("ident", pos), identValue: value };
 | 
			
		||||
                return { ...this.token("ident", pos), identId: value };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (this.test(/[1-9]/)) {
 | 
			
		||||
 | 
			
		||||
@ -199,7 +199,7 @@ export class Parser {
 | 
			
		||||
                this.report("expected 'ident'");
 | 
			
		||||
                return this.stmt({ type: "error" }, spos);
 | 
			
		||||
            }
 | 
			
		||||
            const ident = this.current().identValue!;
 | 
			
		||||
            const ident = this.current().identId!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            const args: Expr[] = [];
 | 
			
		||||
            if (this.test("(")) {
 | 
			
		||||
@ -250,7 +250,7 @@ export class Parser {
 | 
			
		||||
            this.report("expected 'ident'");
 | 
			
		||||
            return this.stmt({ type: "error" }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        const ident = this.current().identValue!;
 | 
			
		||||
        const ident = this.current().identId!;
 | 
			
		||||
        this.step();
 | 
			
		||||
        if (this.test(";")) {
 | 
			
		||||
            this.eatSemicolon();
 | 
			
		||||
@ -290,7 +290,7 @@ export class Parser {
 | 
			
		||||
            this.report("expected ident");
 | 
			
		||||
            return this.stmt({ type: "error" }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        const ident = this.current().identValue!;
 | 
			
		||||
        const ident = this.current().identId!;
 | 
			
		||||
        this.step();
 | 
			
		||||
        let genericParams: GenericParam[] | undefined;
 | 
			
		||||
        if (this.test("<")) {
 | 
			
		||||
@ -333,7 +333,7 @@ export class Parser {
 | 
			
		||||
    private parseETypeParam(index: number): Res<GenericParam> {
 | 
			
		||||
        const pos = this.pos();
 | 
			
		||||
        if (this.test("ident")) {
 | 
			
		||||
            const ident = this.current().identValue!;
 | 
			
		||||
            const ident = this.current().identId!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            return {
 | 
			
		||||
                ok: true,
 | 
			
		||||
@ -394,7 +394,7 @@ export class Parser {
 | 
			
		||||
                mut = true;
 | 
			
		||||
                this.step();
 | 
			
		||||
            }
 | 
			
		||||
            const ident = this.current().identValue!;
 | 
			
		||||
            const ident = this.current().identId!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            if (this.test(":")) {
 | 
			
		||||
                this.step();
 | 
			
		||||
@ -637,7 +637,7 @@ export class Parser {
 | 
			
		||||
            this.report("expected 'ident'");
 | 
			
		||||
            return { ok: false, pos };
 | 
			
		||||
        }
 | 
			
		||||
        const ident = this.current().identValue!;
 | 
			
		||||
        const ident = this.current().identId!;
 | 
			
		||||
        this.step();
 | 
			
		||||
        if (!this.test(":")) {
 | 
			
		||||
            this.report("expected ':'");
 | 
			
		||||
@ -856,7 +856,7 @@ export class Parser {
 | 
			
		||||
            this.report("expected ident");
 | 
			
		||||
            return this.expr({ type: "error" }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        const ident = this.current().identValue!;
 | 
			
		||||
        const ident = this.current().identId!;
 | 
			
		||||
        this.step();
 | 
			
		||||
        return this.expr({ type: "field", subject, ident }, pos);
 | 
			
		||||
    }
 | 
			
		||||
@ -890,7 +890,7 @@ export class Parser {
 | 
			
		||||
            this.report("expected ident");
 | 
			
		||||
            return this.expr({ type: "error" }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        const ident = this.current().identValue!;
 | 
			
		||||
        const ident = this.current().identId!;
 | 
			
		||||
        this.step();
 | 
			
		||||
        return this.expr({ type: "path", subject, ident }, pos);
 | 
			
		||||
    }
 | 
			
		||||
@ -906,7 +906,7 @@ export class Parser {
 | 
			
		||||
    private parseOperand(): Expr {
 | 
			
		||||
        const pos = this.pos();
 | 
			
		||||
        if (this.test("ident")) {
 | 
			
		||||
            const ident = this.current().identValue!;
 | 
			
		||||
            const ident = this.current().identId!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            return this.expr({ type: "ident", ident }, pos);
 | 
			
		||||
        }
 | 
			
		||||
@ -975,7 +975,7 @@ export class Parser {
 | 
			
		||||
            return this.etype({ type }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.test("ident")) {
 | 
			
		||||
            const ident = this.current().identValue!;
 | 
			
		||||
            const ident = this.current().identId!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            return this.etype({ type: "ident", ident: ident }, pos);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ export class Lexer implements TokenIter {
 | 
			
		||||
                        ? this.token(val, span)
 | 
			
		||||
                        : this.token("ident", span, {
 | 
			
		||||
                            type: "ident",
 | 
			
		||||
                            identValue: val,
 | 
			
		||||
                            identId: this.ctx.internIdent(val),
 | 
			
		||||
                        });
 | 
			
		||||
                },
 | 
			
		||||
                /[a-zA-Z_]/,
 | 
			
		||||
@ -127,8 +127,8 @@ export class Lexer implements TokenIter {
 | 
			
		||||
                return this.token("error", { begin, end });
 | 
			
		||||
            }
 | 
			
		||||
            this.step();
 | 
			
		||||
            return this.token("string", { begin, end }, {
 | 
			
		||||
                type: "string",
 | 
			
		||||
            return this.token("str", { begin, end }, {
 | 
			
		||||
                type: "str",
 | 
			
		||||
                stringValue: value,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
@ -275,7 +275,7 @@ const keywords = new Set([
 | 
			
		||||
    "null",
 | 
			
		||||
    "int",
 | 
			
		||||
    "bool",
 | 
			
		||||
    "string",
 | 
			
		||||
    "str",
 | 
			
		||||
    "return",
 | 
			
		||||
    "break",
 | 
			
		||||
    "continue",
 | 
			
		||||
 | 
			
		||||
@ -280,7 +280,7 @@ export class Parser {
 | 
			
		||||
            return this.stmt({ tag: "error" }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        const ident = this.parseIdent();
 | 
			
		||||
        if (this.test("string")) {
 | 
			
		||||
        if (this.test("str")) {
 | 
			
		||||
            const filePath = this.current().stringValue!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            this.eatSemicolon();
 | 
			
		||||
@ -965,10 +965,10 @@ export class Parser {
 | 
			
		||||
            this.step();
 | 
			
		||||
            return this.expr({ tag: "int", value }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.test("string")) {
 | 
			
		||||
        if (this.test("str")) {
 | 
			
		||||
            const value = this.current().stringValue!;
 | 
			
		||||
            this.step();
 | 
			
		||||
            return this.expr({ tag: "string", value }, pos);
 | 
			
		||||
            return this.expr({ tag: "str", value }, pos);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.test("false")) {
 | 
			
		||||
            this.step();
 | 
			
		||||
@ -1054,12 +1054,12 @@ export class Parser {
 | 
			
		||||
 | 
			
		||||
    private parseTy(): Ty {
 | 
			
		||||
        const pos = this.span();
 | 
			
		||||
        if (["null", "int", "bool", "string"].includes(this.current().type)) {
 | 
			
		||||
        if (["null", "int", "bool", "str"].includes(this.current().type)) {
 | 
			
		||||
            const tag = this.current().type as
 | 
			
		||||
                | "null"
 | 
			
		||||
                | "int"
 | 
			
		||||
                | "bool"
 | 
			
		||||
                | "string";
 | 
			
		||||
                | "str";
 | 
			
		||||
            this.step();
 | 
			
		||||
            return this.ty({ tag }, pos);
 | 
			
		||||
        }
 | 
			
		||||
@ -1225,7 +1225,7 @@ export class Parser {
 | 
			
		||||
    private parseIdent(): Ident {
 | 
			
		||||
        const tok = this.current();
 | 
			
		||||
        this.step();
 | 
			
		||||
        return { text: tok.identValue!, span: tok.span };
 | 
			
		||||
        return { id: tok.identId!, span: tok.span };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private step() {
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
import { IdentId } from "../ctx.ts";
 | 
			
		||||
import { Span } from "../diagnostics.ts";
 | 
			
		||||
 | 
			
		||||
export type Token = {
 | 
			
		||||
    type: string;
 | 
			
		||||
    span: Span;
 | 
			
		||||
    length: number;
 | 
			
		||||
    identValue?: string;
 | 
			
		||||
    identId?: IdentId;
 | 
			
		||||
    intValue?: number;
 | 
			
		||||
    stringValue?: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								compiler/program.slg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								compiler/program.slg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
 | 
			
		||||
fn main() -> int {
 | 
			
		||||
    let a = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user