import { exhausted } from "../util.ts"; import { File, ModBlockStmt, ModFileStmt, Stmt } from "./ast.ts"; export type VisitRes = "stop" | void; type R = VisitRes; type PM = unknown[]; export interface Visitor< P extends PM = [], > { 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; } export function visitFile< P extends PM = [], >( v: Visitor
, file: File, ...p: P ) { if (v.visitFile?.(file, ...p) === "stop") return; visitStmts(v, file.stmts, ...p); } export function visitStmts< P extends PM = [], >( v: Visitor
, stmts: Stmt[], ...p: P ) { for (const stmt of stmts) { visitStmt(v, stmt, ...p); } } export function visitStmt< P extends PM = [], >( v: Visitor
, stmt: Stmt, ...p: P ) { switch (stmt.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); return; case "mod_file": if (v.visitModFileStmt?.(stmt, stmt.kind, ...p) === "stop") return; return; } exhausted(stmt.kind); }