UNPKG

aran

Version:
245 lines (232 loc) 6.65 kB
import type { Atom, Node, Parameter, Program, RoutineBlock, SegmentBlock, Statement, Effect, Expression, ResolvePartialAtom, } from "../../lang/syntax.d.ts"; import type { GetDefault, Json } from "../../util/util.d.ts"; import type { ValueOf } from "../../util/util.d.ts"; export type BlockPointcut<atom extends Atom, point extends Json[]> = ( node: SegmentBlock<atom> | RoutineBlock<atom>, parent: Node<atom>, root: Program<atom>, ) => undefined | null | point; export type StatementPointcut<atom extends Atom, point extends Json[]> = ( node: Statement<atom>, parent: Node<atom>, root: Program<atom>, ) => undefined | null | point; export type EffectPointcut<atom extends Atom, point extends Json[]> = ( node: Effect<atom>, parent: Node<atom>, root: Program<atom>, ) => undefined | null | point; export type ExpressionPointcut<atom extends Atom, point extends Json[]> = ( node: Expression<atom>, parent: Node<atom>, root: Program<atom>, ) => undefined | null | point; type Frame<variable extends string, value> = { [identifier in variable | Parameter]: value; }; /** * The flexible weaving API expects each advice function to be a global value. * It is more complex to use than the standard weaving API but it let the user * define the static information provided to the advice functions. Unlike the * standard weaving API, each join point can be cut multiple times. NB: the join * points `apply@around` and `construct@around` can only be cut once. The join * points of the flexible weaving API are very similar to the join points of the * standard API. */ export type AspectTyping< atom extends Atom, point extends Json[], runtime extends { State: unknown; Value: unknown; }, > = { // block // "block@setup": { pointcut: BlockPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => runtime["State"]; }; "block@before": { pointcut: BlockPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; "block@declaration": { pointcut: BlockPointcut<atom, point>; advice: ( state: runtime["State"], frame: Frame<atom["Variable"], runtime["Value"]>, ...point: point ) => void; }; "block@declaration-overwrite": { pointcut: BlockPointcut<atom, point>; advice: ( state: runtime["State"], frame: Frame<atom["Variable"], runtime["Value"]>, ...point: point ) => Frame<atom["Variable"], runtime["Value"]>; }; "block@after": { pointcut: BlockPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; "block@throwing": { pointcut: BlockPointcut<atom, point>; advice: ( state: runtime["State"], error: runtime["Value"], ...point: point ) => runtime["Value"]; }; "block@teardown": { pointcut: BlockPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; // statement // "statement@before": { pointcut: StatementPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; "statement@after": { pointcut: StatementPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; // effect // "effect@before": { pointcut: EffectPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; "effect@after": { pointcut: EffectPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; // expression // "expression@before": { pointcut: ExpressionPointcut<atom, point>; advice: (state: runtime["State"], ...point: point) => void; }; "expression@after": { pointcut: ExpressionPointcut<atom, point>; advice: ( state: runtime["State"], result: runtime["Value"], ...point: point ) => runtime["Value"]; }; // apply - construct // "apply@around": { pointcut: ExpressionPointcut<atom, point>; advice: ( state: runtime["State"], callee: runtime["Value"], this_: runtime["Value"], arguments_: runtime["Value"][], ...point: point ) => runtime["Value"]; }; "construct@around": { pointcut: ExpressionPointcut<atom, point>; advice: ( state: runtime["State"], callee: runtime["Value"], arguments_: runtime["Value"][], ...point: point ) => runtime["Value"]; }; }; export type AspectKind = keyof AspectTyping<never, never, never>; export type PointcutElement< kind extends AspectKind, atom extends Atom, point extends Json[], > = AspectTyping<atom, point, { State: never; Value: never }>[kind]["pointcut"]; export type AdviceElement< kind extends AspectKind, atom extends { Variable: string }, point extends Json[], runtime extends { State: unknown; Value: unknown }, > = AspectTyping< atom & { Label: never; Specifier: never; Source: never; Tag: never }, point, runtime >[kind]["advice"]; export type Aspect< param extends Partial<Atom> & { AdviceGlobalVariable?: string; State?: unknown; Value?: unknown; Point?: Json[]; } = {}, > = { [key in param["AdviceGlobalVariable"] & string]: ValueOf<{ [key in AspectKind]: { kind: key; pointcut: PointcutElement< key, ResolvePartialAtom<param>, GetDefault<param, "Point", Json[]> >; advice: AdviceElement< key, { Variable: GetDefault<param, "Variable", string> }, GetDefault<param, "Point", Json[]>, { State: GetDefault<param, "State", null>; Value: GetDefault<param, "Value", unknown>; } >; }; }>; }; export type Pointcut< param extends Partial<Atom> & { AdviceGlobalVariable?: string; Point?: Json[]; } = {}, > = { [key in param["AdviceGlobalVariable"] & string]: ValueOf<{ [key in AspectKind]: { kind: key; pointcut: PointcutElement< key, ResolvePartialAtom<param>, GetDefault<param, "Point", Json[]> >; }; }>; }; export type Advice< param extends { AdviceGlobalVariable?: string; State?: unknown; Value?: unknown; Variable?: string; Point?: Json[]; } = {}, > = { [key in param["AdviceGlobalVariable"] & string]: ValueOf<{ [key in AspectKind]: { kind: key; advice: AdviceElement< key, { Variable: GetDefault<param, "Variable", string> }, GetDefault<param, "Point", Json[]>, { State: GetDefault<param, "State", null>; Value: GetDefault<param, "Value", unknown>; } >; }; }>; };