solve-engine 1.0.1 → 1.1.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 (237) hide show
  1. package/dist/{BytecodeBuilder-B0xskcv5.d.cts → BytecodeBuilder-Bp9xeTmX.d.cts} +4 -0
  2. package/dist/{BytecodeBuilder-B0xskcv5.d.ts → BytecodeBuilder-Bp9xeTmX.d.ts} +4 -0
  3. package/dist/{Configuration-B-G5gTRn.d.cts → Configuration-C9W8tJv_.d.cts} +53 -1
  4. package/dist/{Configuration-B-G5gTRn.d.ts → Configuration-C9W8tJv_.d.ts} +53 -1
  5. package/dist/{EngineError-LU7W7AgI.d.cts → EngineError-B61GS1jp.d.cts} +14 -0
  6. package/dist/{EngineError-LU7W7AgI.d.ts → EngineError-B61GS1jp.d.ts} +14 -0
  7. package/dist/FormattingSettings-CJHyxcYu.d.cts +27 -0
  8. package/dist/FormattingSettings-CJHyxcYu.d.ts +27 -0
  9. package/dist/{Lexer-D78E2yDW.d.cts → Lexer-BOs7euZe.d.cts} +58 -1
  10. package/dist/{Lexer-BN5mt30n.d.ts → Lexer-CSI_lwbW.d.ts} +58 -1
  11. package/dist/PackageCompatibility-B-7rK1TD.d.cts +76 -0
  12. package/dist/PackageCompatibility-Dh59eF-X.d.ts +76 -0
  13. package/dist/{PackageRegistry-B37mRvvz.d.cts → PackageRegistry-BHWJP83F.d.cts} +449 -11
  14. package/dist/{PackageRegistry-DCUEzbQt.d.ts → PackageRegistry-_8rDlvxI.d.ts} +449 -11
  15. package/dist/{Parselet-BaySkMV3.d.ts → Parselet-BBT8riYh.d.ts} +12 -3
  16. package/dist/{Parselet-DuI1Pjiq.d.cts → Parselet-BHcgK9S7.d.cts} +12 -3
  17. package/dist/{ScopeManager-B6GzdhVG.d.cts → ScopeManager-8vf02dwj.d.cts} +56 -5
  18. package/dist/{ScopeManager-udv4Twwq.d.ts → ScopeManager-CxA24W5n.d.ts} +56 -5
  19. package/dist/{Token-BzG5G4ja.d.cts → Token-B1hdkedD.d.cts} +9 -0
  20. package/dist/{Token-BzG5G4ja.d.ts → Token-B1hdkedD.d.ts} +9 -0
  21. package/dist/{TokenNormalizer-t_GotBxr.d.ts → TokenNormalizer-C6VzZgHa.d.ts} +1 -1
  22. package/dist/{TokenNormalizer-DGVa24Q-.d.cts → TokenNormalizer-DRc1Js1V.d.cts} +1 -1
  23. package/dist/{VMCheckpoints-DwLjivM7.d.cts → VMCheckpoints-ELYqITdF.d.cts} +3 -3
  24. package/dist/{VMCheckpoints-BiaIlOOY.d.ts → VMCheckpoints-MK--EBH2.d.ts} +3 -3
  25. package/dist/{Value-CXJqDH9J.d.cts → Value-BUi1RA3S.d.cts} +124 -5
  26. package/dist/{Value-CXJqDH9J.d.ts → Value-BUi1RA3S.d.ts} +124 -5
  27. package/dist/WorkerError-_-RkoQ5P.d.ts +75 -0
  28. package/dist/WorkerError-gzmaopj2.d.cts +75 -0
  29. package/dist/{chunk-GQCOSXMG.js → chunk-267JPOTF.js} +43 -5
  30. package/dist/chunk-267JPOTF.js.map +1 -0
  31. package/dist/{chunk-JMXUNXQS.cjs → chunk-2TZKENDH.cjs} +51 -8
  32. package/dist/chunk-2TZKENDH.cjs.map +1 -0
  33. package/dist/chunk-3OWCDIPN.js +215 -0
  34. package/dist/chunk-3OWCDIPN.js.map +1 -0
  35. package/dist/{chunk-VB37OC6I.js → chunk-4D6NIHE2.js} +40 -3
  36. package/dist/chunk-4D6NIHE2.js.map +1 -0
  37. package/dist/{chunk-TY3TLZAW.cjs → chunk-536WPM2V.cjs} +18 -2
  38. package/dist/chunk-536WPM2V.cjs.map +1 -0
  39. package/dist/chunk-5HRB36DK.js +405 -0
  40. package/dist/chunk-5HRB36DK.js.map +1 -0
  41. package/dist/chunk-5ON7PUAZ.js +12 -0
  42. package/dist/chunk-5ON7PUAZ.js.map +1 -0
  43. package/dist/{chunk-KV7UW6T6.js → chunk-7KYSUDQO.js} +12 -5
  44. package/dist/chunk-7KYSUDQO.js.map +1 -0
  45. package/dist/{chunk-6WFMPTGB.cjs → chunk-7ZX6B7SY.cjs} +774 -528
  46. package/dist/chunk-7ZX6B7SY.cjs.map +1 -0
  47. package/dist/chunk-ALYRJ72W.cjs +434 -0
  48. package/dist/chunk-ALYRJ72W.cjs.map +1 -0
  49. package/dist/{chunk-5KMIY374.cjs → chunk-B4HBEFTB.cjs} +17 -2
  50. package/dist/chunk-B4HBEFTB.cjs.map +1 -0
  51. package/dist/chunk-B7NLZMQ3.cjs +74 -0
  52. package/dist/chunk-B7NLZMQ3.cjs.map +1 -0
  53. package/dist/{chunk-UQ3UIZJC.js → chunk-BLI4NIQY.js} +6 -2
  54. package/dist/chunk-BLI4NIQY.js.map +1 -0
  55. package/dist/{chunk-BHTNFEGZ.cjs → chunk-C75AFGVD.cjs} +11 -11
  56. package/dist/{chunk-BHTNFEGZ.cjs.map → chunk-C75AFGVD.cjs.map} +1 -1
  57. package/dist/{chunk-G535KJEG.js → chunk-CCBZZQAE.js} +2 -2
  58. package/dist/{chunk-G535KJEG.js.map → chunk-CCBZZQAE.js.map} +1 -1
  59. package/dist/chunk-CKQMXMHR.cjs +219 -0
  60. package/dist/chunk-CKQMXMHR.cjs.map +1 -0
  61. package/dist/{chunk-PFUESQTW.cjs → chunk-EJ3ILXX6.cjs} +48 -2
  62. package/dist/chunk-EJ3ILXX6.cjs.map +1 -0
  63. package/dist/{chunk-526PMQOA.js → chunk-ENKKJYD3.js} +10 -4
  64. package/dist/chunk-ENKKJYD3.js.map +1 -0
  65. package/dist/{chunk-5X2PTP6F.cjs → chunk-ENRIK36Q.cjs} +2 -12
  66. package/dist/chunk-ENRIK36Q.cjs.map +1 -0
  67. package/dist/{chunk-3D7V24DG.js → chunk-ERCOHGXD.js} +17 -2
  68. package/dist/chunk-ERCOHGXD.js.map +1 -0
  69. package/dist/{chunk-IF532O7C.js → chunk-FD5ZZHEU.js} +3 -12
  70. package/dist/chunk-FD5ZZHEU.js.map +1 -0
  71. package/dist/{chunk-TBN7DEHO.js → chunk-G7Z4HJQA.js} +11 -5
  72. package/dist/chunk-G7Z4HJQA.js.map +1 -0
  73. package/dist/{chunk-QY25VWBF.js → chunk-GQMUHVE3.js} +142 -6
  74. package/dist/chunk-GQMUHVE3.js.map +1 -0
  75. package/dist/chunk-GUG7SNSV.js +1764 -0
  76. package/dist/chunk-GUG7SNSV.js.map +1 -0
  77. package/dist/{chunk-UM6BVY2S.cjs → chunk-HIQ5HSZL.cjs} +175 -43
  78. package/dist/chunk-HIQ5HSZL.cjs.map +1 -0
  79. package/dist/{chunk-HVQFNJKE.cjs → chunk-HVRVSI2Z.cjs} +104 -86
  80. package/dist/chunk-HVRVSI2Z.cjs.map +1 -0
  81. package/dist/{chunk-3LAEG75D.js → chunk-I4GAWIPW.js} +24 -6
  82. package/dist/chunk-I4GAWIPW.js.map +1 -0
  83. package/dist/{chunk-PA4VC73I.cjs → chunk-J45BCEZ4.cjs} +33 -27
  84. package/dist/chunk-J45BCEZ4.cjs.map +1 -0
  85. package/dist/{chunk-V5PYO44Y.js → chunk-JIPATHVY.js} +1853 -2638
  86. package/dist/chunk-JIPATHVY.js.map +1 -0
  87. package/dist/{chunk-YPPPYLSR.js → chunk-JJIXHXFQ.js} +5 -5
  88. package/dist/{chunk-YPPPYLSR.js.map → chunk-JJIXHXFQ.js.map} +1 -1
  89. package/dist/chunk-L2TE7PMO.cjs +14 -0
  90. package/dist/chunk-L2TE7PMO.cjs.map +1 -0
  91. package/dist/{chunk-B7TLZABL.cjs → chunk-MG6Q3DUO.cjs} +1962 -2746
  92. package/dist/chunk-MG6Q3DUO.cjs.map +1 -0
  93. package/dist/{chunk-R3PY4G7J.js → chunk-MVTOCRV2.js} +48 -3
  94. package/dist/chunk-MVTOCRV2.js.map +1 -0
  95. package/dist/{chunk-Y7FT4IQT.js → chunk-NKW7LKYU.js} +266 -28
  96. package/dist/chunk-NKW7LKYU.js.map +1 -0
  97. package/dist/{chunk-O3ANBHSA.js → chunk-NNQ2TYDF.js} +123 -5
  98. package/dist/chunk-NNQ2TYDF.js.map +1 -0
  99. package/dist/{chunk-5F4C26RU.js → chunk-OADDUPT3.js} +4 -4
  100. package/dist/{chunk-5F4C26RU.js.map → chunk-OADDUPT3.js.map} +1 -1
  101. package/dist/{chunk-3AFRJYP4.cjs → chunk-OTN6SZOD.cjs} +1868 -393
  102. package/dist/chunk-OTN6SZOD.cjs.map +1 -0
  103. package/dist/{chunk-5LI5EPGJ.cjs → chunk-QFTDTX6K.cjs} +40 -3
  104. package/dist/chunk-QFTDTX6K.cjs.map +1 -0
  105. package/dist/{chunk-HMOISHXR.js → chunk-RRLHC37V.js} +1530 -57
  106. package/dist/chunk-RRLHC37V.js.map +1 -0
  107. package/dist/chunk-SNHVVOJK.cjs +1768 -0
  108. package/dist/chunk-SNHVVOJK.cjs.map +1 -0
  109. package/dist/{chunk-HDP7VK3C.cjs → chunk-SRGQ72IR.cjs} +649 -349
  110. package/dist/chunk-SRGQ72IR.cjs.map +1 -0
  111. package/dist/{chunk-4B2CNWQU.cjs → chunk-SSV46KFA.cjs} +14 -7
  112. package/dist/chunk-SSV46KFA.cjs.map +1 -0
  113. package/dist/{chunk-AJA6LUI7.js → chunk-UO6BUV6K.js} +18 -2
  114. package/dist/chunk-UO6BUV6K.js.map +1 -0
  115. package/dist/chunk-WWQEY7BV.js +67 -0
  116. package/dist/chunk-WWQEY7BV.js.map +1 -0
  117. package/dist/{chunk-5WVP4YHP.js → chunk-WXEHD6TT.js} +333 -33
  118. package/dist/chunk-WXEHD6TT.js.map +1 -0
  119. package/dist/{chunk-47LRVGOT.cjs → chunk-XA4CKRML.cjs} +2 -2
  120. package/dist/{chunk-47LRVGOT.cjs.map → chunk-XA4CKRML.cjs.map} +1 -1
  121. package/dist/{chunk-6KFYJ6TD.cjs → chunk-XIYYHA65.cjs} +6 -2
  122. package/dist/chunk-XIYYHA65.cjs.map +1 -0
  123. package/dist/{chunk-KBSXGXPM.cjs → chunk-XJGJCF2R.cjs} +6 -6
  124. package/dist/{chunk-KBSXGXPM.cjs.map → chunk-XJGJCF2R.cjs.map} +1 -1
  125. package/dist/{chunk-YWQ6V4ZN.cjs → chunk-YTIYVHL7.cjs} +211 -75
  126. package/dist/chunk-YTIYVHL7.cjs.map +1 -0
  127. package/dist/{chunk-TMA4RCEN.js → chunk-Z7XGGLI2.js} +3 -3
  128. package/dist/{chunk-TMA4RCEN.js.map → chunk-Z7XGGLI2.js.map} +1 -1
  129. package/dist/{chunk-A2N2GFCG.cjs → chunk-ZVTWQLK4.cjs} +10 -10
  130. package/dist/{chunk-A2N2GFCG.cjs.map → chunk-ZVTWQLK4.cjs.map} +1 -1
  131. package/dist/{chunk-2XLQPQKI.cjs → chunk-ZXCESUJS.cjs} +15 -9
  132. package/dist/chunk-ZXCESUJS.cjs.map +1 -0
  133. package/dist/constants.cjs +5 -5
  134. package/dist/constants.d.cts +1 -1
  135. package/dist/constants.d.ts +1 -1
  136. package/dist/constants.js +2 -2
  137. package/dist/engine.cjs +52 -35
  138. package/dist/engine.d.cts +13 -13
  139. package/dist/engine.d.ts +13 -13
  140. package/dist/engine.js +26 -21
  141. package/dist/errors.cjs +44 -19
  142. package/dist/errors.d.cts +3 -2
  143. package/dist/errors.d.ts +3 -2
  144. package/dist/errors.js +2 -1
  145. package/dist/format.cjs +19 -169
  146. package/dist/format.cjs.map +1 -1
  147. package/dist/format.d.cts +18 -26
  148. package/dist/format.d.ts +18 -26
  149. package/dist/format.js +7 -171
  150. package/dist/format.js.map +1 -1
  151. package/dist/index.cjs +250 -31
  152. package/dist/index.cjs.map +1 -1
  153. package/dist/index.d.cts +110 -74
  154. package/dist/index.d.ts +110 -74
  155. package/dist/index.js +228 -23
  156. package/dist/index.js.map +1 -1
  157. package/dist/language.cjs +9 -9
  158. package/dist/language.d.cts +12 -12
  159. package/dist/language.d.ts +12 -12
  160. package/dist/language.js +3 -3
  161. package/dist/lexer.cjs +16 -16
  162. package/dist/lexer.d.cts +3 -3
  163. package/dist/lexer.d.ts +3 -3
  164. package/dist/lexer.js +5 -5
  165. package/dist/normalizer.cjs +10 -10
  166. package/dist/normalizer.d.cts +3 -3
  167. package/dist/normalizer.d.ts +3 -3
  168. package/dist/normalizer.js +4 -4
  169. package/dist/packages.cjs +45 -36
  170. package/dist/packages.d.cts +135 -31
  171. package/dist/packages.d.ts +135 -31
  172. package/dist/packages.js +14 -13
  173. package/dist/parser.cjs +16 -16
  174. package/dist/parser.d.cts +6 -5
  175. package/dist/parser.d.ts +6 -5
  176. package/dist/parser.js +6 -6
  177. package/dist/{pipeline-BEb3hujr.d.cts → pipeline-CtfJtPQc.d.cts} +3 -3
  178. package/dist/{pipeline-B6k5lCB7.d.ts → pipeline-DCd5M6Gk.d.ts} +3 -3
  179. package/dist/resolvers.d.cts +3 -3
  180. package/dist/resolvers.d.ts +3 -3
  181. package/dist/testing.cjs +478 -0
  182. package/dist/testing.cjs.map +1 -0
  183. package/dist/testing.d.cts +271 -0
  184. package/dist/testing.d.ts +271 -0
  185. package/dist/testing.js +470 -0
  186. package/dist/testing.js.map +1 -0
  187. package/dist/uom.cjs +16 -16
  188. package/dist/uom.d.cts +3 -3
  189. package/dist/uom.d.ts +3 -3
  190. package/dist/uom.js +6 -6
  191. package/dist/utilities.cjs +6 -5
  192. package/dist/utilities.js +2 -1
  193. package/dist/vm.cjs +34 -34
  194. package/dist/vm.d.cts +8 -8
  195. package/dist/vm.d.ts +8 -8
  196. package/dist/vm.js +9 -9
  197. package/dist/worker.cjs +493 -0
  198. package/dist/worker.cjs.map +1 -0
  199. package/dist/worker.d.cts +509 -0
  200. package/dist/worker.d.ts +509 -0
  201. package/dist/worker.js +484 -0
  202. package/dist/worker.js.map +1 -0
  203. package/package.json +21 -1
  204. package/dist/chunk-2XLQPQKI.cjs.map +0 -1
  205. package/dist/chunk-3AFRJYP4.cjs.map +0 -1
  206. package/dist/chunk-3D7V24DG.js.map +0 -1
  207. package/dist/chunk-3LAEG75D.js.map +0 -1
  208. package/dist/chunk-4B2CNWQU.cjs.map +0 -1
  209. package/dist/chunk-526PMQOA.js.map +0 -1
  210. package/dist/chunk-5KMIY374.cjs.map +0 -1
  211. package/dist/chunk-5LI5EPGJ.cjs.map +0 -1
  212. package/dist/chunk-5WVP4YHP.js.map +0 -1
  213. package/dist/chunk-5X2PTP6F.cjs.map +0 -1
  214. package/dist/chunk-6KFYJ6TD.cjs.map +0 -1
  215. package/dist/chunk-6WFMPTGB.cjs.map +0 -1
  216. package/dist/chunk-AJA6LUI7.js.map +0 -1
  217. package/dist/chunk-B7TLZABL.cjs.map +0 -1
  218. package/dist/chunk-GQCOSXMG.js.map +0 -1
  219. package/dist/chunk-HDP7VK3C.cjs.map +0 -1
  220. package/dist/chunk-HMOISHXR.js.map +0 -1
  221. package/dist/chunk-HVQFNJKE.cjs.map +0 -1
  222. package/dist/chunk-IF532O7C.js.map +0 -1
  223. package/dist/chunk-JMXUNXQS.cjs.map +0 -1
  224. package/dist/chunk-KV7UW6T6.js.map +0 -1
  225. package/dist/chunk-O3ANBHSA.js.map +0 -1
  226. package/dist/chunk-PA4VC73I.cjs.map +0 -1
  227. package/dist/chunk-PFUESQTW.cjs.map +0 -1
  228. package/dist/chunk-QY25VWBF.js.map +0 -1
  229. package/dist/chunk-R3PY4G7J.js.map +0 -1
  230. package/dist/chunk-TBN7DEHO.js.map +0 -1
  231. package/dist/chunk-TY3TLZAW.cjs.map +0 -1
  232. package/dist/chunk-UM6BVY2S.cjs.map +0 -1
  233. package/dist/chunk-UQ3UIZJC.js.map +0 -1
  234. package/dist/chunk-V5PYO44Y.js.map +0 -1
  235. package/dist/chunk-VB37OC6I.js.map +0 -1
  236. package/dist/chunk-Y7FT4IQT.js.map +0 -1
  237. package/dist/chunk-YWQ6V4ZN.cjs.map +0 -1
@@ -1,12 +1,12 @@
1
- import { DiagnosticEventType } from './chunk-G535KJEG.js';
2
- import { defaultEngineContext, builtinFunctions, asConverterRegistry, sharedGlobalVariableStore, SYMBOLIC_NATIVE_BUILTINS, symbolicBuiltin, compareBigIntOperands, compareUom, incomparableUnitsError, toBigIntOperand, symbolicNeg, power, symbolicPow, binaryOp, bigIntDivisionByZero, unifyUom } from './chunk-Y7FT4IQT.js';
3
- import { sharedCurrencyExchange } from './chunk-TMA4RCEN.js';
4
- import { getOpCodeName } from './chunk-UQ3UIZJC.js';
5
- import { collectionToValues, matAt, inBounds, matrixEntryToValue, matIndex, rowMajorToColumnMajor, varNode, matrixCompare, matrixPower, matrixMultiply, CURRENCY_DISPLAY } from './chunk-O3ANBHSA.js';
6
- import { numberValue, ValueType, isArenaActive, beginEvaluation, errorValue, chargeAllocation, faultedOperand, checkedArray, matrixValue, rangeValue, datetimeValue, isRateUnit, splitRateUnit, rateValue, uomValue, stringValue, hexValue, percentageValue, persistentValue, symbolicValue, chargeFunctionCall, faultedIn, boolValue, bigIntValue, checkAllocation, isTimecodeUnit, endEvaluation, timecodeFps } from './chunk-GQCOSXMG.js';
7
- import { getMeasure, convertUnit, getBestUnit, getConvertiblePossibilities, isWorkdayUnit } from './chunk-R3PY4G7J.js';
1
+ import { DiagnosticEventType } from './chunk-CCBZZQAE.js';
2
+ import { defaultEngineContext, builtinFunctions, moneyExactMagnitude, asConverterRegistry, sharedGlobalVariableStore, SYMBOLIC_NATIVE_BUILTINS, symbolicBuiltin, compareRationalOperands, compareBigIntOperands, compareUom, incomparableUnitsError, toBigIntOperand, symbolicNeg, power, symbolicPow, binaryOp, bigIntDivisionByZero, uncertainOp, unifyUom, exactRationalOp, describeConversionMismatch, scaleMoneyExact, scaleMoneyByPercent } from './chunk-NKW7LKYU.js';
3
+ import { sharedCurrencyExchange } from './chunk-Z7XGGLI2.js';
4
+ import { getOpCodeName } from './chunk-BLI4NIQY.js';
5
+ import { collectionToValues, matAt, inBounds, matrixEntryToValue, matIndex, rowMajorToColumnMajor, varNode, matrixCompare, decimalNegate, rationalNeg, matrixPower, matrixMultiply, decimalFromLiteral, decimalToNumber, CURRENCY_DISPLAY } from './chunk-NNQ2TYDF.js';
6
+ import { numberValue, ValueType, isArenaActive, beginEvaluation, errorValue, chargeAllocation, faultedOperand, checkedArray, matrixValue, rangeValue, datetimeValue, isRateUnit, splitRateUnit, rateValue, uomValue, stringValue, uomValueExact, hexValue, percentageValue, colourValue, persistentValue, symbolicValue, chargeFunctionCall, faultedIn, boolValue, bigIntValue, numberValueUncertain, numberValueRational, numberValueExact, checkAllocation, isTimecodeUnit, endEvaluation, timecodeFps } from './chunk-267JPOTF.js';
7
+ import { getMeasure, convertUnit, convertRate, getBestUnit, getConvertiblePossibilities, isWorkdayUnit } from './chunk-MVTOCRV2.js';
8
8
  import { UNIT_TABLE } from './chunk-V4XG5QF6.js';
9
- import { ErrorFactory, normalizeUnknownError } from './chunk-3D7V24DG.js';
9
+ import { ErrorFactory, CoreErrorCodes, normalizeUnknownError } from './chunk-ERCOHGXD.js';
10
10
 
11
11
  // src/vm/DependencyGraph.ts
12
12
  var DependencyGraph = class {
@@ -330,6 +330,47 @@ var ScopeManager = class {
330
330
  }
331
331
  };
332
332
 
333
+ // src/vm/BusinessDays.ts
334
+ var MS_PER_DAY = 864e5;
335
+ function isWeekend(epochMs) {
336
+ const day = new Date(epochMs).getDay();
337
+ return day === 0 || day === 6;
338
+ }
339
+ function isBusinessDay(epochMs, isHoliday) {
340
+ if (isWeekend(epochMs)) return false;
341
+ return isHoliday ? !isHoliday(epochMs) : true;
342
+ }
343
+ function startOfLocalDay(epochMs) {
344
+ const d = new Date(epochMs);
345
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
346
+ }
347
+ function addBusinessDays(startMs, n, isHoliday, maxCalendarSteps) {
348
+ let remaining = Math.trunc(Math.abs(n));
349
+ const direction = n >= 0 ? 1 : -1;
350
+ const date = new Date(startMs);
351
+ let steps = 0;
352
+ while (remaining > 0) {
353
+ date.setDate(date.getDate() + direction);
354
+ steps++;
355
+ if (steps > maxCalendarSteps) return null;
356
+ if (isBusinessDay(date.getTime(), isHoliday)) remaining--;
357
+ }
358
+ return date.getTime();
359
+ }
360
+ function countBusinessDaysBetween(aMs, bMs, isHoliday, maxCalendarSteps) {
361
+ const startDay = startOfLocalDay(Math.min(aMs, bMs));
362
+ const endDay = startOfLocalDay(Math.max(aMs, bMs));
363
+ const spanDays = Math.round((endDay - startDay) / MS_PER_DAY);
364
+ if (spanDays > maxCalendarSteps) return null;
365
+ let count = 0;
366
+ const date = new Date(startDay);
367
+ for (let i = 0; i <= spanDays; i++) {
368
+ if (isBusinessDay(date.getTime(), isHoliday)) count++;
369
+ date.setDate(date.getDate() + 1);
370
+ }
371
+ return count;
372
+ }
373
+
333
374
  // src/vm/VMBuiltinArity.ts
334
375
  var BUILTIN_ARITY = {
335
376
  0: { name: "sqrt", min: 1, max: 1 },
@@ -340,7 +381,7 @@ var BUILTIN_ARITY = {
340
381
  5: { name: "log", min: 1, max: 1 },
341
382
  6: { name: "ceil", min: 1, max: 1 },
342
383
  7: { name: "floor", min: 1, max: 1 },
343
- 8: { name: "round", min: 1, max: 1 },
384
+ 8: { name: "round", min: 1, max: 2 },
344
385
  // min/max compare as many operands as they are given.
345
386
  9: { name: "min", min: 1, max: Infinity },
346
387
  10: { name: "max", min: 1, max: Infinity },
@@ -462,7 +503,7 @@ function builtinArityError(index, argCount) {
462
503
  }
463
504
 
464
505
  // src/vm/VM.ts
465
- function createVM(registry, maxStackDepth = 200, maxInstructions = 5e4, maxFunctionRecursionDepth = 50, maxCollectionSize = 1e5, maxAllocatedElements = 2e6, maxFunctionCalls = 1e4, maxDateOffsetYears = 100, minDateOffsetYears = -100, context = defaultEngineContext) {
506
+ function createVM(registry, maxStackDepth = 200, maxInstructions = 5e4, maxFunctionRecursionDepth = 50, maxCollectionSize = 1e5, maxAllocatedElements = 2e6, maxFunctionCalls = 1e4, maxDateOffsetYears = 100, minDateOffsetYears = -100, context = defaultEngineContext, holidayPredicate) {
466
507
  const stack = [];
467
508
  const variables = /* @__PURE__ */ new Map();
468
509
  let instructionCount = 0;
@@ -496,6 +537,12 @@ function createVM(registry, maxStackDepth = 200, maxInstructions = 5e4, maxFunct
496
537
  getMinDateOffsetYears() {
497
538
  return minDateOffsetYears;
498
539
  },
540
+ // False whenever no calendar was configured, which is what makes
541
+ // unconfigured working-day arithmetic weekends-only. See
542
+ // vm/BusinessDays.ts, the only reader.
543
+ isHoliday(epochMs) {
544
+ return holidayPredicate ? holidayPredicate(epochMs) : false;
545
+ },
499
546
  pop() {
500
547
  if (stack.length === 0) {
501
548
  return numberValue(0);
@@ -569,6 +616,12 @@ function createVM(registry, maxStackDepth = 200, maxInstructions = 5e4, maxFunct
569
616
  hasUserFunction(name) {
570
617
  return userFunctions.has(name);
571
618
  },
619
+ getVariableEntries() {
620
+ return Array.from(variables.entries());
621
+ },
622
+ getUserFunctionDefs() {
623
+ return Array.from(userFunctions.values());
624
+ },
572
625
  defineEquation(variable, factorNames, rhsProgram) {
573
626
  equations.set(variable, { variable, factorNames, rhsProgram });
574
627
  },
@@ -840,15 +893,48 @@ function moneyTimesQuantity(l, r) {
840
893
  function combinePercentage(l, r, sign) {
841
894
  if (l.type === 5 /* Percentage */) {
842
895
  if (r.type === 6 /* Uom */ && r.unit !== void 0) {
843
- return uomValue(r.toNumber() * (1 + sign * l.toNumber()), r.unit);
896
+ return scaleMoneyByPercent(r, r.unit, l.toNumber(), sign);
844
897
  }
845
898
  if (r.type !== 5 /* Percentage */ && r.type !== 0 /* Number */) return null;
846
899
  return percentageValue(l.toNumber() + sign * r.toNumber());
847
900
  }
848
901
  if (r.type !== 5 /* Percentage */) return null;
849
902
  const factor = 1 + sign * r.toNumber();
850
- if (l.type === 0 /* Number */) return numberValue(l.toNumber() * factor);
851
- if (l.type === 6 /* Uom */ && l.unit !== void 0) return uomValue(l.toNumber() * factor, l.unit);
903
+ if (l.type === 0 /* Number */) {
904
+ const scaled = l.toNumber() * factor;
905
+ if (l.uncertainty !== void 0) return numberValueUncertain(scaled, Math.abs(l.uncertainty * factor));
906
+ return numberValue(scaled);
907
+ }
908
+ if (l.type === 6 /* Uom */ && l.unit !== void 0) return scaleMoneyByPercent(l, l.unit, r.toNumber(), sign);
909
+ return null;
910
+ }
911
+ function multiplyPercentWithUncertainty(l, r) {
912
+ const pct = l.type === 5 /* Percentage */ ? l : r.type === 5 /* Percentage */ ? r : null;
913
+ if (pct === null) return null;
914
+ const other = pct === l ? r : l;
915
+ if (other.type !== 0 /* Number */ || other.uncertainty === void 0) return null;
916
+ const factor = pct.toNumber();
917
+ return numberValueUncertain(other.toNumber() * factor, Math.abs(other.uncertainty * factor));
918
+ }
919
+ function multiplyMoneyByScalarExact(l, r) {
920
+ const money = l.type === 6 /* Uom */ ? l : r;
921
+ const scalar = l.type === 6 /* Uom */ ? r : l;
922
+ if (money.type !== 6 /* Uom */ || money.unit === void 0 || !sharedCurrencyExchange.isCurrency(money.unit)) return null;
923
+ if (scalar.type !== 0 /* Number */ && scalar.type !== 5 /* Percentage */) return null;
924
+ if (scalar.rational !== void 0) return null;
925
+ return scaleMoneyExact(money, scalar.toNumber(), money.unit);
926
+ }
927
+ function dividePercentWithUncertainty(l, r) {
928
+ if (r.type === 5 /* Percentage */ && l.type === 0 /* Number */ && l.uncertainty !== void 0) {
929
+ const factor = r.toNumber();
930
+ if (factor === 0) return null;
931
+ return numberValueUncertain(l.toNumber() / factor, Math.abs(l.uncertainty / factor));
932
+ }
933
+ if (l.type === 5 /* Percentage */ && r.type === 0 /* Number */ && r.uncertainty !== void 0) {
934
+ const b = r.toNumber();
935
+ if (b === 0) return null;
936
+ return numberValueUncertain(l.toNumber() / b, Math.abs(l.toNumber() * r.uncertainty / (b * b)));
937
+ }
852
938
  return null;
853
939
  }
854
940
  function extractDurationMs(value) {
@@ -865,8 +951,8 @@ function extractDurationMs(value) {
865
951
  return value.toNumber();
866
952
  }
867
953
  var WORKDAYS_PER_YEAR = 260;
868
- function addBusinessDays(epochMs, n, vm) {
869
- let remaining = Math.trunc(Math.abs(n));
954
+ function addBusinessDays2(epochMs, n, vm) {
955
+ const remaining = Math.trunc(Math.abs(n));
870
956
  const direction = n >= 0 ? 1 : -1;
871
957
  const limitYears = direction > 0 ? vm.getMaxDateOffsetYears() : -vm.getMinDateOffsetYears();
872
958
  const limitWorkdays = Math.floor(limitYears * WORKDAYS_PER_YEAR);
@@ -877,15 +963,18 @@ function addBusinessDays(epochMs, n, vm) {
877
963
  { requestedWorkdays: remaining, limitYears, limitWorkdays }
878
964
  );
879
965
  }
880
- const date = new Date(epochMs);
881
- while (remaining > 0) {
882
- date.setDate(date.getDate() + direction);
883
- const day = date.getDay();
884
- if (day !== 0 && day !== 6) remaining--;
966
+ const maxCalendarSteps = limitWorkdays * 7 + 7;
967
+ const landed = addBusinessDays(epochMs, n, (ms) => vm.isHoliday(ms), maxCalendarSteps);
968
+ if (landed === null) {
969
+ throw ErrorFactory.execution(
970
+ "DATE_OFFSET_LIMIT_EXCEEDED",
971
+ `A working-day offset of ${remaining.toLocaleString("en-US")} could not be reached within the ${limitYears}-year limit; the configured holiday calendar leaves too few working days`,
972
+ { requestedWorkdays: remaining, limitYears, maxCalendarSteps }
973
+ );
885
974
  }
886
- return date.getTime();
975
+ return landed;
887
976
  }
888
- var MS_PER_DAY = 864e5;
977
+ var MS_PER_DAY2 = 864e5;
889
978
  var CALENDAR_MONTHS_PER_UNIT = {
890
979
  month: 1,
891
980
  months: 1,
@@ -911,8 +1000,8 @@ function addCalendarDays(epochMs, days) {
911
1000
  const date = new Date(epochMs);
912
1001
  date.setDate(date.getDate() + whole);
913
1002
  const shifted = date.getTime();
914
- if (Number.isNaN(shifted)) return epochMs + days * MS_PER_DAY;
915
- return shifted + (days - whole) * MS_PER_DAY;
1003
+ if (Number.isNaN(shifted)) return epochMs + days * MS_PER_DAY2;
1004
+ return shifted + (days - whole) * MS_PER_DAY2;
916
1005
  }
917
1006
  function addCalendarMonths(epochMs, months) {
918
1007
  const whole = Math.trunc(months);
@@ -930,7 +1019,7 @@ function shiftDatetime(epochMs, duration, sign, vm) {
930
1019
  if (duration.type === 6 /* Uom */ && duration.unit !== void 0) {
931
1020
  const unit = duration.unit;
932
1021
  const amount = sign * duration.toNumber();
933
- if (isWorkdayUnit(unit)) return addBusinessDays(epochMs, amount, vm);
1022
+ if (isWorkdayUnit(unit)) return addBusinessDays2(epochMs, amount, vm);
934
1023
  const monthsPerUnit = CALENDAR_MONTHS_PER_UNIT[unit];
935
1024
  if (monthsPerUnit !== void 0) return addCalendarMonths(epochMs, amount * monthsPerUnit);
936
1025
  if (getMeasure(unit) === "time") {
@@ -972,9 +1061,10 @@ function isTruthy(value) {
972
1061
  return value.toNumber() !== 0;
973
1062
  }
974
1063
  function incompatibleConversionError(fromUnit, toUnit) {
1064
+ const named = describeConversionMismatch(fromUnit, toUnit);
975
1065
  return errorValue(
976
1066
  "INCOMPATIBLE_UNITS",
977
- `Cannot convert ${fromUnit} to ${toUnit}: they do not measure the same thing`
1067
+ named ?? `Cannot convert ${fromUnit} to ${toUnit}: they do not measure the same thing`
978
1068
  );
979
1069
  }
980
1070
  var MAX_EXACT_POW_BITS = 65536;
@@ -1060,6 +1150,9 @@ function toFractionString(n) {
1060
1150
  const numerator = whole * k1 + h1;
1061
1151
  return `${negative ? "-" : ""}${numerator}/${k1}`;
1062
1152
  }
1153
+ function rationalToFractionString(r) {
1154
+ return r.d === 1n ? String(r.n) : `${r.n}/${r.d}`;
1155
+ }
1063
1156
  function toMultiplierString(value) {
1064
1157
  const n = value.toNumber();
1065
1158
  const multiple = value.type === 5 /* Percentage */ ? 1 + n : n;
@@ -1159,6 +1252,11 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1159
1252
  case 11 /* PUSH_BIGINT */:
1160
1253
  stack.push(bigIntValue(parseBigIntLiteral(poolString(opcodes, ip++, strings, op, "constant-pool index"), op)));
1161
1254
  break;
1255
+ case 16 /* PUSH_DECIMAL */: {
1256
+ const dec = decimalFromLiteral(poolString(opcodes, ip++, strings, op, "constant-pool index"));
1257
+ stack.push(numberValueExact(decimalToNumber(dec), dec));
1258
+ break;
1259
+ }
1162
1260
  case 12 /* PUSH_HEX */:
1163
1261
  stack.push(hexValue(numbers[poolIndex(opcodes, ip++, op, "constant-pool index", numbers.length, "number-pool")]));
1164
1262
  break;
@@ -1180,6 +1278,20 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1180
1278
  stack.push(addFault);
1181
1279
  break;
1182
1280
  }
1281
+ if (l.uncertainty !== void 0 || r.uncertainty !== void 0) {
1282
+ const uncAdd = uncertainOp(l, r, "add");
1283
+ if (uncAdd) {
1284
+ stack.push(uncAdd);
1285
+ break;
1286
+ }
1287
+ }
1288
+ if (l.rational !== void 0 || r.rational !== void 0) {
1289
+ const ratAdd = exactRationalOp(l, r, "add");
1290
+ if (ratAdd) {
1291
+ stack.push(ratAdd);
1292
+ break;
1293
+ }
1294
+ }
1183
1295
  const pctAdd = combinePercentage(l, r, 1);
1184
1296
  const ratePeriodAdd = pctAdd === null ? unifyRatePeriods(l, r) : null;
1185
1297
  if (pctAdd !== null) {
@@ -1212,6 +1324,20 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1212
1324
  stack.push(subFault);
1213
1325
  break;
1214
1326
  }
1327
+ if (l.uncertainty !== void 0 || r.uncertainty !== void 0) {
1328
+ const uncSub = uncertainOp(l, r, "sub");
1329
+ if (uncSub) {
1330
+ stack.push(uncSub);
1331
+ break;
1332
+ }
1333
+ }
1334
+ if (l.rational !== void 0 || r.rational !== void 0) {
1335
+ const ratSub = exactRationalOp(l, r, "sub");
1336
+ if (ratSub) {
1337
+ stack.push(ratSub);
1338
+ break;
1339
+ }
1340
+ }
1215
1341
  const pctSub = combinePercentage(l, r, -1);
1216
1342
  const ratePeriodSub = pctSub === null ? unifyRatePeriods(l, r) : null;
1217
1343
  if (pctSub !== null) {
@@ -1240,6 +1366,30 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1240
1366
  }
1241
1367
  case 22 /* MUL */: {
1242
1368
  const r = safePop(stack), l = safePop(stack);
1369
+ const pctUnc = multiplyPercentWithUncertainty(l, r);
1370
+ if (pctUnc) {
1371
+ stack.push(pctUnc);
1372
+ break;
1373
+ }
1374
+ if (l.uncertainty !== void 0 || r.uncertainty !== void 0) {
1375
+ const uncMul = uncertainOp(l, r, "mul");
1376
+ if (uncMul) {
1377
+ stack.push(uncMul);
1378
+ break;
1379
+ }
1380
+ }
1381
+ if (l.rational !== void 0 || r.rational !== void 0) {
1382
+ const ratMul = exactRationalOp(l, r, "mul");
1383
+ if (ratMul) {
1384
+ stack.push(ratMul);
1385
+ break;
1386
+ }
1387
+ }
1388
+ const moneyScalar = multiplyMoneyByScalarExact(l, r);
1389
+ if (moneyScalar) {
1390
+ stack.push(moneyScalar);
1391
+ break;
1392
+ }
1243
1393
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1244
1394
  stack.push(numberValue(l.value * r.value));
1245
1395
  } else if (l.type === 7 /* Matrix */ && r.type === 7 /* Matrix */) {
@@ -1258,6 +1408,18 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1258
1408
  }
1259
1409
  case 23 /* DIV */: {
1260
1410
  const r = safePop(stack), l = safePop(stack);
1411
+ const pctDivUnc = dividePercentWithUncertainty(l, r);
1412
+ if (pctDivUnc) {
1413
+ stack.push(pctDivUnc);
1414
+ break;
1415
+ }
1416
+ if (l.uncertainty !== void 0 || r.uncertainty !== void 0) {
1417
+ const uncDiv = uncertainOp(l, r, "div");
1418
+ if (uncDiv) {
1419
+ stack.push(uncDiv);
1420
+ break;
1421
+ }
1422
+ }
1261
1423
  if (l.type === 6 /* Uom */ && r.type === 6 /* Uom */) {
1262
1424
  const { lv, rv, sameMeasure } = unifyUom(l, r);
1263
1425
  if (sameMeasure) {
@@ -1268,6 +1430,11 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1268
1430
  stack.push(rateValue(lv / rv, l.unit, r.unit));
1269
1431
  }
1270
1432
  } else {
1433
+ const ratDiv = exactRationalOp(l, r, "div");
1434
+ if (ratDiv) {
1435
+ stack.push(ratDiv);
1436
+ break;
1437
+ }
1271
1438
  stack.push(binaryOp(l, r, (a, b) => a / b, (a, b) => {
1272
1439
  if (b === 0n) throw bigIntDivisionByZero();
1273
1440
  return a / b;
@@ -1346,9 +1513,12 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1346
1513
  break;
1347
1514
  }
1348
1515
  if (v.type === 2 /* BigInt */) stack.push(bigIntValue(-v.value));
1516
+ else if (v.type === 6 /* Uom */ && v.exact !== void 0) stack.push(uomValueExact(-v.toNumber(), v.unit, decimalNegate(v.exact)));
1349
1517
  else if (v.type === 6 /* Uom */) stack.push(uomValue(-v.toNumber(), v.unit));
1350
1518
  else if (v.type === 5 /* Percentage */) stack.push(percentageValue(-v.toNumber()));
1351
1519
  else if (v.type === 9 /* Symbolic */) stack.push(symbolicNeg(v));
1520
+ else if (v.type === 0 /* Number */ && v.rational !== void 0) stack.push(numberValueRational(-v.toNumber(), rationalNeg(v.rational)));
1521
+ else if (v.type === 0 /* Number */ && v.exact !== void 0) stack.push(numberValueExact(-v.toNumber(), decimalNegate(v.exact)));
1352
1522
  else stack.push(numberValue(-v.toNumber()));
1353
1523
  break;
1354
1524
  }
@@ -1359,11 +1529,24 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1359
1529
  stack.push(posFault);
1360
1530
  break;
1361
1531
  }
1362
- if (v.type === 6 /* Uom */) stack.push(uomValue(v.toNumber(), v.unit));
1532
+ if (v.type === 6 /* Uom */ && v.exact !== void 0) stack.push(uomValueExact(v.toNumber(), v.unit, v.exact));
1533
+ else if (v.type === 6 /* Uom */) stack.push(uomValue(v.toNumber(), v.unit));
1363
1534
  else if (v.type === 5 /* Percentage */) stack.push(percentageValue(v.toNumber()));
1535
+ else if (v.type === 0 /* Number */ && v.rational !== void 0) stack.push(numberValueRational(v.toNumber(), v.rational));
1536
+ else if (v.type === 0 /* Number */ && v.exact !== void 0) stack.push(numberValueExact(v.toNumber(), v.exact));
1364
1537
  else stack.push(numberValue(v.toNumber()));
1365
1538
  break;
1366
1539
  }
1540
+ case 28 /* MAKE_UNCERTAIN */: {
1541
+ const spread = safePop(stack), center = safePop(stack);
1542
+ const uncFault = faultedOperand(center, spread);
1543
+ if (uncFault) {
1544
+ stack.push(uncFault);
1545
+ break;
1546
+ }
1547
+ stack.push(numberValueUncertain(center.toNumber(), Math.abs(spread.toNumber())));
1548
+ break;
1549
+ }
1367
1550
  // ═══════════════════════════════════════════════════════════════
1368
1551
  // §4 Bitwise (OpCode 30–36)
1369
1552
  // None of these routes through binaryOp(), so each one carries
@@ -1496,6 +1679,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1496
1679
  stack.push(eqFault);
1497
1680
  break;
1498
1681
  }
1682
+ if (l.rational !== void 0 || r.rational !== void 0) {
1683
+ const cmp = compareRationalOperands(l, r);
1684
+ if (cmp !== null) {
1685
+ stack.push(boolValue(cmp === 0));
1686
+ break;
1687
+ }
1688
+ }
1499
1689
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1500
1690
  stack.push(boolValue(l.value === r.value));
1501
1691
  } else if (l.type === 2 /* BigInt */ || r.type === 2 /* BigInt */) {
@@ -1508,6 +1698,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1508
1698
  stack.push(boolValue(sameMeasure && equal));
1509
1699
  } else if (l.type === 7 /* Matrix */ && r.type === 7 /* Matrix */) {
1510
1700
  stack.push(matrixCompare(l.value, r.value, (a, b) => a === b));
1701
+ } else if (l.type === 14 /* Colour */ || r.type === 14 /* Colour */) {
1702
+ if (l.type === 14 /* Colour */ && r.type === 14 /* Colour */) {
1703
+ const a = l.value, b = r.value;
1704
+ stack.push(boolValue(a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a));
1705
+ } else {
1706
+ stack.push(boolValue(false));
1707
+ }
1511
1708
  } else {
1512
1709
  stack.push(boolValue(l.toNumber() === r.toNumber()));
1513
1710
  }
@@ -1520,6 +1717,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1520
1717
  stack.push(neqFault);
1521
1718
  break;
1522
1719
  }
1720
+ if (l.rational !== void 0 || r.rational !== void 0) {
1721
+ const cmp = compareRationalOperands(l, r);
1722
+ if (cmp !== null) {
1723
+ stack.push(boolValue(cmp !== 0));
1724
+ break;
1725
+ }
1726
+ }
1523
1727
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1524
1728
  stack.push(boolValue(l.value !== r.value));
1525
1729
  } else if (l.type === 2 /* BigInt */ || r.type === 2 /* BigInt */) {
@@ -1532,6 +1736,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1532
1736
  stack.push(boolValue(!sameMeasure || !equal));
1533
1737
  } else if (l.type === 7 /* Matrix */ && r.type === 7 /* Matrix */) {
1534
1738
  stack.push(matrixCompare(l.value, r.value, (a, b) => a !== b));
1739
+ } else if (l.type === 14 /* Colour */ || r.type === 14 /* Colour */) {
1740
+ if (l.type === 14 /* Colour */ && r.type === 14 /* Colour */) {
1741
+ const a = l.value, b = r.value;
1742
+ stack.push(boolValue(!(a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a)));
1743
+ } else {
1744
+ stack.push(boolValue(true));
1745
+ }
1535
1746
  } else {
1536
1747
  stack.push(boolValue(l.toNumber() !== r.toNumber()));
1537
1748
  }
@@ -1544,6 +1755,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1544
1755
  stack.push(ltFault);
1545
1756
  break;
1546
1757
  }
1758
+ if (l.rational !== void 0 || r.rational !== void 0) {
1759
+ const cmp = compareRationalOperands(l, r);
1760
+ if (cmp !== null) {
1761
+ stack.push(boolValue(cmp < 0));
1762
+ break;
1763
+ }
1764
+ }
1547
1765
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1548
1766
  stack.push(boolValue(l.value < r.value));
1549
1767
  } else if (l.type === 2 /* BigInt */ || r.type === 2 /* BigInt */) {
@@ -1566,6 +1784,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1566
1784
  stack.push(lteFault);
1567
1785
  break;
1568
1786
  }
1787
+ if (l.rational !== void 0 || r.rational !== void 0) {
1788
+ const cmp = compareRationalOperands(l, r);
1789
+ if (cmp !== null) {
1790
+ stack.push(boolValue(cmp <= 0));
1791
+ break;
1792
+ }
1793
+ }
1569
1794
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1570
1795
  stack.push(boolValue(l.value <= r.value));
1571
1796
  } else if (l.type === 2 /* BigInt */ || r.type === 2 /* BigInt */) {
@@ -1588,6 +1813,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1588
1813
  stack.push(gtFault);
1589
1814
  break;
1590
1815
  }
1816
+ if (l.rational !== void 0 || r.rational !== void 0) {
1817
+ const cmp = compareRationalOperands(l, r);
1818
+ if (cmp !== null) {
1819
+ stack.push(boolValue(cmp > 0));
1820
+ break;
1821
+ }
1822
+ }
1591
1823
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1592
1824
  stack.push(boolValue(l.value > r.value));
1593
1825
  } else if (l.type === 2 /* BigInt */ || r.type === 2 /* BigInt */) {
@@ -1610,6 +1842,13 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1610
1842
  stack.push(gteFault);
1611
1843
  break;
1612
1844
  }
1845
+ if (l.rational !== void 0 || r.rational !== void 0) {
1846
+ const cmp = compareRationalOperands(l, r);
1847
+ if (cmp !== null) {
1848
+ stack.push(boolValue(cmp >= 0));
1849
+ break;
1850
+ }
1851
+ }
1613
1852
  if (l.type === 0 /* Number */ && r.type === 0 /* Number */) {
1614
1853
  stack.push(boolValue(l.value >= r.value));
1615
1854
  } else if (l.type === 2 /* BigInt */ || r.type === 2 /* BigInt */) {
@@ -1843,6 +2082,11 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1843
2082
  stack.push(toHexFault);
1844
2083
  break;
1845
2084
  }
2085
+ if (v.type === 14 /* Colour */) {
2086
+ const c = v.value;
2087
+ stack.push(colourValue({ r: c.r, g: c.g, b: c.b, a: c.a, format: "hex" }));
2088
+ break;
2089
+ }
1846
2090
  stack.push(hexValue(v.type === 2 /* BigInt */ ? v.value : v.toNumber()));
1847
2091
  break;
1848
2092
  }
@@ -1863,7 +2107,7 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1863
2107
  stack.push(toFractionFault);
1864
2108
  break;
1865
2109
  }
1866
- stack.push(stringValue(toFractionString(v.toNumber())));
2110
+ stack.push(stringValue(v.rational !== void 0 ? rationalToFractionString(v.rational) : toFractionString(v.toNumber())));
1867
2111
  break;
1868
2112
  }
1869
2113
  case 141 /* TO_MULTIPLIER */: {
@@ -1935,7 +2179,9 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1935
2179
  stack.push(faulted);
1936
2180
  break;
1937
2181
  }
1938
- stack.push(uomValue(operand.toNumber(), unit));
2182
+ const money = moneyExactMagnitude(operand, unit);
2183
+ if (money) stack.push(uomValueExact(operand.toNumber(), unit, money));
2184
+ else stack.push(uomValue(operand.toNumber(), unit));
1939
2185
  break;
1940
2186
  }
1941
2187
  case 81 /* UOM_CONVERT_TO */: {
@@ -1960,7 +2206,12 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
1960
2206
  stack.push(errorValue("CURRENCY_RATE_UNAVAILABLE", `No exchange rate available for ${fromUnit} to ${toUnit}`));
1961
2207
  }
1962
2208
  } else {
1963
- stack.push(incompatibleConversionError(fromUnit, toUnit));
2209
+ const rate = convertRate(val, fromUnit, toUnit);
2210
+ if (rate !== null) {
2211
+ stack.push(uomValue(rate, toUnit));
2212
+ } else {
2213
+ stack.push(incompatibleConversionError(fromUnit, toUnit));
2214
+ }
1964
2215
  }
1965
2216
  break;
1966
2217
  }
@@ -2005,7 +2256,12 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
2005
2256
  stack.push(errorValue("CURRENCY_RATE_UNAVAILABLE", `No exchange rate available for ${fromUnit} to ${toUnit}`));
2006
2257
  }
2007
2258
  } else {
2008
- stack.push(incompatibleConversionError(fromUnit, toUnit));
2259
+ const rate = convertRate(val, fromUnit, toUnit);
2260
+ if (rate !== null) {
2261
+ stack.push(uomValue(rate, toUnit));
2262
+ } else {
2263
+ stack.push(incompatibleConversionError(fromUnit, toUnit));
2264
+ }
2009
2265
  }
2010
2266
  } else {
2011
2267
  stack.push(uomValue(left.toNumber(), toUnit));
@@ -2133,6 +2389,50 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
2133
2389
  stack.push(datetimeValue(shiftDatetime(dtValue.toNumber(), durValue, -1, vm)));
2134
2390
  break;
2135
2391
  }
2392
+ case 96 /* DATE_WORKDAY_OFFSET */: {
2393
+ const workdayDirection = operandByte(opcodes, ip++, op, "workday offset direction") === 1 ? -1 : 1;
2394
+ const anchorValue = safePop(stack), countValue = safePop(stack);
2395
+ const offsetFault = faultedOperand(countValue, anchorValue);
2396
+ if (offsetFault) {
2397
+ stack.push(offsetFault);
2398
+ break;
2399
+ }
2400
+ if (anchorValue.type !== 4 /* Datetime */) {
2401
+ stack.push(errorValue(
2402
+ CoreErrorCodes.WORKDAY_OFFSET_EXPECTED_DATE,
2403
+ `"working days after/before/from" expects a date to count from, got ${ValueType[anchorValue.type] ?? "an unsupported value"}`
2404
+ ));
2405
+ break;
2406
+ }
2407
+ stack.push(datetimeValue(addBusinessDays2(anchorValue.toNumber(), workdayDirection * countValue.toNumber(), vm)));
2408
+ break;
2409
+ }
2410
+ case 97 /* DATE_WORKDAYS_BETWEEN */: {
2411
+ const endValue = safePop(stack), startValue = safePop(stack);
2412
+ const betweenFault = faultedOperand(startValue, endValue);
2413
+ if (betweenFault) {
2414
+ stack.push(betweenFault);
2415
+ break;
2416
+ }
2417
+ if (startValue.type !== 4 /* Datetime */ || endValue.type !== 4 /* Datetime */) {
2418
+ stack.push(errorValue(
2419
+ CoreErrorCodes.WORKDAYS_BETWEEN_EXPECTED_DATES,
2420
+ `"working days between" expects two dates, got ${ValueType[startValue.type] ?? "an unsupported value"} and ${ValueType[endValue.type] ?? "an unsupported value"}`
2421
+ ));
2422
+ break;
2423
+ }
2424
+ const spanLimitDays = Math.ceil((vm.getMaxDateOffsetYears() - vm.getMinDateOffsetYears()) * 366);
2425
+ const workdayCount = countBusinessDaysBetween(startValue.toNumber(), endValue.toNumber(), (ms) => vm.isHoliday(ms), spanLimitDays);
2426
+ if (workdayCount === null) {
2427
+ stack.push(errorValue(
2428
+ CoreErrorCodes.WORKDAYS_BETWEEN_RANGE_TOO_LARGE,
2429
+ `The two dates are more than ${vm.getMaxDateOffsetYears() - vm.getMinDateOffsetYears()} years apart, past the working-day count's limit`
2430
+ ));
2431
+ break;
2432
+ }
2433
+ stack.push(numberValue(workdayCount));
2434
+ break;
2435
+ }
2136
2436
  case 93 /* DATE_NEXT_WEEKDAY */:
2137
2437
  case 94 /* DATE_LAST_WEEKDAY */: {
2138
2438
  const targetDayValue = safePop(stack);
@@ -2491,5 +2791,5 @@ function executeBytecode(bytecode, vm, pipeline, expression, context, symbolicTo
2491
2791
  }
2492
2792
 
2493
2793
  export { DependencyGraph, ScopeManager, createVM, executeBytecode };
2494
- //# sourceMappingURL=chunk-5WVP4YHP.js.map
2495
- //# sourceMappingURL=chunk-5WVP4YHP.js.map
2794
+ //# sourceMappingURL=chunk-WXEHD6TT.js.map
2795
+ //# sourceMappingURL=chunk-WXEHD6TT.js.map