import * as a from './syntax/ast.ts';import { AstDefaultMapper, IAstPartialMapper, astMapper, IAstMapper } from './ast-mapper.ts';import { ReplaceReturnType } from './utils.ts';
export type IAstPartialVisitor = { [key in keyof IAstPartialMapper]: ReplaceReturnType<IAstPartialMapper[key], any> }export type IAstFullVisitor = { [key in keyof IAstPartialVisitor]-?: IAstPartialVisitor[key];}
export type IAstVisitor = IAstFullVisitor & { super(): IAstVisitor;}
class Visitor { mapper?: IAstMapper; visitor?: IAstPartialVisitor;
super() { return new SkipVisitor(this); }}
const mapperProto = AstDefaultMapper.prototype as any;for (const k of Object.getOwnPropertyNames(mapperProto)) { const orig = mapperProto[k] as Function; if (k === 'constructor' || k === 'super' || typeof orig !== 'function') { continue; } Object.defineProperty(Visitor.prototype, k, { configurable: false, get() { return function (this: Visitor, ...args: any[]) { const impl = (this.visitor as any)[k] as Function; if (!impl) { return orig.apply(this, args); } impl.apply(this.visitor, args); return args[0]; } } })}
class SkipVisitor { constructor(readonly parent: Visitor) { }}
for (const k of Object.getOwnPropertyNames(mapperProto)) { const orig = mapperProto[k] as Function; if (k === 'constructor' || k === 'super' || typeof orig !== 'function') { continue; } Object.defineProperty(SkipVisitor.prototype, k, { configurable: false, get() { return function (this: SkipVisitor, ...args: []) { return orig.apply(this.parent, args); } } });}
export function astVisitor<T extends IAstPartialVisitor = IAstPartialVisitor>(visitorBuilder: (defaultImplem: IAstVisitor) => T): IAstVisitor { return astMapper(m => { const ret = new Visitor(); ret.mapper = m; ret.visitor = visitorBuilder(ret as any); return ret as any; })}