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