declare module '@glimmer/interfaces/lib/program' { import type { Encoder } from "@glimmer/interfaces/lib/compile/index.js"; import type { ComponentDefinition, ComponentDefinitionState } from "@glimmer/interfaces/lib/components.js"; import type { Nullable } from "@glimmer/interfaces/lib/core.js"; import type { Environment, HelperDefinitionState, Owner, Program } from "@glimmer/interfaces/lib/runtime.js"; import type { ModifierDefinitionState } from "@glimmer/interfaces/lib/runtime/modifier.js"; import type { ResolvedComponentDefinition } from "@glimmer/interfaces/lib/serialize.js"; import type { BlockMetadata, STDLib, Template } from "@glimmer/interfaces/lib/template.js"; import type { SomeVmOp, VmMachineOp, VmOp } from "@glimmer/interfaces/lib/vm-opcodes.js"; export type CreateRuntimeOp = (heap: ProgramHeap) => RuntimeOp; export interface RuntimeOp { offset: number; type: SomeVmOp; op1: number; op2: number; op3: number; size: number; isMachine: 0 | 1; } export interface SerializedHeap { buffer: ArrayBuffer; table: number[]; handle: number; } export interface ProgramHeap { pushRaw(value: number): void; pushOp(name: VmOp, op1?: number, op2?: number, op3?: number): void; pushMachine(name: VmMachineOp, op1?: number, op2?: number, op3?: number): void; malloc(): number; finishMalloc(handle: number, scopeSize: number): void; offset: number; // for debugging getaddr(handle: number): number; sizeof(handle: number): number; getbyaddr(address: number): number; setbyaddr(address: number, value: number): void; /** * Return the number of entries in the table. A handle is legal if * it is less than this number. * * @debugging */ entries(): number; } /** * The `EvaluationContext` is the context that remains the same across all of the templates and * evaluations in a single program. * * Note that multiple programs can co-exist on the same page, sharing tracking logic (and the * global tracking context) but having different *evaluation* contexts. */ export interface EvaluationContext { /** * The program's environment, which contains customized framework behavior. */ readonly env: Environment; /** * The compiled program itself: the constants and heap */ readonly program: Program; /** * The offsets to stdlib functions */ readonly stdlib: STDLib; /** * A framework-specified resolver for resolving free variables in classic templates. * * A strict component can invoke a classic component and vice versa, but only classic components * will use the resolver. If no resolver is available in the `ProgramContext`, only strict components * will compile and run. */ readonly resolver: Nullable; // Create a runtime op from the heap readonly createOp: CreateRuntimeOp; } /** * Options for compiling a specific template. This carries * along the static information associated with the entire * template when compiling blocks nested inside of it. */ export interface CompilationContext { readonly evaluation: EvaluationContext; readonly encoder: Encoder; readonly meta: BlockMetadata; } export type EMPTY_ARRAY = Array>; export type ConstantPool = unknown[]; /** * Constants are interned values that are referenced as numbers in the program. * The constant pool is a part of the program, and is always transmitted * together with the program. */ export interface CompileTimeConstants { value(value: unknown): number; array(values: unknown[] | readonly unknown[]): number; toPool(): ConstantPool; } /** * Resolution happens when components are first loaded, either via the resolver * or via looking them up in template scope. */ export interface ResolutionTimeConstants { // TODO: The default template is unique per-program. This should likely belong // in StdLib, but it's not really possible to thread it through that way // currently. defaultTemplate: Template; helper( definitionState: HelperDefinitionState, resolvedName: string | null, isOptional: true ): number | null; helper(definitionState: HelperDefinitionState, resolvedName?: string | null): number; modifier( definitionState: ModifierDefinitionState, resolvedName: string | null, isOptional: true ): number | null; modifier(definitionState: ModifierDefinitionState, resolvedName?: string | null): number; component( definitionState: ComponentDefinitionState, owner: object, isOptional?: false, debugName?: string ): ComponentDefinition; component( definitionState: ComponentDefinitionState, owner: object, isOptional?: boolean, debugName?: string ): ComponentDefinition | null; resolvedComponent( definitionState: ResolvedComponentDefinition, resolvedName: string ): ComponentDefinition; } export interface RuntimeConstants { hasHandle(handle: number): boolean; getValue(handle: number): T; getArray(handle: number): T[]; } export type ProgramConstants = CompileTimeConstants & ResolutionTimeConstants & RuntimeConstants; export interface CompileTimeArtifacts { heap: ProgramHeap; constants: ProgramConstants; } export interface ClassicResolver { lookupHelper?(name: string, owner: O): Nullable; lookupModifier?(name: string, owner: O): Nullable; lookupComponent?(name: string, owner: O): Nullable; // TODO: These are used to lookup keywords that are implemented as helpers/modifiers. // We should try to figure out a cleaner way to do this. lookupBuiltInHelper?(name: string): Nullable; lookupBuiltInModifier?(name: string): Nullable; lookupComponent?(name: string, owner: O): Nullable; } }