solve-engine 1.0.0-beta.0 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BytecodeBuilder-3egMyuDi.d.cts +274 -0
- package/dist/BytecodeBuilder-3egMyuDi.d.ts +274 -0
- package/dist/Configuration-fVpd-HC-.d.cts +228 -0
- package/dist/Configuration-fVpd-HC-.d.ts +228 -0
- package/dist/EngineError-DvPSnhZi.d.cts +304 -0
- package/dist/EngineError-DvPSnhZi.d.ts +304 -0
- package/dist/Lexer-BJdhlnej.d.cts +531 -0
- package/dist/Lexer-D9l4Yrk2.d.ts +531 -0
- package/dist/NormalizerRule-BrVoVjmP.d.cts +163 -0
- package/dist/NormalizerRule-CEjf1FyD.d.ts +163 -0
- package/dist/PackageRegistry-D-Tv_7ca.d.cts +2572 -0
- package/dist/PackageRegistry-DaH4aIKP.d.ts +2572 -0
- package/dist/Parselet-CK8cQu2a.d.cts +299 -0
- package/dist/Parselet-ConOIdRO.d.ts +299 -0
- package/dist/ScopeManager-B5k0nk05.d.ts +559 -0
- package/dist/ScopeManager-CKfQtl7l.d.cts +559 -0
- package/dist/Token-0jpvUdPY.d.cts +245 -0
- package/dist/Token-0jpvUdPY.d.ts +245 -0
- package/dist/VMCheckpoints-BmDwIXgK.d.ts +171 -0
- package/dist/VMCheckpoints-CqFuLwrT.d.cts +171 -0
- package/dist/Value-KtAQNHur.d.cts +295 -0
- package/dist/Value-KtAQNHur.d.ts +295 -0
- package/dist/chunk-2RWAXT6O.js +3 -0
- package/dist/chunk-2RWAXT6O.js.map +1 -0
- package/dist/chunk-34RRD7PC.js +1492 -0
- package/dist/chunk-34RRD7PC.js.map +1 -0
- package/dist/chunk-3PPFLFH4.js +5097 -0
- package/dist/chunk-3PPFLFH4.js.map +1 -0
- package/dist/chunk-3VGDNEE3.js +84 -0
- package/dist/chunk-3VGDNEE3.js.map +1 -0
- package/dist/chunk-3YNVWKR2.cjs +370 -0
- package/dist/chunk-3YNVWKR2.cjs.map +1 -0
- package/dist/chunk-47LRVGOT.cjs +316 -0
- package/dist/chunk-47LRVGOT.cjs.map +1 -0
- package/dist/chunk-4MG4XKO2.js +1644 -0
- package/dist/chunk-4MG4XKO2.js.map +1 -0
- package/dist/chunk-4QADQTWS.js +2392 -0
- package/dist/chunk-4QADQTWS.js.map +1 -0
- package/dist/chunk-53B6KDDJ.cjs +1651 -0
- package/dist/chunk-53B6KDDJ.cjs.map +1 -0
- package/dist/chunk-5X2PTP6F.cjs +104 -0
- package/dist/chunk-5X2PTP6F.cjs.map +1 -0
- package/dist/chunk-5YEMOYSE.js +264 -0
- package/dist/chunk-5YEMOYSE.js.map +1 -0
- package/dist/chunk-64W6GLLZ.js +481 -0
- package/dist/chunk-64W6GLLZ.js.map +1 -0
- package/dist/chunk-6BKTCEUP.cjs +233 -0
- package/dist/chunk-6BKTCEUP.cjs.map +1 -0
- package/dist/chunk-6NTVRDQV.cjs +1642 -0
- package/dist/chunk-6NTVRDQV.cjs.map +1 -0
- package/dist/chunk-6RDSQURE.js +290 -0
- package/dist/chunk-6RDSQURE.js.map +1 -0
- package/dist/chunk-75JP4BZX.js +93 -0
- package/dist/chunk-75JP4BZX.js.map +1 -0
- package/dist/chunk-B7LXJ6LC.cjs +36 -0
- package/dist/chunk-B7LXJ6LC.cjs.map +1 -0
- package/dist/chunk-BVAR5J2F.js +257 -0
- package/dist/chunk-BVAR5J2F.js.map +1 -0
- package/dist/chunk-C4XZV6E7.cjs +269 -0
- package/dist/chunk-C4XZV6E7.cjs.map +1 -0
- package/dist/chunk-CCJPSHGI.cjs +40 -0
- package/dist/chunk-CCJPSHGI.cjs.map +1 -0
- package/dist/chunk-CLL7RUQV.cjs +316 -0
- package/dist/chunk-CLL7RUQV.cjs.map +1 -0
- package/dist/chunk-DM3LMRBC.js +329 -0
- package/dist/chunk-DM3LMRBC.js.map +1 -0
- package/dist/chunk-DUEZFTK2.js +38 -0
- package/dist/chunk-DUEZFTK2.js.map +1 -0
- package/dist/chunk-EBSPLUW4.cjs +489 -0
- package/dist/chunk-EBSPLUW4.cjs.map +1 -0
- package/dist/chunk-EHAHVROS.cjs +261 -0
- package/dist/chunk-EHAHVROS.cjs.map +1 -0
- package/dist/chunk-EIGTWK5N.js +167 -0
- package/dist/chunk-EIGTWK5N.js.map +1 -0
- package/dist/chunk-EPOXXJBK.js +96 -0
- package/dist/chunk-EPOXXJBK.js.map +1 -0
- package/dist/chunk-FEAIOR7N.cjs +91 -0
- package/dist/chunk-FEAIOR7N.cjs.map +1 -0
- package/dist/chunk-G535KJEG.js +312 -0
- package/dist/chunk-G535KJEG.js.map +1 -0
- package/dist/chunk-GCM5JHMX.js +88 -0
- package/dist/chunk-GCM5JHMX.js.map +1 -0
- package/dist/chunk-GOLDJNMZ.js +368 -0
- package/dist/chunk-GOLDJNMZ.js.map +1 -0
- package/dist/chunk-GW32KPCU.cjs +360 -0
- package/dist/chunk-GW32KPCU.cjs.map +1 -0
- package/dist/chunk-HTXVVJRA.cjs +1549 -0
- package/dist/chunk-HTXVVJRA.cjs.map +1 -0
- package/dist/chunk-HWSZJQCI.js +311 -0
- package/dist/chunk-HWSZJQCI.js.map +1 -0
- package/dist/chunk-IF532O7C.js +101 -0
- package/dist/chunk-IF532O7C.js.map +1 -0
- package/dist/chunk-J73SJHR3.cjs +2415 -0
- package/dist/chunk-J73SJHR3.cjs.map +1 -0
- package/dist/chunk-JBSYC7BB.cjs +7473 -0
- package/dist/chunk-JBSYC7BB.cjs.map +1 -0
- package/dist/chunk-KVILKGMS.js +228 -0
- package/dist/chunk-KVILKGMS.js.map +1 -0
- package/dist/chunk-LIPPNDBE.js +258 -0
- package/dist/chunk-LIPPNDBE.js.map +1 -0
- package/dist/chunk-LR7YASZF.cjs +172 -0
- package/dist/chunk-LR7YASZF.cjs.map +1 -0
- package/dist/chunk-M4N5GA5Z.cjs +309 -0
- package/dist/chunk-M4N5GA5Z.cjs.map +1 -0
- package/dist/chunk-M5LX5AOO.js +7459 -0
- package/dist/chunk-M5LX5AOO.js.map +1 -0
- package/dist/chunk-MZOVP3WI.cjs +96 -0
- package/dist/chunk-MZOVP3WI.cjs.map +1 -0
- package/dist/chunk-N5YFR4UP.cjs +10 -0
- package/dist/chunk-N5YFR4UP.cjs.map +1 -0
- package/dist/chunk-NGBBNL4K.cjs +4 -0
- package/dist/chunk-NGBBNL4K.cjs.map +1 -0
- package/dist/chunk-NH2O2AUR.js +146 -0
- package/dist/chunk-NH2O2AUR.js.map +1 -0
- package/dist/chunk-NLNDMWZC.js +31 -0
- package/dist/chunk-NLNDMWZC.js.map +1 -0
- package/dist/chunk-NMCRQP3Z.cjs +778 -0
- package/dist/chunk-NMCRQP3Z.cjs.map +1 -0
- package/dist/chunk-NMD5VRN4.cjs +1327 -0
- package/dist/chunk-NMD5VRN4.cjs.map +1 -0
- package/dist/chunk-OC6LTXYS.cjs +286 -0
- package/dist/chunk-OC6LTXYS.cjs.map +1 -0
- package/dist/chunk-OT6OJY7C.cjs +114 -0
- package/dist/chunk-OT6OJY7C.cjs.map +1 -0
- package/dist/chunk-PFSDGGYL.js +8 -0
- package/dist/chunk-PFSDGGYL.js.map +1 -0
- package/dist/chunk-QNJ4ACRT.cjs +155 -0
- package/dist/chunk-QNJ4ACRT.cjs.map +1 -0
- package/dist/chunk-QWY3VEZN.js +1637 -0
- package/dist/chunk-QWY3VEZN.js.map +1 -0
- package/dist/chunk-RFYD5TJE.js +111 -0
- package/dist/chunk-RFYD5TJE.js.map +1 -0
- package/dist/chunk-RIN643A3.js +354 -0
- package/dist/chunk-RIN643A3.js.map +1 -0
- package/dist/chunk-RZCWSXTA.cjs +5122 -0
- package/dist/chunk-RZCWSXTA.cjs.map +1 -0
- package/dist/chunk-SDGRK7EP.js +774 -0
- package/dist/chunk-SDGRK7EP.js.map +1 -0
- package/dist/chunk-VEKIWQ3F.cjs +39 -0
- package/dist/chunk-VEKIWQ3F.cjs.map +1 -0
- package/dist/chunk-WQTTOGXC.cjs +99 -0
- package/dist/chunk-WQTTOGXC.cjs.map +1 -0
- package/dist/chunk-X6K3HUOY.cjs +86 -0
- package/dist/chunk-X6K3HUOY.cjs.map +1 -0
- package/dist/chunk-XJCMXB2E.cjs +333 -0
- package/dist/chunk-XJCMXB2E.cjs.map +1 -0
- package/dist/chunk-XVWCOTR6.js +1324 -0
- package/dist/chunk-XVWCOTR6.js.map +1 -0
- package/dist/chunk-YLJ4XMA6.js +33 -0
- package/dist/chunk-YLJ4XMA6.js.map +1 -0
- package/dist/chunk-Z2XP767T.cjs +35 -0
- package/dist/chunk-Z2XP767T.cjs.map +1 -0
- package/dist/chunk-Z4X2RWOF.js +37 -0
- package/dist/chunk-Z4X2RWOF.js.map +1 -0
- package/dist/constants.cjs +22 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +12 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -0
- package/dist/engine.cjs +79 -0
- package/dist/engine.cjs.map +1 -0
- package/dist/engine.d.cts +587 -0
- package/dist/engine.d.ts +587 -0
- package/dist/engine.js +34 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.cjs +81 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +95 -0
- package/dist/errors.d.ts +95 -0
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -0
- package/dist/format.cjs +171 -0
- package/dist/format.cjs.map +1 -0
- package/dist/format.d.cts +51 -0
- package/dist/format.d.ts +51 -0
- package/dist/format.js +168 -0
- package/dist/format.js.map +1 -0
- package/dist/index.cjs +97 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +152 -0
- package/dist/index.d.ts +152 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -0
- package/dist/language.cjs +308 -0
- package/dist/language.cjs.map +1 -0
- package/dist/language.d.cts +110 -0
- package/dist/language.d.ts +110 -0
- package/dist/language.js +287 -0
- package/dist/language.js.map +1 -0
- package/dist/lexer.cjs +64 -0
- package/dist/lexer.cjs.map +1 -0
- package/dist/lexer.d.cts +56 -0
- package/dist/lexer.d.ts +56 -0
- package/dist/lexer.js +11 -0
- package/dist/lexer.js.map +1 -0
- package/dist/normalizer.cjs +40 -0
- package/dist/normalizer.cjs.map +1 -0
- package/dist/normalizer.d.cts +364 -0
- package/dist/normalizer.d.ts +364 -0
- package/dist/normalizer.js +11 -0
- package/dist/normalizer.js.map +1 -0
- package/dist/packages.cjs +121 -0
- package/dist/packages.cjs.map +1 -0
- package/dist/packages.d.cts +691 -0
- package/dist/packages.d.ts +691 -0
- package/dist/packages.js +24 -0
- package/dist/packages.js.map +1 -0
- package/dist/parser.cjs +55 -0
- package/dist/parser.cjs.map +1 -0
- package/dist/parser.d.cts +46 -0
- package/dist/parser.d.ts +46 -0
- package/dist/parser.js +10 -0
- package/dist/parser.js.map +1 -0
- package/dist/pipeline-CrsRPmsv.d.ts +285 -0
- package/dist/pipeline-DPUQt7yL.d.cts +285 -0
- package/dist/resolvers.cjs +13 -0
- package/dist/resolvers.cjs.map +1 -0
- package/dist/resolvers.d.cts +111 -0
- package/dist/resolvers.d.ts +111 -0
- package/dist/resolvers.js +4 -0
- package/dist/resolvers.js.map +1 -0
- package/dist/services.cjs +21 -0
- package/dist/services.cjs.map +1 -0
- package/dist/services.d.cts +30 -0
- package/dist/services.d.ts +30 -0
- package/dist/services.js +4 -0
- package/dist/services.js.map +1 -0
- package/dist/uom.cjs +56 -0
- package/dist/uom.cjs.map +1 -0
- package/dist/uom.d.cts +224 -0
- package/dist/uom.d.ts +224 -0
- package/dist/uom.js +11 -0
- package/dist/uom.js.map +1 -0
- package/dist/utilities.cjs +32 -0
- package/dist/utilities.cjs.map +1 -0
- package/dist/utilities.d.cts +113 -0
- package/dist/utilities.d.ts +113 -0
- package/dist/utilities.js +7 -0
- package/dist/utilities.js.map +1 -0
- package/dist/variables.cjs +17 -0
- package/dist/variables.cjs.map +1 -0
- package/dist/variables.d.cts +87 -0
- package/dist/variables.d.ts +87 -0
- package/dist/variables.js +4 -0
- package/dist/variables.js.map +1 -0
- package/dist/vm.cjs +284 -0
- package/dist/vm.cjs.map +1 -0
- package/dist/vm.d.cts +68 -0
- package/dist/vm.d.ts +68 -0
- package/dist/vm.js +194 -0
- package/dist/vm.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
import { V as Value } from './Value-KtAQNHur.js';
|
|
2
|
+
import { U as UserFunctionDef, A as AnonymousBodyDef, a as BytecodeProgram } from './BytecodeBuilder-3egMyuDi.js';
|
|
3
|
+
import { E as EngineError } from './EngineError-DvPSnhZi.js';
|
|
4
|
+
import { D as DiagnosticPipeline } from './pipeline-CrsRPmsv.js';
|
|
5
|
+
import { VariableResolver } from './variables.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create a new VM instance with the given opcode registry and configurable limits.
|
|
9
|
+
*
|
|
10
|
+
* The VM is a stack machine that executes compiled bytecode. It manages:
|
|
11
|
+
* - A value stack (bounded by `maxStackDepth`)
|
|
12
|
+
* - A variable store (Map of name → Value)
|
|
13
|
+
* - An instruction counter (bounded by `maxInstructions`)
|
|
14
|
+
* - An AbortSignal for async cancellation
|
|
15
|
+
*
|
|
16
|
+
* @param registry - Opcode handler registry for plugin-extensible opcodes
|
|
17
|
+
* @param maxStackDepth - Maximum stack slots (default 200)
|
|
18
|
+
* @param maxInstructions - Maximum opcodes per expression (default 50000)
|
|
19
|
+
* @param maxFunctionRecursionDepth - Maximum nested user-defined-function
|
|
20
|
+
* calls (default 50). See the VM interface's `pushCallFrame` doc for why
|
|
21
|
+
* this exists as its own dedicated guard, separate from `maxInstructions`.
|
|
22
|
+
*/
|
|
23
|
+
declare function createVM(registry: OpRegistry, maxStackDepth?: number, maxInstructions?: number, maxFunctionRecursionDepth?: number, context?: EngineContext): VM;
|
|
24
|
+
/**
|
|
25
|
+
* Compiled bytecode ready for VM execution.
|
|
26
|
+
*
|
|
27
|
+
* Uses packed TypedArrays for cache-friendly memory layout:
|
|
28
|
+
* - `opcodes`: Uint8Array of OpCode values
|
|
29
|
+
* - `numbers`: Float64Array of numeric literals (indexed by opcode operands)
|
|
30
|
+
* - `strings`: String table for identifiers, UoM units, and BigInt literals
|
|
31
|
+
*/
|
|
32
|
+
interface Bytecode {
|
|
33
|
+
opcodes: Uint8Array;
|
|
34
|
+
numbers: Float64Array;
|
|
35
|
+
strings: string[];
|
|
36
|
+
/** User-defined-function bodies compiled alongside this program. See `parser/BytecodeBuilder.ts`'s `BytecodeProgram.userFunctionBodies`. */
|
|
37
|
+
userFunctionBodies?: UserFunctionDef[];
|
|
38
|
+
/** map/reduce anonymous transform bodies. See `parser/BytecodeBuilder.ts`'s `BytecodeProgram.anonymousBodies`. */
|
|
39
|
+
anonymousBodies?: AnonymousBodyDef[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Per-line execution context, threaded optionally through
|
|
43
|
+
* {@link executeBytecode} down to `CALL_PLUGIN`'s plugin-function handlers
|
|
44
|
+
* (see `vm/VMBuiltins.ts`'s `pluginFunctionRegistry`).
|
|
45
|
+
*
|
|
46
|
+
* Exists so a package can implement cross-line features (`prev`, `line<N>`,
|
|
47
|
+
* range/above aggregation. See `packages/lines/`) without every other
|
|
48
|
+
* plugin function having to care: it's optional, and every existing
|
|
49
|
+
* handler ignores it unchanged. Before this, a plugin function's only
|
|
50
|
+
* input was its own call-site arguments, no line number, no access to
|
|
51
|
+
* any other line's cached result. `getLineResult`/`isLineBoundary` are
|
|
52
|
+
* both `undefined` when there's no real document (e.g.
|
|
53
|
+
* `ExpressionEngine.evaluateExpression()`'s single-expression path, which
|
|
54
|
+
* uses `lineIndex = -1` as its existing "no document" sentinel), a
|
|
55
|
+
* plugin function needing document access must check for that itself
|
|
56
|
+
* and return a clear error, never silently treat it as line 0.
|
|
57
|
+
*/
|
|
58
|
+
interface LineExecutionContext {
|
|
59
|
+
/** 1-based current line number, or -1 when there is no real document (see class doc above). */
|
|
60
|
+
lineIndex: number;
|
|
61
|
+
/** Look up another line's cached result by 1-based line number. `undefined` = not evaluated yet (or out of range), distinct from a line that evaluated to an actual `undefined`-like Value, which can't happen (every Value type has a concrete representation). */
|
|
62
|
+
getLineResult?: (lineNumber: number) => Value | undefined;
|
|
63
|
+
/** Whether line `lineNumber` is a blank line or a `#` heading, the stopping condition for "total above"/"sum above"/"average above" aggregation. */
|
|
64
|
+
isLineBoundary?: (lineNumber: number) => boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Discriminated union returned by {@link executeBytecode}.
|
|
68
|
+
*
|
|
69
|
+
* Two variants:
|
|
70
|
+
* - `value`: execution completed synchronously with a concrete Value
|
|
71
|
+
* - `pending`: an async plugin call was encountered, the orchestrator
|
|
72
|
+
* must await the resolver Promise, then re-execute
|
|
73
|
+
*
|
|
74
|
+
* Replaces the old throw-AsyncSuspenseError pattern, eliminating the need
|
|
75
|
+
* for try/catch in the engine.
|
|
76
|
+
*/
|
|
77
|
+
type EvalResult = {
|
|
78
|
+
type: 'value';
|
|
79
|
+
value: Value;
|
|
80
|
+
} | {
|
|
81
|
+
type: 'pending';
|
|
82
|
+
queryKey: string;
|
|
83
|
+
resolver: Promise<Value>;
|
|
84
|
+
packageId: string;
|
|
85
|
+
signal: AbortSignal;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* NEW third arm, an internal invariant violation (stack underflow via
|
|
89
|
+
* `safePop()`, an unresolved global variable bypassing preflight, a
|
|
90
|
+
* safety limit exceeded) surfaced as a controlled, structured
|
|
91
|
+
* `EngineError` instead of letting a raw exception escape
|
|
92
|
+
* `executeBytecode()` uncaught. See `executeBytecode()`'s own doc
|
|
93
|
+
* comment on the try/catch this arm makes possible.
|
|
94
|
+
*/
|
|
95
|
+
| {
|
|
96
|
+
type: 'error';
|
|
97
|
+
error: EngineError;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Execute bytecode with optional diagnostic pipeline integration.
|
|
101
|
+
*
|
|
102
|
+
* Performance notes:
|
|
103
|
+
* - Uses a `switch(op)` statement for dispatch. V8 compiles dense integer
|
|
104
|
+
* switches (OpCode values 0–200) into a jump table with O(1) dispatch.
|
|
105
|
+
* All handler code is inlined directly in the switch cases, allowing
|
|
106
|
+
* TurboFan to optimize across opcode boundaries.
|
|
107
|
+
* - ADD/SUB/MUL have an inlined numeric fast path that skips the `binaryOp()`
|
|
108
|
+
* function call + closure allocation when both operands are plain numbers
|
|
109
|
+
* (>90% of arithmetic ops).
|
|
110
|
+
* - Tracing uses a boolean guard (`shouldTrace`) that the JIT eliminates
|
|
111
|
+
* entirely when diagnostics are disabled. No function call overhead.
|
|
112
|
+
* - `Value.toNumber()` caches its result, computed once, read thereafter.
|
|
113
|
+
*/
|
|
114
|
+
declare function executeBytecode(bytecode: Bytecode, vm: VM, pipeline?: DiagnosticPipeline | undefined, expression?: string, context?: LineExecutionContext, symbolicTolerant?: boolean): EvalResult;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Per-engine state that used to live in module-level singletons.
|
|
118
|
+
*
|
|
119
|
+
* Two {@link ExpressionEngine} instances in one process could not be isolated
|
|
120
|
+
* from each other, because the registries they depend on were module globals
|
|
121
|
+
* shared by every instance. Registering a package mutated state that another
|
|
122
|
+
* engine was already reading. Tests worked only because they cleared those
|
|
123
|
+
* globals by hand, and per-document engines were safe only because
|
|
124
|
+
* registration happened to be idempotent.
|
|
125
|
+
*
|
|
126
|
+
* An `EngineContext` is created by the `ExpressionEngine` constructor and owned
|
|
127
|
+
* by that engine. Anything that needs one of these registries receives the
|
|
128
|
+
* context rather than importing a singleton.
|
|
129
|
+
*
|
|
130
|
+
* Runtime imports here are restricted to leaf modules of `vm/`. This file is
|
|
131
|
+
* imported by `vm/`, which `engine/` imports in turn, so pulling in anything
|
|
132
|
+
* that reaches back into `engine/` would close a cycle. `OpRegistry` and
|
|
133
|
+
* `VariableResolver` are safe because they import only types plus the error
|
|
134
|
+
* factory. Everything else arrives
|
|
135
|
+
* through `import type`, which is erased before the code runs.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* A function a package contributes to the VM, reachable from bytecode through
|
|
140
|
+
* `CALL_PLUGIN`.
|
|
141
|
+
*
|
|
142
|
+
* Returning a promise puts the line into the pending state rather than
|
|
143
|
+
* blocking: the engine resolves it and re-executes.
|
|
144
|
+
*/
|
|
145
|
+
type PluginFunctionHandler = (args: Value[], context?: LineExecutionContext) => Value | Promise<Value>;
|
|
146
|
+
/**
|
|
147
|
+
* The registries one engine instance owns.
|
|
148
|
+
*
|
|
149
|
+
* Members are added here as each former singleton is migrated. The migration
|
|
150
|
+
* order is deliberate and recorded in `docs-internal/plans`: plugin functions,
|
|
151
|
+
* then the opcode registry, the variable resolver, the lexer, and finally
|
|
152
|
+
* currency exchange. The lexer comes near the end because package registration
|
|
153
|
+
* writes vocabularies into it, so moving it early would churn every package.
|
|
154
|
+
*
|
|
155
|
+
* Currency exchange is deliberately NOT migrated, which is a departure from
|
|
156
|
+
* that plan. `CurrencyExchangeService` holds a cache of live market rates with
|
|
157
|
+
* a fifteen minute freshness window and no per-engine configuration. Sharing is
|
|
158
|
+
* the correct behaviour there: giving each engine its own would make two
|
|
159
|
+
* engines in one process fetch the same public endpoint independently, and let
|
|
160
|
+
* them disagree about the rate for one currency pair at one moment. The
|
|
161
|
+
* singleton rationale, that one engine's registration should not be visible to
|
|
162
|
+
* another, does not apply to a cache of state that is global in the real world.
|
|
163
|
+
*
|
|
164
|
+
* If a host ever needs per-engine rates, for a what-if scenario against
|
|
165
|
+
* historical figures, the answer is an optional override on the context that
|
|
166
|
+
* falls back to the shared cache, not a private copy per engine.
|
|
167
|
+
*/
|
|
168
|
+
interface EngineContext {
|
|
169
|
+
/**
|
|
170
|
+
* Package-contributed VM functions, keyed by the index the bytecode
|
|
171
|
+
* carries.
|
|
172
|
+
*
|
|
173
|
+
* Indices come from `allocatePluginFunctionIndex()`. Two packages picking
|
|
174
|
+
* the same number by hand would silently overwrite one another, which is
|
|
175
|
+
* why the allocator exists and why nothing should hardcode an index.
|
|
176
|
+
*/
|
|
177
|
+
readonly pluginFunctions: Record<number, PluginFunctionHandler>;
|
|
178
|
+
/**
|
|
179
|
+
* Custom opcode handlers a package registered.
|
|
180
|
+
*
|
|
181
|
+
* Largely vestigial: packages reach the VM through `CALL_PLUGIN` and
|
|
182
|
+
* {@link EngineContext.pluginFunctions} now, and nothing in the built-in
|
|
183
|
+
* set registers an opcode. It moves here anyway because the VM interface
|
|
184
|
+
* still requires a registry, and one shared instance would put any future
|
|
185
|
+
* registration back into every engine at once.
|
|
186
|
+
*/
|
|
187
|
+
readonly opRegistry: OpRegistry;
|
|
188
|
+
/**
|
|
189
|
+
* Named-variable sources a package contributed.
|
|
190
|
+
*
|
|
191
|
+
* A package registering a source used to make its variables visible to
|
|
192
|
+
* every engine in the process, including ones that never registered it.
|
|
193
|
+
*/
|
|
194
|
+
readonly variableResolver: VariableResolver;
|
|
195
|
+
/**
|
|
196
|
+
* Which package registered each plugin function index.
|
|
197
|
+
*
|
|
198
|
+
* The VM emits a pending result when a plugin function returns a promise,
|
|
199
|
+
* and that result carries the owning package so diagnostics and the error
|
|
200
|
+
* surface can name it. Without this the VM had nothing to report and sent an
|
|
201
|
+
* empty string, so every async failure looked as though it came from
|
|
202
|
+
* nowhere.
|
|
203
|
+
*/
|
|
204
|
+
readonly pluginFunctionOwners: Record<number, string>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* A stored bare (colon-less) equation of the shape `factor1*factor2*...*
|
|
209
|
+
* variable = rhs` (e.g. `a*x = [60;70]`, or `s*t*v = [vx;vy;1]`)
|
|
210
|
+
* registered when that line is EXECUTED (mirroring `UserFunctionDef`'s own
|
|
211
|
+
* execution-time registration, not parse-time), and consulted when
|
|
212
|
+
* `<variable> =>` is later evaluated. Solving is `variable =
|
|
213
|
+
* inv(factor1*factor2*...) * rhs` (`vm/VM.ts`'s THEREFORE-handling code,
|
|
214
|
+
* `vm/MatrixOps.ts`'s `matrixMultiply()`/`inverse()`, both symbolic-aware
|
|
215
|
+
* so a factor whose OWN cells are still-unassigned free variables, e.g.
|
|
216
|
+
* `s = [sx,0,0;...]`, solves correctly too).
|
|
217
|
+
*
|
|
218
|
+
* `factorNames` are looked up via `vm.getVar()` at solve time (ordinary,
|
|
219
|
+
* ALREADY-evaluated Matrix values, ordinary ("bare") assignment always
|
|
220
|
+
* evaluates its RHS eagerly, even when that RHS itself contains
|
|
221
|
+
* unassigned names, via symbolic-tolerant evaluation, so by solve time
|
|
222
|
+
* each factor is already a genuine, possibly-partially-symbolic Matrix
|
|
223
|
+
* Value sitting in the variable store), NOT re-compiled bytecode, since
|
|
224
|
+
* this pattern only ever allows bare identifiers as factors (see
|
|
225
|
+
* `ExpressionEngine.ts`'s own equation-detection doc comment for why this
|
|
226
|
+
* stays a narrow, disclosed pattern rather than a general expression).
|
|
227
|
+
* `rhsProgram` IS a real compiled program (the right-hand side can be an
|
|
228
|
+
* arbitrary expression, e.g. `[vx;vy;1]`), evaluated in symbolic-tolerant
|
|
229
|
+
* mode at solve time.
|
|
230
|
+
*/
|
|
231
|
+
interface EquationDef {
|
|
232
|
+
variable: string;
|
|
233
|
+
factorNames: string[];
|
|
234
|
+
rhsProgram: BytecodeProgram;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* A stored scalar equation, the general `x^2 - 4 = 0` shape, kept separate from
|
|
238
|
+
* {@link EquationDef} rather than merged into it.
|
|
239
|
+
*
|
|
240
|
+
* The two are genuinely different problems solved by different machinery.
|
|
241
|
+
* {@link EquationDef} is a product chain of matrix factors solved by inverting
|
|
242
|
+
* their product; this is an arbitrary polynomial in one unknown solved by
|
|
243
|
+
* `symbolic/Solve.ts`. Merging them into one optional-field type would mean
|
|
244
|
+
* every consumer branching on which half is populated, and would put the older,
|
|
245
|
+
* already-shipped matrix path at risk of being changed by accident.
|
|
246
|
+
*
|
|
247
|
+
* Both sides are compiled programs rather than pre-evaluated values, because
|
|
248
|
+
* neither side can be evaluated until solve time: they contain the very unknown
|
|
249
|
+
* being solved for.
|
|
250
|
+
*/
|
|
251
|
+
interface ScalarEquationDef {
|
|
252
|
+
/** The unknown this equation is keyed by and will be solved for. */
|
|
253
|
+
variable: string;
|
|
254
|
+
/** Compiled left-hand side, evaluated symbolic-tolerantly at solve time. */
|
|
255
|
+
lhsProgram: BytecodeProgram;
|
|
256
|
+
/** Compiled right-hand side, likewise. */
|
|
257
|
+
rhsProgram: BytecodeProgram;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Handler function for plugin-registered opcodes via CALL_PLUGIN (opcode 50).
|
|
261
|
+
* No longer dispatched directly from the VM switch, plugins register
|
|
262
|
+
* functions in pluginFunctionRegistry instead.
|
|
263
|
+
*
|
|
264
|
+
* @deprecated Use CALL_PLUGIN + pluginFunctionRegistry for plugin functionality.
|
|
265
|
+
* OpRegistry remains for the VM interface contract only.
|
|
266
|
+
*/
|
|
267
|
+
type OpcodeHandler = (vm: VM, opcodes: Uint8Array, ip: number, numbers: Float64Array, strings: string[]) => number;
|
|
268
|
+
/** Registration payload for an opcode handler. Binds an OpCode to its handler function with plugin attribution. */
|
|
269
|
+
interface IOpcodeHandlerRegistration {
|
|
270
|
+
opcode: number;
|
|
271
|
+
handler: OpcodeHandler;
|
|
272
|
+
pluginName: string;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Legacy opcode registry, retained for the VM interface contract.
|
|
276
|
+
*
|
|
277
|
+
* Previously dispatched custom opcodes (>= 200) from the VM switch-default
|
|
278
|
+
* branch. Now plugins should use CALL_PLUGIN (opcode 50) via
|
|
279
|
+
* pluginFunctionRegistry instead.
|
|
280
|
+
*/
|
|
281
|
+
declare class OpRegistry {
|
|
282
|
+
private handlers;
|
|
283
|
+
private nextOpcode;
|
|
284
|
+
register(registration: IOpcodeHandlerRegistration): void;
|
|
285
|
+
/**
|
|
286
|
+
* Remove a previously registered opcode handler.
|
|
287
|
+
* Used by package unregistration to reverse shared-registry contributions.
|
|
288
|
+
*/
|
|
289
|
+
unregister(opcode: number): void;
|
|
290
|
+
get(opcode: number): OpcodeHandler | undefined;
|
|
291
|
+
has(opcode: number): boolean;
|
|
292
|
+
/**
|
|
293
|
+
* Allocate a unique opcode for a plugin's custom bytecode handler.
|
|
294
|
+
*
|
|
295
|
+
* Returns the next available opcode (starting at 201). Each call
|
|
296
|
+
* returns a distinct value. Plugins should call this once during
|
|
297
|
+
* registration and store the result.
|
|
298
|
+
*
|
|
299
|
+
* @throws If the dynamic opcode pool is exhausted.
|
|
300
|
+
* @returns A unique opcode number for the calling plugin.
|
|
301
|
+
*/
|
|
302
|
+
allocateOpcode(): number;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* VM interface consumed by opcode handlers and the bytecode executor.
|
|
306
|
+
*
|
|
307
|
+
* Provides stack operations, variable access, instruction counting,
|
|
308
|
+
* and abort signal management for async cancellation.
|
|
309
|
+
*/
|
|
310
|
+
interface VM {
|
|
311
|
+
push(value: Value): void;
|
|
312
|
+
pop(): Value;
|
|
313
|
+
popNumber(): number;
|
|
314
|
+
popString(): string;
|
|
315
|
+
peek(): Value;
|
|
316
|
+
getStack(): Value[];
|
|
317
|
+
registry: OpRegistry;
|
|
318
|
+
/**
|
|
319
|
+
* Read a variable by name, checks the INNERMOST active user-defined-
|
|
320
|
+
* function call frame first (see `pushCallFrame`), then falls back to
|
|
321
|
+
* the flat, session-scoped variable store. This is why a function
|
|
322
|
+
* parameter needs no dedicated load opcode: an ordinary `LOAD_VAR
|
|
323
|
+
* "x"` inside a function body resolves to the current call's bound
|
|
324
|
+
* argument automatically, without the parser needing to know it's
|
|
325
|
+
* compiling a function body at all.
|
|
326
|
+
*/
|
|
327
|
+
getVar(key: string): Value | undefined;
|
|
328
|
+
setVar(key: string, value: Value): void;
|
|
329
|
+
/**
|
|
330
|
+
* User-defined-function call frame, a name-keyed `Map` of this call's
|
|
331
|
+
* bound arguments, PUSHED before `CALL_USER_FUNCTION` executes the
|
|
332
|
+
* callee's body and POPPED immediately after (even if the body throws),
|
|
333
|
+
* so nested/recursive calls (`double(double(5))`) each get their own
|
|
334
|
+
* frame instead of clobbering a shared flat map. See `vm/VM.ts`'s
|
|
335
|
+
* `CALL_USER_FUNCTION` case. Deliberately NOT the same store as
|
|
336
|
+
* `setVar`'s flat `:name` variables, a call frame is call-scoped and
|
|
337
|
+
* stacked (only the INNERMOST frame is ever consulted by `getVar`, see
|
|
338
|
+
* its own doc comment, no lexical capture of an outer call's
|
|
339
|
+
* parameters), a variable is session-scoped and flat.
|
|
340
|
+
*
|
|
341
|
+
* @throws `FUNCTION_RECURSION_LIMIT_EXCEEDED` if pushing would exceed
|
|
342
|
+
* the VM's configured `maxFunctionRecursionDepth`, the backstop for
|
|
343
|
+
* `f(x) = f(x)`, which would otherwise recurse via nested
|
|
344
|
+
* `executeBytecode()` calls until the native V8 stack overflows
|
|
345
|
+
* uncatchably (each reentrant call gets its OWN fresh
|
|
346
|
+
* `localInstructionCount`, so `maxInstructions` cannot catch this).
|
|
347
|
+
*/
|
|
348
|
+
pushCallFrame(frame: Map<string, Value>): void;
|
|
349
|
+
popCallFrame(): void;
|
|
350
|
+
/** Register (or redefine, overwrites any previous definition, matching `:name = value`'s own reassignment semantics) a user-defined function. */
|
|
351
|
+
defineUserFunction(name: string, params: string[], program: BytecodeProgram): void;
|
|
352
|
+
getUserFunction(name: string): UserFunctionDef | undefined;
|
|
353
|
+
hasUserFunction(name: string): boolean;
|
|
354
|
+
/** Register (or redefine) a bare equation (`a*x = rhs`), keyed by its free variable. See {@link EquationDef}. */
|
|
355
|
+
defineEquation(variable: string, factorNames: string[], rhsProgram: BytecodeProgram): void;
|
|
356
|
+
getEquation(variable: string): EquationDef | undefined;
|
|
357
|
+
hasEquation(variable: string): boolean;
|
|
358
|
+
/** Register (or redefine) a stored scalar equation (`x^2-4 = 0`), keyed by its unknown. See {@link ScalarEquationDef}. */
|
|
359
|
+
defineScalarEquation(variable: string, lhsProgram: BytecodeProgram, rhsProgram: BytecodeProgram): void;
|
|
360
|
+
getScalarEquation(variable: string): ScalarEquationDef | undefined;
|
|
361
|
+
hasScalarEquation(variable: string): boolean;
|
|
362
|
+
reset(): void;
|
|
363
|
+
getMaxInstructions(): number;
|
|
364
|
+
getMaxStackDepth(): number;
|
|
365
|
+
getInstructionCount(): number;
|
|
366
|
+
incrementInstructions(n: number): void;
|
|
367
|
+
/** Active AbortSignal for the current expression evaluation. Checked before cache writes. */
|
|
368
|
+
activeSignal?: AbortSignal;
|
|
369
|
+
/** Abort the current evaluation (called when expression changes before resolution). */
|
|
370
|
+
abortCurrent?: () => void;
|
|
371
|
+
/**
|
|
372
|
+
* Registries belonging to the engine that created this VM.
|
|
373
|
+
*
|
|
374
|
+
* `CALL_PLUGIN` resolves handlers through here rather than through a
|
|
375
|
+
* module-level registry, so two engines in one process no longer share the
|
|
376
|
+
* plugin functions their packages registered. This follows what
|
|
377
|
+
* `userFunctions` and `equations` already do by being VM-instance scoped.
|
|
378
|
+
*/
|
|
379
|
+
context: EngineContext;
|
|
380
|
+
}
|
|
381
|
+
/** Shared singleton OpRegistry, used when no custom opcodes are needed. */
|
|
382
|
+
declare const sharedOpRegistry: OpRegistry;
|
|
383
|
+
|
|
384
|
+
/** Serialized snapshot of the dependency graph for diagnostic rendering. */
|
|
385
|
+
interface DagSnapshot {
|
|
386
|
+
consumers: Record<string, number[]>;
|
|
387
|
+
writes: Record<number, string[]>;
|
|
388
|
+
reads: Record<number, string[]>;
|
|
389
|
+
dataSourceDeps: Record<number, string[]>;
|
|
390
|
+
dataSourceConsumers: Record<string, number[]>;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Dependency graph for variable and data-source tracking across document lines.
|
|
394
|
+
*
|
|
395
|
+
* Tracks which lines read/write which variables, and propagates changes through
|
|
396
|
+
* the graph when a variable is modified. Supports:
|
|
397
|
+
* - Variable dependency tracking (registerLine, getAffectedLines)
|
|
398
|
+
* - Data-source dependency tracking (registerLineDataSourceDependency)
|
|
399
|
+
* - Topological ordering of affected lines (getAffectedLinesInOrder)
|
|
400
|
+
* - Efficient removal of deleted lines (removeLine)
|
|
401
|
+
*/
|
|
402
|
+
declare class DependencyGraph {
|
|
403
|
+
private consumers;
|
|
404
|
+
private dependencies;
|
|
405
|
+
private writes;
|
|
406
|
+
private lineReads;
|
|
407
|
+
private dataSourceDependencies;
|
|
408
|
+
private dataSourceConsumers;
|
|
409
|
+
/**
|
|
410
|
+
* Register a line's variable reads and writes in the dependency graph.
|
|
411
|
+
*
|
|
412
|
+
* If re-registering the same line (e.g., after editing), old consumer
|
|
413
|
+
* references are cleaned up first. Write-variables are removed from
|
|
414
|
+
* the consumer set so that redefinition breaks the old dependency chain.
|
|
415
|
+
*
|
|
416
|
+
* @param lineNumber - 1-based line number in the document
|
|
417
|
+
* @param reads - Variable names this line reads
|
|
418
|
+
* @param writes - Variable names this line writes (assigns to)
|
|
419
|
+
*/
|
|
420
|
+
registerLine(lineNumber: number, reads: string[], writes: string[]): void;
|
|
421
|
+
/**
|
|
422
|
+
* Register a line's dependency on an external data source (e.g., currency rate, OSRS GE price).
|
|
423
|
+
*
|
|
424
|
+
* When the data source updates, {@link getAffectedLinesByDataSource} returns all lines
|
|
425
|
+
* that depend on this data, enabling targeted re-evaluation.
|
|
426
|
+
*
|
|
427
|
+
* @param lineNumber - 1-based line number in the document
|
|
428
|
+
* @param dataSourceId - Unique identifier for the data source (e.g., "currency", "osrs-ge")
|
|
429
|
+
* @param queryKey - Query key array identifying the specific data (e.g., ["USD", "EUR"])
|
|
430
|
+
*/
|
|
431
|
+
registerLineDataSourceDependency(lineNumber: number, dataSourceId: string, queryKey: string[]): void;
|
|
432
|
+
/**
|
|
433
|
+
* Find all lines affected by a changed variable via BFS through the consumer graph.
|
|
434
|
+
*
|
|
435
|
+
* When a variable is modified (e.g., `:x = 5` changes to `:x = 10`), this returns
|
|
436
|
+
* all lines that transitively depend on it, lines that read `x`, lines that read
|
|
437
|
+
* variables written by those lines, and so on.
|
|
438
|
+
*
|
|
439
|
+
* @param changedVariable - The variable name that changed
|
|
440
|
+
* @returns Set of line numbers that need re-evaluation
|
|
441
|
+
*/
|
|
442
|
+
getAffectedLines(changedVariable: string): Set<number>;
|
|
443
|
+
/**
|
|
444
|
+
* Phase 1.4 DAG-walk optimization: return affected lines in dependency-safe
|
|
445
|
+
* topological order. Uses Kahn's algorithm (BFS-based) to ensure every line
|
|
446
|
+
* is evaluated AFTER all lines it depends on have been processed.
|
|
447
|
+
*
|
|
448
|
+
* This is more correct than ascending line-number sort, which fails when
|
|
449
|
+
* variable definitions and their consumers are not in document order.
|
|
450
|
+
*
|
|
451
|
+
* @returns Line numbers in topological order (producers before consumers).
|
|
452
|
+
*/
|
|
453
|
+
getAffectedLinesInOrder(startVariable: string): number[];
|
|
454
|
+
/**
|
|
455
|
+
* Find all lines affected by a data source update.
|
|
456
|
+
*
|
|
457
|
+
* When an async data source resolves (e.g., currency rate fetch completes),
|
|
458
|
+
* this returns all lines that depend on that specific data query.
|
|
459
|
+
*
|
|
460
|
+
* @param dataSourceId - The data source identifier
|
|
461
|
+
* @param queryKey - The query key that was updated
|
|
462
|
+
* @returns Set of line numbers that need re-evaluation
|
|
463
|
+
*/
|
|
464
|
+
getAffectedLinesByDataSource(dataSourceId: string, queryKey: string[]): Set<number>;
|
|
465
|
+
/**
|
|
466
|
+
* Remove a line from the dependency graph (e.g., when a line is deleted from the document).
|
|
467
|
+
*
|
|
468
|
+
* Cleans up all consumer references, write registrations, and data source dependencies
|
|
469
|
+
* for the removed line. O(k) where k is the number of variables the line reads.
|
|
470
|
+
*
|
|
471
|
+
* @param lineNumber - The line number being removed
|
|
472
|
+
*/
|
|
473
|
+
removeLine(lineNumber: number): void;
|
|
474
|
+
/**
|
|
475
|
+
* Get all line numbers that consume (read) a given variable.
|
|
476
|
+
*
|
|
477
|
+
* @param variable - The variable name
|
|
478
|
+
* @returns Set of line numbers that read this variable, or empty set if none
|
|
479
|
+
*/
|
|
480
|
+
getConsumers(variable: string): Set<number>;
|
|
481
|
+
/**
|
|
482
|
+
* Get all variables that a line depends on (reads).
|
|
483
|
+
*
|
|
484
|
+
* @param lineNumber - The line number to query
|
|
485
|
+
* @returns Set of variable names this line reads, or empty set if none
|
|
486
|
+
*/
|
|
487
|
+
getDependencies(lineNumber: number): Set<string>;
|
|
488
|
+
/**
|
|
489
|
+
* Get all variables that a line writes (assigns to).
|
|
490
|
+
*
|
|
491
|
+
* @param lineNumber - The line number to query
|
|
492
|
+
* @returns Set of variable names this line writes, or empty set if none
|
|
493
|
+
*/
|
|
494
|
+
getWrites(lineNumber: number): Set<string>;
|
|
495
|
+
/**
|
|
496
|
+
* Get a serializable snapshot of the entire dependency graph for diagnostics.
|
|
497
|
+
*
|
|
498
|
+
* Returns plain objects (not Maps/Sets) so consumers don't need to reach
|
|
499
|
+
* into private fields. Used by playground diagnostic tabs for DAG visualization.
|
|
500
|
+
*/
|
|
501
|
+
getSnapshot(): DagSnapshot;
|
|
502
|
+
/** Clear all dependency graph state. Called on document switch or engine reset. */
|
|
503
|
+
clear(): void;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Record of a compiled expression in the scope.
|
|
508
|
+
* Tracks the expression text, compiled bytecode, last evaluation result,
|
|
509
|
+
* and the variable reads/writes for dependency tracking.
|
|
510
|
+
*/
|
|
511
|
+
interface ExpressionRecord {
|
|
512
|
+
lineNumber: number;
|
|
513
|
+
expression: string;
|
|
514
|
+
bytecode: {
|
|
515
|
+
opcodes: Uint8Array;
|
|
516
|
+
numbers: Float64Array;
|
|
517
|
+
strings: string[];
|
|
518
|
+
};
|
|
519
|
+
lastResult: Value;
|
|
520
|
+
readVariables: string[];
|
|
521
|
+
writeVariable: string | null;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Scoped variable manager for expression evaluation.
|
|
525
|
+
*
|
|
526
|
+
* Tracks variable definitions across line numbers with write-on-read semantics.
|
|
527
|
+
* When a value is read, the most recent definition at or before the reading line
|
|
528
|
+
* is returned. Invalidation trims downstream definitions when a variable is redefined.
|
|
529
|
+
*/
|
|
530
|
+
declare class ScopeManager {
|
|
531
|
+
private definitions;
|
|
532
|
+
/**
|
|
533
|
+
* Record a variable definition at `lineNumber`. A variable may have
|
|
534
|
+
* multiple definitions across different lines (e.g. redefined further
|
|
535
|
+
* down a document), each call adds one, keeping the internal stack
|
|
536
|
+
* sorted by line so {@link read} can binary-scan for "most recent
|
|
537
|
+
* definition at or before" a given line.
|
|
538
|
+
*/
|
|
539
|
+
write(variable: string, lineNumber: number, expr: ExpressionRecord): void;
|
|
540
|
+
/**
|
|
541
|
+
* Look up a variable's value as seen from `readLine`: returns the result
|
|
542
|
+
* of the closest definition at or before `readLine`, not simply the most
|
|
543
|
+
* recently-written one, so a read on line 5 of a variable redefined on
|
|
544
|
+
* lines 2 and 10 sees line 2's value, not line 10's. Returns `undefined`
|
|
545
|
+
* if the variable has no definition at or before `readLine`.
|
|
546
|
+
*/
|
|
547
|
+
read(variable: string, readLine: number): Value | undefined;
|
|
548
|
+
/**
|
|
549
|
+
* Drop every definition of `variable` that comes strictly after
|
|
550
|
+
* `definitionLine`. Call this when a line is re-evaluated with a new
|
|
551
|
+
* definition, so stale later-line definitions from a previous edit don't
|
|
552
|
+
* linger and get returned by {@link read}.
|
|
553
|
+
*/
|
|
554
|
+
invalidateDownstream(variable: string, definitionLine: number): void;
|
|
555
|
+
/** Remove every tracked variable definition, used when an engine/document is reset. */
|
|
556
|
+
clear(): void;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export { type Bytecode as B, DependencyGraph as D, type ExpressionRecord as E, type LineExecutionContext as L, OpRegistry as O, type PluginFunctionHandler as P, ScopeManager as S, type VM as V, type DagSnapshot as a, type EngineContext as b, createVM as c, executeBytecode as e, sharedOpRegistry as s };
|