@cortex-js/compute-engine 0.55.0 → 0.55.2

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 (256) hide show
  1. package/dist/compile.esm.js +1564 -1412
  2. package/dist/compile.min.esm.js +29 -29
  3. package/dist/compile.min.umd.cjs +29 -29
  4. package/dist/compile.umd.cjs +1564 -1412
  5. package/dist/compute-engine.esm.js +741 -486
  6. package/dist/compute-engine.min.esm.js +65 -65
  7. package/dist/compute-engine.min.umd.cjs +65 -65
  8. package/dist/compute-engine.umd.cjs +741 -486
  9. package/dist/core.esm.js +740 -485
  10. package/dist/core.min.esm.js +63 -63
  11. package/dist/core.min.umd.cjs +63 -63
  12. package/dist/core.umd.cjs +740 -485
  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 +1 -1
  105. package/dist/types/compute-engine/compilation/compile-expression.d.ts +1 -1
  106. package/dist/types/compute-engine/compilation/glsl-target.d.ts +1 -1
  107. package/dist/types/compute-engine/compilation/gpu-target.d.ts +1 -1
  108. package/dist/types/compute-engine/compilation/interval-javascript-target.d.ts +1 -1
  109. package/dist/types/compute-engine/compilation/javascript-target.d.ts +1 -1
  110. package/dist/types/compute-engine/compilation/python-target.d.ts +1 -1
  111. package/dist/types/compute-engine/compilation/types.d.ts +1 -1
  112. package/dist/types/compute-engine/compilation/wgsl-target.d.ts +1 -1
  113. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  114. package/dist/types/compute-engine/engine-assumptions.d.ts +1 -1
  115. package/dist/types/compute-engine/engine-cache.d.ts +1 -1
  116. package/dist/types/compute-engine/engine-common-symbols.d.ts +1 -1
  117. package/dist/types/compute-engine/engine-compilation-targets.d.ts +1 -1
  118. package/dist/types/compute-engine/engine-configuration-lifecycle.d.ts +1 -1
  119. package/dist/types/compute-engine/engine-declarations.d.ts +1 -1
  120. package/dist/types/compute-engine/engine-expression-entrypoints.d.ts +1 -1
  121. package/dist/types/compute-engine/engine-extension-contracts.d.ts +1 -1
  122. package/dist/types/compute-engine/engine-library-bootstrap.d.ts +1 -1
  123. package/dist/types/compute-engine/engine-numeric-configuration.d.ts +1 -1
  124. package/dist/types/compute-engine/engine-runtime-state.d.ts +1 -1
  125. package/dist/types/compute-engine/engine-scope.d.ts +1 -1
  126. package/dist/types/compute-engine/engine-sequences.d.ts +1 -1
  127. package/dist/types/compute-engine/engine-simplification-rules.d.ts +1 -1
  128. package/dist/types/compute-engine/engine-startup-coordinator.d.ts +1 -1
  129. package/dist/types/compute-engine/engine-type-resolver.d.ts +1 -1
  130. package/dist/types/compute-engine/engine-validation-entrypoints.d.ts +1 -1
  131. package/dist/types/compute-engine/free-functions.d.ts +1 -1
  132. package/dist/types/compute-engine/function-utils.d.ts +1 -1
  133. package/dist/types/compute-engine/global-types.d.ts +1 -1
  134. package/dist/types/compute-engine/index.d.ts +1 -1
  135. package/dist/types/compute-engine/interval/arithmetic.d.ts +1 -1
  136. package/dist/types/compute-engine/interval/comparison.d.ts +1 -1
  137. package/dist/types/compute-engine/interval/elementary.d.ts +1 -1
  138. package/dist/types/compute-engine/interval/index.d.ts +1 -1
  139. package/dist/types/compute-engine/interval/trigonometric.d.ts +1 -1
  140. package/dist/types/compute-engine/interval/types.d.ts +1 -1
  141. package/dist/types/compute-engine/interval/util.d.ts +1 -1
  142. package/dist/types/compute-engine/latex-syntax/dictionary/default-dictionary.d.ts +1 -1
  143. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  144. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  145. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  146. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-complex.d.ts +1 -1
  147. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  148. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-linear-algebra.d.ts +1 -1
  149. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +3 -1
  150. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  151. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-relational-operators.d.ts +1 -1
  152. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  153. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-statistics.d.ts +1 -1
  154. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  155. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  156. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-units.d.ts +1 -1
  157. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
  158. package/dist/types/compute-engine/latex-syntax/dictionary/indexed-types.d.ts +1 -1
  159. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
  160. package/dist/types/compute-engine/latex-syntax/parse-number.d.ts +1 -1
  161. package/dist/types/compute-engine/latex-syntax/parse-symbol.d.ts +1 -1
  162. package/dist/types/compute-engine/latex-syntax/parse.d.ts +11 -1
  163. package/dist/types/compute-engine/latex-syntax/serialize-dms.d.ts +1 -1
  164. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  165. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  166. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
  167. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  168. package/dist/types/compute-engine/latex-syntax/types.d.ts +1 -1
  169. package/dist/types/compute-engine/latex-syntax/utils.d.ts +1 -1
  170. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  171. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  172. package/dist/types/compute-engine/library/collections.d.ts +1 -1
  173. package/dist/types/compute-engine/library/colors.d.ts +1 -1
  174. package/dist/types/compute-engine/library/combinatorics.d.ts +1 -1
  175. package/dist/types/compute-engine/library/complex.d.ts +1 -1
  176. package/dist/types/compute-engine/library/control-structures.d.ts +1 -1
  177. package/dist/types/compute-engine/library/core.d.ts +1 -1
  178. package/dist/types/compute-engine/library/fractals.d.ts +1 -1
  179. package/dist/types/compute-engine/library/library.d.ts +1 -1
  180. package/dist/types/compute-engine/library/linear-algebra.d.ts +1 -1
  181. package/dist/types/compute-engine/library/logic-analysis.d.ts +1 -1
  182. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  183. package/dist/types/compute-engine/library/number-theory.d.ts +1 -1
  184. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  185. package/dist/types/compute-engine/library/quantity-arithmetic.d.ts +1 -1
  186. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  187. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  188. package/dist/types/compute-engine/library/sets.d.ts +1 -1
  189. package/dist/types/compute-engine/library/statistics.d.ts +1 -1
  190. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  191. package/dist/types/compute-engine/library/type-handlers.d.ts +1 -1
  192. package/dist/types/compute-engine/library/unit-data.d.ts +1 -1
  193. package/dist/types/compute-engine/library/units.d.ts +1 -1
  194. package/dist/types/compute-engine/library/utils.d.ts +1 -1
  195. package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +1 -1
  196. package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +1 -1
  197. package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +1 -1
  198. package/dist/types/compute-engine/numeric-value/types.d.ts +1 -1
  199. package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
  200. package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
  201. package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
  202. package/dist/types/compute-engine/numerics/linear-algebra.d.ts +1 -1
  203. package/dist/types/compute-engine/numerics/monte-carlo.d.ts +1 -1
  204. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  205. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  206. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  207. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  208. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  209. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  210. package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
  211. package/dist/types/compute-engine/numerics/special-functions.d.ts +1 -1
  212. package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
  213. package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
  214. package/dist/types/compute-engine/numerics/types.d.ts +1 -1
  215. package/dist/types/compute-engine/numerics/unit-data.d.ts +1 -1
  216. package/dist/types/compute-engine/oeis.d.ts +1 -1
  217. package/dist/types/compute-engine/sequence.d.ts +1 -1
  218. package/dist/types/compute-engine/symbolic/antiderivative.d.ts +1 -1
  219. package/dist/types/compute-engine/symbolic/derivative.d.ts +1 -1
  220. package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
  221. package/dist/types/compute-engine/symbolic/fu-cost.d.ts +1 -1
  222. package/dist/types/compute-engine/symbolic/fu-transforms.d.ts +1 -1
  223. package/dist/types/compute-engine/symbolic/fu.d.ts +1 -1
  224. package/dist/types/compute-engine/symbolic/logic-utils.d.ts +1 -1
  225. package/dist/types/compute-engine/symbolic/simplify-abs.d.ts +1 -1
  226. package/dist/types/compute-engine/symbolic/simplify-divide.d.ts +1 -1
  227. package/dist/types/compute-engine/symbolic/simplify-factorial.d.ts +1 -1
  228. package/dist/types/compute-engine/symbolic/simplify-hyperbolic.d.ts +1 -1
  229. package/dist/types/compute-engine/symbolic/simplify-infinity.d.ts +1 -1
  230. package/dist/types/compute-engine/symbolic/simplify-log.d.ts +1 -1
  231. package/dist/types/compute-engine/symbolic/simplify-logic.d.ts +1 -1
  232. package/dist/types/compute-engine/symbolic/simplify-power.d.ts +1 -1
  233. package/dist/types/compute-engine/symbolic/simplify-product.d.ts +1 -1
  234. package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
  235. package/dist/types/compute-engine/symbolic/simplify-sum.d.ts +1 -1
  236. package/dist/types/compute-engine/symbolic/simplify-trig.d.ts +1 -1
  237. package/dist/types/compute-engine/tensor/tensor-fields.d.ts +1 -1
  238. package/dist/types/compute-engine/tensor/tensors.d.ts +1 -1
  239. package/dist/types/compute-engine/types-definitions.d.ts +1 -1
  240. package/dist/types/compute-engine/types-engine.d.ts +1 -1
  241. package/dist/types/compute-engine/types-evaluation.d.ts +1 -1
  242. package/dist/types/compute-engine/types-expression.d.ts +1 -1
  243. package/dist/types/compute-engine/types-kernel-evaluation.d.ts +1 -1
  244. package/dist/types/compute-engine/types-kernel-serialization.d.ts +1 -1
  245. package/dist/types/compute-engine/types-serialization.d.ts +1 -1
  246. package/dist/types/compute-engine/types.d.ts +1 -1
  247. package/dist/types/compute-engine.d.ts +1 -1
  248. package/dist/types/core.d.ts +1 -1
  249. package/dist/types/interval.d.ts +1 -1
  250. package/dist/types/latex-syntax.d.ts +2 -2
  251. package/dist/types/math-json/symbols.d.ts +1 -1
  252. package/dist/types/math-json/types.d.ts +1 -1
  253. package/dist/types/math-json/utils.d.ts +1 -1
  254. package/dist/types/math-json.d.ts +2 -2
  255. package/dist/types/numerics.d.ts +1 -1
  256. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- /** Compute Engine 0.55.0 */
1
+ /** Compute Engine 0.55.2 */
2
2
 
3
3
  // src/compute-engine/numerics/richardson.ts
4
4
  function extrapolate(f, x0, options = {}) {
@@ -4735,1132 +4735,1726 @@ function expressionToDictionaryValue(expr) {
4735
4735
  return expr;
4736
4736
  }
4737
4737
 
4738
- // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
4739
- function parseSequence(parser, terminator, lhs, prec, sep) {
4740
- if (terminator && terminator.minPrec >= prec) return null;
4741
- const result = lhs ? [lhs] : ["Nothing"];
4742
- let done = false;
4743
- while (!done) {
4744
- done = true;
4745
- parser.skipSpace();
4746
- while (parser.match(sep)) {
4747
- result.push("Nothing");
4748
- parser.skipSpace();
4749
- }
4750
- parser.skipVisualSpace();
4751
- if (parser.atTerminator(terminator)) {
4752
- result.push("Nothing");
4753
- } else {
4754
- const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
4755
- result.push(rhs ?? "Nothing");
4756
- done = rhs === null;
4757
- }
4758
- if (!done) {
4759
- parser.skipSpace();
4760
- done = !parser.match(sep);
4761
- if (!done) parser.skipVisualSpace();
4762
- }
4763
- }
4764
- return result;
4765
- }
4766
- function serializeOps(sep = "") {
4767
- return (serializer, expr) => {
4768
- if (!expr) return "";
4769
- const xs = operands(expr);
4770
- if (xs.length === 0) return "";
4771
- if (xs.length === 1) return serializer.serialize(xs[0]);
4772
- sep = {
4773
- "&": "\\&",
4774
- ":": "\\colon",
4775
- "|": "\\mvert",
4776
- "-": "-",
4777
- "\xB7": "\\cdot",
4778
- // U+00B7 MIDDLE DOT
4779
- "\u2012": "-",
4780
- // U+2012 FIGURE DASH
4781
- "\u2013": "--",
4782
- // U+2013 EN DASH
4783
- "\u2014": "---",
4784
- // U+2014 EM DASH
4785
- "\u2015": "-",
4786
- // U+2015 HORIZONTAL BAR
4787
- "\u2022": "\\bullet",
4788
- // U+2022 BULLET
4789
- "\u2026": "\\ldots"
4790
- }[sep] ?? sep;
4791
- const ys = xs.reduce((acc, item) => {
4792
- acc.push(serializer.serialize(item), sep);
4793
- return acc;
4794
- }, []);
4795
- ys.pop();
4796
- return joinLatex(ys);
4797
- };
4798
- }
4799
- var DEFINITIONS_CORE = [
4800
- //
4738
+ // src/compute-engine/latex-syntax/dictionary/definitions-logic.ts
4739
+ var DEFINITIONS_LOGIC = [
4801
4740
  // Constants
4802
- //
4803
4741
  {
4804
- latexTrigger: ["\\placeholder"],
4742
+ name: "True",
4805
4743
  kind: "symbol",
4806
- parse: (parser) => {
4807
- while (parser.match("<space>")) {
4808
- }
4809
- if (parser.match("["))
4810
- while (!parser.match("]") && !parser.atBoundary) parser.nextToken();
4811
- while (parser.match("<space>")) {
4812
- }
4813
- if (parser.match("<{>"))
4814
- while (!parser.match("<}>") && !parser.atBoundary) parser.nextToken();
4815
- return "Nothing";
4816
- }
4744
+ latexTrigger: ["\\top"]
4745
+ // U+22A4
4817
4746
  },
4818
- { name: "ContinuationPlaceholder", latexTrigger: ["\\dots"] },
4819
- { latexTrigger: ["\\ldots"], parse: "ContinuationPlaceholder" },
4820
- { latexTrigger: [".", ".", "."], parse: "ContinuationPlaceholder" },
4821
- //
4822
- // Functions
4823
- //
4824
- // Anonymous function, i.e. `(x) \mapsto x^2`
4825
4747
  {
4826
- name: "Function",
4827
- latexTrigger: ["\\mapsto"],
4828
- kind: "infix",
4829
- precedence: ARROW_PRECEDENCE,
4830
- // MathML rightwards arrow
4831
- parse: (parser, lhs, _until) => {
4832
- let params = [];
4833
- if (operator(lhs) === "Delimiter") lhs = operand(lhs, 1) ?? "Nothing";
4834
- if (operator(lhs) === "Sequence") {
4835
- for (const x of operands(lhs)) {
4836
- if (!symbol(x)) return null;
4837
- params.push(symbol(x));
4838
- }
4839
- } else {
4840
- if (!symbol(lhs)) return null;
4841
- params = [symbol(lhs)];
4842
- }
4843
- let rhs = parser.parseExpression({ minPrec: ARROW_PRECEDENCE }) ?? "Nothing";
4844
- if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
4845
- if (operator(rhs) === "Sequence") rhs = ["Block", ...operands(rhs)];
4846
- return ["Function", rhs, ...params];
4847
- },
4848
- serialize: (serializer, expr) => {
4849
- const args = operands(expr);
4850
- if (args.length < 1) return "()\\mapsto()";
4851
- if (args.length === 1)
4852
- return joinLatex([
4853
- "()",
4854
- "\\mapsto",
4855
- serializer.serialize(operand(expr, 1))
4856
- ]);
4857
- if (args.length === 2) {
4858
- return joinLatex([
4859
- serializer.serialize(operand(expr, 2)),
4860
- "\\mapsto",
4861
- serializer.serialize(operand(expr, 1))
4862
- ]);
4863
- }
4864
- return joinLatex([
4865
- serializer.wrapString(
4866
- operands(expr)?.slice(1).map((x) => serializer.serialize(x)).join(", "),
4867
- "normal"
4868
- ),
4869
- "\\mapsto",
4870
- serializer.serialize(operand(expr, 1))
4871
- ]);
4872
- }
4748
+ kind: "symbol",
4749
+ latexTrigger: "\\mathrm{True}",
4750
+ parse: "True"
4873
4751
  },
4874
4752
  {
4875
- name: "Apply",
4876
- kind: "function",
4877
- symbolTrigger: "apply",
4878
- serialize: (serializer, expr) => {
4879
- const lhs = operand(expr, 1);
4880
- const h = operator(lhs);
4881
- if (h === "InverseFunction" || h === "Derivative") {
4882
- const style2 = serializer.options.applyFunctionStyle(
4883
- expr,
4884
- serializer.level
4885
- );
4886
- const args = operands(expr).slice(1);
4887
- return serializer.serializeFunction(
4888
- lhs,
4889
- serializer.dictionary.ids.get(h)
4890
- ) + serializer.wrapString(
4891
- args.map((x) => serializer.serialize(x)).join(", "),
4892
- style2
4893
- );
4894
- }
4895
- const rhs = operand(expr, 2);
4896
- if (typeof lhs === "string" || !rhs) {
4897
- const fn = operands(expr).slice(1);
4898
- return serializer.serialize(fn);
4899
- }
4900
- if (nops(expr) === 2) {
4901
- return joinLatex([
4902
- serializer.wrap(lhs, 20),
4903
- "\\lhd",
4904
- serializer.wrap(rhs, 20)
4905
- ]);
4906
- }
4907
- const style = serializer.options.applyFunctionStyle(
4908
- expr,
4909
- serializer.level
4910
- );
4911
- return joinLatex([
4912
- "\\operatorname{apply}",
4913
- serializer.wrapString(
4914
- serializer.serialize(h) + ", " + serializer.serialize(["List", ...operands(expr)]),
4915
- style
4916
- )
4917
- ]);
4918
- }
4753
+ kind: "symbol",
4754
+ latexTrigger: "\\operatorname{True}",
4755
+ parse: "True"
4919
4756
  },
4920
4757
  {
4921
- latexTrigger: "\\lhd",
4922
- kind: "infix",
4923
- precedence: 20,
4924
- parse: "Apply"
4758
+ kind: "symbol",
4759
+ latexTrigger: "\\mathsf{T}",
4760
+ parse: "True"
4925
4761
  },
4926
4762
  {
4927
- latexTrigger: "\\rhd",
4763
+ name: "False",
4764
+ kind: "symbol",
4765
+ latexTrigger: ["\\bot"]
4766
+ // ⊥ U+22A5
4767
+ },
4768
+ {
4769
+ kind: "symbol",
4770
+ latexTrigger: "\\operatorname{False}",
4771
+ parse: "False"
4772
+ },
4773
+ {
4774
+ kind: "symbol",
4775
+ latexTrigger: "\\mathsf{F}",
4776
+ parse: "False"
4777
+ },
4778
+ // Operators
4779
+ // Logic operators have lower precedence than comparisons (245)
4780
+ // so that `x = 1 \lor x = 2` parses as `(x = 1) \lor (x = 2)`
4781
+ // See https://github.com/cortex-js/compute-engine/issues/243
4782
+ {
4783
+ name: "And",
4928
4784
  kind: "infix",
4929
- precedence: 20,
4930
- parse: (parser, lhs, _until) => {
4931
- const rhs = parser.parseExpression({ minPrec: 21 }) ?? "Nothing";
4932
- return ["Apply", rhs, lhs];
4933
- }
4785
+ latexTrigger: ["\\land"],
4786
+ precedence: 235
4787
+ // serialize: '\\land',
4934
4788
  },
4789
+ { kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence: 235 },
4790
+ { kind: "infix", latexTrigger: "\\&", parse: "And", precedence: 235 },
4935
4791
  {
4936
- name: "EvaluateAt",
4937
- openTrigger: ".",
4938
- closeTrigger: "|",
4939
- kind: "matchfix",
4940
- serialize: (serializer, expr) => {
4941
- const fn = operand(expr, 1);
4942
- if (!fn) return "";
4943
- const args = operands(expr).slice(1);
4944
- if (operator(fn) === "Function") {
4945
- const parameters = operands(fn).slice(1);
4946
- let body = operand(fn, 1);
4947
- if (operator(body) === "Block" && nops(body) === 1)
4948
- body = operand(body, 1);
4949
- if (parameters.length > 0) {
4950
- return `\\left.\\left(${serializer.serialize(
4951
- body
4952
- )}\\right)\\right|_{${parameters.map(
4953
- (x, i) => `${serializer.serialize(x)}=${serializer.serialize(args[i])}`
4954
- ).join(", ")}}`;
4955
- }
4956
- }
4957
- return `\\left.\\left(${serializer.serialize(fn)}\\right)\\right|_{${args.map((x) => serializer.serialize(x)).join(", ")}}`;
4958
- }
4792
+ kind: "infix",
4793
+ latexTrigger: "\\operatorname{and}",
4794
+ parse: "And",
4795
+ precedence: 235
4959
4796
  },
4960
- // The mathtools package includes several synonmyms for \colonequals. The
4961
- // preferred one as of summer 2022 is `\coloneq` (see § 3.7.3 https://ctan.math.illinois.edu/macros/latex/contrib/mathtools/mathtools.pdf)
4962
4797
  {
4963
- name: "Assign",
4964
- latexTrigger: "\\coloneq",
4798
+ name: "Or",
4965
4799
  kind: "infix",
4966
- associativity: "right",
4967
- precedence: ASSIGNMENT_PRECEDENCE,
4968
- serialize: (serializer, expr) => {
4969
- const id = unhold(operand(expr, 1));
4970
- if (operator(operand(expr, 2)) === "Function") {
4971
- const op_2 = operand(expr, 2);
4972
- const body = unhold(operand(op_2, 1));
4973
- const args = operands(op_2).slice(1);
4974
- return joinLatex([
4975
- serializer.serialize(id),
4976
- serializer.wrapString(
4977
- args.map((x) => serializer.serialize(x)).join(", "),
4978
- serializer.options.applyFunctionStyle(expr, serializer.level)
4979
- ),
4980
- "\\coloneq",
4981
- serializer.serialize(body)
4982
- ]);
4983
- }
4984
- return joinLatex([
4985
- serializer.serialize(id),
4986
- "\\coloneq",
4987
- serializer.serialize(operand(expr, 2))
4988
- ]);
4989
- },
4990
- parse: parseAssign
4800
+ latexTrigger: ["\\lor"],
4801
+ precedence: 230
4991
4802
  },
4803
+ { kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence: 230 },
4804
+ { kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence: 230 },
4992
4805
  {
4993
- latexTrigger: "\\coloneqq",
4994
4806
  kind: "infix",
4995
- associativity: "right",
4996
- precedence: ASSIGNMENT_PRECEDENCE,
4997
- parse: parseAssign
4807
+ latexTrigger: "\\operatorname{or}",
4808
+ parse: "Or",
4809
+ precedence: 230
4998
4810
  },
4999
- // From the colonequals package:
5000
4811
  {
5001
- latexTrigger: "\\colonequals",
4812
+ name: "Xor",
5002
4813
  kind: "infix",
5003
- associativity: "right",
5004
- precedence: ASSIGNMENT_PRECEDENCE,
5005
- parse: parseAssign
4814
+ latexTrigger: ["\\veebar"],
4815
+ precedence: 232
5006
4816
  },
4817
+ // Possible alt: \oplus ⊕ U+2295
5007
4818
  {
5008
- latexTrigger: [":", "="],
5009
- kind: "infix",
5010
- associativity: "right",
5011
- precedence: ASSIGNMENT_PRECEDENCE,
5012
- parse: parseAssign
4819
+ name: "Not",
4820
+ kind: "prefix",
4821
+ latexTrigger: ["\\lnot"],
4822
+ precedence: 880
5013
4823
  },
5014
- // General colon operator (type annotation, mapping notation)
5015
- // Precedence below assignment (260) so `:=` takes priority,
5016
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5017
4824
  {
5018
- name: "Colon",
5019
- latexTrigger: ":",
4825
+ kind: "prefix",
4826
+ latexTrigger: ["\\neg"],
4827
+ parse: "Not",
4828
+ precedence: 880
4829
+ },
4830
+ {
4831
+ name: "Nand",
5020
4832
  kind: "infix",
5021
- associativity: "right",
5022
- precedence: 250,
5023
- serialize: (serializer, expr) => joinLatex([
5024
- serializer.serialize(operand(expr, 1)),
5025
- "\\colon",
5026
- serializer.serialize(operand(expr, 2))
5027
- ])
4833
+ latexTrigger: ["\\barwedge"],
4834
+ precedence: 232
4835
+ // serialize: '\\mid',
5028
4836
  },
5029
4837
  {
5030
- latexTrigger: "\\colon",
4838
+ name: "Nor",
5031
4839
  kind: "infix",
5032
- associativity: "right",
5033
- precedence: 250,
5034
- parse: "Colon"
4840
+ latexTrigger: ["\u22BD"],
4841
+ // bar vee
4842
+ precedence: 232
4843
+ // serialize: '\\downarrow',
5035
4844
  },
4845
+ // Functions
5036
4846
  {
5037
- name: "BaseForm",
5038
- serialize: (serializer, expr) => {
5039
- const radix = machineValue(operand(expr, 2)) ?? NaN;
5040
- if (isFinite(radix) && radix >= 2 && radix <= 36) {
5041
- const num = machineValue(operand(expr, 1)) ?? NaN;
5042
- if (isFinite(num) && Number.isInteger(num)) {
5043
- let digits = Number(num).toString(radix);
5044
- let groupLength = 0;
5045
- if (radix === 2) {
5046
- groupLength = 4;
5047
- } else if (radix === 10) {
5048
- groupLength = 4;
5049
- } else if (radix === 16) {
5050
- groupLength = 2;
5051
- } else if (radix > 16) {
5052
- groupLength = 4;
5053
- }
5054
- if (groupLength > 0) {
5055
- const oldDigits = digits;
5056
- digits = "";
5057
- for (let i = 0; i < oldDigits.length; i++) {
5058
- if (i > 0 && i % groupLength === 0) digits = "\\, " + digits;
5059
- digits = oldDigits[oldDigits.length - i - 1] + digits;
5060
- }
5061
- }
5062
- return `(\\text{${digits}}_{${radix}}`;
5063
- }
5064
- }
5065
- return "\\operatorname{BaseForm}(" + serializer.serialize(operand(expr, 1)) + ", " + serializer.serialize(operand(expr, 2)) + ")";
5066
- }
4847
+ kind: "function",
4848
+ symbolTrigger: "and",
4849
+ parse: "And"
5067
4850
  },
5068
4851
  {
5069
- name: "Sequence",
5070
- // Use a space as a separator, otherwise a sequence of numbers
5071
- // could be interpreted as a single number.
5072
- serialize: serializeOps(" ")
4852
+ kind: "function",
4853
+ symbolTrigger: "or",
4854
+ parse: "Or"
5073
4855
  },
5074
4856
  {
5075
- name: "InvisibleOperator",
5076
- serialize: serializeOps("")
4857
+ kind: "function",
4858
+ symbolTrigger: "not",
4859
+ parse: "Not"
5077
4860
  },
4861
+ // Relations
5078
4862
  {
5079
- // The first argument is a function expression.
5080
- // The second (optional) argument is a string specifying the
5081
- // delimiters and separator.
5082
- name: "Delimiter",
5083
- serialize: (serializer, expr) => {
5084
- const style = serializer.options.groupStyle(expr, serializer.level + 1);
5085
- const arg1 = operand(expr, 1);
5086
- let delims = {
5087
- Set: "{,}",
5088
- List: "[,]",
5089
- Tuple: "(,)",
5090
- Single: "(,)",
5091
- Pair: "(,)",
5092
- Triple: "(,)",
5093
- Sequence: "(,)",
5094
- String: '""'
5095
- }[operator(arg1)];
5096
- const items = delims ? arg1 : ["Sequence", arg1];
5097
- delims ??= "(,)";
5098
- if (nops(expr) > 1) {
5099
- const op2 = stringValue(operand(expr, 2));
5100
- if (typeof op2 === "string" && op2.length <= 3) delims = op2;
5101
- }
5102
- let [open, sep, close] = ["", "", ""];
5103
- if (delims.length === 3) [open, sep, close] = delims;
5104
- else if (delims.length === 2) [open, close] = delims;
5105
- else if (delims.length === 1) sep = delims;
5106
- const body = arg1 ? items ? serializeOps(sep)(serializer, items) : serializer.serialize(arg1) : "";
5107
- return serializer.wrapString(body, style, open + close);
5108
- }
4863
+ name: "Implies",
4864
+ kind: "infix",
4865
+ precedence: 220,
4866
+ associativity: "right",
4867
+ latexTrigger: ["\\implies"],
4868
+ serialize: "\\implies"
5109
4869
  },
5110
4870
  {
5111
- name: "Tuple",
5112
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
4871
+ latexTrigger: ["\\Rightarrow"],
4872
+ kind: "infix",
4873
+ precedence: 220,
4874
+ associativity: "right",
4875
+ parse: "Implies"
5113
4876
  },
5114
4877
  {
5115
- name: "Pair",
5116
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
4878
+ latexTrigger: ["\\rightarrow"],
4879
+ kind: "infix",
4880
+ precedence: 220,
4881
+ associativity: "right",
4882
+ parse: "Implies"
5117
4883
  },
5118
4884
  {
5119
- name: "Triple",
5120
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
4885
+ latexTrigger: ["\\Longrightarrow"],
4886
+ kind: "infix",
4887
+ precedence: 220,
4888
+ associativity: "right",
4889
+ parse: "Implies"
5121
4890
  },
5122
4891
  {
5123
- name: "Single",
5124
- serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
4892
+ latexTrigger: ["\\longrightarrow"],
4893
+ kind: "infix",
4894
+ precedence: 220,
4895
+ associativity: "right",
4896
+ parse: "Implies"
5125
4897
  },
5126
4898
  {
5127
- name: "Domain",
5128
- serialize: (serializer, expr) => {
5129
- if (operator(expr) === "Error") return serializer.serialize(expr);
5130
- return `\\mathbf{${serializer.serialize(operand(expr, 1))}}`;
4899
+ // Non-strict mode: => for implies
4900
+ latexTrigger: ["=", ">"],
4901
+ kind: "infix",
4902
+ precedence: 220,
4903
+ associativity: "right",
4904
+ parse: (parser, lhs, until) => {
4905
+ if (parser.options.strict !== false) return null;
4906
+ const rhs = parser.parseExpression({ ...until, minPrec: 220 });
4907
+ if (rhs === null) return null;
4908
+ return ["Implies", lhs, rhs];
5131
4909
  }
5132
4910
  },
5133
4911
  {
5134
- latexTrigger: ["\\mathtip"],
5135
- parse: (parser) => {
5136
- const op1 = parser.parseGroup();
5137
- parser.parseGroup();
5138
- return op1;
5139
- }
4912
+ name: "Equivalent",
4913
+ // MathML: identical to, Mathematica: Congruent
4914
+ latexTrigger: ["\\iff"],
4915
+ kind: "infix",
4916
+ associativity: "right",
4917
+ precedence: 219
5140
4918
  },
5141
4919
  {
5142
- latexTrigger: ["\\texttip"],
5143
- parse: (parser) => {
5144
- const op1 = parser.parseGroup();
5145
- parser.parseGroup();
5146
- return op1;
5147
- }
4920
+ latexTrigger: ["\\Leftrightarrow"],
4921
+ kind: "infix",
4922
+ associativity: "right",
4923
+ precedence: 219,
4924
+ parse: "Equivalent"
5148
4925
  },
5149
4926
  {
5150
- latexTrigger: ["\\error"],
5151
- parse: (parser) => ["Error", parser.parseGroup()]
4927
+ latexTrigger: ["\\leftrightarrow"],
4928
+ kind: "infix",
4929
+ associativity: "right",
4930
+ precedence: 219,
4931
+ parse: "Equivalent"
5152
4932
  },
5153
4933
  {
5154
- name: "Error",
5155
- serialize: (serializer, expr) => {
5156
- const op1 = operand(expr, 1);
5157
- if (stringValue(op1) === "missing")
5158
- return `\\error{${serializer.options.missingSymbol ?? "\\placeholder{}"}}`;
5159
- const where = errorContextAsLatex(serializer, expr) || "\\blacksquare";
5160
- const code = operator(op1) === "ErrorCode" ? stringValue(operand(op1, 1)) : stringValue(op1);
5161
- if (code === "incompatible-type") {
5162
- if (symbol(operand(op1, 3)) === "Undefined") {
5163
- return `\\mathtip{\\error{${where}}}{\\notin ${serializer.serialize(
5164
- operand(op1, 2)
5165
- )}}`;
5166
- }
5167
- return `\\mathtip{\\error{${where}}}{\\in ${serializer.serialize(
5168
- operand(op1, 3)
5169
- )}\\notin ${serializer.serialize(operand(op1, 2))}}`;
5170
- }
5171
- if (typeof code === "string") return `\\error{${where}}`;
5172
- return `\\error{${where}}`;
5173
- }
5174
- },
5175
- {
5176
- name: "ErrorCode",
5177
- serialize: (serializer, expr) => {
5178
- const code = stringValue(operand(expr, 1));
5179
- if (code === "missing")
5180
- return serializer.options.missingSymbol ?? "\\placeholder{}";
5181
- if (code === "unexpected-command" || code === "unexpected-operator" || code === "unexpected-token" || code === "invalid-symbol" || code === "unknown-environment" || code === "unexpected-base" || code === "incompatible-type") {
5182
- return "";
5183
- }
5184
- return `\\texttip{\\error{\\blacksquare}}{\\mathtt{${code}}}`;
5185
- }
4934
+ latexTrigger: ["\\Longleftrightarrow"],
4935
+ kind: "infix",
4936
+ associativity: "right",
4937
+ precedence: 219,
4938
+ parse: "Equivalent"
5186
4939
  },
5187
4940
  {
5188
- name: "FromLatex",
5189
- serialize: (_serializer, expr) => {
5190
- return `\\texttt{${sanitizeLatex(stringValue(operand(expr, 1)))}}`;
5191
- }
4941
+ latexTrigger: ["\\longleftrightarrow"],
4942
+ kind: "infix",
4943
+ associativity: "right",
4944
+ precedence: 219,
4945
+ parse: "Equivalent"
5192
4946
  },
5193
4947
  {
5194
- name: "Latex",
5195
- serialize: (serializer, expr) => {
5196
- if (expr === null) return "";
5197
- return joinLatex(
5198
- mapArgs(expr, (x) => stringValue(x) ?? serializer.serialize(x))
5199
- );
4948
+ // Non-strict mode: <=> for equivalence
4949
+ latexTrigger: ["<", "=", ">"],
4950
+ kind: "infix",
4951
+ precedence: 219,
4952
+ associativity: "right",
4953
+ parse: (parser, lhs, until) => {
4954
+ if (parser.options.strict !== false) return null;
4955
+ const rhs = parser.parseExpression({ ...until, minPrec: 219 });
4956
+ if (rhs === null) return null;
4957
+ return ["Equivalent", lhs, rhs];
5200
4958
  }
5201
4959
  },
5202
4960
  {
5203
- name: "LatexString",
5204
- serialize: (serializer, expr) => {
5205
- if (expr === null) return "";
5206
- return joinLatex(mapArgs(expr, (x) => serializer.serialize(x)));
4961
+ latexTrigger: ["\\equiv"],
4962
+ kind: "infix",
4963
+ associativity: "right",
4964
+ precedence: 219,
4965
+ parse: (parser, lhs, terminator) => {
4966
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 219 });
4967
+ const index = parser.index;
4968
+ const modulus = parser.parseExpression({ ...terminator, minPrec: 219 });
4969
+ if (modulus !== null && operator(modulus) === "Mod")
4970
+ return ["Congruent", lhs, rhs, missingIfEmpty(operand(modulus, 1))];
4971
+ parser.index = index;
4972
+ return ["Equivalent", lhs, missingIfEmpty(rhs)];
5207
4973
  }
5208
4974
  },
5209
- { name: "LatexTokens", serialize: serializeLatexTokens },
5210
4975
  {
5211
- name: "At",
5212
- kind: "postfix",
5213
- precedence: 810,
5214
- latexTrigger: ["["],
5215
- parse: parseAt("]"),
5216
- serialize: (serializer, expr) => joinLatex(["\\lbrack", serializeOps(", ")(serializer, expr), "\\rbrack"])
4976
+ name: "Proves",
4977
+ kind: "infix",
4978
+ latexTrigger: ["\\vdash"],
4979
+ precedence: 220,
4980
+ associativity: "right",
4981
+ serialize: "\\vdash"
5217
4982
  },
5218
4983
  {
5219
- kind: "postfix",
5220
- precedence: 810,
5221
- latexTrigger: ["\\lbrack"],
5222
- parse: parseAt("\\rbrack")
4984
+ name: "Entails",
4985
+ kind: "infix",
4986
+ latexTrigger: ["\\vDash"],
4987
+ precedence: 220,
4988
+ associativity: "right",
4989
+ serialize: "\\vDash"
5223
4990
  },
5224
4991
  {
5225
- kind: "postfix",
5226
- precedence: 810,
5227
- latexTrigger: ["\\left", "\\lbrack"],
5228
- parse: parseAt("\\right", "\\rbrack")
4992
+ name: "Satisfies",
4993
+ kind: "infix",
4994
+ latexTrigger: ["\\models"],
4995
+ precedence: 220,
4996
+ associativity: "right",
4997
+ serialize: "\\models"
5229
4998
  },
4999
+ // Quantifiers: for all, exists
5230
5000
  {
5231
- kind: "postfix",
5232
- latexTrigger: ["_"],
5233
- parse: (parser, lhs, _until) => {
5234
- let rhs = parser.parseGroup() ?? parser.parseToken();
5235
- if (rhs === null && parser.options.strict === false && parser.peek === "(")
5236
- rhs = parser.parseEnclosure();
5237
- const sym2 = symbol(lhs);
5238
- if (rhs !== null && (sym2 && parser.getSymbolType(sym2).matches("indexed_collection") || operator(lhs) === "List")) {
5239
- if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
5240
- if (operator(rhs) === "Sequence") return ["At", lhs, ...operands(rhs)];
5241
- return ["At", lhs, rhs];
5242
- }
5243
- return ["Subscript", lhs, rhs];
5244
- }
5001
+ name: "ForAll",
5002
+ kind: "prefix",
5003
+ latexTrigger: ["\\forall"],
5004
+ precedence: 200,
5005
+ // Has to be lower than COMPARISON_PRECEDENCE
5006
+ serialize: serializeQuantifier("\\forall"),
5007
+ parse: parseQuantifier("ForAll")
5245
5008
  },
5246
5009
  {
5247
- name: "List",
5248
- kind: "matchfix",
5249
- openTrigger: "[",
5250
- closeTrigger: "]",
5251
- parse: parseBrackets,
5252
- serialize: serializeList
5010
+ name: "Exists",
5011
+ kind: "prefix",
5012
+ latexTrigger: ["\\exists"],
5013
+ precedence: 200,
5014
+ // Has to be lower than COMPARISON_PRECEDENCE,
5015
+ serialize: serializeQuantifier("\\exists"),
5016
+ parse: parseQuantifier("Exists")
5253
5017
  },
5254
5018
  {
5255
- kind: "matchfix",
5256
- openTrigger: "(",
5257
- closeTrigger: ")",
5258
- parse: parseParenDelimiter
5019
+ name: "ExistsUnique",
5020
+ kind: "prefix",
5021
+ latexTrigger: ["\\exists", "!"],
5022
+ precedence: 200,
5023
+ // Has to be lower than COMPARISON_PRECEDENCE,
5024
+ serialize: serializeQuantifier("\\exists!"),
5025
+ parse: parseQuantifier("ExistsUnique")
5259
5026
  },
5260
5027
  {
5261
- latexTrigger: [","],
5262
- kind: "infix",
5263
- precedence: 20,
5264
- // Unlike the matchfix version of List,
5265
- // when the comma operator is used, the lhs and rhs are flattened,
5266
- // i.e. `1,2,3` -> `["Delimiter", ["List", 1, 2, 3], ","]`,
5267
- // and `1, (2, 3)` -> `["Delimiter",
5268
- // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "()", ","]]],
5269
- parse: (parser, lhs, terminator) => {
5270
- const seq = parseSequence(parser, terminator, lhs, 20, ",");
5271
- if (seq === null) return null;
5272
- return ["Delimiter", ["Sequence", ...seq], { str: "," }];
5273
- }
5028
+ name: "NotForAll",
5029
+ kind: "prefix",
5030
+ latexTrigger: ["\\lnot", "\\forall"],
5031
+ precedence: 200,
5032
+ // Has to be lower than COMPARISON_PRECEDENCE
5033
+ serialize: serializeQuantifier("\\lnot\\forall"),
5034
+ parse: parseQuantifier("NotForAll")
5274
5035
  },
5275
- // Entry to handle the case of a single comma
5276
- // with a missing lhs.
5277
5036
  {
5278
- latexTrigger: [","],
5037
+ name: "NotExists",
5279
5038
  kind: "prefix",
5280
- precedence: 20,
5281
- parse: (parser, terminator) => {
5282
- const seq = parseSequence(parser, terminator, null, 20, ",");
5283
- if (seq === null) return null;
5284
- return ["Delimiter", ["Sequence", ...seq], { str: "," }];
5285
- }
5039
+ latexTrigger: ["\\lnot", "\\exists"],
5040
+ precedence: 200,
5041
+ // Has to be lower than COMPARISON_PRECEDENCE,
5042
+ serialize: serializeQuantifier("\\lnot\\exists"),
5043
+ parse: parseQuantifier("NotExists")
5286
5044
  },
5287
5045
  {
5288
- name: "Range",
5289
- latexTrigger: [".", "."],
5290
- kind: "infix",
5291
- // associativity: 'left',
5292
- precedence: 800,
5293
- parse: parseRange,
5046
+ name: "KroneckerDelta",
5047
+ kind: "prefix",
5048
+ latexTrigger: ["\\delta", "_"],
5049
+ precedence: 200,
5294
5050
  serialize: (serializer, expr) => {
5295
5051
  const args = operands(expr);
5296
- if (args.length === 0) return "";
5297
- if (args.length === 1)
5298
- return "1.." + serializer.serialize(operand(expr, 1));
5299
- if (args.length === 2)
5300
- return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(operand(expr, 2), 10);
5301
- if (args.length === 3) {
5302
- const step = machineValue(operand(expr, 3));
5303
- const start = machineValue(operand(expr, 1));
5304
- if (step !== null && start !== null) {
5305
- return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(start + step, 10) + ".." + serializer.wrap(operand(expr, 2), 10);
5306
- }
5307
- 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);
5052
+ if (args.length === 0) return "\\delta";
5053
+ if (args.every((x) => symbol(x)))
5054
+ return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join("")}}`;
5055
+ return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join(", ")}}`;
5056
+ },
5057
+ parse: (parser) => {
5058
+ const group = parser.parseGroup();
5059
+ if (group === null) {
5060
+ const token = parser.parseToken();
5061
+ if (!token) return null;
5062
+ return ["KroneckerDelta", token];
5308
5063
  }
5309
- return "";
5064
+ const seq = getSequence(group);
5065
+ if (seq && seq.length <= 2) return ["KroneckerDelta", ...seq];
5066
+ if (operator(group) === "InvisibleOperator")
5067
+ return ["KroneckerDelta", ...operands(group)];
5068
+ if (group !== null) return ["KroneckerDelta", group];
5069
+ return null;
5310
5070
  }
5311
5071
  },
5072
+ // Iverson brackets. Also called the "indicator function"
5073
+ // Must have a single argument, a relational expression, i.e.
5074
+ // `[ a = b ]` or `[ x \leq 0 ]`
5075
+ // Otherwise, it gets rejected, it could be something else, like a list or
5076
+ // tuple.
5312
5077
  {
5313
- latexTrigger: [";"],
5314
- kind: "infix",
5315
- precedence: 19,
5316
- parse: (parser, lhs, terminator) => {
5317
- const seq = parseSequence(parser, terminator, lhs, 19, ";");
5318
- if (seq === null) return null;
5319
- if (seq.some((e) => operator(e) === "Assign"))
5320
- return buildBlockFromSequence(seq);
5321
- return ["Delimiter", ["Sequence", ...seq], "';'"];
5078
+ name: "Boole",
5079
+ kind: "matchfix",
5080
+ openTrigger: "[",
5081
+ closeTrigger: "]",
5082
+ // serialize: (serializer: Serializer, expr: MathJsonExpression) => {
5083
+ // const args = ops(expr);
5084
+ // return `[${serializer.serialize(arg)}]`;
5085
+ // },
5086
+ parse: (_parser, body) => {
5087
+ const h = operator(body);
5088
+ if (!h) return null;
5089
+ if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
5090
+ return ["Boole", body];
5322
5091
  }
5323
5092
  },
5324
- // \text{where} — variable binding infix
5325
5093
  {
5326
- latexTrigger: ["\\text"],
5327
- kind: "infix",
5328
- associativity: "none",
5329
- precedence: 21,
5330
- // Above ; (19) and , (20), very low binding
5331
- parse: (parser, lhs, until) => {
5332
- const start = parser.index;
5333
- if (!matchTextKeyword(parser, "where")) {
5334
- parser.index = start;
5335
- return null;
5336
- }
5337
- return parseWhereExpression(parser, lhs, until);
5094
+ kind: "matchfix",
5095
+ openTrigger: "\\llbracket",
5096
+ closeTrigger: "\\rrbracket",
5097
+ parse: (_parser, body) => {
5098
+ const h = operator(body);
5099
+ if (!h) return null;
5100
+ if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
5101
+ return ["Boole", body];
5338
5102
  }
5339
5103
  },
5340
- // \operatorname{where}
5341
- {
5342
- symbolTrigger: "where",
5343
- kind: "infix",
5344
- associativity: "none",
5345
- precedence: 21,
5346
- parse: (parser, lhs, until) => parseWhereExpression(parser, lhs, until)
5347
- },
5348
- // Block serializer — used by both `where` and semicolon blocks
5104
+ // Predicate application in First-Order Logic.
5105
+ // ["Predicate", "P", "x", "y"] serializes to "P(x, y)"
5349
5106
  {
5350
- name: "Block",
5107
+ name: "Predicate",
5351
5108
  serialize: (serializer, expr) => {
5352
5109
  const args = operands(expr);
5353
- if (!args || args.length === 0) return "";
5354
- const parts = args.filter((a) => operator(a) !== "Declare").map((a) => serializer.serialize(a));
5355
- return parts.join("; ");
5110
+ if (args.length === 0) return "";
5111
+ const pred = args[0];
5112
+ const predStr = typeof pred === "string" ? pred : serializer.serialize(pred);
5113
+ if (args.length === 1) return predStr;
5114
+ const argStrs = args.slice(1).map((arg) => serializer.serialize(arg));
5115
+ return `${predStr}(${argStrs.join(", ")})`;
5116
+ }
5117
+ }
5118
+ ];
5119
+ function serializeQuantifier(quantifierSymbol) {
5120
+ return (serializer, expr) => {
5121
+ const args = operands(expr);
5122
+ if (args.length === 0) return quantifierSymbol;
5123
+ if (args.length === 1)
5124
+ return `${quantifierSymbol} ${serializer.serialize(args[0])}`;
5125
+ const boundVar = serializer.serialize(args[0]);
5126
+ const body = serializer.serialize(args[1]);
5127
+ return `${quantifierSymbol} ${boundVar}, ${body}`;
5128
+ };
5129
+ }
5130
+ function tightBindingCondition(p, terminator) {
5131
+ 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);
5132
+ }
5133
+ function parseQuantifier(kind) {
5134
+ return (parser, terminator) => {
5135
+ const index = parser.index;
5136
+ const useTightBinding = parser.options.quantifierScope !== "loose";
5137
+ const symbol2 = parser.parseSymbol(terminator);
5138
+ if (symbol2) {
5139
+ parser.skipSpace();
5140
+ if (parser.match(",") || parser.match("\\mid") || parser.match(".") || parser.match(":") || parser.match("\\colon")) {
5141
+ const bodyTerminator = useTightBinding ? {
5142
+ ...terminator,
5143
+ condition: (p) => tightBindingCondition(p, terminator)
5144
+ } : terminator;
5145
+ parser.enterQuantifierScope();
5146
+ const body2 = parser.parseExpression(bodyTerminator);
5147
+ parser.exitQuantifierScope();
5148
+ return [kind, symbol2, missingIfEmpty(body2)];
5149
+ }
5150
+ parser.enterQuantifierScope();
5151
+ const body = parser.parseEnclosure();
5152
+ parser.exitQuantifierScope();
5153
+ if (body) return [kind, symbol2, missingIfEmpty(body)];
5154
+ }
5155
+ parser.index = index;
5156
+ const condTerminator = {
5157
+ ...terminator,
5158
+ condition: (p) => p.peek === ":" || p.peek === "\\colon" || (terminator.condition?.(p) ?? false)
5159
+ };
5160
+ const condition = parser.parseExpression(condTerminator);
5161
+ if (condition === null) return null;
5162
+ parser.skipSpace();
5163
+ if (parser.matchAny([",", "\\mid", ":", "\\colon"])) {
5164
+ const bodyTerminator = useTightBinding ? {
5165
+ ...terminator,
5166
+ condition: (p) => tightBindingCondition(p, terminator)
5167
+ } : terminator;
5168
+ parser.enterQuantifierScope();
5169
+ const body = parser.parseExpression(bodyTerminator);
5170
+ parser.exitQuantifierScope();
5171
+ return [kind, condition, missingIfEmpty(body)];
5172
+ }
5173
+ if (parser.match("(")) {
5174
+ parser.enterQuantifierScope();
5175
+ const body = parser.parseExpression(terminator);
5176
+ parser.exitQuantifierScope();
5177
+ if (!parser.match(")")) return null;
5178
+ return [kind, condition, missingIfEmpty(body)];
5179
+ }
5180
+ return null;
5181
+ };
5182
+ }
5183
+
5184
+ // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
5185
+ function parseSequence(parser, terminator, lhs, prec, sep) {
5186
+ if (terminator && terminator.minPrec >= prec) return null;
5187
+ const result = lhs ? [lhs] : ["Nothing"];
5188
+ let done = false;
5189
+ while (!done) {
5190
+ done = true;
5191
+ parser.skipSpace();
5192
+ while (parser.match(sep)) {
5193
+ result.push("Nothing");
5194
+ parser.skipSpace();
5195
+ }
5196
+ parser.skipVisualSpace();
5197
+ if (parser.atTerminator(terminator)) {
5198
+ result.push("Nothing");
5199
+ } else {
5200
+ const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
5201
+ result.push(rhs ?? "Nothing");
5202
+ done = rhs === null;
5203
+ }
5204
+ if (!done) {
5205
+ parser.skipSpace();
5206
+ done = !parser.match(sep);
5207
+ if (!done) parser.skipVisualSpace();
5208
+ }
5209
+ }
5210
+ return result;
5211
+ }
5212
+ function serializeOps(sep = "") {
5213
+ return (serializer, expr) => {
5214
+ if (!expr) return "";
5215
+ const xs = operands(expr);
5216
+ if (xs.length === 0) return "";
5217
+ if (xs.length === 1) return serializer.serialize(xs[0]);
5218
+ sep = {
5219
+ "&": "\\&",
5220
+ ":": "\\colon",
5221
+ "|": "\\mvert",
5222
+ "-": "-",
5223
+ "\xB7": "\\cdot",
5224
+ // U+00B7 MIDDLE DOT
5225
+ "\u2012": "-",
5226
+ // U+2012 FIGURE DASH
5227
+ "\u2013": "--",
5228
+ // U+2013 EN DASH
5229
+ "\u2014": "---",
5230
+ // U+2014 EM DASH
5231
+ "\u2015": "-",
5232
+ // U+2015 HORIZONTAL BAR
5233
+ "\u2022": "\\bullet",
5234
+ // U+2022 BULLET
5235
+ "\u2026": "\\ldots"
5236
+ }[sep] ?? sep;
5237
+ const ys = xs.reduce((acc, item) => {
5238
+ acc.push(serializer.serialize(item), sep);
5239
+ return acc;
5240
+ }, []);
5241
+ ys.pop();
5242
+ return joinLatex(ys);
5243
+ };
5244
+ }
5245
+ var DEFINITIONS_CORE = [
5246
+ //
5247
+ // Constants
5248
+ //
5249
+ {
5250
+ latexTrigger: ["\\placeholder"],
5251
+ kind: "symbol",
5252
+ parse: (parser) => {
5253
+ while (parser.match("<space>")) {
5254
+ }
5255
+ if (parser.match("["))
5256
+ while (!parser.match("]") && !parser.atBoundary) parser.nextToken();
5257
+ while (parser.match("<space>")) {
5258
+ }
5259
+ if (parser.match("<{>"))
5260
+ while (!parser.match("<}>") && !parser.atBoundary) parser.nextToken();
5261
+ return "Nothing";
5356
5262
  }
5357
5263
  },
5358
- // Serializer for If expressions (separate from the parser entry
5359
- // because name-based entries affect kind-based indexing)
5264
+ { name: "ContinuationPlaceholder", latexTrigger: ["\\dots"] },
5265
+ { latexTrigger: ["\\ldots"], parse: "ContinuationPlaceholder" },
5266
+ { latexTrigger: [".", ".", "."], parse: "ContinuationPlaceholder" },
5267
+ //
5268
+ // Functions
5269
+ //
5270
+ // Anonymous function, i.e. `(x) \mapsto x^2`
5360
5271
  {
5361
- name: "If",
5272
+ name: "Function",
5273
+ latexTrigger: ["\\mapsto"],
5274
+ kind: "infix",
5275
+ precedence: ARROW_PRECEDENCE,
5276
+ // MathML rightwards arrow
5277
+ parse: (parser, lhs, _until) => {
5278
+ let params = [];
5279
+ if (operator(lhs) === "Delimiter") lhs = operand(lhs, 1) ?? "Nothing";
5280
+ if (operator(lhs) === "Sequence") {
5281
+ for (const x of operands(lhs)) {
5282
+ if (!symbol(x)) return null;
5283
+ params.push(symbol(x));
5284
+ }
5285
+ } else {
5286
+ if (!symbol(lhs)) return null;
5287
+ params = [symbol(lhs)];
5288
+ }
5289
+ let rhs = parser.parseExpression({ minPrec: ARROW_PRECEDENCE }) ?? "Nothing";
5290
+ if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
5291
+ if (operator(rhs) === "Sequence") rhs = ["Block", ...operands(rhs)];
5292
+ return ["Function", rhs, ...params];
5293
+ },
5362
5294
  serialize: (serializer, expr) => {
5363
5295
  const args = operands(expr);
5364
- if (!args || args.length < 3) return "";
5296
+ if (args.length < 1) return "()\\mapsto()";
5297
+ if (args.length === 1)
5298
+ return joinLatex([
5299
+ "()",
5300
+ "\\mapsto",
5301
+ serializer.serialize(operand(expr, 1))
5302
+ ]);
5303
+ if (args.length === 2) {
5304
+ return joinLatex([
5305
+ serializer.serialize(operand(expr, 2)),
5306
+ "\\mapsto",
5307
+ serializer.serialize(operand(expr, 1))
5308
+ ]);
5309
+ }
5365
5310
  return joinLatex([
5366
- "\\text{if }",
5367
- serializer.serialize(args[0]),
5368
- "\\text{ then }",
5369
- serializer.serialize(args[1]),
5370
- "\\text{ else }",
5371
- serializer.serialize(args[2])
5311
+ serializer.wrapString(
5312
+ operands(expr)?.slice(1).map((x) => serializer.serialize(x)).join(", "),
5313
+ "normal"
5314
+ ),
5315
+ "\\mapsto",
5316
+ serializer.serialize(operand(expr, 1))
5372
5317
  ]);
5373
5318
  }
5374
5319
  },
5375
- // Serializer for Loop expressions
5376
5320
  {
5377
- name: "Loop",
5321
+ name: "Apply",
5322
+ kind: "function",
5323
+ symbolTrigger: "apply",
5378
5324
  serialize: (serializer, expr) => {
5379
- const args = operands(expr);
5380
- if (!args || args.length < 2) return "";
5381
- const body = args[0];
5382
- const indexing = args[1];
5383
- if (operator(indexing) === "Element") {
5384
- const index = operand(indexing, 1);
5385
- const range2 = operand(indexing, 2);
5386
- if (operator(range2) === "Range") {
5387
- const lo = operand(range2, 1);
5388
- const hi = operand(range2, 2);
5389
- return joinLatex([
5390
- "\\text{for }",
5391
- serializer.serialize(index),
5392
- "\\text{ from }",
5393
- serializer.serialize(lo),
5394
- "\\text{ to }",
5395
- serializer.serialize(hi),
5396
- "\\text{ do }",
5397
- serializer.serialize(body)
5398
- ]);
5399
- }
5325
+ const lhs = operand(expr, 1);
5326
+ const h = operator(lhs);
5327
+ if (h === "InverseFunction" || h === "Derivative") {
5328
+ const style2 = serializer.options.applyFunctionStyle(
5329
+ expr,
5330
+ serializer.level
5331
+ );
5332
+ const args = operands(expr).slice(1);
5333
+ return serializer.serializeFunction(
5334
+ lhs,
5335
+ serializer.dictionary.ids.get(h)
5336
+ ) + serializer.wrapString(
5337
+ args.map((x) => serializer.serialize(x)).join(", "),
5338
+ style2
5339
+ );
5340
+ }
5341
+ const rhs = operand(expr, 2);
5342
+ if (typeof lhs === "string" || !rhs) {
5343
+ const fn = operands(expr).slice(1);
5344
+ return serializer.serialize(fn);
5345
+ }
5346
+ if (nops(expr) === 2) {
5347
+ return joinLatex([
5348
+ serializer.wrap(lhs, 20),
5349
+ "\\lhd",
5350
+ serializer.wrap(rhs, 20)
5351
+ ]);
5400
5352
  }
5353
+ const style = serializer.options.applyFunctionStyle(
5354
+ expr,
5355
+ serializer.level
5356
+ );
5401
5357
  return joinLatex([
5402
- "\\operatorname{Loop}(",
5403
- serializer.serialize(body),
5404
- ", ",
5405
- serializer.serialize(indexing),
5406
- ")"
5358
+ "\\operatorname{apply}",
5359
+ serializer.wrapString(
5360
+ serializer.serialize(h) + ", " + serializer.serialize(["List", ...operands(expr)]),
5361
+ style
5362
+ )
5407
5363
  ]);
5408
5364
  }
5409
5365
  },
5410
- // Serializer for Break
5411
- { name: "Break", serialize: () => "\\text{break}" },
5412
- // Serializer for Continue
5413
- { name: "Continue", serialize: () => "\\text{continue}" },
5414
- // Serializer for Return
5415
5366
  {
5416
- name: "Return",
5417
- serialize: (serializer, expr) => {
5418
- const arg = operand(expr, 1);
5419
- if (!arg || symbol(arg) === "Nothing") return "\\text{return}";
5420
- return joinLatex(["\\text{return }", serializer.serialize(arg)]);
5421
- }
5367
+ latexTrigger: "\\lhd",
5368
+ kind: "infix",
5369
+ precedence: 20,
5370
+ parse: "Apply"
5422
5371
  },
5423
- // Also match `\operatorname{if}` / `\mathrm{if}`
5424
5372
  {
5425
- symbolTrigger: "if",
5426
- kind: "prefix",
5427
- precedence: 245,
5428
- parse: (parser, until) => {
5429
- return parseIfExpression(parser, until);
5373
+ latexTrigger: "\\rhd",
5374
+ kind: "infix",
5375
+ precedence: 20,
5376
+ parse: (parser, lhs, _until) => {
5377
+ const rhs = parser.parseExpression({ minPrec: 21 }) ?? "Nothing";
5378
+ return ["Apply", rhs, lhs];
5430
5379
  }
5431
5380
  },
5432
- // \operatorname{for}
5433
- {
5434
- symbolTrigger: "for",
5435
- kind: "prefix",
5436
- precedence: 245,
5437
- parse: (parser, until) => parseForExpression(parser, until)
5438
- },
5439
- // \operatorname{break}
5440
- {
5441
- symbolTrigger: "break",
5442
- kind: "prefix",
5443
- precedence: 245,
5444
- parse: () => ["Break"]
5445
- },
5446
- // \operatorname{continue}
5447
5381
  {
5448
- symbolTrigger: "continue",
5449
- kind: "prefix",
5450
- precedence: 245,
5451
- parse: () => ["Continue"]
5452
- },
5453
- // \operatorname{return}
5454
- {
5455
- symbolTrigger: "return",
5456
- kind: "prefix",
5457
- precedence: 245,
5458
- parse: (parser, until) => [
5459
- "Return",
5460
- parser.parseExpression(until) ?? "Nothing"
5461
- ]
5382
+ name: "EvaluateAt",
5383
+ openTrigger: ".",
5384
+ closeTrigger: "|",
5385
+ kind: "matchfix",
5386
+ serialize: (serializer, expr) => {
5387
+ const fn = operand(expr, 1);
5388
+ if (!fn) return "";
5389
+ const args = operands(expr).slice(1);
5390
+ if (operator(fn) === "Function") {
5391
+ const parameters = operands(fn).slice(1);
5392
+ let body = operand(fn, 1);
5393
+ if (operator(body) === "Block" && nops(body) === 1)
5394
+ body = operand(body, 1);
5395
+ if (parameters.length > 0) {
5396
+ return `\\left.\\left(${serializer.serialize(
5397
+ body
5398
+ )}\\right)\\right|_{${parameters.map(
5399
+ (x, i) => `${serializer.serialize(x)}=${serializer.serialize(args[i])}`
5400
+ ).join(", ")}}`;
5401
+ }
5402
+ }
5403
+ return `\\left.\\left(${serializer.serialize(fn)}\\right)\\right|_{${args.map((x) => serializer.serialize(x)).join(", ")}}`;
5404
+ }
5462
5405
  },
5406
+ // The mathtools package includes several synonmyms for \colonequals. The
5407
+ // preferred one as of summer 2022 is `\coloneq` (see § 3.7.3 https://ctan.math.illinois.edu/macros/latex/contrib/mathtools/mathtools.pdf)
5463
5408
  {
5464
- name: "String",
5465
- latexTrigger: ["\\text"],
5466
- parse: (parser, until) => {
5467
- const start = parser.index;
5468
- if (matchTextKeyword(parser, "if"))
5469
- return parseIfExpression(parser, until);
5470
- parser.index = start;
5471
- if (matchTextKeyword(parser, "for"))
5472
- return parseForExpression(parser, until);
5473
- parser.index = start;
5474
- if (matchTextKeyword(parser, "break"))
5475
- return ["Break"];
5476
- parser.index = start;
5477
- if (matchTextKeyword(parser, "continue"))
5478
- return ["Continue"];
5479
- parser.index = start;
5480
- if (matchTextKeyword(parser, "return"))
5481
- return [
5482
- "Return",
5483
- parser.parseExpression(until) ?? "Nothing"
5484
- ];
5485
- parser.index = start;
5486
- return parseTextRun(parser);
5487
- },
5409
+ name: "Assign",
5410
+ latexTrigger: "\\coloneq",
5411
+ kind: "infix",
5412
+ associativity: "right",
5413
+ precedence: ASSIGNMENT_PRECEDENCE,
5488
5414
  serialize: (serializer, expr) => {
5489
- const args = operands(expr);
5490
- if (args.length === 0) return "\\text{}";
5415
+ const id = unhold(operand(expr, 1));
5416
+ if (operator(operand(expr, 2)) === "Function") {
5417
+ const op_2 = operand(expr, 2);
5418
+ const body = unhold(operand(op_2, 1));
5419
+ const args = operands(op_2).slice(1);
5420
+ return joinLatex([
5421
+ serializer.serialize(id),
5422
+ serializer.wrapString(
5423
+ args.map((x) => serializer.serialize(x)).join(", "),
5424
+ serializer.options.applyFunctionStyle(expr, serializer.level)
5425
+ ),
5426
+ "\\coloneq",
5427
+ serializer.serialize(body)
5428
+ ]);
5429
+ }
5491
5430
  return joinLatex([
5492
- "\\text{",
5493
- args.map((x) => serializer.serialize(x)).join(""),
5494
- "}"
5431
+ serializer.serialize(id),
5432
+ "\\coloneq",
5433
+ serializer.serialize(operand(expr, 2))
5495
5434
  ]);
5496
- }
5435
+ },
5436
+ parse: parseAssign
5497
5437
  },
5498
5438
  {
5499
- name: "Subscript",
5500
- latexTrigger: ["_"],
5439
+ latexTrigger: "\\coloneqq",
5501
5440
  kind: "infix",
5502
- serialize: (serializer, expr) => {
5503
- if (nops(expr) === 2) {
5504
- return serializer.serialize(operand(expr, 1)) + "_{" + serializer.serialize(operand(expr, 2)) + "}";
5505
- }
5506
- return "_{" + serializer.serialize(operand(expr, 1)) + "}";
5507
- }
5441
+ associativity: "right",
5442
+ precedence: ASSIGNMENT_PRECEDENCE,
5443
+ parse: parseAssign
5508
5444
  },
5509
- { name: "Superplus", latexTrigger: ["^", "+"], kind: "postfix" },
5510
- { name: "Subplus", latexTrigger: ["_", "+"], kind: "postfix" },
5445
+ // From the colonequals package:
5511
5446
  {
5512
- name: "Superminus",
5513
- latexTrigger: ["^", "-"],
5514
- kind: "postfix",
5515
- parse: (parser, lhs) => {
5516
- if (parser.options.strict === false && /^[0-9]$/.test(parser.peek))
5517
- return null;
5518
- return ["Superminus", lhs];
5519
- }
5447
+ latexTrigger: "\\colonequals",
5448
+ kind: "infix",
5449
+ associativity: "right",
5450
+ precedence: ASSIGNMENT_PRECEDENCE,
5451
+ parse: parseAssign
5520
5452
  },
5521
- { name: "Subminus", latexTrigger: ["_", "-"], kind: "postfix" },
5522
5453
  {
5523
- latexTrigger: ["^", "*"],
5524
- kind: "postfix",
5525
- parse: (_parser, lhs) => ["Superstar", lhs]
5454
+ latexTrigger: [":", "="],
5455
+ kind: "infix",
5456
+ associativity: "right",
5457
+ precedence: ASSIGNMENT_PRECEDENCE,
5458
+ parse: parseAssign
5526
5459
  },
5527
- // { name: 'Superstar', latexTrigger: ['^', '\\star'], kind: 'postfix' },
5460
+ // General colon operator (type annotation, mapping notation)
5461
+ // Precedence below assignment (260) so `:=` takes priority,
5462
+ // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5528
5463
  {
5529
- latexTrigger: ["_", "*"],
5530
- kind: "postfix",
5531
- parse: (_parser, lhs) => ["Substar", lhs]
5464
+ name: "Colon",
5465
+ latexTrigger: ":",
5466
+ kind: "infix",
5467
+ associativity: "right",
5468
+ precedence: 250,
5469
+ serialize: (serializer, expr) => joinLatex([
5470
+ serializer.serialize(operand(expr, 1)),
5471
+ "\\colon",
5472
+ serializer.serialize(operand(expr, 2))
5473
+ ])
5532
5474
  },
5533
- { name: "Substar", latexTrigger: ["_", "\\star"], kind: "postfix" },
5534
- { name: "Superdagger", latexTrigger: ["^", "\\dagger"], kind: "postfix" },
5535
5475
  {
5536
- latexTrigger: ["^", "\\dag"],
5537
- kind: "postfix",
5538
- parse: (_parser, lhs) => ["Superdagger", lhs]
5476
+ latexTrigger: "\\colon",
5477
+ kind: "infix",
5478
+ associativity: "right",
5479
+ precedence: 250,
5480
+ parse: "Colon"
5539
5481
  },
5540
5482
  {
5541
- name: "Prime",
5542
- latexTrigger: ["^", "\\prime"],
5543
- // Note: we don't need a precedence because the trigger is '^'
5544
- // and '^' (and '_') are treated specially by the parser.
5545
- kind: "postfix",
5546
- parse: (parser, lhs) => parsePrime(parser, lhs, 1),
5483
+ name: "BaseForm",
5547
5484
  serialize: (serializer, expr) => {
5548
- const n2 = machineValue(operand(expr, 2)) ?? 1;
5549
- const base = serializer.serialize(operand(expr, 1));
5550
- if (n2 === 1) return base + "^\\prime";
5551
- if (n2 === 2) return base + "^\\doubleprime";
5552
- if (n2 === 3) return base + "^\\tripleprime";
5553
- return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
5485
+ const radix = machineValue(operand(expr, 2)) ?? NaN;
5486
+ if (isFinite(radix) && radix >= 2 && radix <= 36) {
5487
+ const num = machineValue(operand(expr, 1)) ?? NaN;
5488
+ if (isFinite(num) && Number.isInteger(num)) {
5489
+ let digits = Number(num).toString(radix);
5490
+ let groupLength = 0;
5491
+ if (radix === 2) {
5492
+ groupLength = 4;
5493
+ } else if (radix === 10) {
5494
+ groupLength = 4;
5495
+ } else if (radix === 16) {
5496
+ groupLength = 2;
5497
+ } else if (radix > 16) {
5498
+ groupLength = 4;
5499
+ }
5500
+ if (groupLength > 0) {
5501
+ const oldDigits = digits;
5502
+ digits = "";
5503
+ for (let i = 0; i < oldDigits.length; i++) {
5504
+ if (i > 0 && i % groupLength === 0) digits = "\\, " + digits;
5505
+ digits = oldDigits[oldDigits.length - i - 1] + digits;
5506
+ }
5507
+ }
5508
+ return `(\\text{${digits}}_{${radix}}`;
5509
+ }
5510
+ }
5511
+ return "\\operatorname{BaseForm}(" + serializer.serialize(operand(expr, 1)) + ", " + serializer.serialize(operand(expr, 2)) + ")";
5554
5512
  }
5555
5513
  },
5556
5514
  {
5557
- latexTrigger: "^{\\prime\\prime}",
5558
- kind: "postfix",
5559
- parse: (parser, lhs) => parsePrime(parser, lhs, 2)
5515
+ name: "Sequence",
5516
+ // Use a space as a separator, otherwise a sequence of numbers
5517
+ // could be interpreted as a single number.
5518
+ serialize: serializeOps(" ")
5560
5519
  },
5561
5520
  {
5562
- latexTrigger: "^{\\prime\\prime\\prime}",
5563
- kind: "postfix",
5564
- parse: (parser, lhs) => parsePrime(parser, lhs, 3)
5521
+ name: "InvisibleOperator",
5522
+ serialize: serializeOps("")
5565
5523
  },
5566
5524
  {
5567
- latexTrigger: ["^", "\\doubleprime"],
5568
- kind: "postfix",
5569
- parse: (parser, lhs) => parsePrime(parser, lhs, 2)
5525
+ // The first argument is a function expression.
5526
+ // The second (optional) argument is a string specifying the
5527
+ // delimiters and separator.
5528
+ name: "Delimiter",
5529
+ serialize: (serializer, expr) => {
5530
+ const style = serializer.options.groupStyle(expr, serializer.level + 1);
5531
+ const arg1 = operand(expr, 1);
5532
+ let delims = {
5533
+ Set: "{,}",
5534
+ List: "[,]",
5535
+ Tuple: "(,)",
5536
+ Single: "(,)",
5537
+ Pair: "(,)",
5538
+ Triple: "(,)",
5539
+ Sequence: "(,)",
5540
+ String: '""'
5541
+ }[operator(arg1)];
5542
+ const items = delims ? arg1 : ["Sequence", arg1];
5543
+ delims ??= "(,)";
5544
+ if (nops(expr) > 1) {
5545
+ const op2 = stringValue(operand(expr, 2));
5546
+ if (typeof op2 === "string" && op2.length <= 3) delims = op2;
5547
+ }
5548
+ let [open, sep, close] = ["", "", ""];
5549
+ if (delims.length === 3) [open, sep, close] = delims;
5550
+ else if (delims.length === 2) [open, close] = delims;
5551
+ else if (delims.length === 1) sep = delims;
5552
+ const body = arg1 ? items ? serializeOps(sep)(serializer, items) : serializer.serialize(arg1) : "";
5553
+ return serializer.wrapString(body, style, open + close);
5554
+ }
5570
5555
  },
5571
5556
  {
5572
- latexTrigger: ["^", "\\tripleprime"],
5573
- kind: "postfix",
5574
- parse: (parser, lhs) => parsePrime(parser, lhs, 3)
5557
+ name: "Tuple",
5558
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5575
5559
  },
5576
5560
  {
5577
- latexTrigger: "'",
5578
- kind: "postfix",
5579
- precedence: 810,
5580
- parse: (parser, lhs) => parsePrime(parser, lhs, 1)
5561
+ name: "Pair",
5562
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5581
5563
  },
5582
5564
  {
5583
- latexTrigger: "\\prime",
5584
- kind: "postfix",
5585
- precedence: 810,
5586
- parse: (parser, lhs) => parsePrime(parser, lhs, 1)
5565
+ name: "Triple",
5566
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5587
5567
  },
5588
5568
  {
5589
- latexTrigger: "\\doubleprime",
5590
- kind: "postfix",
5591
- precedence: 810,
5592
- parse: (parser, lhs) => parsePrime(parser, lhs, 2)
5569
+ name: "Single",
5570
+ serialize: (serializer, expr) => joinLatex(["(", serializeOps(",")(serializer, expr), ")"])
5593
5571
  },
5594
5572
  {
5595
- latexTrigger: "\\tripleprime",
5596
- kind: "postfix",
5597
- precedence: 810,
5598
- parse: (parser, lhs) => parsePrime(parser, lhs, 3)
5573
+ name: "Domain",
5574
+ serialize: (serializer, expr) => {
5575
+ if (operator(expr) === "Error") return serializer.serialize(expr);
5576
+ return `\\mathbf{${serializer.serialize(operand(expr, 1))}}`;
5577
+ }
5599
5578
  },
5600
- // Lagrange Notation for n-th order derivatives,
5601
- // i.e. f^{(n)} -> Derivative(f, n)
5602
5579
  {
5603
- latexTrigger: ["^", "<{>", "("],
5604
- kind: "postfix",
5605
- parse: (parser, lhs, until) => {
5606
- const sym2 = symbol(lhs);
5607
- if (!sym2 || !parser.getSymbolType(sym2).matches("function")) return null;
5608
- parser.addBoundary([")"]);
5609
- const expr = parser.parseExpression(until);
5610
- if (!parser.matchBoundary()) return null;
5611
- if (!parser.match("<}>")) return null;
5612
- return ["Derivative", lhs, expr];
5580
+ latexTrigger: ["\\mathtip"],
5581
+ parse: (parser) => {
5582
+ const op1 = parser.parseGroup();
5583
+ parser.parseGroup();
5584
+ return op1;
5613
5585
  }
5614
5586
  },
5615
5587
  {
5616
- name: "InverseFunction",
5617
- latexTrigger: "^{-1",
5618
- // Note: the closing brace is not included
5619
- kind: "postfix",
5620
- parse: (parser, lhs) => {
5621
- if (operator(lhs) === "Matrix") {
5622
- parser.match("<}>");
5623
- return ["Inverse", lhs];
5624
- }
5625
- const sym2 = symbol(lhs);
5626
- if (!sym2) return null;
5627
- const symType = parser.getSymbolType(sym2);
5628
- if (symType.matches(new BoxedType("matrix"))) {
5629
- parser.match("<}>");
5630
- return ["Inverse", lhs];
5631
- }
5632
- if (!symType.matches("function")) return null;
5633
- let primeCount = 0;
5634
- while (!parser.atEnd && !parser.match("<}>")) {
5635
- if (parser.match("'")) primeCount++;
5636
- else if (parser.match("\\prime")) primeCount++;
5637
- else if (parser.match("\\doubleprime")) primeCount += 2;
5638
- else if (parser.match("\\tripleprime")) primeCount += 3;
5639
- else return null;
5640
- }
5641
- if (primeCount === 1)
5642
- return ["Derivative", ["InverseFunction", lhs]];
5643
- if (primeCount > 0)
5644
- return [
5645
- "Derivative",
5646
- ["InverseFunction", lhs],
5647
- primeCount
5648
- ];
5649
- return ["InverseFunction", lhs];
5650
- },
5651
- serialize: (serializer, expr) => serializer.serialize(operand(expr, 1)) + "^{-1}"
5588
+ latexTrigger: ["\\texttip"],
5589
+ parse: (parser) => {
5590
+ const op1 = parser.parseGroup();
5591
+ parser.parseGroup();
5592
+ return op1;
5593
+ }
5652
5594
  },
5653
- // Lagrange notation
5654
5595
  {
5655
- name: "Derivative",
5656
- // @todo: Leibniz notation: {% latex " \\frac{d^n}{dx^n} f(x)" %}
5657
- // @todo: Euler modified notation: This notation is used by Mathematica. The Euler notation uses `D` instead of
5658
- // `\partial`: `\partial_{x} f`, `\partial_{x,y} f`
5659
- // Newton notation (\dot{v}, \ddot{v}) is implemented below
5660
- serialize: (serializer, expr) => {
5661
- const degree = machineValue(operand(expr, 2)) ?? 1;
5662
- const base = serializer.serialize(operand(expr, 1));
5663
- if (degree === 1) return base + "^{\\prime}";
5664
- if (degree === 2) return base + "^{\\doubleprime}";
5665
- if (degree === 3) return base + "^{\\tripleprime}";
5666
- return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
5667
- }
5596
+ latexTrigger: ["\\error"],
5597
+ parse: (parser) => ["Error", parser.parseGroup()]
5668
5598
  },
5669
- // Serializer for D (partial derivative) - outputs Leibniz notation
5670
5599
  {
5671
- name: "D",
5600
+ name: "Error",
5672
5601
  serialize: (serializer, expr) => {
5673
- if (operator(expr) !== "D") return "D";
5674
- const fn = operand(expr, 1);
5675
- const variable = operand(expr, 2);
5676
- if (!fn || !variable) return "D";
5677
- let order2 = 1;
5678
- let innerFn = fn;
5679
- while (operator(innerFn) === "D") {
5680
- const innerVar = operand(innerFn, 2);
5681
- if (symbol(innerVar) === symbol(variable)) {
5682
- order2++;
5683
- innerFn = operand(innerFn, 1);
5684
- } else {
5685
- break;
5602
+ const op1 = operand(expr, 1);
5603
+ if (stringValue(op1) === "missing")
5604
+ return `\\error{${serializer.options.missingSymbol ?? "\\placeholder{}"}}`;
5605
+ const where = errorContextAsLatex(serializer, expr) || "\\blacksquare";
5606
+ const code = operator(op1) === "ErrorCode" ? stringValue(operand(op1, 1)) : stringValue(op1);
5607
+ if (code === "incompatible-type") {
5608
+ if (symbol(operand(op1, 3)) === "Undefined") {
5609
+ return `\\mathtip{\\error{${where}}}{\\notin ${serializer.serialize(
5610
+ operand(op1, 2)
5611
+ )}}`;
5686
5612
  }
5613
+ return `\\mathtip{\\error{${where}}}{\\in ${serializer.serialize(
5614
+ operand(op1, 3)
5615
+ )}\\notin ${serializer.serialize(operand(op1, 2))}}`;
5687
5616
  }
5688
- let bodyToSerialize = innerFn;
5689
- if (operator(innerFn) === "Function") {
5690
- bodyToSerialize = operand(innerFn, 1) ?? innerFn;
5691
- }
5692
- const fnLatex = serializer.serialize(bodyToSerialize);
5693
- const varLatex = serializer.serialize(variable);
5694
- if (order2 === 1) {
5695
- return `\\frac{\\mathrm{d}}{\\mathrm{d}${varLatex}}${fnLatex}`;
5696
- }
5697
- return `\\frac{\\mathrm{d}^{${order2}}}{\\mathrm{d}${varLatex}^{${order2}}}${fnLatex}`;
5617
+ if (typeof code === "string") return `\\error{${where}}`;
5618
+ return `\\error{${where}}`;
5698
5619
  }
5699
5620
  },
5700
- // Newton notation for time derivatives: \dot{x}, \ddot{x}, etc.
5701
5621
  {
5702
- name: "NewtonDerivative1",
5703
- latexTrigger: ["\\dot"],
5704
- kind: "prefix",
5705
- precedence: 740,
5706
- parse: (parser) => {
5707
- const body = parser.parseGroup();
5708
- if (body === null) return null;
5709
- const t = parser.options.timeDerivativeVariable;
5710
- return ["D", body, t];
5622
+ name: "ErrorCode",
5623
+ serialize: (serializer, expr) => {
5624
+ const code = stringValue(operand(expr, 1));
5625
+ if (code === "missing")
5626
+ return serializer.options.missingSymbol ?? "\\placeholder{}";
5627
+ if (code === "unexpected-command" || code === "unexpected-operator" || code === "unexpected-token" || code === "invalid-symbol" || code === "unknown-environment" || code === "unexpected-base" || code === "incompatible-type") {
5628
+ return "";
5629
+ }
5630
+ return `\\texttip{\\error{\\blacksquare}}{\\mathtt{${code}}}`;
5711
5631
  }
5712
5632
  },
5713
5633
  {
5714
- name: "NewtonDerivative2",
5715
- latexTrigger: ["\\ddot"],
5716
- kind: "prefix",
5717
- precedence: 740,
5718
- parse: (parser) => {
5719
- const body = parser.parseGroup();
5720
- if (body === null) return null;
5721
- const t = parser.options.timeDerivativeVariable;
5722
- return ["D", ["D", body, t], t];
5634
+ name: "FromLatex",
5635
+ serialize: (_serializer, expr) => {
5636
+ return `\\texttt{${sanitizeLatex(stringValue(operand(expr, 1)))}}`;
5723
5637
  }
5724
5638
  },
5725
5639
  {
5726
- name: "NewtonDerivative3",
5727
- latexTrigger: ["\\dddot"],
5728
- kind: "prefix",
5729
- precedence: 740,
5730
- parse: (parser) => {
5731
- const body = parser.parseGroup();
5732
- if (body === null) return null;
5733
- const t = parser.options.timeDerivativeVariable;
5734
- return ["D", ["D", ["D", body, t], t], t];
5640
+ name: "Latex",
5641
+ serialize: (serializer, expr) => {
5642
+ if (expr === null) return "";
5643
+ return joinLatex(
5644
+ mapArgs(expr, (x) => stringValue(x) ?? serializer.serialize(x))
5645
+ );
5735
5646
  }
5736
5647
  },
5737
5648
  {
5738
- name: "NewtonDerivative4",
5739
- latexTrigger: ["\\ddddot"],
5740
- kind: "prefix",
5741
- precedence: 740,
5742
- parse: (parser) => {
5743
- const body = parser.parseGroup();
5744
- if (body === null) return null;
5745
- const t = parser.options.timeDerivativeVariable;
5746
- return ["D", ["D", ["D", ["D", body, t], t], t], t];
5649
+ name: "LatexString",
5650
+ serialize: (serializer, expr) => {
5651
+ if (expr === null) return "";
5652
+ return joinLatex(mapArgs(expr, (x) => serializer.serialize(x)));
5747
5653
  }
5748
5654
  },
5749
- // Euler notation for derivatives: D_x f, D^2_x f, D_x^2 f
5750
- // Uses latexTrigger to intercept before symbol parsing combines D with subscript
5655
+ { name: "LatexTokens", serialize: serializeLatexTokens },
5751
5656
  {
5752
- name: "EulerDerivative",
5753
- latexTrigger: ["D"],
5754
- kind: "expression",
5755
- parse: (parser) => {
5756
- let degree = 1;
5757
- let variable = null;
5758
- let done = false;
5759
- while (!done) {
5760
- if (parser.match("_")) {
5761
- variable = parser.parseGroup() ?? parser.parseToken();
5762
- if (!variable) return null;
5763
- } else if (parser.match("^")) {
5764
- const degExpr = parser.parseGroup() ?? parser.parseToken();
5765
- degree = machineValue(degExpr) ?? 1;
5766
- } else {
5767
- done = true;
5768
- }
5769
- }
5770
- if (!variable) return null;
5771
- parser.skipSpace();
5772
- const fn = parser.parseExpression({ minPrec: 740 });
5773
- if (!fn) return null;
5774
- let result = fn;
5775
- for (let i = 0; i < degree; i++) {
5776
- result = ["D", result, variable];
5657
+ name: "At",
5658
+ kind: "postfix",
5659
+ precedence: 810,
5660
+ latexTrigger: ["["],
5661
+ parse: parseAt("]"),
5662
+ serialize: (serializer, expr) => joinLatex(["\\lbrack", serializeOps(", ")(serializer, expr), "\\rbrack"])
5663
+ },
5664
+ {
5665
+ kind: "postfix",
5666
+ precedence: 810,
5667
+ latexTrigger: ["\\lbrack"],
5668
+ parse: parseAt("\\rbrack")
5669
+ },
5670
+ {
5671
+ kind: "postfix",
5672
+ precedence: 810,
5673
+ latexTrigger: ["\\left", "\\lbrack"],
5674
+ parse: parseAt("\\right", "\\rbrack")
5675
+ },
5676
+ {
5677
+ kind: "postfix",
5678
+ latexTrigger: ["_"],
5679
+ parse: (parser, lhs, _until) => {
5680
+ let rhs = parser.parseGroup() ?? parser.parseToken();
5681
+ if (rhs === null && parser.options.strict === false && parser.peek === "(")
5682
+ rhs = parser.parseEnclosure();
5683
+ const sym2 = symbol(lhs);
5684
+ if (rhs !== null && (sym2 && parser.getSymbolType(sym2).matches("indexed_collection") || operator(lhs) === "List")) {
5685
+ if (operator(rhs) === "Delimiter") rhs = operand(rhs, 1) ?? "Nothing";
5686
+ if (operator(rhs) === "Sequence") return ["At", lhs, ...operands(rhs)];
5687
+ return ["At", lhs, rhs];
5777
5688
  }
5778
- return result;
5689
+ return ["Subscript", lhs, rhs];
5779
5690
  }
5780
5691
  },
5781
5692
  {
5782
- kind: "environment",
5783
- name: "Which",
5784
- symbolTrigger: "cases",
5785
- parse: parseCasesEnvironment,
5786
- serialize: (serialize, expr) => {
5787
- const rows = [];
5693
+ name: "List",
5694
+ kind: "matchfix",
5695
+ openTrigger: "[",
5696
+ closeTrigger: "]",
5697
+ parse: parseBrackets,
5698
+ serialize: serializeList
5699
+ },
5700
+ {
5701
+ kind: "matchfix",
5702
+ openTrigger: "(",
5703
+ closeTrigger: ")",
5704
+ parse: parseParenDelimiter
5705
+ },
5706
+ {
5707
+ latexTrigger: [","],
5708
+ kind: "infix",
5709
+ precedence: 20,
5710
+ // Unlike the matchfix version of List,
5711
+ // when the comma operator is used, the lhs and rhs are flattened,
5712
+ // i.e. `1,2,3` -> `["Delimiter", ["List", 1, 2, 3], ","]`,
5713
+ // and `1, (2, 3)` -> `["Delimiter",
5714
+ // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "()", ","]]],
5715
+ parse: (parser, lhs, terminator) => {
5716
+ const seq = parseSequence(parser, terminator, lhs, 20, ",");
5717
+ if (seq === null) return null;
5718
+ return ["Delimiter", ["Sequence", ...seq], { str: "," }];
5719
+ }
5720
+ },
5721
+ // Entry to handle the case of a single comma
5722
+ // with a missing lhs.
5723
+ {
5724
+ latexTrigger: [","],
5725
+ kind: "prefix",
5726
+ precedence: 20,
5727
+ parse: (parser, terminator) => {
5728
+ const seq = parseSequence(parser, terminator, null, 20, ",");
5729
+ if (seq === null) return null;
5730
+ return ["Delimiter", ["Sequence", ...seq], { str: "," }];
5731
+ }
5732
+ },
5733
+ {
5734
+ name: "Range",
5735
+ latexTrigger: [".", "."],
5736
+ kind: "infix",
5737
+ // associativity: 'left',
5738
+ precedence: 800,
5739
+ parse: parseRange,
5740
+ serialize: (serializer, expr) => {
5788
5741
  const args = operands(expr);
5789
- if (args.length > 0) {
5790
- for (let i = 0; i <= args.length - 2; i += 2) {
5791
- const row = [];
5792
- row.push(serialize.serialize(args[i + 1]));
5793
- row.push(serialize.serialize(args[i]));
5794
- rows.push(row.join("&"));
5742
+ if (args.length === 0) return "";
5743
+ if (args.length === 1)
5744
+ return "1.." + serializer.serialize(operand(expr, 1));
5745
+ if (args.length === 2)
5746
+ return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(operand(expr, 2), 10);
5747
+ if (args.length === 3) {
5748
+ const step = machineValue(operand(expr, 3));
5749
+ const start = machineValue(operand(expr, 1));
5750
+ if (step !== null && start !== null) {
5751
+ return serializer.wrap(operand(expr, 1), 10) + ".." + serializer.wrap(start + step, 10) + ".." + serializer.wrap(operand(expr, 2), 10);
5795
5752
  }
5753
+ 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);
5796
5754
  }
5797
- return joinLatex(["\\begin{cases}", rows.join("\\\\"), "\\end{cases}"]);
5755
+ return "";
5798
5756
  }
5799
5757
  },
5800
5758
  {
5801
- kind: "environment",
5802
- symbolTrigger: "dcases",
5803
- parse: parseCasesEnvironment
5759
+ latexTrigger: [";"],
5760
+ kind: "infix",
5761
+ precedence: 19,
5762
+ parse: (parser, lhs, terminator) => {
5763
+ const seq = parseSequence(parser, terminator, lhs, 19, ";");
5764
+ if (seq === null) return null;
5765
+ if (seq.some((e) => operator(e) === "Assign"))
5766
+ return buildBlockFromSequence(seq);
5767
+ return ["Delimiter", ["Sequence", ...seq], "';'"];
5768
+ }
5804
5769
  },
5770
+ // \text{where} — variable binding infix
5805
5771
  {
5806
- kind: "environment",
5807
- symbolTrigger: "rcases",
5808
- parse: parseCasesEnvironment
5809
- }
5810
- ];
5811
- function parseTextRun(parser, style) {
5812
- if (!parser.match("<{>")) return "''";
5813
- const runs = [];
5814
- let text = "";
5815
- let runinStyle = null;
5816
- const flush = () => {
5817
- if (runinStyle !== null && text) {
5818
- runs.push(["Annotated", `'${text}'`, dictionaryFromEntries(runinStyle)]);
5819
- } else if (text) {
5820
- runs.push(`'${text}'`);
5772
+ latexTrigger: ["\\text"],
5773
+ kind: "infix",
5774
+ associativity: "none",
5775
+ precedence: 21,
5776
+ // Above ; (19) and , (20), very low binding
5777
+ parse: (parser, lhs, until) => {
5778
+ const start = parser.index;
5779
+ if (!matchTextKeyword(parser, "where")) {
5780
+ parser.index = start;
5781
+ return null;
5782
+ }
5783
+ return parseWhereExpression(parser, lhs, until);
5821
5784
  }
5822
- text = "";
5823
- runinStyle = null;
5824
- };
5825
- while (!parser.atEnd && !parser.match("<}>")) {
5826
- if (parser.peek === "<{>") {
5827
- flush();
5828
- runs.push(parseTextRun(parser));
5829
- } else if (parser.match("\\textbf")) {
5830
- flush();
5831
- runs.push(parseTextRun(parser, { fontWeight: "bold" }));
5832
- } else if (parser.match("\\textmd")) {
5833
- flush();
5834
- runs.push(parseTextRun(parser, { fontStyle: "normal" }));
5835
- } else if (parser.match("\\textup")) {
5836
- flush();
5837
- runs.push(parseTextRun(parser, { fontStyle: "normal" }));
5838
- } else if (parser.match("\\textsl")) {
5839
- flush();
5840
- runs.push(parseTextRun(parser, { fontStyle: "italic" }));
5841
- } else if (parser.match("\\textit")) {
5842
- flush();
5843
- runs.push(parseTextRun(parser, { fontStyle: "italic" }));
5844
- } else if (parser.match("\\texttt")) {
5845
- flush();
5846
- runs.push(parseTextRun(parser, { fontFamily: "monospace" }));
5847
- } else if (parser.match("\\textsf")) {
5848
- flush();
5849
- runs.push(parseTextRun(parser, { fontFamily: "sans-serif" }));
5850
- } else if (parser.match("\\textcolor")) {
5851
- const pos = parser.index;
5852
- const color = parser.parseStringGroup();
5853
- const body2 = parser.parseExpression();
5854
- if (color !== null && body2 !== null) {
5855
- runs.push(["Annotated", body2, { dict: { color } }]);
5856
- } else {
5857
- parser.index = pos;
5858
- text += "\\textcolor";
5785
+ },
5786
+ // \operatorname{where}
5787
+ {
5788
+ symbolTrigger: "where",
5789
+ kind: "infix",
5790
+ associativity: "none",
5791
+ precedence: 21,
5792
+ parse: (parser, lhs, until) => parseWhereExpression(parser, lhs, until)
5793
+ },
5794
+ // \text{and} logical conjunction infix
5795
+ {
5796
+ latexTrigger: ["\\text"],
5797
+ kind: "infix",
5798
+ associativity: "right",
5799
+ precedence: 235,
5800
+ // Same as \land
5801
+ parse: (parser, lhs, until) => {
5802
+ const start = parser.index;
5803
+ if (!matchTextKeyword(parser, "and")) {
5804
+ parser.index = start;
5805
+ return null;
5859
5806
  }
5860
- } else if (parser.match("\\color")) {
5861
- const color = parser.parseStringGroup();
5862
- if (color !== null) {
5863
- flush();
5807
+ const rhs = parser.parseExpression({ ...until, minPrec: 235 });
5808
+ return ["And", lhs, rhs ?? "Nothing"];
5809
+ }
5810
+ },
5811
+ // \text{or} — logical disjunction infix
5812
+ {
5813
+ latexTrigger: ["\\text"],
5814
+ kind: "infix",
5815
+ associativity: "right",
5816
+ precedence: 230,
5817
+ // Same as \lor
5818
+ parse: (parser, lhs, until) => {
5819
+ const start = parser.index;
5820
+ if (!matchTextKeyword(parser, "or")) {
5821
+ parser.index = start;
5822
+ return null;
5823
+ }
5824
+ const rhs = parser.parseExpression({ ...until, minPrec: 230 });
5825
+ return ["Or", lhs, rhs ?? "Nothing"];
5826
+ }
5827
+ },
5828
+ // \text{iff} — biconditional (if and only if)
5829
+ {
5830
+ latexTrigger: ["\\text"],
5831
+ kind: "infix",
5832
+ associativity: "right",
5833
+ precedence: 219,
5834
+ // Same as \iff
5835
+ parse: (parser, lhs, until) => {
5836
+ const start = parser.index;
5837
+ if (!matchTextKeyword(parser, "iff")) {
5838
+ parser.index = start;
5839
+ return null;
5840
+ }
5841
+ const rhs = parser.parseExpression({ ...until, minPrec: 219 });
5842
+ return ["Equivalent", lhs, rhs ?? "Nothing"];
5843
+ }
5844
+ },
5845
+ // \text{if and only if} — verbose biconditional
5846
+ {
5847
+ latexTrigger: ["\\text"],
5848
+ kind: "infix",
5849
+ associativity: "right",
5850
+ precedence: 219,
5851
+ parse: (parser, lhs, until) => {
5852
+ const start = parser.index;
5853
+ if (!matchTextKeyword(parser, "if and only if")) {
5854
+ parser.index = start;
5855
+ return null;
5856
+ }
5857
+ const rhs = parser.parseExpression({ ...until, minPrec: 219 });
5858
+ return ["Equivalent", lhs, rhs ?? "Nothing"];
5859
+ }
5860
+ },
5861
+ // \text{such that} — constraint separator (like : in set-builder notation)
5862
+ {
5863
+ latexTrigger: ["\\text"],
5864
+ kind: "infix",
5865
+ associativity: "right",
5866
+ precedence: 21,
5867
+ // Low precedence to capture full condition (same as 'where')
5868
+ parse: (parser, lhs, until) => {
5869
+ const start = parser.index;
5870
+ if (!matchTextKeyword(parser, "such that")) {
5871
+ parser.index = start;
5872
+ return null;
5873
+ }
5874
+ const rhs = parser.parseExpression({ ...until, minPrec: 21 });
5875
+ return ["Colon", lhs, rhs ?? "Nothing"];
5876
+ }
5877
+ },
5878
+ // \text{for all} — universal quantifier
5879
+ {
5880
+ latexTrigger: ["\\text"],
5881
+ kind: "prefix",
5882
+ precedence: 200,
5883
+ // Same as \forall
5884
+ parse: (parser, until) => {
5885
+ const start = parser.index;
5886
+ if (!matchTextKeyword(parser, "for all")) {
5887
+ parser.index = start;
5888
+ return null;
5889
+ }
5890
+ return parseQuantifier("ForAll")(parser, until);
5891
+ }
5892
+ },
5893
+ // \text{there exists} — existential quantifier
5894
+ {
5895
+ latexTrigger: ["\\text"],
5896
+ kind: "prefix",
5897
+ precedence: 200,
5898
+ // Same as \exists
5899
+ parse: (parser, until) => {
5900
+ const start = parser.index;
5901
+ if (!matchTextKeyword(parser, "there exists")) {
5902
+ parser.index = start;
5903
+ return null;
5904
+ }
5905
+ return parseQuantifier("Exists")(parser, until);
5906
+ }
5907
+ },
5908
+ // Block serializer — used by both `where` and semicolon blocks
5909
+ {
5910
+ name: "Block",
5911
+ serialize: (serializer, expr) => {
5912
+ const args = operands(expr);
5913
+ if (!args || args.length === 0) return "";
5914
+ const parts = args.filter((a) => operator(a) !== "Declare").map((a) => serializer.serialize(a));
5915
+ return parts.join("; ");
5916
+ }
5917
+ },
5918
+ // Serializer for If expressions (separate from the parser entry
5919
+ // because name-based entries affect kind-based indexing)
5920
+ {
5921
+ name: "If",
5922
+ serialize: (serializer, expr) => {
5923
+ const args = operands(expr);
5924
+ if (!args || args.length < 3) return "";
5925
+ return joinLatex([
5926
+ "\\text{if }",
5927
+ serializer.serialize(args[0]),
5928
+ "\\text{ then }",
5929
+ serializer.serialize(args[1]),
5930
+ "\\text{ else }",
5931
+ serializer.serialize(args[2])
5932
+ ]);
5933
+ }
5934
+ },
5935
+ // Serializer for Loop expressions
5936
+ {
5937
+ name: "Loop",
5938
+ serialize: (serializer, expr) => {
5939
+ const args = operands(expr);
5940
+ if (!args || args.length < 2) return "";
5941
+ const body = args[0];
5942
+ const indexing = args[1];
5943
+ if (operator(indexing) === "Element") {
5944
+ const index = operand(indexing, 1);
5945
+ const range2 = operand(indexing, 2);
5946
+ if (operator(range2) === "Range") {
5947
+ const lo = operand(range2, 1);
5948
+ const hi = operand(range2, 2);
5949
+ return joinLatex([
5950
+ "\\text{for }",
5951
+ serializer.serialize(index),
5952
+ "\\text{ from }",
5953
+ serializer.serialize(lo),
5954
+ "\\text{ to }",
5955
+ serializer.serialize(hi),
5956
+ "\\text{ do }",
5957
+ serializer.serialize(body)
5958
+ ]);
5959
+ }
5960
+ }
5961
+ return joinLatex([
5962
+ "\\operatorname{Loop}(",
5963
+ serializer.serialize(body),
5964
+ ", ",
5965
+ serializer.serialize(indexing),
5966
+ ")"
5967
+ ]);
5968
+ }
5969
+ },
5970
+ // Serializer for Break
5971
+ { name: "Break", serialize: () => "\\text{break}" },
5972
+ // Serializer for Continue
5973
+ { name: "Continue", serialize: () => "\\text{continue}" },
5974
+ // Serializer for Return
5975
+ {
5976
+ name: "Return",
5977
+ serialize: (serializer, expr) => {
5978
+ const arg = operand(expr, 1);
5979
+ if (!arg || symbol(arg) === "Nothing") return "\\text{return}";
5980
+ return joinLatex(["\\text{return }", serializer.serialize(arg)]);
5981
+ }
5982
+ },
5983
+ // Also match `\operatorname{if}` / `\mathrm{if}`
5984
+ {
5985
+ symbolTrigger: "if",
5986
+ kind: "prefix",
5987
+ precedence: 245,
5988
+ parse: (parser, until) => {
5989
+ return parseIfExpression(parser, until);
5990
+ }
5991
+ },
5992
+ // \operatorname{for}
5993
+ {
5994
+ symbolTrigger: "for",
5995
+ kind: "prefix",
5996
+ precedence: 245,
5997
+ parse: (parser, until) => parseForExpression(parser, until)
5998
+ },
5999
+ // \operatorname{break}
6000
+ {
6001
+ symbolTrigger: "break",
6002
+ kind: "prefix",
6003
+ precedence: 245,
6004
+ parse: () => ["Break"]
6005
+ },
6006
+ // \operatorname{continue}
6007
+ {
6008
+ symbolTrigger: "continue",
6009
+ kind: "prefix",
6010
+ precedence: 245,
6011
+ parse: () => ["Continue"]
6012
+ },
6013
+ // \operatorname{return}
6014
+ {
6015
+ symbolTrigger: "return",
6016
+ kind: "prefix",
6017
+ precedence: 245,
6018
+ parse: (parser, until) => [
6019
+ "Return",
6020
+ parser.parseExpression(until) ?? "Nothing"
6021
+ ]
6022
+ },
6023
+ // Text serializer — reconstructs \text{...} with inline $...$ for math
6024
+ {
6025
+ name: "Text",
6026
+ serialize: (serializer, expr) => {
6027
+ const args = operands(expr);
6028
+ if (args.length === 0) return "";
6029
+ let firstStr = -1;
6030
+ let lastStr = -1;
6031
+ for (let i = 0; i < args.length; i++) {
6032
+ if (stringValue(args[i]) !== null) {
6033
+ if (firstStr < 0) firstStr = i;
6034
+ lastStr = i;
6035
+ }
6036
+ }
6037
+ if (firstStr < 0)
6038
+ return joinLatex(args.map((a) => serializer.serialize(a)));
6039
+ const parts = [];
6040
+ for (let i = 0; i < firstStr; i++)
6041
+ parts.push(serializer.serialize(args[i]));
6042
+ let textContent = "";
6043
+ for (let i = firstStr; i <= lastStr; i++) {
6044
+ const s = stringValue(args[i]);
6045
+ if (s !== null) textContent += sanitizeLatex(s);
6046
+ else if (operator(args[i]) === "Annotated" || operator(args[i]) === "Text")
6047
+ textContent += serializer.serialize(args[i]);
6048
+ else textContent += "$" + serializer.serialize(args[i]) + "$";
6049
+ }
6050
+ parts.push("\\text{" + textContent + "}");
6051
+ for (let i = lastStr + 1; i < args.length; i++)
6052
+ parts.push(serializer.serialize(args[i]));
6053
+ return joinLatex(parts);
6054
+ }
6055
+ },
6056
+ {
6057
+ name: "String",
6058
+ latexTrigger: ["\\text"],
6059
+ parse: (parser, until) => {
6060
+ const start = parser.index;
6061
+ if (matchTextKeyword(parser, "if"))
6062
+ return parseIfExpression(parser, until);
6063
+ parser.index = start;
6064
+ if (matchTextKeyword(parser, "for"))
6065
+ return parseForExpression(parser, until);
6066
+ parser.index = start;
6067
+ if (matchTextKeyword(parser, "break"))
6068
+ return ["Break"];
6069
+ parser.index = start;
6070
+ if (matchTextKeyword(parser, "continue"))
6071
+ return ["Continue"];
6072
+ parser.index = start;
6073
+ if (matchTextKeyword(parser, "return"))
6074
+ return [
6075
+ "Return",
6076
+ parser.parseExpression(until) ?? "Nothing"
6077
+ ];
6078
+ parser.index = start;
6079
+ return parseTextRun(parser);
6080
+ },
6081
+ serialize: (serializer, expr) => {
6082
+ const args = operands(expr);
6083
+ if (args.length === 0) return "\\text{}";
6084
+ return joinLatex([
6085
+ "\\text{",
6086
+ args.map((x) => serializer.serialize(x)).join(""),
6087
+ "}"
6088
+ ]);
6089
+ }
6090
+ },
6091
+ {
6092
+ name: "Subscript",
6093
+ latexTrigger: ["_"],
6094
+ kind: "infix",
6095
+ serialize: (serializer, expr) => {
6096
+ if (nops(expr) === 2) {
6097
+ return serializer.serialize(operand(expr, 1)) + "_{" + serializer.serialize(operand(expr, 2)) + "}";
6098
+ }
6099
+ return "_{" + serializer.serialize(operand(expr, 1)) + "}";
6100
+ }
6101
+ },
6102
+ { name: "Superplus", latexTrigger: ["^", "+"], kind: "postfix" },
6103
+ { name: "Subplus", latexTrigger: ["_", "+"], kind: "postfix" },
6104
+ {
6105
+ name: "Superminus",
6106
+ latexTrigger: ["^", "-"],
6107
+ kind: "postfix",
6108
+ parse: (parser, lhs) => {
6109
+ if (parser.options.strict === false && /^[0-9]$/.test(parser.peek))
6110
+ return null;
6111
+ return ["Superminus", lhs];
6112
+ }
6113
+ },
6114
+ { name: "Subminus", latexTrigger: ["_", "-"], kind: "postfix" },
6115
+ {
6116
+ latexTrigger: ["^", "*"],
6117
+ kind: "postfix",
6118
+ parse: (_parser, lhs) => ["Superstar", lhs]
6119
+ },
6120
+ // { name: 'Superstar', latexTrigger: ['^', '\\star'], kind: 'postfix' },
6121
+ {
6122
+ latexTrigger: ["_", "*"],
6123
+ kind: "postfix",
6124
+ parse: (_parser, lhs) => ["Substar", lhs]
6125
+ },
6126
+ { name: "Substar", latexTrigger: ["_", "\\star"], kind: "postfix" },
6127
+ { name: "Superdagger", latexTrigger: ["^", "\\dagger"], kind: "postfix" },
6128
+ {
6129
+ latexTrigger: ["^", "\\dag"],
6130
+ kind: "postfix",
6131
+ parse: (_parser, lhs) => ["Superdagger", lhs]
6132
+ },
6133
+ {
6134
+ name: "Prime",
6135
+ latexTrigger: ["^", "\\prime"],
6136
+ // Note: we don't need a precedence because the trigger is '^'
6137
+ // and '^' (and '_') are treated specially by the parser.
6138
+ kind: "postfix",
6139
+ parse: (parser, lhs) => parsePrime(parser, lhs, 1),
6140
+ serialize: (serializer, expr) => {
6141
+ const n2 = machineValue(operand(expr, 2)) ?? 1;
6142
+ const base = serializer.serialize(operand(expr, 1));
6143
+ if (n2 === 1) return base + "^\\prime";
6144
+ if (n2 === 2) return base + "^\\doubleprime";
6145
+ if (n2 === 3) return base + "^\\tripleprime";
6146
+ return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
6147
+ }
6148
+ },
6149
+ {
6150
+ latexTrigger: "^{\\prime\\prime}",
6151
+ kind: "postfix",
6152
+ parse: (parser, lhs) => parsePrime(parser, lhs, 2)
6153
+ },
6154
+ {
6155
+ latexTrigger: "^{\\prime\\prime\\prime}",
6156
+ kind: "postfix",
6157
+ parse: (parser, lhs) => parsePrime(parser, lhs, 3)
6158
+ },
6159
+ {
6160
+ latexTrigger: ["^", "\\doubleprime"],
6161
+ kind: "postfix",
6162
+ parse: (parser, lhs) => parsePrime(parser, lhs, 2)
6163
+ },
6164
+ {
6165
+ latexTrigger: ["^", "\\tripleprime"],
6166
+ kind: "postfix",
6167
+ parse: (parser, lhs) => parsePrime(parser, lhs, 3)
6168
+ },
6169
+ {
6170
+ latexTrigger: "'",
6171
+ kind: "postfix",
6172
+ precedence: 810,
6173
+ parse: (parser, lhs) => parsePrime(parser, lhs, 1)
6174
+ },
6175
+ {
6176
+ latexTrigger: "\\prime",
6177
+ kind: "postfix",
6178
+ precedence: 810,
6179
+ parse: (parser, lhs) => parsePrime(parser, lhs, 1)
6180
+ },
6181
+ {
6182
+ latexTrigger: "\\doubleprime",
6183
+ kind: "postfix",
6184
+ precedence: 810,
6185
+ parse: (parser, lhs) => parsePrime(parser, lhs, 2)
6186
+ },
6187
+ {
6188
+ latexTrigger: "\\tripleprime",
6189
+ kind: "postfix",
6190
+ precedence: 810,
6191
+ parse: (parser, lhs) => parsePrime(parser, lhs, 3)
6192
+ },
6193
+ // Lagrange Notation for n-th order derivatives,
6194
+ // i.e. f^{(n)} -> Derivative(f, n)
6195
+ {
6196
+ latexTrigger: ["^", "<{>", "("],
6197
+ kind: "postfix",
6198
+ parse: (parser, lhs, until) => {
6199
+ const sym2 = symbol(lhs);
6200
+ if (!sym2 || !parser.getSymbolType(sym2).matches("function")) return null;
6201
+ parser.addBoundary([")"]);
6202
+ const expr = parser.parseExpression(until);
6203
+ if (!parser.matchBoundary()) return null;
6204
+ if (!parser.match("<}>")) return null;
6205
+ return ["Derivative", lhs, expr];
6206
+ }
6207
+ },
6208
+ {
6209
+ name: "InverseFunction",
6210
+ latexTrigger: "^{-1",
6211
+ // Note: the closing brace is not included
6212
+ kind: "postfix",
6213
+ parse: (parser, lhs) => {
6214
+ if (operator(lhs) === "Matrix") {
6215
+ parser.match("<}>");
6216
+ return ["Inverse", lhs];
6217
+ }
6218
+ const sym2 = symbol(lhs);
6219
+ if (!sym2) return null;
6220
+ const symType = parser.getSymbolType(sym2);
6221
+ if (symType.matches(new BoxedType("matrix"))) {
6222
+ parser.match("<}>");
6223
+ return ["Inverse", lhs];
6224
+ }
6225
+ if (!symType.matches("function")) return null;
6226
+ let primeCount = 0;
6227
+ while (!parser.atEnd && !parser.match("<}>")) {
6228
+ if (parser.match("'")) primeCount++;
6229
+ else if (parser.match("\\prime")) primeCount++;
6230
+ else if (parser.match("\\doubleprime")) primeCount += 2;
6231
+ else if (parser.match("\\tripleprime")) primeCount += 3;
6232
+ else return null;
6233
+ }
6234
+ if (primeCount === 1)
6235
+ return ["Derivative", ["InverseFunction", lhs]];
6236
+ if (primeCount > 0)
6237
+ return [
6238
+ "Derivative",
6239
+ ["InverseFunction", lhs],
6240
+ primeCount
6241
+ ];
6242
+ return ["InverseFunction", lhs];
6243
+ },
6244
+ serialize: (serializer, expr) => serializer.serialize(operand(expr, 1)) + "^{-1}"
6245
+ },
6246
+ // Lagrange notation
6247
+ {
6248
+ name: "Derivative",
6249
+ // @todo: Leibniz notation: {% latex " \\frac{d^n}{dx^n} f(x)" %}
6250
+ // @todo: Euler modified notation: This notation is used by Mathematica. The Euler notation uses `D` instead of
6251
+ // `\partial`: `\partial_{x} f`, `\partial_{x,y} f`
6252
+ // Newton notation (\dot{v}, \ddot{v}) is implemented below
6253
+ serialize: (serializer, expr) => {
6254
+ const degree = machineValue(operand(expr, 2)) ?? 1;
6255
+ const base = serializer.serialize(operand(expr, 1));
6256
+ if (degree === 1) return base + "^{\\prime}";
6257
+ if (degree === 2) return base + "^{\\doubleprime}";
6258
+ if (degree === 3) return base + "^{\\tripleprime}";
6259
+ return base + "^{(" + serializer.serialize(operand(expr, 2)) + ")}";
6260
+ }
6261
+ },
6262
+ // Serializer for D (partial derivative) - outputs Leibniz notation
6263
+ {
6264
+ name: "D",
6265
+ serialize: (serializer, expr) => {
6266
+ if (operator(expr) !== "D") return "D";
6267
+ const fn = operand(expr, 1);
6268
+ const variable = operand(expr, 2);
6269
+ if (!fn || !variable) return "D";
6270
+ let order2 = 1;
6271
+ let innerFn = fn;
6272
+ while (operator(innerFn) === "D") {
6273
+ const innerVar = operand(innerFn, 2);
6274
+ if (symbol(innerVar) === symbol(variable)) {
6275
+ order2++;
6276
+ innerFn = operand(innerFn, 1);
6277
+ } else {
6278
+ break;
6279
+ }
6280
+ }
6281
+ let bodyToSerialize = innerFn;
6282
+ if (operator(innerFn) === "Function") {
6283
+ bodyToSerialize = operand(innerFn, 1) ?? innerFn;
6284
+ }
6285
+ const fnLatex = serializer.serialize(bodyToSerialize);
6286
+ const varLatex = serializer.serialize(variable);
6287
+ if (order2 === 1) {
6288
+ return `\\frac{\\mathrm{d}}{\\mathrm{d}${varLatex}}${fnLatex}`;
6289
+ }
6290
+ return `\\frac{\\mathrm{d}^{${order2}}}{\\mathrm{d}${varLatex}^{${order2}}}${fnLatex}`;
6291
+ }
6292
+ },
6293
+ // Newton notation for time derivatives: \dot{x}, \ddot{x}, etc.
6294
+ {
6295
+ name: "NewtonDerivative1",
6296
+ latexTrigger: ["\\dot"],
6297
+ kind: "prefix",
6298
+ precedence: 740,
6299
+ parse: (parser) => {
6300
+ const body = parser.parseGroup();
6301
+ if (body === null) return null;
6302
+ const t = parser.options.timeDerivativeVariable;
6303
+ return ["D", body, t];
6304
+ }
6305
+ },
6306
+ {
6307
+ name: "NewtonDerivative2",
6308
+ latexTrigger: ["\\ddot"],
6309
+ kind: "prefix",
6310
+ precedence: 740,
6311
+ parse: (parser) => {
6312
+ const body = parser.parseGroup();
6313
+ if (body === null) return null;
6314
+ const t = parser.options.timeDerivativeVariable;
6315
+ return ["D", ["D", body, t], t];
6316
+ }
6317
+ },
6318
+ {
6319
+ name: "NewtonDerivative3",
6320
+ latexTrigger: ["\\dddot"],
6321
+ kind: "prefix",
6322
+ precedence: 740,
6323
+ parse: (parser) => {
6324
+ const body = parser.parseGroup();
6325
+ if (body === null) return null;
6326
+ const t = parser.options.timeDerivativeVariable;
6327
+ return ["D", ["D", ["D", body, t], t], t];
6328
+ }
6329
+ },
6330
+ {
6331
+ name: "NewtonDerivative4",
6332
+ latexTrigger: ["\\ddddot"],
6333
+ kind: "prefix",
6334
+ precedence: 740,
6335
+ parse: (parser) => {
6336
+ const body = parser.parseGroup();
6337
+ if (body === null) return null;
6338
+ const t = parser.options.timeDerivativeVariable;
6339
+ return ["D", ["D", ["D", ["D", body, t], t], t], t];
6340
+ }
6341
+ },
6342
+ // Euler notation for derivatives: D_x f, D^2_x f, D_x^2 f
6343
+ // Uses latexTrigger to intercept before symbol parsing combines D with subscript
6344
+ {
6345
+ name: "EulerDerivative",
6346
+ latexTrigger: ["D"],
6347
+ kind: "expression",
6348
+ parse: (parser) => {
6349
+ let degree = 1;
6350
+ let variable = null;
6351
+ let done = false;
6352
+ while (!done) {
6353
+ if (parser.match("_")) {
6354
+ variable = parser.parseGroup() ?? parser.parseToken();
6355
+ if (!variable) return null;
6356
+ } else if (parser.match("^")) {
6357
+ const degExpr = parser.parseGroup() ?? parser.parseToken();
6358
+ degree = machineValue(degExpr) ?? 1;
6359
+ } else {
6360
+ done = true;
6361
+ }
6362
+ }
6363
+ if (!variable) return null;
6364
+ parser.skipSpace();
6365
+ const fn = parser.parseExpression({ minPrec: 740 });
6366
+ if (!fn) return null;
6367
+ let result = fn;
6368
+ for (let i = 0; i < degree; i++) {
6369
+ result = ["D", result, variable];
6370
+ }
6371
+ return result;
6372
+ }
6373
+ },
6374
+ {
6375
+ kind: "environment",
6376
+ name: "Which",
6377
+ symbolTrigger: "cases",
6378
+ parse: parseCasesEnvironment,
6379
+ serialize: (serialize, expr) => {
6380
+ const rows = [];
6381
+ const args = operands(expr);
6382
+ if (args.length > 0) {
6383
+ for (let i = 0; i <= args.length - 2; i += 2) {
6384
+ const row = [];
6385
+ row.push(serialize.serialize(args[i + 1]));
6386
+ row.push(serialize.serialize(args[i]));
6387
+ rows.push(row.join("&"));
6388
+ }
6389
+ }
6390
+ return joinLatex(["\\begin{cases}", rows.join("\\\\"), "\\end{cases}"]);
6391
+ }
6392
+ },
6393
+ {
6394
+ kind: "environment",
6395
+ symbolTrigger: "dcases",
6396
+ parse: parseCasesEnvironment
6397
+ },
6398
+ {
6399
+ kind: "environment",
6400
+ symbolTrigger: "rcases",
6401
+ parse: parseCasesEnvironment
6402
+ }
6403
+ ];
6404
+ function parseTextRun(parser, style) {
6405
+ if (!parser.match("<{>")) return "''";
6406
+ const runs = [];
6407
+ let text = "";
6408
+ let runinStyle = null;
6409
+ const flush = () => {
6410
+ if (runinStyle !== null && text) {
6411
+ runs.push(["Annotated", `'${text}'`, dictionaryFromEntries(runinStyle)]);
6412
+ } else if (text) {
6413
+ runs.push(`'${text}'`);
6414
+ }
6415
+ text = "";
6416
+ runinStyle = null;
6417
+ };
6418
+ while (!parser.atEnd && !parser.match("<}>")) {
6419
+ if (parser.peek === "<{>") {
6420
+ flush();
6421
+ runs.push(parseTextRun(parser));
6422
+ } else if (parser.match("\\textbf")) {
6423
+ flush();
6424
+ runs.push(parseTextRun(parser, { fontWeight: "bold" }));
6425
+ } else if (parser.match("\\textmd")) {
6426
+ flush();
6427
+ runs.push(parseTextRun(parser, { fontStyle: "normal" }));
6428
+ } else if (parser.match("\\textup")) {
6429
+ flush();
6430
+ runs.push(parseTextRun(parser, { fontStyle: "normal" }));
6431
+ } else if (parser.match("\\textsl")) {
6432
+ flush();
6433
+ runs.push(parseTextRun(parser, { fontStyle: "italic" }));
6434
+ } else if (parser.match("\\textit")) {
6435
+ flush();
6436
+ runs.push(parseTextRun(parser, { fontStyle: "italic" }));
6437
+ } else if (parser.match("\\texttt")) {
6438
+ flush();
6439
+ runs.push(parseTextRun(parser, { fontFamily: "monospace" }));
6440
+ } else if (parser.match("\\textsf")) {
6441
+ flush();
6442
+ runs.push(parseTextRun(parser, { fontFamily: "sans-serif" }));
6443
+ } else if (parser.match("\\textcolor")) {
6444
+ const pos = parser.index;
6445
+ const color = parser.parseStringGroup();
6446
+ if (color !== null) {
6447
+ flush();
6448
+ const body2 = parseTextRun(parser);
6449
+ runs.push(["Annotated", body2, dictionaryFromEntries({ color })]);
6450
+ } else {
6451
+ parser.index = pos;
6452
+ text += "\\textcolor";
6453
+ }
6454
+ } else if (parser.match("\\color")) {
6455
+ const color = parser.parseStringGroup();
6456
+ if (color !== null) {
6457
+ flush();
5864
6458
  runinStyle = { color };
5865
6459
  }
5866
6460
  } else if (parser.match("<space>")) {
@@ -5870,6 +6464,7 @@ function parseTextRun(parser, style) {
5870
6464
  const expr = parser.parseExpression() ?? "Nothing";
5871
6465
  parser.skipSpace();
5872
6466
  if (parser.match("<$>")) {
6467
+ flush();
5873
6468
  runs.push(expr);
5874
6469
  } else {
5875
6470
  text += "$";
@@ -5880,6 +6475,7 @@ function parseTextRun(parser, style) {
5880
6475
  const expr = parser.parseExpression() ?? "Nothing";
5881
6476
  parser.skipSpace();
5882
6477
  if (parser.match("<$$>")) {
6478
+ flush();
5883
6479
  runs.push(expr);
5884
6480
  } else {
5885
6481
  text += "$$";
@@ -6230,14 +6826,20 @@ function matchTextKeyword(parser, keyword) {
6230
6826
  }
6231
6827
  while (parser.match("<space>")) {
6232
6828
  }
6233
- let text = "";
6234
- while (!parser.atEnd && parser.peek !== "<}>" && parser.peek !== "<space>") {
6235
- const tok = parser.peek;
6236
- if (/^[a-zA-Z]$/.test(tok)) {
6237
- text += tok;
6238
- parser.nextToken();
6829
+ for (let i = 0; i < keyword.length; i++) {
6830
+ if (keyword[i] === " ") {
6831
+ if (!parser.match("<space>")) {
6832
+ parser.index = start;
6833
+ return false;
6834
+ }
6835
+ while (parser.match("<space>")) {
6836
+ }
6239
6837
  } else {
6240
- break;
6838
+ if (parser.peek !== keyword[i]) {
6839
+ parser.index = start;
6840
+ return false;
6841
+ }
6842
+ parser.nextToken();
6241
6843
  }
6242
6844
  }
6243
6845
  while (parser.match("<space>")) {
@@ -6246,10 +6848,6 @@ function matchTextKeyword(parser, keyword) {
6246
6848
  parser.index = start;
6247
6849
  return false;
6248
6850
  }
6249
- if (text !== keyword) {
6250
- parser.index = start;
6251
- return false;
6252
- }
6253
6851
  return true;
6254
6852
  }
6255
6853
  function matchKeyword(parser, keyword) {
@@ -6491,487 +7089,41 @@ var DEFINITIONS_SYMBOLS = [
6491
7089
  return {
6492
7090
  kind: "symbol",
6493
7091
  name: symbol2,
6494
- latexTrigger: [latex],
6495
- parse: symbol2
6496
- };
6497
- }),
6498
- ...SYMBOLS.map(([symbol2, _latex, codepoint]) => {
6499
- return {
6500
- kind: "symbol",
6501
- latexTrigger: [String.fromCodePoint(codepoint)],
6502
- parse: symbol2
6503
- };
6504
- })
6505
- ];
6506
-
6507
- // src/compute-engine/latex-syntax/dictionary/definitions-algebra.ts
6508
- var DEFINITIONS_ALGEBRA = [
6509
- {
6510
- name: "To",
6511
- latexTrigger: ["\\to"],
6512
- kind: "infix",
6513
- precedence: 270
6514
- // MathML rightwards arrow
6515
- },
6516
- {
6517
- // Non-strict mode: -> for maps-to arrow
6518
- latexTrigger: ["-", ">"],
6519
- kind: "infix",
6520
- precedence: 270,
6521
- parse: (parser, lhs, until) => {
6522
- if (parser.options.strict !== false) return null;
6523
- const rhs = parser.parseExpression({ ...until, minPrec: 270 });
6524
- if (rhs === null) return null;
6525
- return ["To", lhs, rhs];
6526
- }
6527
- }
6528
- ];
6529
-
6530
- // src/compute-engine/latex-syntax/dictionary/definitions-logic.ts
6531
- var DEFINITIONS_LOGIC = [
6532
- // Constants
6533
- {
6534
- name: "True",
6535
- kind: "symbol",
6536
- latexTrigger: ["\\top"]
6537
- // ⊤ U+22A4
6538
- },
6539
- {
6540
- kind: "symbol",
6541
- latexTrigger: "\\mathrm{True}",
6542
- parse: "True"
6543
- },
6544
- {
6545
- kind: "symbol",
6546
- latexTrigger: "\\operatorname{True}",
6547
- parse: "True"
6548
- },
6549
- {
6550
- kind: "symbol",
6551
- latexTrigger: "\\mathsf{T}",
6552
- parse: "True"
6553
- },
6554
- {
6555
- name: "False",
6556
- kind: "symbol",
6557
- latexTrigger: ["\\bot"]
6558
- // ⊥ U+22A5
6559
- },
6560
- {
6561
- kind: "symbol",
6562
- latexTrigger: "\\operatorname{False}",
6563
- parse: "False"
6564
- },
6565
- {
6566
- kind: "symbol",
6567
- latexTrigger: "\\mathsf{F}",
6568
- parse: "False"
6569
- },
6570
- // Operators
6571
- // Logic operators have lower precedence than comparisons (245)
6572
- // so that `x = 1 \lor x = 2` parses as `(x = 1) \lor (x = 2)`
6573
- // See https://github.com/cortex-js/compute-engine/issues/243
6574
- {
6575
- name: "And",
6576
- kind: "infix",
6577
- latexTrigger: ["\\land"],
6578
- precedence: 235
6579
- // serialize: '\\land',
6580
- },
6581
- { kind: "infix", latexTrigger: ["\\wedge"], parse: "And", precedence: 235 },
6582
- { kind: "infix", latexTrigger: "\\&", parse: "And", precedence: 235 },
6583
- {
6584
- kind: "infix",
6585
- latexTrigger: "\\operatorname{and}",
6586
- parse: "And",
6587
- precedence: 235
6588
- },
6589
- {
6590
- name: "Or",
6591
- kind: "infix",
6592
- latexTrigger: ["\\lor"],
6593
- precedence: 230
6594
- },
6595
- { kind: "infix", latexTrigger: ["\\vee"], parse: "Or", precedence: 230 },
6596
- { kind: "infix", latexTrigger: "\\parallel", parse: "Or", precedence: 230 },
6597
- {
6598
- kind: "infix",
6599
- latexTrigger: "\\operatorname{or}",
6600
- parse: "Or",
6601
- precedence: 230
6602
- },
6603
- {
6604
- name: "Xor",
6605
- kind: "infix",
6606
- latexTrigger: ["\\veebar"],
6607
- precedence: 232
6608
- },
6609
- // Possible alt: \oplus ⊕ U+2295
6610
- {
6611
- name: "Not",
6612
- kind: "prefix",
6613
- latexTrigger: ["\\lnot"],
6614
- precedence: 880
6615
- },
6616
- {
6617
- kind: "prefix",
6618
- latexTrigger: ["\\neg"],
6619
- parse: "Not",
6620
- precedence: 880
6621
- },
6622
- {
6623
- name: "Nand",
6624
- kind: "infix",
6625
- latexTrigger: ["\\barwedge"],
6626
- precedence: 232
6627
- // serialize: '\\mid',
6628
- },
6629
- {
6630
- name: "Nor",
6631
- kind: "infix",
6632
- latexTrigger: ["\u22BD"],
6633
- // bar vee
6634
- precedence: 232
6635
- // serialize: '\\downarrow',
6636
- },
6637
- // Functions
6638
- {
6639
- kind: "function",
6640
- symbolTrigger: "and",
6641
- parse: "And"
6642
- },
6643
- {
6644
- kind: "function",
6645
- symbolTrigger: "or",
6646
- parse: "Or"
6647
- },
6648
- {
6649
- kind: "function",
6650
- symbolTrigger: "not",
6651
- parse: "Not"
6652
- },
6653
- // Relations
6654
- {
6655
- name: "Implies",
6656
- kind: "infix",
6657
- precedence: 220,
6658
- associativity: "right",
6659
- latexTrigger: ["\\implies"],
6660
- serialize: "\\implies"
6661
- },
6662
- {
6663
- latexTrigger: ["\\Rightarrow"],
6664
- kind: "infix",
6665
- precedence: 220,
6666
- associativity: "right",
6667
- parse: "Implies"
6668
- },
6669
- {
6670
- latexTrigger: ["\\rightarrow"],
6671
- kind: "infix",
6672
- precedence: 220,
6673
- associativity: "right",
6674
- parse: "Implies"
6675
- },
6676
- {
6677
- latexTrigger: ["\\Longrightarrow"],
6678
- kind: "infix",
6679
- precedence: 220,
6680
- associativity: "right",
6681
- parse: "Implies"
6682
- },
6683
- {
6684
- latexTrigger: ["\\longrightarrow"],
6685
- kind: "infix",
6686
- precedence: 220,
6687
- associativity: "right",
6688
- parse: "Implies"
6689
- },
6690
- {
6691
- // Non-strict mode: => for implies
6692
- latexTrigger: ["=", ">"],
6693
- kind: "infix",
6694
- precedence: 220,
6695
- associativity: "right",
6696
- parse: (parser, lhs, until) => {
6697
- if (parser.options.strict !== false) return null;
6698
- const rhs = parser.parseExpression({ ...until, minPrec: 220 });
6699
- if (rhs === null) return null;
6700
- return ["Implies", lhs, rhs];
6701
- }
6702
- },
6703
- {
6704
- name: "Equivalent",
6705
- // MathML: identical to, Mathematica: Congruent
6706
- latexTrigger: ["\\iff"],
6707
- kind: "infix",
6708
- associativity: "right",
6709
- precedence: 219
6710
- },
6711
- {
6712
- latexTrigger: ["\\Leftrightarrow"],
6713
- kind: "infix",
6714
- associativity: "right",
6715
- precedence: 219,
6716
- parse: "Equivalent"
6717
- },
6718
- {
6719
- latexTrigger: ["\\leftrightarrow"],
6720
- kind: "infix",
6721
- associativity: "right",
6722
- precedence: 219,
6723
- parse: "Equivalent"
6724
- },
6725
- {
6726
- latexTrigger: ["\\Longleftrightarrow"],
6727
- kind: "infix",
6728
- associativity: "right",
6729
- precedence: 219,
6730
- parse: "Equivalent"
6731
- },
7092
+ latexTrigger: [latex],
7093
+ parse: symbol2
7094
+ };
7095
+ }),
7096
+ ...SYMBOLS.map(([symbol2, _latex, codepoint]) => {
7097
+ return {
7098
+ kind: "symbol",
7099
+ latexTrigger: [String.fromCodePoint(codepoint)],
7100
+ parse: symbol2
7101
+ };
7102
+ })
7103
+ ];
7104
+
7105
+ // src/compute-engine/latex-syntax/dictionary/definitions-algebra.ts
7106
+ var DEFINITIONS_ALGEBRA = [
6732
7107
  {
6733
- latexTrigger: ["\\longleftrightarrow"],
7108
+ name: "To",
7109
+ latexTrigger: ["\\to"],
6734
7110
  kind: "infix",
6735
- associativity: "right",
6736
- precedence: 219,
6737
- parse: "Equivalent"
7111
+ precedence: 270
7112
+ // MathML rightwards arrow
6738
7113
  },
6739
7114
  {
6740
- // Non-strict mode: <=> for equivalence
6741
- latexTrigger: ["<", "=", ">"],
7115
+ // Non-strict mode: -> for maps-to arrow
7116
+ latexTrigger: ["-", ">"],
6742
7117
  kind: "infix",
6743
- precedence: 219,
6744
- associativity: "right",
7118
+ precedence: 270,
6745
7119
  parse: (parser, lhs, until) => {
6746
7120
  if (parser.options.strict !== false) return null;
6747
- const rhs = parser.parseExpression({ ...until, minPrec: 219 });
7121
+ const rhs = parser.parseExpression({ ...until, minPrec: 270 });
6748
7122
  if (rhs === null) return null;
6749
- return ["Equivalent", lhs, rhs];
6750
- }
6751
- },
6752
- {
6753
- latexTrigger: ["\\equiv"],
6754
- kind: "infix",
6755
- associativity: "right",
6756
- precedence: 219,
6757
- parse: (parser, lhs, terminator) => {
6758
- const rhs = parser.parseExpression({ ...terminator, minPrec: 219 });
6759
- const index = parser.index;
6760
- const modulus = parser.parseExpression({ ...terminator, minPrec: 219 });
6761
- if (modulus !== null && operator(modulus) === "Mod")
6762
- return ["Congruent", lhs, rhs, missingIfEmpty(operand(modulus, 1))];
6763
- parser.index = index;
6764
- return ["Equivalent", lhs, missingIfEmpty(rhs)];
6765
- }
6766
- },
6767
- {
6768
- name: "Proves",
6769
- kind: "infix",
6770
- latexTrigger: ["\\vdash"],
6771
- precedence: 220,
6772
- associativity: "right",
6773
- serialize: "\\vdash"
6774
- },
6775
- {
6776
- name: "Entails",
6777
- kind: "infix",
6778
- latexTrigger: ["\\vDash"],
6779
- precedence: 220,
6780
- associativity: "right",
6781
- serialize: "\\vDash"
6782
- },
6783
- {
6784
- name: "Satisfies",
6785
- kind: "infix",
6786
- latexTrigger: ["\\models"],
6787
- precedence: 220,
6788
- associativity: "right",
6789
- serialize: "\\models"
6790
- },
6791
- // Quantifiers: for all, exists
6792
- {
6793
- name: "ForAll",
6794
- kind: "prefix",
6795
- latexTrigger: ["\\forall"],
6796
- precedence: 200,
6797
- // Has to be lower than COMPARISON_PRECEDENCE
6798
- serialize: serializeQuantifier("\\forall"),
6799
- parse: parseQuantifier("ForAll")
6800
- },
6801
- {
6802
- name: "Exists",
6803
- kind: "prefix",
6804
- latexTrigger: ["\\exists"],
6805
- precedence: 200,
6806
- // Has to be lower than COMPARISON_PRECEDENCE,
6807
- serialize: serializeQuantifier("\\exists"),
6808
- parse: parseQuantifier("Exists")
6809
- },
6810
- {
6811
- name: "ExistsUnique",
6812
- kind: "prefix",
6813
- latexTrigger: ["\\exists", "!"],
6814
- precedence: 200,
6815
- // Has to be lower than COMPARISON_PRECEDENCE,
6816
- serialize: serializeQuantifier("\\exists!"),
6817
- parse: parseQuantifier("ExistsUnique")
6818
- },
6819
- {
6820
- name: "NotForAll",
6821
- kind: "prefix",
6822
- latexTrigger: ["\\lnot", "\\forall"],
6823
- precedence: 200,
6824
- // Has to be lower than COMPARISON_PRECEDENCE
6825
- serialize: serializeQuantifier("\\lnot\\forall"),
6826
- parse: parseQuantifier("NotForAll")
6827
- },
6828
- {
6829
- name: "NotExists",
6830
- kind: "prefix",
6831
- latexTrigger: ["\\lnot", "\\exists"],
6832
- precedence: 200,
6833
- // Has to be lower than COMPARISON_PRECEDENCE,
6834
- serialize: serializeQuantifier("\\lnot\\exists"),
6835
- parse: parseQuantifier("NotExists")
6836
- },
6837
- {
6838
- name: "KroneckerDelta",
6839
- kind: "prefix",
6840
- latexTrigger: ["\\delta", "_"],
6841
- precedence: 200,
6842
- serialize: (serializer, expr) => {
6843
- const args = operands(expr);
6844
- if (args.length === 0) return "\\delta";
6845
- if (args.every((x) => symbol(x)))
6846
- return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join("")}}`;
6847
- return `\\delta_{${args.map((arg) => serializer.serialize(arg)).join(", ")}}`;
6848
- },
6849
- parse: (parser) => {
6850
- const group = parser.parseGroup();
6851
- if (group === null) {
6852
- const token = parser.parseToken();
6853
- if (!token) return null;
6854
- return ["KroneckerDelta", token];
6855
- }
6856
- const seq = getSequence(group);
6857
- if (seq && seq.length <= 2) return ["KroneckerDelta", ...seq];
6858
- if (operator(group) === "InvisibleOperator")
6859
- return ["KroneckerDelta", ...operands(group)];
6860
- if (group !== null) return ["KroneckerDelta", group];
6861
- return null;
6862
- }
6863
- },
6864
- // Iverson brackets. Also called the "indicator function"
6865
- // Must have a single argument, a relational expression, i.e.
6866
- // `[ a = b ]` or `[ x \leq 0 ]`
6867
- // Otherwise, it gets rejected, it could be something else, like a list or
6868
- // tuple.
6869
- {
6870
- name: "Boole",
6871
- kind: "matchfix",
6872
- openTrigger: "[",
6873
- closeTrigger: "]",
6874
- // serialize: (serializer: Serializer, expr: MathJsonExpression) => {
6875
- // const args = ops(expr);
6876
- // return `[${serializer.serialize(arg)}]`;
6877
- // },
6878
- parse: (_parser, body) => {
6879
- const h = operator(body);
6880
- if (!h) return null;
6881
- if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
6882
- return ["Boole", body];
6883
- }
6884
- },
6885
- {
6886
- kind: "matchfix",
6887
- openTrigger: "\\llbracket",
6888
- closeTrigger: "\\rrbracket",
6889
- parse: (_parser, body) => {
6890
- const h = operator(body);
6891
- if (!h) return null;
6892
- if (!DEFINITIONS_INEQUALITIES.some((x) => x.name === h)) return null;
6893
- return ["Boole", body];
6894
- }
6895
- },
6896
- // Predicate application in First-Order Logic.
6897
- // ["Predicate", "P", "x", "y"] serializes to "P(x, y)"
6898
- {
6899
- name: "Predicate",
6900
- serialize: (serializer, expr) => {
6901
- const args = operands(expr);
6902
- if (args.length === 0) return "";
6903
- const pred = args[0];
6904
- const predStr = typeof pred === "string" ? pred : serializer.serialize(pred);
6905
- if (args.length === 1) return predStr;
6906
- const argStrs = args.slice(1).map((arg) => serializer.serialize(arg));
6907
- return `${predStr}(${argStrs.join(", ")})`;
7123
+ return ["To", lhs, rhs];
6908
7124
  }
6909
7125
  }
6910
7126
  ];
6911
- function serializeQuantifier(quantifierSymbol) {
6912
- return (serializer, expr) => {
6913
- const args = operands(expr);
6914
- if (args.length === 0) return quantifierSymbol;
6915
- if (args.length === 1)
6916
- return `${quantifierSymbol} ${serializer.serialize(args[0])}`;
6917
- const boundVar = serializer.serialize(args[0]);
6918
- const body = serializer.serialize(args[1]);
6919
- return `${quantifierSymbol} ${boundVar}, ${body}`;
6920
- };
6921
- }
6922
- function tightBindingCondition(p, terminator) {
6923
- 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);
6924
- }
6925
- function parseQuantifier(kind) {
6926
- return (parser, terminator) => {
6927
- const index = parser.index;
6928
- const useTightBinding = parser.options.quantifierScope !== "loose";
6929
- const symbol2 = parser.parseSymbol(terminator);
6930
- if (symbol2) {
6931
- parser.skipSpace();
6932
- if (parser.match(",") || parser.match("\\mid") || parser.match(".") || parser.match(":") || parser.match("\\colon")) {
6933
- const bodyTerminator = useTightBinding ? {
6934
- ...terminator,
6935
- condition: (p) => tightBindingCondition(p, terminator)
6936
- } : terminator;
6937
- parser.enterQuantifierScope();
6938
- const body2 = parser.parseExpression(bodyTerminator);
6939
- parser.exitQuantifierScope();
6940
- return [kind, symbol2, missingIfEmpty(body2)];
6941
- }
6942
- parser.enterQuantifierScope();
6943
- const body = parser.parseEnclosure();
6944
- parser.exitQuantifierScope();
6945
- if (body) return [kind, symbol2, missingIfEmpty(body)];
6946
- }
6947
- parser.index = index;
6948
- const condTerminator = {
6949
- ...terminator,
6950
- condition: (p) => p.peek === ":" || p.peek === "\\colon" || (terminator.condition?.(p) ?? false)
6951
- };
6952
- const condition = parser.parseExpression(condTerminator);
6953
- if (condition === null) return null;
6954
- parser.skipSpace();
6955
- if (parser.matchAny([",", "\\mid", ":", "\\colon"])) {
6956
- const bodyTerminator = useTightBinding ? {
6957
- ...terminator,
6958
- condition: (p) => tightBindingCondition(p, terminator)
6959
- } : terminator;
6960
- parser.enterQuantifierScope();
6961
- const body = parser.parseExpression(bodyTerminator);
6962
- parser.exitQuantifierScope();
6963
- return [kind, condition, missingIfEmpty(body)];
6964
- }
6965
- if (parser.match("(")) {
6966
- parser.enterQuantifierScope();
6967
- const body = parser.parseExpression(terminator);
6968
- parser.exitQuantifierScope();
6969
- if (!parser.match(")")) return null;
6970
- return [kind, condition, missingIfEmpty(body)];
6971
- }
6972
- return null;
6973
- };
6974
- }
6975
7127
 
6976
7128
  // src/compute-engine/latex-syntax/dictionary/definitions-sets.ts
6977
7129
  function parseIntervalBody(body, openLeft, openRight) {
@@ -11307,7 +11459,7 @@ var ZWJ = "\\u{200D}";
11307
11459
  var FLAG_SEQUENCE = "\\p{RI}\\p{RI}";
11308
11460
  var TAG_MOD = `(?:[\\u{E0020}-\\u{E007E}]+\\u{E007F})`;
11309
11461
  var EMOJI_MOD = `(?:\\p{EMod}|${VS16}${KEYCAP}?|${TAG_MOD})`;
11310
- var EMOJI_NOT_SYMBOL = `(?:(?=\\P{XIDC})\\p{Emoji})`;
11462
+ var EMOJI_NOT_SYMBOL = `(?:(?=\\P{XIDC})(?=[^\\x23\\x2a\\x30-\\x39])\\p{Emoji})`;
11311
11463
  var ZWJ_ELEMENT = `(?:${EMOJI_NOT_SYMBOL}${EMOJI_MOD}*|\\p{Emoji}${EMOJI_MOD}+|${FLAG_SEQUENCE})`;
11312
11464
  var POSSIBLE_EMOJI = `(?:${ZWJ_ELEMENT})(${ZWJ}${ZWJ_ELEMENT})*`;
11313
11465
  var SOME_EMOJI = new RegExp(`(?:${POSSIBLE_EMOJI})+`, "u");
@@ -24388,7 +24540,7 @@ function compileToIntervalTarget(expr, target) {
24388
24540
  }
24389
24541
 
24390
24542
  // src/compile.ts
24391
- var version = "0.55.0";
24543
+ var version = "0.55.2";
24392
24544
  export {
24393
24545
  BaseCompiler,
24394
24546
  GLSLTarget,