mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-30 14:50:53 +00:00
add ast stuff
This commit is contained in:
parent
6a5fce18fe
commit
ab5a830f66
@ -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 };
|
||||
|
@ -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<P>,
|
||||
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<P>,
|
||||
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<P>,
|
||||
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<P>,
|
||||
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<P>,
|
||||
ident: Ident,
|
||||
...p: P
|
||||
) {
|
||||
v.visitIdent?.(ident, ...p);
|
||||
}
|
||||
|
@ -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<void> {
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user