( expr: Expression | undefined )
| 109 | type ValidateArgumentsFn = ( |
| 110 | ce: ComputeEngine, |
| 111 | ops: ReadonlyArray<Expression>, |
| 112 | signature: Type, |
| 113 | lazy?: boolean, |
| 114 | threadable?: boolean, |
| 115 | freshlyInferred?: ReadonlySet<BoxedValueDefinition> |
| 116 | ) => ReadonlyArray<Expression> | null; |
| 117 | |
| 118 | let _validateArguments: ValidateArgumentsFn | undefined; |
| 119 | export function _setValidateArguments(fn: ValidateArgumentsFn): void { |
| 120 | _validateArguments = fn; |
| 121 | } |
| 122 | |
| 123 | /*** |
| 124 | * ### THEORY OF OPERATIONS |
| 125 | * |
| 126 | * The body of a `["Function"]` expression is a `["Block"]` expression, |
| 127 | * which is scoped. The function arguments are declared in that scope as well. |
| 128 | * |
| 129 | * Some expressions with anonymous parameters (e.g. `["Add", "_", 1]`) |
| 130 | * are rewritten to a `["Function"]` expression with anonymous parameters |
| 131 | * (e.g. `["Function", ["Block", ["Add", "_", 1]], "_"]`). |
| 132 | * |
| 133 | * |
| 134 | * #### DURING CANONICALIZATION (in canonicalFunctionLiteralArguments()) |
| 135 | * |
| 136 | * 1/ If not a `["Function"]` expression, the expression is rewritten |
| 137 | * to a `["Function"]` expression with anonymous parameters |
| 138 | * 2/ A `Block` scope is created |
| 139 | * 3/ The function parameters are declared in the Block's scope |
| 140 | * 4/ The function body is canonicalized in the context of the scope. |
| 141 | * The Block's localScope captures the defining scope as its parent. |
| 142 | * |
| 143 | * |
| 144 | * #### DURING EVALUATION (executing the result of makeLambda()) |
| 145 | * |
| 146 | * 1/ The arguments are evaluated in the **calling** scope |
| 147 | * 2/ A fresh scope is created per call, with parent = the **defining** |
| 148 | * scope (body.localScope.parent), giving true lexical scoping |
| 149 | * 3/ The function parameters are declared in the fresh scope |
| 150 | * 4/ body.localScope is temporarily re-parented to chain through the |
| 151 | * fresh scope: bigOpScope → bodyScope → freshScope → capturedScope. |
| 152 | * Param bindings in bodyScope (stale, from canonicalization) are |
| 153 | * temporarily hidden so they don't shadow freshScope's values. |
| 154 | * This lets nested scoped expressions (Sum, Product) find params |
| 155 | * by walking up their static scope chain. |
| 156 | * 5/ The function body is evaluated in the context of the fresh scope |
| 157 | * 6/ If the result contains Function literals, they are rebound to |
| 158 | * close over the fresh scope (closure capture) |
| 159 | * 7/ The fresh scope is discarded; body.localScope.parent is restored |
| 160 | * 8/ The result is returned |
| 161 | * |
| 162 | */ |
| 163 | |
| 164 | /** |
| 165 | * From an expression, return a predicate function, which can be used to filter. |
| 166 | */ |
| 167 | export function predicate( |
| 168 | _expr: Expression |
no test coverage detected