solve-engine 1.0.0-beta.2 → 1.0.0-beta.4

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 (171) hide show
  1. package/dist/{Lexer-D9l4Yrk2.d.ts → Lexer-Cfm79Dak.d.cts} +18 -2
  2. package/dist/{Lexer-BJdhlnej.d.cts → Lexer-W9MBOP0V.d.ts} +18 -2
  3. package/dist/{PackageRegistry-DaH4aIKP.d.ts → PackageRegistry-CjDt-Jy_.d.ts} +60 -4
  4. package/dist/{PackageRegistry-D-Tv_7ca.d.cts → PackageRegistry-pHtKythi.d.cts} +60 -4
  5. package/dist/{Parselet-CK8cQu2a.d.cts → Parselet-Cu0bLSis.d.cts} +1 -1
  6. package/dist/{Parselet-ConOIdRO.d.ts → Parselet-DEdF9I7n.d.ts} +1 -1
  7. package/dist/{Token-0jpvUdPY.d.cts → Token-BzG5G4ja.d.cts} +44 -0
  8. package/dist/{Token-0jpvUdPY.d.ts → Token-BzG5G4ja.d.ts} +44 -0
  9. package/dist/TokenNormalizer-DGVa24Q-.d.cts +377 -0
  10. package/dist/TokenNormalizer-t_GotBxr.d.ts +377 -0
  11. package/dist/{chunk-HWSZJQCI.js → chunk-2CS6OMZK.js} +37 -15
  12. package/dist/chunk-2CS6OMZK.js.map +1 -0
  13. package/dist/{chunk-XJCMXB2E.cjs → chunk-2MV4HBKC.cjs} +187 -61
  14. package/dist/chunk-2MV4HBKC.cjs.map +1 -0
  15. package/dist/{chunk-J73SJHR3.cjs → chunk-2NPS5DQ3.cjs} +558 -341
  16. package/dist/chunk-2NPS5DQ3.cjs.map +1 -0
  17. package/dist/{chunk-QWY3VEZN.js → chunk-3MNKQZ77.js} +65 -12
  18. package/dist/chunk-3MNKQZ77.js.map +1 -0
  19. package/dist/{chunk-RZCWSXTA.cjs → chunk-43G3JT2E.cjs} +1491 -218
  20. package/dist/chunk-43G3JT2E.cjs.map +1 -0
  21. package/dist/{chunk-WQTTOGXC.cjs → chunk-4AVD7NZW.cjs} +4 -4
  22. package/dist/{chunk-WQTTOGXC.cjs.map → chunk-4AVD7NZW.cjs.map} +1 -1
  23. package/dist/{chunk-HTXVVJRA.cjs → chunk-4CVLFLOB.cjs} +112 -2
  24. package/dist/chunk-4CVLFLOB.cjs.map +1 -0
  25. package/dist/{chunk-5YEMOYSE.js → chunk-6GCKCWLB.js} +9 -3
  26. package/dist/chunk-6GCKCWLB.js.map +1 -0
  27. package/dist/{chunk-EBSPLUW4.cjs → chunk-AHCLWAM5.cjs} +28 -10
  28. package/dist/chunk-AHCLWAM5.cjs.map +1 -0
  29. package/dist/{chunk-KVILKGMS.js → chunk-AJA6LUI7.js} +36 -2
  30. package/dist/chunk-AJA6LUI7.js.map +1 -0
  31. package/dist/{chunk-EHAHVROS.cjs → chunk-CLVQBF5C.cjs} +5 -5
  32. package/dist/{chunk-EHAHVROS.cjs.map → chunk-CLVQBF5C.cjs.map} +1 -1
  33. package/dist/{chunk-34RRD7PC.js → chunk-CYFK5SY2.js} +111 -3
  34. package/dist/chunk-CYFK5SY2.js.map +1 -0
  35. package/dist/{chunk-M5LX5AOO.js → chunk-DDQVZGLO.js} +25 -12
  36. package/dist/chunk-DDQVZGLO.js.map +1 -0
  37. package/dist/{chunk-LR7YASZF.cjs → chunk-EAAHVJ4P.cjs} +3 -3
  38. package/dist/chunk-EAAHVJ4P.cjs.map +1 -0
  39. package/dist/{chunk-3PPFLFH4.js → chunk-FIFQPKBA.js} +1417 -144
  40. package/dist/chunk-FIFQPKBA.js.map +1 -0
  41. package/dist/{chunk-RIN643A3.js → chunk-GPPLSM2Z.js} +61 -2
  42. package/dist/chunk-GPPLSM2Z.js.map +1 -0
  43. package/dist/{chunk-4QADQTWS.js → chunk-KHJUSHFU.js} +231 -14
  44. package/dist/chunk-KHJUSHFU.js.map +1 -0
  45. package/dist/{chunk-NMD5VRN4.cjs → chunk-M4F66R4O.cjs} +74 -73
  46. package/dist/chunk-M4F66R4O.cjs.map +1 -0
  47. package/dist/{chunk-6NTVRDQV.cjs → chunk-M4Q47KHF.cjs} +126 -73
  48. package/dist/chunk-M4Q47KHF.cjs.map +1 -0
  49. package/dist/{chunk-LIPPNDBE.js → chunk-M5E34VG5.js} +3 -3
  50. package/dist/{chunk-LIPPNDBE.js.map → chunk-M5E34VG5.js.map} +1 -1
  51. package/dist/{chunk-53B6KDDJ.cjs → chunk-MBNQVDVC.cjs} +38 -3
  52. package/dist/{chunk-53B6KDDJ.cjs.map → chunk-MBNQVDVC.cjs.map} +1 -1
  53. package/dist/{chunk-SDGRK7EP.js → chunk-MEOHSQEH.js} +6 -5
  54. package/dist/chunk-MEOHSQEH.js.map +1 -0
  55. package/dist/{chunk-NMCRQP3Z.cjs → chunk-MTX2KVU7.cjs} +71 -70
  56. package/dist/chunk-MTX2KVU7.cjs.map +1 -0
  57. package/dist/{chunk-QNJ4ACRT.cjs → chunk-NJTXJ5AG.cjs} +37 -15
  58. package/dist/chunk-NJTXJ5AG.cjs.map +1 -0
  59. package/dist/{chunk-C4XZV6E7.cjs → chunk-NZFKROS7.cjs} +26 -20
  60. package/dist/chunk-NZFKROS7.cjs.map +1 -0
  61. package/dist/{chunk-64W6GLLZ.js → chunk-OFXOTECC.js} +24 -6
  62. package/dist/chunk-OFXOTECC.js.map +1 -0
  63. package/dist/{chunk-3YNVWKR2.cjs → chunk-OUHT5Z36.cjs} +28 -5
  64. package/dist/chunk-OUHT5Z36.cjs.map +1 -0
  65. package/dist/{chunk-EIGTWK5N.js → chunk-OWRHDUJD.js} +3 -3
  66. package/dist/chunk-OWRHDUJD.js.map +1 -0
  67. package/dist/{chunk-4MG4XKO2.js → chunk-PCPX42KL.js} +38 -3
  68. package/dist/{chunk-4MG4XKO2.js.map → chunk-PCPX42KL.js.map} +1 -1
  69. package/dist/{chunk-GW32KPCU.cjs → chunk-R24DI24X.cjs} +61 -2
  70. package/dist/chunk-R24DI24X.cjs.map +1 -0
  71. package/dist/{chunk-XVWCOTR6.js → chunk-SFQWJMKT.js} +7 -6
  72. package/dist/chunk-SFQWJMKT.js.map +1 -0
  73. package/dist/{chunk-6BKTCEUP.cjs → chunk-TY3TLZAW.cjs} +36 -2
  74. package/dist/chunk-TY3TLZAW.cjs.map +1 -0
  75. package/dist/{chunk-DM3LMRBC.js → chunk-UKPGSAZW.js} +187 -61
  76. package/dist/chunk-UKPGSAZW.js.map +1 -0
  77. package/dist/{chunk-NH2O2AUR.js → chunk-WC5FFSHB.js} +26 -4
  78. package/dist/chunk-WC5FFSHB.js.map +1 -0
  79. package/dist/{chunk-CLL7RUQV.cjs → chunk-WWOLFXTX.cjs} +40 -18
  80. package/dist/chunk-WWOLFXTX.cjs.map +1 -0
  81. package/dist/{chunk-JBSYC7BB.cjs → chunk-X2BWAZAU.cjs} +66 -53
  82. package/dist/chunk-X2BWAZAU.cjs.map +1 -0
  83. package/dist/{chunk-GOLDJNMZ.js → chunk-XBTEO4OB.js} +28 -5
  84. package/dist/chunk-XBTEO4OB.js.map +1 -0
  85. package/dist/{chunk-EPOXXJBK.js → chunk-YU2CUNFO.js} +3 -3
  86. package/dist/{chunk-EPOXXJBK.js.map → chunk-YU2CUNFO.js.map} +1 -1
  87. package/dist/constants.cjs +4 -4
  88. package/dist/constants.js +1 -1
  89. package/dist/engine.cjs +29 -30
  90. package/dist/engine.d.cts +6 -6
  91. package/dist/engine.d.ts +6 -6
  92. package/dist/engine.js +19 -20
  93. package/dist/format.cjs +7 -8
  94. package/dist/format.cjs.map +1 -1
  95. package/dist/format.js +2 -3
  96. package/dist/format.js.map +1 -1
  97. package/dist/index.cjs +28 -29
  98. package/dist/index.cjs.map +1 -1
  99. package/dist/index.d.cts +6 -6
  100. package/dist/index.d.ts +6 -6
  101. package/dist/index.js +20 -21
  102. package/dist/index.js.map +1 -1
  103. package/dist/language.cjs +74 -12
  104. package/dist/language.cjs.map +1 -1
  105. package/dist/language.d.cts +6 -6
  106. package/dist/language.d.ts +6 -6
  107. package/dist/language.js +68 -6
  108. package/dist/language.js.map +1 -1
  109. package/dist/lexer.cjs +19 -19
  110. package/dist/lexer.d.cts +3 -3
  111. package/dist/lexer.d.ts +3 -3
  112. package/dist/lexer.js +7 -7
  113. package/dist/normalizer.cjs +12 -12
  114. package/dist/normalizer.d.cts +4 -210
  115. package/dist/normalizer.d.ts +4 -210
  116. package/dist/normalizer.js +6 -6
  117. package/dist/packages.cjs +36 -37
  118. package/dist/packages.d.cts +5 -47
  119. package/dist/packages.d.ts +5 -47
  120. package/dist/packages.js +13 -14
  121. package/dist/parser.cjs +12 -12
  122. package/dist/parser.d.cts +3 -2
  123. package/dist/parser.d.ts +3 -2
  124. package/dist/parser.js +4 -4
  125. package/dist/resolvers.d.cts +1 -1
  126. package/dist/resolvers.d.ts +1 -1
  127. package/dist/uom.cjs +14 -14
  128. package/dist/uom.d.cts +12 -4
  129. package/dist/uom.d.ts +12 -4
  130. package/dist/uom.js +4 -4
  131. package/dist/vm.cjs +17 -17
  132. package/dist/vm.js +6 -6
  133. package/package.json +2 -1
  134. package/dist/NormalizerRule-BrVoVjmP.d.cts +0 -163
  135. package/dist/NormalizerRule-CEjf1FyD.d.ts +0 -163
  136. package/dist/chunk-34RRD7PC.js.map +0 -1
  137. package/dist/chunk-3PPFLFH4.js.map +0 -1
  138. package/dist/chunk-3YNVWKR2.cjs.map +0 -1
  139. package/dist/chunk-4QADQTWS.js.map +0 -1
  140. package/dist/chunk-5YEMOYSE.js.map +0 -1
  141. package/dist/chunk-64W6GLLZ.js.map +0 -1
  142. package/dist/chunk-6BKTCEUP.cjs.map +0 -1
  143. package/dist/chunk-6NTVRDQV.cjs.map +0 -1
  144. package/dist/chunk-C4XZV6E7.cjs.map +0 -1
  145. package/dist/chunk-CLL7RUQV.cjs.map +0 -1
  146. package/dist/chunk-DM3LMRBC.js.map +0 -1
  147. package/dist/chunk-EBSPLUW4.cjs.map +0 -1
  148. package/dist/chunk-EIGTWK5N.js.map +0 -1
  149. package/dist/chunk-GOLDJNMZ.js.map +0 -1
  150. package/dist/chunk-GW32KPCU.cjs.map +0 -1
  151. package/dist/chunk-HTXVVJRA.cjs.map +0 -1
  152. package/dist/chunk-HWSZJQCI.js.map +0 -1
  153. package/dist/chunk-J73SJHR3.cjs.map +0 -1
  154. package/dist/chunk-JBSYC7BB.cjs.map +0 -1
  155. package/dist/chunk-KVILKGMS.js.map +0 -1
  156. package/dist/chunk-LR7YASZF.cjs.map +0 -1
  157. package/dist/chunk-M5LX5AOO.js.map +0 -1
  158. package/dist/chunk-NH2O2AUR.js.map +0 -1
  159. package/dist/chunk-NMCRQP3Z.cjs.map +0 -1
  160. package/dist/chunk-NMD5VRN4.cjs.map +0 -1
  161. package/dist/chunk-OT6OJY7C.cjs +0 -114
  162. package/dist/chunk-OT6OJY7C.cjs.map +0 -1
  163. package/dist/chunk-QNJ4ACRT.cjs.map +0 -1
  164. package/dist/chunk-QWY3VEZN.js.map +0 -1
  165. package/dist/chunk-RFYD5TJE.js +0 -111
  166. package/dist/chunk-RFYD5TJE.js.map +0 -1
  167. package/dist/chunk-RIN643A3.js.map +0 -1
  168. package/dist/chunk-RZCWSXTA.cjs.map +0 -1
  169. package/dist/chunk-SDGRK7EP.js.map +0 -1
  170. package/dist/chunk-XJCMXB2E.cjs.map +0 -1
  171. package/dist/chunk-XVWCOTR6.js.map +0 -1
package/dist/vm.cjs CHANGED
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var chunk6NTVRDQV_cjs = require('./chunk-6NTVRDQV.cjs');
3
+ var chunkM4Q47KHF_cjs = require('./chunk-M4Q47KHF.cjs');
4
4
  require('./chunk-47LRVGOT.cjs');
5
- var chunkJ73SJHR3_cjs = require('./chunk-J73SJHR3.cjs');
5
+ var chunk2NPS5DQ3_cjs = require('./chunk-2NPS5DQ3.cjs');
6
6
  require('./chunk-FEAIOR7N.cjs');
7
- require('./chunk-XJCMXB2E.cjs');
7
+ require('./chunk-2MV4HBKC.cjs');
8
8
  require('./chunk-MZOVP3WI.cjs');
9
9
  require('./chunk-VEKIWQ3F.cjs');
10
- require('./chunk-HTXVVJRA.cjs');
10
+ require('./chunk-4CVLFLOB.cjs');
11
11
  var chunkOC6LTXYS_cjs = require('./chunk-OC6LTXYS.cjs');
12
- require('./chunk-QNJ4ACRT.cjs');
13
- require('./chunk-53B6KDDJ.cjs');
12
+ require('./chunk-NJTXJ5AG.cjs');
13
+ require('./chunk-MBNQVDVC.cjs');
14
14
  require('./chunk-M4N5GA5Z.cjs');
15
15
  require('./chunk-B7LXJ6LC.cjs');
16
16
 
@@ -193,47 +193,47 @@ var VMCheckpointer = class {
193
193
 
194
194
  Object.defineProperty(exports, "DependencyGraph", {
195
195
  enumerable: true,
196
- get: function () { return chunk6NTVRDQV_cjs.DependencyGraph; }
196
+ get: function () { return chunkM4Q47KHF_cjs.DependencyGraph; }
197
197
  });
198
198
  Object.defineProperty(exports, "ScopeManager", {
199
199
  enumerable: true,
200
- get: function () { return chunk6NTVRDQV_cjs.ScopeManager; }
200
+ get: function () { return chunkM4Q47KHF_cjs.ScopeManager; }
201
201
  });
202
202
  Object.defineProperty(exports, "createVM", {
203
203
  enumerable: true,
204
- get: function () { return chunk6NTVRDQV_cjs.createVM; }
204
+ get: function () { return chunkM4Q47KHF_cjs.createVM; }
205
205
  });
206
206
  Object.defineProperty(exports, "executeBytecode", {
207
207
  enumerable: true,
208
- get: function () { return chunk6NTVRDQV_cjs.executeBytecode; }
208
+ get: function () { return chunkM4Q47KHF_cjs.executeBytecode; }
209
209
  });
210
210
  Object.defineProperty(exports, "OpRegistry", {
211
211
  enumerable: true,
212
- get: function () { return chunkJ73SJHR3_cjs.OpRegistry; }
212
+ get: function () { return chunk2NPS5DQ3_cjs.OpRegistry; }
213
213
  });
214
214
  Object.defineProperty(exports, "allocatePluginFunctionIndex", {
215
215
  enumerable: true,
216
- get: function () { return chunkJ73SJHR3_cjs.allocatePluginFunctionIndex; }
216
+ get: function () { return chunk2NPS5DQ3_cjs.allocatePluginFunctionIndex; }
217
217
  });
218
218
  Object.defineProperty(exports, "binaryOp", {
219
219
  enumerable: true,
220
- get: function () { return chunkJ73SJHR3_cjs.binaryOp; }
220
+ get: function () { return chunk2NPS5DQ3_cjs.binaryOp; }
221
221
  });
222
222
  Object.defineProperty(exports, "builtinFunctions", {
223
223
  enumerable: true,
224
- get: function () { return chunkJ73SJHR3_cjs.builtinFunctions; }
224
+ get: function () { return chunk2NPS5DQ3_cjs.builtinFunctions; }
225
225
  });
226
226
  Object.defineProperty(exports, "pluginFunctionRegistry", {
227
227
  enumerable: true,
228
- get: function () { return chunkJ73SJHR3_cjs.pluginFunctionRegistry; }
228
+ get: function () { return chunk2NPS5DQ3_cjs.pluginFunctionRegistry; }
229
229
  });
230
230
  Object.defineProperty(exports, "sharedOpRegistry", {
231
231
  enumerable: true,
232
- get: function () { return chunkJ73SJHR3_cjs.sharedOpRegistry; }
232
+ get: function () { return chunk2NPS5DQ3_cjs.sharedOpRegistry; }
233
233
  });
234
234
  Object.defineProperty(exports, "unifyUom", {
235
235
  enumerable: true,
236
- get: function () { return chunkJ73SJHR3_cjs.unifyUom; }
236
+ get: function () { return chunk2NPS5DQ3_cjs.unifyUom; }
237
237
  });
238
238
  Object.defineProperty(exports, "Value", {
239
239
  enumerable: true,
package/dist/vm.js CHANGED
@@ -1,14 +1,14 @@
1
- export { DependencyGraph, ScopeManager, createVM, executeBytecode } from './chunk-QWY3VEZN.js';
1
+ export { DependencyGraph, ScopeManager, createVM, executeBytecode } from './chunk-3MNKQZ77.js';
2
2
  import './chunk-G535KJEG.js';
3
- export { OpRegistry, allocatePluginFunctionIndex, binaryOp, builtinFunctions, pluginFunctionRegistry, sharedOpRegistry, unifyUom } from './chunk-4QADQTWS.js';
3
+ export { OpRegistry, allocatePluginFunctionIndex, binaryOp, builtinFunctions, pluginFunctionRegistry, sharedOpRegistry, unifyUom } from './chunk-KHJUSHFU.js';
4
4
  import './chunk-GCM5JHMX.js';
5
- import './chunk-DM3LMRBC.js';
5
+ import './chunk-UKPGSAZW.js';
6
6
  import './chunk-75JP4BZX.js';
7
7
  import './chunk-Z4X2RWOF.js';
8
- import './chunk-34RRD7PC.js';
8
+ import './chunk-CYFK5SY2.js';
9
9
  export { Value, ValueType, bigIntValue, colVectorValue, hexValue, matrixValue, numberValue, rangeValue, rowVectorValue, stringValue, uomValue } from './chunk-BVAR5J2F.js';
10
- import './chunk-NH2O2AUR.js';
11
- import './chunk-4MG4XKO2.js';
10
+ import './chunk-WC5FFSHB.js';
11
+ import './chunk-PCPX42KL.js';
12
12
  import './chunk-6RDSQURE.js';
13
13
  import './chunk-YLJ4XMA6.js';
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solve-engine",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "The expression evaluation engine behind Solve — lexer, parser, bytecode VM, and an extensible package system.",
5
5
  "keywords": [
6
6
  "expression-evaluator",
@@ -221,5 +221,6 @@
221
221
  "tsup": "8.5.1",
222
222
  "typescript": "5.9.3"
223
223
  },
224
+ "//sideEffects": "Load-bearing claim, not boilerplate. tsup's splitting emits bare chunk imports at the top of dist/index.js, and this field tells Rollup, webpack and Vite they may delete them, which esbuild reports as [ignored-bare-import] once per import during `npm run size`. The engine does have module-level work to lose: registerAllTokenTypes(), _PrecedenceParser.BP_TABLE and its cached token ids, and several process-wide registries. It is safe because every chunk doing that work is also imported for its bindings somewhere, so no bundler can drop it. That is a property of how tsup currently splits the code rather than a design guarantee, so `npm run smoke:bundled` (scripts/check-tree-shaking.mjs) proves it on every run of `npm run verify` instead of assuming it, and its header explains the two fixes if it ever stops holding.",
224
225
  "sideEffects": false
225
226
  }
@@ -1,163 +0,0 @@
1
- import { T as Token } from './Token-0jpvUdPY.cjs';
2
-
3
- /**
4
- * NormalizerRule, pluggable token normalization rule for the
5
- * TokenNormalizer post-lexer pass.
6
- *
7
- * ## Purpose
8
- * After the ExpressionLexer produces raw tokens (numbers, identifiers,
9
- * operators, etc.), the TokenNormalizer applies domain-specific rules
10
- * to transform the token stream before parsing. This keeps the lexer
11
- * focused on single-token production and moves multi-token pattern
12
- * matching into a dedicated normalization layer.
13
- *
14
- * ## How rules work
15
- * Rules are applied in priority order (highest first). At each token
16
- * position, the normalizer tries every rule in priority order until one
17
- * matches. Matched tokens are consumed and replaced; unmatched tokens
18
- * pass through unchanged.
19
- *
20
- * ## What rules can do
21
- * - **Phrase fusion**: Merge consecutive words into compound tokens
22
- * (e.g., `"to" "the" "power" "of"` → `CARET`)
23
- * - **Implicit operators**: Insert missing operators between tokens
24
- * (e.g., `NUMBER IDENT` → `NUMBER STAR IDENT`)
25
- * - **Domain transformations**: Coalesce item names, currency pairs, etc.
26
- *
27
- * ## Why a separate file?
28
- * This is a duplicate-free copy of the interface defined in
29
- * TokenNormalizer.ts. Storing it in a separate file avoids circular
30
- * imports, TokenNormalizer imports NormalizerRule, and rule factories
31
- * import TokenNormalizer's `createFusedToken`.
32
- *
33
- * @module NormalizerRule
34
- */
35
-
36
- /**
37
- * Result of a successful rule match attempt against the token stream.
38
- *
39
- * When a {@link NormalizerRule.match} function finds a pattern at the
40
- * current position, it returns a NormalizerMatch describing how many
41
- * tokens to consume and what to replace them with.
42
- *
43
- * @example
44
- * ```ts
45
- * // The phrase "to the power of" (5 tokens) becomes a single CARET token
46
- * const match: NormalizerMatch = {
47
- * consumed: 5,
48
- * replacement: [caretToken],
49
- * };
50
- * ```
51
- */
52
- interface NormalizerMatch {
53
- /**
54
- * Number of tokens consumed from the stream at the match position.
55
- * Must be ≥ 1, a match always advances the cursor.
56
- */
57
- consumed: number;
58
- /**
59
- * Replacement tokens to insert at the match position.
60
- * May be empty (deletion), a single token (fusion), or multiple
61
- * tokens (expansion/splitting).
62
- */
63
- replacement: Token[];
64
- /**
65
- * Human-readable rule name for diagnostic fusion tracking.
66
- * When set, the normalizer uses this instead of the rule's `name`
67
- * in {@link TokenFusion} records. Used by {@link PhraseTrie} to
68
- * report which specific phrase matched (e.g., "phrase:to the power of").
69
- */
70
- ruleName?: string;
71
- }
72
- /**
73
- * A pluggable normalization rule registered with the TokenNormalizer.
74
- *
75
- * Each rule has a {@link name}, {@link priority}, and {@link match} function.
76
- * The match function receives the current token stream and a position,
77
- * and returns a {@link NormalizerMatch} on success or `null` on failure.
78
- *
79
- * ## Priority ordering
80
- * Higher priority rules are tried first at each position. This allows
81
- * long phrases (priority 100, e.g. "to the power of") to match before
82
- * shorter fragments (priority 80, e.g. "power of").
83
- *
84
- * ## Match contract
85
- * - Must be pure (no side effects, no mutation of input tokens)
86
- * - Must return `null` for any position that doesn't match
87
- * - Consumed tokens must be consecutive starting at `pos`
88
- * - Replacement tokens must be valid for downstream parsing
89
- *
90
- * @example
91
- * ```ts
92
- * // A phrase fusion rule that converts "to the power of" into CARET
93
- * const phraseRule: NormalizerRule = {
94
- * name: 'phrase:to the power of',
95
- * priority: 100,
96
- * match: (tokens, pos) => {
97
- * if (pos + 4 > tokens.length) return null;
98
- * const phrase = tokens.slice(pos, pos + 5)
99
- * .map(t => t.value.toLowerCase()).join(' ');
100
- * if (phrase === 'to the power of') {
101
- * return {
102
- * consumed: 5,
103
- * replacement: [createFusedToken('CARET', 'to the power of', tokens.slice(pos, pos + 5))],
104
- * };
105
- * }
106
- * return null;
107
- * },
108
- * };
109
- * ```
110
- */
111
- interface NormalizerRule {
112
- /**
113
- * Human-readable name for debugging and diagnostic display.
114
- * Convention: `"category:description"`, e.g. `"phrase:to the power of"`.
115
- */
116
- readonly name: string;
117
- /**
118
- * Priority for ordering rules. Higher values are tried first.
119
- * Recommended ranges:
120
- * - 100: Long multi-word phrase fusion (e.g., "to the power of")
121
- * - 80: Short phrase fusion (e.g., "power of", "times by")
122
- * - 50: Implicit operator insertion (e.g., implicit multiply)
123
- * - 20: Domain-specific transformations
124
- */
125
- readonly priority: number;
126
- /**
127
- * Attempt to match a pattern starting at position `pos` in the token stream.
128
- *
129
- * @param tokens - The current token stream (may be partially normalized from prior passes)
130
- * @param pos - The current position to attempt matching from
131
- * @returns A {@link NormalizerMatch} if the pattern is found, or `null` if no match
132
- */
133
- match(tokens: Token[], pos: number): NormalizerMatch | null;
134
- }
135
- /**
136
- * Record of a token fusion event performed by the normalizer.
137
- *
138
- * When a rule merges multiple source tokens into fewer replacement tokens,
139
- * the normalizer fires a {@link NormalizerOptions.onFusion | fusion callback}
140
- * with this record. The playground uses these records to render the
141
- * fusion detail table showing exactly which tokens were merged and by
142
- * which rule.
143
- *
144
- * @example
145
- * ```ts
146
- * // "to" "the" "power" "of" fused into CARET "^"
147
- * const fusion: TokenFusion = {
148
- * rule: "phrase:to the power of",
149
- * sourceTokens: [toToken, theToken, powerToken, ofToken],
150
- * fusedToken: caretToken,
151
- * };
152
- * ```
153
- */
154
- interface TokenFusion {
155
- /** The name of the rule that triggered this fusion (e.g., "phrase:to the power of") */
156
- rule: string;
157
- /** The original tokens before fusion, always ≥ 2 tokens */
158
- sourceTokens: Token[];
159
- /** The resulting fused token with its new type and combined value */
160
- fusedToken: Token;
161
- }
162
-
163
- export type { NormalizerRule as N, TokenFusion as T, NormalizerMatch as a };
@@ -1,163 +0,0 @@
1
- import { T as Token } from './Token-0jpvUdPY.js';
2
-
3
- /**
4
- * NormalizerRule, pluggable token normalization rule for the
5
- * TokenNormalizer post-lexer pass.
6
- *
7
- * ## Purpose
8
- * After the ExpressionLexer produces raw tokens (numbers, identifiers,
9
- * operators, etc.), the TokenNormalizer applies domain-specific rules
10
- * to transform the token stream before parsing. This keeps the lexer
11
- * focused on single-token production and moves multi-token pattern
12
- * matching into a dedicated normalization layer.
13
- *
14
- * ## How rules work
15
- * Rules are applied in priority order (highest first). At each token
16
- * position, the normalizer tries every rule in priority order until one
17
- * matches. Matched tokens are consumed and replaced; unmatched tokens
18
- * pass through unchanged.
19
- *
20
- * ## What rules can do
21
- * - **Phrase fusion**: Merge consecutive words into compound tokens
22
- * (e.g., `"to" "the" "power" "of"` → `CARET`)
23
- * - **Implicit operators**: Insert missing operators between tokens
24
- * (e.g., `NUMBER IDENT` → `NUMBER STAR IDENT`)
25
- * - **Domain transformations**: Coalesce item names, currency pairs, etc.
26
- *
27
- * ## Why a separate file?
28
- * This is a duplicate-free copy of the interface defined in
29
- * TokenNormalizer.ts. Storing it in a separate file avoids circular
30
- * imports, TokenNormalizer imports NormalizerRule, and rule factories
31
- * import TokenNormalizer's `createFusedToken`.
32
- *
33
- * @module NormalizerRule
34
- */
35
-
36
- /**
37
- * Result of a successful rule match attempt against the token stream.
38
- *
39
- * When a {@link NormalizerRule.match} function finds a pattern at the
40
- * current position, it returns a NormalizerMatch describing how many
41
- * tokens to consume and what to replace them with.
42
- *
43
- * @example
44
- * ```ts
45
- * // The phrase "to the power of" (5 tokens) becomes a single CARET token
46
- * const match: NormalizerMatch = {
47
- * consumed: 5,
48
- * replacement: [caretToken],
49
- * };
50
- * ```
51
- */
52
- interface NormalizerMatch {
53
- /**
54
- * Number of tokens consumed from the stream at the match position.
55
- * Must be ≥ 1, a match always advances the cursor.
56
- */
57
- consumed: number;
58
- /**
59
- * Replacement tokens to insert at the match position.
60
- * May be empty (deletion), a single token (fusion), or multiple
61
- * tokens (expansion/splitting).
62
- */
63
- replacement: Token[];
64
- /**
65
- * Human-readable rule name for diagnostic fusion tracking.
66
- * When set, the normalizer uses this instead of the rule's `name`
67
- * in {@link TokenFusion} records. Used by {@link PhraseTrie} to
68
- * report which specific phrase matched (e.g., "phrase:to the power of").
69
- */
70
- ruleName?: string;
71
- }
72
- /**
73
- * A pluggable normalization rule registered with the TokenNormalizer.
74
- *
75
- * Each rule has a {@link name}, {@link priority}, and {@link match} function.
76
- * The match function receives the current token stream and a position,
77
- * and returns a {@link NormalizerMatch} on success or `null` on failure.
78
- *
79
- * ## Priority ordering
80
- * Higher priority rules are tried first at each position. This allows
81
- * long phrases (priority 100, e.g. "to the power of") to match before
82
- * shorter fragments (priority 80, e.g. "power of").
83
- *
84
- * ## Match contract
85
- * - Must be pure (no side effects, no mutation of input tokens)
86
- * - Must return `null` for any position that doesn't match
87
- * - Consumed tokens must be consecutive starting at `pos`
88
- * - Replacement tokens must be valid for downstream parsing
89
- *
90
- * @example
91
- * ```ts
92
- * // A phrase fusion rule that converts "to the power of" into CARET
93
- * const phraseRule: NormalizerRule = {
94
- * name: 'phrase:to the power of',
95
- * priority: 100,
96
- * match: (tokens, pos) => {
97
- * if (pos + 4 > tokens.length) return null;
98
- * const phrase = tokens.slice(pos, pos + 5)
99
- * .map(t => t.value.toLowerCase()).join(' ');
100
- * if (phrase === 'to the power of') {
101
- * return {
102
- * consumed: 5,
103
- * replacement: [createFusedToken('CARET', 'to the power of', tokens.slice(pos, pos + 5))],
104
- * };
105
- * }
106
- * return null;
107
- * },
108
- * };
109
- * ```
110
- */
111
- interface NormalizerRule {
112
- /**
113
- * Human-readable name for debugging and diagnostic display.
114
- * Convention: `"category:description"`, e.g. `"phrase:to the power of"`.
115
- */
116
- readonly name: string;
117
- /**
118
- * Priority for ordering rules. Higher values are tried first.
119
- * Recommended ranges:
120
- * - 100: Long multi-word phrase fusion (e.g., "to the power of")
121
- * - 80: Short phrase fusion (e.g., "power of", "times by")
122
- * - 50: Implicit operator insertion (e.g., implicit multiply)
123
- * - 20: Domain-specific transformations
124
- */
125
- readonly priority: number;
126
- /**
127
- * Attempt to match a pattern starting at position `pos` in the token stream.
128
- *
129
- * @param tokens - The current token stream (may be partially normalized from prior passes)
130
- * @param pos - The current position to attempt matching from
131
- * @returns A {@link NormalizerMatch} if the pattern is found, or `null` if no match
132
- */
133
- match(tokens: Token[], pos: number): NormalizerMatch | null;
134
- }
135
- /**
136
- * Record of a token fusion event performed by the normalizer.
137
- *
138
- * When a rule merges multiple source tokens into fewer replacement tokens,
139
- * the normalizer fires a {@link NormalizerOptions.onFusion | fusion callback}
140
- * with this record. The playground uses these records to render the
141
- * fusion detail table showing exactly which tokens were merged and by
142
- * which rule.
143
- *
144
- * @example
145
- * ```ts
146
- * // "to" "the" "power" "of" fused into CARET "^"
147
- * const fusion: TokenFusion = {
148
- * rule: "phrase:to the power of",
149
- * sourceTokens: [toToken, theToken, powerToken, ofToken],
150
- * fusedToken: caretToken,
151
- * };
152
- * ```
153
- */
154
- interface TokenFusion {
155
- /** The name of the rule that triggered this fusion (e.g., "phrase:to the power of") */
156
- rule: string;
157
- /** The original tokens before fusion, always ≥ 2 tokens */
158
- sourceTokens: Token[];
159
- /** The resulting fused token with its new type and combined value */
160
- fusedToken: Token;
161
- }
162
-
163
- export type { NormalizerRule as N, TokenFusion as T, NormalizerMatch as a };