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.
Files changed (253) hide show
  1. package/dist/BytecodeBuilder-3egMyuDi.d.cts +274 -0
  2. package/dist/BytecodeBuilder-3egMyuDi.d.ts +274 -0
  3. package/dist/Configuration-fVpd-HC-.d.cts +228 -0
  4. package/dist/Configuration-fVpd-HC-.d.ts +228 -0
  5. package/dist/EngineError-DvPSnhZi.d.cts +304 -0
  6. package/dist/EngineError-DvPSnhZi.d.ts +304 -0
  7. package/dist/Lexer-BJdhlnej.d.cts +531 -0
  8. package/dist/Lexer-D9l4Yrk2.d.ts +531 -0
  9. package/dist/NormalizerRule-BrVoVjmP.d.cts +163 -0
  10. package/dist/NormalizerRule-CEjf1FyD.d.ts +163 -0
  11. package/dist/PackageRegistry-D-Tv_7ca.d.cts +2572 -0
  12. package/dist/PackageRegistry-DaH4aIKP.d.ts +2572 -0
  13. package/dist/Parselet-CK8cQu2a.d.cts +299 -0
  14. package/dist/Parselet-ConOIdRO.d.ts +299 -0
  15. package/dist/ScopeManager-B5k0nk05.d.ts +559 -0
  16. package/dist/ScopeManager-CKfQtl7l.d.cts +559 -0
  17. package/dist/Token-0jpvUdPY.d.cts +245 -0
  18. package/dist/Token-0jpvUdPY.d.ts +245 -0
  19. package/dist/VMCheckpoints-BmDwIXgK.d.ts +171 -0
  20. package/dist/VMCheckpoints-CqFuLwrT.d.cts +171 -0
  21. package/dist/Value-KtAQNHur.d.cts +295 -0
  22. package/dist/Value-KtAQNHur.d.ts +295 -0
  23. package/dist/chunk-2RWAXT6O.js +3 -0
  24. package/dist/chunk-2RWAXT6O.js.map +1 -0
  25. package/dist/chunk-34RRD7PC.js +1492 -0
  26. package/dist/chunk-34RRD7PC.js.map +1 -0
  27. package/dist/chunk-3PPFLFH4.js +5097 -0
  28. package/dist/chunk-3PPFLFH4.js.map +1 -0
  29. package/dist/chunk-3VGDNEE3.js +84 -0
  30. package/dist/chunk-3VGDNEE3.js.map +1 -0
  31. package/dist/chunk-3YNVWKR2.cjs +370 -0
  32. package/dist/chunk-3YNVWKR2.cjs.map +1 -0
  33. package/dist/chunk-47LRVGOT.cjs +316 -0
  34. package/dist/chunk-47LRVGOT.cjs.map +1 -0
  35. package/dist/chunk-4MG4XKO2.js +1644 -0
  36. package/dist/chunk-4MG4XKO2.js.map +1 -0
  37. package/dist/chunk-4QADQTWS.js +2392 -0
  38. package/dist/chunk-4QADQTWS.js.map +1 -0
  39. package/dist/chunk-53B6KDDJ.cjs +1651 -0
  40. package/dist/chunk-53B6KDDJ.cjs.map +1 -0
  41. package/dist/chunk-5X2PTP6F.cjs +104 -0
  42. package/dist/chunk-5X2PTP6F.cjs.map +1 -0
  43. package/dist/chunk-5YEMOYSE.js +264 -0
  44. package/dist/chunk-5YEMOYSE.js.map +1 -0
  45. package/dist/chunk-64W6GLLZ.js +481 -0
  46. package/dist/chunk-64W6GLLZ.js.map +1 -0
  47. package/dist/chunk-6BKTCEUP.cjs +233 -0
  48. package/dist/chunk-6BKTCEUP.cjs.map +1 -0
  49. package/dist/chunk-6NTVRDQV.cjs +1642 -0
  50. package/dist/chunk-6NTVRDQV.cjs.map +1 -0
  51. package/dist/chunk-6RDSQURE.js +290 -0
  52. package/dist/chunk-6RDSQURE.js.map +1 -0
  53. package/dist/chunk-75JP4BZX.js +93 -0
  54. package/dist/chunk-75JP4BZX.js.map +1 -0
  55. package/dist/chunk-B7LXJ6LC.cjs +36 -0
  56. package/dist/chunk-B7LXJ6LC.cjs.map +1 -0
  57. package/dist/chunk-BVAR5J2F.js +257 -0
  58. package/dist/chunk-BVAR5J2F.js.map +1 -0
  59. package/dist/chunk-C4XZV6E7.cjs +269 -0
  60. package/dist/chunk-C4XZV6E7.cjs.map +1 -0
  61. package/dist/chunk-CCJPSHGI.cjs +40 -0
  62. package/dist/chunk-CCJPSHGI.cjs.map +1 -0
  63. package/dist/chunk-CLL7RUQV.cjs +316 -0
  64. package/dist/chunk-CLL7RUQV.cjs.map +1 -0
  65. package/dist/chunk-DM3LMRBC.js +329 -0
  66. package/dist/chunk-DM3LMRBC.js.map +1 -0
  67. package/dist/chunk-DUEZFTK2.js +38 -0
  68. package/dist/chunk-DUEZFTK2.js.map +1 -0
  69. package/dist/chunk-EBSPLUW4.cjs +489 -0
  70. package/dist/chunk-EBSPLUW4.cjs.map +1 -0
  71. package/dist/chunk-EHAHVROS.cjs +261 -0
  72. package/dist/chunk-EHAHVROS.cjs.map +1 -0
  73. package/dist/chunk-EIGTWK5N.js +167 -0
  74. package/dist/chunk-EIGTWK5N.js.map +1 -0
  75. package/dist/chunk-EPOXXJBK.js +96 -0
  76. package/dist/chunk-EPOXXJBK.js.map +1 -0
  77. package/dist/chunk-FEAIOR7N.cjs +91 -0
  78. package/dist/chunk-FEAIOR7N.cjs.map +1 -0
  79. package/dist/chunk-G535KJEG.js +312 -0
  80. package/dist/chunk-G535KJEG.js.map +1 -0
  81. package/dist/chunk-GCM5JHMX.js +88 -0
  82. package/dist/chunk-GCM5JHMX.js.map +1 -0
  83. package/dist/chunk-GOLDJNMZ.js +368 -0
  84. package/dist/chunk-GOLDJNMZ.js.map +1 -0
  85. package/dist/chunk-GW32KPCU.cjs +360 -0
  86. package/dist/chunk-GW32KPCU.cjs.map +1 -0
  87. package/dist/chunk-HTXVVJRA.cjs +1549 -0
  88. package/dist/chunk-HTXVVJRA.cjs.map +1 -0
  89. package/dist/chunk-HWSZJQCI.js +311 -0
  90. package/dist/chunk-HWSZJQCI.js.map +1 -0
  91. package/dist/chunk-IF532O7C.js +101 -0
  92. package/dist/chunk-IF532O7C.js.map +1 -0
  93. package/dist/chunk-J73SJHR3.cjs +2415 -0
  94. package/dist/chunk-J73SJHR3.cjs.map +1 -0
  95. package/dist/chunk-JBSYC7BB.cjs +7473 -0
  96. package/dist/chunk-JBSYC7BB.cjs.map +1 -0
  97. package/dist/chunk-KVILKGMS.js +228 -0
  98. package/dist/chunk-KVILKGMS.js.map +1 -0
  99. package/dist/chunk-LIPPNDBE.js +258 -0
  100. package/dist/chunk-LIPPNDBE.js.map +1 -0
  101. package/dist/chunk-LR7YASZF.cjs +172 -0
  102. package/dist/chunk-LR7YASZF.cjs.map +1 -0
  103. package/dist/chunk-M4N5GA5Z.cjs +309 -0
  104. package/dist/chunk-M4N5GA5Z.cjs.map +1 -0
  105. package/dist/chunk-M5LX5AOO.js +7459 -0
  106. package/dist/chunk-M5LX5AOO.js.map +1 -0
  107. package/dist/chunk-MZOVP3WI.cjs +96 -0
  108. package/dist/chunk-MZOVP3WI.cjs.map +1 -0
  109. package/dist/chunk-N5YFR4UP.cjs +10 -0
  110. package/dist/chunk-N5YFR4UP.cjs.map +1 -0
  111. package/dist/chunk-NGBBNL4K.cjs +4 -0
  112. package/dist/chunk-NGBBNL4K.cjs.map +1 -0
  113. package/dist/chunk-NH2O2AUR.js +146 -0
  114. package/dist/chunk-NH2O2AUR.js.map +1 -0
  115. package/dist/chunk-NLNDMWZC.js +31 -0
  116. package/dist/chunk-NLNDMWZC.js.map +1 -0
  117. package/dist/chunk-NMCRQP3Z.cjs +778 -0
  118. package/dist/chunk-NMCRQP3Z.cjs.map +1 -0
  119. package/dist/chunk-NMD5VRN4.cjs +1327 -0
  120. package/dist/chunk-NMD5VRN4.cjs.map +1 -0
  121. package/dist/chunk-OC6LTXYS.cjs +286 -0
  122. package/dist/chunk-OC6LTXYS.cjs.map +1 -0
  123. package/dist/chunk-OT6OJY7C.cjs +114 -0
  124. package/dist/chunk-OT6OJY7C.cjs.map +1 -0
  125. package/dist/chunk-PFSDGGYL.js +8 -0
  126. package/dist/chunk-PFSDGGYL.js.map +1 -0
  127. package/dist/chunk-QNJ4ACRT.cjs +155 -0
  128. package/dist/chunk-QNJ4ACRT.cjs.map +1 -0
  129. package/dist/chunk-QWY3VEZN.js +1637 -0
  130. package/dist/chunk-QWY3VEZN.js.map +1 -0
  131. package/dist/chunk-RFYD5TJE.js +111 -0
  132. package/dist/chunk-RFYD5TJE.js.map +1 -0
  133. package/dist/chunk-RIN643A3.js +354 -0
  134. package/dist/chunk-RIN643A3.js.map +1 -0
  135. package/dist/chunk-RZCWSXTA.cjs +5122 -0
  136. package/dist/chunk-RZCWSXTA.cjs.map +1 -0
  137. package/dist/chunk-SDGRK7EP.js +774 -0
  138. package/dist/chunk-SDGRK7EP.js.map +1 -0
  139. package/dist/chunk-VEKIWQ3F.cjs +39 -0
  140. package/dist/chunk-VEKIWQ3F.cjs.map +1 -0
  141. package/dist/chunk-WQTTOGXC.cjs +99 -0
  142. package/dist/chunk-WQTTOGXC.cjs.map +1 -0
  143. package/dist/chunk-X6K3HUOY.cjs +86 -0
  144. package/dist/chunk-X6K3HUOY.cjs.map +1 -0
  145. package/dist/chunk-XJCMXB2E.cjs +333 -0
  146. package/dist/chunk-XJCMXB2E.cjs.map +1 -0
  147. package/dist/chunk-XVWCOTR6.js +1324 -0
  148. package/dist/chunk-XVWCOTR6.js.map +1 -0
  149. package/dist/chunk-YLJ4XMA6.js +33 -0
  150. package/dist/chunk-YLJ4XMA6.js.map +1 -0
  151. package/dist/chunk-Z2XP767T.cjs +35 -0
  152. package/dist/chunk-Z2XP767T.cjs.map +1 -0
  153. package/dist/chunk-Z4X2RWOF.js +37 -0
  154. package/dist/chunk-Z4X2RWOF.js.map +1 -0
  155. package/dist/constants.cjs +22 -0
  156. package/dist/constants.cjs.map +1 -0
  157. package/dist/constants.d.cts +12 -0
  158. package/dist/constants.d.ts +12 -0
  159. package/dist/constants.js +5 -0
  160. package/dist/constants.js.map +1 -0
  161. package/dist/engine.cjs +79 -0
  162. package/dist/engine.cjs.map +1 -0
  163. package/dist/engine.d.cts +587 -0
  164. package/dist/engine.d.ts +587 -0
  165. package/dist/engine.js +34 -0
  166. package/dist/engine.js.map +1 -0
  167. package/dist/errors.cjs +81 -0
  168. package/dist/errors.cjs.map +1 -0
  169. package/dist/errors.d.cts +95 -0
  170. package/dist/errors.d.ts +95 -0
  171. package/dist/errors.js +4 -0
  172. package/dist/errors.js.map +1 -0
  173. package/dist/format.cjs +171 -0
  174. package/dist/format.cjs.map +1 -0
  175. package/dist/format.d.cts +51 -0
  176. package/dist/format.d.ts +51 -0
  177. package/dist/format.js +168 -0
  178. package/dist/format.js.map +1 -0
  179. package/dist/index.cjs +97 -0
  180. package/dist/index.cjs.map +1 -0
  181. package/dist/index.d.cts +152 -0
  182. package/dist/index.d.ts +152 -0
  183. package/dist/index.js +75 -0
  184. package/dist/index.js.map +1 -0
  185. package/dist/language.cjs +308 -0
  186. package/dist/language.cjs.map +1 -0
  187. package/dist/language.d.cts +110 -0
  188. package/dist/language.d.ts +110 -0
  189. package/dist/language.js +287 -0
  190. package/dist/language.js.map +1 -0
  191. package/dist/lexer.cjs +64 -0
  192. package/dist/lexer.cjs.map +1 -0
  193. package/dist/lexer.d.cts +56 -0
  194. package/dist/lexer.d.ts +56 -0
  195. package/dist/lexer.js +11 -0
  196. package/dist/lexer.js.map +1 -0
  197. package/dist/normalizer.cjs +40 -0
  198. package/dist/normalizer.cjs.map +1 -0
  199. package/dist/normalizer.d.cts +364 -0
  200. package/dist/normalizer.d.ts +364 -0
  201. package/dist/normalizer.js +11 -0
  202. package/dist/normalizer.js.map +1 -0
  203. package/dist/packages.cjs +121 -0
  204. package/dist/packages.cjs.map +1 -0
  205. package/dist/packages.d.cts +691 -0
  206. package/dist/packages.d.ts +691 -0
  207. package/dist/packages.js +24 -0
  208. package/dist/packages.js.map +1 -0
  209. package/dist/parser.cjs +55 -0
  210. package/dist/parser.cjs.map +1 -0
  211. package/dist/parser.d.cts +46 -0
  212. package/dist/parser.d.ts +46 -0
  213. package/dist/parser.js +10 -0
  214. package/dist/parser.js.map +1 -0
  215. package/dist/pipeline-CrsRPmsv.d.ts +285 -0
  216. package/dist/pipeline-DPUQt7yL.d.cts +285 -0
  217. package/dist/resolvers.cjs +13 -0
  218. package/dist/resolvers.cjs.map +1 -0
  219. package/dist/resolvers.d.cts +111 -0
  220. package/dist/resolvers.d.ts +111 -0
  221. package/dist/resolvers.js +4 -0
  222. package/dist/resolvers.js.map +1 -0
  223. package/dist/services.cjs +21 -0
  224. package/dist/services.cjs.map +1 -0
  225. package/dist/services.d.cts +30 -0
  226. package/dist/services.d.ts +30 -0
  227. package/dist/services.js +4 -0
  228. package/dist/services.js.map +1 -0
  229. package/dist/uom.cjs +56 -0
  230. package/dist/uom.cjs.map +1 -0
  231. package/dist/uom.d.cts +224 -0
  232. package/dist/uom.d.ts +224 -0
  233. package/dist/uom.js +11 -0
  234. package/dist/uom.js.map +1 -0
  235. package/dist/utilities.cjs +32 -0
  236. package/dist/utilities.cjs.map +1 -0
  237. package/dist/utilities.d.cts +113 -0
  238. package/dist/utilities.d.ts +113 -0
  239. package/dist/utilities.js +7 -0
  240. package/dist/utilities.js.map +1 -0
  241. package/dist/variables.cjs +17 -0
  242. package/dist/variables.cjs.map +1 -0
  243. package/dist/variables.d.cts +87 -0
  244. package/dist/variables.d.ts +87 -0
  245. package/dist/variables.js +4 -0
  246. package/dist/variables.js.map +1 -0
  247. package/dist/vm.cjs +284 -0
  248. package/dist/vm.cjs.map +1 -0
  249. package/dist/vm.d.cts +68 -0
  250. package/dist/vm.d.ts +68 -0
  251. package/dist/vm.js +194 -0
  252. package/dist/vm.js.map +1 -0
  253. package/package.json +4 -4
@@ -0,0 +1,587 @@
1
+ import { D as DocumentModel, a as ExpressionEngine, V as ViewportRange, c as LineChange, d as InlineSolvePosition } from './PackageRegistry-D-Tv_7ca.cjs';
2
+ export { A as ApplyChangesResult, e as AsyncCachePackageInfo, f as AsyncErrorEvent, g as AsyncResolutionBatcher, h as AsyncResolutionEvent, B as BatcherMetrics, i as BytecodeCacheEntry, C as CacheSnapshot, j as CheckpointSnapshot, E as EvalResults, k as LineCacheEntryInfo, L as LineEvaluation, l as LineState, m as LinesUpdatedEvent } from './PackageRegistry-D-Tv_7ca.cjs';
3
+ import { V as Value } from './Value-KtAQNHur.cjs';
4
+ import { a as VMCheckpointer } from './VMCheckpoints-CqFuLwrT.cjs';
5
+ import { T as Token } from './Token-0jpvUdPY.cjs';
6
+ import { E as EngineError } from './EngineError-DvPSnhZi.cjs';
7
+ import { a as BytecodeProgram } from './BytecodeBuilder-3egMyuDi.cjs';
8
+ export { a as DagSnapshot } from './ScopeManager-CKfQtl7l.cjs';
9
+ import './Parselet-CK8cQu2a.cjs';
10
+ import './pipeline-DPUQt7yL.cjs';
11
+ import './variables.cjs';
12
+ import './Lexer-BJdhlnej.cjs';
13
+ import './resolvers.cjs';
14
+ import '@tanstack/query-core';
15
+ import './NormalizerRule-BrVoVjmP.cjs';
16
+ import './Configuration-fVpd-HC-.cjs';
17
+
18
+ /**
19
+ * PageManager, page-based LRU eviction + directional preloading.
20
+ *
21
+ * Groups document lines into fixed-size pages (128 lines each) and manages
22
+ * three temperature tiers:
23
+ * • Hot (viewport ± 3 pages): Keep bytecode + results
24
+ * • Warm (viewport ± 6 pages): Keep bytecode, evict results
25
+ * • Cold (beyond ± 6 pages): Evict bytecode + results (except variable defs)
26
+ *
27
+ * Variable definition bytecode is **never evicted** because it forms the
28
+ * backbone of the dependency graph and VM checkpoints.
29
+ *
30
+ * Preloading: When the user scrolls in a consistent direction, the next
31
+ * 1–2 pages are pre-compiled via the background worker so bytecode is
32
+ * cache-hot by the time those lines scroll into view.
33
+ *
34
+ * Usage:
35
+ * const pm = new PageManager();
36
+ * // After evaluation:
37
+ * pm.maintainAfterEval(viewport, doc);
38
+ * // After scroll (viewport-only change):
39
+ * pm.maintainAfterEval(viewport, doc);
40
+ * const targets = pm.getPreloadTargets(viewport, doc);
41
+ * // dispatch targets to compilation worker
42
+ */
43
+
44
+ /**
45
+ * Splits a long document into pages so only what is near the viewport is held
46
+ * in full.
47
+ *
48
+ * A document is edited constantly and most of it is off screen. Paging keeps
49
+ * the cost of a keystroke proportional to what is visible rather than to the
50
+ * length of the document.
51
+ */
52
+ declare class PageManager {
53
+ /** Previous viewport for scroll direction detection. null = no previous viewport. */
54
+ private lastViewportStart;
55
+ /** Saved scroll direction from the most recent maintainAfterEval call. */
56
+ private savedDirection;
57
+ /** Per-page access counter for LRU tracking. */
58
+ private pageAccess;
59
+ /** Monotonically increasing access sequence number. */
60
+ private accessSeq;
61
+ /** Get the page number for a 1-based line number (0-based page index). */
62
+ static pageForLine(lineNumber: number): number;
63
+ /** Get the 1-based inclusive line range for a page. */
64
+ static pageRange(pageNum: number, docLineCount: number): {
65
+ startLine: number;
66
+ endLine: number;
67
+ };
68
+ /**
69
+ * Detect scroll direction from viewport movement.
70
+ * Returns null on first call (no previous viewport) or no movement.
71
+ */
72
+ detectDirection(newViewport: {
73
+ startLine: number;
74
+ }): "down" | "up" | null;
75
+ /**
76
+ * Maintain page tiers after evaluation.
77
+ *
78
+ * 1. Records the new viewport position
79
+ * 2. Touches hot pages (viewport ± HOT_PAGE_RADIUS) for LRU
80
+ * 3. Evicts cold/warm pages based on distance from viewport
81
+ *
82
+ * Call this after every `evaluate()`, `setViewport()`, or `evaluateAll()`.
83
+ */
84
+ maintainAfterEval(viewport: {
85
+ startLine: number;
86
+ endLine: number;
87
+ }, doc: DocumentModel): void;
88
+ /**
89
+ * Get lines ahead of the viewport that should be pre-compiled.
90
+ *
91
+ * Looks PRELOAD_PAGE_COUNT pages ahead of the current scroll direction.
92
+ * Only returns lines that are dirty, don't already have bytecode,
93
+ * and are not empty/markdown-only.
94
+ *
95
+ * @param viewport The current viewport.
96
+ * @param doc The document model.
97
+ * @returns Items ready to send to the compilation worker.
98
+ */
99
+ getPreloadTargets(viewport: {
100
+ startLine: number;
101
+ endLine: number;
102
+ }, doc: DocumentModel): Array<{
103
+ lineId: number;
104
+ expression: string;
105
+ textHash: number;
106
+ }>;
107
+ /**
108
+ * Reset internal state (e.g., after document switch).
109
+ */
110
+ clear(): void;
111
+ /** Record a page access with a monotonic sequence number. */
112
+ private touchPage;
113
+ /**
114
+ * Evict results from all non-variable-def lines in a page.
115
+ * Bytecode is preserved so Tier 2 execution works on scroll-back.
116
+ */
117
+ private evictPageResults;
118
+ /**
119
+ * Evict bytecode + results from all non-variable-def lines in a page.
120
+ * Variable definition bytecode is **never** evicted, it forms the
121
+ * backbone of the DAG and VM checkpoints.
122
+ *
123
+ * Evicted lines are marked dirty so they get Tier 1 re-evaluation
124
+ * when scrolled back into view.
125
+ */
126
+ private evictPageBytecode;
127
+ }
128
+
129
+ /**
130
+ * How much work a line's evaluation required.
131
+ *
132
+ * The tiers exist because most lines in a document have not changed. A line
133
+ * that is clean and cached costs far less than one being compiled fresh, and
134
+ * knowing which happened is how a slow document gets diagnosed.
135
+ */
136
+ declare enum EvalTier {
137
+ /** Full pipeline: Lex → Parse → Compile → Execute (visible + dirty). */
138
+ Tier1 = 1,
139
+ /** Execute-only from cached bytecode (visible + cached). */
140
+ Tier2 = 2,
141
+ /** Compile-only for dependency tracking (invisible). Executes only variable assignments. */
142
+ Tier3 = 3,
143
+ /** Skipped, already clean or non-evaluable. */
144
+ Skipped = 0
145
+ }
146
+ /** Outcome for one line, including which tier handled it. */
147
+ interface EvalLineResult {
148
+ /** The line's persistent ID from DocumentModel. */
149
+ lineId: number;
150
+ /** 1-based line position. */
151
+ lineNumber: number;
152
+ /** Which tier was used. */
153
+ tier: EvalTier;
154
+ /** The first evaluation result, or null on error / non-evaluable. */
155
+ result: Value | null;
156
+ /** All result groups (one per expression/inline-solve), or undefined if skipped. */
157
+ results?: Value[][];
158
+ /** Error message, or null. */
159
+ error: string | null;
160
+ }
161
+ /** Outcome for a whole evaluation pass, with per-tier counts. */
162
+ interface EvalResult {
163
+ /** Per-line evaluation results. */
164
+ lines: EvalLineResult[];
165
+ /** Map of line numbers → flattened results for quick lookup. */
166
+ resultMap: Map<number, Value[]>;
167
+ /** Number of lines processed at each tier. */
168
+ tierCounts: {
169
+ tier1: number;
170
+ tier2: number;
171
+ tier3: number;
172
+ skipped: number;
173
+ };
174
+ }
175
+ /**
176
+ * Orchestrates three-tier evaluation over a persistent DocumentModel.
177
+ *
178
+ * ── Tier assignment ─────────────────────────────────────────────────
179
+ * | Tier | Condition | Action |
180
+ * |───────|────────────────────────────────────|───────────────────────────────|
181
+ * | **1** | Visible + Dirty (new/changed) | Full pipeline: lex→parse→compile→execute |
182
+ * | **2** | Visible + Cached (scroll into view)| Execute from cached bytecode |
183
+ * | **3** | Invisible + Dirty | Compile-only; execute only variable defs |
184
+ * | Skip | Clean, empty, or non-evaluable | No action |
185
+ *
186
+ * ── Evaluation order ─────────────────────────────────────────────────
187
+ * Lines are always processed in ascending document order (line 1 → end)
188
+ * so that variable assignments flow correctly through the shared VM.
189
+ * Tier 2 relies on this: by the time a clean cached line is reached,
190
+ * the VM already contains all variables from preceding Tier-1 lines.
191
+ *
192
+ * ── Thread safety ────────────────────────────────────────────────────
193
+ * Tier 1 (visible+dirty) compilation runs synchronously on the main thread
194
+ * for immediate rendering. Tier 3 (invisible+dirty) compilation can be
195
+ * dispatched to a Web Worker via `dispatchBackgroundCompiles()`. Worker-
196
+ * compiled bytecode is stored in the DocumentModel and validated via
197
+ * `isBytecodeValid()` to ensure the line text hasn't changed between
198
+ * dispatch and response.
199
+ */
200
+ declare class ThreeTierEvaluator {
201
+ private doc;
202
+ private engine;
203
+ private dag;
204
+ private checkpointer;
205
+ private compilationWorker;
206
+ private pageManager;
207
+ /**
208
+ * Unsubscribe from sharedGlobalVariableStore, set in the constructor
209
+ * called from terminateWorker(). See the subscription itself below for
210
+ * why this only marks lines dirty and never re-evaluates synchronously.
211
+ */
212
+ private globalUnsubscribe;
213
+ /**
214
+ * @param doc The persistent document model.
215
+ * @param engine The expression engine (shared VM is accessed via engine.getVM()).
216
+ * @param checkpointer Optional VM state checkpointer. If provided, the evaluator
217
+ * will create checkpoints after variable-definition lines and support fast VM
218
+ * restoration via `restoreTo()`. If omitted, checkpointing is disabled.
219
+ */
220
+ constructor(doc: DocumentModel, engine: ExpressionEngine, checkpointer?: VMCheckpointer);
221
+ /**
222
+ * Evaluate all lines needed to render the given viewport.
223
+ *
224
+ * Processes lines from 1 to `viewport.endLine` in document order.
225
+ * Dirty lines in the viewport get Tier-1 full pipeline; clean cached
226
+ * lines get Tier-2 bytecode execution. Lines after the viewport
227
+ * get Tier-3 compile-only (with variable-def execution).
228
+ *
229
+ * @returns Results for all processed lines, including tier metadata.
230
+ */
231
+ evaluate(viewport: ViewportRange, signal?: AbortSignal): EvalResult;
232
+ /**
233
+ * Background-compile invisible dirty lines beyond the viewport (Tier 3 only).
234
+ *
235
+ * Compiles expressions to discover reads/writes for the dependency graph
236
+ * without executing display-only expressions. Variable definitions are
237
+ * executed to maintain VM state for future Tier-2 executions.
238
+ *
239
+ * This is intended to be called after evaluate() so visible lines are
240
+ * rendered first, then background work fills in the dependency graph.
241
+ *
242
+ * **Phase 5.2h:** This synchronous method is retained for environments
243
+ * without Worker support. Prefer `dispatchBackgroundCompiles()` which
244
+ * offloads compilation to a Web Worker with Transferable bytecode.
245
+ */
246
+ backgroundCompile(viewport: ViewportRange): EvalLineResult[];
247
+ /**
248
+ * Dispatch background compilation to a Web Worker (Phase 5.2h).
249
+ *
250
+ * Collects invisible dirty lines beyond the viewport that need compilation,
251
+ * sends them to the compilation worker, and asynchronously stores the
252
+ * transferred bytecode in the DocumentModel when the worker responds.
253
+ *
254
+ * This is the non-blocking alternative to `backgroundCompile()`. The worker
255
+ * compiles expressions with Transferable ArrayBuffers (zero-copy postMessage),
256
+ * so bytecode appears on the main thread without serialization overhead.
257
+ *
258
+ * Lines that already have cached bytecode (from a previous worker pass or
259
+ * synchronous compile) are skipped, only truly uncompiled dirty lines are
260
+ * sent to the worker.
261
+ *
262
+ * **Usage:** Call after `evaluate()` so visible lines render first, then
263
+ * this fills the bytecode cache for future Tier-2 scrolls.
264
+ *
265
+ * @param viewport The current visible range. Lines beyond viewport.endLine
266
+ * that are dirty and don't have bytecode are dispatched.
267
+ */
268
+ dispatchBackgroundCompiles(viewport: ViewportRange): void;
269
+ /**
270
+ * Terminate the compilation worker if active, and unsubscribe from
271
+ * sharedGlobalVariableStore. Call this when the evaluator is no longer
272
+ * needed to clean up resources, every call site that retires a
273
+ * ThreeTierEvaluator (document switch, pane destroy()) already calls
274
+ * this unconditionally, so folding the global-store unsubscribe in here
275
+ * needs no new call sites anywhere.
276
+ */
277
+ terminateWorker(): void;
278
+ /**
279
+ * Get the DocumentModel (read-only access for decoration building).
280
+ */
281
+ getDoc(): DocumentModel;
282
+ /**
283
+ * Evaluate all dirty lines in the document, regardless of viewport.
284
+ * Used for full re-evaluation after plugin register/unregister.
285
+ */
286
+ evaluateAll(signal?: AbortSignal): EvalResult;
287
+ /**
288
+ * Zero-allocation viewport evaluation, the Phase 5.2e "holy grail."
289
+ *
290
+ * **Key insight:** When the user scrolls (viewport-only change, no edits),
291
+ * we don't need to re-evaluate from line 1. Instead:
292
+ *
293
+ * 1. Restore the VM to just before the viewport via the nearest checkpoint.
294
+ * 2. Evaluate ONLY the visible lines (Tier 2 for clean cached, Tier 1 for dirty).
295
+ * 3. Lines before the viewport are completely skipped, their state lives in
296
+ * the VM checkpointer's prototypal chain.
297
+ *
298
+ * **Correctness guard:** If any variable-definition line before the viewport
299
+ * is dirty (e.g., the user edited a variable def that hasn't been
300
+ * re-evaluated yet), we clear stale checkpoints and fall back to `evaluate()`
301
+ * which processes from line 1 and rebuilds fresh checkpoints. This
302
+ * guarantees that stale checkpoints are never used as restoration targets.
303
+ * Only variable-def lines matter here, `VMCheckpointer.snapshot()` only
304
+ * records state for lines that write a variable, so a dirty plain-expression
305
+ * line before the viewport has no checkpoint to invalidate (see
306
+ * `DocumentModel.hasAnyDirtyVariableDefLineBefore()`).
307
+ *
308
+ * **Performance:** O(visible lines) instead of O(document length). Target:
309
+ * < 1ms for a typical ~30-line viewport, independent of document size.
310
+ *
311
+ * @param viewport The visible line range.
312
+ * @returns Results for visible lines only. Lines before the viewport are
313
+ * not included in `lines[]` or `resultMap`.
314
+ */
315
+ setViewport(viewport: ViewportRange, signal?: AbortSignal): EvalResult;
316
+ /**
317
+ * Apply incremental line-level changes to the document model.
318
+ *
319
+ * **Phase 5.2f:** Replaces the O(N) `setDocument()` + full re-evaluation
320
+ * with O(changed) incremental updates. Key benefits:
321
+ *
322
+ * 1. Unchanged lines retain their persistent lineIds → bytecode survives
323
+ * 2. Only changed + DAG-downstream lines are marked dirty → Tier 1 re-evaluation
324
+ * 3. Clean lines in viewport use Tier 2 (cached bytecode execution)
325
+ * 4. Clean lines outside viewport are skipped entirely
326
+ *
327
+ * The DAG is fully cleared after propagation: shifted lines would have
328
+ * stale entries keyed by old line numbers, so the DAG is rebuilt from
329
+ * scratch during the subsequent `evaluate()` call.
330
+ *
331
+ * **Caller should follow up with `evaluate(viewport)`** to re-evaluate
332
+ * dirty lines from line 1 and rebuild the DAG + checkpoints.
333
+ *
334
+ * @param changes Line-level changes to apply. Must be non-overlapping.
335
+ * @returns Metadata about the applied changes.
336
+ */
337
+ applyTransaction(changes: LineChange[]): {
338
+ inserted: number[];
339
+ removed: number[];
340
+ };
341
+ /**
342
+ * Collect evaluation results for a contiguous range of lines.
343
+ *
344
+ * Used by both `evaluate()` (startLine=1) and `setViewport()` (any start).
345
+ * All lines in the range are treated as in-viewport (visible), callers that
346
+ * need the invisible/dirty → Tier 3 handling should use `evaluate()` instead.
347
+ *
348
+ * @param startLine First line to evaluate (1-based, inclusive).
349
+ * @param endLine Last line to evaluate (1-based, inclusive). Clamped to docEnd.
350
+ */
351
+ private collectEvalResults;
352
+ /**
353
+ * Check whether any **variable-definition** line before `position`
354
+ * (1-based, exclusive) is dirty.
355
+ *
356
+ * Used by `setViewport()` to decide whether to fall back to `evaluate()`:
357
+ * if a variable-def before the viewport is dirty, the checkpoint state
358
+ * `restoreTo()` would use may be stale and we need to reprocess from
359
+ * line 1 to rebuild checkpoints correctly.
360
+ *
361
+ * Deliberately narrower than `DocumentModel.hasAnyDirtyLineBefore()`:
362
+ * checkpoints only snapshot variable-def lines (see VMCheckpointer), so a
363
+ * dirty plain-expression line before the viewport can't have invalidated
364
+ * one, there's nothing checkpointed for it to invalidate. Using the
365
+ * broader check here previously caused a real perf bug: `PageManager`'s
366
+ * cold-page eviction marks evicted non-variable-def lines dirty, so
367
+ * scrolling far into a large, variable-def-free document would trip this
368
+ * guard, fall back to `evaluate()`, which recompiles those lines via
369
+ * Tier 3 (never clearing their dirty flag by design), causing the very
370
+ * next `maintainAfterEval()` to re-evict and re-dirty them, a
371
+ * self-sustaining loop that pinned every subsequent `setViewport()` call
372
+ * to the cost of a full re-evaluation instead of O(visible lines).
373
+ *
374
+ * Delegates to DocumentModel.hasAnyDirtyVariableDefLineBefore(), which
375
+ * tracks dirty lineIds incrementally instead of scanning every line up to
376
+ * `position` on every call. This used to be a real per-scroll cost
377
+ * (benchmarked at ~10ms scrolled near the bottom of a 20k-line document)
378
+ * since it fired on every viewport change, not just edits.
379
+ */
380
+ private hasDirtyLinesBefore;
381
+ /**
382
+ * Evaluate a single line using the appropriate tier.
383
+ *
384
+ * Tier assignment logic:
385
+ * - Empty/markdown-only lines → skipped
386
+ * - Dirty + in-viewport → Tier 1 (full pipeline)
387
+ * - Dirty + not in viewport → Tier 3 (compile-only, execute variable defs)
388
+ * - Clean + has bytecode + in viewport → Tier 2 (execute from cache)
389
+ * - Clean + no bytecode → skipped (non-evaluable)
390
+ */
391
+ private evaluateSingleLine;
392
+ /**
393
+ * Tier 1: Full pipeline, lex, parse, compile, execute.
394
+ * Uses the engine's existing evaluateLine() which handles all pipeline
395
+ * stages including DAG updates and LineCache population.
396
+ *
397
+ * Supports multiple expressions per line (inline solves). Evaluates each
398
+ * expression left-to-right through the engine so variable definitions in
399
+ * earlier solves update the VM state before later solves are evaluated.
400
+ * Reads/writes are aggregated across all expressions for the DAG.
401
+ */
402
+ private evaluateTier1;
403
+ /**
404
+ * Tier 2: Execute from cached bytecode only.
405
+ * Skips lexing, parsing, and compiling, runs the pre-compiled bytecode
406
+ * against the engine's shared VM. Supports multiple bytecodes per line
407
+ * (inline solves), each is executed left-to-right so variable definitions
408
+ * in earlier bytecodes update the VM before later ones run.
409
+ * Assumes the VM already has correct variable state from preceding
410
+ * Tier-1 evaluations.
411
+ */
412
+ private evaluateTier2;
413
+ /**
414
+ * Tier 3: Compile-only for invisible lines.
415
+ * Lex → Parse → Compile to discover reads/writes for the dependency graph.
416
+ * Executes the bytecode ONLY if the line defines a variable (isVariableDef
417
+ * or writes.length > 0), because variable assignments affect VM state
418
+ * that other lines depend on. Pure expression lines are compiled but NOT
419
+ * executed, saving CPU for large documents.
420
+ *
421
+ * Supports multiple expressions per line (inline solves). Each is compiled
422
+ * separately; variable-def expressions are also executed.
423
+ */
424
+ private evaluateTier3;
425
+ /**
426
+ * Restore the VM to the state at or just after the given line number.
427
+ *
428
+ * Finds the nearest checkpoint at or before `lineNumber` and replays
429
+ * all variable definitions from the checkpoint chain into the VM.
430
+ * After calling this, the VM is ready to evaluate lines starting at
431
+ * `lineNumber + 1` without re-evaluating all preceding lines.
432
+ *
433
+ * **Usage:** Phase 5.2e's `setViewport()` calls `restoreTo(viewport.startLine - 1)`
434
+ * before evaluating only the newly visible lines. This is the key to
435
+ * O(visible lines) scrolling.
436
+ *
437
+ * @param lineNumber The line number to restore to. Variables defined
438
+ * at lines ≤ this number will be available in the VM.
439
+ */
440
+ restoreTo(lineNumber: number): void;
441
+ /**
442
+ * Get the VM checkpointer, or null if checkpointing is disabled.
443
+ */
444
+ getCheckpointer(): VMCheckpointer | null;
445
+ /**
446
+ * Get the PageManager (Phase 5.2g).
447
+ * Exposed for testing.
448
+ */
449
+ getPageManager(): PageManager;
450
+ /**
451
+ * Preload the next 1–2 pages in the current scroll direction.
452
+ *
453
+ * Called during `setViewport()` (scroll-only path). Collects dirty
454
+ * uncompiled lines in pages just beyond the viewport and dispatches
455
+ * them to the background compilation worker so bytecode is ready
456
+ * before the user scrolls those lines into view.
457
+ */
458
+ private preloadNextPages;
459
+ /**
460
+ * Collect invisible dirty lines that need background compilation.
461
+ *
462
+ * Iterates lines beyond `viewport.endLine`, filtering for:
463
+ * - Dirty lines (need re-compilation)
464
+ * - Non-empty, non-markdown lines
465
+ * - No existing bytecode (skip already-compiled Tier 3 lines)
466
+ *
467
+ * Returns CompileRequestItem[] suitable for CompilationWorkerManager.
468
+ */
469
+ private collectInvisibleCompileTargets;
470
+ /**
471
+ * Extract all evaluable expressions from a LineState.
472
+ *
473
+ * For full-line expressions: returns `{ expressions: [trimmedText], inlineSolveCount: 0 }`.
474
+ * For inline solve lines: returns `{ expressions: [...allSolves], inlineSolveCount: N }`.
475
+ * For pre-extracted (cached) expressions: returns the cached array.
476
+ *
477
+ * Inline solves are extracted left-to-right via the sharedLexer, so variable
478
+ * definitions in earlier solves (e.g., `s\`x = 5\` more text s\`x + 1\``)
479
+ * correctly update the VM state before later solves are evaluated.
480
+ */
481
+ private extractExpressions;
482
+ }
483
+
484
+ /** Bounds applied to input before parsing: length and nesting depth. */
485
+ interface ValidationConfig {
486
+ maxExpressionLength: number;
487
+ maxComplexity: number;
488
+ }
489
+ /** Whether input passed the safety bounds, and which one it failed. */
490
+ interface SafetyCheckResult {
491
+ passed: boolean;
492
+ /**
493
+ * `error.error` (a plain string) exists purely because it's spread
494
+ * directly into `evaluateExpressionWithDiagnostic()`'s own return shape
495
+ * (`{value, tokens, program, error?: string, ...}`), which deliberately
496
+ * keeps errors as display strings for the debug/diagnostic pipeline
497
+ * see that method's own doc comment. `error.engineError` is additive
498
+ * (doesn't replace the string field, so existing consumers of this
499
+ * exported type are unaffected): it carries the real EngineError this
500
+ * check constructed internally, so callers that DO want the original
501
+ * code/category/expected/found/suggestion (prepareExpression(), not the
502
+ * diagnostic pipeline) don't have to reconstruct a generic one from just
503
+ * the flattened message.
504
+ */
505
+ error?: {
506
+ value: Value;
507
+ tokens: Token[];
508
+ program: BytecodeProgram;
509
+ error: string;
510
+ engineError?: EngineError;
511
+ };
512
+ }
513
+ /**
514
+ * Check that the expression doesn't exceed the maximum allowed length.
515
+ */
516
+ declare function checkExpressionLength(expression: string, config: ValidationConfig): SafetyCheckResult;
517
+ /**
518
+ * Score expression complexity based on token count, function calls, and nesting depth.
519
+ * Returns the complexity score and whether it exceeds the configured maximum.
520
+ */
521
+ declare function checkExpressionComplexity(tokens: Token[], config: ValidationConfig): {
522
+ passed: boolean;
523
+ complexityScore: number;
524
+ errorMessage?: string;
525
+ engineError?: EngineError;
526
+ };
527
+ /**
528
+ * Extract variable reads and writes from a token stream.
529
+ *
530
+ * Handles both IDENT and UNIT tokens as potential variable references.
531
+ * UNIT tokens occur when the variable name collides with a known unit
532
+ * (e.g., "b" for bits, "s" for seconds). The colon prefix unambiguously
533
+ * signals a variable definition context (handled by VariableParselet).
534
+ * A standalone UNIT token is only a real variable reference when it
535
+ * isn't in unit-literal position (see {@link isUnitLiteralContext})
536
+ * otherwise it's a quantity/conversion unit name, never LOAD_VAR'd.
537
+ *
538
+ * Also detects user-defined-function DEFINITIONS (`name(params) = body`)
539
+ * as a read+write of the function's own name, mirroring `:name = value`'s
540
+ * existing convention of registering the defined name as both, and
541
+ * excludes the definition's own PARAMETER names from reads/writes
542
+ * entirely (see {@link collectFunctionParamNames}). A function CALL
543
+ * (`name(args)`, no trailing `=`) needs no special detection: the call's
544
+ * own name falls through to the ordinary bare-identifier read-tracking
545
+ * below, the same as any other `LOAD_VAR`-producing identifier. This is
546
+ * already correct once calls compile successfully, no change needed.
547
+ */
548
+ declare function extractReadsAndWrites(tokens: Token[]): {
549
+ reads: string[];
550
+ writes: string[];
551
+ };
552
+ /**
553
+ * Check if a line is effectively empty (whitespace only or only markdown syntax).
554
+ *
555
+ * Phase B: Delegates to the ExpressionLexer's character-by-character
556
+ * markdown line scanner, replacing the old regex-based heuristics.
557
+ *
558
+ * Skips lines that contain no evaluable expression:
559
+ * - Whitespace-only lines
560
+ * - Markdown structural markers (headings, blockquotes, lists without inline solves)
561
+ * - Code block fences (```)
562
+ * - MathJax block fences ($$)
563
+ * - Table separator rows (|---|)
564
+ * - Horizontal rules (---, ***, ___)
565
+ * - Standalone wikilinks / embeds ([[...]], ![[...]])
566
+ * - Whole-line comments (a line whose first non-whitespace characters are `//`)
567
+ *
568
+ * Lines containing inline solves (s\`...\`) are never considered empty.
569
+ *
570
+ * Note: a trailing `#`/`//` comment in the MIDDLE of an otherwise-evaluable
571
+ * line does NOT make isEmptyLine() return true, that line is still an
572
+ * "expression" line (skip: false). The comment is instead stripped at
573
+ * tokenization time (ExpressionLexer's HASH/`//` handling emits a COMMENT
574
+ * token for the rest of the line) and then filtered out of the token
575
+ * stream by ExpressionEngine.prepareExpression() before parsing, so
576
+ * `<expr> // note` evaluates identically to `<expr>` alone.
577
+ */
578
+ declare function isEmptyLine(lineText: string): boolean;
579
+ /**
580
+ * Find all inline solves in a line with precise coordinate mapping.
581
+ *
582
+ * Phase B: Delegates to the ExpressionLexer's character-by-character
583
+ * scanner (no regex, handles escaped backticks).
584
+ */
585
+ declare function findInlineSolvesInLine(lineText: string, lineNumber: number): InlineSolvePosition[];
586
+
587
+ export { DocumentModel, type EvalLineResult, type EvalResult, EvalTier, ExpressionEngine, InlineSolvePosition, LineChange, type SafetyCheckResult, ThreeTierEvaluator, type ValidationConfig, ViewportRange, checkExpressionComplexity, checkExpressionLength, extractReadsAndWrites, findInlineSolvesInLine, isEmptyLine };