diff --git a/compiler/ast/ast.ts b/compiler/ast/ast.ts index 2a16763..4fe94be 100644 --- a/compiler/ast/ast.ts +++ b/compiler/ast/ast.ts @@ -5,22 +5,149 @@ export type File = { }; export type Stmt = { - id: number; kind: StmtKind; span: Span; }; export type StmtKind = | { tag: "error" } - | { tag: "mod_block" } & ModBlockStmt - | { tag: "mod_file" } & ModFileStmt; + | { tag: "item" } & ItemStmt + | { tag: "let" } & LetStmt + | { tag: "return" } & ReturnStmt + | { tag: "break" } & BreakStmt + | { tag: "assign" } & AssignStmt + | { tag: "expr" } & ExprStmt; -export type ModBlockStmt = { - ident: string; +export type ItemStmt = { item: Item }; + +export type LetStmt = { + subject: Pat; + 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 = { + 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: "static" } & StaticItem + | { tag: "type_alias" } & TypeAliasItem; + +export type ModBlockItem = { + ident: Ident; stmts: Stmt[]; }; -export type ModFileStmt = { - ident: string; +export type ModFileItem = { + ident: Ident; filePath: string; }; + +export type EnumItem = { variants: Variant[] }; +export type StructItem = { data: VariantData }; +export type FnItem = { _: 0 }; +export type UseItem = { _: 0 }; +export type StaticItem = { _: 0 }; +export type TypeAliasItem = { _: 0 }; + +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 Expr = { + kind: ExprKind; + span: Span; +}; + +export type ExprKind = + | { tag: "error" } + | { tag: "ident" } & Ident; + +export type Pat = { + kind: PatKind; + span: Span; +}; + +export type PatKind = + | { tag: "error" } + | { tag: "bind" } & BindPat; + +export type BindPat = { + ident: Ident; + mut: boolean; +}; + +export type Ty = { + kind: TyKind; + span: Span; +}; + +export type TyKind = + | { tag: "error" } + | { tag: "ident" } & Ident + | { tag: "ref" } & RefTy + | { tag: "ptr" } & PtrTy + | { tag: "slice" } & SliceTy + | { tag: "array" } & ArrayTy; + +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 StructTy = { fields: FieldDef[] }; + +export type AnonFieldDef = { + ident: Ident; + ty: Ty; + span: Span; +}; + +export type Ident = { text: string; span: Span }; diff --git a/compiler/ast/visitor.ts b/compiler/ast/visitor.ts index 7c4ed88..17b9bd0 100644 --- a/compiler/ast/visitor.ts +++ b/compiler/ast/visitor.ts @@ -1,5 +1,32 @@ import { exhausted } from "../util.ts"; -import { File, ModBlockStmt, ModFileStmt, Stmt } from "./ast.ts"; +import { + ArrayTy, + AssignStmt, + BindPat, + BreakStmt, + EnumItem, + Expr, + ExprStmt, + File, + FnItem, + Ident, + Item, + ItemStmt, + LetStmt, + ModBlockItem, + ModFileItem, + Pat, + PtrTy, + RefTy, + ReturnStmt, + SliceTy, + StaticItem, + Stmt, + StructItem, + Ty, + TypeAliasItem, + UseItem, +} from "./ast.ts"; export type VisitRes = "stop" | void; @@ -12,8 +39,36 @@ export interface Visitor< visitFile?(file: File, ...p: P): R; visitStmt?(stmt: Stmt, ...p: P): R; visitErrorStmt?(stmt: Stmt, ...p: P): R; - visitModBlockStmt?(stmt: Stmt, kind: ModBlockStmt, ...p: P): R; - visitModFileStmt?(stmt: Stmt, kind: ModFileStmt, ...p: P): R; + visitItemStmt?(stmt: Stmt, kind: ItemStmt, ...p: P): R; + visitLetStmt?(stmt: Stmt, kind: LetStmt, ...p: P): R; + visitReturnStmt?(stmt: Stmt, kind: ReturnStmt, ...p: P): R; + visitBreakStmt?(stmt: Stmt, kind: BreakStmt, ...p: P): R; + visitAssignStmt?(stmt: Stmt, kind: AssignStmt, ...p: P): R; + visitExprStmt?(stmt: Stmt, kind: ExprStmt, ...p: P): R; + visitItem?(item: Item, ...p: P): R; + visitErrorItem?(item: Item, ...p: P): R; + visitModBlockItem?(item: Item, kind: ModBlockItem, ...p: P): R; + visitModFileItem?(item: Item, kind: ModFileItem, ...p: P): R; + visitEnumItem?(item: Item, kind: EnumItem, ...p: P): R; + visitStructItem?(item: Item, kind: StructItem, ...p: P): R; + visitFnItem?(item: Item, kind: FnItem, ...p: P): R; + visitUseItem?(item: Item, kind: UseItem, ...p: P): R; + visitStaticItem?(item: Item, kind: StaticItem, ...p: P): R; + visitTypeAliasItem?(item: Item, kind: TypeAliasItem, ...p: P): R; + visitExpr?(expr: Expr, ...p: P): R; + visitErrorExpr?(expr: Expr, ...p: P): R; + visitIdentExpr?(expr: Expr, kind: Ident, ...p: P): R; + visitPat?(pat: Pat, ...p: P): R; + visitErrorPat?(pat: Pat, ...p: P): R; + visitBindPat?(pat: Pat, kind: BindPat, ...p: P): R; + visitTy?(ty: Ty, ...p: P): R; + visitErrorTy?(ty: Ty, ...p: P): R; + visitIdentTy?(ty: Ty, kind: Ident, ...p: P): R; + visitRefTy?(ty: Ty, kind: RefTy, ...p: P): R; + visitPtrTy?(ty: Ty, kind: PtrTy, ...p: P): R; + visitSliceTy?(ty: Ty, kind: SliceTy, ...p: P): R; + visitArrayTy?(ty: Ty, kind: ArrayTy, ...p: P): R; + visitIdent?(ident: Ident, ...p: P): R; } export function visitFile< @@ -46,17 +101,136 @@ export function visitStmt< stmt: Stmt, ...p: P ) { - switch (stmt.kind.tag) { + const kind = stmt.kind; + switch (kind.tag) { case "error": if (v.visitErrorStmt?.(stmt, ...p) === "stop") return; return; - case "mod_block": - if (v.visitModBlockStmt?.(stmt, stmt.kind, ...p) === "stop") return; - visitStmts(v, stmt.kind.stmts, ...p); + case "item": + if (v.visitItemStmt?.(stmt, kind, ...p) === "stop") return; return; - case "mod_file": - if (v.visitModFileStmt?.(stmt, stmt.kind, ...p) === "stop") return; + case "let": + if (v.visitLetStmt?.(stmt, kind, ...p) === "stop") return; + return; + case "return": + if (v.visitReturnStmt?.(stmt, kind, ...p) === "stop") return; + return; + case "break": + if (v.visitBreakStmt?.(stmt, kind, ...p) === "stop") return; + return; + case "assign": + if (v.visitAssignStmt?.(stmt, kind, ...p) === "stop") return; + return; + case "expr": + if (v.visitExprStmt?.(stmt, kind, ...p) === "stop") return; return; } - exhausted(stmt.kind); + exhausted(kind); +} + +export function visitItem< + P extends PM = [], +>( + v: Visitor
, + item: Item, + ...p: P +) { + const kind = item.kind; + switch (kind.tag) { + case "error": + if (v.visitErrorItem?.(item, ...p) === "stop") return; + return; + case "mod_block": + if (v.visitModBlockItem?.(item, kind, ...p) === "stop") return; + return; + case "mod_file": + if (v.visitModFileItem?.(item, kind, ...p) === "stop") return; + return; + case "enum": + if (v.visitEnumItem?.(item, kind, ...p) === "stop") return; + return; + case "struct": + if (v.visitStructItem?.(item, kind, ...p) === "stop") return; + return; + case "fn": + if (v.visitFnItem?.(item, kind, ...p) === "stop") return; + return; + case "use": + if (v.visitUseItem?.(item, kind, ...p) === "stop") return; + return; + case "static": + if (v.visitStaticItem?.(item, kind, ...p) === "stop") return; + return; + case "type_alias": + if (v.visitTypeAliasItem?.(item, kind, ...p) === "stop") return; + return; + } + exhausted(kind); +} + +export function visitExpr< + P extends PM = [], +>( + v: Visitor
, + expr: Expr, + ...p: P +) { + const kind = expr.kind; + switch (kind.tag) { + case "error": + if (v.visitErrorExpr?.(expr, ...p) === "stop") return; + return; + case "ident": + if (v.visitIdentExpr?.(expr, kind, ...p) === "stop") return; + return; + } + exhausted(kind); +} + +export function visitPat< + P extends PM = [], +>( + v: Visitor
, + pat: Pat, + ...p: P +) { + const kind = pat.kind; + switch (kind.tag) { + case "error": + if (v.visitErrorPat?.(pat, ...p) === "stop") return; + return; + case "bind": + if (v.visitBindPat?.(pat, kind, ...p) === "stop") return; + return; + } + exhausted(kind); +} + +export function visitTy< + P extends PM = [], +>( + v: Visitor
, + ty: Ty, + ...p: P +) { + const kind = ty.kind; + switch (kind.tag) { + case "error": + if (v.visitErrorTy?.(ty, ...p) === "stop") return; + return; + case "ident": + if (v.visitIdentTy?.(ty, kind, ...p) === "stop") return; + return; + } + exhausted(kind); +} + +export function visitIdent< + P extends PM = [], +>( + v: Visitor
,
+ ident: Ident,
+ ...p: P
+) {
+ v.visitIdent?.(ident, ...p);
}
diff --git a/compiler/main.ts b/compiler/main.ts
index 5dcf461..6cbe952 100644
--- a/compiler/main.ts
+++ b/compiler/main.ts
@@ -15,20 +15,25 @@ export interface PackEmitter {
}
export class PackCompiler {
+ private ctx = new Ctx();
+
public constructor(
private entryFilePath: string,
private emitter: PackEmitter,
) {}
public compile() {
+ FileTreeAstCollector
+ .fromEntryFile(this.ctx, this.entryFilePath)
+ .collect();
}
}
type _P = { file: File };
-export class FileTreeCollector implements ast.Visitor<[_P]> {
+export class FileTreeAstCollector implements ast.Visitor<[_P]> {
private subFilePromise = Promise.resolve();
- public constructor(
+ private constructor(
private ctx: Ctx,
private superFile: File | undefined,
private ident: string,
@@ -36,6 +41,19 @@ export class FileTreeCollector implements ast.Visitor<[_P]> {
private relPath: string,
) {}
+ public static fromEntryFile(
+ ctx: Ctx,
+ entryFilePath: string,
+ ): FileTreeAstCollector {
+ return new FileTreeAstCollector(
+ ctx,
+ undefined,
+ "root",
+ entryFilePath,
+ entryFilePath,
+ );
+ }
+
public async collect(): Promise