mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-30 22:20:54 +00:00
add ast stuff
This commit is contained in:
parent
6a5fce18fe
commit
ab5a830f66
@ -5,22 +5,149 @@ export type File = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type Stmt = {
|
export type Stmt = {
|
||||||
id: number;
|
|
||||||
kind: StmtKind;
|
kind: StmtKind;
|
||||||
span: Span;
|
span: Span;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StmtKind =
|
export type StmtKind =
|
||||||
| { tag: "error" }
|
| { tag: "error" }
|
||||||
| { tag: "mod_block" } & ModBlockStmt
|
| { tag: "item" } & ItemStmt
|
||||||
| { tag: "mod_file" } & ModFileStmt;
|
| { tag: "let" } & LetStmt
|
||||||
|
| { tag: "return" } & ReturnStmt
|
||||||
|
| { tag: "break" } & BreakStmt
|
||||||
|
| { tag: "assign" } & AssignStmt
|
||||||
|
| { tag: "expr" } & ExprStmt;
|
||||||
|
|
||||||
export type ModBlockStmt = {
|
export type ItemStmt = { item: Item };
|
||||||
ident: string;
|
|
||||||
|
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[];
|
stmts: Stmt[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ModFileStmt = {
|
export type ModFileItem = {
|
||||||
ident: string;
|
ident: Ident;
|
||||||
filePath: string;
|
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 { 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;
|
export type VisitRes = "stop" | void;
|
||||||
|
|
||||||
@ -12,8 +39,36 @@ export interface Visitor<
|
|||||||
visitFile?(file: File, ...p: P): R;
|
visitFile?(file: File, ...p: P): R;
|
||||||
visitStmt?(stmt: Stmt, ...p: P): R;
|
visitStmt?(stmt: Stmt, ...p: P): R;
|
||||||
visitErrorStmt?(stmt: Stmt, ...p: P): R;
|
visitErrorStmt?(stmt: Stmt, ...p: P): R;
|
||||||
visitModBlockStmt?(stmt: Stmt, kind: ModBlockStmt, ...p: P): R;
|
visitItemStmt?(stmt: Stmt, kind: ItemStmt, ...p: P): R;
|
||||||
visitModFileStmt?(stmt: Stmt, kind: ModFileStmt, ...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<
|
export function visitFile<
|
||||||
@ -46,17 +101,136 @@ export function visitStmt<
|
|||||||
stmt: Stmt,
|
stmt: Stmt,
|
||||||
...p: P
|
...p: P
|
||||||
) {
|
) {
|
||||||
switch (stmt.kind.tag) {
|
const kind = stmt.kind;
|
||||||
|
switch (kind.tag) {
|
||||||
case "error":
|
case "error":
|
||||||
if (v.visitErrorStmt?.(stmt, ...p) === "stop") return;
|
if (v.visitErrorStmt?.(stmt, ...p) === "stop") return;
|
||||||
return;
|
return;
|
||||||
case "mod_block":
|
case "item":
|
||||||
if (v.visitModBlockStmt?.(stmt, stmt.kind, ...p) === "stop") return;
|
if (v.visitItemStmt?.(stmt, kind, ...p) === "stop") return;
|
||||||
visitStmts(v, stmt.kind.stmts, ...p);
|
|
||||||
return;
|
return;
|
||||||
case "mod_file":
|
case "let":
|
||||||
if (v.visitModFileStmt?.(stmt, stmt.kind, ...p) === "stop") return;
|
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;
|
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 {
|
export class PackCompiler {
|
||||||
|
private ctx = new Ctx();
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private entryFilePath: string,
|
private entryFilePath: string,
|
||||||
private emitter: PackEmitter,
|
private emitter: PackEmitter,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public compile() {
|
public compile() {
|
||||||
|
FileTreeAstCollector
|
||||||
|
.fromEntryFile(this.ctx, this.entryFilePath)
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type _P = { file: File };
|
type _P = { file: File };
|
||||||
export class FileTreeCollector implements ast.Visitor<[_P]> {
|
export class FileTreeAstCollector implements ast.Visitor<[_P]> {
|
||||||
private subFilePromise = Promise.resolve();
|
private subFilePromise = Promise.resolve();
|
||||||
|
|
||||||
public constructor(
|
private constructor(
|
||||||
private ctx: Ctx,
|
private ctx: Ctx,
|
||||||
private superFile: File | undefined,
|
private superFile: File | undefined,
|
||||||
private ident: string,
|
private ident: string,
|
||||||
@ -36,6 +41,19 @@ export class FileTreeCollector implements ast.Visitor<[_P]> {
|
|||||||
private relPath: string,
|
private relPath: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public static fromEntryFile(
|
||||||
|
ctx: Ctx,
|
||||||
|
entryFilePath: string,
|
||||||
|
): FileTreeAstCollector {
|
||||||
|
return new FileTreeAstCollector(
|
||||||
|
ctx,
|
||||||
|
undefined,
|
||||||
|
"root",
|
||||||
|
entryFilePath,
|
||||||
|
entryFilePath,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public async collect(): Promise<void> {
|
public async collect(): Promise<void> {
|
||||||
const text = await Deno.readTextFile(this.absPath);
|
const text = await Deno.readTextFile(this.absPath);
|
||||||
const file = this.ctx.addFile(
|
const file = this.ctx.addFile(
|
||||||
@ -51,12 +69,12 @@ export class FileTreeCollector implements ast.Visitor<[_P]> {
|
|||||||
await this.subFilePromise;
|
await this.subFilePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitModFileStmt(
|
visitModFileItem(
|
||||||
stmt: ast.Stmt,
|
item: ast.Item,
|
||||||
kind: ast.ModFileStmt,
|
kind: ast.ModFileItem,
|
||||||
{ file }: _P,
|
{ file }: _P,
|
||||||
): ast.VisitRes {
|
): ast.VisitRes {
|
||||||
const { ident, filePath: relPath } = kind;
|
const { ident: { text: ident }, filePath: relPath } = kind;
|
||||||
const absPath = path.join(path.dirname(this.absPath), relPath);
|
const absPath = path.join(path.dirname(this.absPath), relPath);
|
||||||
this.subFilePromise = this.subFilePromise
|
this.subFilePromise = this.subFilePromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -65,10 +83,11 @@ export class FileTreeCollector implements ast.Visitor<[_P]> {
|
|||||||
severity: "fatal",
|
severity: "fatal",
|
||||||
msg: `module '${ident}' already declared`,
|
msg: `module '${ident}' already declared`,
|
||||||
file,
|
file,
|
||||||
span: stmt.span,
|
span: item.span,
|
||||||
});
|
});
|
||||||
|
Deno.exit(1);
|
||||||
}
|
}
|
||||||
return new FileTreeCollector(
|
return new FileTreeAstCollector(
|
||||||
this.ctx,
|
this.ctx,
|
||||||
file,
|
file,
|
||||||
ident,
|
ident,
|
||||||
|
Loading…
Reference in New Issue
Block a user