From ab5a830f6629f9967beff0d873dca43b704ce78d Mon Sep 17 00:00:00 2001 From: SimonFJ20 Date: Thu, 23 Jan 2025 14:19:27 +0100 Subject: [PATCH] add ast stuff --- compiler/ast/ast.ts | 141 +++++++++++++++++++++++++++-- compiler/ast/visitor.ts | 194 +++++++++++++++++++++++++++++++++++++--- compiler/main.ts | 35 ++++++-- 3 files changed, 345 insertions(+), 25 deletions(-) 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 { const text = await Deno.readTextFile(this.absPath); const file = this.ctx.addFile( @@ -51,12 +69,12 @@ export class FileTreeCollector implements ast.Visitor<[_P]> { await this.subFilePromise; } - visitModFileStmt( - stmt: ast.Stmt, - kind: ast.ModFileStmt, + visitModFileItem( + item: ast.Item, + kind: ast.ModFileItem, { file }: _P, ): ast.VisitRes { - const { ident, filePath: relPath } = kind; + const { ident: { text: ident }, filePath: relPath } = kind; const absPath = path.join(path.dirname(this.absPath), relPath); this.subFilePromise = this.subFilePromise .then(() => { @@ -65,10 +83,11 @@ export class FileTreeCollector implements ast.Visitor<[_P]> { severity: "fatal", msg: `module '${ident}' already declared`, file, - span: stmt.span, + span: item.span, }); + Deno.exit(1); } - return new FileTreeCollector( + return new FileTreeAstCollector( this.ctx, file, ident,