solve-engine 2.23.0 → 2.25.0

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 (226) hide show
  1. package/README.md +82 -32
  2. package/dist/{BytecodeBuilder-aqVa7Plx.d.cts → BytecodeBuilder-DSWKZi4f.d.cts} +11 -9
  3. package/dist/{BytecodeBuilder-aqVa7Plx.d.ts → BytecodeBuilder-DSWKZi4f.d.ts} +11 -9
  4. package/dist/{Configuration-BGQn-cJ8.d.cts → Configuration-DnzYPmoK.d.cts} +33 -0
  5. package/dist/{Configuration-BGQn-cJ8.d.ts → Configuration-DnzYPmoK.d.ts} +33 -0
  6. package/dist/{EngineError-DTk7I7hZ.d.cts → EngineError-fR1K1rvx.d.cts} +6 -0
  7. package/dist/{EngineError-DTk7I7hZ.d.ts → EngineError-fR1K1rvx.d.ts} +6 -0
  8. package/dist/{Lexer-CqagTewQ.d.ts → Lexer-Bmctxl0n.d.ts} +84 -35
  9. package/dist/{Lexer-CCHFDcgP.d.cts → Lexer-aB95pjoX.d.cts} +84 -35
  10. package/dist/{PackageCompatibility-BGXSFuL9.d.ts → PackageCompatibility-BludTs7v.d.ts} +1 -1
  11. package/dist/{PackageCompatibility-BZCqaTOO.d.cts → PackageCompatibility-CUVg8tmt.d.cts} +1 -1
  12. package/dist/{PackageRegistry-BRoVOYzg.d.ts → PackageRegistry-DT-x32OM.d.ts} +67 -14
  13. package/dist/{PackageRegistry-rMGnTh7W.d.cts → PackageRegistry-Dvn4i2QK.d.cts} +67 -14
  14. package/dist/{Parselet-Bkbp9CKD.d.cts → Parselet-BawfGuTF.d.cts} +8 -2
  15. package/dist/{Parselet-B-WyUtX4.d.ts → Parselet-DqTbbtWA.d.ts} +8 -2
  16. package/dist/{ScopeManager-gB9UengK.d.ts → ScopeManager-B636am7Y.d.ts} +39 -8
  17. package/dist/{ScopeManager-bCYewWVt.d.cts → ScopeManager-CdwX0VTw.d.cts} +39 -8
  18. package/dist/{TokenNormalizer-OTPS0Otq.d.ts → TokenNormalizer-CLBtiE8M.d.ts} +45 -26
  19. package/dist/{TokenNormalizer-MXaKLJ_m.d.cts → TokenNormalizer-CjTDmHgB.d.cts} +45 -26
  20. package/dist/{VMCheckpoints-DGar9Yg8.d.cts → VMCheckpoints-CYqeq8IV.d.cts} +3 -3
  21. package/dist/{VMCheckpoints-BDRY1Kx8.d.ts → VMCheckpoints-DDlxNssY.d.ts} +3 -3
  22. package/dist/{Value-DCTqTSeP.d.cts → Value-Ds3Gy07C.d.cts} +1 -1
  23. package/dist/{Value-DCTqTSeP.d.ts → Value-Ds3Gy07C.d.ts} +1 -1
  24. package/dist/{WorkerError-DGBNM3gA.d.cts → WorkerError-B1dF3VYT.d.cts} +1 -1
  25. package/dist/{WorkerError-DpZgKRks.d.ts → WorkerError-dneODN-u.d.ts} +1 -1
  26. package/dist/{chunk-YAONCEAW.cjs → chunk-4BAUQE6A.cjs} +3 -3
  27. package/dist/{chunk-YAONCEAW.cjs.map → chunk-4BAUQE6A.cjs.map} +1 -1
  28. package/dist/chunk-4BRTUFTH.js +2 -0
  29. package/dist/chunk-4BRTUFTH.js.map +1 -0
  30. package/dist/chunk-4NZXCHQL.cjs +2 -0
  31. package/dist/chunk-4NZXCHQL.cjs.map +1 -0
  32. package/dist/chunk-57PSJQQW.js +3 -0
  33. package/dist/chunk-57PSJQQW.js.map +1 -0
  34. package/dist/chunk-634ILVMP.cjs +2 -0
  35. package/dist/chunk-634ILVMP.cjs.map +1 -0
  36. package/dist/{chunk-HMC7FJO7.js → chunk-63ZOOUOL.js} +2 -2
  37. package/dist/{chunk-HMC7FJO7.js.map → chunk-63ZOOUOL.js.map} +1 -1
  38. package/dist/chunk-72PYPENZ.js +2 -0
  39. package/dist/chunk-72PYPENZ.js.map +1 -0
  40. package/dist/chunk-77KI7AKJ.cjs +2 -0
  41. package/dist/chunk-77KI7AKJ.cjs.map +1 -0
  42. package/dist/chunk-7DP57BA7.js +2 -0
  43. package/dist/chunk-7DP57BA7.js.map +1 -0
  44. package/dist/chunk-7N3IJSWF.js +5 -0
  45. package/dist/chunk-7N3IJSWF.js.map +1 -0
  46. package/dist/chunk-BMXYR5LI.cjs +2 -0
  47. package/dist/chunk-BMXYR5LI.cjs.map +1 -0
  48. package/dist/chunk-DUYTXLO2.js +2 -0
  49. package/dist/chunk-DUYTXLO2.js.map +1 -0
  50. package/dist/chunk-EL2XUOWX.js +2 -0
  51. package/dist/chunk-EL2XUOWX.js.map +1 -0
  52. package/dist/chunk-FYAMQFZZ.cjs +3 -0
  53. package/dist/chunk-FYAMQFZZ.cjs.map +1 -0
  54. package/dist/chunk-FYTB7SDP.cjs +2 -0
  55. package/dist/chunk-FYTB7SDP.cjs.map +1 -0
  56. package/dist/chunk-GBCN7FNV.cjs +2 -0
  57. package/dist/chunk-GBCN7FNV.cjs.map +1 -0
  58. package/dist/{chunk-7E7NXKQ5.js → chunk-IJHL3LMH.js} +2 -2
  59. package/dist/chunk-IJHL3LMH.js.map +1 -0
  60. package/dist/{chunk-4ETS224G.js → chunk-JFZ5SLF7.js} +2 -2
  61. package/dist/{chunk-4ETS224G.js.map → chunk-JFZ5SLF7.js.map} +1 -1
  62. package/dist/chunk-JSM3O7EM.cjs +2 -0
  63. package/dist/chunk-JSM3O7EM.cjs.map +1 -0
  64. package/dist/chunk-MZMA32NE.js +3 -0
  65. package/dist/chunk-MZMA32NE.js.map +1 -0
  66. package/dist/chunk-N4SSR7Q6.js +2 -0
  67. package/dist/chunk-N4SSR7Q6.js.map +1 -0
  68. package/dist/{chunk-TL545PXW.cjs → chunk-NEGZZB7F.cjs} +2 -2
  69. package/dist/{chunk-TL545PXW.cjs.map → chunk-NEGZZB7F.cjs.map} +1 -1
  70. package/dist/{chunk-3GR46UOX.js → chunk-NMU5E7W7.js} +2 -2
  71. package/dist/{chunk-3GR46UOX.js.map → chunk-NMU5E7W7.js.map} +1 -1
  72. package/dist/chunk-OB2VX4IL.js +2 -0
  73. package/dist/chunk-OB2VX4IL.js.map +1 -0
  74. package/dist/{chunk-MRRMIBHE.js → chunk-OONQ3V3I.js} +2 -2
  75. package/dist/{chunk-MRRMIBHE.js.map → chunk-OONQ3V3I.js.map} +1 -1
  76. package/dist/{chunk-N37PUZJR.cjs → chunk-RAPEZR5L.cjs} +2 -2
  77. package/dist/{chunk-N37PUZJR.cjs.map → chunk-RAPEZR5L.cjs.map} +1 -1
  78. package/dist/{chunk-KEA5HRL3.js → chunk-RDYXH7ML.js} +2 -2
  79. package/dist/{chunk-KEA5HRL3.js.map → chunk-RDYXH7ML.js.map} +1 -1
  80. package/dist/{chunk-3SSMOVWB.cjs → chunk-SAF3B3AX.cjs} +2 -2
  81. package/dist/{chunk-3SSMOVWB.cjs.map → chunk-SAF3B3AX.cjs.map} +1 -1
  82. package/dist/chunk-SPOVFRZO.cjs +5 -0
  83. package/dist/chunk-SPOVFRZO.cjs.map +1 -0
  84. package/dist/{chunk-75JLWK4L.cjs → chunk-SQHBOWES.cjs} +2 -2
  85. package/dist/{chunk-75JLWK4L.cjs.map → chunk-SQHBOWES.cjs.map} +1 -1
  86. package/dist/chunk-UF5XMZTT.js +2 -0
  87. package/dist/chunk-UF5XMZTT.js.map +1 -0
  88. package/dist/chunk-UV3EUIBT.cjs +3 -0
  89. package/dist/chunk-UV3EUIBT.cjs.map +1 -0
  90. package/dist/chunk-VMSCRVNX.cjs +2 -0
  91. package/dist/chunk-VMSCRVNX.cjs.map +1 -0
  92. package/dist/{chunk-J7ABVGZH.cjs → chunk-WGP4UUO5.cjs} +2 -2
  93. package/dist/{chunk-J7ABVGZH.cjs.map → chunk-WGP4UUO5.cjs.map} +1 -1
  94. package/dist/chunk-XBGK3TTU.cjs +3 -0
  95. package/dist/chunk-XBGK3TTU.cjs.map +1 -0
  96. package/dist/chunk-XHQYHXRE.js +3 -0
  97. package/dist/chunk-XHQYHXRE.js.map +1 -0
  98. package/dist/chunk-XX55RR4Q.js +3 -0
  99. package/dist/chunk-XX55RR4Q.js.map +1 -0
  100. package/dist/chunk-YBQPEWT7.cjs +3 -0
  101. package/dist/chunk-YBQPEWT7.cjs.map +1 -0
  102. package/dist/{chunk-CHSO3DCS.js → chunk-ZDCZ5IDD.js} +3 -3
  103. package/dist/{chunk-CHSO3DCS.js.map → chunk-ZDCZ5IDD.js.map} +1 -1
  104. package/dist/{chunk-LNZNJSRW.cjs → chunk-ZVPZQ66D.cjs} +2 -2
  105. package/dist/chunk-ZVPZQ66D.cjs.map +1 -0
  106. package/dist/constants.cjs +1 -1
  107. package/dist/constants.d.cts +1 -1
  108. package/dist/constants.d.ts +1 -1
  109. package/dist/constants.js +1 -1
  110. package/dist/engine.cjs +1 -1
  111. package/dist/engine.d.cts +12 -12
  112. package/dist/engine.d.ts +12 -12
  113. package/dist/engine.js +1 -1
  114. package/dist/errors.cjs +1 -1
  115. package/dist/errors.d.cts +3 -3
  116. package/dist/errors.d.ts +3 -3
  117. package/dist/errors.js +1 -1
  118. package/dist/format.cjs +1 -1
  119. package/dist/format.d.cts +1 -1
  120. package/dist/format.d.ts +1 -1
  121. package/dist/format.js +1 -1
  122. package/dist/index.cjs +1 -1
  123. package/dist/index.cjs.map +1 -1
  124. package/dist/index.d.cts +14 -12
  125. package/dist/index.d.ts +14 -12
  126. package/dist/index.js +1 -1
  127. package/dist/index.js.map +1 -1
  128. package/dist/language.d.cts +11 -11
  129. package/dist/language.d.ts +11 -11
  130. package/dist/lexer.cjs +1 -1
  131. package/dist/lexer.cjs.map +1 -1
  132. package/dist/lexer.d.cts +8 -7
  133. package/dist/lexer.d.ts +8 -7
  134. package/dist/lexer.js +1 -1
  135. package/dist/lexer.js.map +1 -1
  136. package/dist/normalizer.cjs +1 -1
  137. package/dist/normalizer.d.cts +16 -10
  138. package/dist/normalizer.d.ts +16 -10
  139. package/dist/normalizer.js +1 -1
  140. package/dist/packages.cjs +1 -1
  141. package/dist/packages.d.cts +10 -10
  142. package/dist/packages.d.ts +10 -10
  143. package/dist/packages.js +1 -1
  144. package/dist/parser.cjs +1 -1
  145. package/dist/parser.d.cts +4 -4
  146. package/dist/parser.d.ts +4 -4
  147. package/dist/parser.js +1 -1
  148. package/dist/{pipeline-B4wf3M1h.d.cts → pipeline-69q2tsLE.d.cts} +1 -1
  149. package/dist/{pipeline-QIT4iD8f.d.ts → pipeline-DTqGLPsV.d.ts} +1 -1
  150. package/dist/resolvers.cjs +1 -1
  151. package/dist/resolvers.d.cts +19 -3
  152. package/dist/resolvers.d.ts +19 -3
  153. package/dist/resolvers.js +1 -1
  154. package/dist/testing.cjs +2 -2
  155. package/dist/testing.d.cts +11 -11
  156. package/dist/testing.d.ts +11 -11
  157. package/dist/testing.js +1 -1
  158. package/dist/uom.cjs +1 -1
  159. package/dist/uom.d.cts +2 -2
  160. package/dist/uom.d.ts +2 -2
  161. package/dist/uom.js +1 -1
  162. package/dist/vm.cjs +1 -1
  163. package/dist/vm.d.cts +8 -8
  164. package/dist/vm.d.ts +8 -8
  165. package/dist/vm.js +1 -1
  166. package/dist/worker.cjs +2 -2
  167. package/dist/worker.cjs.map +1 -1
  168. package/dist/worker.d.cts +34 -25
  169. package/dist/worker.d.ts +34 -25
  170. package/dist/worker.js +1 -1
  171. package/dist/worker.js.map +1 -1
  172. package/package.json +5 -5
  173. package/dist/chunk-42JXN3BH.js +0 -5
  174. package/dist/chunk-42JXN3BH.js.map +0 -1
  175. package/dist/chunk-4DJJIUQF.js +0 -2
  176. package/dist/chunk-4DJJIUQF.js.map +0 -1
  177. package/dist/chunk-6YM67DWH.cjs +0 -3
  178. package/dist/chunk-6YM67DWH.cjs.map +0 -1
  179. package/dist/chunk-7E7NXKQ5.js.map +0 -1
  180. package/dist/chunk-7SZBEE5R.cjs +0 -2
  181. package/dist/chunk-7SZBEE5R.cjs.map +0 -1
  182. package/dist/chunk-A5M4QZIK.js +0 -2
  183. package/dist/chunk-A5M4QZIK.js.map +0 -1
  184. package/dist/chunk-AF7HQN6I.js +0 -2
  185. package/dist/chunk-AF7HQN6I.js.map +0 -1
  186. package/dist/chunk-ALY4ZMYO.js +0 -2
  187. package/dist/chunk-ALY4ZMYO.js.map +0 -1
  188. package/dist/chunk-BRJ4RT5U.js +0 -2
  189. package/dist/chunk-BRJ4RT5U.js.map +0 -1
  190. package/dist/chunk-CO2BI6WL.cjs +0 -3
  191. package/dist/chunk-CO2BI6WL.cjs.map +0 -1
  192. package/dist/chunk-EN3CDYOS.cjs +0 -2
  193. package/dist/chunk-EN3CDYOS.cjs.map +0 -1
  194. package/dist/chunk-EQDT42JG.js +0 -3
  195. package/dist/chunk-EQDT42JG.js.map +0 -1
  196. package/dist/chunk-FMMT5C5H.cjs +0 -3
  197. package/dist/chunk-FMMT5C5H.cjs.map +0 -1
  198. package/dist/chunk-FP6Z6PYR.js +0 -2
  199. package/dist/chunk-FP6Z6PYR.js.map +0 -1
  200. package/dist/chunk-H3JXNH7X.cjs +0 -3
  201. package/dist/chunk-H3JXNH7X.cjs.map +0 -1
  202. package/dist/chunk-HZOLIL5T.js +0 -3
  203. package/dist/chunk-HZOLIL5T.js.map +0 -1
  204. package/dist/chunk-JVMINMAB.js +0 -2
  205. package/dist/chunk-JVMINMAB.js.map +0 -1
  206. package/dist/chunk-JYLNQOPU.cjs +0 -2
  207. package/dist/chunk-JYLNQOPU.cjs.map +0 -1
  208. package/dist/chunk-KRXO3MOW.cjs +0 -2
  209. package/dist/chunk-KRXO3MOW.cjs.map +0 -1
  210. package/dist/chunk-KVLJDOZ7.cjs +0 -5
  211. package/dist/chunk-KVLJDOZ7.cjs.map +0 -1
  212. package/dist/chunk-LNZNJSRW.cjs.map +0 -1
  213. package/dist/chunk-O3BDXOQJ.js +0 -2
  214. package/dist/chunk-O3BDXOQJ.js.map +0 -1
  215. package/dist/chunk-PIZQIQVM.js +0 -3
  216. package/dist/chunk-PIZQIQVM.js.map +0 -1
  217. package/dist/chunk-QTSDIDAS.js +0 -3
  218. package/dist/chunk-QTSDIDAS.js.map +0 -1
  219. package/dist/chunk-SGIDBZ4T.cjs +0 -2
  220. package/dist/chunk-SGIDBZ4T.cjs.map +0 -1
  221. package/dist/chunk-UNKSCVIL.cjs +0 -2
  222. package/dist/chunk-UNKSCVIL.cjs.map +0 -1
  223. package/dist/chunk-USQ4KL6S.cjs +0 -2
  224. package/dist/chunk-USQ4KL6S.cjs.map +0 -1
  225. package/dist/chunk-XDXIPVZB.cjs +0 -2
  226. package/dist/chunk-XDXIPVZB.cjs.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/defineFunction.ts","../src/api/createEngine.ts"],"names":["DefineFunctionErrorCodes","NAME_PATTERN","SUPPORTED_TYPES","plural","count","describeValueType","v","coerceArgument","value","arg","fnName","ErrorFactory","wrapReturn","result","returns","numberValue","stringValue","boolValue","DefinedFunctionParselet","parser","_token","builder","argCount","BindingPower","makeHandler","spec","arity","args","jsArgs","i","validateSpec","defineFunction","name","tokenType","createEngine","options","extraPackages","engineOptions","ExpressionEngine","BUILTIN_PACKAGES"],"mappings":"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","file":"index.js","sourcesContent":["import type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport type { PrefixParselet } from \"@solve-js/parser/Parselet\";\nimport type { Parser } from \"@solve-js/parser/Parser\";\nimport type { Token } from \"@solve-js/lexer/Token\";\nimport type { BytecodeBuilder } from \"@solve-js/parser/BytecodeBuilder\";\nimport { BindingPower } from \"@solve-js/parser/BindingPower\";\nimport {\n Value,\n ValueType,\n numberValue,\n stringValue,\n boolValue,\n} from \"@solve-js/vm/Value\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\n\n/**\n * A higher-level, declarative way to contribute a single `name(args)`\n * function, sitting ON TOP OF the package contract rather than replacing it.\n *\n * The low-level contract (allocate a plugin function index, write a parselet,\n * emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add\n * anything that needs custom parsing. This module derives that same wiring\n * from a declaration for the common case, a function called with parenthesised\n * arguments, so adding `vat(x)` costs a spec object rather than an\n * understanding of the parser and the VM. See `defineFunction`.\n */\n\n/** The value types a declared argument or return may take. */\nexport type FunctionValueType = \"number\" | \"string\" | \"boolean\";\n\n/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */\ntype JsValue<T extends FunctionValueType> = T extends \"number\"\n ? number\n : T extends \"string\"\n ? string\n : boolean;\n\n/** One declared parameter: a name (for error messages) and a value type. */\nexport interface FunctionArg {\n /** Parameter name, used only in the generated type-mismatch messages. */\n name: string;\n /** The value type this parameter accepts. */\n type: FunctionValueType;\n}\n\n/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */\ntype CallArgs<A extends readonly FunctionArg[]> = {\n [K in keyof A]: JsValue<A[K][\"type\"]>;\n};\n\n/**\n * A declarative function definition.\n *\n * `A` and `R` are inferred from the literal `args`/`returns` (via\n * `defineFunction`'s `const` type parameter), so `call`'s parameters and\n * return are typed from the declaration with no annotations: an\n * `{ type: \"number\" }` argument arrives as a `number`, and a `returns:\n * \"string\"` demands a `string` back.\n */\nexport interface FunctionSpec<\n A extends readonly FunctionArg[] = readonly FunctionArg[],\n R extends FunctionValueType = FunctionValueType,\n> {\n /**\n * The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered\n * as a lexer keyword, so it is matched case-insensitively and cannot collide\n * with a built-in keyword (that collision throws at registration time).\n */\n name: string;\n /** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */\n args: A;\n /** The value type the function returns. */\n returns: R;\n /** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */\n call: (...args: CallArgs<A>) => JsValue<R>;\n}\n\n/**\n * Error codes the declarative function API raises. Kept as a co-located const\n * (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so\n * the strings have one source of truth.\n */\nexport const DefineFunctionErrorCodes = {\n /** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */\n DEFINE_FUNCTION_INVALID_NAME: \"DEFINE_FUNCTION_INVALID_NAME\",\n /** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */\n DEFINE_FUNCTION_INVALID_SPEC: \"DEFINE_FUNCTION_INVALID_SPEC\",\n /** The call site passed the wrong number of arguments. Raised at evaluation time. */\n DEFINE_FUNCTION_ARITY_MISMATCH: \"DEFINE_FUNCTION_ARITY_MISMATCH\",\n /** An argument was the wrong value type. Raised at evaluation time. */\n DEFINE_FUNCTION_ARGUMENT_TYPE: \"DEFINE_FUNCTION_ARGUMENT_TYPE\",\n /** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */\n DEFINE_FUNCTION_RETURN_TYPE: \"DEFINE_FUNCTION_RETURN_TYPE\",\n} as const;\n\n/** A single identifier: a letter or underscore, then letters, digits, or underscores. */\nconst NAME_PATTERN = /^[a-z_][a-z0-9_]*$/i;\n\nconst SUPPORTED_TYPES: ReadonlySet<string> = new Set([\"number\", \"string\", \"boolean\"]);\n\n/** \"1 argument\" / \"2 arguments\", so a count reads as English either way. Mirrors `VMBuiltinArity.ts`. */\nfunction plural(count: number): string {\n return count === 1 ? \"1 argument\" : `${count} arguments`;\n}\n\n/**\n * A human noun for the type a Value actually carries, for the \"was given ...\"\n * half of a mismatch message. Covers the three declarable types by their own\n * names and everything else by a readable category, so the message never reads\n * \"given a 6\".\n */\nfunction describeValueType(v: Value): string {\n switch (v.type) {\n case ValueType.Number:\n case ValueType.Hex:\n return \"a number\";\n case ValueType.String:\n return \"a string\";\n case ValueType.Boolean:\n return \"a boolean\";\n case ValueType.BigInt:\n return \"a big integer\";\n case ValueType.Percentage:\n return \"a percentage\";\n case ValueType.Uom:\n return \"a value with a unit\";\n case ValueType.Datetime:\n return \"a date\";\n case ValueType.Matrix:\n return \"a matrix\";\n case ValueType.Range:\n return \"a range\";\n case ValueType.Symbolic:\n return \"a symbolic expression\";\n default:\n return \"an unsupported value\";\n }\n}\n\n/**\n * Read one runtime Value as the JS primitive its declared type promises, or\n * raise the engine's structured type error.\n *\n * A \"number\" accepts a plain number or a based literal (`0xFF`), both of which\n * ARE numbers written differently, and reads it with `toNumber()`. Nothing\n * else is coerced: a percentage, a unit-bearing value or a string is a\n * genuinely different kind of value, and silently reinterpreting it is the\n * class of wrong-answer this API exists to avoid.\n */\nfunction coerceArgument(\n value: Value,\n arg: FunctionArg,\n fnName: string,\n): number | string | boolean {\n switch (arg.type) {\n case \"number\":\n // Hex is a number in another base (see `hexValue`), so it reads as one here.\n if (value.type === ValueType.Number || value.type === ValueType.Hex) {\n return value.toNumber();\n }\n break;\n case \"string\":\n if (value.type === ValueType.String) return value.value as string;\n break;\n case \"boolean\":\n if (value.type === ValueType.Boolean) return value.value as boolean;\n break;\n }\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARGUMENT_TYPE,\n message: `${fnName}() expects \"${arg.name}\" to be a ${arg.type}, but was given ${describeValueType(value)}`,\n expected: `a ${arg.type}`,\n found: describeValueType(value),\n context: { functionName: fnName, argName: arg.name, expectedType: arg.type },\n });\n}\n\n/**\n * Wrap the `call` result back into a Value of the declared return type, or\n * raise a structured error if the implementation handed back something else.\n *\n * The type check here catches an authoring mistake (a function declared to\n * return a number that returns `undefined`, or a Promise from an accidental\n * `async`), turning it into a named error rather than a Value that lies about\n * its own type downstream.\n */\nfunction wrapReturn(result: unknown, returns: FunctionValueType, fnName: string): Value {\n switch (returns) {\n case \"number\":\n if (typeof result === \"number\") return numberValue(result);\n break;\n case \"string\":\n if (typeof result === \"string\") return stringValue(result);\n break;\n case \"boolean\":\n if (typeof result === \"boolean\") return boolValue(result);\n break;\n }\n throw ErrorFactory.internal({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_RETURN_TYPE,\n message: `${fnName}() is declared to return a ${returns}, but its implementation returned ${typeof result}`,\n expected: `a ${returns}`,\n found: typeof result,\n context: { functionName: fnName, expectedType: returns },\n });\n}\n\n/**\n * The call-syntax parselet generated for one declared function.\n *\n * Identical in shape to the built-in `FunctionCallParselet`: consume the open\n * paren, parse a comma-separated argument list, then emit `CALL_PLUGIN` with\n * the function's index and the argument count. The count is whatever was\n * written, arity is checked at the dispatch point (see {@link makeHandler}),\n * the same place the built-in arity check lives.\n */\nclass DefinedFunctionParselet implements PrefixParselet {\n readonly category = \"Function\";\n\n constructor(\n private readonly fnName: string,\n ) {}\n\n parse(parser: Parser, _token: Token, builder: BytecodeBuilder): void {\n parser.consume(\"LPAREN\");\n\n let argCount = 0;\n if (parser.peek()?.type !== \"RPAREN\") {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n while (parser.match(\"COMMA\")) {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n }\n }\n\n parser.consume(\"RPAREN\");\n\n builder.emitPluginCall(this.fnName, argCount);\n }\n}\n\n/**\n * Build the plugin function that checks arity and argument types, calls the\n * host implementation, and wraps the result.\n *\n * The VM has already screened out faulted arguments (an errored or still\n * pending operand short-circuits before the handler runs, see\n * `VM.ts`'s `CALL_PLUGIN` case), so every Value reaching here carries a real\n * result. Arity is checked first, before any argument is read, so a wrong\n * count is reported as a wrong count rather than as a type error on a missing\n * argument.\n */\nfunction makeHandler(spec: FunctionSpec): (args: Value[]) => Value {\n const arity = spec.args.length;\n return (args: Value[]): Value => {\n if (args.length !== arity) {\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARITY_MISMATCH,\n message: `${spec.name}() takes ${plural(arity)}, but was given ${args.length === 0 ? \"none\" : plural(args.length)}`,\n expected: plural(arity),\n found: args.length === 0 ? \"none\" : plural(args.length),\n context: { functionName: spec.name, expected: arity, actual: args.length },\n });\n }\n\n const jsArgs: (number | string | boolean)[] = new Array(arity);\n for (let i = 0; i < arity; i++) {\n jsArgs[i] = coerceArgument(args[i], spec.args[i], spec.name);\n }\n\n const result = (spec.call as (...a: (number | string | boolean)[]) => unknown)(...jsArgs);\n return wrapReturn(result, spec.returns, spec.name);\n };\n}\n\n/** Reject a spec that could not produce a working function, before any engine sees it. */\nfunction validateSpec(spec: FunctionSpec): void {\n if (typeof spec?.name !== \"string\" || !NAME_PATTERN.test(spec.name)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_NAME,\n message: `defineFunction: name must be a single identifier, got ${JSON.stringify(spec?.name)}`,\n suggestion: 'e.g. \"vat\" or \"net_price\"',\n context: { name: spec?.name },\n });\n }\n if (!Array.isArray(spec.args)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" args must be an array`,\n context: { name: spec.name },\n });\n }\n for (const arg of spec.args) {\n if (typeof arg?.name !== \"string\" || arg.name.length === 0) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has an argument with no name`,\n context: { name: spec.name },\n });\n }\n if (!SUPPORTED_TYPES.has(arg.type)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" argument \"${arg.name}\" has unsupported type ${JSON.stringify(arg.type)}`,\n suggestion: \"supported argument types are number, string, boolean\",\n context: { name: spec.name, argName: arg.name, type: arg.type },\n });\n }\n }\n if (!SUPPORTED_TYPES.has(spec.returns)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has unsupported return type ${JSON.stringify(spec.returns)}`,\n suggestion: \"supported return types are number, string, boolean\",\n context: { name: spec.name, returns: spec.returns },\n });\n }\n if (typeof spec.call !== \"function\") {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" is missing a call implementation`,\n context: { name: spec.name },\n });\n }\n}\n\n/**\n * Turn a declarative {@link FunctionSpec} into a ready-to-register\n * {@link IEnginePackage}.\n *\n * This is the higher-level API from issue #102. It derives, from the\n * declaration alone, everything the low-level contract asks an author to write\n * by hand: a named plugin function (the engine assigns its `CALL_PLUGIN`\n * index), a lexer keyword so the name tokenises, a call-syntax parselet emitting\n * that call by name, and a handler that checks arity and argument types (yielding\n * the engine's own structured errors) before invoking `call` and wrapping its\n * result. Anything needing custom parsing keeps writing a raw parselet exactly\n * as before, this sits on top of that contract and does not change it.\n *\n * @example\n * ```ts\n * const engine = new ExpressionEngine({ packages: [\n * ...BUILTIN_PACKAGES,\n * defineFunction({\n * name: \"vat\",\n * args: [{ name: \"amount\", type: \"number\" }],\n * returns: \"number\",\n * call: (amount) => amount * 1.2,\n * }),\n * ] });\n * engine.evaluateExpression(\"vat(100)\"); // 120\n * ```\n *\n * The returned package is self-contained and composes with any others through\n * the engine's `packages` array; register several functions by passing several\n * packages. Its name is `solve-fn-<name>`.\n *\n * Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and\n * `call` is synchronous. Variadic and optional arguments, other value types\n * (units, percentages, dates, matrices), and async work are deliberately out\n * of scope, a function needing any of those keeps using the low-level\n * contract, whose parselets and async resolvers are unchanged.\n *\n * @throws {EngineError} (category CONFIG) if the spec is malformed, at the\n * point `defineFunction` is called, before the package reaches an engine.\n */\nexport function defineFunction<\n const A extends readonly FunctionArg[],\n R extends FunctionValueType,\n>(spec: FunctionSpec<A, R>): IEnginePackage {\n validateSpec(spec as FunctionSpec);\n\n const name = spec.name;\n // Uppercased so the generated type is a valid, collision-resistant token\n // type; the name pattern guarantees it forms one. Distinct from the\n // built-in FUNC type, so this never routes through the builtin name map.\n const tokenType = `DEFINE_FN_${name.toUpperCase()}`;\n\n return {\n name: `solve-fn-${name}`,\n lexerVocabulary: {\n // Lowercased because the lexer lowercases input before lookup, so the\n // call is matched case-insensitively.\n keywords: { [name.toLowerCase()]: tokenType },\n },\n prefixParselets: {\n [tokenType]: new DefinedFunctionParselet(name),\n },\n pluginFunctions: {\n [name]: makeHandler(spec as FunctionSpec),\n },\n };\n}\n","import { ExpressionEngine, type EngineOptions } from \"@solve-js/engine/ExpressionEngine\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\n\n/** Options for {@link createEngine}: the engine options, minus `packages` (the\n * built-in set is always registered), plus `extraPackages` to add your own. */\nexport interface CreateEngineOptions extends Omit<EngineOptions, \"packages\"> {\n\t/** Packages to register ON TOP of the built-in set (e.g. an OSRS or stocks package). */\n\textraPackages?: IEnginePackage[];\n}\n\n/**\n * A batteries-included {@link ExpressionEngine} with every built-in package\n * registered.\n *\n * The constructor registers only the packages it is given, so a consumer's\n * bundler can tree-shake away the built-ins they never use: an engine built\n * with `new ExpressionEngine({ packages: [ARITHMETIC_PACKAGE] })` carries no\n * finance, colour or weather code. This convenience is the opposite trade: it\n * pulls the FULL built-in set (`BUILTIN_PACKAGES`) for the common \"I want\n * everything\" case, so importing it defeats that tree-shaking. Reach for the\n * constructor with an explicit package list when bundle size matters, and for\n * `createEngine` when it does not.\n *\n * @param options - Engine options ({@link EngineOptions}) minus `packages`, plus\n * an optional `extraPackages` to register alongside the built-in set.\n * @returns An engine with the built-in packages (and any extras) registered.\n *\n * @example\n * ```typescript\n * import { createEngine } from \"solve-engine\";\n * const engine = createEngine();\n * const value = engine.evaluateExpression(\"2 + 2 * 10\");\n * console.log(value.toNumber()); // 22\n * ```\n */\nexport function createEngine(options: CreateEngineOptions = {}): ExpressionEngine {\n\tconst { extraPackages = [], ...engineOptions } = options;\n\treturn new ExpressionEngine({\n\t\t...engineOptions,\n\t\tpackages: extraPackages.length > 0 ? [...BUILTIN_PACKAGES, ...extraPackages] : BUILTIN_PACKAGES,\n\t});\n}\n"]}
1
+ {"version":3,"sources":["../src/api/defineFunction.ts","../src/api/createEngine.ts"],"names":["DefineFunctionErrorCodes","NAME_PATTERN","SUPPORTED_TYPES","plural","count","describeValueType","v","coerceArgument","value","arg","fnName","ErrorFactory","wrapReturn","result","returns","numberValue","stringValue","boolValue","DefinedFunctionParselet","parser","_token","builder","argCount","BindingPower","makeHandler","spec","arity","args","jsArgs","i","validateSpec","defineFunction","name","tokenType","createEngine","options","extraPackages","engineOptions","ExpressionEngine","BUILTIN_PACKAGES"],"mappings":"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","file":"index.js","sourcesContent":["import type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport type { PrefixParselet } from \"@solve-js/parser/Parselet\";\nimport type { Parser } from \"@solve-js/parser/Parser\";\nimport type { Token } from \"@solve-js/lexer/Token\";\nimport type { BytecodeBuilder } from \"@solve-js/parser/BytecodeBuilder\";\nimport { BindingPower } from \"@solve-js/parser/BindingPower\";\nimport {\n Value,\n ValueType,\n numberValue,\n stringValue,\n boolValue,\n} from \"@solve-js/vm/Value\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\n\n/**\n * A higher-level, declarative way to contribute a single `name(args)`\n * function, sitting ON TOP OF the package contract rather than replacing it.\n *\n * The low-level contract (allocate a plugin function index, write a parselet,\n * emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add\n * anything that needs custom parsing. This module derives that same wiring\n * from a declaration for the common case, a function called with parenthesised\n * arguments, so adding `vat(x)` costs a spec object rather than an\n * understanding of the parser and the VM. See `defineFunction`.\n */\n\n/** The value types a declared argument or return may take. */\nexport type FunctionValueType = \"number\" | \"string\" | \"boolean\";\n\n/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */\ntype JsValue<T extends FunctionValueType> = T extends \"number\"\n ? number\n : T extends \"string\"\n ? string\n : boolean;\n\n/** One declared parameter: a name (for error messages) and a value type. */\nexport interface FunctionArg {\n /** Parameter name, used only in the generated type-mismatch messages. */\n name: string;\n /** The value type this parameter accepts. */\n type: FunctionValueType;\n}\n\n/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */\ntype CallArgs<A extends readonly FunctionArg[]> = {\n [K in keyof A]: JsValue<A[K][\"type\"]>;\n};\n\n/**\n * A declarative function definition.\n *\n * `A` and `R` are inferred from the literal `args`/`returns` (via\n * `defineFunction`'s `const` type parameter), so `call`'s parameters and\n * return are typed from the declaration with no annotations: an\n * `{ type: \"number\" }` argument arrives as a `number`, and a `returns:\n * \"string\"` demands a `string` back.\n */\nexport interface FunctionSpec<\n A extends readonly FunctionArg[] = readonly FunctionArg[],\n R extends FunctionValueType = FunctionValueType,\n> {\n /**\n * The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered\n * as a lexer keyword, so it is matched case-insensitively and cannot collide\n * with a built-in keyword (that collision throws at registration time).\n */\n name: string;\n /** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */\n args: A;\n /** The value type the function returns. */\n returns: R;\n /** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */\n call: (...args: CallArgs<A>) => JsValue<R>;\n}\n\n/**\n * Error codes the declarative function API raises. Kept as a co-located const\n * (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so\n * the strings have one source of truth.\n */\nexport const DefineFunctionErrorCodes = {\n /** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */\n DEFINE_FUNCTION_INVALID_NAME: \"DEFINE_FUNCTION_INVALID_NAME\",\n /** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */\n DEFINE_FUNCTION_INVALID_SPEC: \"DEFINE_FUNCTION_INVALID_SPEC\",\n /** The call site passed the wrong number of arguments. Raised at evaluation time. */\n DEFINE_FUNCTION_ARITY_MISMATCH: \"DEFINE_FUNCTION_ARITY_MISMATCH\",\n /** An argument was the wrong value type. Raised at evaluation time. */\n DEFINE_FUNCTION_ARGUMENT_TYPE: \"DEFINE_FUNCTION_ARGUMENT_TYPE\",\n /** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */\n DEFINE_FUNCTION_RETURN_TYPE: \"DEFINE_FUNCTION_RETURN_TYPE\",\n} as const;\n\n/** A single identifier: a letter or underscore, then letters, digits, or underscores. */\nconst NAME_PATTERN = /^[a-z_][a-z0-9_]*$/i;\n\nconst SUPPORTED_TYPES: ReadonlySet<string> = new Set([\"number\", \"string\", \"boolean\"]);\n\n/** \"1 argument\" / \"2 arguments\", so a count reads as English either way. Mirrors `VMBuiltinArity.ts`. */\nfunction plural(count: number): string {\n return count === 1 ? \"1 argument\" : `${count} arguments`;\n}\n\n/**\n * A human noun for the type a Value actually carries, for the \"was given ...\"\n * half of a mismatch message. Covers the three declarable types by their own\n * names and everything else by a readable category, so the message never reads\n * \"given a 6\".\n */\nfunction describeValueType(v: Value): string {\n switch (v.type) {\n case ValueType.Number:\n case ValueType.Hex:\n return \"a number\";\n case ValueType.String:\n return \"a string\";\n case ValueType.Boolean:\n return \"a boolean\";\n case ValueType.BigInt:\n return \"a big integer\";\n case ValueType.Percentage:\n return \"a percentage\";\n case ValueType.Uom:\n return \"a value with a unit\";\n case ValueType.Datetime:\n return \"a date\";\n case ValueType.Matrix:\n return \"a matrix\";\n case ValueType.Range:\n return \"a range\";\n case ValueType.Symbolic:\n return \"a symbolic expression\";\n default:\n return \"an unsupported value\";\n }\n}\n\n/**\n * Read one runtime Value as the JS primitive its declared type promises, or\n * raise the engine's structured type error.\n *\n * A \"number\" accepts a plain number or a based literal (`0xFF`), both of which\n * ARE numbers written differently, and reads it with `toNumber()`. Nothing\n * else is coerced: a percentage, a unit-bearing value or a string is a\n * genuinely different kind of value, and silently reinterpreting it is the\n * class of wrong-answer this API exists to avoid.\n */\nfunction coerceArgument(\n value: Value,\n arg: FunctionArg,\n fnName: string,\n): number | string | boolean {\n switch (arg.type) {\n case \"number\":\n // Hex is a number in another base (see `hexValue`), so it reads as one here.\n if (value.type === ValueType.Number || value.type === ValueType.Hex) {\n return value.toNumber();\n }\n break;\n case \"string\":\n if (value.type === ValueType.String) return value.value as string;\n break;\n case \"boolean\":\n if (value.type === ValueType.Boolean) return value.value as boolean;\n break;\n }\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARGUMENT_TYPE,\n message: `${fnName}() expects \"${arg.name}\" to be a ${arg.type}, but was given ${describeValueType(value)}`,\n expected: `a ${arg.type}`,\n found: describeValueType(value),\n context: { functionName: fnName, argName: arg.name, expectedType: arg.type },\n });\n}\n\n/**\n * Wrap the `call` result back into a Value of the declared return type, or\n * raise a structured error if the implementation handed back something else.\n *\n * The type check here catches an authoring mistake (a function declared to\n * return a number that returns `undefined`, or a Promise from an accidental\n * `async`), turning it into a named error rather than a Value that lies about\n * its own type downstream.\n */\nfunction wrapReturn(result: unknown, returns: FunctionValueType, fnName: string): Value {\n switch (returns) {\n case \"number\":\n if (typeof result === \"number\") return numberValue(result);\n break;\n case \"string\":\n if (typeof result === \"string\") return stringValue(result);\n break;\n case \"boolean\":\n if (typeof result === \"boolean\") return boolValue(result);\n break;\n }\n throw ErrorFactory.internal({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_RETURN_TYPE,\n message: `${fnName}() is declared to return a ${returns}, but its implementation returned ${typeof result}`,\n expected: `a ${returns}`,\n found: typeof result,\n context: { functionName: fnName, expectedType: returns },\n });\n}\n\n/**\n * The call-syntax parselet generated for one declared function.\n *\n * Identical in shape to the built-in `FunctionCallParselet`: consume the open\n * paren, parse a comma-separated argument list, then emit `CALL_PLUGIN` with\n * the function's index and the argument count. The count is whatever was\n * written, arity is checked at the dispatch point (see {@link makeHandler}),\n * the same place the built-in arity check lives.\n */\nclass DefinedFunctionParselet implements PrefixParselet {\n readonly category = \"Function\";\n\n constructor(\n private readonly fnName: string,\n ) {}\n\n parse(parser: Parser, _token: Token, builder: BytecodeBuilder): void {\n parser.consume(\"LPAREN\");\n\n let argCount = 0;\n if (parser.peek()?.type !== \"RPAREN\") {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n while (parser.match(\"COMMA\")) {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n }\n }\n\n parser.consume(\"RPAREN\");\n\n builder.emitPluginCall(this.fnName, argCount);\n }\n}\n\n/**\n * Build the plugin function that checks arity and argument types, calls the\n * host implementation, and wraps the result.\n *\n * The VM has already screened out faulted arguments (an errored or still\n * pending operand short-circuits before the handler runs, see\n * `VM.ts`'s `CALL_PLUGIN` case), so every Value reaching here carries a real\n * result. Arity is checked first, before any argument is read, so a wrong\n * count is reported as a wrong count rather than as a type error on a missing\n * argument.\n */\nfunction makeHandler(spec: FunctionSpec): (args: Value[]) => Value {\n const arity = spec.args.length;\n return (args: Value[]): Value => {\n if (args.length !== arity) {\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARITY_MISMATCH,\n message: `${spec.name}() takes ${plural(arity)}, but was given ${args.length === 0 ? \"none\" : plural(args.length)}`,\n expected: plural(arity),\n found: args.length === 0 ? \"none\" : plural(args.length),\n context: { functionName: spec.name, expected: arity, actual: args.length },\n });\n }\n\n const jsArgs: (number | string | boolean)[] = new Array(arity);\n for (let i = 0; i < arity; i++) {\n jsArgs[i] = coerceArgument(args[i], spec.args[i], spec.name);\n }\n\n const result = (spec.call as (...a: (number | string | boolean)[]) => unknown)(...jsArgs);\n return wrapReturn(result, spec.returns, spec.name);\n };\n}\n\n/** Reject a spec that could not produce a working function, before any engine sees it. */\nfunction validateSpec(spec: FunctionSpec): void {\n if (typeof spec?.name !== \"string\" || !NAME_PATTERN.test(spec.name)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_NAME,\n message: `defineFunction: name must be a single identifier, got ${JSON.stringify(spec?.name)}`,\n suggestion: 'e.g. \"vat\" or \"net_price\"',\n context: { name: spec?.name },\n });\n }\n if (!Array.isArray(spec.args)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" args must be an array`,\n context: { name: spec.name },\n });\n }\n for (const arg of spec.args) {\n if (typeof arg?.name !== \"string\" || arg.name.length === 0) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has an argument with no name`,\n context: { name: spec.name },\n });\n }\n if (!SUPPORTED_TYPES.has(arg.type)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" argument \"${arg.name}\" has unsupported type ${JSON.stringify(arg.type)}`,\n suggestion: \"supported argument types are number, string, boolean\",\n context: { name: spec.name, argName: arg.name, type: arg.type },\n });\n }\n }\n if (!SUPPORTED_TYPES.has(spec.returns)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has unsupported return type ${JSON.stringify(spec.returns)}`,\n suggestion: \"supported return types are number, string, boolean\",\n context: { name: spec.name, returns: spec.returns },\n });\n }\n if (typeof spec.call !== \"function\") {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" is missing a call implementation`,\n context: { name: spec.name },\n });\n }\n}\n\n/**\n * Turn a declarative {@link FunctionSpec} into a ready-to-register\n * {@link IEnginePackage}.\n *\n * This is the higher-level API from issue #102. It derives, from the\n * declaration alone, everything the low-level contract asks an author to write\n * by hand: a named plugin function (the engine assigns its `CALL_PLUGIN`\n * index), a lexer keyword so the name tokenises, a call-syntax parselet emitting\n * that call by name, and a handler that checks arity and argument types (yielding\n * the engine's own structured errors) before invoking `call` and wrapping its\n * result. Anything needing custom parsing keeps writing a raw parselet exactly\n * as before, this sits on top of that contract and does not change it.\n *\n * @example\n * ```ts\n * const engine = new ExpressionEngine({ packages: [\n * ...BUILTIN_PACKAGES,\n * defineFunction({\n * name: \"vat\",\n * args: [{ name: \"amount\", type: \"number\" }],\n * returns: \"number\",\n * call: (amount) => amount * 1.2,\n * }),\n * ] });\n * engine.evaluateExpression(\"vat(100)\"); // 120\n * ```\n *\n * The returned package is self-contained and composes with any others through\n * the engine's `packages` array; register several functions by passing several\n * packages. Its name is `solve-fn-<name>`.\n *\n * Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and\n * `call` is synchronous. Variadic and optional arguments, other value types\n * (units, percentages, dates, matrices), and async work are deliberately out\n * of scope, a function needing any of those keeps using the low-level\n * contract, whose parselets and async resolvers are unchanged.\n *\n * @throws {EngineError} (category CONFIG) if the spec is malformed, at the\n * point `defineFunction` is called, before the package reaches an engine.\n */\nexport function defineFunction<\n const A extends readonly FunctionArg[],\n R extends FunctionValueType,\n>(spec: FunctionSpec<A, R>): IEnginePackage {\n validateSpec(spec as FunctionSpec);\n\n const name = spec.name;\n // Uppercased so the generated type is a valid, collision-resistant token\n // type; the name pattern guarantees it forms one. Distinct from the\n // built-in FUNC type, so this never routes through the builtin name map.\n const tokenType = `DEFINE_FN_${name.toUpperCase()}`;\n\n return {\n name: `solve-fn-${name}`,\n lexerVocabulary: {\n // Lowercased because the lexer lowercases input before lookup, so the\n // call is matched case-insensitively.\n keywords: { [name.toLowerCase()]: tokenType },\n },\n prefixParselets: {\n [tokenType]: new DefinedFunctionParselet(name),\n },\n pluginFunctions: {\n [name]: makeHandler(spec as FunctionSpec),\n },\n };\n}\n","import { ExpressionEngine, type EngineOptions } from \"@solve-js/engine/ExpressionEngine\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\n\n/** Options for {@link createEngine}: the engine options, minus `packages` (the\n * built-in set is always registered), plus `extraPackages` to add your own. */\nexport interface CreateEngineOptions extends Omit<EngineOptions, \"packages\"> {\n\t/** Packages to register ON TOP of the built-in set (e.g. an OSRS or stocks package). */\n\textraPackages?: IEnginePackage[];\n}\n\n/**\n * A batteries-included {@link ExpressionEngine} with every built-in package\n * registered.\n *\n * The constructor registers only the packages it is given, so a consumer's\n * bundler can tree-shake away the built-ins they never use: an engine built\n * with `new ExpressionEngine({ packages: [ARITHMETIC_PACKAGE] })` carries no\n * finance, colour or weather code. This convenience is the opposite trade: it\n * pulls the FULL built-in set (`BUILTIN_PACKAGES`) for the common \"I want\n * everything\" case, so importing it defeats that tree-shaking. Reach for the\n * constructor with an explicit package list when bundle size matters, and for\n * `createEngine` when it does not.\n *\n * @param options - Engine options ({@link EngineOptions}) minus `packages`, plus\n * an optional `extraPackages` to register alongside the built-in set.\n * @returns An engine with the built-in packages (and any extras) registered.\n *\n * @example\n * ```typescript\n * import { createEngine } from \"solve-engine\";\n * const engine = createEngine();\n * const value = engine.evaluateExpression(\"2 + 2 * 10\");\n * console.log(value.toNumber()); // 22\n * ```\n */\nexport function createEngine(options: CreateEngineOptions = {}): ExpressionEngine {\n\tconst { extraPackages = [], ...engineOptions } = options;\n\treturn new ExpressionEngine({\n\t\t...engineOptions,\n\t\tpackages: extraPackages.length > 0 ? [...BUILTIN_PACKAGES, ...extraPackages] : BUILTIN_PACKAGES,\n\t});\n}\n"]}
@@ -1,17 +1,17 @@
1
- import { C as CompletionItem } from './PackageRegistry-rMGnTh7W.cjs';
2
- export { L as LanguageService, p as LanguageServiceOptions, q as SemanticToken } from './PackageRegistry-rMGnTh7W.cjs';
3
- import { e as TokenCategory } from './Lexer-CCHFDcgP.cjs';
4
- import './Parselet-Bkbp9CKD.cjs';
5
- import './BytecodeBuilder-aqVa7Plx.cjs';
1
+ import { C as CompletionItem } from './PackageRegistry-Dvn4i2QK.cjs';
2
+ export { L as LanguageService, p as LanguageServiceOptions, q as SemanticToken } from './PackageRegistry-Dvn4i2QK.cjs';
3
+ import { e as TokenCategory } from './Lexer-aB95pjoX.cjs';
4
+ import './Parselet-BawfGuTF.cjs';
5
+ import './BytecodeBuilder-DSWKZi4f.cjs';
6
6
  import './Token-CbP_OutD.cjs';
7
- import './pipeline-B4wf3M1h.cjs';
8
- import './Value-DCTqTSeP.cjs';
7
+ import './pipeline-69q2tsLE.cjs';
8
+ import './Value-Ds3Gy07C.cjs';
9
9
  import './resolvers.cjs';
10
10
  import '@tanstack/query-core';
11
- import './TokenNormalizer-MXaKLJ_m.cjs';
12
- import './ScopeManager-bCYewWVt.cjs';
13
- import './EngineError-DTk7I7hZ.cjs';
14
- import './Configuration-BGQn-cJ8.cjs';
11
+ import './TokenNormalizer-CjTDmHgB.cjs';
12
+ import './ScopeManager-CdwX0VTw.cjs';
13
+ import './EngineError-fR1K1rvx.cjs';
14
+ import './Configuration-DnzYPmoK.cjs';
15
15
 
16
16
  /**
17
17
  * Token types intentionally left uncategorized, either purely structural
@@ -1,17 +1,17 @@
1
- import { C as CompletionItem } from './PackageRegistry-BRoVOYzg.js';
2
- export { L as LanguageService, p as LanguageServiceOptions, q as SemanticToken } from './PackageRegistry-BRoVOYzg.js';
3
- import { e as TokenCategory } from './Lexer-CqagTewQ.js';
4
- import './Parselet-B-WyUtX4.js';
5
- import './BytecodeBuilder-aqVa7Plx.js';
1
+ import { C as CompletionItem } from './PackageRegistry-DT-x32OM.js';
2
+ export { L as LanguageService, p as LanguageServiceOptions, q as SemanticToken } from './PackageRegistry-DT-x32OM.js';
3
+ import { e as TokenCategory } from './Lexer-Bmctxl0n.js';
4
+ import './Parselet-DqTbbtWA.js';
5
+ import './BytecodeBuilder-DSWKZi4f.js';
6
6
  import './Token-CbP_OutD.js';
7
- import './pipeline-QIT4iD8f.js';
8
- import './Value-DCTqTSeP.js';
7
+ import './pipeline-DTqGLPsV.js';
8
+ import './Value-Ds3Gy07C.js';
9
9
  import './resolvers.js';
10
10
  import '@tanstack/query-core';
11
- import './TokenNormalizer-OTPS0Otq.js';
12
- import './ScopeManager-gB9UengK.js';
13
- import './EngineError-DTk7I7hZ.js';
14
- import './Configuration-BGQn-cJ8.js';
11
+ import './TokenNormalizer-CLBtiE8M.js';
12
+ import './ScopeManager-B636am7Y.js';
13
+ import './EngineError-fR1K1rvx.js';
14
+ import './Configuration-DnzYPmoK.js';
15
15
 
16
16
  /**
17
17
  * Token types intentionally left uncategorized, either purely structural
package/dist/lexer.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var chunkKRXO3MOW_cjs=require('./chunk-KRXO3MOW.cjs');require('./chunk-Y7O4D3BJ.cjs');var chunkUSQ4KL6S_cjs=require('./chunk-USQ4KL6S.cjs'),chunk5IJD5L3O_cjs=require('./chunk-5IJD5L3O.cjs');require('./chunk-S3DFU33X.cjs');var chunkJ4LSAHCY_cjs=require('./chunk-J4LSAHCY.cjs');require('./chunk-EZKR44MA.cjs'),require('./chunk-CO2BI6WL.cjs');Object.defineProperty(exports,"Lexer",{enumerable:true,get:function(){return chunkKRXO3MOW_cjs.b}});Object.defineProperty(exports,"LexerState",{enumerable:true,get:function(){return chunkKRXO3MOW_cjs.a}});Object.defineProperty(exports,"buildTokenLookup",{enumerable:true,get:function(){return chunkKRXO3MOW_cjs.d}});Object.defineProperty(exports,"sharedLexer",{enumerable:true,get:function(){return chunkKRXO3MOW_cjs.c}});Object.defineProperty(exports,"ExpressionLexer",{enumerable:true,get:function(){return chunkUSQ4KL6S_cjs.b}});Object.defineProperty(exports,"LexerToken",{enumerable:true,get:function(){return chunkUSQ4KL6S_cjs.a}});Object.defineProperty(exports,"TokenTypes",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.a}});Object.defineProperty(exports,"registerAllTokenTypes",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.e}});Object.defineProperty(exports,"registerTokenType",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.b}});Object.defineProperty(exports,"tokenTypeId",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.c}});Object.defineProperty(exports,"tokenTypeName",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.d}});Object.defineProperty(exports,"knownUnits",{enumerable:true,get:function(){return chunkJ4LSAHCY_cjs.a}});//# sourceMappingURL=lexer.cjs.map
1
+ 'use strict';var chunkBMXYR5LI_cjs=require('./chunk-BMXYR5LI.cjs');require('./chunk-Y7O4D3BJ.cjs');var chunk77KI7AKJ_cjs=require('./chunk-77KI7AKJ.cjs'),chunk5IJD5L3O_cjs=require('./chunk-5IJD5L3O.cjs'),chunkS3DFU33X_cjs=require('./chunk-S3DFU33X.cjs'),chunkJ4LSAHCY_cjs=require('./chunk-J4LSAHCY.cjs');require('./chunk-EZKR44MA.cjs'),require('./chunk-YBQPEWT7.cjs');var i=class{constructor(){this.classes=[];this.localeKeywordMap=null;this.localePhraseMap=null;this.unitNames=null;}register(e){this.classes.push(e);}unregister(e){this.classes=this.classes.filter(r=>r.tokenType!==e);}setLocale(e,r){this.localeKeywordMap=e,this.localePhraseMap=r??null;}setUnits(e){this.unitNames=e;}build(){let e=new Map;if(this.localeKeywordMap)for(let[s,t]of Object.entries(this.localeKeywordMap))e.set(s.toLowerCase(),t);let r=[...this.classes].sort((s,t)=>(s.priority??0)-(t.priority??0));for(let s of r)for(let t of Object.keys(s.keywords))e.set(t.toLowerCase(),s.tokenType);let o=this.buildPhraseTrie(),n=this.buildPhraseStartWords();return {keywordToType:e,phraseTrie:o,phraseStartWords:n,unitNames:this.unitNames??new Set}}buildPhraseTrie(){let e={children:new Map};if(this.localePhraseMap)for(let[r,o]of Object.entries(this.localePhraseMap))this.insertPhrase(e,r.toLowerCase(),o);for(let r of this.classes)if(r.phrases)for(let o of Object.keys(r.phrases))this.insertPhrase(e,o.toLowerCase(),r.tokenType);return e.children.size>0?e:null}insertPhrase(e,r,o){let n=r.split(" "),s=e;for(let t of n)s.children.has(t)||s.children.set(t,{children:new Map}),s=s.children.get(t);s.type||(s.type=o);}buildPhraseStartWords(){let e=new Set;if(this.localePhraseMap)for(let r of Object.keys(this.localePhraseMap)){let o=r.split(" ")[0].toLowerCase();e.add(o);}for(let r of this.classes)if(r.phrases)for(let o of Object.keys(r.phrases)){let n=o.split(" ")[0].toLowerCase();e.add(n);}return e}};function m(p="en"){let e=chunkS3DFU33X_cjs.a(p),r=new i;return r.setLocale(e.keywordMap,chunk77KI7AKJ_cjs.c),r.setUnits(chunkJ4LSAHCY_cjs.a),r.build()}Object.defineProperty(exports,"Lexer",{enumerable:true,get:function(){return chunkBMXYR5LI_cjs.b}});Object.defineProperty(exports,"LexerState",{enumerable:true,get:function(){return chunkBMXYR5LI_cjs.a}});Object.defineProperty(exports,"sharedLexer",{enumerable:true,get:function(){return chunkBMXYR5LI_cjs.c}});Object.defineProperty(exports,"ExpressionLexer",{enumerable:true,get:function(){return chunk77KI7AKJ_cjs.b}});Object.defineProperty(exports,"LexerToken",{enumerable:true,get:function(){return chunk77KI7AKJ_cjs.a}});Object.defineProperty(exports,"TokenTypes",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.a}});Object.defineProperty(exports,"registerAllTokenTypes",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.e}});Object.defineProperty(exports,"registerTokenType",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.b}});Object.defineProperty(exports,"tokenTypeId",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.c}});Object.defineProperty(exports,"tokenTypeName",{enumerable:true,get:function(){return chunk5IJD5L3O_cjs.d}});Object.defineProperty(exports,"knownUnits",{enumerable:true,get:function(){return chunkJ4LSAHCY_cjs.a}});exports.buildTokenLookup=m;//# sourceMappingURL=lexer.cjs.map
2
2
  //# sourceMappingURL=lexer.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"lexer.cjs"}
1
+ {"version":3,"sources":["../src/lexer/TokenClassRegistry.ts","../src/lexer/tokenRegistration.ts"],"names":["TokenClassRegistry","tokenClass","tokenType","c","keywordMap","phraseMap","unitNames","keywordToType","keyword","sorted","a","b","tc","phraseTrie","phraseStartWords","root","phrase","words","node","word","startWords","first","buildTokenLookup","localeCode","locale","getLocale","registry","BUILTIN_PHRASES","knownUnits"],"mappings":"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","file":"lexer.cjs","sourcesContent":["/**\n * TokenClass, Plugin-extensible keyword registration for the Lexer.\n *\n * Providers call `registry.register(tokenClass)` to teach the lexer about\n * their keywords. The registry merges locale keywords, provider keywords,\n * phrase mappings, and unit names into an optimized TokenLookup structure\n * consumed by the Lexer.\n *\n * @example\n * registry.register({\n * tokenType: 'CARET',\n * keywords: {},\n * phrases: { 'to the power of': true, 'power of': true },\n * priority: 10,\n * description: 'Exponentiation operators (x^y)',\n * });\n */\nexport interface TokenClass {\n /** The token type string produced by the lexer (e.g., \"FUNC\", \"PI\", \"CARET\").\n * Must match a token type that a ParseletRegistry has a parselet for. */\n tokenType: string;\n\n /** Single-word keywords (case-insensitive). The lexer lowercases input\n * before lookup, so these should be lowercase. Example:\n * { sqrt: true, abs: true, sin: true, cos: true } for tokenType \"FUNC\" */\n keywords: Record<string, boolean>;\n\n /** Multi-word phrases (case-insensitive). Matched by the built-in PhraseMatcher\n * via the phrase trie. Example:\n * { \"to the power of\": true, \"power of\": true } for tokenType \"CARET\" */\n phrases?: Record<string, boolean>;\n\n /** Priority for conflict resolution. When two TokenClasses register\n * the same keyword, the higher-priority class wins. Locale keywords\n * have priority 0 (set via setLocale). Providers should use\n * priority >= 10 to override locale defaults. Default: 0 */\n priority?: number;\n\n /** Human-readable description for debugging and introspection */\n description?: string;\n}\n\n// ── Phrase Trie ──────────────────────────────────────────────────────────────\n\n/** Trie node for multi-word phrase matching. */\nexport interface PhraseNode {\n /** Complete phrase token type (null = intermediate node) */\n type?: string;\n children: Map<string, PhraseNode>;\n}\n\n// ── TokenLookup, Optimized lookup structure for the Lexer ──────────────────\n\n/**\n * The optimized lookup structure built by TokenClassRegistry.build().\n * Consumed by the Lexer for O(1) keyword → token type lookups and\n * O(word-count) phrase matching.\n */\nexport interface TokenLookup {\n /** Lowercase keyword → token type. O(1) Map lookup. */\n keywordToType: Map<string, string>;\n\n /** Phrase trie for multi-word matching. Root node with children maps.\n * Null if no phrases registered. */\n phraseTrie: PhraseNode | null;\n\n /** Set of lowercase first-words of all registered phrases.\n * Used by the lexer to emit IDENT (not a phrase keyword) for words\n * that start multi-word phrases, deferring to the PhraseMatcher.\n *\n * Example: \"to\" is in phraseStartWords because \"to the power of\" is a phrase.\n * When the lexer sees \"to\", it emits IDENT and lets the phrase matcher\n * combine \"to the power of\" into a single CARET token.\n *\n * This prevents plugins from accidentally overriding phrase-start words.\n */\n phraseStartWords: Set<string>;\n\n /** Case-sensitive unit names for UNIT fallback after keyword lookup fails. */\n unitNames: ReadonlySet<string>;\n}\n\n// ── TokenClassRegistry ───────────────────────────────────────────────────────\n\n/**\n * Central registry for keyword→token-type mappings.\n *\n * Providers register TokenClasses; locales provide keyword maps;\n * units provide a name set. `build()` merges all sources into an\n * optimized TokenLookup consumed by the Lexer.\n *\n * Merge order (later overrides earlier):\n * 1. Locale keywords (priority 0)\n * 2. Provider keywords (sorted by priority ascending, higher priority wins)\n *\n * Unit names are stored separately (checked AFTER keyword lookup fails).\n * Phrases are stored in a trie for O(phrase-length) matching.\n */\nexport class TokenClassRegistry {\n private classes: TokenClass[] = [];\n private localeKeywordMap: Record<string, string> | null = null;\n private localePhraseMap: Record<string, string> | null = null;\n private unitNames: ReadonlySet<string> | null = null;\n\n /**\n * Register a provider's TokenClass. Must be called BEFORE build().\n * Can be called multiple times to add more entries.\n *\n * Built-in token types CANNOT be overridden, throws a EngineError\n * if the TokenClass attempts to register a keyword that conflicts\n * with an already-registered token type.\n */\n register(tokenClass: TokenClass): void {\n this.classes.push(tokenClass);\n }\n\n /**\n * Unregister all TokenClasses for a given token type.\n * Useful for plugin unload. Requires rebuild() to take effect.\n */\n unregister(tokenType: string): void {\n this.classes = this.classes.filter(c => c.tokenType !== tokenType);\n }\n\n /**\n * Set the locale's keyword→type map and optional phrase map.\n * Called on locale change. Priority 0 (cannot override providers with higher priority).\n */\n setLocale(keywordMap: Record<string, string>, phraseMap?: Record<string, string>): void {\n this.localeKeywordMap = keywordMap;\n this.localePhraseMap = phraseMap ?? null;\n }\n\n /**\n * Set the unit name set. Called when unit list changes.\n * Units are stored separately (checked AFTER keyword lookup fails).\n *\n * Takes a ReadonlySet because the caller's set is derived from the\n * conversion tables and must not be mutated; this class only ever reads it.\n */\n setUnits(unitNames: ReadonlySet<string>): void {\n this.unitNames = unitNames;\n }\n\n /**\n * Build the optimized TokenLookup from all registered sources.\n *\n * Merge order (later overrides earlier):\n * 1. Locale keywords (priority 0)\n * 2. Provider classes (sorted by priority ascending)\n *\n * Returns a frozen TokenLookup that the Lexer consumes.\n * Call build() again after register()/setLocale()/setUnits() changes.\n */\n build(): TokenLookup {\n const keywordToType = new Map<string, string>();\n\n // Layer 1: Locale keywords (priority 0, lowest)\n if (this.localeKeywordMap) {\n for (const [keyword, tokenType] of Object.entries(this.localeKeywordMap)) {\n keywordToType.set(keyword.toLowerCase(), tokenType);\n }\n }\n\n // Layer 2: Provider keywords (sorted by priority ascending, higher wins)\n const sorted = [...this.classes].sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));\n for (const tc of sorted) {\n for (const keyword of Object.keys(tc.keywords)) {\n keywordToType.set(keyword.toLowerCase(), tc.tokenType);\n }\n }\n\n // Build phrase trie from locale + provider phrases\n const phraseTrie = this.buildPhraseTrie();\n\n // Build phraseStartWords set (first word of every phrase)\n const phraseStartWords = this.buildPhraseStartWords();\n\n return {\n keywordToType,\n phraseTrie,\n phraseStartWords,\n unitNames: this.unitNames ?? new Set(),\n };\n }\n\n // ── Private helpers ─────────────────────────────────────────────────────\n\n private buildPhraseTrie(): PhraseNode | null {\n const root: PhraseNode = { children: new Map() };\n\n // Layer 1: Locale phrases\n if (this.localePhraseMap) {\n for (const [phrase, tokenType] of Object.entries(this.localePhraseMap)) {\n this.insertPhrase(root, phrase.toLowerCase(), tokenType);\n }\n }\n\n // Layer 2: Provider phrases\n for (const tc of this.classes) {\n if (!tc.phrases) continue;\n for (const phrase of Object.keys(tc.phrases)) {\n this.insertPhrase(root, phrase.toLowerCase(), tc.tokenType);\n }\n }\n\n return root.children.size > 0 ? root : null;\n }\n\n private insertPhrase(root: PhraseNode, phrase: string, tokenType: string): void {\n const words = phrase.split(' ');\n let node = root;\n for (const word of words) {\n if (!node.children.has(word)) {\n node.children.set(word, { children: new Map() });\n }\n node = node.children.get(word)!;\n }\n // Only set type if not already set, first-registered (locale) wins\n if (!node.type) {\n node.type = tokenType;\n }\n }\n\n private buildPhraseStartWords(): Set<string> {\n const startWords = new Set<string>();\n\n // Locale phrase first words\n if (this.localePhraseMap) {\n for (const phrase of Object.keys(this.localePhraseMap)) {\n const first = phrase.split(' ')[0].toLowerCase();\n startWords.add(first);\n }\n }\n\n // Provider phrase first words\n for (const tc of this.classes) {\n if (!tc.phrases) continue;\n for (const phrase of Object.keys(tc.phrases)) {\n const first = phrase.split(' ')[0].toLowerCase();\n startWords.add(first);\n }\n }\n\n return startWords;\n }\n}","/**\n * tokenRegistration.ts, Bootstrap for building TokenLookup from locale, units, and phrases.\n *\n * This module centralizes the assembly of the TokenLookup consumed by ExpressionLexer.\n * It merges:\n * 1. Locale keywords (from ILocale.keywordMap)\n * 2. Built-in phrase patterns (to the power of, increase by, etc.)\n * 3. Known unit names (from units.ts)\n *\n * The resulting TokenLookup is frozen. Nothing in the engine consumes it any\n * more (see the deprecation on {@link buildTokenLookup}).\n */\nimport { TokenClassRegistry } from '@solve-js/lexer/TokenClassRegistry';\nimport type { TokenLookup } from '@solve-js/lexer/TokenClassRegistry';\nimport { getLocale, type ILocale } from '@solve-js/constants/locales';\nimport { knownUnits } from '@solve-js/lexer/units';\n// The multi-word expressions handled as compound tokens, matched by the\n// PhraseMatcher (trie-based) in ExpressionLexer.tryMatchPhrase(). The same\n// table the normalizer's phrase trie reads, so the two cannot drift.\nimport { BUILTIN_PHRASES } from '@solve-js/lexer/BuiltinPhrases';\n\n/**\n * Build a TokenLookup from locale keywords, known units, and built-in phrases.\n *\n * Merge order (later overrides earlier):\n * 1. Locale keywords (priority 0, lowest, can be overridden by providers)\n * 2. Built-in phrases (via locale phraseMap)\n * 3. Known units (checked AFTER keyword lookup fails, via unitNames set)\n *\n * @param localeCode - The locale code (e.g., \"en\", \"de\"). Defaults to \"en\".\n * @returns A frozen TokenLookup.\n * @deprecated The lexer never read the lookup it was handed: its keyword, unit\n * and phrase tables are built from the locale and the packages registered\n * with it, and the engine no longer builds one at construction. Kept for\n * callers that build their own; removed in 3.0.\n */\nexport function buildTokenLookup(localeCode = 'en'): TokenLookup {\n const locale: ILocale = getLocale(localeCode);\n const registry = new TokenClassRegistry();\n\n // Layer 1: Locale keywords (priority 0, lowest)\n registry.setLocale(locale.keywordMap, BUILTIN_PHRASES);\n\n // Layer 2: Known units (checked after keyword lookup)\n registry.setUnits(knownUnits);\n\n // Build and return the lookup\n return registry.build();\n}\n"]}
package/dist/lexer.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- import { T as TokenLookup } from './Lexer-CCHFDcgP.cjs';
2
- export { E as ExpressionLexer, I as InlineSolveSpan, L as Lexer, a as LexerState, b as LexerToken, c as LexerVocabulary, d as LineClassification, M as MarkdownLineType, S as ScanLineResult, s as sharedLexer } from './Lexer-CCHFDcgP.cjs';
1
+ import { T as TokenLookup } from './Lexer-aB95pjoX.cjs';
2
+ export { E as ExpressionLexer, I as InlineSolveSpan, L as Lexer, a as LexerState, b as LexerToken, c as LexerVocabulary, d as LineClassification, M as MarkdownLineType, S as ScanLineResult, s as sharedLexer } from './Lexer-aB95pjoX.cjs';
3
3
  export { T as Token, a as TokenType, b as TokenTypes, r as registerAllTokenTypes, c as registerTokenType, t as tokenTypeId, d as tokenTypeName } from './Token-CbP_OutD.cjs';
4
+ import './EngineError-fR1K1rvx.cjs';
4
5
 
5
6
  /**
6
7
  * The set of unit identifiers the lexer will turn into a UNIT token.
@@ -44,12 +45,12 @@ declare const knownUnits: ReadonlySet<string>;
44
45
  * 2. Built-in phrases (via locale phraseMap)
45
46
  * 3. Known units (checked AFTER keyword lookup fails, via unitNames set)
46
47
  *
47
- * The resulting TokenLookup replaces the internal keyword map, unit set,
48
- * phrase trie, and phraseStartWords in ExpressionLexer when set via
49
- * ExpressionLexer.configuredLookup.
50
- *
51
48
  * @param localeCode - The locale code (e.g., "en", "de"). Defaults to "en".
52
- * @returns A frozen TokenLookup ready for consumption by the lexer.
49
+ * @returns A frozen TokenLookup.
50
+ * @deprecated The lexer never read the lookup it was handed: its keyword, unit
51
+ * and phrase tables are built from the locale and the packages registered
52
+ * with it, and the engine no longer builds one at construction. Kept for
53
+ * callers that build their own; removed in 3.0.
53
54
  */
54
55
  declare function buildTokenLookup(localeCode?: string): TokenLookup;
55
56
 
package/dist/lexer.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { T as TokenLookup } from './Lexer-CqagTewQ.js';
2
- export { E as ExpressionLexer, I as InlineSolveSpan, L as Lexer, a as LexerState, b as LexerToken, c as LexerVocabulary, d as LineClassification, M as MarkdownLineType, S as ScanLineResult, s as sharedLexer } from './Lexer-CqagTewQ.js';
1
+ import { T as TokenLookup } from './Lexer-Bmctxl0n.js';
2
+ export { E as ExpressionLexer, I as InlineSolveSpan, L as Lexer, a as LexerState, b as LexerToken, c as LexerVocabulary, d as LineClassification, M as MarkdownLineType, S as ScanLineResult, s as sharedLexer } from './Lexer-Bmctxl0n.js';
3
3
  export { T as Token, a as TokenType, b as TokenTypes, r as registerAllTokenTypes, c as registerTokenType, t as tokenTypeId, d as tokenTypeName } from './Token-CbP_OutD.js';
4
+ import './EngineError-fR1K1rvx.js';
4
5
 
5
6
  /**
6
7
  * The set of unit identifiers the lexer will turn into a UNIT token.
@@ -44,12 +45,12 @@ declare const knownUnits: ReadonlySet<string>;
44
45
  * 2. Built-in phrases (via locale phraseMap)
45
46
  * 3. Known units (checked AFTER keyword lookup fails, via unitNames set)
46
47
  *
47
- * The resulting TokenLookup replaces the internal keyword map, unit set,
48
- * phrase trie, and phraseStartWords in ExpressionLexer when set via
49
- * ExpressionLexer.configuredLookup.
50
- *
51
48
  * @param localeCode - The locale code (e.g., "en", "de"). Defaults to "en".
52
- * @returns A frozen TokenLookup ready for consumption by the lexer.
49
+ * @returns A frozen TokenLookup.
50
+ * @deprecated The lexer never read the lookup it was handed: its keyword, unit
51
+ * and phrase tables are built from the locale and the packages registered
52
+ * with it, and the engine no longer builds one at construction. Kept for
53
+ * callers that build their own; removed in 3.0.
53
54
  */
54
55
  declare function buildTokenLookup(localeCode?: string): TokenLookup;
55
56
 
package/dist/lexer.js CHANGED
@@ -1,2 +1,2 @@
1
- export{b as Lexer,a as LexerState,d as buildTokenLookup,c as sharedLexer}from'./chunk-FP6Z6PYR.js';import'./chunk-JPFCXLJV.js';export{b as ExpressionLexer,a as LexerToken}from'./chunk-AF7HQN6I.js';export{a as TokenTypes,e as registerAllTokenTypes,b as registerTokenType,c as tokenTypeId,d as tokenTypeName}from'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';export{a as knownUnits}from'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import'./chunk-PIZQIQVM.js';//# sourceMappingURL=lexer.js.map
1
+ export{b as Lexer,a as LexerState,c as sharedLexer}from'./chunk-7DP57BA7.js';import'./chunk-JPFCXLJV.js';import {c}from'./chunk-OB2VX4IL.js';export{b as ExpressionLexer,a as LexerToken}from'./chunk-OB2VX4IL.js';export{a as TokenTypes,e as registerAllTokenTypes,b as registerTokenType,c as tokenTypeId,d as tokenTypeName}from'./chunk-IJMNVBIS.js';import {a}from'./chunk-LHLW7JLS.js';import {a as a$1}from'./chunk-CHVGFTO3.js';export{a as knownUnits}from'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import'./chunk-57PSJQQW.js';var i=class{constructor(){this.classes=[];this.localeKeywordMap=null;this.localePhraseMap=null;this.unitNames=null;}register(e){this.classes.push(e);}unregister(e){this.classes=this.classes.filter(r=>r.tokenType!==e);}setLocale(e,r){this.localeKeywordMap=e,this.localePhraseMap=r??null;}setUnits(e){this.unitNames=e;}build(){let e=new Map;if(this.localeKeywordMap)for(let[s,t]of Object.entries(this.localeKeywordMap))e.set(s.toLowerCase(),t);let r=[...this.classes].sort((s,t)=>(s.priority??0)-(t.priority??0));for(let s of r)for(let t of Object.keys(s.keywords))e.set(t.toLowerCase(),s.tokenType);let o=this.buildPhraseTrie(),n=this.buildPhraseStartWords();return {keywordToType:e,phraseTrie:o,phraseStartWords:n,unitNames:this.unitNames??new Set}}buildPhraseTrie(){let e={children:new Map};if(this.localePhraseMap)for(let[r,o]of Object.entries(this.localePhraseMap))this.insertPhrase(e,r.toLowerCase(),o);for(let r of this.classes)if(r.phrases)for(let o of Object.keys(r.phrases))this.insertPhrase(e,o.toLowerCase(),r.tokenType);return e.children.size>0?e:null}insertPhrase(e,r,o){let n=r.split(" "),s=e;for(let t of n)s.children.has(t)||s.children.set(t,{children:new Map}),s=s.children.get(t);s.type||(s.type=o);}buildPhraseStartWords(){let e=new Set;if(this.localePhraseMap)for(let r of Object.keys(this.localePhraseMap)){let o=r.split(" ")[0].toLowerCase();e.add(o);}for(let r of this.classes)if(r.phrases)for(let o of Object.keys(r.phrases)){let n=o.split(" ")[0].toLowerCase();e.add(n);}return e}};function m(p="en"){let e=a(p),r=new i;return r.setLocale(e.keywordMap,c),r.setUnits(a$1),r.build()}export{m as buildTokenLookup};//# sourceMappingURL=lexer.js.map
2
2
  //# sourceMappingURL=lexer.js.map
package/dist/lexer.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"lexer.js"}
1
+ {"version":3,"sources":["../src/lexer/TokenClassRegistry.ts","../src/lexer/tokenRegistration.ts"],"names":["TokenClassRegistry","tokenClass","tokenType","c","keywordMap","phraseMap","unitNames","keywordToType","keyword","sorted","a","b","tc","phraseTrie","phraseStartWords","root","phrase","words","node","word","startWords","first","buildTokenLookup","localeCode","locale","getLocale","registry","BUILTIN_PHRASES","knownUnits"],"mappings":"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","file":"lexer.js","sourcesContent":["/**\n * TokenClass, Plugin-extensible keyword registration for the Lexer.\n *\n * Providers call `registry.register(tokenClass)` to teach the lexer about\n * their keywords. The registry merges locale keywords, provider keywords,\n * phrase mappings, and unit names into an optimized TokenLookup structure\n * consumed by the Lexer.\n *\n * @example\n * registry.register({\n * tokenType: 'CARET',\n * keywords: {},\n * phrases: { 'to the power of': true, 'power of': true },\n * priority: 10,\n * description: 'Exponentiation operators (x^y)',\n * });\n */\nexport interface TokenClass {\n /** The token type string produced by the lexer (e.g., \"FUNC\", \"PI\", \"CARET\").\n * Must match a token type that a ParseletRegistry has a parselet for. */\n tokenType: string;\n\n /** Single-word keywords (case-insensitive). The lexer lowercases input\n * before lookup, so these should be lowercase. Example:\n * { sqrt: true, abs: true, sin: true, cos: true } for tokenType \"FUNC\" */\n keywords: Record<string, boolean>;\n\n /** Multi-word phrases (case-insensitive). Matched by the built-in PhraseMatcher\n * via the phrase trie. Example:\n * { \"to the power of\": true, \"power of\": true } for tokenType \"CARET\" */\n phrases?: Record<string, boolean>;\n\n /** Priority for conflict resolution. When two TokenClasses register\n * the same keyword, the higher-priority class wins. Locale keywords\n * have priority 0 (set via setLocale). Providers should use\n * priority >= 10 to override locale defaults. Default: 0 */\n priority?: number;\n\n /** Human-readable description for debugging and introspection */\n description?: string;\n}\n\n// ── Phrase Trie ──────────────────────────────────────────────────────────────\n\n/** Trie node for multi-word phrase matching. */\nexport interface PhraseNode {\n /** Complete phrase token type (null = intermediate node) */\n type?: string;\n children: Map<string, PhraseNode>;\n}\n\n// ── TokenLookup, Optimized lookup structure for the Lexer ──────────────────\n\n/**\n * The optimized lookup structure built by TokenClassRegistry.build().\n * Consumed by the Lexer for O(1) keyword → token type lookups and\n * O(word-count) phrase matching.\n */\nexport interface TokenLookup {\n /** Lowercase keyword → token type. O(1) Map lookup. */\n keywordToType: Map<string, string>;\n\n /** Phrase trie for multi-word matching. Root node with children maps.\n * Null if no phrases registered. */\n phraseTrie: PhraseNode | null;\n\n /** Set of lowercase first-words of all registered phrases.\n * Used by the lexer to emit IDENT (not a phrase keyword) for words\n * that start multi-word phrases, deferring to the PhraseMatcher.\n *\n * Example: \"to\" is in phraseStartWords because \"to the power of\" is a phrase.\n * When the lexer sees \"to\", it emits IDENT and lets the phrase matcher\n * combine \"to the power of\" into a single CARET token.\n *\n * This prevents plugins from accidentally overriding phrase-start words.\n */\n phraseStartWords: Set<string>;\n\n /** Case-sensitive unit names for UNIT fallback after keyword lookup fails. */\n unitNames: ReadonlySet<string>;\n}\n\n// ── TokenClassRegistry ───────────────────────────────────────────────────────\n\n/**\n * Central registry for keyword→token-type mappings.\n *\n * Providers register TokenClasses; locales provide keyword maps;\n * units provide a name set. `build()` merges all sources into an\n * optimized TokenLookup consumed by the Lexer.\n *\n * Merge order (later overrides earlier):\n * 1. Locale keywords (priority 0)\n * 2. Provider keywords (sorted by priority ascending, higher priority wins)\n *\n * Unit names are stored separately (checked AFTER keyword lookup fails).\n * Phrases are stored in a trie for O(phrase-length) matching.\n */\nexport class TokenClassRegistry {\n private classes: TokenClass[] = [];\n private localeKeywordMap: Record<string, string> | null = null;\n private localePhraseMap: Record<string, string> | null = null;\n private unitNames: ReadonlySet<string> | null = null;\n\n /**\n * Register a provider's TokenClass. Must be called BEFORE build().\n * Can be called multiple times to add more entries.\n *\n * Built-in token types CANNOT be overridden, throws a EngineError\n * if the TokenClass attempts to register a keyword that conflicts\n * with an already-registered token type.\n */\n register(tokenClass: TokenClass): void {\n this.classes.push(tokenClass);\n }\n\n /**\n * Unregister all TokenClasses for a given token type.\n * Useful for plugin unload. Requires rebuild() to take effect.\n */\n unregister(tokenType: string): void {\n this.classes = this.classes.filter(c => c.tokenType !== tokenType);\n }\n\n /**\n * Set the locale's keyword→type map and optional phrase map.\n * Called on locale change. Priority 0 (cannot override providers with higher priority).\n */\n setLocale(keywordMap: Record<string, string>, phraseMap?: Record<string, string>): void {\n this.localeKeywordMap = keywordMap;\n this.localePhraseMap = phraseMap ?? null;\n }\n\n /**\n * Set the unit name set. Called when unit list changes.\n * Units are stored separately (checked AFTER keyword lookup fails).\n *\n * Takes a ReadonlySet because the caller's set is derived from the\n * conversion tables and must not be mutated; this class only ever reads it.\n */\n setUnits(unitNames: ReadonlySet<string>): void {\n this.unitNames = unitNames;\n }\n\n /**\n * Build the optimized TokenLookup from all registered sources.\n *\n * Merge order (later overrides earlier):\n * 1. Locale keywords (priority 0)\n * 2. Provider classes (sorted by priority ascending)\n *\n * Returns a frozen TokenLookup that the Lexer consumes.\n * Call build() again after register()/setLocale()/setUnits() changes.\n */\n build(): TokenLookup {\n const keywordToType = new Map<string, string>();\n\n // Layer 1: Locale keywords (priority 0, lowest)\n if (this.localeKeywordMap) {\n for (const [keyword, tokenType] of Object.entries(this.localeKeywordMap)) {\n keywordToType.set(keyword.toLowerCase(), tokenType);\n }\n }\n\n // Layer 2: Provider keywords (sorted by priority ascending, higher wins)\n const sorted = [...this.classes].sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));\n for (const tc of sorted) {\n for (const keyword of Object.keys(tc.keywords)) {\n keywordToType.set(keyword.toLowerCase(), tc.tokenType);\n }\n }\n\n // Build phrase trie from locale + provider phrases\n const phraseTrie = this.buildPhraseTrie();\n\n // Build phraseStartWords set (first word of every phrase)\n const phraseStartWords = this.buildPhraseStartWords();\n\n return {\n keywordToType,\n phraseTrie,\n phraseStartWords,\n unitNames: this.unitNames ?? new Set(),\n };\n }\n\n // ── Private helpers ─────────────────────────────────────────────────────\n\n private buildPhraseTrie(): PhraseNode | null {\n const root: PhraseNode = { children: new Map() };\n\n // Layer 1: Locale phrases\n if (this.localePhraseMap) {\n for (const [phrase, tokenType] of Object.entries(this.localePhraseMap)) {\n this.insertPhrase(root, phrase.toLowerCase(), tokenType);\n }\n }\n\n // Layer 2: Provider phrases\n for (const tc of this.classes) {\n if (!tc.phrases) continue;\n for (const phrase of Object.keys(tc.phrases)) {\n this.insertPhrase(root, phrase.toLowerCase(), tc.tokenType);\n }\n }\n\n return root.children.size > 0 ? root : null;\n }\n\n private insertPhrase(root: PhraseNode, phrase: string, tokenType: string): void {\n const words = phrase.split(' ');\n let node = root;\n for (const word of words) {\n if (!node.children.has(word)) {\n node.children.set(word, { children: new Map() });\n }\n node = node.children.get(word)!;\n }\n // Only set type if not already set, first-registered (locale) wins\n if (!node.type) {\n node.type = tokenType;\n }\n }\n\n private buildPhraseStartWords(): Set<string> {\n const startWords = new Set<string>();\n\n // Locale phrase first words\n if (this.localePhraseMap) {\n for (const phrase of Object.keys(this.localePhraseMap)) {\n const first = phrase.split(' ')[0].toLowerCase();\n startWords.add(first);\n }\n }\n\n // Provider phrase first words\n for (const tc of this.classes) {\n if (!tc.phrases) continue;\n for (const phrase of Object.keys(tc.phrases)) {\n const first = phrase.split(' ')[0].toLowerCase();\n startWords.add(first);\n }\n }\n\n return startWords;\n }\n}","/**\n * tokenRegistration.ts, Bootstrap for building TokenLookup from locale, units, and phrases.\n *\n * This module centralizes the assembly of the TokenLookup consumed by ExpressionLexer.\n * It merges:\n * 1. Locale keywords (from ILocale.keywordMap)\n * 2. Built-in phrase patterns (to the power of, increase by, etc.)\n * 3. Known unit names (from units.ts)\n *\n * The resulting TokenLookup is frozen. Nothing in the engine consumes it any\n * more (see the deprecation on {@link buildTokenLookup}).\n */\nimport { TokenClassRegistry } from '@solve-js/lexer/TokenClassRegistry';\nimport type { TokenLookup } from '@solve-js/lexer/TokenClassRegistry';\nimport { getLocale, type ILocale } from '@solve-js/constants/locales';\nimport { knownUnits } from '@solve-js/lexer/units';\n// The multi-word expressions handled as compound tokens, matched by the\n// PhraseMatcher (trie-based) in ExpressionLexer.tryMatchPhrase(). The same\n// table the normalizer's phrase trie reads, so the two cannot drift.\nimport { BUILTIN_PHRASES } from '@solve-js/lexer/BuiltinPhrases';\n\n/**\n * Build a TokenLookup from locale keywords, known units, and built-in phrases.\n *\n * Merge order (later overrides earlier):\n * 1. Locale keywords (priority 0, lowest, can be overridden by providers)\n * 2. Built-in phrases (via locale phraseMap)\n * 3. Known units (checked AFTER keyword lookup fails, via unitNames set)\n *\n * @param localeCode - The locale code (e.g., \"en\", \"de\"). Defaults to \"en\".\n * @returns A frozen TokenLookup.\n * @deprecated The lexer never read the lookup it was handed: its keyword, unit\n * and phrase tables are built from the locale and the packages registered\n * with it, and the engine no longer builds one at construction. Kept for\n * callers that build their own; removed in 3.0.\n */\nexport function buildTokenLookup(localeCode = 'en'): TokenLookup {\n const locale: ILocale = getLocale(localeCode);\n const registry = new TokenClassRegistry();\n\n // Layer 1: Locale keywords (priority 0, lowest)\n registry.setLocale(locale.keywordMap, BUILTIN_PHRASES);\n\n // Layer 2: Known units (checked after keyword lookup)\n registry.setUnits(knownUnits);\n\n // Build and return the lookup\n return registry.build();\n}\n"]}
@@ -1,2 +1,2 @@
1
- 'use strict';require('./chunk-NGBBNL4K.cjs');var chunkSGIDBZ4T_cjs=require('./chunk-SGIDBZ4T.cjs');require('./chunk-USQ4KL6S.cjs'),require('./chunk-5IJD5L3O.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-J4LSAHCY.cjs'),require('./chunk-EZKR44MA.cjs'),require('./chunk-CO2BI6WL.cjs');Object.defineProperty(exports,"BUILTIN_PHRASES",{enumerable:true,get:function(){return chunkSGIDBZ4T_cjs.g}});Object.defineProperty(exports,"PhraseTrie",{enumerable:true,get:function(){return chunkSGIDBZ4T_cjs.a}});Object.defineProperty(exports,"TokenNormalizer",{enumerable:true,get:function(){return chunkSGIDBZ4T_cjs.c}});Object.defineProperty(exports,"createBuiltinNormalizerRules",{enumerable:true,get:function(){return chunkSGIDBZ4T_cjs.f}});Object.defineProperty(exports,"createFusedToken",{enumerable:true,get:function(){return chunkSGIDBZ4T_cjs.b}});Object.defineProperty(exports,"implicitMultiplyRule",{enumerable:true,get:function(){return chunkSGIDBZ4T_cjs.d}});//# sourceMappingURL=normalizer.cjs.map
1
+ 'use strict';require('./chunk-NGBBNL4K.cjs');var chunkGBCN7FNV_cjs=require('./chunk-GBCN7FNV.cjs'),chunk77KI7AKJ_cjs=require('./chunk-77KI7AKJ.cjs');require('./chunk-5IJD5L3O.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-J4LSAHCY.cjs'),require('./chunk-EZKR44MA.cjs'),require('./chunk-YBQPEWT7.cjs');Object.defineProperty(exports,"PhraseTrie",{enumerable:true,get:function(){return chunkGBCN7FNV_cjs.a}});Object.defineProperty(exports,"TokenNormalizer",{enumerable:true,get:function(){return chunkGBCN7FNV_cjs.c}});Object.defineProperty(exports,"createBuiltinNormalizerRules",{enumerable:true,get:function(){return chunkGBCN7FNV_cjs.f}});Object.defineProperty(exports,"createFusedToken",{enumerable:true,get:function(){return chunkGBCN7FNV_cjs.b}});Object.defineProperty(exports,"implicitMultiplyRule",{enumerable:true,get:function(){return chunkGBCN7FNV_cjs.d}});Object.defineProperty(exports,"BUILTIN_PHRASES",{enumerable:true,get:function(){return chunk77KI7AKJ_cjs.c}});//# sourceMappingURL=normalizer.cjs.map
2
2
  //# sourceMappingURL=normalizer.cjs.map
@@ -1,5 +1,5 @@
1
- import { N as NormalizerMatch, a as NormalizerRule } from './TokenNormalizer-MXaKLJ_m.cjs';
2
- export { b as NormalizerOptions, T as TokenFusion, c as TokenNormalizer, d as createFusedToken } from './TokenNormalizer-MXaKLJ_m.cjs';
1
+ import { N as NormalizerMatch, a as NormalizerRule } from './TokenNormalizer-CjTDmHgB.cjs';
2
+ export { b as NormalizerOptions, T as TokenFusion, c as TokenNormalizer, d as createFusedToken } from './TokenNormalizer-CjTDmHgB.cjs';
3
3
  import { T as Token } from './Token-CbP_OutD.cjs';
4
4
 
5
5
  /**
@@ -96,6 +96,20 @@ declare class PhraseTrie {
96
96
  canStart(word: string): boolean;
97
97
  }
98
98
 
99
+ /**
100
+ * The engine's own multi-word phrases and the token each one fuses into.
101
+ *
102
+ * One table, read by two consumers: the lexer's token lookup
103
+ * (`lexer/tokenRegistration.ts`) and the normalizer's phrase trie
104
+ * (`engine/ExpressionEngine.ts`, via `normalizer/BuiltinNormalizerRules.ts`).
105
+ * It used to be two hand-copied tables, and they drifted: the lexer's copy
106
+ * never learned "divided by". A phrase added here reaches both.
107
+ *
108
+ * @module BuiltinPhrases
109
+ */
110
+ /** Built-in phrase → token type. See the module doc. */
111
+ declare const BUILTIN_PHRASES: Record<string, string>;
112
+
99
113
  /**
100
114
  * Built-in normalization rules for the {@link TokenNormalizer}.
101
115
  *
@@ -146,13 +160,5 @@ declare function implicitMultiplyRule(priority?: number, canStart?: (word: strin
146
160
  * @returns An array of {@link NormalizerRule} instances ready for registration
147
161
  */
148
162
  declare function createBuiltinNormalizerRules(): NormalizerRule[];
149
- /**
150
- * Built-in phrase → tokenType mappings.
151
- *
152
- * These are registered into the engine's {@link PhraseTrie} during
153
- * construction. Tests that create a standalone {@link TokenNormalizer}
154
- * should register these via {@link TokenNormalizer.addPhrase}.
155
- */
156
- declare const BUILTIN_PHRASES: Record<string, string>;
157
163
 
158
164
  export { BUILTIN_PHRASES, NormalizerMatch, NormalizerRule, PhraseTrie, createBuiltinNormalizerRules, implicitMultiplyRule };
@@ -1,5 +1,5 @@
1
- import { N as NormalizerMatch, a as NormalizerRule } from './TokenNormalizer-OTPS0Otq.js';
2
- export { b as NormalizerOptions, T as TokenFusion, c as TokenNormalizer, d as createFusedToken } from './TokenNormalizer-OTPS0Otq.js';
1
+ import { N as NormalizerMatch, a as NormalizerRule } from './TokenNormalizer-CLBtiE8M.js';
2
+ export { b as NormalizerOptions, T as TokenFusion, c as TokenNormalizer, d as createFusedToken } from './TokenNormalizer-CLBtiE8M.js';
3
3
  import { T as Token } from './Token-CbP_OutD.js';
4
4
 
5
5
  /**
@@ -96,6 +96,20 @@ declare class PhraseTrie {
96
96
  canStart(word: string): boolean;
97
97
  }
98
98
 
99
+ /**
100
+ * The engine's own multi-word phrases and the token each one fuses into.
101
+ *
102
+ * One table, read by two consumers: the lexer's token lookup
103
+ * (`lexer/tokenRegistration.ts`) and the normalizer's phrase trie
104
+ * (`engine/ExpressionEngine.ts`, via `normalizer/BuiltinNormalizerRules.ts`).
105
+ * It used to be two hand-copied tables, and they drifted: the lexer's copy
106
+ * never learned "divided by". A phrase added here reaches both.
107
+ *
108
+ * @module BuiltinPhrases
109
+ */
110
+ /** Built-in phrase → token type. See the module doc. */
111
+ declare const BUILTIN_PHRASES: Record<string, string>;
112
+
99
113
  /**
100
114
  * Built-in normalization rules for the {@link TokenNormalizer}.
101
115
  *
@@ -146,13 +160,5 @@ declare function implicitMultiplyRule(priority?: number, canStart?: (word: strin
146
160
  * @returns An array of {@link NormalizerRule} instances ready for registration
147
161
  */
148
162
  declare function createBuiltinNormalizerRules(): NormalizerRule[];
149
- /**
150
- * Built-in phrase → tokenType mappings.
151
- *
152
- * These are registered into the engine's {@link PhraseTrie} during
153
- * construction. Tests that create a standalone {@link TokenNormalizer}
154
- * should register these via {@link TokenNormalizer.addPhrase}.
155
- */
156
- declare const BUILTIN_PHRASES: Record<string, string>;
157
163
 
158
164
  export { BUILTIN_PHRASES, NormalizerMatch, NormalizerRule, PhraseTrie, createBuiltinNormalizerRules, implicitMultiplyRule };
@@ -1,2 +1,2 @@
1
- import'./chunk-2RWAXT6O.js';export{g as BUILTIN_PHRASES,a as PhraseTrie,c as TokenNormalizer,f as createBuiltinNormalizerRules,b as createFusedToken,d as implicitMultiplyRule}from'./chunk-4DJJIUQF.js';import'./chunk-AF7HQN6I.js';import'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';import'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import'./chunk-PIZQIQVM.js';//# sourceMappingURL=normalizer.js.map
1
+ import'./chunk-2RWAXT6O.js';export{a as PhraseTrie,c as TokenNormalizer,f as createBuiltinNormalizerRules,b as createFusedToken,d as implicitMultiplyRule}from'./chunk-72PYPENZ.js';export{c as BUILTIN_PHRASES}from'./chunk-OB2VX4IL.js';import'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';import'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import'./chunk-57PSJQQW.js';//# sourceMappingURL=normalizer.js.map
2
2
  //# sourceMappingURL=normalizer.js.map
package/dist/packages.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var chunkFMMT5C5H_cjs=require('./chunk-FMMT5C5H.cjs');require('./chunk-TL545PXW.cjs');var chunkN37PUZJR_cjs=require('./chunk-N37PUZJR.cjs');require('./chunk-EN3CDYOS.cjs'),require('./chunk-SGIDBZ4T.cjs'),require('./chunk-UURM7P3P.cjs'),require('./chunk-ZLRJ7TDP.cjs'),require('./chunk-XDXIPVZB.cjs'),require('./chunk-6YM67DWH.cjs'),require('./chunk-ABVDKMNF.cjs'),require('./chunk-TLG7VZRX.cjs'),require('./chunk-5TVI2UPZ.cjs'),require('./chunk-J7ABVGZH.cjs'),require('./chunk-75JLWK4L.cjs'),require('./chunk-ZKFCKAIX.cjs'),require('./chunk-USQ4KL6S.cjs'),require('./chunk-5IJD5L3O.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-J4LSAHCY.cjs'),require('./chunk-EZKR44MA.cjs'),require('./chunk-CO2BI6WL.cjs');Object.defineProperty(exports,"ARITHMETIC_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.a}});Object.defineProperty(exports,"BIGINT_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.n}});Object.defineProperty(exports,"BUILTIN_PACKAGES",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.z}});Object.defineProperty(exports,"CONDITIONALS_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.o}});Object.defineProperty(exports,"CONVERTERS_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.p}});Object.defineProperty(exports,"CURRENCY_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.j}});Object.defineProperty(exports,"DATETIME_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.d}});Object.defineProperty(exports,"DICE_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.f}});Object.defineProperty(exports,"FINANCE_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.r}});Object.defineProperty(exports,"FUNCTION_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.c}});Object.defineProperty(exports,"LINES_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.w}});Object.defineProperty(exports,"MAPREDUCE_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.m}});Object.defineProperty(exports,"MATHPHRASES_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.q}});Object.defineProperty(exports,"MATRIX_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.l}});Object.defineProperty(exports,"PERCENTAGE_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.b}});Object.defineProperty(exports,"TABLES_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.x}});Object.defineProperty(exports,"TAGS_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.y}});Object.defineProperty(exports,"TIME_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.e}});Object.defineProperty(exports,"UOM_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.h}});Object.defineProperty(exports,"VARIABLES_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.g}});Object.defineProperty(exports,"VECTOR_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.k}});Object.defineProperty(exports,"WEATHER_PACKAGE",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.s}});Object.defineProperty(exports,"createCryptoPackage",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.u}});Object.defineProperty(exports,"createCurrencyPackage",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.i}});Object.defineProperty(exports,"createKnowledgePackage",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.v}});Object.defineProperty(exports,"createStocksPackage",{enumerable:true,get:function(){return chunkFMMT5C5H_cjs.t}});Object.defineProperty(exports,"SYMBOLIC_PACKAGE",{enumerable:true,get:function(){return chunkN37PUZJR_cjs.a}});//# sourceMappingURL=packages.cjs.map
1
+ 'use strict';var chunkUV3EUIBT_cjs=require('./chunk-UV3EUIBT.cjs');require('./chunk-NEGZZB7F.cjs');var chunkRAPEZR5L_cjs=require('./chunk-RAPEZR5L.cjs');require('./chunk-FYTB7SDP.cjs'),require('./chunk-GBCN7FNV.cjs'),require('./chunk-UURM7P3P.cjs'),require('./chunk-ZLRJ7TDP.cjs'),require('./chunk-634ILVMP.cjs'),require('./chunk-FYAMQFZZ.cjs'),require('./chunk-ABVDKMNF.cjs'),require('./chunk-TLG7VZRX.cjs'),require('./chunk-5TVI2UPZ.cjs'),require('./chunk-WGP4UUO5.cjs'),require('./chunk-SQHBOWES.cjs'),require('./chunk-ZKFCKAIX.cjs'),require('./chunk-77KI7AKJ.cjs'),require('./chunk-5IJD5L3O.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-J4LSAHCY.cjs'),require('./chunk-EZKR44MA.cjs'),require('./chunk-YBQPEWT7.cjs');Object.defineProperty(exports,"ARITHMETIC_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.a}});Object.defineProperty(exports,"BIGINT_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.n}});Object.defineProperty(exports,"BUILTIN_PACKAGES",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.z}});Object.defineProperty(exports,"CONDITIONALS_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.o}});Object.defineProperty(exports,"CONVERTERS_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.p}});Object.defineProperty(exports,"CURRENCY_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.j}});Object.defineProperty(exports,"DATETIME_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.d}});Object.defineProperty(exports,"DICE_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.f}});Object.defineProperty(exports,"FINANCE_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.r}});Object.defineProperty(exports,"FUNCTION_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.c}});Object.defineProperty(exports,"LINES_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.w}});Object.defineProperty(exports,"MAPREDUCE_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.m}});Object.defineProperty(exports,"MATHPHRASES_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.q}});Object.defineProperty(exports,"MATRIX_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.l}});Object.defineProperty(exports,"PERCENTAGE_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.b}});Object.defineProperty(exports,"TABLES_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.x}});Object.defineProperty(exports,"TAGS_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.y}});Object.defineProperty(exports,"TIME_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.e}});Object.defineProperty(exports,"UOM_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.h}});Object.defineProperty(exports,"VARIABLES_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.g}});Object.defineProperty(exports,"VECTOR_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.k}});Object.defineProperty(exports,"WEATHER_PACKAGE",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.s}});Object.defineProperty(exports,"createCryptoPackage",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.u}});Object.defineProperty(exports,"createCurrencyPackage",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.i}});Object.defineProperty(exports,"createKnowledgePackage",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.v}});Object.defineProperty(exports,"createStocksPackage",{enumerable:true,get:function(){return chunkUV3EUIBT_cjs.t}});Object.defineProperty(exports,"SYMBOLIC_PACKAGE",{enumerable:true,get:function(){return chunkRAPEZR5L_cjs.a}});//# sourceMappingURL=packages.cjs.map
2
2
  //# sourceMappingURL=packages.cjs.map
@@ -1,16 +1,16 @@
1
- import { I as IEnginePackage } from './PackageRegistry-rMGnTh7W.cjs';
2
- import './Parselet-Bkbp9CKD.cjs';
3
- import './BytecodeBuilder-aqVa7Plx.cjs';
1
+ import { I as IEnginePackage } from './PackageRegistry-Dvn4i2QK.cjs';
2
+ import './Parselet-BawfGuTF.cjs';
3
+ import './BytecodeBuilder-DSWKZi4f.cjs';
4
4
  import './Token-CbP_OutD.cjs';
5
- import './pipeline-B4wf3M1h.cjs';
6
- import './Value-DCTqTSeP.cjs';
7
- import './Lexer-CCHFDcgP.cjs';
5
+ import './pipeline-69q2tsLE.cjs';
6
+ import './Value-Ds3Gy07C.cjs';
7
+ import './Lexer-aB95pjoX.cjs';
8
+ import './EngineError-fR1K1rvx.cjs';
8
9
  import './resolvers.cjs';
9
10
  import '@tanstack/query-core';
10
- import './TokenNormalizer-MXaKLJ_m.cjs';
11
- import './ScopeManager-bCYewWVt.cjs';
12
- import './EngineError-DTk7I7hZ.cjs';
13
- import './Configuration-BGQn-cJ8.cjs';
11
+ import './TokenNormalizer-CjTDmHgB.cjs';
12
+ import './ScopeManager-CdwX0VTw.cjs';
13
+ import './Configuration-DnzYPmoK.cjs';
14
14
 
15
15
  /** Core arithmetic: numbers, `()` grouping, `pi`/`e` constants, `+ - * / % ^`, bitwise `<< >> & | ^`, and their `*_by` word forms. */
16
16
  declare const ARITHMETIC_PACKAGE: IEnginePackage;
@@ -1,16 +1,16 @@
1
- import { I as IEnginePackage } from './PackageRegistry-BRoVOYzg.js';
2
- import './Parselet-B-WyUtX4.js';
3
- import './BytecodeBuilder-aqVa7Plx.js';
1
+ import { I as IEnginePackage } from './PackageRegistry-DT-x32OM.js';
2
+ import './Parselet-DqTbbtWA.js';
3
+ import './BytecodeBuilder-DSWKZi4f.js';
4
4
  import './Token-CbP_OutD.js';
5
- import './pipeline-QIT4iD8f.js';
6
- import './Value-DCTqTSeP.js';
7
- import './Lexer-CqagTewQ.js';
5
+ import './pipeline-DTqGLPsV.js';
6
+ import './Value-Ds3Gy07C.js';
7
+ import './Lexer-Bmctxl0n.js';
8
+ import './EngineError-fR1K1rvx.js';
8
9
  import './resolvers.js';
9
10
  import '@tanstack/query-core';
10
- import './TokenNormalizer-OTPS0Otq.js';
11
- import './ScopeManager-gB9UengK.js';
12
- import './EngineError-DTk7I7hZ.js';
13
- import './Configuration-BGQn-cJ8.js';
11
+ import './TokenNormalizer-CLBtiE8M.js';
12
+ import './ScopeManager-B636am7Y.js';
13
+ import './Configuration-DnzYPmoK.js';
14
14
 
15
15
  /** Core arithmetic: numbers, `()` grouping, `pi`/`e` constants, `+ - * / % ^`, bitwise `<< >> & | ^`, and their `*_by` word forms. */
16
16
  declare const ARITHMETIC_PACKAGE: IEnginePackage;
package/dist/packages.js CHANGED
@@ -1,2 +1,2 @@
1
- export{a as ARITHMETIC_PACKAGE,n as BIGINT_PACKAGE,z as BUILTIN_PACKAGES,o as CONDITIONALS_PACKAGE,p as CONVERTERS_PACKAGE,j as CURRENCY_PACKAGE,d as DATETIME_PACKAGE,f as DICE_PACKAGE,r as FINANCE_PACKAGE,c as FUNCTION_PACKAGE,w as LINES_PACKAGE,m as MAPREDUCE_PACKAGE,q as MATHPHRASES_PACKAGE,l as MATRIX_PACKAGE,b as PERCENTAGE_PACKAGE,x as TABLES_PACKAGE,y as TAGS_PACKAGE,e as TIME_PACKAGE,h as UOM_PACKAGE,g as VARIABLES_PACKAGE,k as VECTOR_PACKAGE,s as WEATHER_PACKAGE,u as createCryptoPackage,i as createCurrencyPackage,v as createKnowledgePackage,t as createStocksPackage}from'./chunk-HZOLIL5T.js';import'./chunk-MRRMIBHE.js';export{a as SYMBOLIC_PACKAGE}from'./chunk-HMC7FJO7.js';import'./chunk-O3BDXOQJ.js';import'./chunk-4DJJIUQF.js';import'./chunk-76F3LCIL.js';import'./chunk-TCZSPH4A.js';import'./chunk-A5M4QZIK.js';import'./chunk-EQDT42JG.js';import'./chunk-TZYMXNIB.js';import'./chunk-HFKDWQUL.js';import'./chunk-5TCSFTZD.js';import'./chunk-KEA5HRL3.js';import'./chunk-3GR46UOX.js';import'./chunk-4CNYGIND.js';import'./chunk-AF7HQN6I.js';import'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';import'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import'./chunk-PIZQIQVM.js';//# sourceMappingURL=packages.js.map
1
+ export{a as ARITHMETIC_PACKAGE,n as BIGINT_PACKAGE,z as BUILTIN_PACKAGES,o as CONDITIONALS_PACKAGE,p as CONVERTERS_PACKAGE,j as CURRENCY_PACKAGE,d as DATETIME_PACKAGE,f as DICE_PACKAGE,r as FINANCE_PACKAGE,c as FUNCTION_PACKAGE,w as LINES_PACKAGE,m as MAPREDUCE_PACKAGE,q as MATHPHRASES_PACKAGE,l as MATRIX_PACKAGE,b as PERCENTAGE_PACKAGE,x as TABLES_PACKAGE,y as TAGS_PACKAGE,e as TIME_PACKAGE,h as UOM_PACKAGE,g as VARIABLES_PACKAGE,k as VECTOR_PACKAGE,s as WEATHER_PACKAGE,u as createCryptoPackage,i as createCurrencyPackage,v as createKnowledgePackage,t as createStocksPackage}from'./chunk-MZMA32NE.js';import'./chunk-OONQ3V3I.js';export{a as SYMBOLIC_PACKAGE}from'./chunk-63ZOOUOL.js';import'./chunk-EL2XUOWX.js';import'./chunk-72PYPENZ.js';import'./chunk-76F3LCIL.js';import'./chunk-TCZSPH4A.js';import'./chunk-UF5XMZTT.js';import'./chunk-XHQYHXRE.js';import'./chunk-TZYMXNIB.js';import'./chunk-HFKDWQUL.js';import'./chunk-5TCSFTZD.js';import'./chunk-RDYXH7ML.js';import'./chunk-NMU5E7W7.js';import'./chunk-4CNYGIND.js';import'./chunk-OB2VX4IL.js';import'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';import'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import'./chunk-57PSJQQW.js';//# sourceMappingURL=packages.js.map
2
2
  //# sourceMappingURL=packages.js.map
package/dist/parser.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var chunkJYLNQOPU_cjs=require('./chunk-JYLNQOPU.cjs');require('./chunk-HG4NPDN5.cjs');var chunkEN3CDYOS_cjs=require('./chunk-EN3CDYOS.cjs'),chunkABVDKMNF_cjs=require('./chunk-ABVDKMNF.cjs');require('./chunk-5IJD5L3O.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-CO2BI6WL.cjs');Object.defineProperty(exports,"ParseletRegistry",{enumerable:true,get:function(){return chunkJYLNQOPU_cjs.b}});Object.defineProperty(exports,"Parser",{enumerable:true,get:function(){return chunkJYLNQOPU_cjs.a}});Object.defineProperty(exports,"PrecedenceParser",{enumerable:true,get:function(){return chunkJYLNQOPU_cjs.a}});Object.defineProperty(exports,"sharedParseletRegistry",{enumerable:true,get:function(){return chunkJYLNQOPU_cjs.c}});Object.defineProperty(exports,"BindingPower",{enumerable:true,get:function(){return chunkEN3CDYOS_cjs.a}});Object.defineProperty(exports,"BytecodeBuilder",{enumerable:true,get:function(){return chunkEN3CDYOS_cjs.d}});Object.defineProperty(exports,"buildBindingPowerTable",{enumerable:true,get:function(){return chunkEN3CDYOS_cjs.b}});Object.defineProperty(exports,"invalidateBindingPowerTable",{enumerable:true,get:function(){return chunkEN3CDYOS_cjs.c}});Object.defineProperty(exports,"OpCode",{enumerable:true,get:function(){return chunkABVDKMNF_cjs.a}});Object.defineProperty(exports,"getOpCodeName",{enumerable:true,get:function(){return chunkABVDKMNF_cjs.b}});//# sourceMappingURL=parser.cjs.map
1
+ 'use strict';var chunkVMSCRVNX_cjs=require('./chunk-VMSCRVNX.cjs');require('./chunk-HG4NPDN5.cjs');var chunkFYTB7SDP_cjs=require('./chunk-FYTB7SDP.cjs'),chunkABVDKMNF_cjs=require('./chunk-ABVDKMNF.cjs');require('./chunk-5IJD5L3O.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-YBQPEWT7.cjs');Object.defineProperty(exports,"ParseletRegistry",{enumerable:true,get:function(){return chunkVMSCRVNX_cjs.b}});Object.defineProperty(exports,"Parser",{enumerable:true,get:function(){return chunkVMSCRVNX_cjs.a}});Object.defineProperty(exports,"PrecedenceParser",{enumerable:true,get:function(){return chunkVMSCRVNX_cjs.a}});Object.defineProperty(exports,"sharedParseletRegistry",{enumerable:true,get:function(){return chunkVMSCRVNX_cjs.c}});Object.defineProperty(exports,"BindingPower",{enumerable:true,get:function(){return chunkFYTB7SDP_cjs.a}});Object.defineProperty(exports,"BytecodeBuilder",{enumerable:true,get:function(){return chunkFYTB7SDP_cjs.d}});Object.defineProperty(exports,"buildBindingPowerTable",{enumerable:true,get:function(){return chunkFYTB7SDP_cjs.b}});Object.defineProperty(exports,"invalidateBindingPowerTable",{enumerable:true,get:function(){return chunkFYTB7SDP_cjs.c}});Object.defineProperty(exports,"OpCode",{enumerable:true,get:function(){return chunkABVDKMNF_cjs.a}});Object.defineProperty(exports,"getOpCodeName",{enumerable:true,get:function(){return chunkABVDKMNF_cjs.b}});//# sourceMappingURL=parser.cjs.map
2
2
  //# sourceMappingURL=parser.cjs.map
package/dist/parser.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- export { I as InfixParselet, P as ParseletRegistry, a as Parser, a as PrecedenceParser, b as PrefixParselet, s as sharedParseletRegistry } from './Parselet-Bkbp9CKD.cjs';
2
- export { B as BytecodeBuilder, a as BytecodeProgram, O as OpCode, g as getOpCodeName } from './BytecodeBuilder-aqVa7Plx.cjs';
1
+ export { I as InfixParselet, P as ParseletRegistry, a as Parser, a as PrecedenceParser, b as PrefixParselet, s as sharedParseletRegistry } from './Parselet-BawfGuTF.cjs';
2
+ export { B as BytecodeBuilder, a as BytecodeProgram, O as OpCode, g as getOpCodeName } from './BytecodeBuilder-DSWKZi4f.cjs';
3
3
  import './Token-CbP_OutD.cjs';
4
- import './pipeline-B4wf3M1h.cjs';
5
- import './Value-DCTqTSeP.cjs';
4
+ import './pipeline-69q2tsLE.cjs';
5
+ import './Value-Ds3Gy07C.cjs';
6
6
 
7
7
  /**
8
8
  * Named precedence levels for the Pratt parser, from loosest (`Lowest`) to
package/dist/parser.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { I as InfixParselet, P as ParseletRegistry, a as Parser, a as PrecedenceParser, b as PrefixParselet, s as sharedParseletRegistry } from './Parselet-B-WyUtX4.js';
2
- export { B as BytecodeBuilder, a as BytecodeProgram, O as OpCode, g as getOpCodeName } from './BytecodeBuilder-aqVa7Plx.js';
1
+ export { I as InfixParselet, P as ParseletRegistry, a as Parser, a as PrecedenceParser, b as PrefixParselet, s as sharedParseletRegistry } from './Parselet-DqTbbtWA.js';
2
+ export { B as BytecodeBuilder, a as BytecodeProgram, O as OpCode, g as getOpCodeName } from './BytecodeBuilder-DSWKZi4f.js';
3
3
  import './Token-CbP_OutD.js';
4
- import './pipeline-QIT4iD8f.js';
5
- import './Value-DCTqTSeP.js';
4
+ import './pipeline-DTqGLPsV.js';
5
+ import './Value-Ds3Gy07C.js';
6
6
 
7
7
  /**
8
8
  * Named precedence levels for the Pratt parser, from loosest (`Lowest`) to
package/dist/parser.js CHANGED
@@ -1,2 +1,2 @@
1
- export{b as ParseletRegistry,a as Parser,a as PrecedenceParser,c as sharedParseletRegistry}from'./chunk-JVMINMAB.js';import'./chunk-JP4JMQOG.js';export{a as BindingPower,d as BytecodeBuilder,b as buildBindingPowerTable,c as invalidateBindingPowerTable}from'./chunk-O3BDXOQJ.js';export{a as OpCode,b as getOpCodeName}from'./chunk-TZYMXNIB.js';import'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';import'./chunk-PIZQIQVM.js';//# sourceMappingURL=parser.js.map
1
+ export{b as ParseletRegistry,a as Parser,a as PrecedenceParser,c as sharedParseletRegistry}from'./chunk-4BRTUFTH.js';import'./chunk-JP4JMQOG.js';export{a as BindingPower,d as BytecodeBuilder,b as buildBindingPowerTable,c as invalidateBindingPowerTable}from'./chunk-EL2XUOWX.js';export{a as OpCode,b as getOpCodeName}from'./chunk-TZYMXNIB.js';import'./chunk-IJMNVBIS.js';import'./chunk-LHLW7JLS.js';import'./chunk-57PSJQQW.js';//# sourceMappingURL=parser.js.map
2
2
  //# sourceMappingURL=parser.js.map