@cortex-js/compute-engine 0.55.0 → 0.55.3

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 (257) hide show
  1. package/dist/compile.esm.js +2498 -2108
  2. package/dist/compile.min.esm.js +48 -48
  3. package/dist/compile.min.umd.cjs +49 -49
  4. package/dist/compile.umd.cjs +2498 -2108
  5. package/dist/compute-engine.esm.js +1219 -719
  6. package/dist/compute-engine.min.esm.js +73 -73
  7. package/dist/compute-engine.min.umd.cjs +73 -73
  8. package/dist/compute-engine.umd.cjs +1219 -719
  9. package/dist/core.esm.js +1223 -715
  10. package/dist/core.min.esm.js +72 -72
  11. package/dist/core.min.umd.cjs +72 -72
  12. package/dist/core.umd.cjs +1223 -715
  13. package/dist/interval.esm.js +1564 -1412
  14. package/dist/interval.min.esm.js +6 -6
  15. package/dist/interval.min.umd.cjs +6 -6
  16. package/dist/interval.umd.cjs +1564 -1412
  17. package/dist/latex-syntax.esm.js +673 -492
  18. package/dist/latex-syntax.min.esm.js +6 -6
  19. package/dist/latex-syntax.min.umd.cjs +6 -6
  20. package/dist/latex-syntax.umd.cjs +673 -492
  21. package/dist/math-json.esm.js +2 -2
  22. package/dist/math-json.min.esm.js +2 -2
  23. package/dist/math-json.min.umd.cjs +2 -2
  24. package/dist/math-json.umd.cjs +2 -2
  25. package/dist/numerics.esm.js +2 -2
  26. package/dist/numerics.min.esm.js +2 -2
  27. package/dist/numerics.min.umd.cjs +2 -2
  28. package/dist/numerics.umd.cjs +2 -2
  29. package/dist/types/big-decimal/big-decimal.d.ts +1 -1
  30. package/dist/types/big-decimal/index.d.ts +1 -1
  31. package/dist/types/big-decimal/transcendentals.d.ts +1 -1
  32. package/dist/types/big-decimal/utils.d.ts +1 -1
  33. package/dist/types/common/ansi-codes.d.ts +1 -1
  34. package/dist/types/common/configuration-change.d.ts +1 -1
  35. package/dist/types/common/fuzzy-string-match.d.ts +1 -1
  36. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  37. package/dist/types/common/interruptible.d.ts +1 -1
  38. package/dist/types/common/one-of.d.ts +1 -1
  39. package/dist/types/common/signals.d.ts +1 -1
  40. package/dist/types/common/type/ast-nodes.d.ts +1 -1
  41. package/dist/types/common/type/boxed-type.d.ts +1 -1
  42. package/dist/types/common/type/lexer.d.ts +1 -1
  43. package/dist/types/common/type/parse.d.ts +1 -1
  44. package/dist/types/common/type/parser.d.ts +1 -1
  45. package/dist/types/common/type/primitive.d.ts +1 -1
  46. package/dist/types/common/type/reduce.d.ts +1 -1
  47. package/dist/types/common/type/serialize.d.ts +1 -1
  48. package/dist/types/common/type/subtype.d.ts +1 -1
  49. package/dist/types/common/type/type-builder.d.ts +1 -1
  50. package/dist/types/common/type/types.d.ts +1 -1
  51. package/dist/types/common/type/utils.d.ts +1 -1
  52. package/dist/types/common/utils.d.ts +1 -1
  53. package/dist/types/compile.d.ts +1 -1
  54. package/dist/types/compute-engine/assume.d.ts +1 -1
  55. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +1 -1
  56. package/dist/types/compute-engine/boxed-expression/apply.d.ts +1 -1
  57. package/dist/types/compute-engine/boxed-expression/arithmetic-add.d.ts +1 -1
  58. package/dist/types/compute-engine/boxed-expression/arithmetic-mul-div.d.ts +1 -1
  59. package/dist/types/compute-engine/boxed-expression/arithmetic-power.d.ts +1 -1
  60. package/dist/types/compute-engine/boxed-expression/ascii-math.d.ts +1 -1
  61. package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
  62. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
  63. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +1 -1
  64. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -1
  65. package/dist/types/compute-engine/boxed-expression/boxed-operator-definition.d.ts +1 -1
  66. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  67. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -1
  68. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +1 -1
  69. package/dist/types/compute-engine/boxed-expression/boxed-tensor.d.ts +1 -1
  70. package/dist/types/compute-engine/boxed-expression/boxed-value-definition.d.ts +1 -1
  71. package/dist/types/compute-engine/boxed-expression/cache.d.ts +1 -1
  72. package/dist/types/compute-engine/boxed-expression/canonical-utils.d.ts +1 -1
  73. package/dist/types/compute-engine/boxed-expression/canonical.d.ts +1 -1
  74. package/dist/types/compute-engine/boxed-expression/compare.d.ts +1 -1
  75. package/dist/types/compute-engine/boxed-expression/constants.d.ts +1 -1
  76. package/dist/types/compute-engine/boxed-expression/expand.d.ts +1 -1
  77. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  78. package/dist/types/compute-engine/boxed-expression/factor.d.ts +1 -1
  79. package/dist/types/compute-engine/boxed-expression/flatten.d.ts +1 -1
  80. package/dist/types/compute-engine/boxed-expression/hold.d.ts +1 -1
  81. package/dist/types/compute-engine/boxed-expression/inequality-bounds.d.ts +1 -1
  82. package/dist/types/compute-engine/boxed-expression/init-lazy-refs.d.ts +1 -1
  83. package/dist/types/compute-engine/boxed-expression/invisible-operator.d.ts +1 -1
  84. package/dist/types/compute-engine/boxed-expression/match.d.ts +1 -1
  85. package/dist/types/compute-engine/boxed-expression/negate.d.ts +1 -1
  86. package/dist/types/compute-engine/boxed-expression/numerics.d.ts +1 -1
  87. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  88. package/dist/types/compute-engine/boxed-expression/pattern-utils.d.ts +1 -1
  89. package/dist/types/compute-engine/boxed-expression/polynomial-degree.d.ts +1 -1
  90. package/dist/types/compute-engine/boxed-expression/polynomials.d.ts +1 -1
  91. package/dist/types/compute-engine/boxed-expression/predicates.d.ts +1 -1
  92. package/dist/types/compute-engine/boxed-expression/rules.d.ts +1 -1
  93. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  94. package/dist/types/compute-engine/boxed-expression/sgn.d.ts +1 -1
  95. package/dist/types/compute-engine/boxed-expression/simplify.d.ts +1 -1
  96. package/dist/types/compute-engine/boxed-expression/solve-linear-system.d.ts +1 -1
  97. package/dist/types/compute-engine/boxed-expression/solve.d.ts +1 -1
  98. package/dist/types/compute-engine/boxed-expression/stochastic-equal.d.ts +1 -1
  99. package/dist/types/compute-engine/boxed-expression/trigonometry.d.ts +1 -1
  100. package/dist/types/compute-engine/boxed-expression/type-guards.d.ts +1 -1
  101. package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
  102. package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
  103. package/dist/types/compute-engine/collection-utils.d.ts +1 -1
  104. package/dist/types/compute-engine/compilation/base-compiler.d.ts +8 -7
  105. package/dist/types/compute-engine/compilation/compile-expression.d.ts +1 -1
  106. package/dist/types/compute-engine/compilation/constant-folding.d.ts +50 -0
  107. package/dist/types/compute-engine/compilation/glsl-target.d.ts +1 -1
  108. package/dist/types/compute-engine/compilation/gpu-target.d.ts +1 -1
  109. package/dist/types/compute-engine/compilation/interval-javascript-target.d.ts +1 -1
  110. package/dist/types/compute-engine/compilation/javascript-target.d.ts +23 -1
  111. package/dist/types/compute-engine/compilation/python-target.d.ts +1 -1
  112. package/dist/types/compute-engine/compilation/types.d.ts +1 -1
  113. package/dist/types/compute-engine/compilation/wgsl-target.d.ts +1 -1
  114. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  115. package/dist/types/compute-engine/engine-assumptions.d.ts +1 -1
  116. package/dist/types/compute-engine/engine-cache.d.ts +1 -1
  117. package/dist/types/compute-engine/engine-common-symbols.d.ts +1 -1
  118. package/dist/types/compute-engine/engine-compilation-targets.d.ts +1 -1
  119. package/dist/types/compute-engine/engine-configuration-lifecycle.d.ts +1 -1
  120. package/dist/types/compute-engine/engine-declarations.d.ts +1 -1
  121. package/dist/types/compute-engine/engine-expression-entrypoints.d.ts +1 -1
  122. package/dist/types/compute-engine/engine-extension-contracts.d.ts +1 -1
  123. package/dist/types/compute-engine/engine-library-bootstrap.d.ts +1 -1
  124. package/dist/types/compute-engine/engine-numeric-configuration.d.ts +1 -1
  125. package/dist/types/compute-engine/engine-runtime-state.d.ts +1 -1
  126. package/dist/types/compute-engine/engine-scope.d.ts +1 -1
  127. package/dist/types/compute-engine/engine-sequences.d.ts +1 -1
  128. package/dist/types/compute-engine/engine-simplification-rules.d.ts +1 -1
  129. package/dist/types/compute-engine/engine-startup-coordinator.d.ts +1 -1
  130. package/dist/types/compute-engine/engine-type-resolver.d.ts +1 -1
  131. package/dist/types/compute-engine/engine-validation-entrypoints.d.ts +1 -1
  132. package/dist/types/compute-engine/free-functions.d.ts +1 -1
  133. package/dist/types/compute-engine/function-utils.d.ts +1 -1
  134. package/dist/types/compute-engine/global-types.d.ts +1 -1
  135. package/dist/types/compute-engine/index.d.ts +1 -1
  136. package/dist/types/compute-engine/interval/arithmetic.d.ts +1 -1
  137. package/dist/types/compute-engine/interval/comparison.d.ts +1 -1
  138. package/dist/types/compute-engine/interval/elementary.d.ts +1 -1
  139. package/dist/types/compute-engine/interval/index.d.ts +1 -1
  140. package/dist/types/compute-engine/interval/trigonometric.d.ts +1 -1
  141. package/dist/types/compute-engine/interval/types.d.ts +1 -1
  142. package/dist/types/compute-engine/interval/util.d.ts +1 -1
  143. package/dist/types/compute-engine/latex-syntax/dictionary/default-dictionary.d.ts +1 -1
  144. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  145. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  146. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  147. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-complex.d.ts +1 -1
  148. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  149. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-linear-algebra.d.ts +1 -1
  150. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +3 -1
  151. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  152. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-relational-operators.d.ts +1 -1
  153. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  154. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-statistics.d.ts +1 -1
  155. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  156. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  157. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-units.d.ts +1 -1
  158. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
  159. package/dist/types/compute-engine/latex-syntax/dictionary/indexed-types.d.ts +1 -1
  160. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
  161. package/dist/types/compute-engine/latex-syntax/parse-number.d.ts +1 -1
  162. package/dist/types/compute-engine/latex-syntax/parse-symbol.d.ts +1 -1
  163. package/dist/types/compute-engine/latex-syntax/parse.d.ts +11 -1
  164. package/dist/types/compute-engine/latex-syntax/serialize-dms.d.ts +1 -1
  165. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  166. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  167. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
  168. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  169. package/dist/types/compute-engine/latex-syntax/types.d.ts +1 -1
  170. package/dist/types/compute-engine/latex-syntax/utils.d.ts +1 -1
  171. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  172. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  173. package/dist/types/compute-engine/library/collections.d.ts +1 -1
  174. package/dist/types/compute-engine/library/colors.d.ts +1 -1
  175. package/dist/types/compute-engine/library/combinatorics.d.ts +1 -1
  176. package/dist/types/compute-engine/library/complex.d.ts +1 -1
  177. package/dist/types/compute-engine/library/control-structures.d.ts +1 -1
  178. package/dist/types/compute-engine/library/core.d.ts +1 -1
  179. package/dist/types/compute-engine/library/fractals.d.ts +1 -1
  180. package/dist/types/compute-engine/library/library.d.ts +1 -1
  181. package/dist/types/compute-engine/library/linear-algebra.d.ts +1 -1
  182. package/dist/types/compute-engine/library/logic-analysis.d.ts +1 -1
  183. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  184. package/dist/types/compute-engine/library/number-theory.d.ts +1 -1
  185. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  186. package/dist/types/compute-engine/library/quantity-arithmetic.d.ts +1 -1
  187. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  188. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  189. package/dist/types/compute-engine/library/sets.d.ts +1 -1
  190. package/dist/types/compute-engine/library/statistics.d.ts +1 -1
  191. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  192. package/dist/types/compute-engine/library/type-handlers.d.ts +1 -1
  193. package/dist/types/compute-engine/library/unit-data.d.ts +1 -1
  194. package/dist/types/compute-engine/library/units.d.ts +1 -1
  195. package/dist/types/compute-engine/library/utils.d.ts +1 -1
  196. package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +1 -1
  197. package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +1 -1
  198. package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +1 -1
  199. package/dist/types/compute-engine/numeric-value/types.d.ts +1 -1
  200. package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
  201. package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
  202. package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
  203. package/dist/types/compute-engine/numerics/linear-algebra.d.ts +1 -1
  204. package/dist/types/compute-engine/numerics/monte-carlo.d.ts +1 -1
  205. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  206. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  207. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  208. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  209. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  210. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  211. package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
  212. package/dist/types/compute-engine/numerics/special-functions.d.ts +1 -1
  213. package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
  214. package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
  215. package/dist/types/compute-engine/numerics/types.d.ts +1 -1
  216. package/dist/types/compute-engine/numerics/unit-data.d.ts +1 -1
  217. package/dist/types/compute-engine/oeis.d.ts +1 -1
  218. package/dist/types/compute-engine/sequence.d.ts +1 -1
  219. package/dist/types/compute-engine/symbolic/antiderivative.d.ts +1 -1
  220. package/dist/types/compute-engine/symbolic/derivative.d.ts +1 -1
  221. package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
  222. package/dist/types/compute-engine/symbolic/fu-cost.d.ts +1 -1
  223. package/dist/types/compute-engine/symbolic/fu-transforms.d.ts +1 -1
  224. package/dist/types/compute-engine/symbolic/fu.d.ts +1 -1
  225. package/dist/types/compute-engine/symbolic/logic-utils.d.ts +1 -1
  226. package/dist/types/compute-engine/symbolic/simplify-abs.d.ts +1 -1
  227. package/dist/types/compute-engine/symbolic/simplify-divide.d.ts +1 -1
  228. package/dist/types/compute-engine/symbolic/simplify-factorial.d.ts +1 -1
  229. package/dist/types/compute-engine/symbolic/simplify-hyperbolic.d.ts +1 -1
  230. package/dist/types/compute-engine/symbolic/simplify-infinity.d.ts +1 -1
  231. package/dist/types/compute-engine/symbolic/simplify-log.d.ts +1 -1
  232. package/dist/types/compute-engine/symbolic/simplify-logic.d.ts +1 -1
  233. package/dist/types/compute-engine/symbolic/simplify-power.d.ts +1 -1
  234. package/dist/types/compute-engine/symbolic/simplify-product.d.ts +1 -1
  235. package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
  236. package/dist/types/compute-engine/symbolic/simplify-sum.d.ts +1 -1
  237. package/dist/types/compute-engine/symbolic/simplify-trig.d.ts +1 -1
  238. package/dist/types/compute-engine/tensor/tensor-fields.d.ts +1 -1
  239. package/dist/types/compute-engine/tensor/tensors.d.ts +1 -1
  240. package/dist/types/compute-engine/types-definitions.d.ts +1 -1
  241. package/dist/types/compute-engine/types-engine.d.ts +1 -1
  242. package/dist/types/compute-engine/types-evaluation.d.ts +1 -1
  243. package/dist/types/compute-engine/types-expression.d.ts +1 -1
  244. package/dist/types/compute-engine/types-kernel-evaluation.d.ts +1 -1
  245. package/dist/types/compute-engine/types-kernel-serialization.d.ts +1 -1
  246. package/dist/types/compute-engine/types-serialization.d.ts +1 -1
  247. package/dist/types/compute-engine/types.d.ts +1 -1
  248. package/dist/types/compute-engine.d.ts +1 -1
  249. package/dist/types/core.d.ts +1 -1
  250. package/dist/types/interval.d.ts +1 -1
  251. package/dist/types/latex-syntax.d.ts +2 -2
  252. package/dist/types/math-json/symbols.d.ts +1 -1
  253. package/dist/types/math-json/types.d.ts +1 -1
  254. package/dist/types/math-json/utils.d.ts +1 -1
  255. package/dist/types/math-json.d.ts +2 -2
  256. package/dist/types/numerics.d.ts +1 -1
  257. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- /** Interval 0.55.0 */
1
+ /** Interval 0.55.3 */
2
2
  (function(global,factory){typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'],factory):(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Interval = {}));})(this, (function (exports) { 'use strict';
3
3
  var Interval = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -5592,1132 +5592,1726 @@ var Interval = (() => {
5592
5592
  return expr;
5593
5593
  }
5594
5594
 
5595
- // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
5596
- function parseSequence(parser, terminator, lhs, prec, sep) {
5597
- if (terminator && terminator.minPrec >= prec) return null;
5598
- const result = lhs ? [lhs] : ["Nothing"];
5599
- let done = false;
5600
- while (!done) {
5601
- done = true;
5602
- parser.skipSpace();
5603
- while (parser.match(sep)) {
5604
- result.push("Nothing");
5605
- parser.skipSpace();
5606
- }
5607
- parser.skipVisualSpace();
5608
- if (parser.atTerminator(terminator)) {
5609
- result.push("Nothing");
5610
- } else {
5611
- const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
5612
- result.push(rhs ?? "Nothing");
5613
- done = rhs === null;
5614
- }
5615
- if (!done) {
5616
- parser.skipSpace();
5617
- done = !parser.match(sep);
5618
- if (!done) parser.skipVisualSpace();
5619
- }
5620
- }
5621
- return result;
5622
- }
5623
- function serializeOps(sep = "") {
5624
- return (serializer, expr) => {
5625
- if (!expr) return "";
5626
- const xs = operands(expr);
5627
- if (xs.length === 0) return "";
5628
- if (xs.length === 1) return serializer.serialize(xs[0]);
5629
- sep = {
5630
- "&": "\\&",
5631
- ":": "\\colon",
5632
- "|": "\\mvert",
5633
- "-": "-",
5634
- "\xB7": "\\cdot",
5635
- // U+00B7 MIDDLE DOT
5636
- "\u2012": "-",
5637
- // U+2012 FIGURE DASH
5638
- "\u2013": "--",
5639
- // U+2013 EN DASH
5640
- "\u2014": "---",
5641
- // U+2014 EM DASH
5642
- "\u2015": "-",
5643
- // U+2015 HORIZONTAL BAR
5644
- "\u2022": "\\bullet",
5645
- // U+2022 BULLET
5646
- "\u2026": "\\ldots"
5647
- }[sep] ?? sep;
5648
- const ys = xs.reduce((acc, item) => {
5649
- acc.push(serializer.serialize(item), sep);
5650
- return acc;
5651
- }, []);
5652
- ys.pop();
5653
- return joinLatex(ys);
5654
- };
5655
- }
5656
- var DEFINITIONS_CORE = [
5657
- //
5595
+ // src/compute-engine/latex-syntax/dictionary/definitions-logic.ts
5596
+ var DEFINITIONS_LOGIC = [
5658
5597
  // Constants
5659
- //
5660
5598
  {
5661
- latexTrigger: ["\\placeholder"],
5599
+ name: "True",
5662
5600
  kind: "symbol",
5663
- parse: (parser) => {
5664
- while (parser.match("<space>")) {
5665
- }
5666
- if (parser.match("["))
5667
- while (!parser.match("]") && !parser.atBoundary) parser.nextToken();
5668
- while (parser.match("<space>")) {
5669
- }
5670
- if (parser.match("<{>"))
5671
- while (!parser.match("<}>") && !parser.atBoundary) parser.nextToken();
5672
- return "Nothing";
5673
- }
5601
+ latexTrigger: ["\\top"]
5602
+ // U+22A4
5674
5603
  },
5675
- { name: "ContinuationPlaceholder", latexTrigger: ["\\dots"] },
5676
- { latexTrigger: ["\\ldots"], parse: "ContinuationPlaceholder" },
5677
- { latexTrigger: [".", ".", "."], parse: "ContinuationPlaceholder" },
5678
- //
5679
- // Functions
5680
- //
5681
- // Anonymous function, i.e. `(x) \mapsto x^2`
5682
5604
  {
5683
- name: "Function",
5684
- latexTrigger: ["\\mapsto"],
5685
- kind: "infix",
5686
- precedence: ARROW_PRECEDENCE,
5687
- // MathML rightwards arrow
5688
- parse: (parser, lhs, _until) => {
5689
- let params = [];
5690
- if (operator(lhs) === "Delimiter") lhs = operand(lhs, 1) ?? "Nothing";
5691
- if (operator(lhs) === "Sequence") {
5692
- for (const x of operands(lhs)) {
5693
- if (!symbol(x)) return null;
5694
- params.push(symbol(x));
5695
- }
5696
- } else {
5697
- if (!symbol(lhs)) return null;
5698
- params = [symbol(lhs)];
5699
- }
5700
- let rhs = parser.parseExpression({ minPrec: ARROW_PRECEDENCE }) ?? "Nothing";
5701
- if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
5702
- if (operator(rhs) === "Sequence") rhs = ["Block", ...operands(rhs)];
5703
- return ["Function", rhs, ...params];
5704
- },
5705
- serialize: (serializer, expr) => {
5706
- const args = operands(expr);
5707
- if (args.length < 1) return "()\\mapsto()";
5708
- if (args.length === 1)
5709
- return joinLatex([
5710
- "()",
5711
- "\\mapsto",
5712
- serializer.serialize(operand(expr, 1))
5713
- ]);
5714
- if (args.length === 2) {
5715
- return joinLatex([
5716
- serializer.serialize(operand(expr, 2)),
5717
- "\\mapsto",
5718
- serializer.serialize(operand(expr, 1))
5719
- ]);
5720
- }
5721
- return joinLatex([
5722
- serializer.wrapString(
5723
- operands(expr)?.slice(1).map((x) => serializer.serialize(x)).join(", "),
5724
- "normal"
5725
- ),
5726
- "\\mapsto",
5727
- serializer.serialize(operand(expr, 1))
5728
- ]);
5729
- }
5605
+ kind: "symbol",
5606
+ latexTrigger: "\\mathrm{True}",
5607
+ parse: "True"
5730
5608
  },
5731
5609
  {
5732
- name: "Apply",
5733
- kind: "function",
5734
- symbolTrigger: "apply",
5735
- serialize: (serializer, expr) => {
5736
- const lhs = operand(expr, 1);
5737
- const h = operator(lhs);
5738
- if (h === "InverseFunction" || h === "Derivative") {
5739
- const style2 = serializer.options.applyFunctionStyle(
5740
- expr,
5741
- serializer.level
5742
- );
5743
- const args = operands(expr).slice(1);
5744
- return serializer.serializeFunction(
5745
- lhs,
5746
- serializer.dictionary.ids.get(h)
5747
- ) + serializer.wrapString(
5748
- args.map((x) => serializer.serialize(x)).join(", "),
5749
- style2
5750
- );
5751
- }
5752
- const rhs = operand(expr, 2);
5753
- if (typeof lhs === "string" || !rhs) {
5754
- const fn = operands(expr).slice(1);
5755
- return serializer.serialize(fn);
5756
- }
5757
- if (nops(expr) === 2) {
5758
- return joinLatex([
5759
- serializer.wrap(lhs, 20),
5760
- "\\lhd",
5761
- serializer.wrap(rhs, 20)
5762
- ]);
5763
- }
5764
- const style = serializer.options.applyFunctionStyle(
5765
- expr,
5766
- serializer.level
5767
- );
5768
- return joinLatex([
5769
- "\\operatorname{apply}",
5770
- serializer.wrapString(
5771
- serializer.serialize(h) + ", " + serializer.serialize(["List", ...operands(expr)]),
5772
- style
5773
- )
5774
- ]);
5775
- }
5610
+ kind: "symbol",
5611
+ latexTrigger: "\\operatorname{True}",
5612
+ parse: "True"
5776
5613
  },
5777
5614
  {
5778
- latexTrigger: "\\lhd",
5779
- kind: "infix",
5780
- precedence: 20,
5781
- parse: "Apply"
5615
+ kind: "symbol",
5616
+ latexTrigger: "\\mathsf{T}",
5617
+ parse: "True"
5782
5618
  },
5783
5619
  {
5784
- latexTrigger: "\\rhd",
5620
+ name: "False",
5621
+ kind: "symbol",
5622
+ latexTrigger: ["\\bot"]
5623
+ // ⊥ U+22A5
5624
+ },
5625
+ {
5626
+ kind: "symbol",
5627
+ latexTrigger: "\\operatorname{False}",
5628
+ parse: "False"
5629
+ },
5630
+ {
5631
+ kind: "symbol",
5632
+ latexTrigger: "\\mathsf{F}",
5633
+ parse: "False"
5634
+ },
5635
+ // Operators
5636
+ // Logic operators have lower precedence than comparisons (245)
5637
+ // so that `x = 1 \lor x = 2` parses as `(x = 1) \lor (x = 2)`
5638
+ // See https://github.com/cortex-js/compute-engine/issues/243
5639
+ {
5640
+ name: "And",
5785
5641
  kind: "infix",
5786
- precedence: 20,
5787
- parse: (parser, lhs, _until) => {
5788
- const rhs = parser.parseExpression({ minPrec: 21 }) ?? "Nothing";
5789
- return ["Apply", rhs, lhs];
5790
- }
5642
+ latexTrigger: ["\\land"],
5643
+ precedence: 235
5644
+ // serialize: '\\land',
5791
5645
  },
5646
+ { kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence: 235 },
5647
+ { kind: "infix", latexTrigger: "\\&", parse: "And", precedence: 235 },
5792
5648
  {
5793
- name: "EvaluateAt",
5794
- openTrigger: ".",
5795
- closeTrigger: "|",
5796
- kind: "matchfix",
5797
- serialize: (serializer, expr) => {
5798
- const fn = operand(expr, 1);
5799
- if (!fn) return "";
5800
- const args = operands(expr).slice(1);
5801
- if (operator(fn) === "Function") {
5802
- const parameters = operands(fn).slice(1);
5803
- let body = operand(fn, 1);
5804
- if (operator(body) === "Block" && nops(body) === 1)
5805
- body = operand(body, 1);
5806
- if (parameters.length > 0) {
5807
- return `\\left.\\left(${serializer.serialize(
5808
- body
5809
- )}\\right)\\right|_{${parameters.map(
5810
- (x, i) => `${serializer.serialize(x)}=${serializer.serialize(args[i])}`
5811
- ).join(", ")}}`;
5812
- }
5813
- }
5814
- return `\\left.\\left(${serializer.serialize(fn)}\\right)\\right|_{${args.map((x) => serializer.serialize(x)).join(", ")}}`;
5815
- }
5649
+ kind: "infix",
5650
+ latexTrigger: "\\operatorname{and}",
5651
+ parse: "And",
5652
+ precedence: 235
5816
5653
  },
5817
- // The mathtools package includes several synonmyms for \colonequals. The
5818
- // preferred one as of summer 2022 is `\coloneq` (see § 3.7.3 https://ctan.math.illinois.edu/macros/latex/contrib/mathtools/mathtools.pdf)
5819
5654
  {
5820
- name: "Assign",
5821
- latexTrigger: "\\coloneq",
5655
+ name: "Or",
5822
5656
  kind: "infix",
5823
- associativity: "right",
5824
- precedence: ASSIGNMENT_PRECEDENCE,
5825
- serialize: (serializer, expr) => {
5826
- const id = unhold(operand(expr, 1));
5827
- if (operator(operand(expr, 2)) === "Function") {
5828
- const op_2 = operand(expr, 2);
5829
- const body = unhold(operand(op_2, 1));
5830
- const args = operands(op_2).slice(1);
5831
- return joinLatex([
5832
- serializer.serialize(id),
5833
- serializer.wrapString(
5834
- args.map((x) => serializer.serialize(x)).join(", "),
5835
- serializer.options.applyFunctionStyle(expr, serializer.level)
5836
- ),
5837
- "\\coloneq",
5838
- serializer.serialize(body)
5839
- ]);
5840
- }
5841
- return joinLatex([
5842
- serializer.serialize(id),
5843
- "\\coloneq",
5844
- serializer.serialize(operand(expr, 2))
5845
- ]);
5846
- },
5847
- parse: parseAssign
5657
+ latexTrigger: ["\\lor"],
5658
+ precedence: 230
5848
5659
  },
5660
+ { kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence: 230 },
5661
+ { kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence: 230 },
5849
5662
  {
5850
- latexTrigger: "\\coloneqq",
5851
5663
  kind: "infix",
5852
- associativity: "right",
5853
- precedence: ASSIGNMENT_PRECEDENCE,
5854
- parse: parseAssign
5664
+ latexTrigger: "\\operatorname{or}",
5665
+ parse: "Or",
5666
+ precedence: 230
5855
5667
  },
5856
- // From the colonequals package:
5857
5668
  {
5858
- latexTrigger: "\\colonequals",
5669
+ name: "Xor",
5859
5670
  kind: "infix",
5860
- associativity: "right",
5861
- precedence: ASSIGNMENT_PRECEDENCE,
5862
- parse: parseAssign
5671
+ latexTrigger: ["\\veebar"],
5672
+ precedence: 232
5863
5673
  },
5674
+ // Possible alt: \oplus ⊕ U+2295
5864
5675
  {
5865
- latexTrigger: [":", "="],
5866
- kind: "infix",
5867
- associativity: "right",
5868
- precedence: ASSIGNMENT_PRECEDENCE,
5869
- parse: parseAssign
5676
+ name: "Not",
5677
+ kind: "prefix",
5678
+ latexTrigger: ["\\lnot"],
5679
+ precedence: 880
5870
5680
  },
5871
- // General colon operator (type annotation, mapping notation)
5872
- // Precedence below assignment (260) so `:=` takes priority,
5873
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5874
5681
  {
5875
- name: "Colon",
5876
- latexTrigger: ":",
5682
+ kind: "prefix",
5683
+ latexTrigger: ["\\neg"],
5684
+ parse: "Not",
5685
+ precedence: 880
5686
+ },
5687
+ {
5688
+ name: "Nand",
5877
5689
  kind: "infix",
5878
- associativity: "right",
5879
- precedence: 250,
5880
- serialize: (serializer, expr) => joinLatex([
5881
- serializer.serialize(operand(expr, 1)),
5882
- "\\colon",
5883
- serializer.serialize(operand(expr, 2))
5884
- ])
5690
+ latexTrigger: ["\\barwedge"],
5691
+ precedence: 232
5692
+ // serialize: '\\mid',
5885
5693
  },
5886
5694
  {
5887
- latexTrigger: "\\colon",
5695
+ name: "Nor",
5888
5696
  kind: "infix",
5889
- associativity: "right",
5890
- precedence: 250,
5891
- parse: "Colon"
5697
+ latexTrigger: ["\u22BD"],
5698
+ // bar vee
5699
+ precedence: 232
5700
+ // serialize: '\\downarrow',
5892
5701
  },
5702
+ // Functions
5893
5703
  {
5894
- name: "BaseForm",
5895
- serialize: (serializer, expr) => {
5896
- const radix = machineValue(operand(expr, 2)) ?? NaN;
5897
- if (isFinite(radix) && radix >= 2 && radix <= 36) {
5898
- const num = machineValue(operand(expr, 1)) ?? NaN;
5899
- if (isFinite(num) && Number.isInteger(num)) {
5900
- let digits = Number(num).toString(radix);
5901
- let groupLength = 0;
5902
- if (radix === 2) {
5903
- groupLength = 4;
5904
- } else if (radix === 10) {
5905
- groupLength = 4;
5906
- } else if (radix === 16) {
5907
- groupLength = 2;
5908
- } else if (radix > 16) {
5909
- groupLength = 4;
5910
- }
5911
- if (groupLength > 0) {
5912
- const oldDigits = digits;
5913
- digits = "";
5914
- for (let i = 0; i < oldDigits.length; i++) {
5915
- if (i > 0 && i % groupLength === 0) digits = "\\, " + digits;
5916
- digits = oldDigits[oldDigits.length - i - 1] + digits;
5917
- }
5918
- }
5919
- return `(\\text{${digits}}_{${radix}}`;
5920
- }
5921
- }
5922
- return "\\operatorname{BaseForm}(" + serializer.serialize(operand(expr, 1)) + ", " + serializer.serialize(operand(expr, 2)) + ")";
5923
- }
5704
+ kind: "function",
5705
+ symbolTrigger: "and",
5706
+ parse: "And"
5924
5707
  },
5925
5708
  {
5926
- name: "Sequence",
5927
- // Use a space as a separator, otherwise a sequence of numbers
5928
- // could be interpreted as a single number.
5929
- serialize: serializeOps(" ")
5709
+ kind: "function",
5710
+ symbolTrigger: "or",
5711
+ parse: "Or"
5930
5712
  },
5931
5713
  {
5932
- name: "InvisibleOperator",
5933
- serialize: serializeOps("")
5714
+ kind: "function",
5715
+ symbolTrigger: "not",
5716
+ parse: "Not"
5934
5717
  },
5718
+ // Relations
5935
5719
  {
5936
- // The first argument is a function expression.
5937
- // The second (optional) argument is a string specifying the
5938
- // delimiters and separator.
5939
- name: "Delimiter",
5940
- serialize: (serializer, expr) => {
5941
- const style = serializer.options.groupStyle(expr, serializer.level + 1);
5942
- const arg1 = operand(expr, 1);
5943
- let delims = {
5944
- Set: "{,}",
5945
- List: "[,]",
5946
- Tuple: "(,)",
5947
- Single: "(,)",
5948
- Pair: "(,)",
5949
- Triple: "(,)",
5950
- Sequence: "(,)",
5951
- String: '""'
5952
- }[operator(arg1)];
5953
- const items = delims ? arg1 : ["Sequence", arg1];
5954
- delims ??= "(,)";
5955
- if (nops(expr) > 1) {
5956
- const op2 = stringValue(operand(expr, 2));
5957
- if (typeof op2 === "string" && op2.length <= 3) delims = op2;
5958
- }
5959
- let [open, sep, close] = ["", "", ""];
5960
- if (delims.length === 3) [open, sep, close] = delims;
5961
- else if (delims.length === 2) [open, close] = delims;
5962
- else if (delims.length === 1) sep = delims;
5963
- const body = arg1 ? items ? serializeOps(sep)(serializer, items) : serializer.serialize(arg1) : "";
5964
- return serializer.wrapString(body, style, open + close);
5965
- }
5720
+ name: "Implies",
5721
+ kind: "infix",
5722
+ precedence: 220,
5723
+ associativity: "right",
5724
+ latexTrigger: ["\\implies"],
5725
+ serialize: "\\implies"
5966
5726
  },
5967
5727
  {
5968
- name: "Tuple",
5969
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5728
+ latexTrigger: ["\\Rightarrow"],
5729
+ kind: "infix",
5730
+ precedence: 220,
5731
+ associativity: "right",
5732
+ parse: "Implies"
5970
5733
  },
5971
5734
  {
5972
- name: "Pair",
5973
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5735
+ latexTrigger: ["\\rightarrow"],
5736
+ kind: "infix",
5737
+ precedence: 220,
5738
+ associativity: "right",
5739
+ parse: "Implies"
5974
5740
  },
5975
5741
  {
5976
- name: "Triple",
5977
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5742
+ latexTrigger: ["\\Longrightarrow"],
5743
+ kind: "infix",
5744
+ precedence: 220,
5745
+ associativity: "right",
5746
+ parse: "Implies"
5978
5747
  },
5979
5748
  {
5980
- name: "Single",
5981
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5749
+ latexTrigger: ["\\longrightarrow"],
5750
+ kind: "infix",
5751
+ precedence: 220,
5752
+ associativity: "right",
5753
+ parse: "Implies"
5982
5754
  },
5983
5755
  {
5984
- name: "Domain",
5985
- serialize: (serializer, expr) => {
5986
- if (operator(expr) === "Error") return serializer.serialize(expr);
5987
- return `\\mathbf{${serializer.serialize(operand(expr, 1))}}`;
5756
+ // Non-strict mode: => for implies
5757
+ latexTrigger: ["=", ">"],
5758
+ kind: "infix",
5759
+ precedence: 220,
5760
+ associativity: "right",
5761
+ parse: (parser, lhs, until) => {
5762
+ if (parser.options.strict !== false) return null;
5763
+ const rhs = parser.parseExpression({ ...until, minPrec: 220 });
5764
+ if (rhs === null) return null;
5765
+ return ["Implies", lhs, rhs];
5988
5766
  }
5989
5767
  },
5990
5768
  {
5991
- latexTrigger: ["\\mathtip"],
5992
- parse: (parser) => {
5993
- const op1 = parser.parseGroup();
5994
- parser.parseGroup();
5995
- return op1;
5996
- }
5769
+ name: "Equivalent",
5770
+ // MathML: identical to, Mathematica: Congruent
5771
+ latexTrigger: ["\\iff"],
5772
+ kind: "infix",
5773
+ associativity: "right",
5774
+ precedence: 219
5997
5775
  },
5998
5776
  {
5999
- latexTrigger: ["\\texttip"],
6000
- parse: (parser) => {
6001
- const op1 = parser.parseGroup();
6002
- parser.parseGroup();
6003
- return op1;
6004
- }
5777
+ latexTrigger: ["\\Leftrightarrow"],
5778
+ kind: "infix",
5779
+ associativity: "right",
5780
+ precedence: 219,
5781
+ parse: "Equivalent"
6005
5782
  },
6006
5783
  {
6007
- latexTrigger: ["\\error"],
6008
- parse: (parser) => ["Error", parser.parseGroup()]
5784
+ latexTrigger: ["\\leftrightarrow"],
5785
+ kind: "infix",
5786
+ associativity: "right",
5787
+ precedence: 219,
5788
+ parse: "Equivalent"
6009
5789
  },
6010
5790
  {
6011
- name: "Error",
6012
- serialize: (serializer, expr) => {
6013
- const op1 = operand(expr, 1);
6014
- if (stringValue(op1) === "missing")
6015
- return `\\error{${serializer.options.missingSymbol ?? "\\placeholder{}"}}`;
6016
- const where = errorContextAsLatex(serializer, expr) || "\\blacksquare";
6017
- const code = operator(op1) === "ErrorCode" ? stringValue(operand(op1, 1)) : stringValue(op1);
6018
- if (code === "incompatible-type") {
6019
- if (symbol(operand(op1, 3)) === "Undefined") {
6020
- return `\\mathtip{\\error{${where}}}{\\notin ${serializer.serialize(
6021
- operand(op1, 2)
6022
- )}}`;
6023
- }
6024
- return `\\mathtip{\\error{${where}}}{\\in ${serializer.serialize(
6025
- operand(op1, 3)
6026
- )}\\notin ${serializer.serialize(operand(op1, 2))}}`;
6027
- }
6028
- if (typeof code === "string") return `\\error{${where}}`;
6029
- return `\\error{${where}}`;
6030
- }
6031
- },
6032
- {
6033
- name: "ErrorCode",
6034
- serialize: (serializer, expr) => {
6035
- const code = stringValue(operand(expr, 1));
6036
- if (code === "missing")
6037
- return serializer.options.missingSymbol ?? "\\placeholder{}";
6038
- if (code === "unexpected-command" || code === "unexpected-operator" || code === "unexpected-token" || code === "invalid-symbol" || code === "unknown-environment" || code === "unexpected-base" || code === "incompatible-type") {
6039
- return "";
6040
- }
6041
- return `\\texttip{\\error{\\blacksquare}}{\\mathtt{${code}}}`;
6042
- }
5791
+ latexTrigger: ["\\Longleftrightarrow"],
5792
+ kind: "infix",
5793
+ associativity: "right",
5794
+ precedence: 219,
5795
+ parse: "Equivalent"
6043
5796
  },
6044
5797
  {
6045
- name: "FromLatex",
6046
- serialize: (_serializer, expr) => {
6047
- return `\\texttt{${sanitizeLatex(stringValue(operand(expr, 1)))}}`;
6048
- }
5798
+ latexTrigger: ["\\longleftrightarrow"],
5799
+ kind: "infix",
5800
+ associativity: "right",
5801
+ precedence: 219,
5802
+ parse: "Equivalent"
6049
5803
  },
6050
5804
  {
6051
- name: "Latex",
6052
- serialize: (serializer, expr) => {
6053
- if (expr === null) return "";
6054
- return joinLatex(
6055
- mapArgs(expr, (x) => stringValue(x) ?? serializer.serialize(x))
6056
- );
5805
+ // Non-strict mode: <=> for equivalence
5806
+ latexTrigger: ["<", "=", ">"],
5807
+ kind: "infix",
5808
+ precedence: 219,
5809
+ associativity: "right",
5810
+ parse: (parser, lhs, until) => {
5811
+ if (parser.options.strict !== false) return null;
5812
+ const rhs = parser.parseExpression({ ...until, minPrec: 219 });
5813
+ if (rhs === null) return null;
5814
+ return ["Equivalent", lhs, rhs];
6057
5815
  }
6058
5816
  },
6059
5817
  {
6060
- name: "LatexString",
6061
- serialize: (serializer, expr) => {
6062
- if (expr === null) return "";
6063
- return joinLatex(mapArgs(expr, (x) => serializer.serialize(x)));
5818
+ latexTrigger: ["\\equiv"],
5819
+ kind: "infix",
5820
+ associativity: "right",
5821
+ precedence: 219,
5822
+ parse: (parser, lhs, terminator) => {
5823
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 219 });
5824
+ const index = parser.index;
5825
+ const modulus = parser.parseExpression({ ...terminator, minPrec: 219 });
5826
+ if (modulus !== null && operator(modulus) === "Mod")
5827
+ return ["Congruent", lhs, rhs, missingIfEmpty(operand(modulus, 1))];
5828
+ parser.index = index;
5829
+ return ["Equivalent", lhs, missingIfEmpty(rhs)];
6064
5830
  }
6065
5831
  },
6066
- { name: "LatexTokens", serialize: serializeLatexTokens },
6067
5832
  {
6068
- name: "At",
6069
- kind: "postfix",
6070
- precedence: 810,
6071
- latexTrigger: ["["],
6072
- parse: parseAt("]"),
6073
- serialize: (serializer, expr) => joinLatex(["\\lbrack", serializeOps(", ")(serializer, expr), "\\rbrack"])
5833
+ name: "Proves",
5834
+ kind: "infix",
5835
+ latexTrigger: ["\\vdash"],
5836
+ precedence: 220,
5837
+ associativity: "right",
5838
+ serialize: "\\vdash"
6074
5839
  },
6075
5840
  {
6076
- kind: "postfix",
6077
- precedence: 810,
6078
- latexTrigger: ["\\lbrack"],
6079
- parse: parseAt("\\rbrack")
5841
+ name: "Entails",
5842
+ kind: "infix",
5843
+ latexTrigger: ["\\vDash"],
5844
+ precedence: 220,
5845
+ associativity: "right",
5846
+ serialize: "\\vDash"
6080
5847
  },
6081
5848
  {
6082
- kind: "postfix",
6083
- precedence: 810,
6084
- latexTrigger: ["\\left", "\\lbrack"],
6085
- parse: parseAt("\\right", "\\rbrack")
5849
+ name: "Satisfies",
5850
+ kind: "infix",
5851
+ latexTrigger: ["\\models"],
5852
+ precedence: 220,
5853
+ associativity: "right",
5854
+ serialize: "\\models"
6086
5855
  },
5856
+ // Quantifiers: for all, exists
6087
5857
  {
6088
- kind: "postfix",
6089
- latexTrigger: ["_"],
6090
- parse: (parser, lhs, _until) => {
6091
- let rhs = parser.parseGroup() ?? parser.parseToken();
6092
- if (rhs === null && parser.options.strict === false && parser.peek === "(")
6093
- rhs = parser.parseEnclosure();
6094
- const sym = symbol(lhs);
6095
- if (rhs !== null && (sym && parser.getSymbolType(sym).matches("indexed_collection") || operator(lhs) === "List")) {
6096
- if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
6097
- if (operator(rhs) === "Sequence") return ["At", lhs, ...operands(rhs)];
6098
- return ["At", lhs, rhs];
6099
- }
6100
- return ["Subscript", lhs, rhs];
6101
- }
5858
+ name: "ForAll",
5859
+ kind: "prefix",
5860
+ latexTrigger: ["\\forall"],
5861
+ precedence: 200,
5862
+ // Has to be lower than COMPARISON_PRECEDENCE
5863
+ serialize: serializeQuantifier("\\forall"),
5864
+ parse: parseQuantifier("ForAll")
6102
5865
  },
6103
5866
  {
6104
- name: "List",
6105
- kind: "matchfix",
6106
- openTrigger: "[",
6107
- closeTrigger: "]",
6108
- parse: parseBrackets,
6109
- serialize: serializeList
5867
+ name: "Exists",
5868
+ kind: "prefix",
5869
+ latexTrigger: ["\\exists"],
5870
+ precedence: 200,
5871
+ // Has to be lower than COMPARISON_PRECEDENCE,
5872
+ serialize: serializeQuantifier("\\exists"),
5873
+ parse: parseQuantifier("Exists")
6110
5874
  },
6111
5875
  {
6112
- kind: "matchfix",
6113
- openTrigger: "(",
6114
- closeTrigger: ")",
6115
- parse: parseParenDelimiter
5876
+ name: "ExistsUnique",
5877
+ kind: "prefix",
5878
+ latexTrigger: ["\\exists", "!"],
5879
+ precedence: 200,
5880
+ // Has to be lower than COMPARISON_PRECEDENCE,
5881
+ serialize: serializeQuantifier("\\exists!"),
5882
+ parse: parseQuantifier("ExistsUnique")
6116
5883
  },
6117
5884
  {
6118
- latexTrigger: [","],
6119
- kind: "infix",
6120
- precedence: 20,
6121
- // Unlike the matchfix version of List,
6122
- // when the comma operator is used, the lhs and rhs are flattened,
6123
- // i.e. `1,2,3` -> `["Delimiter", ["List", 1, 2, 3], ","]`,
6124
- // and `1, (2, 3)` -> `["Delimiter",
6125
- // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "()", ","]]],
6126
- parse: (parser, lhs, terminator) => {
6127
- const seq = parseSequence(parser, terminator, lhs, 20, ",");
6128
- if (seq === null) return null;
6129
- return ["Delimiter", ["Sequence", ...seq], { str: "," }];
6130
- }
5885
+ name: "NotForAll",
5886
+ kind: "prefix",
5887
+ latexTrigger: ["\\lnot", "\\forall"],
5888
+ precedence: 200,
5889
+ // Has to be lower than COMPARISON_PRECEDENCE
5890
+ serialize: serializeQuantifier("\\lnot\\forall"),
5891
+ parse: parseQuantifier("NotForAll")
6131
5892
  },
6132
- // Entry to handle the case of a single comma
6133
- // with a missing lhs.
6134
5893
  {
6135
- latexTrigger: [","],
5894
+ name: "NotExists",
6136
5895
  kind: "prefix",
6137
- precedence: 20,
6138
- parse: (parser, terminator) => {
6139
- const seq = parseSequence(parser, terminator, null, 20, ",");
6140
- if (seq === null) return null;
6141
- return ["Delimiter", ["Sequence", ...seq], { str: "," }];
6142
- }
5896
+ latexTrigger: ["\\lnot", "\\exists"],
5897
+ precedence: 200,
5898
+ // Has to be lower than COMPARISON_PRECEDENCE,
5899
+ serialize: serializeQuantifier("\\lnot\\exists"),
5900
+ parse: parseQuantifier("NotExists")
6143
5901
  },
6144
5902
  {
6145
- name: "Range",
6146
- latexTrigger: [".", "."],
6147
- kind: "infix",
6148
- // associativity: 'left',
6149
- precedence: 800,
6150
- parse: parseRange,
5903
+ name: "KroneckerDelta",
5904
+ kind: "prefix",
5905
+ latexTrigger: ["\\delta", "_"],
5906
+ precedence: 200,
6151
5907
  serialize: (serializer, expr) => {
6152
5908
  const args = operands(expr);
6153
- if (args.length === 0) return "";
6154
- if (args.length === 1)
6155
- return "1.." + serializer.serialize(operand(expr, 1));
6156
- if (args.length === 2)
6157
- return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(operand(expr, 2), 10);
6158
- if (args.length === 3) {
6159
- const step = machineValue(operand(expr, 3));
6160
- const start = machineValue(operand(expr, 1));
6161
- if (step !== null && start !== null) {
6162
- return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(start + step, 10) + ".." + serializer.wrap(operand(expr, 2), 10);
6163
- }
6164
- return serializer.wrap(operand(expr, 1), 10) + "..(" + (serializer.wrap(operand(expr, 1), ADDITION_PRECEDENCE) + "+" + serializer.wrap(operand(expr, 3), ADDITION_PRECEDENCE)) + ").." + serializer.wrap(operand(expr, 2), 10);
5909
+ if (args.length === 0) return "\\delta";
5910
+ if (args.every((x) => symbol(x)))
5911
+ return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join("")}}`;
5912
+ return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join(", ")}}`;
5913
+ },
5914
+ parse: (parser) => {
5915
+ const group = parser.parseGroup();
5916
+ if (group === null) {
5917
+ const token = parser.parseToken();
5918
+ if (!token) return null;
5919
+ return ["KroneckerDelta", token];
6165
5920
  }
6166
- return "";
5921
+ const seq = getSequence(group);
5922
+ if (seq && seq.length <= 2) return ["KroneckerDelta", ...seq];
5923
+ if (operator(group) === "InvisibleOperator")
5924
+ return ["KroneckerDelta", ...operands(group)];
5925
+ if (group !== null) return ["KroneckerDelta", group];
5926
+ return null;
6167
5927
  }
6168
5928
  },
5929
+ // Iverson brackets. Also called the "indicator function"
5930
+ // Must have a single argument, a relational expression, i.e.
5931
+ // `[ a = b ]` or `[ x \leq 0 ]`
5932
+ // Otherwise, it gets rejected, it could be something else, like a list or
5933
+ // tuple.
6169
5934
  {
6170
- latexTrigger: [";"],
6171
- kind: "infix",
6172
- precedence: 19,
6173
- parse: (parser, lhs, terminator) => {
6174
- const seq = parseSequence(parser, terminator, lhs, 19, ";");
6175
- if (seq === null) return null;
6176
- if (seq.some((e) => operator(e) === "Assign"))
6177
- return buildBlockFromSequence(seq);
6178
- return ["Delimiter", ["Sequence", ...seq], "';'"];
5935
+ name: "Boole",
5936
+ kind: "matchfix",
5937
+ openTrigger: "[",
5938
+ closeTrigger: "]",
5939
+ // serialize: (serializer: Serializer, expr: MathJsonExpression) => {
5940
+ // const args = ops(expr);
5941
+ // return `[${serializer.serialize(arg)}]`;
5942
+ // },
5943
+ parse: (_parser, body) => {
5944
+ const h = operator(body);
5945
+ if (!h) return null;
5946
+ if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
5947
+ return ["Boole", body];
6179
5948
  }
6180
5949
  },
6181
- // \text{where} — variable binding infix
6182
5950
  {
6183
- latexTrigger: ["\\text"],
6184
- kind: "infix",
6185
- associativity: "none",
6186
- precedence: 21,
6187
- // Above ; (19) and , (20), very low binding
6188
- parse: (parser, lhs, until) => {
6189
- const start = parser.index;
6190
- if (!matchTextKeyword(parser, "where")) {
6191
- parser.index = start;
6192
- return null;
6193
- }
6194
- return parseWhereExpression(parser, lhs, until);
5951
+ kind: "matchfix",
5952
+ openTrigger: "\\llbracket",
5953
+ closeTrigger: "\\rrbracket",
5954
+ parse: (_parser, body) => {
5955
+ const h = operator(body);
5956
+ if (!h) return null;
5957
+ if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
5958
+ return ["Boole", body];
6195
5959
  }
6196
5960
  },
6197
- // \operatorname{where}
6198
- {
6199
- symbolTrigger: "where",
6200
- kind: "infix",
6201
- associativity: "none",
6202
- precedence: 21,
6203
- parse: (parser, lhs, until) => parseWhereExpression(parser, lhs, until)
6204
- },
6205
- // Block serializer — used by both `where` and semicolon blocks
5961
+ // Predicate application in First-Order Logic.
5962
+ // ["Predicate", "P", "x", "y"] serializes to "P(x, y)"
6206
5963
  {
6207
- name: "Block",
5964
+ name: "Predicate",
6208
5965
  serialize: (serializer, expr) => {
6209
5966
  const args = operands(expr);
6210
- if (!args || args.length === 0) return "";
6211
- const parts = args.filter((a) => operator(a) !== "Declare").map((a) => serializer.serialize(a));
6212
- return parts.join("; ");
5967
+ if (args.length === 0) return "";
5968
+ const pred = args[0];
5969
+ const predStr = typeof pred === "string" ? pred : serializer.serialize(pred);
5970
+ if (args.length === 1) return predStr;
5971
+ const argStrs = args.slice(1).map((arg) => serializer.serialize(arg));
5972
+ return `${predStr}(${argStrs.join(", ")})`;
5973
+ }
5974
+ }
5975
+ ];
5976
+ function serializeQuantifier(quantifierSymbol) {
5977
+ return (serializer, expr) => {
5978
+ const args = operands(expr);
5979
+ if (args.length === 0) return quantifierSymbol;
5980
+ if (args.length === 1)
5981
+ return `${quantifierSymbol} ${serializer.serialize(args[0])}`;
5982
+ const boundVar = serializer.serialize(args[0]);
5983
+ const body = serializer.serialize(args[1]);
5984
+ return `${quantifierSymbol} ${boundVar}, ${body}`;
5985
+ };
5986
+ }
5987
+ function tightBindingCondition(p, terminator) {
5988
+ return p.peek === "\\to" || p.peek === "\\rightarrow" || p.peek === "\\implies" || p.peek === "\\Rightarrow" || p.peek === "\\iff" || p.peek === "\\Leftrightarrow" || p.peek === "\\land" || p.peek === "\\wedge" || p.peek === "\\lor" || p.peek === "\\vee" || (terminator.condition?.(p) ?? false);
5989
+ }
5990
+ function parseQuantifier(kind) {
5991
+ return (parser, terminator) => {
5992
+ const index = parser.index;
5993
+ const useTightBinding = parser.options.quantifierScope !== "loose";
5994
+ const symbol2 = parser.parseSymbol(terminator);
5995
+ if (symbol2) {
5996
+ parser.skipSpace();
5997
+ if (parser.match(",") || parser.match("\\mid") || parser.match(".") || parser.match(":") || parser.match("\\colon")) {
5998
+ const bodyTerminator = useTightBinding ? {
5999
+ ...terminator,
6000
+ condition: (p) => tightBindingCondition(p, terminator)
6001
+ } : terminator;
6002
+ parser.enterQuantifierScope();
6003
+ const body2 = parser.parseExpression(bodyTerminator);
6004
+ parser.exitQuantifierScope();
6005
+ return [kind, symbol2, missingIfEmpty(body2)];
6006
+ }
6007
+ parser.enterQuantifierScope();
6008
+ const body = parser.parseEnclosure();
6009
+ parser.exitQuantifierScope();
6010
+ if (body) return [kind, symbol2, missingIfEmpty(body)];
6011
+ }
6012
+ parser.index = index;
6013
+ const condTerminator = {
6014
+ ...terminator,
6015
+ condition: (p) => p.peek === ":" || p.peek === "\\colon" || (terminator.condition?.(p) ?? false)
6016
+ };
6017
+ const condition = parser.parseExpression(condTerminator);
6018
+ if (condition === null) return null;
6019
+ parser.skipSpace();
6020
+ if (parser.matchAny([",", "\\mid", ":", "\\colon"])) {
6021
+ const bodyTerminator = useTightBinding ? {
6022
+ ...terminator,
6023
+ condition: (p) => tightBindingCondition(p, terminator)
6024
+ } : terminator;
6025
+ parser.enterQuantifierScope();
6026
+ const body = parser.parseExpression(bodyTerminator);
6027
+ parser.exitQuantifierScope();
6028
+ return [kind, condition, missingIfEmpty(body)];
6029
+ }
6030
+ if (parser.match("(")) {
6031
+ parser.enterQuantifierScope();
6032
+ const body = parser.parseExpression(terminator);
6033
+ parser.exitQuantifierScope();
6034
+ if (!parser.match(")")) return null;
6035
+ return [kind, condition, missingIfEmpty(body)];
6036
+ }
6037
+ return null;
6038
+ };
6039
+ }
6040
+
6041
+ // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
6042
+ function parseSequence(parser, terminator, lhs, prec, sep) {
6043
+ if (terminator && terminator.minPrec >= prec) return null;
6044
+ const result = lhs ? [lhs] : ["Nothing"];
6045
+ let done = false;
6046
+ while (!done) {
6047
+ done = true;
6048
+ parser.skipSpace();
6049
+ while (parser.match(sep)) {
6050
+ result.push("Nothing");
6051
+ parser.skipSpace();
6052
+ }
6053
+ parser.skipVisualSpace();
6054
+ if (parser.atTerminator(terminator)) {
6055
+ result.push("Nothing");
6056
+ } else {
6057
+ const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
6058
+ result.push(rhs ?? "Nothing");
6059
+ done = rhs === null;
6060
+ }
6061
+ if (!done) {
6062
+ parser.skipSpace();
6063
+ done = !parser.match(sep);
6064
+ if (!done) parser.skipVisualSpace();
6065
+ }
6066
+ }
6067
+ return result;
6068
+ }
6069
+ function serializeOps(sep = "") {
6070
+ return (serializer, expr) => {
6071
+ if (!expr) return "";
6072
+ const xs = operands(expr);
6073
+ if (xs.length === 0) return "";
6074
+ if (xs.length === 1) return serializer.serialize(xs[0]);
6075
+ sep = {
6076
+ "&": "\\&",
6077
+ ":": "\\colon",
6078
+ "|": "\\mvert",
6079
+ "-": "-",
6080
+ "\xB7": "\\cdot",
6081
+ // U+00B7 MIDDLE DOT
6082
+ "\u2012": "-",
6083
+ // U+2012 FIGURE DASH
6084
+ "\u2013": "--",
6085
+ // U+2013 EN DASH
6086
+ "\u2014": "---",
6087
+ // U+2014 EM DASH
6088
+ "\u2015": "-",
6089
+ // U+2015 HORIZONTAL BAR
6090
+ "\u2022": "\\bullet",
6091
+ // U+2022 BULLET
6092
+ "\u2026": "\\ldots"
6093
+ }[sep] ?? sep;
6094
+ const ys = xs.reduce((acc, item) => {
6095
+ acc.push(serializer.serialize(item), sep);
6096
+ return acc;
6097
+ }, []);
6098
+ ys.pop();
6099
+ return joinLatex(ys);
6100
+ };
6101
+ }
6102
+ var DEFINITIONS_CORE = [
6103
+ //
6104
+ // Constants
6105
+ //
6106
+ {
6107
+ latexTrigger: ["\\placeholder"],
6108
+ kind: "symbol",
6109
+ parse: (parser) => {
6110
+ while (parser.match("<space>")) {
6111
+ }
6112
+ if (parser.match("["))
6113
+ while (!parser.match("]") && !parser.atBoundary) parser.nextToken();
6114
+ while (parser.match("<space>")) {
6115
+ }
6116
+ if (parser.match("<{>"))
6117
+ while (!parser.match("<}>") && !parser.atBoundary) parser.nextToken();
6118
+ return "Nothing";
6213
6119
  }
6214
6120
  },
6215
- // Serializer for If expressions (separate from the parser entry
6216
- // because name-based entries affect kind-based indexing)
6121
+ { name: "ContinuationPlaceholder", latexTrigger: ["\\dots"] },
6122
+ { latexTrigger: ["\\ldots"], parse: "ContinuationPlaceholder" },
6123
+ { latexTrigger: [".", ".", "."], parse: "ContinuationPlaceholder" },
6124
+ //
6125
+ // Functions
6126
+ //
6127
+ // Anonymous function, i.e. `(x) \mapsto x^2`
6217
6128
  {
6218
- name: "If",
6129
+ name: "Function",
6130
+ latexTrigger: ["\\mapsto"],
6131
+ kind: "infix",
6132
+ precedence: ARROW_PRECEDENCE,
6133
+ // MathML rightwards arrow
6134
+ parse: (parser, lhs, _until) => {
6135
+ let params = [];
6136
+ if (operator(lhs) === "Delimiter") lhs = operand(lhs, 1) ?? "Nothing";
6137
+ if (operator(lhs) === "Sequence") {
6138
+ for (const x of operands(lhs)) {
6139
+ if (!symbol(x)) return null;
6140
+ params.push(symbol(x));
6141
+ }
6142
+ } else {
6143
+ if (!symbol(lhs)) return null;
6144
+ params = [symbol(lhs)];
6145
+ }
6146
+ let rhs = parser.parseExpression({ minPrec: ARROW_PRECEDENCE }) ?? "Nothing";
6147
+ if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
6148
+ if (operator(rhs) === "Sequence") rhs = ["Block", ...operands(rhs)];
6149
+ return ["Function", rhs, ...params];
6150
+ },
6219
6151
  serialize: (serializer, expr) => {
6220
6152
  const args = operands(expr);
6221
- if (!args || args.length < 3) return "";
6153
+ if (args.length < 1) return "()\\mapsto()";
6154
+ if (args.length === 1)
6155
+ return joinLatex([
6156
+ "()",
6157
+ "\\mapsto",
6158
+ serializer.serialize(operand(expr, 1))
6159
+ ]);
6160
+ if (args.length === 2) {
6161
+ return joinLatex([
6162
+ serializer.serialize(operand(expr, 2)),
6163
+ "\\mapsto",
6164
+ serializer.serialize(operand(expr, 1))
6165
+ ]);
6166
+ }
6222
6167
  return joinLatex([
6223
- "\\text{if }",
6224
- serializer.serialize(args[0]),
6225
- "\\text{ then }",
6226
- serializer.serialize(args[1]),
6227
- "\\text{ else }",
6228
- serializer.serialize(args[2])
6168
+ serializer.wrapString(
6169
+ operands(expr)?.slice(1).map((x) => serializer.serialize(x)).join(", "),
6170
+ "normal"
6171
+ ),
6172
+ "\\mapsto",
6173
+ serializer.serialize(operand(expr, 1))
6229
6174
  ]);
6230
6175
  }
6231
6176
  },
6232
- // Serializer for Loop expressions
6233
6177
  {
6234
- name: "Loop",
6178
+ name: "Apply",
6179
+ kind: "function",
6180
+ symbolTrigger: "apply",
6235
6181
  serialize: (serializer, expr) => {
6236
- const args = operands(expr);
6237
- if (!args || args.length < 2) return "";
6238
- const body = args[0];
6239
- const indexing = args[1];
6240
- if (operator(indexing) === "Element") {
6241
- const index = operand(indexing, 1);
6242
- const range = operand(indexing, 2);
6243
- if (operator(range) === "Range") {
6244
- const lo = operand(range, 1);
6245
- const hi = operand(range, 2);
6246
- return joinLatex([
6247
- "\\text{for }",
6248
- serializer.serialize(index),
6249
- "\\text{ from }",
6250
- serializer.serialize(lo),
6251
- "\\text{ to }",
6252
- serializer.serialize(hi),
6253
- "\\text{ do }",
6254
- serializer.serialize(body)
6255
- ]);
6256
- }
6182
+ const lhs = operand(expr, 1);
6183
+ const h = operator(lhs);
6184
+ if (h === "InverseFunction" || h === "Derivative") {
6185
+ const style2 = serializer.options.applyFunctionStyle(
6186
+ expr,
6187
+ serializer.level
6188
+ );
6189
+ const args = operands(expr).slice(1);
6190
+ return serializer.serializeFunction(
6191
+ lhs,
6192
+ serializer.dictionary.ids.get(h)
6193
+ ) + serializer.wrapString(
6194
+ args.map((x) => serializer.serialize(x)).join(", "),
6195
+ style2
6196
+ );
6197
+ }
6198
+ const rhs = operand(expr, 2);
6199
+ if (typeof lhs === "string" || !rhs) {
6200
+ const fn = operands(expr).slice(1);
6201
+ return serializer.serialize(fn);
6202
+ }
6203
+ if (nops(expr) === 2) {
6204
+ return joinLatex([
6205
+ serializer.wrap(lhs, 20),
6206
+ "\\lhd",
6207
+ serializer.wrap(rhs, 20)
6208
+ ]);
6257
6209
  }
6210
+ const style = serializer.options.applyFunctionStyle(
6211
+ expr,
6212
+ serializer.level
6213
+ );
6258
6214
  return joinLatex([
6259
- "\\operatorname{Loop}(",
6260
- serializer.serialize(body),
6261
- ", ",
6262
- serializer.serialize(indexing),
6263
- ")"
6215
+ "\\operatorname{apply}",
6216
+ serializer.wrapString(
6217
+ serializer.serialize(h) + ", " + serializer.serialize(["List", ...operands(expr)]),
6218
+ style
6219
+ )
6264
6220
  ]);
6265
6221
  }
6266
6222
  },
6267
- // Serializer for Break
6268
- { name: "Break", serialize: () => "\\text{break}" },
6269
- // Serializer for Continue
6270
- { name: "Continue", serialize: () => "\\text{continue}" },
6271
- // Serializer for Return
6272
6223
  {
6273
- name: "Return",
6274
- serialize: (serializer, expr) => {
6275
- const arg = operand(expr, 1);
6276
- if (!arg || symbol(arg) === "Nothing") return "\\text{return}";
6277
- return joinLatex(["\\text{return }", serializer.serialize(arg)]);
6278
- }
6224
+ latexTrigger: "\\lhd",
6225
+ kind: "infix",
6226
+ precedence: 20,
6227
+ parse: "Apply"
6279
6228
  },
6280
- // Also match `\operatorname{if}` / `\mathrm{if}`
6281
6229
  {
6282
- symbolTrigger: "if",
6283
- kind: "prefix",
6284
- precedence: 245,
6285
- parse: (parser, until) => {
6286
- return parseIfExpression(parser, until);
6230
+ latexTrigger: "\\rhd",
6231
+ kind: "infix",
6232
+ precedence: 20,
6233
+ parse: (parser, lhs, _until) => {
6234
+ const rhs = parser.parseExpression({ minPrec: 21 }) ?? "Nothing";
6235
+ return ["Apply", rhs, lhs];
6287
6236
  }
6288
6237
  },
6289
- // \operatorname{for}
6290
- {
6291
- symbolTrigger: "for",
6292
- kind: "prefix",
6293
- precedence: 245,
6294
- parse: (parser, until) => parseForExpression(parser, until)
6295
- },
6296
- // \operatorname{break}
6297
- {
6298
- symbolTrigger: "break",
6299
- kind: "prefix",
6300
- precedence: 245,
6301
- parse: () => ["Break"]
6302
- },
6303
- // \operatorname{continue}
6304
6238
  {
6305
- symbolTrigger: "continue",
6306
- kind: "prefix",
6307
- precedence: 245,
6308
- parse: () => ["Continue"]
6309
- },
6310
- // \operatorname{return}
6311
- {
6312
- symbolTrigger: "return",
6313
- kind: "prefix",
6314
- precedence: 245,
6315
- parse: (parser, until) => [
6316
- "Return",
6317
- parser.parseExpression(until) ?? "Nothing"
6318
- ]
6239
+ name: "EvaluateAt",
6240
+ openTrigger: ".",
6241
+ closeTrigger: "|",
6242
+ kind: "matchfix",
6243
+ serialize: (serializer, expr) => {
6244
+ const fn = operand(expr, 1);
6245
+ if (!fn) return "";
6246
+ const args = operands(expr).slice(1);
6247
+ if (operator(fn) === "Function") {
6248
+ const parameters = operands(fn).slice(1);
6249
+ let body = operand(fn, 1);
6250
+ if (operator(body) === "Block" && nops(body) === 1)
6251
+ body = operand(body, 1);
6252
+ if (parameters.length > 0) {
6253
+ return `\\left.\\left(${serializer.serialize(
6254
+ body
6255
+ )}\\right)\\right|_{${parameters.map(
6256
+ (x, i) => `${serializer.serialize(x)}=${serializer.serialize(args[i])}`
6257
+ ).join(", ")}}`;
6258
+ }
6259
+ }
6260
+ return `\\left.\\left(${serializer.serialize(fn)}\\right)\\right|_{${args.map((x) => serializer.serialize(x)).join(", ")}}`;
6261
+ }
6319
6262
  },
6263
+ // The mathtools package includes several synonmyms for \colonequals. The
6264
+ // preferred one as of summer 2022 is `\coloneq` (see § 3.7.3 https://ctan.math.illinois.edu/macros/latex/contrib/mathtools/mathtools.pdf)
6320
6265
  {
6321
- name: "String",
6322
- latexTrigger: ["\\text"],
6323
- parse: (parser, until) => {
6324
- const start = parser.index;
6325
- if (matchTextKeyword(parser, "if"))
6326
- return parseIfExpression(parser, until);
6327
- parser.index = start;
6328
- if (matchTextKeyword(parser, "for"))
6329
- return parseForExpression(parser, until);
6330
- parser.index = start;
6331
- if (matchTextKeyword(parser, "break"))
6332
- return ["Break"];
6333
- parser.index = start;
6334
- if (matchTextKeyword(parser, "continue"))
6335
- return ["Continue"];
6336
- parser.index = start;
6337
- if (matchTextKeyword(parser, "return"))
6338
- return [
6339
- "Return",
6340
- parser.parseExpression(until) ?? "Nothing"
6341
- ];
6342
- parser.index = start;
6343
- return parseTextRun(parser);
6344
- },
6266
+ name: "Assign",
6267
+ latexTrigger: "\\coloneq",
6268
+ kind: "infix",
6269
+ associativity: "right",
6270
+ precedence: ASSIGNMENT_PRECEDENCE,
6345
6271
  serialize: (serializer, expr) => {
6346
- const args = operands(expr);
6347
- if (args.length === 0) return "\\text{}";
6272
+ const id = unhold(operand(expr, 1));
6273
+ if (operator(operand(expr, 2)) === "Function") {
6274
+ const op_2 = operand(expr, 2);
6275
+ const body = unhold(operand(op_2, 1));
6276
+ const args = operands(op_2).slice(1);
6277
+ return joinLatex([
6278
+ serializer.serialize(id),
6279
+ serializer.wrapString(
6280
+ args.map((x) => serializer.serialize(x)).join(", "),
6281
+ serializer.options.applyFunctionStyle(expr, serializer.level)
6282
+ ),
6283
+ "\\coloneq",
6284
+ serializer.serialize(body)
6285
+ ]);
6286
+ }
6348
6287
  return joinLatex([
6349
- "\\text{",
6350
- args.map((x) => serializer.serialize(x)).join(""),
6351
- "}"
6288
+ serializer.serialize(id),
6289
+ "\\coloneq",
6290
+ serializer.serialize(operand(expr, 2))
6352
6291
  ]);
6353
- }
6292
+ },
6293
+ parse: parseAssign
6354
6294
  },
6355
6295
  {
6356
- name: "Subscript",
6357
- latexTrigger: ["_"],
6296
+ latexTrigger: "\\coloneqq",
6358
6297
  kind: "infix",
6359
- serialize: (serializer, expr) => {
6360
- if (nops(expr) === 2) {
6361
- return serializer.serialize(operand(expr, 1)) + "_{" + serializer.serialize(operand(expr, 2)) + "}";
6362
- }
6363
- return "_{" + serializer.serialize(operand(expr, 1)) + "}";
6364
- }
6298
+ associativity: "right",
6299
+ precedence: ASSIGNMENT_PRECEDENCE,
6300
+ parse: parseAssign
6365
6301
  },
6366
- { name: "Superplus", latexTrigger: ["^", "+"], kind: "postfix" },
6367
- { name: "Subplus", latexTrigger: ["_", "+"], kind: "postfix" },
6302
+ // From the colonequals package:
6368
6303
  {
6369
- name: "Superminus",
6370
- latexTrigger: ["^", "-"],
6371
- kind: "postfix",
6372
- parse: (parser, lhs) => {
6373
- if (parser.options.strict === false && /^[0-9]$/.test(parser.peek))
6374
- return null;
6375
- return ["Superminus", lhs];
6376
- }
6304
+ latexTrigger: "\\colonequals",
6305
+ kind: "infix",
6306
+ associativity: "right",
6307
+ precedence: ASSIGNMENT_PRECEDENCE,
6308
+ parse: parseAssign
6377
6309
  },
6378
- { name: "Subminus", latexTrigger: ["_", "-"], kind: "postfix" },
6379
6310
  {
6380
- latexTrigger: ["^", "*"],
6381
- kind: "postfix",
6382
- parse: (_parser, lhs) => ["Superstar", lhs]
6311
+ latexTrigger: [":", "="],
6312
+ kind: "infix",
6313
+ associativity: "right",
6314
+ precedence: ASSIGNMENT_PRECEDENCE,
6315
+ parse: parseAssign
6383
6316
  },
6384
- // { name: 'Superstar', latexTrigger: ['^', '\\star'], kind: 'postfix' },
6317
+ // General colon operator (type annotation, mapping notation)
6318
+ // Precedence below assignment (260) so `:=` takes priority,
6319
+ // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
6385
6320
  {
6386
- latexTrigger: ["_", "*"],
6387
- kind: "postfix",
6388
- parse: (_parser, lhs) => ["Substar", lhs]
6321
+ name: "Colon",
6322
+ latexTrigger: ":",
6323
+ kind: "infix",
6324
+ associativity: "right",
6325
+ precedence: 250,
6326
+ serialize: (serializer, expr) => joinLatex([
6327
+ serializer.serialize(operand(expr, 1)),
6328
+ "\\colon",
6329
+ serializer.serialize(operand(expr, 2))
6330
+ ])
6389
6331
  },
6390
- { name: "Substar", latexTrigger: ["_", "\\star"], kind: "postfix" },
6391
- { name: "Superdagger", latexTrigger: ["^", "\\dagger"], kind: "postfix" },
6392
6332
  {
6393
- latexTrigger: ["^", "\\dag"],
6394
- kind: "postfix",
6395
- parse: (_parser, lhs) => ["Superdagger", lhs]
6333
+ latexTrigger: "\\colon",
6334
+ kind: "infix",
6335
+ associativity: "right",
6336
+ precedence: 250,
6337
+ parse: "Colon"
6396
6338
  },
6397
6339
  {
6398
- name: "Prime",
6399
- latexTrigger: ["^", "\\prime"],
6400
- // Note: we don't need a precedence because the trigger is '^'
6401
- // and '^' (and '_') are treated specially by the parser.
6402
- kind: "postfix",
6403
- parse: (parser, lhs) => parsePrime(parser, lhs, 1),
6340
+ name: "BaseForm",
6404
6341
  serialize: (serializer, expr) => {
6405
- const n2 = machineValue(operand(expr, 2)) ?? 1;
6406
- const base = serializer.serialize(operand(expr, 1));
6407
- if (n2 === 1) return base + "^\\prime";
6408
- if (n2 === 2) return base + "^\\doubleprime";
6409
- if (n2 === 3) return base + "^\\tripleprime";
6410
- return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
6342
+ const radix = machineValue(operand(expr, 2)) ?? NaN;
6343
+ if (isFinite(radix) && radix >= 2 && radix <= 36) {
6344
+ const num = machineValue(operand(expr, 1)) ?? NaN;
6345
+ if (isFinite(num) && Number.isInteger(num)) {
6346
+ let digits = Number(num).toString(radix);
6347
+ let groupLength = 0;
6348
+ if (radix === 2) {
6349
+ groupLength = 4;
6350
+ } else if (radix === 10) {
6351
+ groupLength = 4;
6352
+ } else if (radix === 16) {
6353
+ groupLength = 2;
6354
+ } else if (radix > 16) {
6355
+ groupLength = 4;
6356
+ }
6357
+ if (groupLength > 0) {
6358
+ const oldDigits = digits;
6359
+ digits = "";
6360
+ for (let i = 0; i < oldDigits.length; i++) {
6361
+ if (i > 0 && i % groupLength === 0) digits = "\\, " + digits;
6362
+ digits = oldDigits[oldDigits.length - i - 1] + digits;
6363
+ }
6364
+ }
6365
+ return `(\\text{${digits}}_{${radix}}`;
6366
+ }
6367
+ }
6368
+ return "\\operatorname{BaseForm}(" + serializer.serialize(operand(expr, 1)) + ", " + serializer.serialize(operand(expr, 2)) + ")";
6411
6369
  }
6412
6370
  },
6413
6371
  {
6414
- latexTrigger: "^{\\prime\\prime}",
6415
- kind: "postfix",
6416
- parse: (parser, lhs) => parsePrime(parser, lhs, 2)
6372
+ name: "Sequence",
6373
+ // Use a space as a separator, otherwise a sequence of numbers
6374
+ // could be interpreted as a single number.
6375
+ serialize: serializeOps(" ")
6417
6376
  },
6418
6377
  {
6419
- latexTrigger: "^{\\prime\\prime\\prime}",
6420
- kind: "postfix",
6421
- parse: (parser, lhs) => parsePrime(parser, lhs, 3)
6378
+ name: "InvisibleOperator",
6379
+ serialize: serializeOps("")
6422
6380
  },
6423
6381
  {
6424
- latexTrigger: ["^", "\\doubleprime"],
6425
- kind: "postfix",
6426
- parse: (parser, lhs) => parsePrime(parser, lhs, 2)
6382
+ // The first argument is a function expression.
6383
+ // The second (optional) argument is a string specifying the
6384
+ // delimiters and separator.
6385
+ name: "Delimiter",
6386
+ serialize: (serializer, expr) => {
6387
+ const style = serializer.options.groupStyle(expr, serializer.level + 1);
6388
+ const arg1 = operand(expr, 1);
6389
+ let delims = {
6390
+ Set: "{,}",
6391
+ List: "[,]",
6392
+ Tuple: "(,)",
6393
+ Single: "(,)",
6394
+ Pair: "(,)",
6395
+ Triple: "(,)",
6396
+ Sequence: "(,)",
6397
+ String: '""'
6398
+ }[operator(arg1)];
6399
+ const items = delims ? arg1 : ["Sequence", arg1];
6400
+ delims ??= "(,)";
6401
+ if (nops(expr) > 1) {
6402
+ const op2 = stringValue(operand(expr, 2));
6403
+ if (typeof op2 === "string" && op2.length <= 3) delims = op2;
6404
+ }
6405
+ let [open, sep, close] = ["", "", ""];
6406
+ if (delims.length === 3) [open, sep, close] = delims;
6407
+ else if (delims.length === 2) [open, close] = delims;
6408
+ else if (delims.length === 1) sep = delims;
6409
+ const body = arg1 ? items ? serializeOps(sep)(serializer, items) : serializer.serialize(arg1) : "";
6410
+ return serializer.wrapString(body, style, open + close);
6411
+ }
6427
6412
  },
6428
6413
  {
6429
- latexTrigger: ["^", "\\tripleprime"],
6430
- kind: "postfix",
6431
- parse: (parser, lhs) => parsePrime(parser, lhs, 3)
6414
+ name: "Tuple",
6415
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
6432
6416
  },
6433
6417
  {
6434
- latexTrigger: "'",
6435
- kind: "postfix",
6436
- precedence: 810,
6437
- parse: (parser, lhs) => parsePrime(parser, lhs, 1)
6418
+ name: "Pair",
6419
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
6438
6420
  },
6439
6421
  {
6440
- latexTrigger: "\\prime",
6441
- kind: "postfix",
6442
- precedence: 810,
6443
- parse: (parser, lhs) => parsePrime(parser, lhs, 1)
6422
+ name: "Triple",
6423
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
6444
6424
  },
6445
6425
  {
6446
- latexTrigger: "\\doubleprime",
6447
- kind: "postfix",
6448
- precedence: 810,
6449
- parse: (parser, lhs) => parsePrime(parser, lhs, 2)
6426
+ name: "Single",
6427
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
6450
6428
  },
6451
6429
  {
6452
- latexTrigger: "\\tripleprime",
6453
- kind: "postfix",
6454
- precedence: 810,
6455
- parse: (parser, lhs) => parsePrime(parser, lhs, 3)
6430
+ name: "Domain",
6431
+ serialize: (serializer, expr) => {
6432
+ if (operator(expr) === "Error") return serializer.serialize(expr);
6433
+ return `\\mathbf{${serializer.serialize(operand(expr, 1))}}`;
6434
+ }
6456
6435
  },
6457
- // Lagrange Notation for n-th order derivatives,
6458
- // i.e. f^{(n)} -> Derivative(f, n)
6459
6436
  {
6460
- latexTrigger: ["^", "<{>", "("],
6461
- kind: "postfix",
6462
- parse: (parser, lhs, until) => {
6463
- const sym = symbol(lhs);
6464
- if (!sym || !parser.getSymbolType(sym).matches("function")) return null;
6465
- parser.addBoundary([")"]);
6466
- const expr = parser.parseExpression(until);
6467
- if (!parser.matchBoundary()) return null;
6468
- if (!parser.match("<}>")) return null;
6469
- return ["Derivative", lhs, expr];
6437
+ latexTrigger: ["\\mathtip"],
6438
+ parse: (parser) => {
6439
+ const op1 = parser.parseGroup();
6440
+ parser.parseGroup();
6441
+ return op1;
6470
6442
  }
6471
6443
  },
6472
6444
  {
6473
- name: "InverseFunction",
6474
- latexTrigger: "^{-1",
6475
- // Note: the closing brace is not included
6476
- kind: "postfix",
6477
- parse: (parser, lhs) => {
6478
- if (operator(lhs) === "Matrix") {
6479
- parser.match("<}>");
6480
- return ["Inverse", lhs];
6481
- }
6482
- const sym = symbol(lhs);
6483
- if (!sym) return null;
6484
- const symType = parser.getSymbolType(sym);
6485
- if (symType.matches(new BoxedType("matrix"))) {
6486
- parser.match("<}>");
6487
- return ["Inverse", lhs];
6488
- }
6489
- if (!symType.matches("function")) return null;
6490
- let primeCount = 0;
6491
- while (!parser.atEnd && !parser.match("<}>")) {
6492
- if (parser.match("'")) primeCount++;
6493
- else if (parser.match("\\prime")) primeCount++;
6494
- else if (parser.match("\\doubleprime")) primeCount += 2;
6495
- else if (parser.match("\\tripleprime")) primeCount += 3;
6496
- else return null;
6497
- }
6498
- if (primeCount === 1)
6499
- return ["Derivative", ["InverseFunction", lhs]];
6500
- if (primeCount > 0)
6501
- return [
6502
- "Derivative",
6503
- ["InverseFunction", lhs],
6504
- primeCount
6505
- ];
6506
- return ["InverseFunction", lhs];
6507
- },
6508
- serialize: (serializer, expr) => serializer.serialize(operand(expr, 1)) + "^{-1}"
6445
+ latexTrigger: ["\\texttip"],
6446
+ parse: (parser) => {
6447
+ const op1 = parser.parseGroup();
6448
+ parser.parseGroup();
6449
+ return op1;
6450
+ }
6509
6451
  },
6510
- // Lagrange notation
6511
6452
  {
6512
- name: "Derivative",
6513
- // @todo: Leibniz notation: {% latex " \\frac{d^n}{dx^n} f(x)" %}
6514
- // @todo: Euler modified notation: This notation is used by Mathematica. The Euler notation uses `D` instead of
6515
- // `\partial`: `\partial_{x} f`, `\partial_{x,y} f`
6516
- // Newton notation (\dot{v}, \ddot{v}) is implemented below
6517
- serialize: (serializer, expr) => {
6518
- const degree = machineValue(operand(expr, 2)) ?? 1;
6519
- const base = serializer.serialize(operand(expr, 1));
6520
- if (degree === 1) return base + "^{\\prime}";
6521
- if (degree === 2) return base + "^{\\doubleprime}";
6522
- if (degree === 3) return base + "^{\\tripleprime}";
6523
- return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
6524
- }
6453
+ latexTrigger: ["\\error"],
6454
+ parse: (parser) => ["Error", parser.parseGroup()]
6525
6455
  },
6526
- // Serializer for D (partial derivative) - outputs Leibniz notation
6527
6456
  {
6528
- name: "D",
6457
+ name: "Error",
6529
6458
  serialize: (serializer, expr) => {
6530
- if (operator(expr) !== "D") return "D";
6531
- const fn = operand(expr, 1);
6532
- const variable = operand(expr, 2);
6533
- if (!fn || !variable) return "D";
6534
- let order2 = 1;
6535
- let innerFn = fn;
6536
- while (operator(innerFn) === "D") {
6537
- const innerVar = operand(innerFn, 2);
6538
- if (symbol(innerVar) === symbol(variable)) {
6539
- order2++;
6540
- innerFn = operand(innerFn, 1);
6541
- } else {
6542
- break;
6459
+ const op1 = operand(expr, 1);
6460
+ if (stringValue(op1) === "missing")
6461
+ return `\\error{${serializer.options.missingSymbol ?? "\\placeholder{}"}}`;
6462
+ const where = errorContextAsLatex(serializer, expr) || "\\blacksquare";
6463
+ const code = operator(op1) === "ErrorCode" ? stringValue(operand(op1, 1)) : stringValue(op1);
6464
+ if (code === "incompatible-type") {
6465
+ if (symbol(operand(op1, 3)) === "Undefined") {
6466
+ return `\\mathtip{\\error{${where}}}{\\notin ${serializer.serialize(
6467
+ operand(op1, 2)
6468
+ )}}`;
6543
6469
  }
6470
+ return `\\mathtip{\\error{${where}}}{\\in ${serializer.serialize(
6471
+ operand(op1, 3)
6472
+ )}\\notin ${serializer.serialize(operand(op1, 2))}}`;
6544
6473
  }
6545
- let bodyToSerialize = innerFn;
6546
- if (operator(innerFn) === "Function") {
6547
- bodyToSerialize = operand(innerFn, 1) ?? innerFn;
6548
- }
6549
- const fnLatex = serializer.serialize(bodyToSerialize);
6550
- const varLatex = serializer.serialize(variable);
6551
- if (order2 === 1) {
6552
- return `\\frac{\\mathrm{d}}{\\mathrm{d}${varLatex}}${fnLatex}`;
6553
- }
6554
- return `\\frac{\\mathrm{d}^{${order2}}}{\\mathrm{d}${varLatex}^{${order2}}}${fnLatex}`;
6474
+ if (typeof code === "string") return `\\error{${where}}`;
6475
+ return `\\error{${where}}`;
6555
6476
  }
6556
6477
  },
6557
- // Newton notation for time derivatives: \dot{x}, \ddot{x}, etc.
6558
6478
  {
6559
- name: "NewtonDerivative1",
6560
- latexTrigger: ["\\dot"],
6561
- kind: "prefix",
6562
- precedence: 740,
6563
- parse: (parser) => {
6564
- const body = parser.parseGroup();
6565
- if (body === null) return null;
6566
- const t = parser.options.timeDerivativeVariable;
6567
- return ["D", body, t];
6479
+ name: "ErrorCode",
6480
+ serialize: (serializer, expr) => {
6481
+ const code = stringValue(operand(expr, 1));
6482
+ if (code === "missing")
6483
+ return serializer.options.missingSymbol ?? "\\placeholder{}";
6484
+ if (code === "unexpected-command" || code === "unexpected-operator" || code === "unexpected-token" || code === "invalid-symbol" || code === "unknown-environment" || code === "unexpected-base" || code === "incompatible-type") {
6485
+ return "";
6486
+ }
6487
+ return `\\texttip{\\error{\\blacksquare}}{\\mathtt{${code}}}`;
6568
6488
  }
6569
6489
  },
6570
6490
  {
6571
- name: "NewtonDerivative2",
6572
- latexTrigger: ["\\ddot"],
6573
- kind: "prefix",
6574
- precedence: 740,
6575
- parse: (parser) => {
6576
- const body = parser.parseGroup();
6577
- if (body === null) return null;
6578
- const t = parser.options.timeDerivativeVariable;
6579
- return ["D", ["D", body, t], t];
6491
+ name: "FromLatex",
6492
+ serialize: (_serializer, expr) => {
6493
+ return `\\texttt{${sanitizeLatex(stringValue(operand(expr, 1)))}}`;
6580
6494
  }
6581
6495
  },
6582
6496
  {
6583
- name: "NewtonDerivative3",
6584
- latexTrigger: ["\\dddot"],
6585
- kind: "prefix",
6586
- precedence: 740,
6587
- parse: (parser) => {
6588
- const body = parser.parseGroup();
6589
- if (body === null) return null;
6590
- const t = parser.options.timeDerivativeVariable;
6591
- return ["D", ["D", ["D", body, t], t], t];
6497
+ name: "Latex",
6498
+ serialize: (serializer, expr) => {
6499
+ if (expr === null) return "";
6500
+ return joinLatex(
6501
+ mapArgs(expr, (x) => stringValue(x) ?? serializer.serialize(x))
6502
+ );
6592
6503
  }
6593
6504
  },
6594
6505
  {
6595
- name: "NewtonDerivative4",
6596
- latexTrigger: ["\\ddddot"],
6597
- kind: "prefix",
6598
- precedence: 740,
6599
- parse: (parser) => {
6600
- const body = parser.parseGroup();
6601
- if (body === null) return null;
6602
- const t = parser.options.timeDerivativeVariable;
6603
- return ["D", ["D", ["D", ["D", body, t], t], t], t];
6506
+ name: "LatexString",
6507
+ serialize: (serializer, expr) => {
6508
+ if (expr === null) return "";
6509
+ return joinLatex(mapArgs(expr, (x) => serializer.serialize(x)));
6604
6510
  }
6605
6511
  },
6606
- // Euler notation for derivatives: D_x f, D^2_x f, D_x^2 f
6607
- // Uses latexTrigger to intercept before symbol parsing combines D with subscript
6512
+ { name: "LatexTokens", serialize: serializeLatexTokens },
6608
6513
  {
6609
- name: "EulerDerivative",
6610
- latexTrigger: ["D"],
6611
- kind: "expression",
6612
- parse: (parser) => {
6613
- let degree = 1;
6614
- let variable = null;
6615
- let done = false;
6616
- while (!done) {
6617
- if (parser.match("_")) {
6618
- variable = parser.parseGroup() ?? parser.parseToken();
6619
- if (!variable) return null;
6620
- } else if (parser.match("^")) {
6621
- const degExpr = parser.parseGroup() ?? parser.parseToken();
6622
- degree = machineValue(degExpr) ?? 1;
6623
- } else {
6624
- done = true;
6625
- }
6626
- }
6627
- if (!variable) return null;
6628
- parser.skipSpace();
6629
- const fn = parser.parseExpression({ minPrec: 740 });
6630
- if (!fn) return null;
6631
- let result = fn;
6632
- for (let i = 0; i < degree; i++) {
6633
- result = ["D", result, variable];
6514
+ name: "At",
6515
+ kind: "postfix",
6516
+ precedence: 810,
6517
+ latexTrigger: ["["],
6518
+ parse: parseAt("]"),
6519
+ serialize: (serializer, expr) => joinLatex(["\\lbrack", serializeOps(", ")(serializer, expr), "\\rbrack"])
6520
+ },
6521
+ {
6522
+ kind: "postfix",
6523
+ precedence: 810,
6524
+ latexTrigger: ["\\lbrack"],
6525
+ parse: parseAt("\\rbrack")
6526
+ },
6527
+ {
6528
+ kind: "postfix",
6529
+ precedence: 810,
6530
+ latexTrigger: ["\\left", "\\lbrack"],
6531
+ parse: parseAt("\\right", "\\rbrack")
6532
+ },
6533
+ {
6534
+ kind: "postfix",
6535
+ latexTrigger: ["_"],
6536
+ parse: (parser, lhs, _until) => {
6537
+ let rhs = parser.parseGroup() ?? parser.parseToken();
6538
+ if (rhs === null && parser.options.strict === false && parser.peek === "(")
6539
+ rhs = parser.parseEnclosure();
6540
+ const sym = symbol(lhs);
6541
+ if (rhs !== null && (sym && parser.getSymbolType(sym).matches("indexed_collection") || operator(lhs) === "List")) {
6542
+ if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
6543
+ if (operator(rhs) === "Sequence") return ["At", lhs, ...operands(rhs)];
6544
+ return ["At", lhs, rhs];
6634
6545
  }
6635
- return result;
6546
+ return ["Subscript", lhs, rhs];
6636
6547
  }
6637
6548
  },
6638
6549
  {
6639
- kind: "environment",
6640
- name: "Which",
6641
- symbolTrigger: "cases",
6642
- parse: parseCasesEnvironment,
6643
- serialize: (serialize, expr) => {
6644
- const rows = [];
6550
+ name: "List",
6551
+ kind: "matchfix",
6552
+ openTrigger: "[",
6553
+ closeTrigger: "]",
6554
+ parse: parseBrackets,
6555
+ serialize: serializeList
6556
+ },
6557
+ {
6558
+ kind: "matchfix",
6559
+ openTrigger: "(",
6560
+ closeTrigger: ")",
6561
+ parse: parseParenDelimiter
6562
+ },
6563
+ {
6564
+ latexTrigger: [","],
6565
+ kind: "infix",
6566
+ precedence: 20,
6567
+ // Unlike the matchfix version of List,
6568
+ // when the comma operator is used, the lhs and rhs are flattened,
6569
+ // i.e. `1,2,3` -> `["Delimiter", ["List", 1, 2, 3], ","]`,
6570
+ // and `1, (2, 3)` -> `["Delimiter",
6571
+ // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "()", ","]]],
6572
+ parse: (parser, lhs, terminator) => {
6573
+ const seq = parseSequence(parser, terminator, lhs, 20, ",");
6574
+ if (seq === null) return null;
6575
+ return ["Delimiter", ["Sequence", ...seq], { str: "," }];
6576
+ }
6577
+ },
6578
+ // Entry to handle the case of a single comma
6579
+ // with a missing lhs.
6580
+ {
6581
+ latexTrigger: [","],
6582
+ kind: "prefix",
6583
+ precedence: 20,
6584
+ parse: (parser, terminator) => {
6585
+ const seq = parseSequence(parser, terminator, null, 20, ",");
6586
+ if (seq === null) return null;
6587
+ return ["Delimiter", ["Sequence", ...seq], { str: "," }];
6588
+ }
6589
+ },
6590
+ {
6591
+ name: "Range",
6592
+ latexTrigger: [".", "."],
6593
+ kind: "infix",
6594
+ // associativity: 'left',
6595
+ precedence: 800,
6596
+ parse: parseRange,
6597
+ serialize: (serializer, expr) => {
6645
6598
  const args = operands(expr);
6646
- if (args.length > 0) {
6647
- for (let i = 0; i <= args.length - 2; i += 2) {
6648
- const row = [];
6649
- row.push(serialize.serialize(args[i + 1]));
6650
- row.push(serialize.serialize(args[i]));
6651
- rows.push(row.join("&"));
6599
+ if (args.length === 0) return "";
6600
+ if (args.length === 1)
6601
+ return "1.." + serializer.serialize(operand(expr, 1));
6602
+ if (args.length === 2)
6603
+ return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(operand(expr, 2), 10);
6604
+ if (args.length === 3) {
6605
+ const step = machineValue(operand(expr, 3));
6606
+ const start = machineValue(operand(expr, 1));
6607
+ if (step !== null && start !== null) {
6608
+ return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(start + step, 10) + ".." + serializer.wrap(operand(expr, 2), 10);
6652
6609
  }
6610
+ return serializer.wrap(operand(expr, 1), 10) + "..(" + (serializer.wrap(operand(expr, 1), ADDITION_PRECEDENCE) + "+" + serializer.wrap(operand(expr, 3), ADDITION_PRECEDENCE)) + ").." + serializer.wrap(operand(expr, 2), 10);
6653
6611
  }
6654
- return joinLatex(["\\begin{cases}", rows.join("\\\\"), "\\end{cases}"]);
6612
+ return "";
6655
6613
  }
6656
6614
  },
6657
6615
  {
6658
- kind: "environment",
6659
- symbolTrigger: "dcases",
6660
- parse: parseCasesEnvironment
6616
+ latexTrigger: [";"],
6617
+ kind: "infix",
6618
+ precedence: 19,
6619
+ parse: (parser, lhs, terminator) => {
6620
+ const seq = parseSequence(parser, terminator, lhs, 19, ";");
6621
+ if (seq === null) return null;
6622
+ if (seq.some((e) => operator(e) === "Assign"))
6623
+ return buildBlockFromSequence(seq);
6624
+ return ["Delimiter", ["Sequence", ...seq], "';'"];
6625
+ }
6661
6626
  },
6627
+ // \text{where} — variable binding infix
6662
6628
  {
6663
- kind: "environment",
6664
- symbolTrigger: "rcases",
6665
- parse: parseCasesEnvironment
6666
- }
6667
- ];
6668
- function parseTextRun(parser, style) {
6669
- if (!parser.match("<{>")) return "''";
6670
- const runs = [];
6671
- let text = "";
6672
- let runinStyle = null;
6673
- const flush = () => {
6674
- if (runinStyle !== null && text) {
6675
- runs.push(["Annotated", `'${text}'`, dictionaryFromEntries(runinStyle)]);
6676
- } else if (text) {
6677
- runs.push(`'${text}'`);
6629
+ latexTrigger: ["\\text"],
6630
+ kind: "infix",
6631
+ associativity: "none",
6632
+ precedence: 21,
6633
+ // Above ; (19) and , (20), very low binding
6634
+ parse: (parser, lhs, until) => {
6635
+ const start = parser.index;
6636
+ if (!matchTextKeyword(parser, "where")) {
6637
+ parser.index = start;
6638
+ return null;
6639
+ }
6640
+ return parseWhereExpression(parser, lhs, until);
6678
6641
  }
6679
- text = "";
6680
- runinStyle = null;
6681
- };
6682
- while (!parser.atEnd && !parser.match("<}>")) {
6683
- if (parser.peek === "<{>") {
6684
- flush();
6685
- runs.push(parseTextRun(parser));
6686
- } else if (parser.match("\\textbf")) {
6687
- flush();
6688
- runs.push(parseTextRun(parser, { fontWeight: "bold" }));
6689
- } else if (parser.match("\\textmd")) {
6690
- flush();
6691
- runs.push(parseTextRun(parser, { fontStyle: "normal" }));
6692
- } else if (parser.match("\\textup")) {
6693
- flush();
6694
- runs.push(parseTextRun(parser, { fontStyle: "normal" }));
6695
- } else if (parser.match("\\textsl")) {
6696
- flush();
6697
- runs.push(parseTextRun(parser, { fontStyle: "italic" }));
6698
- } else if (parser.match("\\textit")) {
6699
- flush();
6700
- runs.push(parseTextRun(parser, { fontStyle: "italic" }));
6701
- } else if (parser.match("\\texttt")) {
6702
- flush();
6703
- runs.push(parseTextRun(parser, { fontFamily: "monospace" }));
6704
- } else if (parser.match("\\textsf")) {
6705
- flush();
6706
- runs.push(parseTextRun(parser, { fontFamily: "sans-serif" }));
6707
- } else if (parser.match("\\textcolor")) {
6708
- const pos = parser.index;
6709
- const color = parser.parseStringGroup();
6710
- const body2 = parser.parseExpression();
6711
- if (color !== null && body2 !== null) {
6712
- runs.push(["Annotated", body2, { dict: { color } }]);
6713
- } else {
6714
- parser.index = pos;
6715
- text += "\\textcolor";
6642
+ },
6643
+ // \operatorname{where}
6644
+ {
6645
+ symbolTrigger: "where",
6646
+ kind: "infix",
6647
+ associativity: "none",
6648
+ precedence: 21,
6649
+ parse: (parser, lhs, until) => parseWhereExpression(parser, lhs, until)
6650
+ },
6651
+ // \text{and} logical conjunction infix
6652
+ {
6653
+ latexTrigger: ["\\text"],
6654
+ kind: "infix",
6655
+ associativity: "right",
6656
+ precedence: 235,
6657
+ // Same as \land
6658
+ parse: (parser, lhs, until) => {
6659
+ const start = parser.index;
6660
+ if (!matchTextKeyword(parser, "and")) {
6661
+ parser.index = start;
6662
+ return null;
6716
6663
  }
6717
- } else if (parser.match("\\color")) {
6718
- const color = parser.parseStringGroup();
6719
- if (color !== null) {
6720
- flush();
6664
+ const rhs = parser.parseExpression({ ...until, minPrec: 235 });
6665
+ return ["And", lhs, rhs ?? "Nothing"];
6666
+ }
6667
+ },
6668
+ // \text{or} — logical disjunction infix
6669
+ {
6670
+ latexTrigger: ["\\text"],
6671
+ kind: "infix",
6672
+ associativity: "right",
6673
+ precedence: 230,
6674
+ // Same as \lor
6675
+ parse: (parser, lhs, until) => {
6676
+ const start = parser.index;
6677
+ if (!matchTextKeyword(parser, "or")) {
6678
+ parser.index = start;
6679
+ return null;
6680
+ }
6681
+ const rhs = parser.parseExpression({ ...until, minPrec: 230 });
6682
+ return ["Or", lhs, rhs ?? "Nothing"];
6683
+ }
6684
+ },
6685
+ // \text{iff} — biconditional (if and only if)
6686
+ {
6687
+ latexTrigger: ["\\text"],
6688
+ kind: "infix",
6689
+ associativity: "right",
6690
+ precedence: 219,
6691
+ // Same as \iff
6692
+ parse: (parser, lhs, until) => {
6693
+ const start = parser.index;
6694
+ if (!matchTextKeyword(parser, "iff")) {
6695
+ parser.index = start;
6696
+ return null;
6697
+ }
6698
+ const rhs = parser.parseExpression({ ...until, minPrec: 219 });
6699
+ return ["Equivalent", lhs, rhs ?? "Nothing"];
6700
+ }
6701
+ },
6702
+ // \text{if and only if} — verbose biconditional
6703
+ {
6704
+ latexTrigger: ["\\text"],
6705
+ kind: "infix",
6706
+ associativity: "right",
6707
+ precedence: 219,
6708
+ parse: (parser, lhs, until) => {
6709
+ const start = parser.index;
6710
+ if (!matchTextKeyword(parser, "if and only if")) {
6711
+ parser.index = start;
6712
+ return null;
6713
+ }
6714
+ const rhs = parser.parseExpression({ ...until, minPrec: 219 });
6715
+ return ["Equivalent", lhs, rhs ?? "Nothing"];
6716
+ }
6717
+ },
6718
+ // \text{such that} — constraint separator (like : in set-builder notation)
6719
+ {
6720
+ latexTrigger: ["\\text"],
6721
+ kind: "infix",
6722
+ associativity: "right",
6723
+ precedence: 21,
6724
+ // Low precedence to capture full condition (same as 'where')
6725
+ parse: (parser, lhs, until) => {
6726
+ const start = parser.index;
6727
+ if (!matchTextKeyword(parser, "such that")) {
6728
+ parser.index = start;
6729
+ return null;
6730
+ }
6731
+ const rhs = parser.parseExpression({ ...until, minPrec: 21 });
6732
+ return ["Colon", lhs, rhs ?? "Nothing"];
6733
+ }
6734
+ },
6735
+ // \text{for all} — universal quantifier
6736
+ {
6737
+ latexTrigger: ["\\text"],
6738
+ kind: "prefix",
6739
+ precedence: 200,
6740
+ // Same as \forall
6741
+ parse: (parser, until) => {
6742
+ const start = parser.index;
6743
+ if (!matchTextKeyword(parser, "for all")) {
6744
+ parser.index = start;
6745
+ return null;
6746
+ }
6747
+ return parseQuantifier("ForAll")(parser, until);
6748
+ }
6749
+ },
6750
+ // \text{there exists} — existential quantifier
6751
+ {
6752
+ latexTrigger: ["\\text"],
6753
+ kind: "prefix",
6754
+ precedence: 200,
6755
+ // Same as \exists
6756
+ parse: (parser, until) => {
6757
+ const start = parser.index;
6758
+ if (!matchTextKeyword(parser, "there exists")) {
6759
+ parser.index = start;
6760
+ return null;
6761
+ }
6762
+ return parseQuantifier("Exists")(parser, until);
6763
+ }
6764
+ },
6765
+ // Block serializer — used by both `where` and semicolon blocks
6766
+ {
6767
+ name: "Block",
6768
+ serialize: (serializer, expr) => {
6769
+ const args = operands(expr);
6770
+ if (!args || args.length === 0) return "";
6771
+ const parts = args.filter((a) => operator(a) !== "Declare").map((a) => serializer.serialize(a));
6772
+ return parts.join("; ");
6773
+ }
6774
+ },
6775
+ // Serializer for If expressions (separate from the parser entry
6776
+ // because name-based entries affect kind-based indexing)
6777
+ {
6778
+ name: "If",
6779
+ serialize: (serializer, expr) => {
6780
+ const args = operands(expr);
6781
+ if (!args || args.length < 3) return "";
6782
+ return joinLatex([
6783
+ "\\text{if }",
6784
+ serializer.serialize(args[0]),
6785
+ "\\text{ then }",
6786
+ serializer.serialize(args[1]),
6787
+ "\\text{ else }",
6788
+ serializer.serialize(args[2])
6789
+ ]);
6790
+ }
6791
+ },
6792
+ // Serializer for Loop expressions
6793
+ {
6794
+ name: "Loop",
6795
+ serialize: (serializer, expr) => {
6796
+ const args = operands(expr);
6797
+ if (!args || args.length < 2) return "";
6798
+ const body = args[0];
6799
+ const indexing = args[1];
6800
+ if (operator(indexing) === "Element") {
6801
+ const index = operand(indexing, 1);
6802
+ const range = operand(indexing, 2);
6803
+ if (operator(range) === "Range") {
6804
+ const lo = operand(range, 1);
6805
+ const hi = operand(range, 2);
6806
+ return joinLatex([
6807
+ "\\text{for }",
6808
+ serializer.serialize(index),
6809
+ "\\text{ from }",
6810
+ serializer.serialize(lo),
6811
+ "\\text{ to }",
6812
+ serializer.serialize(hi),
6813
+ "\\text{ do }",
6814
+ serializer.serialize(body)
6815
+ ]);
6816
+ }
6817
+ }
6818
+ return joinLatex([
6819
+ "\\operatorname{Loop}(",
6820
+ serializer.serialize(body),
6821
+ ", ",
6822
+ serializer.serialize(indexing),
6823
+ ")"
6824
+ ]);
6825
+ }
6826
+ },
6827
+ // Serializer for Break
6828
+ { name: "Break", serialize: () => "\\text{break}" },
6829
+ // Serializer for Continue
6830
+ { name: "Continue", serialize: () => "\\text{continue}" },
6831
+ // Serializer for Return
6832
+ {
6833
+ name: "Return",
6834
+ serialize: (serializer, expr) => {
6835
+ const arg = operand(expr, 1);
6836
+ if (!arg || symbol(arg) === "Nothing") return "\\text{return}";
6837
+ return joinLatex(["\\text{return }", serializer.serialize(arg)]);
6838
+ }
6839
+ },
6840
+ // Also match `\operatorname{if}` / `\mathrm{if}`
6841
+ {
6842
+ symbolTrigger: "if",
6843
+ kind: "prefix",
6844
+ precedence: 245,
6845
+ parse: (parser, until) => {
6846
+ return parseIfExpression(parser, until);
6847
+ }
6848
+ },
6849
+ // \operatorname{for}
6850
+ {
6851
+ symbolTrigger: "for",
6852
+ kind: "prefix",
6853
+ precedence: 245,
6854
+ parse: (parser, until) => parseForExpression(parser, until)
6855
+ },
6856
+ // \operatorname{break}
6857
+ {
6858
+ symbolTrigger: "break",
6859
+ kind: "prefix",
6860
+ precedence: 245,
6861
+ parse: () => ["Break"]
6862
+ },
6863
+ // \operatorname{continue}
6864
+ {
6865
+ symbolTrigger: "continue",
6866
+ kind: "prefix",
6867
+ precedence: 245,
6868
+ parse: () => ["Continue"]
6869
+ },
6870
+ // \operatorname{return}
6871
+ {
6872
+ symbolTrigger: "return",
6873
+ kind: "prefix",
6874
+ precedence: 245,
6875
+ parse: (parser, until) => [
6876
+ "Return",
6877
+ parser.parseExpression(until) ?? "Nothing"
6878
+ ]
6879
+ },
6880
+ // Text serializer — reconstructs \text{...} with inline $...$ for math
6881
+ {
6882
+ name: "Text",
6883
+ serialize: (serializer, expr) => {
6884
+ const args = operands(expr);
6885
+ if (args.length === 0) return "";
6886
+ let firstStr = -1;
6887
+ let lastStr = -1;
6888
+ for (let i = 0; i < args.length; i++) {
6889
+ if (stringValue(args[i]) !== null) {
6890
+ if (firstStr < 0) firstStr = i;
6891
+ lastStr = i;
6892
+ }
6893
+ }
6894
+ if (firstStr < 0)
6895
+ return joinLatex(args.map((a) => serializer.serialize(a)));
6896
+ const parts = [];
6897
+ for (let i = 0; i < firstStr; i++)
6898
+ parts.push(serializer.serialize(args[i]));
6899
+ let textContent = "";
6900
+ for (let i = firstStr; i <= lastStr; i++) {
6901
+ const s = stringValue(args[i]);
6902
+ if (s !== null) textContent += sanitizeLatex(s);
6903
+ else if (operator(args[i]) === "Annotated" || operator(args[i]) === "Text")
6904
+ textContent += serializer.serialize(args[i]);
6905
+ else textContent += "$" + serializer.serialize(args[i]) + "$";
6906
+ }
6907
+ parts.push("\\text{" + textContent + "}");
6908
+ for (let i = lastStr + 1; i < args.length; i++)
6909
+ parts.push(serializer.serialize(args[i]));
6910
+ return joinLatex(parts);
6911
+ }
6912
+ },
6913
+ {
6914
+ name: "String",
6915
+ latexTrigger: ["\\text"],
6916
+ parse: (parser, until) => {
6917
+ const start = parser.index;
6918
+ if (matchTextKeyword(parser, "if"))
6919
+ return parseIfExpression(parser, until);
6920
+ parser.index = start;
6921
+ if (matchTextKeyword(parser, "for"))
6922
+ return parseForExpression(parser, until);
6923
+ parser.index = start;
6924
+ if (matchTextKeyword(parser, "break"))
6925
+ return ["Break"];
6926
+ parser.index = start;
6927
+ if (matchTextKeyword(parser, "continue"))
6928
+ return ["Continue"];
6929
+ parser.index = start;
6930
+ if (matchTextKeyword(parser, "return"))
6931
+ return [
6932
+ "Return",
6933
+ parser.parseExpression(until) ?? "Nothing"
6934
+ ];
6935
+ parser.index = start;
6936
+ return parseTextRun(parser);
6937
+ },
6938
+ serialize: (serializer, expr) => {
6939
+ const args = operands(expr);
6940
+ if (args.length === 0) return "\\text{}";
6941
+ return joinLatex([
6942
+ "\\text{",
6943
+ args.map((x) => serializer.serialize(x)).join(""),
6944
+ "}"
6945
+ ]);
6946
+ }
6947
+ },
6948
+ {
6949
+ name: "Subscript",
6950
+ latexTrigger: ["_"],
6951
+ kind: "infix",
6952
+ serialize: (serializer, expr) => {
6953
+ if (nops(expr) === 2) {
6954
+ return serializer.serialize(operand(expr, 1)) + "_{" + serializer.serialize(operand(expr, 2)) + "}";
6955
+ }
6956
+ return "_{" + serializer.serialize(operand(expr, 1)) + "}";
6957
+ }
6958
+ },
6959
+ { name: "Superplus", latexTrigger: ["^", "+"], kind: "postfix" },
6960
+ { name: "Subplus", latexTrigger: ["_", "+"], kind: "postfix" },
6961
+ {
6962
+ name: "Superminus",
6963
+ latexTrigger: ["^", "-"],
6964
+ kind: "postfix",
6965
+ parse: (parser, lhs) => {
6966
+ if (parser.options.strict === false && /^[0-9]$/.test(parser.peek))
6967
+ return null;
6968
+ return ["Superminus", lhs];
6969
+ }
6970
+ },
6971
+ { name: "Subminus", latexTrigger: ["_", "-"], kind: "postfix" },
6972
+ {
6973
+ latexTrigger: ["^", "*"],
6974
+ kind: "postfix",
6975
+ parse: (_parser, lhs) => ["Superstar", lhs]
6976
+ },
6977
+ // { name: 'Superstar', latexTrigger: ['^', '\\star'], kind: 'postfix' },
6978
+ {
6979
+ latexTrigger: ["_", "*"],
6980
+ kind: "postfix",
6981
+ parse: (_parser, lhs) => ["Substar", lhs]
6982
+ },
6983
+ { name: "Substar", latexTrigger: ["_", "\\star"], kind: "postfix" },
6984
+ { name: "Superdagger", latexTrigger: ["^", "\\dagger"], kind: "postfix" },
6985
+ {
6986
+ latexTrigger: ["^", "\\dag"],
6987
+ kind: "postfix",
6988
+ parse: (_parser, lhs) => ["Superdagger", lhs]
6989
+ },
6990
+ {
6991
+ name: "Prime",
6992
+ latexTrigger: ["^", "\\prime"],
6993
+ // Note: we don't need a precedence because the trigger is '^'
6994
+ // and '^' (and '_') are treated specially by the parser.
6995
+ kind: "postfix",
6996
+ parse: (parser, lhs) => parsePrime(parser, lhs, 1),
6997
+ serialize: (serializer, expr) => {
6998
+ const n2 = machineValue(operand(expr, 2)) ?? 1;
6999
+ const base = serializer.serialize(operand(expr, 1));
7000
+ if (n2 === 1) return base + "^\\prime";
7001
+ if (n2 === 2) return base + "^\\doubleprime";
7002
+ if (n2 === 3) return base + "^\\tripleprime";
7003
+ return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
7004
+ }
7005
+ },
7006
+ {
7007
+ latexTrigger: "^{\\prime\\prime}",
7008
+ kind: "postfix",
7009
+ parse: (parser, lhs) => parsePrime(parser, lhs, 2)
7010
+ },
7011
+ {
7012
+ latexTrigger: "^{\\prime\\prime\\prime}",
7013
+ kind: "postfix",
7014
+ parse: (parser, lhs) => parsePrime(parser, lhs, 3)
7015
+ },
7016
+ {
7017
+ latexTrigger: ["^", "\\doubleprime"],
7018
+ kind: "postfix",
7019
+ parse: (parser, lhs) => parsePrime(parser, lhs, 2)
7020
+ },
7021
+ {
7022
+ latexTrigger: ["^", "\\tripleprime"],
7023
+ kind: "postfix",
7024
+ parse: (parser, lhs) => parsePrime(parser, lhs, 3)
7025
+ },
7026
+ {
7027
+ latexTrigger: "'",
7028
+ kind: "postfix",
7029
+ precedence: 810,
7030
+ parse: (parser, lhs) => parsePrime(parser, lhs, 1)
7031
+ },
7032
+ {
7033
+ latexTrigger: "\\prime",
7034
+ kind: "postfix",
7035
+ precedence: 810,
7036
+ parse: (parser, lhs) => parsePrime(parser, lhs, 1)
7037
+ },
7038
+ {
7039
+ latexTrigger: "\\doubleprime",
7040
+ kind: "postfix",
7041
+ precedence: 810,
7042
+ parse: (parser, lhs) => parsePrime(parser, lhs, 2)
7043
+ },
7044
+ {
7045
+ latexTrigger: "\\tripleprime",
7046
+ kind: "postfix",
7047
+ precedence: 810,
7048
+ parse: (parser, lhs) => parsePrime(parser, lhs, 3)
7049
+ },
7050
+ // Lagrange Notation for n-th order derivatives,
7051
+ // i.e. f^{(n)} -> Derivative(f, n)
7052
+ {
7053
+ latexTrigger: ["^", "<{>", "("],
7054
+ kind: "postfix",
7055
+ parse: (parser, lhs, until) => {
7056
+ const sym = symbol(lhs);
7057
+ if (!sym || !parser.getSymbolType(sym).matches("function")) return null;
7058
+ parser.addBoundary([")"]);
7059
+ const expr = parser.parseExpression(until);
7060
+ if (!parser.matchBoundary()) return null;
7061
+ if (!parser.match("<}>")) return null;
7062
+ return ["Derivative", lhs, expr];
7063
+ }
7064
+ },
7065
+ {
7066
+ name: "InverseFunction",
7067
+ latexTrigger: "^{-1",
7068
+ // Note: the closing brace is not included
7069
+ kind: "postfix",
7070
+ parse: (parser, lhs) => {
7071
+ if (operator(lhs) === "Matrix") {
7072
+ parser.match("<}>");
7073
+ return ["Inverse", lhs];
7074
+ }
7075
+ const sym = symbol(lhs);
7076
+ if (!sym) return null;
7077
+ const symType = parser.getSymbolType(sym);
7078
+ if (symType.matches(new BoxedType("matrix"))) {
7079
+ parser.match("<}>");
7080
+ return ["Inverse", lhs];
7081
+ }
7082
+ if (!symType.matches("function")) return null;
7083
+ let primeCount = 0;
7084
+ while (!parser.atEnd && !parser.match("<}>")) {
7085
+ if (parser.match("'")) primeCount++;
7086
+ else if (parser.match("\\prime")) primeCount++;
7087
+ else if (parser.match("\\doubleprime")) primeCount += 2;
7088
+ else if (parser.match("\\tripleprime")) primeCount += 3;
7089
+ else return null;
7090
+ }
7091
+ if (primeCount === 1)
7092
+ return ["Derivative", ["InverseFunction", lhs]];
7093
+ if (primeCount > 0)
7094
+ return [
7095
+ "Derivative",
7096
+ ["InverseFunction", lhs],
7097
+ primeCount
7098
+ ];
7099
+ return ["InverseFunction", lhs];
7100
+ },
7101
+ serialize: (serializer, expr) => serializer.serialize(operand(expr, 1)) + "^{-1}"
7102
+ },
7103
+ // Lagrange notation
7104
+ {
7105
+ name: "Derivative",
7106
+ // @todo: Leibniz notation: {% latex " \\frac{d^n}{dx^n} f(x)" %}
7107
+ // @todo: Euler modified notation: This notation is used by Mathematica. The Euler notation uses `D` instead of
7108
+ // `\partial`: `\partial_{x} f`, `\partial_{x,y} f`
7109
+ // Newton notation (\dot{v}, \ddot{v}) is implemented below
7110
+ serialize: (serializer, expr) => {
7111
+ const degree = machineValue(operand(expr, 2)) ?? 1;
7112
+ const base = serializer.serialize(operand(expr, 1));
7113
+ if (degree === 1) return base + "^{\\prime}";
7114
+ if (degree === 2) return base + "^{\\doubleprime}";
7115
+ if (degree === 3) return base + "^{\\tripleprime}";
7116
+ return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
7117
+ }
7118
+ },
7119
+ // Serializer for D (partial derivative) - outputs Leibniz notation
7120
+ {
7121
+ name: "D",
7122
+ serialize: (serializer, expr) => {
7123
+ if (operator(expr) !== "D") return "D";
7124
+ const fn = operand(expr, 1);
7125
+ const variable = operand(expr, 2);
7126
+ if (!fn || !variable) return "D";
7127
+ let order2 = 1;
7128
+ let innerFn = fn;
7129
+ while (operator(innerFn) === "D") {
7130
+ const innerVar = operand(innerFn, 2);
7131
+ if (symbol(innerVar) === symbol(variable)) {
7132
+ order2++;
7133
+ innerFn = operand(innerFn, 1);
7134
+ } else {
7135
+ break;
7136
+ }
7137
+ }
7138
+ let bodyToSerialize = innerFn;
7139
+ if (operator(innerFn) === "Function") {
7140
+ bodyToSerialize = operand(innerFn, 1) ?? innerFn;
7141
+ }
7142
+ const fnLatex = serializer.serialize(bodyToSerialize);
7143
+ const varLatex = serializer.serialize(variable);
7144
+ if (order2 === 1) {
7145
+ return `\\frac{\\mathrm{d}}{\\mathrm{d}${varLatex}}${fnLatex}`;
7146
+ }
7147
+ return `\\frac{\\mathrm{d}^{${order2}}}{\\mathrm{d}${varLatex}^{${order2}}}${fnLatex}`;
7148
+ }
7149
+ },
7150
+ // Newton notation for time derivatives: \dot{x}, \ddot{x}, etc.
7151
+ {
7152
+ name: "NewtonDerivative1",
7153
+ latexTrigger: ["\\dot"],
7154
+ kind: "prefix",
7155
+ precedence: 740,
7156
+ parse: (parser) => {
7157
+ const body = parser.parseGroup();
7158
+ if (body === null) return null;
7159
+ const t = parser.options.timeDerivativeVariable;
7160
+ return ["D", body, t];
7161
+ }
7162
+ },
7163
+ {
7164
+ name: "NewtonDerivative2",
7165
+ latexTrigger: ["\\ddot"],
7166
+ kind: "prefix",
7167
+ precedence: 740,
7168
+ parse: (parser) => {
7169
+ const body = parser.parseGroup();
7170
+ if (body === null) return null;
7171
+ const t = parser.options.timeDerivativeVariable;
7172
+ return ["D", ["D", body, t], t];
7173
+ }
7174
+ },
7175
+ {
7176
+ name: "NewtonDerivative3",
7177
+ latexTrigger: ["\\dddot"],
7178
+ kind: "prefix",
7179
+ precedence: 740,
7180
+ parse: (parser) => {
7181
+ const body = parser.parseGroup();
7182
+ if (body === null) return null;
7183
+ const t = parser.options.timeDerivativeVariable;
7184
+ return ["D", ["D", ["D", body, t], t], t];
7185
+ }
7186
+ },
7187
+ {
7188
+ name: "NewtonDerivative4",
7189
+ latexTrigger: ["\\ddddot"],
7190
+ kind: "prefix",
7191
+ precedence: 740,
7192
+ parse: (parser) => {
7193
+ const body = parser.parseGroup();
7194
+ if (body === null) return null;
7195
+ const t = parser.options.timeDerivativeVariable;
7196
+ return ["D", ["D", ["D", ["D", body, t], t], t], t];
7197
+ }
7198
+ },
7199
+ // Euler notation for derivatives: D_x f, D^2_x f, D_x^2 f
7200
+ // Uses latexTrigger to intercept before symbol parsing combines D with subscript
7201
+ {
7202
+ name: "EulerDerivative",
7203
+ latexTrigger: ["D"],
7204
+ kind: "expression",
7205
+ parse: (parser) => {
7206
+ let degree = 1;
7207
+ let variable = null;
7208
+ let done = false;
7209
+ while (!done) {
7210
+ if (parser.match("_")) {
7211
+ variable = parser.parseGroup() ?? parser.parseToken();
7212
+ if (!variable) return null;
7213
+ } else if (parser.match("^")) {
7214
+ const degExpr = parser.parseGroup() ?? parser.parseToken();
7215
+ degree = machineValue(degExpr) ?? 1;
7216
+ } else {
7217
+ done = true;
7218
+ }
7219
+ }
7220
+ if (!variable) return null;
7221
+ parser.skipSpace();
7222
+ const fn = parser.parseExpression({ minPrec: 740 });
7223
+ if (!fn) return null;
7224
+ let result = fn;
7225
+ for (let i = 0; i < degree; i++) {
7226
+ result = ["D", result, variable];
7227
+ }
7228
+ return result;
7229
+ }
7230
+ },
7231
+ {
7232
+ kind: "environment",
7233
+ name: "Which",
7234
+ symbolTrigger: "cases",
7235
+ parse: parseCasesEnvironment,
7236
+ serialize: (serialize, expr) => {
7237
+ const rows = [];
7238
+ const args = operands(expr);
7239
+ if (args.length > 0) {
7240
+ for (let i = 0; i <= args.length - 2; i += 2) {
7241
+ const row = [];
7242
+ row.push(serialize.serialize(args[i + 1]));
7243
+ row.push(serialize.serialize(args[i]));
7244
+ rows.push(row.join("&"));
7245
+ }
7246
+ }
7247
+ return joinLatex(["\\begin{cases}", rows.join("\\\\"), "\\end{cases}"]);
7248
+ }
7249
+ },
7250
+ {
7251
+ kind: "environment",
7252
+ symbolTrigger: "dcases",
7253
+ parse: parseCasesEnvironment
7254
+ },
7255
+ {
7256
+ kind: "environment",
7257
+ symbolTrigger: "rcases",
7258
+ parse: parseCasesEnvironment
7259
+ }
7260
+ ];
7261
+ function parseTextRun(parser, style) {
7262
+ if (!parser.match("<{>")) return "''";
7263
+ const runs = [];
7264
+ let text = "";
7265
+ let runinStyle = null;
7266
+ const flush = () => {
7267
+ if (runinStyle !== null && text) {
7268
+ runs.push(["Annotated", `'${text}'`, dictionaryFromEntries(runinStyle)]);
7269
+ } else if (text) {
7270
+ runs.push(`'${text}'`);
7271
+ }
7272
+ text = "";
7273
+ runinStyle = null;
7274
+ };
7275
+ while (!parser.atEnd && !parser.match("<}>")) {
7276
+ if (parser.peek === "<{>") {
7277
+ flush();
7278
+ runs.push(parseTextRun(parser));
7279
+ } else if (parser.match("\\textbf")) {
7280
+ flush();
7281
+ runs.push(parseTextRun(parser, { fontWeight: "bold" }));
7282
+ } else if (parser.match("\\textmd")) {
7283
+ flush();
7284
+ runs.push(parseTextRun(parser, { fontStyle: "normal" }));
7285
+ } else if (parser.match("\\textup")) {
7286
+ flush();
7287
+ runs.push(parseTextRun(parser, { fontStyle: "normal" }));
7288
+ } else if (parser.match("\\textsl")) {
7289
+ flush();
7290
+ runs.push(parseTextRun(parser, { fontStyle: "italic" }));
7291
+ } else if (parser.match("\\textit")) {
7292
+ flush();
7293
+ runs.push(parseTextRun(parser, { fontStyle: "italic" }));
7294
+ } else if (parser.match("\\texttt")) {
7295
+ flush();
7296
+ runs.push(parseTextRun(parser, { fontFamily: "monospace" }));
7297
+ } else if (parser.match("\\textsf")) {
7298
+ flush();
7299
+ runs.push(parseTextRun(parser, { fontFamily: "sans-serif" }));
7300
+ } else if (parser.match("\\textcolor")) {
7301
+ const pos = parser.index;
7302
+ const color = parser.parseStringGroup();
7303
+ if (color !== null) {
7304
+ flush();
7305
+ const body2 = parseTextRun(parser);
7306
+ runs.push(["Annotated", body2, dictionaryFromEntries({ color })]);
7307
+ } else {
7308
+ parser.index = pos;
7309
+ text += "\\textcolor";
7310
+ }
7311
+ } else if (parser.match("\\color")) {
7312
+ const color = parser.parseStringGroup();
7313
+ if (color !== null) {
7314
+ flush();
6721
7315
  runinStyle = { color };
6722
7316
  }
6723
7317
  } else if (parser.match("<space>")) {
@@ -6727,6 +7321,7 @@ var Interval = (() => {
6727
7321
  const expr = parser.parseExpression() ?? "Nothing";
6728
7322
  parser.skipSpace();
6729
7323
  if (parser.match("<$>")) {
7324
+ flush();
6730
7325
  runs.push(expr);
6731
7326
  } else {
6732
7327
  text += "$";
@@ -6737,6 +7332,7 @@ var Interval = (() => {
6737
7332
  const expr = parser.parseExpression() ?? "Nothing";
6738
7333
  parser.skipSpace();
6739
7334
  if (parser.match("<$$>")) {
7335
+ flush();
6740
7336
  runs.push(expr);
6741
7337
  } else {
6742
7338
  text += "$$";
@@ -7087,14 +7683,20 @@ var Interval = (() => {
7087
7683
  }
7088
7684
  while (parser.match("<space>")) {
7089
7685
  }
7090
- let text = "";
7091
- while (!parser.atEnd && parser.peek !== "<}>" && parser.peek !== "<space>") {
7092
- const tok = parser.peek;
7093
- if (/^[a-zA-Z]$/.test(tok)) {
7094
- text += tok;
7095
- parser.nextToken();
7686
+ for (let i = 0; i < keyword.length; i++) {
7687
+ if (keyword[i] === " ") {
7688
+ if (!parser.match("<space>")) {
7689
+ parser.index = start;
7690
+ return false;
7691
+ }
7692
+ while (parser.match("<space>")) {
7693
+ }
7096
7694
  } else {
7097
- break;
7695
+ if (parser.peek !== keyword[i]) {
7696
+ parser.index = start;
7697
+ return false;
7698
+ }
7699
+ parser.nextToken();
7098
7700
  }
7099
7701
  }
7100
7702
  while (parser.match("<space>")) {
@@ -7103,10 +7705,6 @@ var Interval = (() => {
7103
7705
  parser.index = start;
7104
7706
  return false;
7105
7707
  }
7106
- if (text !== keyword) {
7107
- parser.index = start;
7108
- return false;
7109
- }
7110
7708
  return true;
7111
7709
  }
7112
7710
  function matchKeyword(parser, keyword) {
@@ -7348,487 +7946,41 @@ var Interval = (() => {
7348
7946
  return {
7349
7947
  kind: "symbol",
7350
7948
  name: symbol2,
7351
- latexTrigger: [latex],
7352
- parse: symbol2
7353
- };
7354
- }),
7355
- ...SYMBOLS.map(([symbol2, _latex, codepoint]) => {
7356
- return {
7357
- kind: "symbol",
7358
- latexTrigger: [String.fromCodePoint(codepoint)],
7359
- parse: symbol2
7360
- };
7361
- })
7362
- ];
7363
-
7364
- // src/compute-engine/latex-syntax/dictionary/definitions-algebra.ts
7365
- var DEFINITIONS_ALGEBRA = [
7366
- {
7367
- name: "To",
7368
- latexTrigger: ["\\to"],
7369
- kind: "infix",
7370
- precedence: 270
7371
- // MathML rightwards arrow
7372
- },
7373
- {
7374
- // Non-strict mode: -> for maps-to arrow
7375
- latexTrigger: ["-", ">"],
7376
- kind: "infix",
7377
- precedence: 270,
7378
- parse: (parser, lhs, until) => {
7379
- if (parser.options.strict !== false) return null;
7380
- const rhs = parser.parseExpression({ ...until, minPrec: 270 });
7381
- if (rhs === null) return null;
7382
- return ["To", lhs, rhs];
7383
- }
7384
- }
7385
- ];
7386
-
7387
- // src/compute-engine/latex-syntax/dictionary/definitions-logic.ts
7388
- var DEFINITIONS_LOGIC = [
7389
- // Constants
7390
- {
7391
- name: "True",
7392
- kind: "symbol",
7393
- latexTrigger: ["\\top"]
7394
- // ⊤ U+22A4
7395
- },
7396
- {
7397
- kind: "symbol",
7398
- latexTrigger: "\\mathrm{True}",
7399
- parse: "True"
7400
- },
7401
- {
7402
- kind: "symbol",
7403
- latexTrigger: "\\operatorname{True}",
7404
- parse: "True"
7405
- },
7406
- {
7407
- kind: "symbol",
7408
- latexTrigger: "\\mathsf{T}",
7409
- parse: "True"
7410
- },
7411
- {
7412
- name: "False",
7413
- kind: "symbol",
7414
- latexTrigger: ["\\bot"]
7415
- // ⊥ U+22A5
7416
- },
7417
- {
7418
- kind: "symbol",
7419
- latexTrigger: "\\operatorname{False}",
7420
- parse: "False"
7421
- },
7422
- {
7423
- kind: "symbol",
7424
- latexTrigger: "\\mathsf{F}",
7425
- parse: "False"
7426
- },
7427
- // Operators
7428
- // Logic operators have lower precedence than comparisons (245)
7429
- // so that `x = 1 \lor x = 2` parses as `(x = 1) \lor (x = 2)`
7430
- // See https://github.com/cortex-js/compute-engine/issues/243
7431
- {
7432
- name: "And",
7433
- kind: "infix",
7434
- latexTrigger: ["\\land"],
7435
- precedence: 235
7436
- // serialize: '\\land',
7437
- },
7438
- { kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence: 235 },
7439
- { kind: "infix", latexTrigger: "\\&", parse: "And", precedence: 235 },
7440
- {
7441
- kind: "infix",
7442
- latexTrigger: "\\operatorname{and}",
7443
- parse: "And",
7444
- precedence: 235
7445
- },
7446
- {
7447
- name: "Or",
7448
- kind: "infix",
7449
- latexTrigger: ["\\lor"],
7450
- precedence: 230
7451
- },
7452
- { kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence: 230 },
7453
- { kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence: 230 },
7454
- {
7455
- kind: "infix",
7456
- latexTrigger: "\\operatorname{or}",
7457
- parse: "Or",
7458
- precedence: 230
7459
- },
7460
- {
7461
- name: "Xor",
7462
- kind: "infix",
7463
- latexTrigger: ["\\veebar"],
7464
- precedence: 232
7465
- },
7466
- // Possible alt: \oplus ⊕ U+2295
7467
- {
7468
- name: "Not",
7469
- kind: "prefix",
7470
- latexTrigger: ["\\lnot"],
7471
- precedence: 880
7472
- },
7473
- {
7474
- kind: "prefix",
7475
- latexTrigger: ["\\neg"],
7476
- parse: "Not",
7477
- precedence: 880
7478
- },
7479
- {
7480
- name: "Nand",
7481
- kind: "infix",
7482
- latexTrigger: ["\\barwedge"],
7483
- precedence: 232
7484
- // serialize: '\\mid',
7485
- },
7486
- {
7487
- name: "Nor",
7488
- kind: "infix",
7489
- latexTrigger: ["\u22BD"],
7490
- // bar vee
7491
- precedence: 232
7492
- // serialize: '\\downarrow',
7493
- },
7494
- // Functions
7495
- {
7496
- kind: "function",
7497
- symbolTrigger: "and",
7498
- parse: "And"
7499
- },
7500
- {
7501
- kind: "function",
7502
- symbolTrigger: "or",
7503
- parse: "Or"
7504
- },
7505
- {
7506
- kind: "function",
7507
- symbolTrigger: "not",
7508
- parse: "Not"
7509
- },
7510
- // Relations
7511
- {
7512
- name: "Implies",
7513
- kind: "infix",
7514
- precedence: 220,
7515
- associativity: "right",
7516
- latexTrigger: ["\\implies"],
7517
- serialize: "\\implies"
7518
- },
7519
- {
7520
- latexTrigger: ["\\Rightarrow"],
7521
- kind: "infix",
7522
- precedence: 220,
7523
- associativity: "right",
7524
- parse: "Implies"
7525
- },
7526
- {
7527
- latexTrigger: ["\\rightarrow"],
7528
- kind: "infix",
7529
- precedence: 220,
7530
- associativity: "right",
7531
- parse: "Implies"
7532
- },
7533
- {
7534
- latexTrigger: ["\\Longrightarrow"],
7535
- kind: "infix",
7536
- precedence: 220,
7537
- associativity: "right",
7538
- parse: "Implies"
7539
- },
7540
- {
7541
- latexTrigger: ["\\longrightarrow"],
7542
- kind: "infix",
7543
- precedence: 220,
7544
- associativity: "right",
7545
- parse: "Implies"
7546
- },
7547
- {
7548
- // Non-strict mode: => for implies
7549
- latexTrigger: ["=", ">"],
7550
- kind: "infix",
7551
- precedence: 220,
7552
- associativity: "right",
7553
- parse: (parser, lhs, until) => {
7554
- if (parser.options.strict !== false) return null;
7555
- const rhs = parser.parseExpression({ ...until, minPrec: 220 });
7556
- if (rhs === null) return null;
7557
- return ["Implies", lhs, rhs];
7558
- }
7559
- },
7560
- {
7561
- name: "Equivalent",
7562
- // MathML: identical to, Mathematica: Congruent
7563
- latexTrigger: ["\\iff"],
7564
- kind: "infix",
7565
- associativity: "right",
7566
- precedence: 219
7567
- },
7568
- {
7569
- latexTrigger: ["\\Leftrightarrow"],
7570
- kind: "infix",
7571
- associativity: "right",
7572
- precedence: 219,
7573
- parse: "Equivalent"
7574
- },
7575
- {
7576
- latexTrigger: ["\\leftrightarrow"],
7577
- kind: "infix",
7578
- associativity: "right",
7579
- precedence: 219,
7580
- parse: "Equivalent"
7581
- },
7582
- {
7583
- latexTrigger: ["\\Longleftrightarrow"],
7584
- kind: "infix",
7585
- associativity: "right",
7586
- precedence: 219,
7587
- parse: "Equivalent"
7588
- },
7949
+ latexTrigger: [latex],
7950
+ parse: symbol2
7951
+ };
7952
+ }),
7953
+ ...SYMBOLS.map(([symbol2, _latex, codepoint]) => {
7954
+ return {
7955
+ kind: "symbol",
7956
+ latexTrigger: [String.fromCodePoint(codepoint)],
7957
+ parse: symbol2
7958
+ };
7959
+ })
7960
+ ];
7961
+
7962
+ // src/compute-engine/latex-syntax/dictionary/definitions-algebra.ts
7963
+ var DEFINITIONS_ALGEBRA = [
7589
7964
  {
7590
- latexTrigger: ["\\longleftrightarrow"],
7965
+ name: "To",
7966
+ latexTrigger: ["\\to"],
7591
7967
  kind: "infix",
7592
- associativity: "right",
7593
- precedence: 219,
7594
- parse: "Equivalent"
7968
+ precedence: 270
7969
+ // MathML rightwards arrow
7595
7970
  },
7596
7971
  {
7597
- // Non-strict mode: <=> for equivalence
7598
- latexTrigger: ["<", "=", ">"],
7972
+ // Non-strict mode: -> for maps-to arrow
7973
+ latexTrigger: ["-", ">"],
7599
7974
  kind: "infix",
7600
- precedence: 219,
7601
- associativity: "right",
7975
+ precedence: 270,
7602
7976
  parse: (parser, lhs, until) => {
7603
7977
  if (parser.options.strict !== false) return null;
7604
- const rhs = parser.parseExpression({ ...until, minPrec: 219 });
7978
+ const rhs = parser.parseExpression({ ...until, minPrec: 270 });
7605
7979
  if (rhs === null) return null;
7606
- return ["Equivalent", lhs, rhs];
7607
- }
7608
- },
7609
- {
7610
- latexTrigger: ["\\equiv"],
7611
- kind: "infix",
7612
- associativity: "right",
7613
- precedence: 219,
7614
- parse: (parser, lhs, terminator) => {
7615
- const rhs = parser.parseExpression({ ...terminator, minPrec: 219 });
7616
- const index = parser.index;
7617
- const modulus = parser.parseExpression({ ...terminator, minPrec: 219 });
7618
- if (modulus !== null && operator(modulus) === "Mod")
7619
- return ["Congruent", lhs, rhs, missingIfEmpty(operand(modulus, 1))];
7620
- parser.index = index;
7621
- return ["Equivalent", lhs, missingIfEmpty(rhs)];
7622
- }
7623
- },
7624
- {
7625
- name: "Proves",
7626
- kind: "infix",
7627
- latexTrigger: ["\\vdash"],
7628
- precedence: 220,
7629
- associativity: "right",
7630
- serialize: "\\vdash"
7631
- },
7632
- {
7633
- name: "Entails",
7634
- kind: "infix",
7635
- latexTrigger: ["\\vDash"],
7636
- precedence: 220,
7637
- associativity: "right",
7638
- serialize: "\\vDash"
7639
- },
7640
- {
7641
- name: "Satisfies",
7642
- kind: "infix",
7643
- latexTrigger: ["\\models"],
7644
- precedence: 220,
7645
- associativity: "right",
7646
- serialize: "\\models"
7647
- },
7648
- // Quantifiers: for all, exists
7649
- {
7650
- name: "ForAll",
7651
- kind: "prefix",
7652
- latexTrigger: ["\\forall"],
7653
- precedence: 200,
7654
- // Has to be lower than COMPARISON_PRECEDENCE
7655
- serialize: serializeQuantifier("\\forall"),
7656
- parse: parseQuantifier("ForAll")
7657
- },
7658
- {
7659
- name: "Exists",
7660
- kind: "prefix",
7661
- latexTrigger: ["\\exists"],
7662
- precedence: 200,
7663
- // Has to be lower than COMPARISON_PRECEDENCE,
7664
- serialize: serializeQuantifier("\\exists"),
7665
- parse: parseQuantifier("Exists")
7666
- },
7667
- {
7668
- name: "ExistsUnique",
7669
- kind: "prefix",
7670
- latexTrigger: ["\\exists", "!"],
7671
- precedence: 200,
7672
- // Has to be lower than COMPARISON_PRECEDENCE,
7673
- serialize: serializeQuantifier("\\exists!"),
7674
- parse: parseQuantifier("ExistsUnique")
7675
- },
7676
- {
7677
- name: "NotForAll",
7678
- kind: "prefix",
7679
- latexTrigger: ["\\lnot", "\\forall"],
7680
- precedence: 200,
7681
- // Has to be lower than COMPARISON_PRECEDENCE
7682
- serialize: serializeQuantifier("\\lnot\\forall"),
7683
- parse: parseQuantifier("NotForAll")
7684
- },
7685
- {
7686
- name: "NotExists",
7687
- kind: "prefix",
7688
- latexTrigger: ["\\lnot", "\\exists"],
7689
- precedence: 200,
7690
- // Has to be lower than COMPARISON_PRECEDENCE,
7691
- serialize: serializeQuantifier("\\lnot\\exists"),
7692
- parse: parseQuantifier("NotExists")
7693
- },
7694
- {
7695
- name: "KroneckerDelta",
7696
- kind: "prefix",
7697
- latexTrigger: ["\\delta", "_"],
7698
- precedence: 200,
7699
- serialize: (serializer, expr) => {
7700
- const args = operands(expr);
7701
- if (args.length === 0) return "\\delta";
7702
- if (args.every((x) => symbol(x)))
7703
- return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join("")}}`;
7704
- return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join(", ")}}`;
7705
- },
7706
- parse: (parser) => {
7707
- const group = parser.parseGroup();
7708
- if (group === null) {
7709
- const token = parser.parseToken();
7710
- if (!token) return null;
7711
- return ["KroneckerDelta", token];
7712
- }
7713
- const seq = getSequence(group);
7714
- if (seq && seq.length <= 2) return ["KroneckerDelta", ...seq];
7715
- if (operator(group) === "InvisibleOperator")
7716
- return ["KroneckerDelta", ...operands(group)];
7717
- if (group !== null) return ["KroneckerDelta", group];
7718
- return null;
7719
- }
7720
- },
7721
- // Iverson brackets. Also called the "indicator function"
7722
- // Must have a single argument, a relational expression, i.e.
7723
- // `[ a = b ]` or `[ x \leq 0 ]`
7724
- // Otherwise, it gets rejected, it could be something else, like a list or
7725
- // tuple.
7726
- {
7727
- name: "Boole",
7728
- kind: "matchfix",
7729
- openTrigger: "[",
7730
- closeTrigger: "]",
7731
- // serialize: (serializer: Serializer, expr: MathJsonExpression) => {
7732
- // const args = ops(expr);
7733
- // return `[${serializer.serialize(arg)}]`;
7734
- // },
7735
- parse: (_parser, body) => {
7736
- const h = operator(body);
7737
- if (!h) return null;
7738
- if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
7739
- return ["Boole", body];
7740
- }
7741
- },
7742
- {
7743
- kind: "matchfix",
7744
- openTrigger: "\\llbracket",
7745
- closeTrigger: "\\rrbracket",
7746
- parse: (_parser, body) => {
7747
- const h = operator(body);
7748
- if (!h) return null;
7749
- if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
7750
- return ["Boole", body];
7751
- }
7752
- },
7753
- // Predicate application in First-Order Logic.
7754
- // ["Predicate", "P", "x", "y"] serializes to "P(x, y)"
7755
- {
7756
- name: "Predicate",
7757
- serialize: (serializer, expr) => {
7758
- const args = operands(expr);
7759
- if (args.length === 0) return "";
7760
- const pred = args[0];
7761
- const predStr = typeof pred === "string" ? pred : serializer.serialize(pred);
7762
- if (args.length === 1) return predStr;
7763
- const argStrs = args.slice(1).map((arg) => serializer.serialize(arg));
7764
- return `${predStr}(${argStrs.join(", ")})`;
7980
+ return ["To", lhs, rhs];
7765
7981
  }
7766
7982
  }
7767
7983
  ];
7768
- function serializeQuantifier(quantifierSymbol) {
7769
- return (serializer, expr) => {
7770
- const args = operands(expr);
7771
- if (args.length === 0) return quantifierSymbol;
7772
- if (args.length === 1)
7773
- return `${quantifierSymbol} ${serializer.serialize(args[0])}`;
7774
- const boundVar = serializer.serialize(args[0]);
7775
- const body = serializer.serialize(args[1]);
7776
- return `${quantifierSymbol} ${boundVar}, ${body}`;
7777
- };
7778
- }
7779
- function tightBindingCondition(p, terminator) {
7780
- return p.peek === "\\to" || p.peek === "\\rightarrow" || p.peek === "\\implies" || p.peek === "\\Rightarrow" || p.peek === "\\iff" || p.peek === "\\Leftrightarrow" || p.peek === "\\land" || p.peek === "\\wedge" || p.peek === "\\lor" || p.peek === "\\vee" || (terminator.condition?.(p) ?? false);
7781
- }
7782
- function parseQuantifier(kind) {
7783
- return (parser, terminator) => {
7784
- const index = parser.index;
7785
- const useTightBinding = parser.options.quantifierScope !== "loose";
7786
- const symbol2 = parser.parseSymbol(terminator);
7787
- if (symbol2) {
7788
- parser.skipSpace();
7789
- if (parser.match(",") || parser.match("\\mid") || parser.match(".") || parser.match(":") || parser.match("\\colon")) {
7790
- const bodyTerminator = useTightBinding ? {
7791
- ...terminator,
7792
- condition: (p) => tightBindingCondition(p, terminator)
7793
- } : terminator;
7794
- parser.enterQuantifierScope();
7795
- const body2 = parser.parseExpression(bodyTerminator);
7796
- parser.exitQuantifierScope();
7797
- return [kind, symbol2, missingIfEmpty(body2)];
7798
- }
7799
- parser.enterQuantifierScope();
7800
- const body = parser.parseEnclosure();
7801
- parser.exitQuantifierScope();
7802
- if (body) return [kind, symbol2, missingIfEmpty(body)];
7803
- }
7804
- parser.index = index;
7805
- const condTerminator = {
7806
- ...terminator,
7807
- condition: (p) => p.peek === ":" || p.peek === "\\colon" || (terminator.condition?.(p) ?? false)
7808
- };
7809
- const condition = parser.parseExpression(condTerminator);
7810
- if (condition === null) return null;
7811
- parser.skipSpace();
7812
- if (parser.matchAny([",", "\\mid", ":", "\\colon"])) {
7813
- const bodyTerminator = useTightBinding ? {
7814
- ...terminator,
7815
- condition: (p) => tightBindingCondition(p, terminator)
7816
- } : terminator;
7817
- parser.enterQuantifierScope();
7818
- const body = parser.parseExpression(bodyTerminator);
7819
- parser.exitQuantifierScope();
7820
- return [kind, condition, missingIfEmpty(body)];
7821
- }
7822
- if (parser.match("(")) {
7823
- parser.enterQuantifierScope();
7824
- const body = parser.parseExpression(terminator);
7825
- parser.exitQuantifierScope();
7826
- if (!parser.match(")")) return null;
7827
- return [kind, condition, missingIfEmpty(body)];
7828
- }
7829
- return null;
7830
- };
7831
- }
7832
7984
 
7833
7985
  // src/compute-engine/latex-syntax/dictionary/definitions-sets.ts
7834
7986
  function parseIntervalBody(body, openLeft, openRight) {
@@ -12164,7 +12316,7 @@ var Interval = (() => {
12164
12316
  var FLAG_SEQUENCE = "\\p{RI}\\p{RI}";
12165
12317
  var TAG_MOD = `(?:[\\u{E0020}-\\u{E007E}]+\\u{E007F})`;
12166
12318
  var EMOJI_MOD = `(?:\\p{EMod}|${VS16}${KEYCAP}?|${TAG_MOD})`;
12167
- var EMOJI_NOT_SYMBOL = `(?:(?=\\P{XIDC})\\p{Emoji})`;
12319
+ var EMOJI_NOT_SYMBOL = `(?:(?=\\P{XIDC})(?=[^\\x23\\x2a\\x30-\\x39])\\p{Emoji})`;
12168
12320
  var ZWJ_ELEMENT = `(?:${EMOJI_NOT_SYMBOL}${EMOJI_MOD}*|\\p{Emoji}${EMOJI_MOD}+|${FLAG_SEQUENCE})`;
12169
12321
  var POSSIBLE_EMOJI = `(?:${ZWJ_ELEMENT})(${ZWJ}${ZWJ_ELEMENT})*`;
12170
12322
  var SOME_EMOJI = new RegExp(`(?:${POSSIBLE_EMOJI})+`, "u");
@@ -13296,7 +13448,7 @@ var Interval = (() => {
13296
13448
  };
13297
13449
 
13298
13450
  // src/interval.ts
13299
- var version = "0.55.0";
13451
+ var version = "0.55.3";
13300
13452
  return __toCommonJS(interval_exports);
13301
13453
  })();
13302
13454
  /*! Bundled license information: