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
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/parser/registry/ParseletRegistry.ts","../src/parser/PrecedenceParser.ts"],"names":["tokenTypeId","TokenTypes","ErrorFactory","getLocale","BindingPower","BytecodeBuilder","DiagnosticEventType","buildBindingPowerTable"],"mappings":"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","file":"chunk-MTX2KVU7.cjs","sourcesContent":["import { PrefixParselet, InfixParselet } from \"@solve-js/parser/Parselet\";\nimport { tokenTypeId } from \"@solve-js/lexer/Token\";\n\n/**\n * Binding-power fields a parselet may expose beyond what its interface\n * requires, read only for diagnostic display.\n *\n * `PrefixParselet` declares no binding power at all and `InfixParselet` declares\n * a single `bindingPower`, but some parselets carry a separate left and right\n * power. The diagnostic views want whatever is there without requiring it, so\n * this describes the optional surface instead of reaching through `any` at each\n * access. `category` is not here: both interfaces already declare it.\n */\ninterface ParseletBindingPowers {\n\treadonly bindingPower?: number;\n\treadonly leftBindingPower?: number;\n\treadonly rightBindingPower?: number;\n}\n\n/** Reads the optional binding-power fields off a parselet for diagnostics. */\nfunction bindingPowersOf(parselet: PrefixParselet | InfixParselet): ParseletBindingPowers {\n\treturn parselet as ParseletBindingPowers;\n}\n\n/**\n * Dual-keyed ParseletRegistry, accepts both string token types and\n * integer token type IDs for fast dispatch in the Parser hot path.\n *\n * Providers call registerPrefix(\"NUMBER\", ...) with string token types.\n * Internally, we populate both string-keyed and integer-keyed maps so\n * Parser.parseExpression() can use token.typeId (integer) for lookup\n * while diagnostics and error messages use token.type (string).\n *\n * Performance: Integer Map.get() avoids string hashing, saving ~2-5ns\n * per dispatch. With ~10-15 dispatches per expression, that's ~20-75ns.\n */\nexport class ParseletRegistry {\n\t// String-keyed maps (kept for diagnostics + backwards compat)\n\tprivate prefixParselets: Map<string, PrefixParselet> = new Map();\n\tprivate infixParselets: Map<string, InfixParselet> = new Map();\n\n\t// Integer-keyed maps for parser hot path\n\tprivate prefixById: Map<number, PrefixParselet> = new Map();\n\tprivate infixById: Map<number, InfixParselet> = new Map();\n\n\t/**\n\t * Register a prefix parselet for `tokenType`.\n\t *\n\t * If another parselet is already registered for this token type, it is\n\t * silently overwritten by default (`Map.set()` semantics), the old\n\t * parselet is simply unreachable from then on, with no error. This is\n\t * a real footgun for third-party packages: two packages independently\n\t * choosing the same custom token type will collide with zero signal\n\t * about which one \"won\". Mirrors ResolverRegistry.register()'s and\n\t * ExpressionEngine.registerPackage()'s existing \"warn and replace\"\n\t * pattern for the same class of problem at the resolver-namespace and\n\t * package-name levels.\n\t *\n\t * Note: this warns about registry-level collisions only. It does NOT\n\t * detect the separate case where `tokenType` is one of PrecedenceParser's\n\t * Tier-1 fast-path token types (NUMBER, STRING, IDENT, LPAREN, MINUS,\n\t * PLUS, and the Tier-1 infix operators), those are deliberately kept\n\t * registered here for introspection/diagnostics even though Tier-1\n\t * always intercepts them before this registry is consulted (see\n\t * PrecedenceParser.parsePrefix()'s docs), so warning there would\n\t * misfire on that intentional, already-documented pattern.\n\t */\n\tregisterPrefix(tokenType: string, parselet: PrefixParselet): void {\n\t\tconst existing = this.prefixParselets.get(tokenType);\n\t\tif (existing && existing !== parselet) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ParseletRegistry] Prefix parselet for token \"${tokenType}\" is already registered ` +\n\t\t\t\t`(category: \"${existing.category ?? \"unknown\"}\"). Overwriting with a new ` +\n\t\t\t\t`parselet (category: \"${parselet.category ?? \"unknown\"}\") — the previous ` +\n\t\t\t\t`parselet is now unreachable. Two packages may be claiming the same token type.`,\n\t\t\t);\n\t\t}\n\t\tthis.prefixParselets.set(tokenType, parselet);\n\t\tthis.prefixById.set(tokenTypeId(tokenType), parselet);\n\t}\n\n\t/** Register an infix parselet for `tokenType`. See {@link registerPrefix} for the collision-warning behavior this mirrors. */\n\tregisterInfix(tokenType: string, parselet: InfixParselet): void {\n\t\tconst existing = this.infixParselets.get(tokenType);\n\t\tif (existing && existing !== parselet) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ParseletRegistry] Infix parselet for token \"${tokenType}\" is already registered ` +\n\t\t\t\t`(category: \"${existing.category ?? \"unknown\"}\"). Overwriting with a new ` +\n\t\t\t\t`parselet (category: \"${parselet.category ?? \"unknown\"}\") — the previous ` +\n\t\t\t\t`parselet is now unreachable. Two packages may be claiming the same token type.`,\n\t\t\t);\n\t\t}\n\t\tthis.infixParselets.set(tokenType, parselet);\n\t\tthis.infixById.set(tokenTypeId(tokenType), parselet);\n\t}\n\n\t/** Iterate all registered prefix parselets for diagnostic display. */\n\tgetAllPrefix(): Array<{ tokenType: string; bindingPower: number; category?: string }> {\n\t\tconst result: Array<{ tokenType: string; bindingPower: number; category?: string }> = [];\n\t\tfor (const [tokenType, parselet] of this.prefixParselets) {\n\t\t\tresult.push({\n\t\t\t\ttokenType,\n\t\t\t\tbindingPower: bindingPowersOf(parselet).bindingPower ?? 0,\n\t\t\t\tcategory: parselet.category,\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Iterate all registered infix parselets for diagnostic display. */\n\tgetAllInfix(): Array<{ tokenType: string; leftBindingPower: number; rightBindingPower: number; category?: string }> {\n\t\tconst result: Array<{ tokenType: string; leftBindingPower: number; rightBindingPower: number; category?: string }> = [];\n\t\tfor (const [tokenType, parselet] of this.infixParselets) {\n\t\t\tresult.push({\n\t\t\t\ttokenType,\n\t\t\t\tleftBindingPower: bindingPowersOf(parselet).leftBindingPower ?? 0,\n\t\t\t\trightBindingPower: bindingPowersOf(parselet).rightBindingPower ?? 0,\n\t\t\t\tcategory: parselet.category,\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Number of registered prefix parselets. */\n\tget prefixCount(): number { return this.prefixParselets.size; }\n\n\t/** Number of registered infix parselets. */\n\tget infixCount(): number { return this.infixParselets.size; }\n\n\t/**\n\t * Get prefix parselet by string token type OR integer typeId.\n\t * Fast path for integer IDs (Parser hot path), fallback for strings\n\t * (diagnostics, error messages, backwards compatibility).\n\t */\n\tgetPrefix(tokenType: string | number): PrefixParselet | undefined {\n\t\tif (typeof tokenType === 'number') return this.prefixById.get(tokenType);\n\t\treturn this.prefixParselets.get(tokenType);\n\t}\n\n\t/**\n\t * Get infix parselet by string token type OR integer typeId.\n\t * Fast path for integer IDs (Parser hot path), fallback for strings.\n\t */\n\tgetInfix(tokenType: string | number): InfixParselet | undefined {\n\t\tif (typeof tokenType === 'number') return this.infixById.get(tokenType);\n\t\treturn this.infixParselets.get(tokenType);\n\t}\n\n\thasPrefix(tokenType: string): boolean {\n\t\treturn this.prefixParselets.has(tokenType);\n\t}\n\n\thasInfix(tokenType: string): boolean {\n\t\treturn this.infixParselets.has(tokenType);\n\t}\n\n\tclear(): void {\n\t\tthis.prefixParselets.clear();\n\t\tthis.infixParselets.clear();\n\t\tthis.prefixById.clear();\n\t\tthis.infixById.clear();\n\t}\n}\n\n/**\n * A process-wide parselet registry.\n *\n * @deprecated An engine builds its own registry and does not read this one, so\n * registering here reaches nothing that evaluates. It survives for the\n * deprecated {@link PackageRegistry} path only.\n */\nexport const sharedParseletRegistry = new ParseletRegistry();\n","import { ParseletRegistry } from \"@solve-js/parser/registry/ParseletRegistry\";\nimport { Token, tokenTypeId, TokenTypes } from \"@solve-js/lexer/Token\";\nimport { BytecodeBuilder } from \"@solve-js/parser/BytecodeBuilder\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\nimport { DiagnosticPipeline, DiagnosticEventType, type DiagnosticEvent } from \"@solve-js/diagnostics\";\nimport { OpCode } from \"@solve-js/parser/OpCode\";\nimport { BindingPower, buildBindingPowerTable } from \"@solve-js/parser/BindingPower\";\nimport { getLocale } from \"@solve-js/constants/locales\";\n\n/**\n * Matches a CHAINED thousands-grouped integer using \".\" as the group\n * separator (e.g. \"1.234.567\"), independent of locale. Kept in sync with\n * the identical constant in NumberParselet.ts (not imported from there\n * that file transitively re-imports PrecedenceParser via Parser.ts's\n * `export { PrecedenceParser as Parser }`, so importing the other\n * direction would create a circular dependency for the sake of one\n * regex literal). See NumberParselet.ts's copy for the full explanation.\n */\nconst CHAINED_DOT_THOUSANDS_GROUPS = /^\\d{1,3}(\\.\\d{3}){2,}$/;\n\n/**\n * ── Hybrid Precedence Climbing Parser ─────────────────────────────────────────\n *\n * Two-tier dispatch strategy:\n *\n * Tier 1 (Fast Path): Inline switch on token.typeId for built-in operators.\n * - Prefix: NUMBER, IDENT, LPAREN, MINUS, PLUS, STRING\n * - Infix: checked via static BP_TABLE (Uint8Array indexed by typeId)\n * - No Map.get(), no parselet function call overhead for ~95% of tokens\n *\n * Tier 2 (Plugin Path): ParseletRegistry fallback for custom/plugin tokens.\n * - Prefix: Map.get(tokenTypeId) for PrefixParselet\n * - Infix: Map.get(tokenTypeId) for InfixParselet\n * - Full flexibility for custom syntax\n *\n * The parser emits directly to a BytecodeBuilder, no AST intermediate.\n * Implements the same public API as the legacy Parser class so existing\n * parselets continue to work without modification.\n */\nexport class PrecedenceParser {\n private tokens: Token[] = [];\n private current = 0;\n private depth = 0;\n private maxDepth: number;\n\n /** Cached registry reference, avoids property chain in hot loop */\n private registry: ParseletRegistry;\n\n /** BytecodeBuilder, set before each parseExpression call */\n private builder!: BytecodeBuilder;\n\n /** Diagnostic pipeline for parselet-matched events */\n private diagnosticPipeline: DiagnosticPipeline | undefined;\n private currentExpression: string = \"\";\n private localeCode: string;\n\n /**\n * Static binding power table, built once at module load, shared across all instances.\n * Index = tokenTypeId, value = binding power (0 = not a built-in infix).\n */\n static readonly BP_TABLE: Uint8Array = buildBindingPowerTable();\n\n // ── Pre-computed token type IDs for inline dispatch ────────────────────────\n // Prefix built-ins\n private static readonly NUMBER_ID = tokenTypeId(TokenTypes.NUMBER);\n private static readonly BIGINT_ID = tokenTypeId(TokenTypes.BIGINT);\n private static readonly STRING_ID = tokenTypeId(TokenTypes.STRING);\n private static readonly IDENT_ID = tokenTypeId(TokenTypes.IDENT);\n private static readonly LPAREN_ID = tokenTypeId(TokenTypes.LPAREN);\n private static readonly RPAREN_ID = tokenTypeId(TokenTypes.RPAREN);\n private static readonly MINUS_ID = tokenTypeId(TokenTypes.MINUS);\n private static readonly PLUS_ID = tokenTypeId(TokenTypes.PLUS);\n private static readonly KEYWORD_ID = tokenTypeId(TokenTypes.KEYWORD);\n\n // Infix built-ins (Tier 1, full inline emission)\n private static readonly STAR_ID = tokenTypeId(TokenTypes.STAR);\n private static readonly SLASH_ID = tokenTypeId(TokenTypes.SLASH);\n private static readonly MOD_ID = tokenTypeId(TokenTypes.MOD);\n private static readonly CARET_ID = tokenTypeId(TokenTypes.CARET);\n private static readonly LSHIFT_ID = tokenTypeId(TokenTypes.LSHIFT);\n private static readonly RSHIFT_ID = tokenTypeId(TokenTypes.RSHIFT);\n private static readonly BIT_AND_ID = tokenTypeId(TokenTypes.BIT_AND);\n private static readonly BIT_OR_ID = tokenTypeId(TokenTypes.BIT_OR);\n private static readonly BIT_XOR_ID = tokenTypeId(TokenTypes.BIT_XOR);\n private static readonly PERCENT_ID = tokenTypeId(TokenTypes.PERCENT);\n private static readonly OF_ID = tokenTypeId(TokenTypes.OF);\n\n /**\n * Inline opcode map for Tier 1 infix operators.\n * tokenTypeId → OpCode. PERCENT and CARET are handled specially (not in this map).\n */\n private static readonly INFIX_OPCODE: Record<number, OpCode> = {\n [tokenTypeId(TokenTypes.PLUS)]: OpCode.ADD,\n [tokenTypeId(TokenTypes.MINUS)]: OpCode.SUB,\n [tokenTypeId(TokenTypes.STAR)]: OpCode.MUL,\n [tokenTypeId(TokenTypes.SLASH)]: OpCode.DIV,\n [tokenTypeId(TokenTypes.MOD)]: OpCode.MOD,\n [tokenTypeId(TokenTypes.CARET)]: OpCode.EXP,\n [tokenTypeId(TokenTypes.LSHIFT)]: OpCode.LSHIFT,\n [tokenTypeId(TokenTypes.RSHIFT)]: OpCode.RSHIFT,\n [tokenTypeId(TokenTypes.BIT_AND)]: OpCode.BIT_AND,\n [tokenTypeId(TokenTypes.BIT_OR)]: OpCode.BIT_OR,\n [tokenTypeId(TokenTypes.BIT_XOR)]: OpCode.BIT_XOR,\n [tokenTypeId(TokenTypes.OF)]: OpCode.MUL,\n };\n\n constructor(parseletRegistry: ParseletRegistry, maxDepth = 50, localeCode = \"en\") {\n this.registry = parseletRegistry;\n this.maxDepth = maxDepth;\n this.localeCode = localeCode;\n }\n\n /** Get locale code for NumberParselet to normalize separators */\n getLocaleCode(): string {\n return this.localeCode;\n }\n\n /**\n * Set the diagnostic pipeline for parselet matching events.\n * Cleared after each non-cached parse to avoid holding refs.\n */\n setDiagnosticPipeline(pipeline: DiagnosticPipeline | undefined, expression: string): void {\n this.diagnosticPipeline = pipeline;\n this.currentExpression = expression ?? \"\";\n }\n\n /**\n * Load tokens for parsing. Identical to Parser.load().\n *\n * @param hasParens - if false, skips the O(n) paren balance scan (~90% of expressions)\n */\n load(tokens: Token[], hasParens?: boolean): void {\n if (hasParens === false) {\n this.tokens = tokens;\n this.current = 0;\n this.depth = 0;\n return;\n }\n // Paren scan: count balance to skip array copy for balanced expressions.\n const LPAREN_ID = tokenTypeId(TokenTypes.LPAREN);\n const RPAREN_ID = tokenTypeId(TokenTypes.RPAREN);\n let openCount = 0;\n for (let i = 0; i < tokens.length; i++) {\n if (tokens[i].typeId === LPAREN_ID) openCount++;\n else if (tokens[i].typeId === RPAREN_ID) openCount--;\n }\n this.tokens = openCount === 0 ? tokens : this.balanceParens(tokens, openCount);\n this.current = 0;\n this.depth = 0;\n }\n\n /**\n * Auto-balance unmatched parentheses.\n */\n private balanceParens(tokens: Token[], openCount: number): Token[] {\n const result = tokens.slice();\n if (openCount > 0) {\n const RPAREN_ID = tokenTypeId(TokenTypes.RPAREN);\n for (let i = 0; i < openCount; i++) {\n const lastToken = tokens[tokens.length - 1];\n result.push({\n type: TokenTypes.RPAREN,\n typeId: RPAREN_ID,\n value: \")\",\n text: \")\",\n offset: lastToken ? lastToken.offset + lastToken.text.length : 0,\n lineBreaks: 0,\n line: lastToken ? lastToken.line : 1,\n col: lastToken ? lastToken.col + lastToken.text.length : 1,\n } as Token);\n }\n } else if (openCount < 0) {\n const LPAREN_ID = tokenTypeId(TokenTypes.LPAREN);\n for (let i = 0; i < -openCount; i++) {\n result.unshift({\n type: TokenTypes.LPAREN,\n typeId: LPAREN_ID,\n value: \"(\",\n text: \"(\",\n offset: 0,\n lineBreaks: 0,\n line: 1,\n col: 1,\n } as Token);\n }\n }\n return result;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // Main entry point: precedence climbing parse expression\n // ═══════════════════════════════════════════════════════════════════════════════\n\n /**\n * Parse a full expression starting at the current token position.\n *\n * @param minBp - minimum binding power (precedence climbing threshold).\n * For left-associative operators, the recursive call uses `bp + 1`.\n * For right-associative operators (^), it uses `bp`.\n * @param _builder - accepted for parselet API compatibility; always uses `this.builder`.\n */\n parseExpression(minBp: number = 0, _builder?: BytecodeBuilder): void {\n // Accept builder via parameter for backward compatibility with the old Parser API.\n // The ExpressionEngine always calls setBuilder() before parseExpression(),\n // but tests and parselets pass builder as a parameter.\n if (_builder) {\n this.builder = _builder;\n }\n this.depth++;\n if (this.depth > this.maxDepth) {\n this.depth--;\n throw ErrorFactory.parsing(\n \"NESTING_DEPTH_EXCEEDED\",\n `Parse nesting depth ${this.depth} exceeds maximum of ${this.maxDepth}`,\n { maxDepth: this.maxDepth, currentDepth: this.depth }\n );\n }\n\n const token = this.consume();\n if (!token) {\n this.depth--;\n throw ErrorFactory.parsing(\"UNEXPECTED_END\", \"Unexpected end of expression\");\n }\n\n // ── Prefix ──────────────────────────────────────────────────────────────\n this.parsePrefix(token);\n\n // ── Infix loop (precedence climbing with inline Tier 1 dispatch) ──────────\n const tokens = this.tokens;\n const len = tokens.length;\n const bpTable = PrecedenceParser.BP_TABLE;\n const registry = this.registry;\n const builder = this.builder;\n let idx = this.current;\n\n while (idx < len) {\n const lookahead = tokens[idx];\n if (!lookahead) break;\n\n const bp = bpTable[lookahead.typeId];\n if (bp > 0) {\n // Tier 1: Built-in infix, full inline emission, zero parselet delegation\n if (bp <= minBp) break;\n\n if (this.diagnosticPipeline) {\n // Fast path skips the registry, but built-ins are still registered\n // there (for introspection/tests), look them up only in this\n // diagnostics-only branch so the playground's \"matched parselets\"\n // view isn't permanently blind to every arithmetic operator.\n const infixParselet = registry.getInfix(lookahead.typeId);\n if (infixParselet) {\n this.fireParseletMatched(infixParselet, lookahead, false, bp);\n }\n }\n\n this.current = ++idx;\n const typeId = lookahead.typeId;\n\n if (typeId === PrecedenceParser.PERCENT_ID) {\n // Postfix: no right operand. \"50%\" → Percentage holding 0.5.\n //\n // Must stay byte-for-byte equivalent to PercentParselet, which is\n // the Tier-2 registration of the same operator. This path is the one\n // that actually runs for ordinary expressions, so a change made only\n // in the parselet does nothing at all: that is exactly how the\n // divide-by-100 here outlived its replacement and kept `200 + 10%`\n // answering 200.10.\n builder.emitOpcode(OpCode.PUSH_NUMBER);\n builder.emitNumber(100);\n builder.emitOpcode(OpCode.DIV);\n builder.emitOpcode(OpCode.TO_PERCENTAGE);\n } else if (typeId === PrecedenceParser.CARET_ID && this.tryEmitMatrixCaretOp(builder)) {\n // `^T` (transpose) or `^-1` (inverse), already fully handled\n // including consuming their own trailing tokens.\n } else {\n // Infix: parse right operand, then emit opcode.\n // Right-associative for CARET (^), left-associative for all others.\n const rightBp = (typeId === PrecedenceParser.CARET_ID) ? bp : bp + 1;\n this.parseExpression(rightBp, builder);\n builder.emitOpcode(PrecedenceParser.INFIX_OPCODE[typeId]);\n }\n } else {\n // Tier 2: Plugin parselet fallback, full flexibility for custom syntax\n const infixParselet = registry.getInfix(lookahead.typeId);\n if (!infixParselet) break;\n if (infixParselet.bindingPower <= minBp) break;\n\n this.current = ++idx;\n\n if (this.diagnosticPipeline) {\n this.fireParseletMatched(infixParselet, lookahead, false, infixParselet.bindingPower);\n }\n // Parselet handles its own recursion for right operand internally\n infixParselet.parse(this, token, lookahead, builder);\n }\n\n idx = this.current;\n }\n\n this.current = idx;\n this.depth--;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // Prefix dispatch: inline switch for built-ins, parselet registry for plugins\n // ═══════════════════════════════════════════════════════════════════════════════\n\n /**\n * Parse a prefix token. Built-in tokens (NUMBER, IDENT, LPAREN, etc.) are\n * handled inline with zero registry lookup. Everything else falls through\n * to the parselet registry (Tier 2).\n */\n private parsePrefix(token: Token): void {\n const builder = this.builder;\n const typeId = token.typeId;\n\n if (this.diagnosticPipeline) {\n // Fast path below skips the registry for built-ins, but they're still\n // registered there (for introspection/tests), look up here so the\n // playground's \"matched parselets\" view isn't permanently blind to\n // every number, identifier, paren, and unary operator.\n const parselet = this.registry.getPrefix(typeId);\n if (parselet) {\n this.fireParseletMatched(parselet, token, true);\n }\n }\n\n switch (typeId) {\n // ── Numeric literals ──────────────────────────────────────────────────\n case PrecedenceParser.NUMBER_ID: {\n // Parse number with locale-aware separator normalization\n let v: number;\n const raw = token.value;\n if (raw.startsWith(\"0x\") || raw.startsWith(\"0X\")) {\n v = parseInt(raw, 16);\n // A prefix with no digits after it (\"0x\" alone) makes parseInt\n // return NaN. This used to push straight through as a silent\n // NaN Number value instead of a visible error.\n if (Number.isNaN(v)) {\n throw ErrorFactory.parsing(\"INVALID_NUMBER_LITERAL\", `Invalid hex literal: \"${raw}\"`, { raw });\n }\n } else if (raw.startsWith(\"0b\") || raw.startsWith(\"0B\")) {\n v = parseInt(raw.slice(2), 2);\n if (Number.isNaN(v)) {\n throw ErrorFactory.parsing(\"INVALID_NUMBER_LITERAL\", `Invalid binary literal: \"${raw}\"`, { raw });\n }\n } else if (raw.startsWith(\"0o\") || raw.startsWith(\"0O\")) {\n v = parseInt(raw.slice(2), 8);\n if (Number.isNaN(v)) {\n throw ErrorFactory.parsing(\"INVALID_NUMBER_LITERAL\", `Invalid octal literal: \"${raw}\"`, { raw });\n }\n } else if (CHAINED_DOT_THOUSANDS_GROUPS.test(raw)) {\n // The lexer accepts \".\" as a thousands-group separator\n // independent of locale (ExpressionLexer's number-scanning\n // \"Thousands separators\" block), but the locale-based\n // normalization below only strips the ACTIVE locale's own\n // configured thousandsSeparator character, for \"en\" that's\n // \",\", not \".\", so a chained dot-grouped literal like\n // \"1.234.567\" fell through to parseFloat() untouched, which\n // stops at the second \".\" and silently truncated it to 1.234\n // (over 99% of the digits dropped, with no error). This is the\n // REAL number-parsing path for actual evaluation, Tier 1 of\n // the two-tier dispatch above always returns for NUMBER_ID, so\n // NumberParselet.parse() (which has the identical fix) never\n // actually runs except via direct unit tests / the \"matched\n // parselets\" diagnostic display.\n v = parseFloat(raw.split(\".\").join(\"\"));\n } else {\n const locale = getLocale(this.localeCode);\n const decimalSep = locale.display.decimalSeparator;\n const thousandsSep = locale.display.thousandsSeparator;\n let normalized = raw;\n // Replace thousands separator with empty string (split+join avoids per-call RegExp compilation)\n if (thousandsSep) {\n normalized = normalized.split(thousandsSep).join(\"\");\n }\n // Replace locale decimal separator with \".\" for JavaScript parsing\n if (decimalSep && decimalSep !== \".\") {\n normalized = normalized.replace(decimalSep, \".\");\n }\n v = parseFloat(normalized);\n }\n builder.emitOpcode(OpCode.PUSH_NUMBER);\n builder.emitNumber(v);\n return;\n }\n\n case PrecedenceParser.BIGINT_ID: {\n // Strip optional 'n' suffix before emitting as string\n let raw = token.value;\n if (raw.endsWith(\"n\")) raw = raw.slice(0, -1);\n builder.emitOpcode(OpCode.PUSH_BIGINT);\n builder.emitString(raw);\n return;\n }\n\n case PrecedenceParser.STRING_ID: {\n builder.emitOpcode(OpCode.PUSH_STRING);\n builder.emitString(token.value);\n return;\n }\n\n // ── Identifiers (variables) ────────────────────────────────────────────\n case PrecedenceParser.IDENT_ID: {\n // An identifier immediately followed by \"(\" may be a user-defined\n // function DEFINITION (`f(x) = ...`) or CALL (`f(5)`). See\n // parseUserFunctionDefOrCall's doc comment for the full\n // disambiguation. Only the (cheap) LPAREN check runs for the\n // overwhelmingly common case of a bare identifier with nothing\n // following it.\n if (this.peek()?.typeId === PrecedenceParser.LPAREN_ID) {\n this.parseUserFunctionDefOrCall(token, builder);\n return;\n }\n // IDENT tokens map to LOAD_VAR by default. The IdentifierParselet\n // and VariableParselet add STORE_VAR for assignments, those are\n // handled via the parselet registry below. Note this is also how a\n // user-defined function's own PARAMETER references compile. See\n // UserFunctionDef's doc comment in BytecodeBuilder.ts for why there\n // is no separate parameter-load opcode: `LOAD_VAR` resolution\n // dynamically checks the VM's innermost call frame first.\n builder.emitOpcode(OpCode.LOAD_VAR);\n builder.emitString(token.value);\n return;\n }\n\n // ── Grouping / bare-tuple vector literal ─────────────────────────────────\n // `(expr)` groups for precedence; `(x, y[, z[, w]])` is the bare-tuple\n // vector literal documented as an alternative to vec2/vec3/vec4(...)\n // (wiki: Arithmetic/Vector). This Tier-1 case is what actually runs for\n // every LPAREN in production parsing, GroupParselet.ts mirrors this\n // logic for registry-introspection/diagnostic-listing purposes, but a\n // package can never override LPAREN's dispatch here (Tier 1 always\n // wins over the ParseletRegistry fallback below), so both must be kept\n // in sync by hand.\n case PrecedenceParser.LPAREN_ID: {\n this.parseExpression(0, builder);\n let count = 1;\n while (this.match(TokenTypes.COMMA)) {\n this.parseExpression(0, builder);\n count++;\n }\n this.consume(TokenTypes.RPAREN);\n if (count > 1) {\n // Legacy bare-tuple vector sugar, a 1xN row-vector Matrix (see\n // packages/vector/parselets/VectorParselet.ts's comment).\n builder.emitOpcode(OpCode.MAT_NEW);\n builder.emitIndex(1);\n builder.emitIndex(count);\n }\n return;\n }\n\n // ── Unary operators ───────────────────────────────────────────────────\n case PrecedenceParser.MINUS_ID: {\n this.parseExpression(BindingPower.Prefix, builder);\n builder.emitOpcode(OpCode.NEG);\n return;\n }\n\n case PrecedenceParser.PLUS_ID: {\n this.parseExpression(BindingPower.Prefix, builder);\n builder.emitOpcode(OpCode.POS);\n return;\n }\n\n // ── Keyword constants ─────────────────────────────────────────────────\n case PrecedenceParser.KEYWORD_ID: {\n // Keywords are handled by parselets (pi→PI, e→E, etc.)\n // Fall through to registry below.\n }\n }\n\n // ── Tier 2: Plugin/parselet prefix path ──────────────────────────────────\n const prefixParselet = this.registry.getPrefix(typeId);\n if (!prefixParselet) {\n throw ErrorFactory.parsing(\n \"NO_PREFIX_PARSELET\",\n `No prefix parselet found for token: ${token.type} (\"${token.value}\")`,\n { tokenType: token.type, tokenValue: token.value }\n );\n }\n\n prefixParselet.parse(this, token, builder);\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // The \"Tier-1 shape-exception\" pattern\n // ═══════════════════════════════════════════════════════════════════════════════\n //\n // Tier 1 exists purely for performance, avoid a Map lookup + parselet call\n // on ~95% of tokens (see this file's own module doc comment above). A\n // recurring consequence: any grammar shape tied to a Tier-1 token type can\n // ONLY be implemented by hand-editing this switch, since a package-\n // registered ParseletRegistry parselet for that same token type would\n // simply never run in production (Tier 1 always wins over the registry\n // fallback). Five confirmed instances of this tension exist in this file\n // (plus one that had to move OUTSIDE it entirely):\n // 1. NUMBER_ID, the full locale-aware number-literal parsing (hex/\n // binary/octal, chained-dot thousands grouping, decimal-separator\n // normalization) is inlined in parsePrefix() above; NumberParselet.ts's\n // own copy is dead code for real evaluation, kept registered only for\n // the \"matched parselets\" diagnostic view.\n // 2. IDENT_ID, parseUserFunctionDefOrCall's lookahead (below) disambig-\n // uates a function DEFINITION from a CALL from a plain variable load.\n // 3. LPAREN_ID, the bare-tuple vector-literal sugar (\"(x,y[,z[,w]])\" ->\n // MAT_NEW) is inlined in parsePrefix() above; GroupParselet.ts mirrors\n // it for introspection only and must be kept in sync by hand.\n // 4. CARET_ID, the transpose/inverse suffix table just below.\n // 5. PLUS_ID, the locale word \"and\" lexes as PLUS (Tier-1, fixed Sum\n // binding power), so a registry parselet can never intercept it the\n // way LogicalParselet.ts intercepts \"or\"/&&/||; unlike the other four,\n // there's no SHAPE to special-case on here (the token itself IS the\n // operator), so the workaround lives entirely outside this file, as a\n // runtime Boolean/Boolean type-check inside vm/VM.ts's OpCode.ADD\n // handler instead.\n //\n // Deliberate non-goal: none of this is exposed as an IEnginePackage\n // extension point (unlike prefixParselets/infixParselets). Letting\n // third-party packages register their own Tier-1 shape-matchers would put\n // per-package matcher iteration on a genuinely hot path (every CARET/\n // NUMBER/IDENT/LPAREN/PLUS token, matched or not), a materially bigger\n // separate product decision than \"make this one table more concise,\" and\n // not one this pattern write-up makes.\n\n /**\n * A single `^`-suffix shape: `matches` peeks ahead (consuming nothing) to\n * check whether this shape starts at the current position; `emit` is only\n * called immediately after `matches` returned true for that SAME position,\n * and is responsible for consuming that shape's own trailing tokens and\n * emitting its bytecode.\n */\n private static readonly CARET_SUFFIX_RULES: ReadonlyArray<{\n name: string;\n matches(parser: PrecedenceParser): boolean;\n emit(parser: PrecedenceParser, builder: BytecodeBuilder): void;\n }> = [\n {\n name: \"transpose (^T)\",\n matches: (p) => {\n const next = p.peek();\n return next?.type === TokenTypes.IDENT && next.value === \"T\";\n },\n emit: (p, builder) => {\n p.advance();\n builder.emitOpcode(OpCode.CALL_BUILTIN);\n builder.emitIndex(63); // transpose — see VMBuiltins.ts\n builder.emitIndex(1);\n },\n },\n {\n name: \"inverse (^-1)\",\n matches: (p) => {\n const next = p.peek();\n if (next?.typeId !== PrecedenceParser.MINUS_ID) return false;\n const afterMinus = p.peekAt(1);\n return afterMinus?.type === TokenTypes.NUMBER && afterMinus.value === \"1\";\n },\n emit: (p, builder) => {\n p.advance();\n p.advance();\n builder.emitOpcode(OpCode.CALL_BUILTIN);\n builder.emitIndex(65); // inv — see VMBuiltins.ts\n builder.emitIndex(1);\n },\n },\n ];\n\n /**\n * After a `^` token (already consumed by the Tier-1 infix loop above),\n * checks {@link CARET_SUFFIX_RULES} in order for a shape that means\n * something other than ordinary exponentiation: `^T` (transpose) and `^-1`\n * (matrix inverse, LITERALLY the integer exponent `-1`; `^-2`, `^-1.5`\n * etc. still mean ordinary exponentiation). On a match, the rule's `emit`\n * consumes that shape's own tokens and this returns `true`. On no match,\n * consumes NOTHING, returning `false` so the caller falls through to\n * ordinary `EXP` parsing.\n *\n * Every rule dispatches purely on SHAPE, never on operand type (unknowable\n * at parse time): `inv()`'s own handler (`VMBuiltins.ts` index 65) returns\n * `1/x` for a plain Number, byte-identical to what `Math.pow(x, -1)`\n * already computed for `x^-1` before this feature existed, and a real\n * matrix inverse for a Matrix, so `5^-1` still means exactly what it always\n * has; only a Matrix operand actually inverts.\n *\n * Adding a future `^`-suffix shape is a new table entry here, not a new\n * if-block. See the \"Tier-1 shape-exception\" pattern write-up above for\n * why this table can't instead be a package-registered parselet.\n */\n private tryEmitMatrixCaretOp(builder: BytecodeBuilder): boolean {\n for (const rule of PrecedenceParser.CARET_SUFFIX_RULES) {\n if (rule.matches(this)) {\n rule.emit(this, builder);\n return true;\n }\n }\n return false;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // User-defined, parameterized, reusable functions (f(x) = 2*x + 1, then f(5))\n // ═══════════════════════════════════════════════════════════════════════════════\n\n /**\n * From an LPAREN token index, scan forward tracking paren depth and\n * return the index of the matching RPAREN, or `null` if the parens never\n * balance before the token stream ends. No emission, no position\n * advance. Same class of technique as {@link balanceParens}'s own\n * pre-scan, just exposed mid-parse instead of only at `load()` time.\n * `openIdx` must point AT the LPAREN itself.\n */\n private findMatchingRParen(openIdx: number): number | null {\n let depth = 0;\n for (let i = openIdx; i < this.tokens.length; i++) {\n const t = this.tokens[i];\n if (t.typeId === PrecedenceParser.LPAREN_ID) depth++;\n else if (t.typeId === PrecedenceParser.RPAREN_ID) {\n depth--;\n if (depth === 0) return i;\n }\n }\n return null;\n }\n\n /**\n * Disambiguates a bare `IDENT` immediately followed by `(` between three\n * things, using ONLY a bracket-depth scan (no backtracking, nothing is\n * consumed until the shape is known):\n * - `f(x) = expr`, a DEFINITION: the matching `)` is followed by `=`.\n * - `f(5)`, a CALL to a (possibly not-yet-defined) function: anything\n * else. This was never valid syntax before this feature (a bare\n * `IDENT` immediately before `(` has no pre-existing \"plain variable\n * read + separately grouped `(...)`\" meaning to preserve, confirmed\n * via `BuiltinNormalizerRules.ts`'s `implicitMultiplyRule()`, which\n * only inserts an implicit `*` for `NUMBER/RPAREN` immediately before\n * `IDENT/LPAREN`, never for a bare `IDENT` immediately before\n * `LPAREN`). Always commits to a CALL; an unregistered name produces a\n * clear `UNDEFINED_FUNCTION` error at VM-execution time, the same\n * forward-reference philosophy `LOAD_VAR`/`UNDEFINED_VARIABLE` already\n * uses, rather than any parse-time registry lookup.\n * If the parens never balance, this falls through to the ordinary\n * `LOAD_VAR` path (a malformed expression surfaces its own parse error\n * shortly after, from the normal expression grammar).\n */\n private parseUserFunctionDefOrCall(nameToken: Token, builder: BytecodeBuilder): void {\n const closeIdx = this.findMatchingRParen(this.current);\n if (closeIdx === null) {\n builder.emitOpcode(OpCode.LOAD_VAR);\n builder.emitString(nameToken.value);\n return;\n }\n const afterClose = this.tokens[closeIdx + 1];\n if (afterClose?.type === TokenTypes.EQUALS) {\n this.parseUserFunctionDefinition(nameToken, builder);\n } else {\n this.parseUserFunctionCall(nameToken, builder);\n }\n }\n\n /**\n * A parameter name, accepted as either `IDENT` or `UNIT`, matches this\n * codebase's established `:name = value` variable-name policy\n * (`VariableParselet.ts` explicitly accepts `UNIT`-typed tokens too, e.g.\n * `:b = 5` for the \"b\" bits unit) since common short parameter names\n * like `h`/`l`/`b`/`t`/`s`/`m` collide with real unit abbreviations\n * (hour, liter, bits, ton, second, meter, ...) and lex as `UNIT`, not\n * `IDENT`.\n */\n private consumeParamName(): string {\n const token = this.peek();\n if (token?.type === TokenTypes.IDENT || token?.type === TokenTypes.UNIT) {\n this.consume();\n return token.value;\n }\n throw ErrorFactory.parsing(\n \"USER_FUNCTION_INVALID_PARAM_NAME\",\n `Expected a parameter name but got \"${token?.type ?? \"end of input\"}\"${token ? ` (\"${token.value}\")` : \"\"}`,\n { actualType: token?.type },\n );\n }\n\n private parseUserFunctionDefinition(nameToken: Token, builder: BytecodeBuilder): void {\n this.consume(TokenTypes.LPAREN);\n const params: string[] = [];\n if (this.peek()?.type !== TokenTypes.RPAREN) {\n params.push(this.consumeParamName());\n while (this.match(TokenTypes.COMMA)) {\n params.push(this.consumeParamName());\n }\n }\n this.consume(TokenTypes.RPAREN);\n this.consume(TokenTypes.EQUALS);\n\n if (params.length === 0) {\n throw ErrorFactory.parsing(\n \"USER_FUNCTION_NO_PARAMS\",\n `\"${nameToken.value}()\" has no parameters -- user-defined functions need at least one (a zero-argument definition is indistinguishable from a plain function CALL with no args, which this grammar doesn't otherwise support)`,\n { name: nameToken.value },\n );\n }\n\n // Compile the body into its OWN independent BytecodeBuilder, reusing\n // the SAME parser/token stream but directing emission elsewhere.\n // `parseExpression(minBp, _builder)` sets `this.builder = _builder`\n // with NO automatic restore, explicitly restoring via `setBuilder()`\n // afterward (not a `finally`, since a thrown parse error here should\n // propagate as-is; there's no further use of `this.builder` on that\n // path before the whole parse aborts) avoids silently emitting\n // whatever parses next (in this same expression, or, via\n // ExpressionEngine's builder pool, a LATER, unrelated line) into a\n // stale, already-.build()'d body builder.\n const bodyBuilder = new BytecodeBuilder();\n this.parseExpression(BindingPower.Lowest, bodyBuilder);\n this.setBuilder(builder);\n\n const bodyProgram = bodyBuilder.build();\n if (bodyProgram.hasAsync) {\n // v1 scope decision: a function body calling an async plugin\n // (weather, stocks, currency, ...) isn't supported yet, propagating\n // a 'pending' result up through a reentrant executeBytecode() call\n // would need the OUTER expression's own bytecode position/stack\n // state to also be resumable later, which this first pass doesn't\n // implement. Rejecting at DEFINITION time (not call time) gives the\n // clearest possible error, matching this codebase's \"never silently\n // pretend to support something it doesn't\" convention (e.g.\n // addBusinessDays()'s own disclosed holiday-exclusion scope-down).\n throw ErrorFactory.parsing(\n \"FUNCTION_BODY_MUST_BE_SYNCHRONOUS\",\n `\"${nameToken.value}(...)\"'s body calls an async operation (weather, stocks, currency, ...) — user-defined function bodies must be synchronous`,\n { name: nameToken.value },\n );\n }\n\n const bodyIdx = builder.emitUserFunctionBody(nameToken.value, params, bodyProgram);\n builder.emitOpcode(OpCode.DEFINE_USER_FUNCTION);\n builder.emitIndex(bodyIdx);\n\n // A definition line has no single input value to echo back the way an\n // assignment does, push a plain confirmation string, matching this\n // codebase's \"never silently produce a misleading numeric 0\" principle.\n builder.emitOpcode(OpCode.PUSH_STRING);\n builder.emitString(`${nameToken.value}(${params.join(\", \")}) defined`);\n }\n\n private parseUserFunctionCall(nameToken: Token, builder: BytecodeBuilder): void {\n this.consume(TokenTypes.LPAREN);\n let argCount = 0;\n if (this.peek()?.type !== TokenTypes.RPAREN) {\n this.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n while (this.match(TokenTypes.COMMA)) {\n this.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n }\n }\n this.consume(TokenTypes.RPAREN);\n\n builder.emitOpcode(OpCode.CALL_USER_FUNCTION);\n builder.emitString(nameToken.value);\n builder.emitByte(argCount);\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // Token stream navigation (identical API to Parser)\n // ═══════════════════════════════════════════════════════════════════════════════\n\n consume(expectedType?: string): Token {\n const token = this.tokens[this.current];\n if (!token) {\n throw ErrorFactory.parsing(\n \"UNEXPECTED_END_OF_INPUT\",\n \"Unexpected end of input\"\n );\n }\n if (expectedType !== undefined) {\n const expectedId = tokenTypeId(expectedType);\n if (token.typeId !== expectedId) {\n throw ErrorFactory.parsing(\n \"UNEXPECTED_TOKEN_TYPE\",\n `Expected token type \"${expectedType}\" but got \"${token.type}\" (\"${token.value}\")`,\n { expectedType, actualType: token.type, actualValue: token.value }\n );\n }\n }\n this.current++;\n return token;\n }\n\n match(expectedType: string): boolean {\n const token = this.peek();\n if (token && token.typeId === tokenTypeId(expectedType)) {\n this.advance();\n return true;\n }\n return false;\n }\n\n peek(): Token | undefined {\n return this.tokens[this.current];\n }\n\n /**\n * Read-only lookahead `offset` tokens past the current position, without\n * consuming anything, `peekAt(0)` is equivalent to {@link peek}.\n * `this.tokens` is a plain in-memory array (not a stream), so this is a\n * simple, safe index read; no rewind/checkpoint mechanism is needed since\n * nothing is consumed.\n */\n peekAt(offset: number): Token | undefined {\n return this.tokens[this.current + offset];\n }\n\n previous(): Token | undefined {\n return this.current > 0 ? this.tokens[this.current - 1] : undefined;\n }\n\n private advance(): void {\n this.current++;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // Builder access, set before parse, read by inline prefix handlers\n // ═══════════════════════════════════════════════════════════════════════════════\n\n /** Set the builder to use for the current parse. Called by ExpressionEngine. */\n setBuilder(builder: BytecodeBuilder): void {\n this.builder = builder;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // Diagnostics\n // ═══════════════════════════════════════════════════════════════════════════════\n\n private fireParseletMatched(\n parselet: { category: string },\n token: Token,\n isPrefix: boolean,\n bindingPower?: number\n ): void {\n const pipeline = this.diagnosticPipeline!;\n const event: DiagnosticEvent & { type: \"parselet_matched\" } = {\n type: DiagnosticEventType.ParseletMatched,\n elapsedNs: 0,\n expression: this.currentExpression,\n tokenType: token.type,\n tokenValue: token.value,\n parseletCategory: parselet.category,\n parseletType: parselet.constructor?.name ?? \"unknown\",\n isPrefix,\n bindingPower,\n tokenOffset: token.offset || 0,\n };\n pipeline.fireParseletMatched(event);\n }\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunk53B6KDDJ_cjs = require('./chunk-53B6KDDJ.cjs');
3
+ var chunkMBNQVDVC_cjs = require('./chunk-MBNQVDVC.cjs');
4
4
 
5
5
  // src/uom/UnitConversion.ts
6
- var UNIT_LOOKUP = new Map(Object.entries(chunk53B6KDDJ_cjs.UNIT_TABLE));
7
- var DIFFERENCE_LOOKUP = new Map(Object.entries(chunk53B6KDDJ_cjs.UNIT_DIFFERENCES));
6
+ var UNIT_LOOKUP = new Map(Object.entries(chunkMBNQVDVC_cjs.UNIT_TABLE));
7
+ var DIFFERENCE_LOOKUP = new Map(Object.entries(chunkMBNQVDVC_cjs.UNIT_DIFFERENCES));
8
8
  function lookupUnit(unit) {
9
9
  return UNIT_LOOKUP.get(unit);
10
10
  }
@@ -45,7 +45,7 @@ function convertToBestMetric(quantity, from) {
45
45
  if (parsedFrom === void 0) {
46
46
  throw new RangeError(`${from} is not a valid unit`);
47
47
  }
48
- const best = chunk53B6KDDJ_cjs.BEST_UNITS_METRIC[parsedFrom[0]];
48
+ const best = chunkMBNQVDVC_cjs.BEST_UNITS_METRIC[parsedFrom[0]];
49
49
  const smallestUnit = best[0][0];
50
50
  let bestUnit = smallestUnit;
51
51
  const baseQuantity = convertRaw(quantity, from, smallestUnit);
@@ -72,11 +72,11 @@ function resolveUnit(unit) {
72
72
  }
73
73
  function getMeasure(unit) {
74
74
  if (isWorkdayUnit(unit)) return getMeasure("day");
75
- const extended = chunk53B6KDDJ_cjs.EXTENDED_UNITS[unit];
75
+ const extended = chunkMBNQVDVC_cjs.EXTENDED_UNITS[unit];
76
76
  if (extended) return extended.measure;
77
77
  const entry = lookupUnit(unit);
78
78
  if (entry === void 0) return void 0;
79
- return chunk53B6KDDJ_cjs.MEASURE_KIND_NAMES[entry[0]];
79
+ return chunkMBNQVDVC_cjs.MEASURE_KIND_NAMES[entry[0]];
80
80
  }
81
81
  function canConvert(from, to) {
82
82
  if (from === to) return true;
@@ -90,12 +90,19 @@ function canConvert(from, to) {
90
90
  if (fromEntry !== void 0 && toEntry !== void 0) {
91
91
  return fromEntry[0] === toEntry[0];
92
92
  }
93
- const fromExtended = chunk53B6KDDJ_cjs.EXTENDED_UNITS[from];
94
- const toExtended = chunk53B6KDDJ_cjs.EXTENDED_UNITS[to];
93
+ const fromExtended = chunkMBNQVDVC_cjs.EXTENDED_UNITS[from];
94
+ const toExtended = chunkMBNQVDVC_cjs.EXTENDED_UNITS[to];
95
95
  if (fromExtended !== void 0 && toExtended !== void 0) {
96
96
  return fromExtended.measure === toExtended.measure;
97
97
  }
98
- return false;
98
+ return bridgesToBaseMeasure(from, to) || bridgesToBaseMeasure(to, from);
99
+ }
100
+ function bridgesToBaseMeasure(extendedUnit, baseUnit) {
101
+ const extended = chunkMBNQVDVC_cjs.EXTENDED_UNITS[extendedUnit];
102
+ if (extended === void 0) return false;
103
+ const base = lookupUnit(resolveUnit(baseUnit));
104
+ if (base === void 0) return false;
105
+ return chunkMBNQVDVC_cjs.MEASURE_KIND_NAMES[base[0]] === extended.measure;
99
106
  }
100
107
  function convertUnit(value, from, to) {
101
108
  if (from === to) return value;
@@ -113,24 +120,39 @@ function convertUnit(value, from, to) {
113
120
  const days = from === "day" ? value : convertUnit(value, from, "day");
114
121
  return days / WORKDAY_TO_DAY_FACTOR;
115
122
  }
116
- const fExt = chunk53B6KDDJ_cjs.EXTENDED_UNITS[from];
117
- const tExt = chunk53B6KDDJ_cjs.EXTENDED_UNITS[to];
123
+ const fExt = chunkMBNQVDVC_cjs.EXTENDED_UNITS[from];
124
+ const tExt = chunkMBNQVDVC_cjs.EXTENDED_UNITS[to];
118
125
  if (fExt !== void 0 && tExt !== void 0) {
119
126
  return value * (fExt.toBase / tExt.toBase);
120
127
  }
128
+ if (fExt !== void 0 && bridgesToBaseMeasure(from, to)) {
129
+ return convertRaw(value * fExt.toBase, baseUnitFor(to), to);
130
+ }
131
+ if (tExt !== void 0 && bridgesToBaseMeasure(to, from)) {
132
+ return convertRaw(value, from, baseUnitFor(from)) / tExt.toBase;
133
+ }
121
134
  return convertRaw(value, from, to);
122
135
  }
136
+ function baseUnitFor(unit) {
137
+ const entry = lookupUnit(resolveUnit(unit));
138
+ if (entry === void 0) return unit;
139
+ for (const symbol of Object.keys(chunkMBNQVDVC_cjs.UNIT_TABLE)) {
140
+ const candidate = chunkMBNQVDVC_cjs.UNIT_TABLE[symbol];
141
+ if (candidate[0] === entry[0] && candidate[1] === 1) return symbol;
142
+ }
143
+ return unit;
144
+ }
123
145
  function getConvertiblePossibilities(unit) {
124
146
  const resolved = resolveUnit(unit);
125
147
  const entry = lookupUnit(resolved);
126
148
  if (entry === void 0) return [];
127
- const symbols = chunk53B6KDDJ_cjs.MEASURE_SYMBOLS[entry[0]];
149
+ const symbols = chunkMBNQVDVC_cjs.MEASURE_SYMBOLS[entry[0]];
128
150
  if (!symbols) return [];
129
151
  return symbols.filter((s) => s !== resolved);
130
152
  }
131
153
  function isConvertibleUnit(unit) {
132
154
  if (isWorkdayUnit(unit)) return true;
133
- if (chunk53B6KDDJ_cjs.EXTENDED_UNITS[unit]) return true;
155
+ if (chunkMBNQVDVC_cjs.EXTENDED_UNITS[unit]) return true;
134
156
  return lookupUnit(resolveUnit(unit)) !== void 0;
135
157
  }
136
158
  function getBestUnit(value, unit) {
@@ -151,5 +173,5 @@ exports.getMeasure = getMeasure;
151
173
  exports.isConvertibleUnit = isConvertibleUnit;
152
174
  exports.isWorkdayUnit = isWorkdayUnit;
153
175
  exports.resolveUnit = resolveUnit;
154
- //# sourceMappingURL=chunk-QNJ4ACRT.cjs.map
155
- //# sourceMappingURL=chunk-QNJ4ACRT.cjs.map
176
+ //# sourceMappingURL=chunk-NJTXJ5AG.cjs.map
177
+ //# sourceMappingURL=chunk-NJTXJ5AG.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/uom/UnitConversion.ts","../src/uom/UomConverter.ts"],"names":["UNIT_TABLE","UNIT_DIFFERENCES","BEST_UNITS_METRIC","EXTENDED_UNITS","MEASURE_KIND_NAMES","MEASURE_SYMBOLS"],"mappings":"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","file":"chunk-NJTXJ5AG.cjs","sourcesContent":["/**\n * The unit conversion algorithm, ported from the `convert` npm package v7.0.2\n * alongside its tables (see `generated/UnitTable.generated.ts` and\n * THIRD-PARTY-NOTICES.md).\n *\n * Transliterated expression for expression rather than rewritten. Floating\n * point is not associative, so `(q + d) * (a / b) - d2` and any algebraically\n * equal rearrangement disagree in the last bits. Those bits are observable:\n * `0.5 l` best-converts to `500.00000000000006 mL` today, and the test suite\n * pins several conversions to ten decimal places.\n *\n * This module is deliberately unaware of the engine's own additions. Workdays,\n * extended units, currency and the caches all live in `UomConverter.ts`, which\n * layers them on top of these three functions.\n */\n\nimport {\n UNIT_TABLE,\n UNIT_DIFFERENCES,\n BEST_UNITS_METRIC,\n type UnitEntry,\n} from \"./generated/UnitTable.generated\";\n\n/**\n * The generated tables re-keyed into Maps once at module load.\n *\n * Not a micro-optimization. A 1456-key object literal lands in V8's dictionary\n * mode, and guarding a read on it against inherited names (`constructor`,\n * `toString`) costs about 123ns per call with either `hasOwnProperty.call` or\n * `Object.hasOwn`, measured. `Map.get` is about 6ns and needs no guard at all,\n * because a Map has no prototype chain to fall through to. That is a 20x\n * difference on the single hottest operation in the unit system: `convertRaw`\n * performs two of these per call, and `LanguageService` sweeps all 1456 keys\n * to build completions.\n */\nconst UNIT_LOOKUP: ReadonlyMap<string, UnitEntry> = new Map(Object.entries(UNIT_TABLE));\n\n/**\n * Temperature offsets, as a Map for the same reason.\n *\n * Also removes a latent hazard: the upstream code tests membership with `in`,\n * and `\"toString\" in UNIT_DIFFERENCES` is true, so an inherited name reaching\n * that branch would add a function to a number.\n */\nconst DIFFERENCE_LOOKUP: ReadonlyMap<string, number> = new Map(Object.entries(UNIT_DIFFERENCES));\n\n/**\n * Looks up a unit spelling.\n *\n * @returns its `[kind, ratio]` entry, or `undefined` if the spelling is not a\n * unit. Case-sensitive: no normalization or aliasing happens anywhere in this\n * module.\n *\n * The one deliberate deviation from upstream. `convert` tests membership with\n * `in` and reads the property directly, so inherited names like \"constructor\"\n * and \"toString\" reach its measure comparison and fail there with \"Cannot\n * convert between different measures\" instead of \"is not a valid unit\". Both\n * throw a RangeError and both report no measure, so nothing downstream can\n * tell the difference, and naming the real problem is the better message.\n */\nexport function lookupUnit(unit: string): UnitEntry | undefined {\n return UNIT_LOOKUP.get(unit);\n}\n\n/**\n * Converts `quantity` from one unit to another.\n *\n * THROWS a `RangeError` for an unknown unit or a pair in different measures.\n * Callers depend on that: `VM.ts`'s `extractDurationMs()` calls this with an\n * arbitrary unit inside a bare try/catch and treats the throw as \"not a\n * duration, contribute zero\". Returning NaN or the input unchanged instead\n * would turn `<date> + 5 kg` into an Invalid Date rather than a no-op.\n */\nexport function convertRaw(quantity: number, from: string, to: string): number {\n const parsedFrom = UNIT_LOOKUP.get(from);\n if (parsedFrom === undefined) {\n throw new RangeError(`${from} is not a valid unit`);\n }\n\n const parsedTo = UNIT_LOOKUP.get(to);\n if (parsedTo === undefined) {\n throw new RangeError(`${to} is not a valid unit`);\n }\n\n return convertResolved(quantity, from, to, parsedFrom, parsedTo);\n}\n\n/**\n * The conversion arithmetic, for callers that have already looked both units\n * up and want to skip doing it twice.\n *\n * Split out for `UomConverter.convertUnit()`, which has to check whether\n * either side is a workday or an extended unit before it can dispatch, and\n * would otherwise resolve each unit once to decide and again to convert. The\n * entries MUST be the ones this module returned for these exact spellings.\n */\nexport function convertResolved(\n quantity: number,\n from: string,\n to: string,\n fromEntry: UnitEntry,\n toEntry: UnitEntry\n): number {\n const parsedFrom = fromEntry;\n const parsedTo = toEntry;\n\n if (parsedFrom[0] !== parsedTo[0]) {\n // DELIBERATE DEVIATION from the ported original, which silently reinterpreted\n // \"m\" as minutes whenever the other side was a time unit. That is a guess,\n // and this project's stated position is that refusing to guess is the safer\n // default for a tool doing arithmetic on someone's real numbers (see\n // docs/architecture/design-decisions.md). The guess was not harmless: it\n // reached `<date> + <duration>` through VM.ts's extractDurationMs(), where\n // `today + 5 m` silently added five MINUTES for someone who wrote metres.\n //\n // Minutes are spelled \"min\", \"minute\" or \"minutes\", all of which the table\n // has always accepted.\n throw new RangeError(`Cannot convert between different measures: ${from} and ${to}`);\n }\n\n const fromRatio = parsedFrom[1];\n const toRatio = parsedTo[1];\n\n // Only six units in the whole table carry an offset, so the common path is\n // both misses. Reading the Map once per side and reusing the value beats\n // testing membership and then reading it again.\n const fromDifference = DIFFERENCE_LOOKUP.get(from);\n const toDifference = DIFFERENCE_LOOKUP.get(to);\n\n // Scales that do not share an origin (temperature) need the offset applied\n // around the ratio. Do not refactor the four branches into one expression:\n // the grouping is what makes the result bit-identical to the original.\n if (fromDifference !== undefined) {\n if (toDifference !== undefined) {\n return (quantity + fromDifference) * (fromRatio / toRatio) - toDifference;\n }\n return (quantity + fromDifference) * (fromRatio / toRatio);\n }\n\n if (toDifference !== undefined) {\n return quantity * (fromRatio / toRatio) - toDifference;\n }\n\n return quantity * (fromRatio / toRatio);\n}\n\n/**\n * Picks the most readable metric unit for a magnitude and converts to it.\n *\n * Only the metric lists are ported; nothing has ever requested the imperial\n * ones. Note the final conversion goes from the ORIGINAL unit to the chosen\n * one directly rather than via the smallest unit, which is what keeps the\n * result exact.\n */\nexport function convertToBestMetric(\n quantity: number,\n from: string\n): { quantity: number; unit: string } {\n const parsedFrom = UNIT_LOOKUP.get(from);\n if (parsedFrom === undefined) {\n throw new RangeError(`${from} is not a valid unit`);\n }\n\n const best = BEST_UNITS_METRIC[parsedFrom[0]];\n const smallestUnit = best[0][0];\n let bestUnit = smallestUnit;\n\n const baseQuantity = convertRaw(quantity, from, smallestUnit);\n const absQuantity = baseQuantity < 0 ? -baseQuantity : baseQuantity;\n\n // Thresholds are expressed in the smallest unit and ascend, so the last one\n // the magnitude reaches wins. Breaking early rather than scanning the whole\n // list matters for zero and for negatives, which stay on the smallest unit.\n for (let i = 0; i < best.length; i++) {\n const bestEntry = best[i];\n if (absQuantity >= bestEntry[1]) {\n bestUnit = bestEntry[0];\n } else {\n break;\n }\n }\n\n return { quantity: convertRaw(quantity, from, bestUnit), unit: bestUnit };\n}\n","/**\n * UoM Converter, built on the in-house unit tables in `UnitConversion.ts` and\n * `generated/UnitTable.generated.ts` (ported from the `convert` npm package\n * v7.0.2 so the engine ships with no runtime dependencies).\n *\n * Units are strictly case-sensitive and are looked up without aliasing. No unit\n * remapping, what you type is what you get.\n * e.g. 'C' = Celsius, 'c' = cup; 'MB' = megabytes, 'mb' = millibits.\n *\n * This file owns everything the base tables do not: the workday shim, the\n * extended (custom-measure) units, and the two caches.\n */\n\nimport { lookupUnit, convertRaw, convertResolved, convertToBestMetric } from \"@solve-js/uom/UnitConversion\";\nimport { MEASURE_KIND_NAMES, MEASURE_SYMBOLS, UNIT_TABLE } from \"@solve-js/uom/generated/UnitTable.generated\";\nimport { EXTENDED_UNITS } from \"@solve-js/uom/ExtendedUnits\";\n\n// ── \"workday\", a synthetic unit with no entry in the base table ───────────\n//\n// A business day (Mon-Fri) backing the datetime package's `<date> + N\n// workdays` arithmetic and `$X/workday` Rate literals\n// (packages/datetime/). NOT a real physical unit, a business day has no\n// fixed duration, since it depends on which calendar dates are weekends\n// so the ported base table has no concept of it and can't be\n// taught one without monkey-patching its internal unit table.\n//\n// For RATE-MATH purposes only (e.g. \"$500/workday x 4 weeks\" needs a\n// workday count to multiply by), a workday is treated as a FIXED 7/5 of a\n// calendar day: 5 workdays span exactly 7 calendar days in a whole week,\n// so this ratio is exact for whole-week spans and a reasonable linear\n// approximation otherwise. This is deliberately NOT the same\n// calendar-aware, weekend-skipping logic real \"<date> + N workdays\" date\n// arithmetic needs (see vm/VM.ts's addBusinessDays()), that can't be\n// reduced to a fixed ratio, since the exact skip pattern depends on which\n// day of the week the calculation actually starts from.\n//\n// Handled here as a thin pre/post layer in front of the normal\n// base-table path (rather than inside the tables themselves) so every\n// caller of getMeasure()/convertUnit()/canConvert() automatically gets\n// workday support for free.\nconst WORKDAY_UNIT_NAMES = new Set([\"workday\", \"workdays\"]);\nconst WORKDAY_TO_DAY_FACTOR = 7 / 5; // 1 workday == 1.4 calendar days\n\n/** Whether `unit` is the synthetic \"workday\" unit (see module note above). */\nexport function isWorkdayUnit(unit: string | undefined): unit is string {\n return typeof unit === \"string\" && WORKDAY_UNIT_NAMES.has(unit);\n}\n\n/**\n * Validate `unit` against the known unit table.\n *\n * @returns `unit` unchanged in all cases. This does NOT normalize casing\n * or aliasing (units are strictly case-sensitive, see the module note\n * above). A unit the table doesn't recognize is still\n * returned as-is (not thrown), so callers must not assume a returned\n * string is actually convertible, check with {@link isConvertibleUnit}\n * or {@link canConvert} first if that matters.\n *\n * Kept as an identity function purely for API compatibility. It used to guard\n * a validity cache, which existed because validating a unit meant a\n * throw/catch round trip through the old dependency. Validation is now a Map\n * lookup, so the cache cost more than it saved: worse, it was capped at 1000\n * entries against a 1456-unit table, so any sweep over the full vocabulary\n * (which is exactly what LanguageService does to build completions) evicted\n * on almost every call. That one change took the full-table sweep from 7.7ms\n * to under 20us.\n */\nexport function resolveUnit(unit: string): string {\n return unit;\n}\n\n// MEASURE_KIND_NAMES now comes from the generated table (it is derived data,\n// so the generator emits it rather than it being retyped here). The reason it\n// is a module-level constant has not changed: getMeasure() runs at least twice\n// per conversion, and this used to be reallocated on every call.\n\n/**\n * Get the measure/dimension kind for `unit` (e.g. `\"length\"`, `\"mass\"`,\n * `\"temperature\"`), used to check whether two units are even in the same\n * dimension before attempting a conversion.\n *\n * @returns `undefined` if `unit` isn't recognized, rather than throwing.\n */\nexport function getMeasure(unit: string): string | undefined {\n // Workday is a Time-measure unit by convention (see isWorkdayUnit's doc\n // comment) and is not in the base table, so resolve its measure via \"day\"\n // instead of attempting the real lookup below.\n if (isWorkdayUnit(unit)) return getMeasure(\"day\");\n\n // Extended (custom) categories the base table has no measure kind for,\n // see ExtendedUnits.ts.\n const extended = EXTENDED_UNITS[unit];\n if (extended) return extended.measure;\n\n const entry = lookupUnit(unit);\n if (entry === undefined) return undefined;\n\n return MEASURE_KIND_NAMES[entry[0]];\n}\n\n/**\n * Check whether `from` can be converted to `to`. Same unit, or same\n * measure kind (length, mass, ...) and the underlying tables accept the pair.\n * Never throws; returns `false` on any failure.\n */\nexport function canConvert(from: string, to: string): boolean {\n if (from === to) return true;\n if (isWorkdayUnit(from) || isWorkdayUnit(to)) {\n const fromMeasure = getMeasure(from);\n const toMeasure = getMeasure(to);\n return !!fromMeasure && fromMeasure === toMeasure;\n }\n // One table read per side, comparing numeric kind ids. The old shape called\n // getMeasure() on each side (two more reads) purely to compare the resulting\n // STRINGS, then did a throwaway conversion to confirm what the kind check had\n // already established.\n const fromEntry = lookupUnit(from);\n const toEntry = lookupUnit(to);\n if (fromEntry !== undefined && toEntry !== undefined) {\n return fromEntry[0] === toEntry[0];\n }\n\n // Extended (custom) categories aren't in the base table at all, so they are\n // compared on their own measure names instead.\n const fromExtended = EXTENDED_UNITS[from];\n const toExtended = EXTENDED_UNITS[to];\n if (fromExtended !== undefined && toExtended !== undefined) {\n return fromExtended.measure === toExtended.measure;\n }\n\n // Mixed: one side is in the base table and the other is extended. That used\n // to be refused outright, on the grounds that the two measure spaces are\n // disjoint. They are not, once an extended unit names a measure the base\n // table also has: `furlong` is a length and so is `m`, and the ratio between\n // them is exactly what both tables already record.\n return bridgesToBaseMeasure(from, to) || bridgesToBaseMeasure(to, from);\n}\n\n/**\n * Whether `extendedUnit` extends a measure the base table also knows, so a\n * value in it can reach `baseUnit`.\n *\n * The bridge works because both tables express a unit as a ratio to the same\n * physical base: the generated table's length ratios are metres and its mass\n * ratios are grams, and an extended unit declaring `measure: \"length\"` states\n * its `toBase` in the same metres. Composing the two ratios is then ordinary\n * arithmetic rather than a second conversion system.\n *\n * A measure the base table has no concept of, such as pace, still fails here,\n * which is the behaviour this replaced and the reason the check is by measure\n * name rather than by presence in the extended table.\n */\nfunction bridgesToBaseMeasure(extendedUnit: string, baseUnit: string): boolean {\n const extended = EXTENDED_UNITS[extendedUnit];\n if (extended === undefined) return false;\n\n const base = lookupUnit(resolveUnit(baseUnit));\n if (base === undefined) return false;\n\n return MEASURE_KIND_NAMES[base[0]] === extended.measure;\n}\n\n/**\n * Convert `value` from unit `from` to unit `to`.\n *\n * Does not validate that the conversion is possible, callers should check\n * with {@link canConvert} first if `from`/`to` aren't already known-good.\n *\n * THROWS a RangeError for an unknown unit or a cross-measure pair. `VM.ts`'s\n * `extractDurationMs()` depends on that, see {@link convertRaw}.\n *\n * This used to memoize a per-pair conversion factor in an LFU cache. The cache\n * is gone: computing the factor is now two Map reads, while the cache cost a\n * template-string key allocation on every call plus the LFU's own frequency\n * bookkeeping, so it was slower than the work it avoided. Removing it is\n * bit-exact, not merely close: the cache stored `convertRaw(1, f, t)`, which is\n * exactly `fromRatio / toRatio`, and then multiplied, which is the identical\n * expression `convertRaw(value, f, t)` evaluates. It also deleted the special\n * case that existed only to keep offset-based temperature pairs out of a\n * factor cache.\n */\nexport function convertUnit(value: number, from: string, to: string): number {\n if (from === to) return value;\n\n // Fast path first: two ordinary units, which is nearly every call. Resolving\n // both here and handing the entries to convertResolved() avoids looking them\n // up again inside convertRaw(). Neither workdays nor extended units appear in\n // the base table, so they always fall through to the branches below and this\n // ordering cannot steal a case from them. UnitVocabulary.spec.ts pins that\n // the two vocabularies stay disjoint.\n const fromEntry = lookupUnit(from);\n const toEntry = lookupUnit(to);\n if (fromEntry !== undefined && toEntry !== undefined) {\n return convertResolved(value, from, to, fromEntry, toEntry);\n }\n\n // Workday <-> any other Time-measure unit: pivot through \"day\" using the\n // fixed 7/5 ratio (see isWorkdayUnit's doc comment above).\n if (isWorkdayUnit(from) && isWorkdayUnit(to)) return value; // \"workday\" <-> \"workdays\" alias\n if (isWorkdayUnit(from)) {\n const days = value * WORKDAY_TO_DAY_FACTOR;\n return to === \"day\" ? days : convertUnit(days, \"day\", to);\n }\n if (isWorkdayUnit(to)) {\n const days = from === \"day\" ? value : convertUnit(value, from, \"day\");\n return days / WORKDAY_TO_DAY_FACTOR;\n }\n\n // Extended (custom) categories the base table has no measure kind for\n // (see ExtendedUnits.ts), compute the ratio directly from each unit's\n // factor-to-base value instead of calling convertRaw(), which would throw\n // on an unrecognized unit string. Every extended category is a pure linear\n // ratio scale (no Temperature-style offset), so this is always safe.\n const fExt = EXTENDED_UNITS[from];\n const tExt = EXTENDED_UNITS[to];\n if (fExt !== undefined && tExt !== undefined) {\n return value * (fExt.toBase / tExt.toBase);\n }\n\n // One side extended, the other in the base table, sharing a measure. Convert\n // through the measure's base unit, which both tables state their ratios\n // against: an extended length declares its `toBase` in metres, and the\n // generated table's length ratios are metres too.\n if (fExt !== undefined && bridgesToBaseMeasure(from, to)) {\n return convertRaw(value * fExt.toBase, baseUnitFor(to), to);\n }\n if (tExt !== undefined && bridgesToBaseMeasure(to, from)) {\n return convertRaw(value, from, baseUnitFor(from)) / tExt.toBase;\n }\n\n // Offsets, cross-measure rejection and the unknown-unit throw all live in\n // convertRaw. Nothing is layered on top here any more.\n return convertRaw(value, from, to);\n}\n\n/**\n * The unit a measure states its ratios against, found from any unit in it.\n *\n * Read out of the table rather than hard-coded, so it cannot drift from the\n * ratios it has to agree with: the base is whichever unit of that measure has\n * a ratio of exactly one.\n */\nfunction baseUnitFor(unit: string): string {\n const entry = lookupUnit(resolveUnit(unit));\n if (entry === undefined) return unit;\n\n for (const symbol of Object.keys(UNIT_TABLE)) {\n const candidate = UNIT_TABLE[symbol];\n if (candidate[0] === entry[0] && candidate[1] === 1) return symbol;\n }\n return unit;\n}\n\n/**\n * List every unit symbol in the same measure/dimension as `unit` (wiki:\n * Units-Of-Measurement, \"Conversion Possibilities\", `sourceUnit to ?`\n * e.g. `cm to ?\"` → every Length unit). Excludes `unit` itself.\n *\n * Reads MEASURE_SYMBOLS, which is a curated symbols-only vocabulary and\n * deliberately NOT the keys of the unit table filtered by kind. The two\n * differ: Volume's symbols include `c` and `pt` but not `cup`/`cups`, and\n * Time's include `wk` and `mo` but not `week`/`month`. Deriving this list\n * from the unit table instead would roughly quadruple every answer.\n *\n * @returns `[]` if `unit` isn't recognized, rather than throwing.\n */\nexport function getConvertiblePossibilities(unit: string): string[] {\n const resolved = resolveUnit(unit);\n const entry = lookupUnit(resolved);\n if (entry === undefined) return [];\n const symbols = MEASURE_SYMBOLS[entry[0]];\n if (!symbols) return [];\n return symbols.filter((s) => s !== resolved);\n}\n\n/** Check whether `unit` is a unit the conversion tables recognize. Never throws. */\nexport function isConvertibleUnit(unit: string): boolean {\n if (isWorkdayUnit(unit)) return true;\n if (EXTENDED_UNITS[unit]) return true;\n return lookupUnit(resolveUnit(unit)) !== undefined;\n}\n\n/**\n * Convert `value` (in `unit`) to whichever unit of the same measure gives\n * the most human-readable magnitude, e.g. 1500 metres becomes 1.5 km. Falls\n * back to returning `value`/`unit` unchanged if `unit` isn't recognized,\n * which is what every extended unit and workday does.\n *\n * Note the chosen unit is drawn from the best-unit lists, which are not\n * restricted to spellings the lexer accepts: 0.5 l reports \"mL\".\n */\nexport function getBestUnit(value: number, unit: string): { value: number; unit: string } {\n const u = resolveUnit(unit);\n try {\n const result = convertToBestMetric(value, u);\n return { value: result.quantity, unit: result.unit };\n } catch {\n return { value, unit: u };\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkGW32KPCU_cjs = require('./chunk-GW32KPCU.cjs');
3
+ var chunkR24DI24X_cjs = require('./chunk-R24DI24X.cjs');
4
4
  var chunkM4N5GA5Z_cjs = require('./chunk-M4N5GA5Z.cjs');
5
5
 
6
6
  // src/parser/BytecodeBuilder.ts
@@ -209,6 +209,12 @@ var BindingPower = {
209
209
  // `&&` — binds tighter than `or` ("a or b and c" = "a or (b and c)")
210
210
  Conditional: 20,
211
211
  // comparisons (`==`, `<`, `>=`, ...) — tighter than and/or, looser than arithmetic
212
+ // The word "and" as addition (`AND_CONJ`). One step looser than `Sum` on
213
+ // purpose: a phrase parselet collecting a list ("average of X, Y and Z")
214
+ // parses each argument at this level, which stops at "and" while still
215
+ // letting a genuine "+" inside an argument bind. Level 28 rather than 29 to
216
+ // leave room, and below Sum rather than above so "1 and 2 * 3" stays 7.
217
+ Conjunction: 28,
212
218
  Sum: 30,
213
219
  BitwiseXor: 35,
214
220
  Product: 40,
@@ -219,39 +225,39 @@ var BindingPower = {
219
225
  };
220
226
  var BUILTIN_INFIX_BP = {
221
227
  // Arithmetic (infix, left-associative)
222
- [chunkGW32KPCU_cjs.TokenTypes.PLUS]: BindingPower.Sum,
223
- [chunkGW32KPCU_cjs.TokenTypes.MINUS]: BindingPower.Sum,
224
- [chunkGW32KPCU_cjs.TokenTypes.STAR]: BindingPower.Product,
225
- [chunkGW32KPCU_cjs.TokenTypes.SLASH]: BindingPower.Product,
226
- [chunkGW32KPCU_cjs.TokenTypes.MOD]: BindingPower.Product,
228
+ [chunkR24DI24X_cjs.TokenTypes.PLUS]: BindingPower.Sum,
229
+ [chunkR24DI24X_cjs.TokenTypes.MINUS]: BindingPower.Sum,
230
+ [chunkR24DI24X_cjs.TokenTypes.STAR]: BindingPower.Product,
231
+ [chunkR24DI24X_cjs.TokenTypes.SLASH]: BindingPower.Product,
232
+ [chunkR24DI24X_cjs.TokenTypes.MOD]: BindingPower.Product,
227
233
  // Arithmetic (infix, RIGHT-associative, PrecedenceParser handles this specially)
228
- [chunkGW32KPCU_cjs.TokenTypes.CARET]: BindingPower.Exponent,
234
+ [chunkR24DI24X_cjs.TokenTypes.CARET]: BindingPower.Exponent,
229
235
  // Bitwise (infix, left-associative)
230
- [chunkGW32KPCU_cjs.TokenTypes.LSHIFT]: BindingPower.BitwiseXor,
231
- [chunkGW32KPCU_cjs.TokenTypes.RSHIFT]: BindingPower.BitwiseXor,
232
- [chunkGW32KPCU_cjs.TokenTypes.BIT_AND]: BindingPower.BitwiseXor,
233
- [chunkGW32KPCU_cjs.TokenTypes.BIT_OR]: BindingPower.BitwiseXor,
234
- [chunkGW32KPCU_cjs.TokenTypes.BIT_XOR]: BindingPower.BitwiseXor,
236
+ [chunkR24DI24X_cjs.TokenTypes.LSHIFT]: BindingPower.BitwiseXor,
237
+ [chunkR24DI24X_cjs.TokenTypes.RSHIFT]: BindingPower.BitwiseXor,
238
+ [chunkR24DI24X_cjs.TokenTypes.BIT_AND]: BindingPower.BitwiseXor,
239
+ [chunkR24DI24X_cjs.TokenTypes.BIT_OR]: BindingPower.BitwiseXor,
240
+ [chunkR24DI24X_cjs.TokenTypes.BIT_XOR]: BindingPower.BitwiseXor,
235
241
  // Postfix (no right operand, PrecedenceParser handles this specially)
236
- [chunkGW32KPCU_cjs.TokenTypes.PERCENT]: BindingPower.Postfix,
242
+ [chunkR24DI24X_cjs.TokenTypes.PERCENT]: BindingPower.Postfix,
237
243
  // Percentage keyword (infix, left-associative: "50% of 200" → MUL)
238
- [chunkGW32KPCU_cjs.TokenTypes.OF]: BindingPower.Product
244
+ [chunkR24DI24X_cjs.TokenTypes.OF]: BindingPower.Product
239
245
  };
240
246
  var _bpTable = null;
241
247
  function buildBindingPowerTable() {
242
248
  if (_bpTable) return _bpTable;
243
249
  let maxId = 0;
244
250
  for (const name of Object.keys(BUILTIN_INFIX_BP)) {
245
- const id = chunkGW32KPCU_cjs.tokenTypeId(name);
251
+ const id = chunkR24DI24X_cjs.tokenTypeId(name);
246
252
  if (id > maxId) maxId = id;
247
253
  }
248
- for (const name of Object.values(chunkGW32KPCU_cjs.TokenTypes)) {
249
- const id = chunkGW32KPCU_cjs.tokenTypeId(name);
254
+ for (const name of Object.values(chunkR24DI24X_cjs.TokenTypes)) {
255
+ const id = chunkR24DI24X_cjs.tokenTypeId(name);
250
256
  if (id > maxId) maxId = id;
251
257
  }
252
258
  const table = new Uint8Array(maxId + 1);
253
259
  for (const [name, bp] of Object.entries(BUILTIN_INFIX_BP)) {
254
- const id = chunkGW32KPCU_cjs.tokenTypeId(name);
260
+ const id = chunkR24DI24X_cjs.tokenTypeId(name);
255
261
  table[id] = bp;
256
262
  }
257
263
  _bpTable = table;
@@ -265,5 +271,5 @@ exports.BindingPower = BindingPower;
265
271
  exports.BytecodeBuilder = BytecodeBuilder;
266
272
  exports.buildBindingPowerTable = buildBindingPowerTable;
267
273
  exports.invalidateBindingPowerTable = invalidateBindingPowerTable;
268
- //# sourceMappingURL=chunk-C4XZV6E7.cjs.map
269
- //# sourceMappingURL=chunk-C4XZV6E7.cjs.map
274
+ //# sourceMappingURL=chunk-NZFKROS7.cjs.map
275
+ //# sourceMappingURL=chunk-NZFKROS7.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/parser/BytecodeBuilder.ts","../src/parser/BindingPower.ts"],"names":["ErrorFactory","TokenTypes","tokenTypeId"],"mappings":"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","file":"chunk-NZFKROS7.cjs","sourcesContent":["import { OpCode } from \"@solve-js/parser/OpCode\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\n\n/**\n * `BytecodeProgram.opcodes` is a `Uint8Array`, every operand written into\n * it (including constant-pool indices from {@link BytecodeBuilder.emitNumber}/\n * {@link BytecodeBuilder.emitString}) is truncated to a single byte on\n * `build()`. Exceeding this silently wraps the index (e.g. entry 300 reads\n * back as entry 44), producing a wrong result with no error. See\n * {@link BytecodeBuilder.emitNumber} for the guard that turns this into a\n * thrown error instead.\n */\nconst MAX_CONSTANT_POOL_INDEX = 255;\n\n/**\n * Compiled bytecode program produced by {@link BytecodeBuilder}.\n * Ready for consumption by {@link executeBytecode} without further processing.\n */\nexport interface BytecodeProgram {\n\topcodes: Uint8Array;\n\tnumbers: Float64Array;\n\tstrings: string[];\n\tconstants?: Map<number, number>;\n\t/**\n\t * Whether the program contains any async opcodes (CALL_PLUGIN, etc.).\n\t * Set during compilation by the BytecodeBuilder. Allows the engine\n\t * to skip the O(n) resolver preflight check in O(1) for purely\n\t * synchronous expressions like `2 + 2`.\n\t */\n\thasAsync: boolean;\n\t/**\n\t * User-defined-function bodies compiled alongside this program (one\n\t * entry per `name(params) = body` definition on this line). See\n\t * {@link BytecodeBuilder.emitUserFunctionBody}. `OpCode.DEFINE_USER_FUNCTION`'s\n\t * operand is an index into this array, resolved at VM-execution time\n\t * (not parse time) so a diagnostic/lookahead parse that never actually\n\t * executes the definition line has no side effect on `vm.userFunctions`.\n\t */\n\tuserFunctionBodies?: UserFunctionDef[];\n\t/**\n\t * Anonymous function bodies compiled alongside this program, one entry\n\t * per `map`/`reduce` inline transform expression (e.g. the `10*x` in\n\t * `map(10*x, [0,1,500])`). See {@link BytecodeBuilder.emitAnonymousBody}.\n\t * Deliberately a SEPARATE side-table from `userFunctionBodies`, not\n\t * routed through `vm.userFunctions` at all: an inline body has no name\n\t * and must never leak into the persistent name-keyed registry the way\n\t * a real `f(x) = ...` definition does.\n\t */\n\tanonymousBodies?: AnonymousBodyDef[];\n}\n\n/**\n * An anonymous transform body for `map`/`reduce`'s inline-expression form\n * (e.g. `10*x` in `map(10*x, [0,1,500])`, or `acc+x` in `reduce(acc+x,\n * [1,2,3])`). Structurally identical to {@link UserFunctionDef} minus the\n * `name`. See `OpCode.MAP_INVOKE`/`REDUCE_INVOKE` and\n * `vm/VM.ts`'s handlers, which build a call frame from `params`/`args`\n * exactly like `CALL_USER_FUNCTION` does, just without ever registering\n * the body in `vm.userFunctions`.\n */\nexport interface AnonymousBodyDef {\n\tparams: string[];\n\tprogram: BytecodeProgram;\n}\n\n/**\n * A user-defined, parameterized, reusable function's compiled form\n * (`f(x) = 2*x + 1`). See `OpCode.DEFINE_USER_FUNCTION`/`CALL_USER_FUNCTION`\n * and `vm/VM.ts`'s `VM.defineUserFunction`/`getUserFunction`.\n *\n * `program` is the body compiled to its OWN independent `BytecodeProgram`,\n * not a fragment of the definition line's own bytecode. Parameter names\n * inside the body compile to ORDINARY `LOAD_VAR <name>` opcodes, no\n * parse-time rewriting, because parameter resolution happens dynamically\n * at the VM level: `CALL_USER_FUNCTION` pushes a name-keyed call frame\n * (`Map<string, Value>`) before re-executing `program`, and `VM.getVar()`\n * checks the innermost call frame before falling back to the flat\n * document-variable store. This is why a `UNIT`-collision parameter name\n * (e.g. `h` in `area(w, h) = w * h`, which lexes as the \"hour\" unit) needs\n * no special handling anywhere, it's just another `LOAD_VAR \"h\"`, resolved\n * the same way as any other name.\n */\nexport interface UserFunctionDef {\n\tname: string;\n\tparams: string[];\n\tprogram: BytecodeProgram;\n}\n\n/**\n * Direct-to-bytecode compiler for the Pratt parser.\n *\n * Accumulates opcodes, numeric constants, and string references during parsing,\n * then produces a {@link BytecodeProgram} for VM execution. Supports:\n * - Standard build via {@link build}\n * - Zero-copy build into pre-allocated buffers via {@link buildInto}\n * - In-place reset for reuse without reallocation\n */\nexport class BytecodeBuilder {\n\tprivate opcodes: number[] = [];\n\tprivate numbers: number[] = [];\n\tprivate strings: string[] = [];\n\tprivate stringIndex = new Map<string, number>();\n\tprivate _hasAsync = false;\n\tprivate userFunctionBodies: UserFunctionDef[] = [];\n\tprivate anonymousBodies: AnonymousBodyDef[] = [];\n\n\t/** Emit an {@link OpCode} instruction. */\n\temitOpcode(op: OpCode): void {\n\t\tthis.opcodes.push(op);\n\t\tif (op === OpCode.CALL_PLUGIN) {\n\t\t\tthis._hasAsync = true;\n\t\t}\n\t}\n\n\t/**\n\t * Emit a numeric literal: appends `n` to the program's constant pool and\n\t * writes its index into the opcode stream (read back by the VM as e.g.\n\t * `PUSH_NUMBER <idx>`).\n\t *\n\t * Numeric constants are NOT deduplicated (unlike {@link emitString})\n\t * every call appends a new entry, so an expression with more than\n\t * {@link MAX_CONSTANT_POOL_INDEX}+1 distinct numeric-literal occurrences\n\t * throws rather than silently wrapping the index (see\n\t * `MAX_CONSTANT_POOL_INDEX`'s doc for what that would otherwise do).\n\t *\n\t * @throws If the constant pool would exceed 256 entries.\n\t */\n\temitNumber(n: number): void {\n\t\tconst idx = this.numbers.length;\n\t\tif (idx > MAX_CONSTANT_POOL_INDEX) {\n\t\t\tthrow ErrorFactory.parsing(\n\t\t\t\t\"TOO_MANY_NUMERIC_CONSTANTS\",\n\t\t\t\t`Expression has more than ${MAX_CONSTANT_POOL_INDEX + 1} numeric literals, exceeding the bytecode constant pool's limit.`,\n\t\t\t\t{ limit: MAX_CONSTANT_POOL_INDEX + 1 }\n\t\t\t);\n\t\t}\n\t\tthis.numbers.push(n);\n\t\tthis.opcodes.push(idx);\n\t}\n\n\t/**\n\t * Emit a string literal: interns `s` into the program's string pool\n\t * (deduplicated via `stringIndex`) and writes its index into the opcode\n\t * stream. Subject to the same constant-pool bound as {@link emitNumber},\n\t * but since strings ARE deduplicated, only distinct string values count\n\t * against the limit.\n\t *\n\t * @throws If the string pool would exceed 256 distinct entries.\n\t */\n\temitString(s: string): void {\n\t\tlet idx = this.stringIndex.get(s);\n\t\tif (idx === undefined) {\n\t\t\tidx = this.strings.length;\n\t\t\tif (idx > MAX_CONSTANT_POOL_INDEX) {\n\t\t\t\tthrow ErrorFactory.parsing(\n\t\t\t\t\t\"TOO_MANY_STRING_CONSTANTS\",\n\t\t\t\t\t`Expression has more than ${MAX_CONSTANT_POOL_INDEX + 1} distinct string literals, exceeding the bytecode constant pool's limit.`,\n\t\t\t\t\t{ limit: MAX_CONSTANT_POOL_INDEX + 1 }\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.strings.push(s);\n\t\t\tthis.stringIndex.set(s, idx);\n\t\t}\n\t\tthis.opcodes.push(idx);\n\t}\n\n\t/**\n\t * Emit a raw numeric operand (0-255) following an opcode, e.g. a\n\t * plugin-function index for `CALL_PLUGIN`, or an argument count. Unlike\n\t * {@link emitOpcode}, this does not go through the `OpCode` enum, so\n\t * package authors use this (not an unsafe cast to `OpCode`) to push\n\t * operands their own opcode handler expects to read positionally.\n\t */\n\temitIndex(idx: number): void {\n\t\tthis.opcodes.push(idx);\n\t}\n\n\t/** Emit a raw byte (0-255), used for fixed small operands like argument counts. */\n\temitByte(b: number): void {\n\t\tthis.opcodes.push(b);\n\t}\n\n\t/** Number of opcodes/operands emitted so far, used to compute jump targets before {@link patchJump}. */\n\tget currentLength(): number {\n\t\treturn this.opcodes.length;\n\t}\n\n\t/**\n\t * Register a compiled user-defined-function body, returning its index\n\t * into this program's `userFunctionBodies` side-table, the caller emits\n\t * that index as `DEFINE_USER_FUNCTION`'s operand via {@link emitIndex}.\n\t * Subject to the same {@link MAX_CONSTANT_POOL_INDEX} bound as\n\t * {@link emitNumber}/{@link emitString} (the index itself is a single\n\t * opcode-stream byte), in practice a single line defines at most a\n\t * handful of functions, so this limit is never realistically reached.\n\t *\n\t * @throws If more than 256 function bodies are registered on one program.\n\t */\n\temitUserFunctionBody(name: string, params: string[], program: BytecodeProgram): number {\n\t\tconst idx = this.userFunctionBodies.length;\n\t\tif (idx > MAX_CONSTANT_POOL_INDEX) {\n\t\t\tthrow ErrorFactory.parsing(\n\t\t\t\t\"TOO_MANY_FUNCTION_DEFINITIONS\",\n\t\t\t\t`More than ${MAX_CONSTANT_POOL_INDEX + 1} function definitions on one line, exceeding the bytecode constant pool's limit.`,\n\t\t\t\t{ limit: MAX_CONSTANT_POOL_INDEX + 1 }\n\t\t\t);\n\t\t}\n\t\tthis.userFunctionBodies.push({ name, params, program });\n\t\treturn idx;\n\t}\n\n\t/**\n\t * Register a compiled `map`/`reduce` anonymous transform body, returning\n\t * its index into this program's `anonymousBodies` side-table, the\n\t * caller emits that index as `MAP_INVOKE`/`REDUCE_INVOKE`'s operand via\n\t * {@link emitIndex}. Same {@link MAX_CONSTANT_POOL_INDEX} bound as\n\t * {@link emitUserFunctionBody}.\n\t *\n\t * @throws If more than 256 anonymous bodies are registered on one program.\n\t */\n\temitAnonymousBody(params: string[], program: BytecodeProgram): number {\n\t\tconst idx = this.anonymousBodies.length;\n\t\tif (idx > MAX_CONSTANT_POOL_INDEX) {\n\t\t\tthrow ErrorFactory.parsing(\n\t\t\t\t\"TOO_MANY_ANONYMOUS_BODIES\",\n\t\t\t\t`More than ${MAX_CONSTANT_POOL_INDEX + 1} map/reduce transform expressions on one line, exceeding the bytecode constant pool's limit.`,\n\t\t\t\t{ limit: MAX_CONSTANT_POOL_INDEX + 1 }\n\t\t\t);\n\t\t}\n\t\tthis.anonymousBodies.push({ params, program });\n\t\treturn idx;\n\t}\n\n\t/** Overwrite a previously-emitted placeholder operand at `position` with the real jump `target`, once known. */\n\tpatchJump(position: number, target: number): void {\n\t\tthis.opcodes[position] = target;\n\t}\n\n\t/**\n\t * Build the accumulated opcodes/numbers/strings into a BytecodeProgram.\n\t * Creates new TypedArrays, the builder can be reused after this call.\n\t */\n\tbuild(): BytecodeProgram {\n\t\treturn {\n\t\t\topcodes: new Uint8Array(this.opcodes),\n\t\t\tnumbers: new Float64Array(this.numbers),\n\t\t\t// Defensive copy: .length = 0 in reset() would clear a shared reference.\n\t\t\t// Strings are rare (only UoM/datetime parselets emit them), so the copy\n\t\t\t// cost is negligible.\n\t\t\tstrings: [...this.strings],\n\t\t\tconstants: new Map(),\n\t\t\thasAsync: this._hasAsync,\n\t\t\tuserFunctionBodies: this.userFunctionBodies.length > 0 ? [...this.userFunctionBodies] : undefined,\n\t\t\tanonymousBodies: this.anonymousBodies.length > 0 ? [...this.anonymousBodies] : undefined,\n\t\t};\n\t}\n\n\t/**\n\t * Build directly into a pre-allocated buffer for zero-copy VM consumption.\n\t *\n\t * When `buf` is provided and large enough, writes into it and returns\n\t * subarray **views** (not copies), the returned TypedArrays share the\n\t * buffer's underlying ArrayBuffer. The caller MUST NOT mutate the buffer\n\t * until the returned BytecodeProgram is no longer needed.\n\t *\n\t * If the caller intends to cache the result, they must copy the TypedArrays\n\t * (e.g. `new Uint8Array(program.opcodes)`) before reusing the buffer pool.\n\t *\n\t * When `buf` is omitted or too small, allocates fresh TypedArrays.\n\t */\n\tbuildInto(buf?: { opcodes: Uint8Array; numbers: Float64Array }): BytecodeProgram {\n\t\tconst opLen = this.opcodes.length;\n\t\tconst numLen = this.numbers.length;\n\n\t\tconst reuseOpcodes = buf && buf.opcodes.length >= opLen;\n\t\tconst reuseNumbers = buf && buf.numbers.length >= numLen;\n\n\t\t// Subarray views that share the buffer's ArrayBuffer (zero-copy)\n\t\tconst opcodes = reuseOpcodes\n\t\t\t? new Uint8Array(buf!.opcodes.buffer, buf!.opcodes.byteOffset, opLen)\n\t\t\t: new Uint8Array(opLen);\n\t\tconst numbers = reuseNumbers\n\t\t\t? new Float64Array(buf!.numbers.buffer, buf!.numbers.byteOffset, numLen)\n\t\t\t: new Float64Array(numLen);\n\n\t\t// Write data into the views\n\t\tfor (let i = 0; i < opLen; i++) opcodes[i] = this.opcodes[i];\n\t\tfor (let i = 0; i < numLen; i++) numbers[i] = this.numbers[i];\n\n\t\treturn {\n\t\t\topcodes,\n\t\t\tnumbers,\n\t\t\tstrings: [...this.strings],\n\t\t\tconstants: new Map(),\n\t\t\thasAsync: this._hasAsync,\n\t\t\tuserFunctionBodies: this.userFunctionBodies.length > 0 ? [...this.userFunctionBodies] : undefined,\n\t\t\tanonymousBodies: this.anonymousBodies.length > 0 ? [...this.anonymousBodies] : undefined,\n\t\t};\n\t}\n\n\treset(): void {\n\t\t// Retain backing stores with .length = 0 to avoid reallocation on growth.\n\t\t// = [] discards the ArrayBuffer, forcing V8 to reallocate on every push()\n\t\t// threshold (4→8→16→32...). For a 50-opcode expression, that's 3-4 copies.\n\t\tthis.opcodes.length = 0;\n\t\tthis.numbers.length = 0;\n\t\tthis.strings.length = 0;\n\t\tthis.stringIndex.clear();\n\t\tthis._hasAsync = false;\n\t\tthis.userFunctionBodies.length = 0;\n\t\tthis.anonymousBodies.length = 0;\n\t}\n}\n","/**\n * Named precedence levels for the Pratt parser, from loosest (`Lowest`) to\n * tightest (`Call`) binding. A custom infix parselet compares its own\n * binding power against the current expression's to decide whether to\n * consume the next operator (higher power binds tighter, e.g. `*` over `+`).\n *\n * Package authors reference these when registering an infix parselet via\n * `IPackageRegistry.registerInfixParselet`. See the built-in packages for\n * examples of picking an appropriate level (e.g. arithmetic `+`/`-` use\n * `Sum`, `*`/`/` use `Product`).\n */\nexport const BindingPower = {\n Lowest: 0,\n Assignment: 10,\n LogicalOr: 12, // `or`, `||` — loosest of the boolean-logic operators\n LogicalAnd: 14, // `&&` — binds tighter than `or` (\"a or b and c\" = \"a or (b and c)\")\n Conditional: 20, // comparisons (`==`, `<`, `>=`, ...) — tighter than and/or, looser than arithmetic\n // The word \"and\" as addition (`AND_CONJ`). One step looser than `Sum` on\n // purpose: a phrase parselet collecting a list (\"average of X, Y and Z\")\n // parses each argument at this level, which stops at \"and\" while still\n // letting a genuine \"+\" inside an argument bind. Level 28 rather than 29 to\n // leave room, and below Sum rather than above so \"1 and 2 * 3\" stays 7.\n Conjunction: 28,\n Sum: 30,\n BitwiseXor: 35,\n Product: 40,\n Exponent: 50,\n Prefix: 60,\n Postfix: 70,\n Call: 80,\n} as const;\n\n/**\n * Set the binding power of a named operator.\n *\n * Binding power is what decides precedence in the Pratt parser: a higher number\n * binds tighter, so `*` outranks `+`. Changing one changes how every existing\n * expression using that operator parses, which is why packages should allocate\n * a new name rather than adjust a built-in.\n *\n * @param name - Operator name.\n * @param power - Higher binds tighter.\n */\nexport function setBindingPower(name: string, power: number): void {\n (BindingPower as Record<string, number>)[name] = power;\n}\n\n/**\n * Read the binding power of a named operator.\n *\n * @param name - Operator name.\n * @returns Its binding power, or 0 when the name is unknown, which makes an\n * unregistered operator terminate an expression rather than swallow the rest\n * of it.\n */\nexport function getBindingPower(name: string): number {\n return (BindingPower as Record<string, number>)[name] ?? 0;\n}\n\n// ── Built-in Infix Operator Binding Power Table ──────────────────────────────\n// Pre-computed Uint8Array lookup indexed by token typeId.\n// value > 0 → built-in infix operator with that binding power\n// value = 0 → not a built-in infix, fall through to Tier 2 parselet registry\n//\n// Built at module load via buildBindingPowerTable(). The table is sparse\n// most entries are 0 since only ~15 of 80+ token types are infix operators.\n//\n// Performance: Uint8Array[typeId] is a single typed array load, no Map.get()\n// no string hashing, no property chain. V8 eliminates bounds checks when typeId\n// is known to be within array length.\n\nimport { TokenTypes } from \"@solve-js/lexer/Token\";\nimport { tokenTypeId } from \"@solve-js/lexer/Token\";\n\n/**\n * Mapping of token type names → binding powers for built-in infix operators.\n * Only operators listed here get the Tier 1 fast path in PrecedenceParser.\n * All other infix tokens use the Tier 2 parselet registry fallback.\n */\nconst BUILTIN_INFIX_BP: Record<string, number> = {\n // Arithmetic (infix, left-associative)\n [TokenTypes.PLUS]: BindingPower.Sum,\n [TokenTypes.MINUS]: BindingPower.Sum,\n [TokenTypes.STAR]: BindingPower.Product,\n [TokenTypes.SLASH]: BindingPower.Product,\n [TokenTypes.MOD]: BindingPower.Product,\n\n // Arithmetic (infix, RIGHT-associative, PrecedenceParser handles this specially)\n [TokenTypes.CARET]: BindingPower.Exponent,\n\n // Bitwise (infix, left-associative)\n [TokenTypes.LSHIFT]: BindingPower.BitwiseXor,\n [TokenTypes.RSHIFT]: BindingPower.BitwiseXor,\n [TokenTypes.BIT_AND]: BindingPower.BitwiseXor,\n [TokenTypes.BIT_OR]: BindingPower.BitwiseXor,\n [TokenTypes.BIT_XOR]: BindingPower.BitwiseXor,\n\n // Postfix (no right operand, PrecedenceParser handles this specially)\n [TokenTypes.PERCENT]: BindingPower.Postfix,\n\n // Percentage keyword (infix, left-associative: \"50% of 200\" → MUL)\n [TokenTypes.OF]: BindingPower.Product,\n};\n\n// Note: These token types are intentionally NOT in the BP_TABLE, they stay in\n// the Tier 2 parselet registry because they require complex handling:\n// IN, TO → UoM conversion parselets (peek at target unit token, complex logic)\n// DOT → Property access (chained OBJ_GET, needs left-token tracking)\n// EQUALS → Assignment (VariableParselet handles :var = expr pattern)\n// EQUALITY, NEQ, GTE, LTE → Comparison ops (need dedicated VM opcodes, task 2.15a)\n// COMMA → Argument separator (function calls, array/object literals)\n\n/** Cached BP_TABLE, built once at module load, immutable thereafter. */\nlet _bpTable: Uint8Array | null = null;\n\n/**\n * Build the Uint8Array binding power table indexed by token typeId.\n * Idempotent, returns cached table on subsequent calls.\n *\n * Must be called after all token types are registered (via registerAllTokenTypes())\n * and after plugin providers have registered their token types.\n */\nexport function buildBindingPowerTable(): Uint8Array {\n if (_bpTable) return _bpTable;\n\n // Size to the largest registered typeId + 1\n let maxId = 0;\n for (const name of Object.keys(BUILTIN_INFIX_BP)) {\n const id = tokenTypeId(name);\n if (id > maxId) maxId = id;\n }\n // Also scan all TokenTypes to ensure table covers all registered IDs\n for (const name of Object.values(TokenTypes)) {\n const id = tokenTypeId(name);\n if (id > maxId) maxId = id;\n }\n\n const table = new Uint8Array(maxId + 1);\n for (const [name, bp] of Object.entries(BUILTIN_INFIX_BP)) {\n const id = tokenTypeId(name);\n table[id] = bp;\n }\n\n _bpTable = table;\n return table;\n}\n\n/**\n * Invalidate the cached BP table, call when plugins register new token types\n * that should participate in the built-in fast path.\n */\nexport function invalidateBindingPowerTable(): void {\n _bpTable = null;\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { LexerToken } from './chunk-XVWCOTR6.js';
2
- import { tokenTypeId } from './chunk-RIN643A3.js';
1
+ import { LexerToken } from './chunk-SFQWJMKT.js';
2
+ import { tokenTypeId } from './chunk-GPPLSM2Z.js';
3
3
  import { ErrorFactory } from './chunk-6RDSQURE.js';
4
4
 
5
5
  // src/normalizer/TokenNormalizer.ts
@@ -11,7 +11,8 @@ var DEFAULT_OPTIONS = {
11
11
  };
12
12
  function createFusedToken(type, text, sourceTokens) {
13
13
  const first = sourceTokens[0];
14
- return new LexerToken(
14
+ const last = sourceTokens[sourceTokens.length - 1];
15
+ const token = new LexerToken(
15
16
  type,
16
17
  tokenTypeId(type),
17
18
  text,
@@ -21,6 +22,13 @@ function createFusedToken(type, text, sourceTokens) {
21
22
  first.line,
22
23
  first.col
23
24
  );
25
+ token.sourceEnd = last.offset + last.value.length;
26
+ return token;
27
+ }
28
+ function recordSourceSpan(fused, sourceTokens) {
29
+ const last = sourceTokens[sourceTokens.length - 1];
30
+ if (!last) return;
31
+ fused.sourceEnd = last.sourceEnd ?? last.offset + last.value.length;
24
32
  }
25
33
  var NON_WORD_NAMES = [
26
34
  "NUMBER",
@@ -223,6 +231,7 @@ var TokenNormalizer = class {
223
231
  result.push(rt);
224
232
  }
225
233
  if (trieMatch.consumed > 1 && trieMatch.replacement.length === 1) {
234
+ recordSourceSpan(trieMatch.replacement[0], sourceTokens);
226
235
  fusionHandler({
227
236
  rule: trieMatch.ruleName ?? "phrase-trie",
228
237
  sourceTokens,
@@ -242,6 +251,7 @@ var TokenNormalizer = class {
242
251
  result.push(rt);
243
252
  }
244
253
  if (match.consumed > 1 && match.replacement.length === 1) {
254
+ recordSourceSpan(match.replacement[0], sourceTokens);
245
255
  fusionHandler({
246
256
  rule: rule.name,
247
257
  sourceTokens,
@@ -407,6 +417,7 @@ var PhraseTrie = class {
407
417
  };
408
418
 
409
419
  // src/normalizer/BuiltinNormalizerRules.ts
420
+ var RATE_DENOMINATOR_WORDS = /* @__PURE__ */ new Set(["per", "a", "an", "each", "every"]);
410
421
  var PHRASE_START_WORDS = /* @__PURE__ */ new Set([
411
422
  "to",
412
423
  "power",
@@ -428,6 +439,7 @@ function implicitMultiplyRule(priority = 50, canStart) {
428
439
  const next = tokens[pos + 1];
429
440
  const nextValue = next.value.toLowerCase();
430
441
  if (phraseGuard(nextValue)) return null;
442
+ if (RATE_DENOMINATOR_WORDS.has(nextValue) && tokens[pos + 2]?.type === "UNIT") return null;
431
443
  const triggers = (t.type === "NUMBER" || t.type === "RPAREN") && (next.type === "IDENT" || next.type === "LPAREN" || next.type === "PI" || next.type === "E");
432
444
  if (!triggers) return null;
433
445
  const starToken = new LexerToken(
@@ -473,9 +485,15 @@ var BUILTIN_PHRASES = {
473
485
  "decrease by": "DECREASE_BY",
474
486
  "times by": "TIMES_BY",
475
487
  "multiply by": "MULTIPLY_BY",
476
- "divide by": "DIVIDE_BY"
488
+ "divide by": "DIVIDE_BY",
489
+ // The past-tense spellings, which is how the operation is usually written
490
+ // out: "3 multiplied by 4". Same tokens, so no new parselets. Both this
491
+ // branch and the parity branch added "multiplied by" independently; the
492
+ // merge kept both copies and the locale table rejected the duplicate key.
493
+ "multiplied by": "MULTIPLY_BY",
494
+ "divided by": "DIVIDE_BY"
477
495
  };
478
496
 
479
497
  export { BUILTIN_PHRASES, PhraseTrie, TokenNormalizer, createBuiltinNormalizerRules, createFusedToken, implicitMultiplyRule, isInsideRangeContext };
480
- //# sourceMappingURL=chunk-64W6GLLZ.js.map
481
- //# sourceMappingURL=chunk-64W6GLLZ.js.map
498
+ //# sourceMappingURL=chunk-OFXOTECC.js.map
499
+ //# sourceMappingURL=chunk-OFXOTECC.js.map