@cortex-js/compute-engine 0.12.5 → 0.12.6

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 (89) hide show
  1. package/dist/compute-engine.esm.js +835 -735
  2. package/dist/compute-engine.js +835 -735
  3. package/dist/compute-engine.min.esm.js +835 -735
  4. package/dist/compute-engine.min.js +835 -735
  5. package/dist/math-json.esm.js +2 -2
  6. package/dist/math-json.js +2 -2
  7. package/dist/math-json.min.esm.js +2 -2
  8. package/dist/math-json.min.js +2 -2
  9. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  10. package/dist/types/common/signals.d.ts +1 -1
  11. package/dist/types/common/utils.d.ts +1 -1
  12. package/dist/types/compute-engine/assume.d.ts +1 -1
  13. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +1 -1
  14. package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
  15. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
  16. package/dist/types/compute-engine/boxed-expression/boxed-domain.d.ts +1 -1
  17. package/dist/types/compute-engine/boxed-expression/boxed-function-definition.d.ts +1 -1
  18. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +1 -1
  19. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -1
  20. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  21. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -1
  22. package/dist/types/compute-engine/boxed-expression/boxed-symbol-definition.d.ts +1 -1
  23. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +1 -1
  24. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  25. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  26. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  27. package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
  28. package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
  29. package/dist/types/compute-engine/compute-engine.d.ts +5 -5
  30. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  31. package/dist/types/compute-engine/domain-utils.d.ts +1 -1
  32. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  33. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  34. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  35. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  36. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-inequalities.d.ts +1 -1
  37. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
  38. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  39. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  40. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  41. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  42. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +14 -9
  43. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +2 -2
  44. package/dist/types/compute-engine/latex-syntax/parse-identifier.d.ts +2 -2
  45. package/dist/types/compute-engine/latex-syntax/parse.d.ts +101 -76
  46. package/dist/types/compute-engine/latex-syntax/public.d.ts +137 -135
  47. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  48. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  49. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +4 -4
  50. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  51. package/dist/types/compute-engine/library/arithmetic-add.d.ts +1 -1
  52. package/dist/types/compute-engine/library/arithmetic-divide.d.ts +1 -1
  53. package/dist/types/compute-engine/library/arithmetic-multiply.d.ts +1 -1
  54. package/dist/types/compute-engine/library/arithmetic-power.d.ts +1 -1
  55. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  56. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  57. package/dist/types/compute-engine/library/collections.d.ts +1 -1
  58. package/dist/types/compute-engine/library/core.d.ts +1 -1
  59. package/dist/types/compute-engine/library/domains.d.ts +2 -1
  60. package/dist/types/compute-engine/library/library.d.ts +1 -1
  61. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  62. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  63. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  64. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  65. package/dist/types/compute-engine/library/sets.d.ts +1 -1
  66. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  67. package/dist/types/compute-engine/library/utils.d.ts +1 -1
  68. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  69. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  70. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  71. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  72. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  73. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  74. package/dist/types/compute-engine/public.d.ts +98 -3
  75. package/dist/types/compute-engine/rules.d.ts +1 -1
  76. package/dist/types/compute-engine/simplify-rules.d.ts +1 -1
  77. package/dist/types/compute-engine/solve.d.ts +1 -1
  78. package/dist/types/compute-engine/symbolic/expand.d.ts +1 -1
  79. package/dist/types/compute-engine/symbolic/flatten.d.ts +1 -1
  80. package/dist/types/compute-engine/symbolic/negate.d.ts +1 -1
  81. package/dist/types/compute-engine/symbolic/polynomials.d.ts +1 -1
  82. package/dist/types/compute-engine/symbolic/product.d.ts +1 -1
  83. package/dist/types/compute-engine/symbolic/sum.d.ts +1 -1
  84. package/dist/types/compute-engine/symbolic/utils.d.ts +1 -1
  85. package/dist/types/compute-engine.d.ts +2 -2
  86. package/dist/types/math-json/math-json-format.d.ts +1 -1
  87. package/dist/types/math-json/utils.d.ts +2 -1
  88. package/dist/types/math-json.d.ts +2 -2
  89. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- /** CortexJS Compute Engine 0.12.5 */
1
+ /** CortexJS Compute Engine 0.12.6 */
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.ComputeEngine = {}));})(this, (function (exports) { 'use strict';
3
3
  var ComputeEngine = (() => {
4
4
  var __create = Object.create;
@@ -1040,21 +1040,25 @@ var ComputeEngine = (() => {
1040
1040
  __export(compute_engine_exports, {
1041
1041
  ComputeEngine: () => ComputeEngine,
1042
1042
  isEnvironmentEntry: () => isEnvironmentEntry,
1043
+ isExpressionEntry: () => isExpressionEntry,
1043
1044
  isFunctionEntry: () => isFunctionEntry,
1044
- isIdentifierEntry: () => isIdentifierEntry,
1045
1045
  isInfixEntry: () => isInfixEntry,
1046
1046
  isMatchfixEntry: () => isMatchfixEntry,
1047
1047
  isPostfixEntry: () => isPostfixEntry,
1048
1048
  isPrefixEntry: () => isPrefixEntry,
1049
+ isSymbolEntry: () => isSymbolEntry,
1049
1050
  version: () => version
1050
1051
  });
1051
1052
 
1052
1053
  // src/compute-engine/latex-syntax/public.ts
1053
- function isIdentifierEntry(entry) {
1054
- return !("kind" in entry) || entry.kind === "identifier";
1054
+ function isExpressionEntry(entry) {
1055
+ return !("kind" in entry) || entry.kind === "expression";
1056
+ }
1057
+ function isSymbolEntry(entry) {
1058
+ return "kind" in entry && entry.kind === "symbol";
1055
1059
  }
1056
1060
  function isFunctionEntry(entry) {
1057
- return !("kind" in entry) || entry.kind === "function";
1061
+ return "kind" in entry && entry.kind === "function";
1058
1062
  }
1059
1063
  function isMatchfixEntry(entry) {
1060
1064
  return "kind" in entry && entry.kind === "matchfix";
@@ -4119,9 +4123,9 @@ var ComputeEngine = (() => {
4119
4123
  return [op3, lhs, rhs];
4120
4124
  }
4121
4125
  function getSequence(expr) {
4122
- let h = head(expr);
4123
4126
  if (expr === null)
4124
4127
  return null;
4128
+ let h = head(expr);
4125
4129
  if (h === "Delimiter") {
4126
4130
  expr = op(expr, 1);
4127
4131
  if (expr === null)
@@ -4130,18 +4134,12 @@ var ComputeEngine = (() => {
4130
4134
  return [expr];
4131
4135
  }
4132
4136
  h = head(expr);
4133
- if (h === "Sequence")
4134
- return ops(expr) ?? [];
4135
- return null;
4137
+ if (h !== "Sequence")
4138
+ return null;
4139
+ return ops(expr) ?? [];
4136
4140
  }
4137
4141
  function isEmptySequence(expr) {
4138
- if (expr === null)
4139
- return false;
4140
- if (head(expr) !== "Sequence")
4141
- return false;
4142
- if (nops(expr) !== 0)
4143
- return false;
4144
- return true;
4142
+ return expr !== null && head(expr) === "Sequence" && nops(expr) === 0;
4145
4143
  }
4146
4144
  function missingIfEmpty(expr) {
4147
4145
  if (expr === null || isEmptySequence(expr))
@@ -4252,8 +4250,8 @@ var ComputeEngine = (() => {
4252
4250
  return [numerator, denominator];
4253
4251
  }
4254
4252
  function parseRoot(parser) {
4255
- const degree = parser.matchLatexOptionalGroup();
4256
- const base = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
4253
+ const degree = parser.parseOptionalGroup();
4254
+ const base = parser.parseGroup() ?? parser.parseToken();
4257
4255
  if (base === null || isEmptySequence(base)) {
4258
4256
  if (degree !== null)
4259
4257
  return ["Root", MISSING, missingIfEmpty(degree)];
@@ -4440,13 +4438,13 @@ var ComputeEngine = (() => {
4440
4438
  return isNegative ? "-" + result : result;
4441
4439
  }
4442
4440
  function parseFraction(parser) {
4443
- let numer = parser.matchLatexGroup();
4441
+ let numer = parser.parseGroup();
4444
4442
  let denom = null;
4445
4443
  if (numer === null) {
4446
- numer = parser.matchSingleAtomArgument();
4447
- denom = parser.matchSingleAtomArgument();
4444
+ numer = parser.parseToken();
4445
+ denom = parser.parseToken();
4448
4446
  } else {
4449
- denom = parser.matchLatexGroup();
4447
+ denom = parser.parseGroup();
4450
4448
  }
4451
4449
  numer = missingIfEmpty(numer);
4452
4450
  denom = missingIfEmpty(denom);
@@ -4454,7 +4452,7 @@ var ComputeEngine = (() => {
4454
4452
  const degree = op(numer, 3) ?? null;
4455
4453
  let fn = op(numer, 1);
4456
4454
  if (fn === null)
4457
- fn = missingIfEmpty(parser.matchExpression());
4455
+ fn = missingIfEmpty(parser.parseExpression());
4458
4456
  let vars = [];
4459
4457
  if (head(denom) === "Multiply") {
4460
4458
  for (const arg of ops(denom) ?? []) {
@@ -4583,7 +4581,7 @@ var ComputeEngine = (() => {
4583
4581
  {
4584
4582
  trigger: ["\\ang"],
4585
4583
  parse: (parser) => {
4586
- const arg = parser.matchLatexGroup();
4584
+ const arg = parser.parseGroup();
4587
4585
  return arg === null ? ["Degrees"] : ["Degrees", arg];
4588
4586
  }
4589
4587
  },
@@ -4600,7 +4598,7 @@ var ComputeEngine = (() => {
4600
4598
  trigger: ["\\tilde", "<{>", "\\infty", "<}>"],
4601
4599
  parse: "ComplexInfinity"
4602
4600
  },
4603
- { name: "Pi", trigger: ["\\pi"] },
4601
+ { name: "Pi", kind: "symbol", trigger: ["\\pi"] },
4604
4602
  { trigger: ["\u03C0"], parse: "Pi" },
4605
4603
  {
4606
4604
  name: "ExponentialE",
@@ -4611,11 +4609,11 @@ var ComputeEngine = (() => {
4611
4609
  {
4612
4610
  kind: "function",
4613
4611
  trigger: "exp",
4614
- parse: (parser) => ["Exp", ...parser.matchArguments("enclosure") ?? []]
4612
+ parse: "Exp"
4615
4613
  },
4616
4614
  {
4617
4615
  trigger: "\\exp",
4618
- parse: (parser) => ["Exp", ...parser.matchArguments("enclosure") ?? []]
4616
+ parse: "Exp"
4619
4617
  },
4620
4618
  {
4621
4619
  name: "ImaginaryUnit",
@@ -4636,10 +4634,7 @@ var ComputeEngine = (() => {
4636
4634
  {
4637
4635
  trigger: "abs",
4638
4636
  kind: "function",
4639
- parse: (parser) => {
4640
- const arg = parser.matchArguments("enclosure");
4641
- return arg === null ? "Abs" : ["Abs", ...arg];
4642
- }
4637
+ parse: "Abs"
4643
4638
  },
4644
4639
  {
4645
4640
  name: "Add",
@@ -4647,10 +4642,10 @@ var ComputeEngine = (() => {
4647
4642
  kind: "infix",
4648
4643
  associativity: "both",
4649
4644
  precedence: 275,
4650
- parse: (parser, until, lhs) => {
4651
- if (275 < until.minPrec)
4645
+ parse: (parser, lhs, until) => {
4646
+ if (until && 275 < until.minPrec)
4652
4647
  return null;
4653
- const rhs = parser.matchExpression({ ...until, minPrec: 275 });
4648
+ const rhs = parser.parseExpression({ ...until, minPrec: 275 });
4654
4649
  if (rhs === null)
4655
4650
  return null;
4656
4651
  return applyAssociativeOperator("Add", lhs, rhs);
@@ -4662,9 +4657,9 @@ var ComputeEngine = (() => {
4662
4657
  trigger: ["+"],
4663
4658
  precedence: 275,
4664
4659
  parse: (parser, until) => {
4665
- if (275 < until.minPrec)
4660
+ if (until && 275 < until.minPrec)
4666
4661
  return null;
4667
- return parser.matchExpression({ ...until, minPrec: 400 });
4662
+ return parser.parseExpression({ ...until, minPrec: 400 });
4668
4663
  }
4669
4664
  },
4670
4665
  {
@@ -4673,13 +4668,16 @@ var ComputeEngine = (() => {
4673
4668
  openDelimiter: "\\lceil",
4674
4669
  closeDelimiter: "\\rceil"
4675
4670
  },
4671
+ {
4672
+ kind: "matchfix",
4673
+ openDelimiter: ["\u2308"],
4674
+ closeDelimiter: ["\u2309"],
4675
+ parse: (_, body) => ["Ceil", body]
4676
+ },
4676
4677
  {
4677
4678
  trigger: "ceil",
4678
4679
  kind: "function",
4679
- parse: (parser) => {
4680
- const arg = parser.matchArguments("enclosure");
4681
- return arg === null ? "Ceil" : ["Ceil", ...arg];
4682
- }
4680
+ parse: "Ceil"
4683
4681
  },
4684
4682
  {
4685
4683
  name: "Complex",
@@ -4765,13 +4763,16 @@ var ComputeEngine = (() => {
4765
4763
  openDelimiter: "\\lfloor",
4766
4764
  closeDelimiter: "\\rfloor"
4767
4765
  },
4766
+ {
4767
+ kind: "matchfix",
4768
+ openDelimiter: ["\u230A"],
4769
+ closeDelimiter: ["\u230B"],
4770
+ parse: (_, body) => ["Floor", body]
4771
+ },
4768
4772
  {
4769
4773
  trigger: "floor",
4770
4774
  kind: "function",
4771
- parse: (parser) => {
4772
- const arg = parser.matchArguments("enclosure");
4773
- return arg === null ? "Floor" : ["Floor", ...arg];
4774
- }
4775
+ parse: "Floor"
4775
4776
  },
4776
4777
  {
4777
4778
  name: "Gcd",
@@ -4787,9 +4788,9 @@ var ComputeEngine = (() => {
4787
4788
  trigger: ["\\lg"],
4788
4789
  serialize: (serializer, expr) => "\\log_{10}" + serializer.wrapArguments(expr),
4789
4790
  parse: (parser) => {
4790
- const arg = parser.matchArguments("implicit");
4791
+ const arg = parser.parseArguments("implicit");
4791
4792
  if (arg === null)
4792
- return ["Lg"];
4793
+ return "Lg";
4793
4794
  return ["Log", ...arg, 10];
4794
4795
  }
4795
4796
  },
@@ -4797,9 +4798,9 @@ var ComputeEngine = (() => {
4797
4798
  name: "Lb",
4798
4799
  trigger: "\\lb",
4799
4800
  parse: (parser) => {
4800
- const arg = parser.matchArguments("implicit");
4801
+ const arg = parser.parseArguments("implicit");
4801
4802
  if (arg === null)
4802
- return ["Log"];
4803
+ return "Log";
4803
4804
  return ["Log", ...arg, 2];
4804
4805
  }
4805
4806
  },
@@ -4850,10 +4851,10 @@ var ComputeEngine = (() => {
4850
4851
  kind: "infix",
4851
4852
  associativity: "both",
4852
4853
  precedence: 390,
4853
- parse: (parser, terminator, lhs) => {
4854
- if (391 < terminator.minPrec)
4854
+ parse: (parser, lhs, terminator) => {
4855
+ if (terminator && 391 < terminator.minPrec)
4855
4856
  return null;
4856
- const rhs = parser.matchExpression({ ...terminator, minPrec: 392 });
4857
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 392 });
4857
4858
  if (rhs === null)
4858
4859
  return ["Multiply", lhs, MISSING];
4859
4860
  return applyAssociativeOperator("Multiply", lhs, rhs);
@@ -4864,10 +4865,10 @@ var ComputeEngine = (() => {
4864
4865
  kind: "infix",
4865
4866
  associativity: "both",
4866
4867
  precedence: 390,
4867
- parse: (parser, terminator, lhs) => {
4868
- if (391 < terminator.minPrec)
4868
+ parse: (parser, lhs, terminator) => {
4869
+ if (terminator && 391 < terminator.minPrec)
4869
4870
  return null;
4870
- const rhs = parser.matchExpression({ ...terminator, minPrec: 392 });
4871
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 392 });
4871
4872
  if (rhs === null)
4872
4873
  return ["Multiply", lhs, MISSING];
4873
4874
  return applyAssociativeOperator("Multiply", lhs, rhs);
@@ -4878,9 +4879,9 @@ var ComputeEngine = (() => {
4878
4879
  trigger: ["-"],
4879
4880
  kind: "prefix",
4880
4881
  parse: (parser, terminator) => {
4881
- if (276 < terminator.minPrec)
4882
+ if (terminator && 276 < terminator.minPrec)
4882
4883
  return null;
4883
- const rhs = parser.matchExpression({ ...terminator, minPrec: 400 });
4884
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4884
4885
  return ["Negate", missingIfEmpty(rhs)];
4885
4886
  },
4886
4887
  precedence: 275
@@ -4942,9 +4943,32 @@ var ComputeEngine = (() => {
4942
4943
  kind: "prefix",
4943
4944
  precedence: 270,
4944
4945
  parse: (parser, terminator) => {
4946
+ if (terminator && 270 < terminator.minPrec)
4947
+ return null;
4948
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4949
+ return ["PlusMinus", missingIfEmpty(rhs)];
4950
+ }
4951
+ },
4952
+ {
4953
+ trigger: ["\\plusmn"],
4954
+ kind: "infix",
4955
+ associativity: "both",
4956
+ precedence: 270,
4957
+ parse: (parser, lhs, terminator) => {
4945
4958
  if (270 < terminator.minPrec)
4946
4959
  return null;
4947
- const rhs = parser.matchExpression({ ...terminator, minPrec: 400 });
4960
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4961
+ return ["PlusMinus", lhs, missingIfEmpty(rhs)];
4962
+ }
4963
+ },
4964
+ {
4965
+ trigger: ["\\plusmn"],
4966
+ kind: "prefix",
4967
+ precedence: 270,
4968
+ parse: (parser, terminator) => {
4969
+ if (terminator && 270 < terminator.minPrec)
4970
+ return null;
4971
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4948
4972
  return ["PlusMinus", missingIfEmpty(rhs)];
4949
4973
  }
4950
4974
  },
@@ -5015,10 +5039,10 @@ var ComputeEngine = (() => {
5015
5039
  kind: "infix",
5016
5040
  associativity: "both",
5017
5041
  precedence: 275,
5018
- parse: (parser, terminator, lhs) => {
5042
+ parse: (parser, lhs, terminator) => {
5019
5043
  if (276 < terminator.minPrec)
5020
5044
  return null;
5021
- const rhs = parser.matchExpression({ ...terminator, minPrec: 277 });
5045
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 277 });
5022
5046
  return ["Subtract", lhs, missingIfEmpty(rhs)];
5023
5047
  }
5024
5048
  }
@@ -5030,9 +5054,9 @@ var ComputeEngine = (() => {
5030
5054
  let sub2 = null;
5031
5055
  while (!(sub2 && sup) && (parser.peek === "_" || parser.peek === "^")) {
5032
5056
  if (parser.match("_"))
5033
- sub2 = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
5057
+ sub2 = parser.parseGroup() ?? parser.parseToken();
5034
5058
  else if (parser.match("^"))
5035
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
5059
+ sup = parser.parseGroup() ?? parser.parseToken();
5036
5060
  parser.skipSpace();
5037
5061
  }
5038
5062
  if (sub2 === "Nothing" || isEmptySequence(sub2))
@@ -5050,7 +5074,7 @@ var ComputeEngine = (() => {
5050
5074
  const sym = symbol(index);
5051
5075
  if (sym)
5052
5076
  parser.computeEngine?.pushScope({ [sym]: { domain: "Integer" } });
5053
- const fn = parser.matchExpression({ minPrec: prec + 1 });
5077
+ const fn = parser.parseExpression({ minPrec: prec + 1 });
5054
5078
  if (sym)
5055
5079
  parser.computeEngine?.popScope();
5056
5080
  if (!fn)
@@ -5111,10 +5135,10 @@ var ComputeEngine = (() => {
5111
5135
  let sub2 = null;
5112
5136
  let base = null;
5113
5137
  if (parser.match("_")) {
5114
- sub2 = parser.matchStringArgument() ?? parser.next();
5138
+ sub2 = parser.parseStringGroup()?.trim() ?? parser.nextToken();
5115
5139
  base = Number.parseFloat(sub2 ?? "10");
5116
5140
  }
5117
- const arg = parser.matchArguments("implicit");
5141
+ const arg = parser.parseArguments("implicit");
5118
5142
  if (arg === null)
5119
5143
  return [command];
5120
5144
  if (base === 10)
@@ -5143,7 +5167,7 @@ var ComputeEngine = (() => {
5143
5167
  if (parser.atTerminator(terminator)) {
5144
5168
  result.push("Nothing");
5145
5169
  } else {
5146
- const rhs = parser.matchExpression({ ...terminator, minPrec: prec });
5170
+ const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
5147
5171
  result.push(rhs ?? "Nothing");
5148
5172
  done = rhs === null;
5149
5173
  }
@@ -5163,15 +5187,18 @@ var ComputeEngine = (() => {
5163
5187
  //
5164
5188
  {
5165
5189
  trigger: ["\\placeholder"],
5190
+ kind: "symbol",
5166
5191
  parse: (parser) => {
5167
- parser.skipSpaceTokens();
5192
+ while (parser.match("<space>")) {
5193
+ }
5168
5194
  if (parser.match("["))
5169
5195
  while (!parser.match("]") && !parser.atBoundary)
5170
- parser.next();
5171
- parser.skipSpaceTokens();
5196
+ parser.nextToken();
5197
+ while (parser.match("<space>")) {
5198
+ }
5172
5199
  if (parser.match("<{>"))
5173
5200
  while (!parser.match("<}>") && !parser.atBoundary)
5174
- parser.next();
5201
+ parser.nextToken();
5175
5202
  return "Nothing";
5176
5203
  }
5177
5204
  },
@@ -5180,7 +5207,6 @@ var ComputeEngine = (() => {
5180
5207
  //
5181
5208
  {
5182
5209
  name: "BaseForm",
5183
- kind: "function",
5184
5210
  serialize: (serializer, expr) => {
5185
5211
  const radix = machineValue(op(expr, 2)) ?? NaN;
5186
5212
  if (isFinite(radix) && radix >= 2 && radix <= 36) {
@@ -5227,9 +5253,9 @@ var ComputeEngine = (() => {
5227
5253
  let close = "";
5228
5254
  if (argCount > 1) {
5229
5255
  const op22 = stringValue(op(expr, 2)) ?? "";
5230
- open = op22[0] ?? "";
5231
- close = op22[1] ?? "";
5232
- sep = op22[2] ?? "";
5256
+ open = op22[0] ?? "(";
5257
+ close = op22[1] ?? ")";
5258
+ sep = op22[2] ?? ",";
5233
5259
  }
5234
5260
  const body = head(arg1) === "List" ? serializeSequence(sep)(serializer, arg1) : serializer.serialize(arg1);
5235
5261
  serializer.wrapString(body, style, stringValue(op(expr, 2)) ?? void 0);
@@ -5249,22 +5275,22 @@ var ComputeEngine = (() => {
5249
5275
  {
5250
5276
  trigger: ["\\mathtip"],
5251
5277
  parse: (parser) => {
5252
- const op12 = parser.matchLatexGroup();
5253
- const op22 = parser.matchLatexGroup();
5278
+ const op12 = parser.parseGroup();
5279
+ const op22 = parser.parseGroup();
5254
5280
  return op12;
5255
5281
  }
5256
5282
  },
5257
5283
  {
5258
5284
  trigger: ["\\texttip"],
5259
5285
  parse: (parser) => {
5260
- const op12 = parser.matchLatexGroup();
5261
- const op22 = parser.matchLatexGroup();
5286
+ const op12 = parser.parseGroup();
5287
+ const op22 = parser.parseGroup();
5262
5288
  return op12;
5263
5289
  }
5264
5290
  },
5265
5291
  {
5266
5292
  trigger: ["\\error"],
5267
- parse: (parser) => parser.matchLatexGroup()
5293
+ parse: (parser) => parser.parseGroup()
5268
5294
  },
5269
5295
  {
5270
5296
  name: "Error",
@@ -5326,12 +5352,12 @@ var ComputeEngine = (() => {
5326
5352
  kind: "matchfix",
5327
5353
  openDelimiter: "[",
5328
5354
  closeDelimiter: "]",
5329
- parse: (_parser, lhs) => {
5330
- if (lhs === null)
5355
+ parse: (_parser, body) => {
5356
+ if (body === null)
5331
5357
  return ["List"];
5332
- if (head(lhs) !== "Sequence" && head(lhs) !== "List")
5333
- return ["List", lhs];
5334
- return ["List", ...ops(lhs) ?? []];
5358
+ if (head(body) !== "Sequence" && head(body) !== "List")
5359
+ return ["List", body];
5360
+ return ["List", ...ops(body) ?? []];
5335
5361
  },
5336
5362
  serialize: (serializer, expr) => {
5337
5363
  return joinLatex([
@@ -5364,8 +5390,8 @@ var ComputeEngine = (() => {
5364
5390
  // when the comma operator is used, the lhs and rhs are flattened,
5365
5391
  // i.e. `1,2,3` -> `["Delimiter", ["List", 1, 2, 3], ","]`,
5366
5392
  // and `1, (2, 3)` -> `["Delimiter",
5367
- // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "(", ",", ")"]], ","],
5368
- parse: (parser, terminator, lhs) => {
5393
+ // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "()", ","]]],
5394
+ parse: (parser, lhs, terminator) => {
5369
5395
  const seq = parseSequence(parser, terminator, lhs, 20, ",");
5370
5396
  if (seq === null)
5371
5397
  return null;
@@ -5380,7 +5406,7 @@ var ComputeEngine = (() => {
5380
5406
  trigger: [";"],
5381
5407
  kind: "infix",
5382
5408
  precedence: 19,
5383
- parse: (parser, terminator, lhs) => {
5409
+ parse: (parser, lhs, terminator) => {
5384
5410
  const seq = parseSequence(parser, terminator, lhs, 19, ";");
5385
5411
  if (seq === null)
5386
5412
  return null;
@@ -5452,10 +5478,20 @@ var ComputeEngine = (() => {
5452
5478
  kind: "postfix",
5453
5479
  parse: (_parser, lhs) => ["Prime", missingIfEmpty(lhs), 2]
5454
5480
  },
5481
+ {
5482
+ trigger: ["^", "\\tripleprime"],
5483
+ kind: "postfix",
5484
+ parse: (_parser, lhs) => ["Prime", missingIfEmpty(lhs), 3]
5485
+ },
5455
5486
  {
5456
5487
  name: "InverseFunction",
5457
- // trigger: '^{-1}',
5458
- // kind: 'postfix',
5488
+ trigger: "^{-1}",
5489
+ kind: "postfix",
5490
+ parse: (parser, lhs) => {
5491
+ if (parser.computeEngine?.box(lhs)?.domain.isFunction)
5492
+ return ["InverseFunction", lhs];
5493
+ return null;
5494
+ },
5459
5495
  serialize: (serializer, expr) => serializer.serialize(op(expr, 1)) + "^{-1}"
5460
5496
  },
5461
5497
  {
@@ -5465,9 +5501,9 @@ var ComputeEngine = (() => {
5465
5501
  const base = serializer.serialize(op(expr, 1));
5466
5502
  if (degree === 1)
5467
5503
  return base + "^{\\prime}";
5468
- else if (degree === 2)
5504
+ if (degree === 2)
5469
5505
  return base + "^{\\doubleprime}";
5470
- else if (degree === 3)
5506
+ if (degree === 3)
5471
5507
  return base + "^{\\tripleprime}";
5472
5508
  return base + "^{(" + Number(degree).toString() + ")}";
5473
5509
  }
@@ -5477,7 +5513,7 @@ var ComputeEngine = (() => {
5477
5513
  trigger: "cases",
5478
5514
  kind: "environment",
5479
5515
  parse: (parser) => {
5480
- const tabular = parser.matchTabular("cases");
5516
+ const tabular = parser.parseTabular();
5481
5517
  if (!tabular)
5482
5518
  return ["Which"];
5483
5519
  const result = ["Which"];
@@ -5526,9 +5562,9 @@ var ComputeEngine = (() => {
5526
5562
  runs.push(parseTextRun(parser));
5527
5563
  } else if (parser.match("\\textbf") && parser.match("<{>")) {
5528
5564
  runs.push(parseTextRun(parser, { "font-weight": "bold" }));
5529
- } else if (parser.match("\\color") && parser.match("<{>")) {
5530
- const color = parser.matchColor();
5531
- if (color && parser.match("<}>")) {
5565
+ } else if (parser.match("\\color")) {
5566
+ const color = parser.parseStringGroup();
5567
+ if (color !== null) {
5532
5568
  if (runinStyle !== null && text) {
5533
5569
  runs.push(["Style", text, { dict: runinStyle }]);
5534
5570
  } else if (text) {
@@ -5541,7 +5577,7 @@ var ComputeEngine = (() => {
5541
5577
  text += " ";
5542
5578
  } else if (parser.match("<$>")) {
5543
5579
  const index = parser.index;
5544
- const expr = parser.matchExpression() ?? ["Sequence"];
5580
+ const expr = parser.parseExpression() ?? ["Sequence"];
5545
5581
  parser.skipSpace();
5546
5582
  if (parser.match("<$>")) {
5547
5583
  runs.push(expr);
@@ -5551,7 +5587,7 @@ var ComputeEngine = (() => {
5551
5587
  }
5552
5588
  } else if (parser.match("<$$>")) {
5553
5589
  const index = parser.index;
5554
- const expr = parser.matchExpression() ?? ["Sequence"];
5590
+ const expr = parser.parseExpression() ?? ["Sequence"];
5555
5591
  parser.skipSpace();
5556
5592
  if (parser.match("<$$>")) {
5557
5593
  runs.push(expr);
@@ -5560,7 +5596,7 @@ var ComputeEngine = (() => {
5560
5596
  parser.index = index;
5561
5597
  }
5562
5598
  } else
5563
- text += parser.matchChar() ?? parser.next();
5599
+ text += parser.matchChar() ?? parser.nextToken();
5564
5600
  }
5565
5601
  if (runinStyle !== null && text) {
5566
5602
  runs.push(["Style", `'${text}'`, { dict: runinStyle }]);
@@ -5629,7 +5665,7 @@ var ComputeEngine = (() => {
5629
5665
  // src/compute-engine/latex-syntax/dictionary/definitions-inequalities.ts
5630
5666
  var DEFINITIONS_INEQUALITIES = [
5631
5667
  {
5632
- trigger: ["!", "<"],
5668
+ trigger: ["\\not", "<"],
5633
5669
  kind: "infix",
5634
5670
  associativity: "right",
5635
5671
  precedence: 246,
@@ -5811,7 +5847,7 @@ var ComputeEngine = (() => {
5811
5847
  {
5812
5848
  name: "NotApprox",
5813
5849
  // Note: Mathematica TildeTilde
5814
- trigger: ["\\approx"],
5850
+ trigger: ["\\not", "\\approx"],
5815
5851
  kind: "infix",
5816
5852
  associativity: "right",
5817
5853
  precedence: 247
@@ -5827,7 +5863,7 @@ var ComputeEngine = (() => {
5827
5863
  {
5828
5864
  name: "NotApproxEqual",
5829
5865
  // Note: Mathematica NotTildeEqual
5830
- trigger: ["!", "\\approxeq"],
5866
+ trigger: ["\\not", "\\approxeq"],
5831
5867
  kind: "infix",
5832
5868
  // Note: no LaTeX symbol for char U+2249
5833
5869
  associativity: "right",
@@ -5915,7 +5951,7 @@ var ComputeEngine = (() => {
5915
5951
  precedence: 244
5916
5952
  },
5917
5953
  {
5918
- trigger: ["!", ">"],
5954
+ trigger: ["\\not", ">"],
5919
5955
  kind: "infix",
5920
5956
  associativity: "right",
5921
5957
  precedence: 244,
@@ -6078,7 +6114,7 @@ var ComputeEngine = (() => {
6078
6114
  // src/compute-engine/latex-syntax/dictionary/definitions-other.ts
6079
6115
  function parseSingleArg(cmd) {
6080
6116
  return (parser) => {
6081
- const arg = parser.matchLatexGroup();
6117
+ const arg = parser.parseGroup();
6082
6118
  return arg === null ? [cmd] : [cmd, arg];
6083
6119
  };
6084
6120
  }
@@ -6132,14 +6168,14 @@ var ComputeEngine = (() => {
6132
6168
  {
6133
6169
  name: "Transpose",
6134
6170
  trigger: ["^", "T"],
6135
- kind: "infix"
6171
+ kind: "postfix"
6136
6172
  // @todo: if lhs is a list/tensor
6137
6173
  },
6138
6174
  {
6139
6175
  // @todo: if lhs is a list/tensor
6140
6176
  name: "ConjugateTranspose",
6141
6177
  trigger: ["^", "H"],
6142
- kind: "infix"
6178
+ kind: "postfix"
6143
6179
  },
6144
6180
  {
6145
6181
  name: "StringJoin",
@@ -6169,9 +6205,9 @@ var ComputeEngine = (() => {
6169
6205
  while (!done) {
6170
6206
  parser.skipSpace();
6171
6207
  if (parser.match("_")) {
6172
- sub2 = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
6208
+ sub2 = parser.parseGroup() ?? parser.parseToken();
6173
6209
  } else if (parser.match("^")) {
6174
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
6210
+ sup = parser.parseGroup() ?? parser.parseToken();
6175
6211
  } else {
6176
6212
  done = true;
6177
6213
  }
@@ -6181,9 +6217,9 @@ var ComputeEngine = (() => {
6181
6217
  sub2 = ["List", ...seq];
6182
6218
  if (sub2 === null || sup === null)
6183
6219
  return null;
6184
- let rhs = parser.matchLatexGroup() ?? "Nothing";
6220
+ let rhs = parser.parseGroup() ?? "Nothing";
6185
6221
  if (rhs !== "Nothing" && !isEmptySequence(rhs)) {
6186
- const arg = parser.matchArguments("enclosure") ?? ["Nothing"];
6222
+ const arg = parser.parseArguments() ?? ["Nothing"];
6187
6223
  rhs = [rhs, ...arg];
6188
6224
  }
6189
6225
  return ["PartialDerivative", rhs, sub2, sup];
@@ -6460,7 +6496,7 @@ var ComputeEngine = (() => {
6460
6496
  // src/compute-engine/latex-syntax/dictionary/definitions-trigonometry.ts
6461
6497
  function parseTrig(op3) {
6462
6498
  return (parser, until) => {
6463
- let head2 = {
6499
+ const head2 = {
6464
6500
  "\\arcsin": "Arcsin",
6465
6501
  "\\arccos": "Arccos",
6466
6502
  "\\arctan": "Arctan",
@@ -6495,37 +6531,11 @@ var ComputeEngine = (() => {
6495
6531
  }[op3 ?? ""] ?? op3 ?? "";
6496
6532
  if (parser.atTerminator(until))
6497
6533
  return head2;
6498
- let isInverse = false;
6499
- let primeLevel = 0;
6500
- let sup = null;
6501
- parser.skipSpace();
6502
- const start = parser.index;
6503
- if (parser.match("^")) {
6504
- parser.skipSpace();
6505
- const superscriptIndex = parser.index;
6506
- if (parser.matchAll(["<{>", "-", "1", "<}>"]))
6507
- isInverse = true;
6508
- else {
6509
- parser.index = start;
6510
- parser.index = start;
6511
- primeLevel = parser.matchPrimeSuffix();
6512
- if (primeLevel === 0) {
6513
- parser.index = superscriptIndex;
6514
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
6515
- }
6516
- }
6517
- }
6518
- primeLevel += parser.matchPrimeSuffix();
6519
- if (isInverse)
6520
- head2 = ["InverseFunction", head2];
6521
- if (primeLevel === 1)
6522
- head2 = ["Derivative", head2];
6523
- else if (primeLevel > 1)
6524
- head2 = ["Derivative", head2, primeLevel];
6525
- const args = parser.matchArguments("implicit", until);
6526
- if (args === null)
6527
- return sup ? [["Power", [head2], sup]] : head2;
6528
- return sup ? ["Power", [head2, ...args], sup] : [head2, ...args];
6534
+ const fn = parser.parsePostfixOperator(head2, until);
6535
+ if (fn !== null)
6536
+ return fn;
6537
+ const args = parser.parseArguments("implicit", until);
6538
+ return args === null ? head2 : [head2, ...args];
6529
6539
  };
6530
6540
  }
6531
6541
  var DEFINITIONS_TRIGONOMETRY = [
@@ -6554,7 +6564,6 @@ var ComputeEngine = (() => {
6554
6564
  parse: parseTrig("Arccot")
6555
6565
  },
6556
6566
  {
6557
- kind: "function",
6558
6567
  name: "Arcsec",
6559
6568
  trigger: "arcsec",
6560
6569
  parse: parseTrig("Arcsec")
@@ -6755,14 +6764,14 @@ var ComputeEngine = (() => {
6755
6764
  // Caution: cartesian product is not associative
6756
6765
  precedence: 390,
6757
6766
  // Same as Multiply?
6758
- parse: (parser, until, lhs) => {
6767
+ parse: (parser, lhs, until) => {
6759
6768
  if (390 < until.minPrec)
6760
6769
  return null;
6761
6770
  const ce = parser.computeEngine;
6762
6771
  if (!ce || !ce.box(lhs).domain.isCompatible("Set"))
6763
6772
  return null;
6764
6773
  const index = parser.index;
6765
- const rhs = parser.matchExpression({ ...until, minPrec: 390 });
6774
+ const rhs = parser.parseExpression({ ...until, minPrec: 390 });
6766
6775
  if (rhs === null || ce.box(lhs).domain.isCompatible("Set") !== true) {
6767
6776
  parser.index = index;
6768
6777
  return null;
@@ -6842,8 +6851,8 @@ var ComputeEngine = (() => {
6842
6851
  associativity: "right",
6843
6852
  precedence: 160,
6844
6853
  // As per MathML, lower precedence
6845
- parse: (parser, terminator, lhs) => {
6846
- const rhs = parser.matchExpression(terminator);
6854
+ parse: (parser, lhs, terminator) => {
6855
+ const rhs = parser.parseExpression(terminator);
6847
6856
  return rhs === null ? null : ["Element", rhs, lhs];
6848
6857
  }
6849
6858
  },
@@ -7048,9 +7057,10 @@ var ComputeEngine = (() => {
7048
7057
  let sub2 = null;
7049
7058
  while (!(sub2 !== null && sup !== null) && (parser.peek === "_" || parser.peek === "^")) {
7050
7059
  if (parser.match("_"))
7051
- sub2 = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
7052
- else if (parser.match("^"))
7053
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
7060
+ sub2 = parser.parseGroup() ?? parser.parseToken();
7061
+ else if (parser.match("^")) {
7062
+ sup = parser.parseGroup() ?? parser.parseToken();
7063
+ }
7054
7064
  parser.skipSpace();
7055
7065
  }
7056
7066
  if (sub2 === "Nothing" || isEmptySequence(sub2))
@@ -7126,7 +7136,7 @@ var ComputeEngine = (() => {
7126
7136
  function parseIntegralBody(parser, n = 1) {
7127
7137
  const start = parser.index;
7128
7138
  let found = false;
7129
- let fn = parser.matchExpression({
7139
+ let fn = parser.parseExpression({
7130
7140
  minPrec: 266,
7131
7141
  condition: () => {
7132
7142
  if (parser.matchAll(["\\mathrm", "<{>", "d", "<}>"]))
@@ -7136,7 +7146,7 @@ var ComputeEngine = (() => {
7136
7146
  });
7137
7147
  if (!found) {
7138
7148
  parser.index = start;
7139
- fn = parser.matchExpression({
7149
+ fn = parser.parseExpression({
7140
7150
  minPrec: 266,
7141
7151
  condition: () => {
7142
7152
  if (parser.match("d"))
@@ -7153,7 +7163,7 @@ var ComputeEngine = (() => {
7153
7163
  function parseIndexes(parser, n = 1) {
7154
7164
  parser.skipSpace();
7155
7165
  const result = [];
7156
- const index = symbol(parser.matchSymbol());
7166
+ const index = symbol(parser.parseSymbol());
7157
7167
  if (index === null)
7158
7168
  return [];
7159
7169
  result.push(index);
@@ -7272,30 +7282,36 @@ var ComputeEngine = (() => {
7272
7282
  }
7273
7283
  var DEFINITIONS_CALCULUS = [
7274
7284
  {
7285
+ kind: "expression",
7275
7286
  name: "Integrate",
7276
7287
  trigger: ["\\int"],
7277
7288
  parse: parseIntegral("Integrate"),
7278
7289
  serialize: serializeIntegral("\\int")
7279
7290
  },
7280
7291
  {
7292
+ kind: "expression",
7281
7293
  trigger: ["\\iint"],
7282
7294
  parse: parseIntegral("Integrate", 2)
7283
7295
  },
7284
7296
  {
7297
+ kind: "expression",
7285
7298
  trigger: ["\\iiint"],
7286
7299
  parse: parseIntegral("Integrate", 3)
7287
7300
  },
7288
7301
  {
7302
+ kind: "expression",
7289
7303
  name: "CircularIntegrate",
7290
7304
  trigger: ["\\oint"],
7291
7305
  parse: parseIntegral("CircularIntegrate"),
7292
7306
  serialize: serializeIntegral("\\oint")
7293
7307
  },
7294
7308
  {
7309
+ kind: "expression",
7295
7310
  trigger: ["\\oiint"],
7296
7311
  parse: parseIntegral("CircularIntegrate", 2)
7297
7312
  },
7298
7313
  {
7314
+ kind: "expression",
7299
7315
  trigger: ["\\oiiint"],
7300
7316
  parse: parseIntegral("CircularIntegrate", 3)
7301
7317
  }
@@ -7401,6 +7417,7 @@ var ComputeEngine = (() => {
7401
7417
  var DEFINITIONS_SYMBOLS = [
7402
7418
  ...SYMBOLS.map(([symbol2, latex, _codepoint]) => {
7403
7419
  return {
7420
+ kind: "symbol",
7404
7421
  name: symbol2,
7405
7422
  trigger: [latex],
7406
7423
  parse: symbol2
@@ -7408,6 +7425,7 @@ var ComputeEngine = (() => {
7408
7425
  }),
7409
7426
  ...SYMBOLS.map(([symbol2, _latex, codepoint]) => {
7410
7427
  return {
7428
+ kind: "symbol",
7411
7429
  trigger: [String.fromCodePoint(codepoint)],
7412
7430
  parse: symbol2
7413
7431
  };
@@ -7436,98 +7454,99 @@ var ComputeEngine = (() => {
7436
7454
  return trigger.length;
7437
7455
  return 1;
7438
7456
  }
7457
+ function addEntry(result, entry, onError) {
7458
+ const [trigger, indexedEntry] = makeIndexedEntry(entry, onError);
7459
+ if (indexedEntry === null)
7460
+ return;
7461
+ const kind = "kind" in entry ? entry.kind : "expression";
7462
+ if (trigger && trigger.length === 2 && /[_^]/.test(trigger[0]) && trigger[1] !== "<{>" && kind !== "function" && entry.name) {
7463
+ let parse = entry.parse;
7464
+ if (parse === void 0) {
7465
+ if (kind === "symbol")
7466
+ parse = entry.name;
7467
+ if (kind === "postfix" || kind === "prefix")
7468
+ parse = (_parser, expr) => [entry.name, expr];
7469
+ }
7470
+ addEntry(
7471
+ result,
7472
+ {
7473
+ ...entry,
7474
+ kind,
7475
+ parse,
7476
+ name: void 0,
7477
+ trigger: [trigger[0], "<{>", trigger[1], "<}>"]
7478
+ },
7479
+ onError
7480
+ );
7481
+ }
7482
+ if (indexedEntry.name !== void 0) {
7483
+ if (result.name.has(indexedEntry.name)) {
7484
+ onError({
7485
+ severity: "warning",
7486
+ message: [
7487
+ "invalid-dictionary-entry",
7488
+ indexedEntry.name,
7489
+ "Duplicate definition. The name must be unique, but a trigger can be used by multiple definitions."
7490
+ ]
7491
+ });
7492
+ }
7493
+ result.name.set(indexedEntry.name, indexedEntry);
7494
+ }
7495
+ if (indexedEntry.kind === "matchfix") {
7496
+ result.matchfix.push(indexedEntry);
7497
+ } else if (indexedEntry.kind === "environment") {
7498
+ const triggerString = tokensToString(entry.trigger ?? "");
7499
+ if (result.environment.has(triggerString)) {
7500
+ onError({
7501
+ severity: "warning",
7502
+ message: [
7503
+ "invalid-dictionary-entry",
7504
+ triggerString,
7505
+ "Duplicate environment definition"
7506
+ ]
7507
+ });
7508
+ }
7509
+ result.environment.set(triggerString, indexedEntry);
7510
+ } else if (trigger) {
7511
+ console.assert(entry.trigger);
7512
+ const triggerString = tokensToString(entry.trigger ?? "");
7513
+ const n = triggerLength(trigger);
7514
+ result.lookahead = Math.max(result.lookahead, n);
7515
+ if (indexedEntry.kind === "function") {
7516
+ if (!result.function.has(triggerString))
7517
+ result.function.set(triggerString, [indexedEntry]);
7518
+ else
7519
+ result.function.set(triggerString, [
7520
+ ...result.function.get(triggerString),
7521
+ indexedEntry
7522
+ ]);
7523
+ } else {
7524
+ const kind2 = indexedEntry.kind;
7525
+ if (result[kind2][n] === void 0)
7526
+ result[kind2][n] = /* @__PURE__ */ new Map();
7527
+ const list = result[kind2][n];
7528
+ if (list.has(triggerString))
7529
+ list.get(triggerString).push(indexedEntry);
7530
+ else
7531
+ list.set(triggerString, [indexedEntry]);
7532
+ }
7533
+ }
7534
+ }
7439
7535
  function indexLatexDictionary(dic, onError) {
7440
7536
  const result = {
7441
7537
  lookahead: 1,
7442
7538
  name: /* @__PURE__ */ new Map(),
7539
+ expression: /* @__PURE__ */ new Map(),
7443
7540
  function: /* @__PURE__ */ new Map(),
7444
- identifier: [],
7541
+ symbol: [],
7445
7542
  infix: [],
7446
7543
  prefix: [],
7447
7544
  postfix: [],
7448
7545
  environment: /* @__PURE__ */ new Map(),
7449
7546
  matchfix: []
7450
7547
  };
7451
- for (const entry of dic) {
7452
- const [trigger, indexedEntry] = makeIndexedEntry(entry, onError);
7453
- if (indexedEntry === null)
7454
- continue;
7455
- if (indexedEntry.name !== void 0) {
7456
- if (result.name.has(indexedEntry.name)) {
7457
- onError({
7458
- severity: "warning",
7459
- message: [
7460
- "invalid-dictionary-entry",
7461
- indexedEntry.name,
7462
- "Duplicate definition. The name must be unique, but a trigger can be used by multiple definitions."
7463
- ]
7464
- });
7465
- }
7466
- result.name.set(indexedEntry.name, indexedEntry);
7467
- }
7468
- if (indexedEntry.kind === "matchfix") {
7469
- result.matchfix.push(indexedEntry);
7470
- } else if (indexedEntry.kind === "environment") {
7471
- const triggerString = tokensToString(entry.trigger ?? "");
7472
- if (result.environment.has(triggerString)) {
7473
- onError({
7474
- severity: "warning",
7475
- message: [
7476
- "invalid-dictionary-entry",
7477
- triggerString,
7478
- "Duplicate environment definition"
7479
- ]
7480
- });
7481
- }
7482
- result.environment.set(triggerString, indexedEntry);
7483
- } else if (trigger) {
7484
- console.assert(entry.trigger);
7485
- const triggerString = tokensToString(entry.trigger ?? "");
7486
- const n = triggerLength(trigger);
7487
- result.lookahead = Math.max(result.lookahead, n);
7488
- if (indexedEntry.kind === "function") {
7489
- if (!result.function.has(triggerString))
7490
- result.function.set(triggerString, [indexedEntry]);
7491
- else
7492
- result.function.set(triggerString, [
7493
- ...result.function.get(triggerString),
7494
- indexedEntry
7495
- ]);
7496
- } else if (indexedEntry.kind === "identifier") {
7497
- if (result.identifier[n] === void 0)
7498
- result.identifier[n] = /* @__PURE__ */ new Map();
7499
- const list = result.identifier[n];
7500
- if (list.has(triggerString))
7501
- list.get(triggerString).push(indexedEntry);
7502
- else
7503
- list.set(triggerString, [indexedEntry]);
7504
- } else if (indexedEntry.kind === "prefix") {
7505
- if (result.prefix[n] === void 0)
7506
- result.prefix[n] = /* @__PURE__ */ new Map();
7507
- const list = result.prefix[n];
7508
- if (list.has(triggerString))
7509
- list.get(triggerString).push(indexedEntry);
7510
- else
7511
- list.set(triggerString, [indexedEntry]);
7512
- } else if (indexedEntry.kind === "infix") {
7513
- if (result.infix[n] === void 0)
7514
- result.infix[n] = /* @__PURE__ */ new Map();
7515
- const list = result.infix[n];
7516
- if (list.has(triggerString))
7517
- list.get(triggerString).push(indexedEntry);
7518
- else
7519
- list.set(triggerString, [indexedEntry]);
7520
- } else if (indexedEntry.kind === "postfix") {
7521
- if (result.postfix[n] === void 0)
7522
- result.postfix[n] = /* @__PURE__ */ new Map();
7523
- const list = result.postfix[n];
7524
- if (list.has(triggerString))
7525
- list.get(triggerString).push(indexedEntry);
7526
- else
7527
- list.set(triggerString, [indexedEntry]);
7528
- }
7529
- }
7530
- }
7548
+ for (const entry of dic)
7549
+ addEntry(result, entry, onError);
7531
7550
  return result;
7532
7551
  }
7533
7552
  function makeIndexedEntry(entry, onError) {
@@ -7535,7 +7554,7 @@ var ComputeEngine = (() => {
7535
7554
  return [null, null];
7536
7555
  const result = {
7537
7556
  name: entry.name,
7538
- kind: "kind" in entry ? entry.kind : "identifier"
7557
+ kind: "kind" in entry ? entry.kind : "expression"
7539
7558
  };
7540
7559
  if (result.kind === "matchfix" && isMatchfixEntry(entry)) {
7541
7560
  result.openDelimiter = entry.openDelimiter;
@@ -7568,29 +7587,57 @@ var ComputeEngine = (() => {
7568
7587
  const triggerString = trigger ? tokensToString(trigger) : "";
7569
7588
  if (result.kind === "function" && isFunctionEntry(entry)) {
7570
7589
  result.serialize = entry.serialize;
7571
- if (triggerString && !entry.serialize)
7572
- result.serialize = (serializer, expr) => `\\mathrm{${triggerString}}${serializer.wrapArguments(expr)}`;
7573
- result.parse = entry.parse;
7574
- if (!result.parse && entry.name)
7575
- result.parse = (parser) => {
7576
- const arg = parser.matchArguments("enclosure");
7577
- return arg === null ? entry.name : [entry.name, ...arg];
7578
- };
7590
+ if (triggerString && !entry.serialize) {
7591
+ if (triggerString.startsWith("\\")) {
7592
+ result.serialize = (serializer, expr) => `${triggerString}${serializer.wrapArguments(expr)}`;
7593
+ } else
7594
+ result.serialize = (serializer, expr) => `\\mathrm{${triggerString}}${serializer.wrapArguments(expr)}`;
7595
+ }
7596
+ if (typeof entry.parse === "function")
7597
+ result.parse = entry.parse;
7598
+ else if (typeof entry.parse === "string")
7599
+ result.parse = () => entry.parse;
7600
+ else if (entry.name)
7601
+ result.parse = () => entry.name;
7579
7602
  return [triggerString, result];
7580
7603
  }
7581
- if (typeof entry.trigger === "string") {
7582
- console.assert(
7583
- entry.parse || trigger.length > 1,
7584
- `Trigger shortcut should produce more than one token. Otherwise, not worth using the shortcut. (${triggerString})`
7585
- );
7604
+ if (result.kind === "expression" && isExpressionEntry(entry)) {
7605
+ result.serialize = entry.serialize ?? triggerString;
7606
+ if (typeof result.serialize === "string") {
7607
+ const serializeExpr = result.serialize;
7608
+ result.serialize = (serializer, expr) => {
7609
+ if (!head(expr))
7610
+ return serializer.serialize(serializeExpr);
7611
+ return `${serializer.serialize(
7612
+ serializeExpr
7613
+ )}${serializer.wrapArguments(expr)}`;
7614
+ };
7615
+ }
7616
+ {
7617
+ if (typeof entry.parse === "function") {
7618
+ result.parse = entry.parse;
7619
+ } else {
7620
+ const parseResult = entry.parse ?? entry.name;
7621
+ result.parse = () => parseResult;
7622
+ }
7623
+ }
7624
+ return [triggerString, result];
7586
7625
  }
7587
- if (result.kind === "identifier" && isIdentifierEntry(entry)) {
7626
+ console.assert(
7627
+ typeof entry.trigger !== "string" || entry.parse || trigger.length > 1 || "kind" in entry && entry.kind === "function",
7628
+ `Trigger shortcuts should produce more than one token. Otherwise, not worth using them. (${triggerString})`
7629
+ );
7630
+ if (result.kind === "symbol" && isSymbolEntry(entry)) {
7588
7631
  result.precedence = entry.precedence ?? 1e4;
7589
7632
  }
7590
7633
  if ((result.kind === "infix" || result.kind === "prefix" || result.kind === "postfix") && (isInfixEntry(entry) || isPrefixEntry(entry) || isPostfixEntry(entry))) {
7591
- if (trigger && (trigger[0] === "^" || trigger[0] === "_"))
7634
+ if (trigger && (trigger[0] === "^" || trigger[0] === "_")) {
7592
7635
  result.precedence = 720;
7593
- else
7636
+ console.assert(
7637
+ entry.precedence === void 0,
7638
+ "'precedence' not allowed with ^ and _ triggers"
7639
+ );
7640
+ } else
7594
7641
  result.precedence = entry.precedence ?? 1e4;
7595
7642
  }
7596
7643
  if (result.kind === "infix" && isInfixEntry(entry)) {
@@ -7603,7 +7650,7 @@ var ComputeEngine = (() => {
7603
7650
  } else if (trigger && (trigger[0] === "^" || trigger[0] === "_")) {
7604
7651
  console.assert(!entry.parse);
7605
7652
  const name = entry.parse ?? entry.name;
7606
- result.parse = (_scanner, _terminator, arg) => [
7653
+ result.parse = (_scanner, arg, _terminator) => [
7607
7654
  name,
7608
7655
  missingIfEmpty(op(arg, 1)),
7609
7656
  missingIfEmpty(op(arg, 2))
@@ -7612,11 +7659,11 @@ var ComputeEngine = (() => {
7612
7659
  const head2 = entry.parse ?? entry.name;
7613
7660
  const prec = result.precedence;
7614
7661
  const associativity = result.associativity;
7615
- result.parse = (scanner, terminator, lhs) => {
7662
+ result.parse = (scanner, lhs, terminator) => {
7616
7663
  if (prec < terminator.minPrec)
7617
7664
  return null;
7618
7665
  const rhs = missingIfEmpty(
7619
- scanner.matchExpression({
7666
+ scanner.parseExpression({
7620
7667
  ...terminator,
7621
7668
  minPrec: prec
7622
7669
  })
@@ -7628,7 +7675,7 @@ var ComputeEngine = (() => {
7628
7675
  if (typeof entry.parse === "function") {
7629
7676
  result.parse = entry.parse;
7630
7677
  } else if (entry.parse !== void 0) {
7631
- console.assert(result.kind === "identifier");
7678
+ console.assert(result.kind === "symbol" || result.kind === "expression");
7632
7679
  result.parse = () => entry.parse;
7633
7680
  } else if (entry.parse === void 0 && entry.name !== void 0) {
7634
7681
  if (result.kind === "postfix") {
@@ -7638,9 +7685,9 @@ var ComputeEngine = (() => {
7638
7685
  console.assert(entry.name);
7639
7686
  const head2 = entry.name;
7640
7687
  result.parse = (parser, terminator) => {
7641
- if (prec < terminator.minPrec)
7688
+ if (terminator && prec < terminator.minPrec)
7642
7689
  return null;
7643
- const rhs = parser.matchExpression({ ...terminator, minPrec: prec });
7690
+ const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
7644
7691
  return rhs === null ? null : [head2, rhs];
7645
7692
  };
7646
7693
  }
@@ -7655,7 +7702,7 @@ var ComputeEngine = (() => {
7655
7702
  result.serialize = triggerString + "#1";
7656
7703
  } else if (result.kind === "infix") {
7657
7704
  result.serialize = "#1" + triggerString + "#2";
7658
- } else if (result.kind === "identifier") {
7705
+ } else if (result.kind === "symbol") {
7659
7706
  result.serialize = triggerString;
7660
7707
  } else {
7661
7708
  result.serialize = "";
@@ -7785,6 +7832,7 @@ var ComputeEngine = (() => {
7785
7832
  physics: [
7786
7833
  {
7787
7834
  name: "mu0",
7835
+ kind: "symbol",
7788
7836
  trigger: "\\mu_0"
7789
7837
  }
7790
7838
  ],
@@ -7834,6 +7882,7 @@ var ComputeEngine = (() => {
7834
7882
  special = {
7835
7883
  "+": "plus",
7836
7884
  "-": "minus",
7885
+ "\\plusmn": "pm",
7837
7886
  "\\pm": "pm",
7838
7887
  "\\ast": "ast",
7839
7888
  "\\dag": "dag",
@@ -7849,22 +7898,22 @@ var ComputeEngine = (() => {
7849
7898
  }[token];
7850
7899
  }
7851
7900
  if (special) {
7852
- parser.next();
7901
+ parser.nextToken();
7853
7902
  return special;
7854
7903
  }
7855
7904
  const i = SYMBOLS.findIndex((x) => x[1] === token);
7856
7905
  if (i >= 0) {
7857
- parser.next();
7906
+ parser.nextToken();
7858
7907
  return SYMBOLS[i][0];
7859
7908
  }
7860
- return parser.matchChar() ?? parser.next();
7909
+ return parser.matchChar() ?? parser.nextToken();
7861
7910
  }
7862
7911
  function matchIdentifierBody(parser) {
7863
7912
  let id = matchPrefixedIdentifier(parser);
7864
7913
  const start = parser.index;
7865
7914
  const prefix = IDENTIFIER_MODIFIER[parser.peek] ?? null;
7866
7915
  if (prefix) {
7867
- parser.next();
7916
+ parser.nextToken();
7868
7917
  if (!parser.match("<{>")) {
7869
7918
  parser.index = start;
7870
7919
  return null;
@@ -7890,7 +7939,7 @@ var ComputeEngine = (() => {
7890
7939
  id += next;
7891
7940
  }
7892
7941
  while (!parser.atEnd && /\d/.test(parser.peek))
7893
- id += parser.next();
7942
+ id += parser.nextToken();
7894
7943
  }
7895
7944
  while (!parser.atEnd) {
7896
7945
  if (parser.match("\\degree"))
@@ -7939,7 +7988,7 @@ var ComputeEngine = (() => {
7939
7988
  const prefix = IDENTIFIER_PREFIX[parser.peek] ?? null;
7940
7989
  if (prefix === null)
7941
7990
  return null;
7942
- parser.next();
7991
+ parser.nextToken();
7943
7992
  if (parser.match("<{>")) {
7944
7993
  let body = "";
7945
7994
  const digit = {
@@ -7956,7 +8005,7 @@ var ComputeEngine = (() => {
7956
8005
  }[parser.peek] ?? "";
7957
8006
  if (digit) {
7958
8007
  body = digit;
7959
- parser.next();
8008
+ parser.nextToken();
7960
8009
  }
7961
8010
  body += matchIdentifierBody(parser);
7962
8011
  if (body === null || !parser.match("<}>")) {
@@ -7970,7 +8019,7 @@ var ComputeEngine = (() => {
7970
8019
  parser.index = start;
7971
8020
  return null;
7972
8021
  }
7973
- function matchInvalidIdentifier(parser) {
8022
+ function parseInvalidIdentifier(parser) {
7974
8023
  const start = parser.index;
7975
8024
  const id = matchPrefixedIdentifier(parser);
7976
8025
  if (id === null || isValidIdentifier(id)) {
@@ -7984,13 +8033,13 @@ var ComputeEngine = (() => {
7984
8033
  }
7985
8034
  function matchIdentifier(parser) {
7986
8035
  if (/^[a-zA-Z]$/.test(parser.peek) || /^\p{XIDS}$/u.test(parser.peek))
7987
- return parser.next();
8036
+ return parser.nextToken();
7988
8037
  const start = parser.index;
7989
8038
  let id = matchPrefixedIdentifier(parser);
7990
8039
  if (!id) {
7991
8040
  id = "";
7992
8041
  while (!parser.atEnd && ONLY_EMOJIS.test(id + parser.peek))
7993
- id += parser.next();
8042
+ id += parser.nextToken();
7994
8043
  }
7995
8044
  if (id) {
7996
8045
  id = id.normalize();
@@ -8037,10 +8086,6 @@ var ComputeEngine = (() => {
8037
8086
  "\\lmoustache": ["\\lmoustache"],
8038
8087
  "\\rmoustache": ["\\rmoustache"]
8039
8088
  };
8040
- var MIDDLE_DELIMITER = {
8041
- ":": [":", "\\colon"],
8042
- "|": ["|", "\\|", "\\mid", "\\mvert"]
8043
- };
8044
8089
  var OPEN_DELIMITER_PREFIX = {
8045
8090
  "\\left": "\\right",
8046
8091
  "\\bigl": "\\bigr",
@@ -8052,17 +8097,6 @@ var ComputeEngine = (() => {
8052
8097
  "\\bigg": "\\bigg",
8053
8098
  "\\Bigg": "\\Bigg"
8054
8099
  };
8055
- var MIDDLE_DELIMITER_PREFIX = [
8056
- "\\middle",
8057
- "\\bigm",
8058
- "\\Bigm",
8059
- "\\biggm",
8060
- "\\Biggm",
8061
- "\\big",
8062
- "\\Big",
8063
- "\\bigg",
8064
- "\\Bigg"
8065
- ];
8066
8100
  var CLOSE_DELIMITER = {
8067
8101
  "(": ")",
8068
8102
  "[": "]",
@@ -8217,7 +8251,7 @@ var ComputeEngine = (() => {
8217
8251
  this._lastPeek = peek;
8218
8252
  return peek;
8219
8253
  }
8220
- next() {
8254
+ nextToken() {
8221
8255
  return this._tokens[this.index++];
8222
8256
  }
8223
8257
  /**
@@ -8270,15 +8304,14 @@ var ComputeEngine = (() => {
8270
8304
  latexAhead(n) {
8271
8305
  return this.latex(this.index, this.index + n);
8272
8306
  }
8273
- latexBefore() {
8274
- return this.latex(0, this.index);
8275
- }
8276
- latexAfter() {
8277
- return this.latex(this.index);
8278
- }
8307
+ // latexBefore(): string {
8308
+ // return this.latex(0, this.index);
8309
+ // }
8310
+ // latexAfter(): string {
8311
+ // return this.latex(this.index);
8312
+ // }
8279
8313
  /**
8280
- * Return at most `this._dictionary.lookahead` strings made from the tokens
8281
- * ahead.
8314
+ * Return at most `this._dictionary.lookahead` LaTeX tokens.
8282
8315
  *
8283
8316
  * The index in the returned array correspond to the number of tokens.
8284
8317
  * Note that since a token can be longer than one char ('\\pi', but also
@@ -8286,6 +8319,10 @@ var ComputeEngine = (() => {
8286
8319
  * does not match that index. However, knowing the index is important
8287
8320
  * to know by how many tokens to advance.
8288
8321
  *
8322
+ * For example:
8323
+ *
8324
+ * `[empty, '\\sqrt', '\\sqrt{', '\\sqrt{2', '\\sqrt{2}']`
8325
+ *
8289
8326
  */
8290
8327
  lookAhead() {
8291
8328
  let n = Math.min(
@@ -8304,12 +8341,12 @@ var ComputeEngine = (() => {
8304
8341
  if (kind === "function") {
8305
8342
  const start = this.index;
8306
8343
  if (this.match("\\operatorname") || this.match("\\mathrm") || this.match("\\mathit")) {
8307
- const fn = this.matchStringArgument();
8344
+ const fn = this.parseStringGroup()?.trim();
8308
8345
  const n = this.index - start;
8309
8346
  this.index = start;
8310
- if (fn !== null && this._dictionary.function.has(fn))
8311
- return this._dictionary.function.get(fn).map((x) => [x, n]);
8312
- return null;
8347
+ if (!fn || !this._dictionary.function.has(fn))
8348
+ return null;
8349
+ return this._dictionary.function.get(fn).map((x) => [x, n]);
8313
8350
  }
8314
8351
  return null;
8315
8352
  } else if (kind === "operator") {
@@ -8342,19 +8379,19 @@ var ComputeEngine = (() => {
8342
8379
  * instead.
8343
8380
  */
8344
8381
  skipSpace() {
8345
- if (!this.options.skipSpace)
8346
- return false;
8347
8382
  if (!this.atEnd && this.peek === "<{>") {
8348
8383
  const index = this.index;
8349
- this.next();
8384
+ this.nextToken();
8350
8385
  while (this.match("<space>")) {
8351
8386
  }
8352
- if (this.next() === "<}>") {
8387
+ if (this.nextToken() === "<}>") {
8353
8388
  this.skipSpace();
8354
8389
  return true;
8355
8390
  }
8356
8391
  this.index = index;
8357
8392
  }
8393
+ if (!this.options.skipSpace)
8394
+ return false;
8358
8395
  let result = false;
8359
8396
  while (this.match("<space>"))
8360
8397
  result = true;
@@ -8377,11 +8414,36 @@ var ComputeEngine = (() => {
8377
8414
  "\\quad",
8378
8415
  "\\qquad"
8379
8416
  ].includes(this.peek)) {
8380
- this.next();
8417
+ this.nextToken();
8381
8418
  this.skipVisualSpace();
8382
8419
  }
8383
8420
  this.skipSpace();
8384
8421
  }
8422
+ match(token) {
8423
+ if (this._tokens[this.index] === token) {
8424
+ this.index++;
8425
+ return true;
8426
+ }
8427
+ return false;
8428
+ }
8429
+ matchAll(tokens) {
8430
+ console.assert(Array.isArray(tokens));
8431
+ if (tokens.length === 0)
8432
+ return false;
8433
+ let matched = true;
8434
+ let i = 0;
8435
+ do {
8436
+ matched = this._tokens[this.index + i] === tokens[i++];
8437
+ } while (matched && i < tokens.length);
8438
+ if (matched)
8439
+ this.index += i;
8440
+ return matched;
8441
+ }
8442
+ matchAny(tokens) {
8443
+ if (tokens.includes(this._tokens[this.index]))
8444
+ return this._tokens[this.index++];
8445
+ return "";
8446
+ }
8385
8447
  matchChar() {
8386
8448
  const index = this.index;
8387
8449
  let caretCount = 0;
@@ -8428,7 +8490,7 @@ var ComputeEngine = (() => {
8428
8490
  } else if (this.match("\\unicode")) {
8429
8491
  this.skipSpaceTokens();
8430
8492
  if (this.peek === "<{>") {
8431
- this.next();
8493
+ this.nextToken();
8432
8494
  const codepoint = this.matchLatexNumber();
8433
8495
  if (this.match("<}>") && codepoint !== null && codepoint >= 0 && codepoint <= 1114111) {
8434
8496
  return String.fromCodePoint(codepoint);
@@ -8443,62 +8505,171 @@ var ComputeEngine = (() => {
8443
8505
  this.index = index;
8444
8506
  return null;
8445
8507
  }
8446
- matchColor(_background = false) {
8447
- let s = "";
8448
- while (!this.atEnd && this.peek !== "}")
8449
- s += this.next();
8450
- return s;
8451
- }
8452
- matchLatexDimension() {
8453
- return null;
8454
- }
8455
- match(token) {
8456
- if (this._tokens[this.index] === token) {
8457
- this.index++;
8458
- return true;
8508
+ parseGroup() {
8509
+ const start = this.index;
8510
+ this.skipSpaceTokens();
8511
+ if (this.match("<{>")) {
8512
+ this.addBoundary(["<}>"]);
8513
+ const expr = this.parseExpression();
8514
+ this.skipSpace();
8515
+ if (this.matchBoundary())
8516
+ return expr ?? ["Sequence"];
8517
+ const from = this.index;
8518
+ while (!this.matchBoundary() && !this.atEnd)
8519
+ this.nextToken();
8520
+ const err = this.error("syntax-error", from);
8521
+ return expr ? ["Sequence", expr, err] : err;
8459
8522
  }
8460
- return false;
8523
+ this.index = start;
8524
+ return null;
8461
8525
  }
8462
- matchAll(tokens) {
8463
- if (typeof tokens === "string")
8464
- tokens = [tokens];
8465
- if (tokens.length === 0)
8466
- return false;
8467
- let matched = true;
8468
- let i = 0;
8469
- do {
8470
- matched = this._tokens[this.index + i] === tokens[i++];
8471
- } while (matched && i < tokens.length);
8472
- if (matched)
8473
- this.index += i;
8474
- return matched;
8526
+ // Some LaTeX commands (but not all) can accept an argument without braces,
8527
+ // for example `^` , `\sqrt` or `\frac`.
8528
+ // This argument will usually be a single token, but can be a sequence of
8529
+ // tokens (e.g. `\sqrt\frac12` or `\sqrt\mathrm{speed}`).
8530
+ parseToken() {
8531
+ const excluding = [
8532
+ ...'!"#$%&(),/;:?@[]\\`|~'.split(""),
8533
+ "\\left",
8534
+ "\\bigl"
8535
+ ];
8536
+ if (excluding.includes(this.peek))
8537
+ return null;
8538
+ if (/^[0-9]$/.test(this.peek))
8539
+ return parseInt(this.nextToken());
8540
+ const result = this.parseGenericExpression() ?? this.parseSymbol();
8541
+ if (!result)
8542
+ return null;
8543
+ return result;
8475
8544
  }
8476
- matchAny(tokens) {
8477
- if (tokens.includes(this._tokens[this.index]))
8478
- return this._tokens[this.index++];
8479
- return "";
8545
+ parseOptionalGroup() {
8546
+ const index = this.index;
8547
+ this.skipSpaceTokens();
8548
+ if (this.match("[")) {
8549
+ this.addBoundary(["]"]);
8550
+ const expr = this.parseExpression();
8551
+ this.skipSpace();
8552
+ if (this.matchBoundary())
8553
+ return expr;
8554
+ return this.boundaryError("expected-closing-delimiter");
8555
+ }
8556
+ this.index = index;
8557
+ return null;
8480
8558
  }
8481
- matchSequence(tokens) {
8559
+ /**
8560
+ * Parse an expression in a tabular format, where rows are separated by `\\`
8561
+ * and columns by `&`.
8562
+ *
8563
+ * Return rows of sparse columns: empty rows are indicated with `Nothing`,
8564
+ * and empty cells are also indicated with `Nothing`.
8565
+ */
8566
+ parseTabular() {
8482
8567
  const result = [];
8483
- while (tokens.includes(this._tokens[this.index]))
8484
- result.push(this._tokens[this.index++]);
8568
+ let row = [];
8569
+ let expr = null;
8570
+ while (!this.atBoundary) {
8571
+ this.skipSpace();
8572
+ if (this.match("&")) {
8573
+ row.push(expr ?? "Nothing");
8574
+ expr = null;
8575
+ } else if (this.match("\\\\") || this.match("\\cr")) {
8576
+ this.skipSpace();
8577
+ this.parseOptionalGroup();
8578
+ if (expr !== null)
8579
+ row.push(expr);
8580
+ result.push(row);
8581
+ row = [];
8582
+ expr = null;
8583
+ } else {
8584
+ const cell = [];
8585
+ let peek = this.peek;
8586
+ while (peek !== "&" && peek !== "\\\\" && peek !== "\\cr" && !this.atBoundary) {
8587
+ expr = this.parseExpression({
8588
+ condition: (p) => {
8589
+ const peek2 = p.peek;
8590
+ return peek2 === "&" || peek2 === "\\\\" || peek2 === "\\cr";
8591
+ }
8592
+ });
8593
+ if (expr)
8594
+ cell.push(expr);
8595
+ else {
8596
+ cell.push(["Error", ["'unexpected-token'", peek]]);
8597
+ this.nextToken();
8598
+ }
8599
+ this.skipSpace();
8600
+ peek = this.peek;
8601
+ }
8602
+ if (cell.length > 1)
8603
+ expr = ["Sequence", ...cell];
8604
+ else
8605
+ expr = cell[0] ?? "Nothing";
8606
+ }
8607
+ }
8608
+ if (expr !== null)
8609
+ row.push(expr);
8610
+ if (row.length > 0)
8611
+ result.push(row);
8485
8612
  return result;
8486
8613
  }
8487
- matchOptionalSign() {
8614
+ /** Parse a group as a a string, for example for `\operatorname` or `\begin` */
8615
+ parseStringGroup() {
8616
+ const start = this.index;
8617
+ while (this.match("<space>")) {
8618
+ }
8619
+ if (this.match("<{>")) {
8620
+ this.addBoundary(["<}>"]);
8621
+ const arg = this.parseStringGroupContent();
8622
+ if (this.matchBoundary())
8623
+ return arg;
8624
+ this.removeBoundary();
8625
+ }
8626
+ this.index = start;
8627
+ return null;
8628
+ }
8629
+ /** Parse an environment: `\begin{env}...\end{end}`
8630
+ */
8631
+ parseEnvironment() {
8632
+ const index = this.index;
8633
+ if (!this.match("\\begin"))
8634
+ return null;
8635
+ const name = this.parseStringGroup()?.trim();
8636
+ if (!name)
8637
+ return this.error("expected-environment-name", index);
8638
+ this.addBoundary(["\\end", "<{>", ...name.split(""), "<}>"]);
8639
+ const def = this._dictionary.environment.get(name);
8640
+ if (!def) {
8641
+ this.parseTabular();
8642
+ this.skipSpace();
8643
+ if (!this.matchBoundary())
8644
+ return this.boundaryError("unbalanced-environment");
8645
+ return this.error(["unknown-environment", { str: name }], index);
8646
+ }
8647
+ const expr = def.parse(this, [], []);
8648
+ this.skipSpace();
8649
+ if (!this.matchBoundary())
8650
+ return this.boundaryError("unbalanced-environment");
8651
+ if (expr !== null)
8652
+ return this.decorate(expr, index);
8653
+ this.index = index;
8654
+ return null;
8655
+ }
8656
+ /** If the next token matches a `+` or `-` sign, return it and advance the index.
8657
+ * Otherwise return `''` and do not advance */
8658
+ parseOptionalSign() {
8488
8659
  let isNegative = !!this.matchAny(["-", "\u2212"]);
8489
8660
  while (this.matchAny(["+", "\uFE62"]) || this.skipSpace())
8490
8661
  if (this.matchAny(["-", "\u2212"]))
8491
8662
  isNegative = !isNegative;
8492
8663
  return isNegative ? "-" : "+";
8493
8664
  }
8494
- matchDecimalDigits(options) {
8665
+ parseDecimalDigits(options) {
8495
8666
  options ?? (options = {});
8496
8667
  options.withGrouping ?? (options.withGrouping = false);
8497
8668
  const result = [];
8498
8669
  let done = false;
8499
8670
  while (!done) {
8500
8671
  while (/^[0-9]$/.test(this.peek)) {
8501
- result.push(this.next());
8672
+ result.push(this.nextToken());
8502
8673
  this.skipVisualSpace();
8503
8674
  }
8504
8675
  done = true;
@@ -8516,21 +8687,21 @@ var ComputeEngine = (() => {
8516
8687
  }
8517
8688
  return result.join("");
8518
8689
  }
8519
- matchSignedInteger(options) {
8690
+ parseSignedInteger(options) {
8520
8691
  options ?? (options = {});
8521
8692
  options.withGrouping ?? (options.withGrouping = false);
8522
8693
  const start = this.index;
8523
- const sign2 = this.matchOptionalSign();
8524
- const result = this.matchDecimalDigits(options);
8694
+ const sign2 = this.parseOptionalSign();
8695
+ const result = this.parseDecimalDigits(options);
8525
8696
  if (result)
8526
8697
  return sign2 === "-" ? "-" + result : result;
8527
8698
  this.index = start;
8528
8699
  return "";
8529
8700
  }
8530
- matchExponent() {
8701
+ parseExponent() {
8531
8702
  const start = this.index;
8532
8703
  if (this.matchAny(["e", "E"])) {
8533
- const exponent = this.matchSignedInteger({ withGrouping: false });
8704
+ const exponent = this.parseSignedInteger({ withGrouping: false });
8534
8705
  if (exponent)
8535
8706
  return "e" + exponent;
8536
8707
  }
@@ -8539,10 +8710,10 @@ var ComputeEngine = (() => {
8539
8710
  this.skipSpaceTokens();
8540
8711
  if (this.match("1") && this.match("0") && this.match("^")) {
8541
8712
  if (/^[0-9]$/.test(this.peek))
8542
- return "e" + this.next();
8713
+ return "e" + this.nextToken();
8543
8714
  if (this.match("<{>")) {
8544
8715
  this.skipSpaceTokens();
8545
- const exponent = this.matchSignedInteger();
8716
+ const exponent = this.parseSignedInteger();
8546
8717
  this.skipSpaceTokens();
8547
8718
  if (this.match("<}>") && exponent)
8548
8719
  return "e" + exponent;
@@ -8558,7 +8729,7 @@ var ComputeEngine = (() => {
8558
8729
  this.skipSpaceTokens();
8559
8730
  if (this.matchAll(this._beginExponentMarkerTokens)) {
8560
8731
  this.skipSpaceTokens();
8561
- const exponent = this.matchSignedInteger();
8732
+ const exponent = this.parseSignedInteger();
8562
8733
  this.skipSpaceTokens();
8563
8734
  if (this.matchAll(this._endExponentMarkerTokens) && exponent)
8564
8735
  return "e" + exponent;
@@ -8567,11 +8738,11 @@ var ComputeEngine = (() => {
8567
8738
  this.index = start;
8568
8739
  return "";
8569
8740
  }
8570
- matchRepeatingDecimal() {
8741
+ parseRepeatingDecimal() {
8571
8742
  const start = this.index;
8572
8743
  let repeatingDecimals2 = "";
8573
8744
  if (this.match("(")) {
8574
- repeatingDecimals2 = this.matchDecimalDigits();
8745
+ repeatingDecimals2 = this.parseDecimalDigits();
8575
8746
  if (repeatingDecimals2 && this.match(")"))
8576
8747
  return "(" + repeatingDecimals2 + ")";
8577
8748
  this.index = start;
@@ -8579,7 +8750,7 @@ var ComputeEngine = (() => {
8579
8750
  }
8580
8751
  this.index = start;
8581
8752
  if (this.matchAll([`\\left`, "("])) {
8582
- repeatingDecimals2 = this.matchDecimalDigits();
8753
+ repeatingDecimals2 = this.parseDecimalDigits();
8583
8754
  if (repeatingDecimals2 && this.matchAll([`\\right`, ")"]))
8584
8755
  return "(" + repeatingDecimals2 + ")";
8585
8756
  this.index = start;
@@ -8587,7 +8758,7 @@ var ComputeEngine = (() => {
8587
8758
  }
8588
8759
  this.index = start;
8589
8760
  if (this.matchAll([`\\overline`, "<{>"])) {
8590
- repeatingDecimals2 = this.matchDecimalDigits();
8761
+ repeatingDecimals2 = this.parseDecimalDigits();
8591
8762
  if (repeatingDecimals2 && this.match("<}>"))
8592
8763
  return "(" + repeatingDecimals2 + ")";
8593
8764
  this.index = start;
@@ -8595,7 +8766,7 @@ var ComputeEngine = (() => {
8595
8766
  }
8596
8767
  this.index = start;
8597
8768
  if (this.matchAll(this._beginRepeatingDigitsTokens)) {
8598
- repeatingDecimals2 = this.matchDecimalDigits();
8769
+ repeatingDecimals2 = this.parseDecimalDigits();
8599
8770
  if (repeatingDecimals2 && this.matchAll(this._endRepeatingDigitsTokens))
8600
8771
  return "(" + repeatingDecimals2 + ")";
8601
8772
  this.index = start;
@@ -8604,9 +8775,13 @@ var ComputeEngine = (() => {
8604
8775
  this.index = start;
8605
8776
  return "";
8606
8777
  }
8607
- matchNumber() {
8778
+ /**
8779
+ * Parse a number, with an optional sign, exponent, decimal marker,
8780
+ * repeating decimals, etc...
8781
+ */
8782
+ parseNumber() {
8608
8783
  if (!this.options.parseNumbers)
8609
- return "";
8784
+ return null;
8610
8785
  const start = this.index;
8611
8786
  this.skipVisualSpace();
8612
8787
  this.match("+");
@@ -8616,32 +8791,32 @@ var ComputeEngine = (() => {
8616
8791
  const peek = this.peek;
8617
8792
  if (peek !== "\\overline" && peek !== this._beginRepeatingDigitsTokens[0] && !/[0-9\(]/.test(peek)) {
8618
8793
  this.index = start;
8619
- return "";
8794
+ return null;
8620
8795
  }
8621
8796
  dotPrefix = true;
8622
8797
  } else {
8623
- result = this.matchDecimalDigits({ withGrouping: true });
8798
+ result = this.parseDecimalDigits({ withGrouping: true });
8624
8799
  if (!result) {
8625
8800
  this.index = start;
8626
- return "";
8801
+ return null;
8627
8802
  }
8628
8803
  }
8629
8804
  let hasDecimal = true;
8630
8805
  if (!dotPrefix && (this.match(".") || this.matchAll(this._decimalMarkerTokens)))
8631
- result += "." + this.matchDecimalDigits({ withGrouping: true });
8806
+ result += "." + this.parseDecimalDigits({ withGrouping: true });
8632
8807
  else if (dotPrefix)
8633
- result = "0." + this.matchDecimalDigits({ withGrouping: true });
8808
+ result = "0." + this.parseDecimalDigits({ withGrouping: true });
8634
8809
  else
8635
8810
  hasDecimal = false;
8636
8811
  if (hasDecimal) {
8637
- const repeat = this.matchRepeatingDecimal();
8812
+ const repeat = this.parseRepeatingDecimal();
8638
8813
  if (repeat)
8639
8814
  result += repeat;
8640
8815
  else if (this.match("\\ldots") || this.matchAll(this._truncationMarkerTokens)) {
8641
8816
  }
8642
8817
  }
8643
8818
  this.skipVisualSpace();
8644
- return result + this.matchExponent();
8819
+ return result + this.parseExponent();
8645
8820
  }
8646
8821
  /**
8647
8822
  * A Latex number can be a decimal, hex or octal number.
@@ -8660,7 +8835,7 @@ var ComputeEngine = (() => {
8660
8835
  while (token === "<space>" || token === "+" || token === "-") {
8661
8836
  if (token === "-")
8662
8837
  negative = !negative;
8663
- this.next();
8838
+ this.nextToken();
8664
8839
  token = this.peek;
8665
8840
  }
8666
8841
  let radix = 10;
@@ -8691,7 +8866,7 @@ var ComputeEngine = (() => {
8691
8866
  ];
8692
8867
  isInteger = true;
8693
8868
  } else if (this.match("`")) {
8694
- token = this.next();
8869
+ token = this.nextToken();
8695
8870
  if (token) {
8696
8871
  if (token.startsWith("\\") && token.length === 2) {
8697
8872
  return (negative ? -1 : 1) * (token.codePointAt(1) ?? 0);
@@ -8702,12 +8877,12 @@ var ComputeEngine = (() => {
8702
8877
  }
8703
8878
  let value = "";
8704
8879
  while (digits.includes(this.peek)) {
8705
- value += this.next();
8880
+ value += this.nextToken();
8706
8881
  }
8707
8882
  if (!isInteger && this.match(".")) {
8708
8883
  value += ".";
8709
8884
  while (digits.includes(this.peek)) {
8710
- value += this.next();
8885
+ value += this.nextToken();
8711
8886
  }
8712
8887
  }
8713
8888
  const result = isInteger ? Number.parseInt(value, radix) : Number.parseFloat(value);
@@ -8715,7 +8890,7 @@ var ComputeEngine = (() => {
8715
8890
  return null;
8716
8891
  return negative ? -result : result;
8717
8892
  }
8718
- matchPrefixOperator(until) {
8893
+ parsePrefixOperator(until) {
8719
8894
  if (!until)
8720
8895
  until = { minPrec: 0 };
8721
8896
  if (!until.minPrec)
@@ -8733,7 +8908,7 @@ var ComputeEngine = (() => {
8733
8908
  this.index = start;
8734
8909
  return null;
8735
8910
  }
8736
- matchInfixOperator(lhs, until) {
8911
+ parseInfixOperator(lhs, until) {
8737
8912
  until ?? (until = { minPrec: 0 });
8738
8913
  if (until.minPrec === void 0)
8739
8914
  until = { ...until, minPrec: 0 };
@@ -8744,7 +8919,7 @@ var ComputeEngine = (() => {
8744
8919
  for (const [def, n] of defs) {
8745
8920
  if (def.precedence >= until.minPrec) {
8746
8921
  this.index = start + n;
8747
- const rhs = def.parse(this, until, lhs);
8922
+ const rhs = def.parse(this, lhs, until);
8748
8923
  if (rhs)
8749
8924
  return rhs;
8750
8925
  }
@@ -8753,93 +8928,74 @@ var ComputeEngine = (() => {
8753
8928
  return null;
8754
8929
  }
8755
8930
  /**
8756
- * - 'enclosure' : will look for an argument inside an enclosure (open/close fence)
8931
+ * This returns an array of arguments (as in a function application),
8932
+ * or null if there is no match.
8933
+ *
8934
+ * - 'enclosure' : will look for an argument inside an enclosure
8935
+ * (open/close fence)
8757
8936
  * - 'implicit': either an expression inside a pair of `()`, or just a product
8758
8937
  * (i.e. we interpret `\cos 2x + 1` as `\cos(2x) + 1`)
8759
8938
  *
8760
- * This returns an array of arguments, or null if there is no match.
8761
8939
  */
8762
- matchArguments(kind, until) {
8763
- if (!kind)
8764
- return null;
8940
+ parseArguments(kind = "enclosure", until) {
8765
8941
  if (this.atTerminator(until))
8766
8942
  return null;
8767
8943
  const savedIndex = this.index;
8768
- const group = this.matchEnclosure();
8769
- if (kind === "enclosure")
8944
+ const group = this.parseEnclosure();
8945
+ if (kind === "enclosure") {
8946
+ if (group === null)
8947
+ return null;
8770
8948
  return getSequence(group) ?? [];
8949
+ }
8771
8950
  if (kind === "implicit") {
8772
8951
  if (head(group) === "Delimiter")
8773
8952
  return getSequence(group) ?? [];
8774
- if (group !== null)
8775
- return [group];
8776
- const primary = this.matchExpression({ ...until, minPrec: 390 });
8777
- return primary === null ? null : [primary];
8778
- }
8779
- this.index = savedIndex;
8780
- return null;
8781
- }
8782
- /**
8783
- * A function can be followed by the following suffixes:
8784
- * - a `\prime`, `\doubleprime`, `'`, `(n)` to indicate a derivative
8785
- * - a subscript to indicate an argument
8786
- * - an argument, optionally inside an enclosure
8787
- */
8788
- matchFunctionSuffix(id) {
8789
- let fn = id;
8790
- do {
8791
- const pf = this.matchPostfix(fn);
8792
- if (pf === null)
8793
- break;
8794
- fn = pf;
8795
- } while (true);
8796
- const seq = this.matchArguments("enclosure");
8797
- return seq ? [fn, ...seq] : fn;
8953
+ if (group !== null)
8954
+ return [group];
8955
+ const primary = this.parseExpression({ ...until, minPrec: 390 });
8956
+ return primary === null ? null : [primary];
8957
+ }
8958
+ this.index = savedIndex;
8959
+ return null;
8798
8960
  }
8799
8961
  /** A prime suffix is a sequence of `'`, `\prime` or `\doubleprime`
8800
8962
  * after a function or in a superscript.
8801
8963
  */
8802
- matchPrimeSuffix() {
8803
- this.skipSpace();
8804
- const start = this.index;
8805
- let count = 0;
8806
- if (this.match("^")) {
8807
- if (this.match("<{>")) {
8808
- if (this.match("(")) {
8809
- const n = this.matchNumber();
8810
- if (n && this.match(")"))
8811
- return parseInt(n);
8812
- this.index = start;
8813
- return 0;
8814
- }
8815
- do {
8816
- const c = countPrimeLevel(this);
8817
- if (c === 0)
8818
- break;
8819
- count += c;
8820
- } while (true);
8821
- if (count !== 0 && this.match("<}>"))
8822
- return count;
8823
- this.index = start;
8824
- return 0;
8825
- }
8826
- count = countPrimeLevel(this);
8827
- if (count !== 0)
8828
- return count;
8829
- this.index = start;
8830
- return 0;
8831
- }
8832
- do {
8833
- const c = countPrimeLevel(this);
8834
- if (c === 0)
8835
- break;
8836
- count += c;
8837
- } while (true);
8838
- if (count !== 0)
8839
- return count;
8840
- this.index = start;
8841
- return 0;
8842
- }
8964
+ // matchPrimeSuffix(): number {
8965
+ // this.skipSpace();
8966
+ // const start = this.index;
8967
+ // let count = 0;
8968
+ // if (this.match('^')) {
8969
+ // if (this.match('<{>')) {
8970
+ // if (this.match('(')) {
8971
+ // const n = this.parseNumber();
8972
+ // if (n && this.match(')')) return parseInt(n);
8973
+ // this.index = start;
8974
+ // return 0;
8975
+ // }
8976
+ // do {
8977
+ // const c = countPrimeLevel(this);
8978
+ // if (c === 0) break;
8979
+ // count += c;
8980
+ // } while (true);
8981
+ // if (count !== 0 && this.match('<}>')) return count;
8982
+ // this.index = start;
8983
+ // return 0;
8984
+ // }
8985
+ // count = countPrimeLevel(this);
8986
+ // if (count !== 0) return count;
8987
+ // this.index = start;
8988
+ // return 0;
8989
+ // }
8990
+ // do {
8991
+ // const c = countPrimeLevel(this);
8992
+ // if (c === 0) break;
8993
+ // count += c;
8994
+ // } while (true);
8995
+ // if (count !== 0) return count;
8996
+ // this.index = start;
8997
+ // return 0;
8998
+ // }
8843
8999
  /** If matches the normalized open delimiter, return the
8844
9000
  * expected closing delimiter.
8845
9001
  *
@@ -8852,7 +9008,7 @@ var ComputeEngine = (() => {
8852
9008
  const index = this.index;
8853
9009
  const closePrefix = OPEN_DELIMITER_PREFIX[this.peek];
8854
9010
  if (closePrefix)
8855
- this.next();
9011
+ this.nextToken();
8856
9012
  const alternatives = DELIMITER_SHORTHAND[openDelim] ?? [openDelim];
8857
9013
  const result = closePrefix ? [closePrefix] : [];
8858
9014
  if (alternatives.includes("||") && this.matchAll(["|", "|"])) {
@@ -8869,28 +9025,30 @@ var ComputeEngine = (() => {
8869
9025
  } else {
8870
9026
  result.push(closeDelim);
8871
9027
  }
8872
- this.next();
9028
+ this.nextToken();
8873
9029
  return result;
8874
9030
  }
8875
- matchMiddleDelimiter(delimiter) {
8876
- const delimiters = MIDDLE_DELIMITER[delimiter] ?? [delimiter];
8877
- if (MIDDLE_DELIMITER_PREFIX.includes(this.peek)) {
8878
- const index = this.index;
8879
- this.next();
8880
- if (delimiters.includes(this.peek)) {
8881
- this.next();
8882
- return true;
8883
- }
8884
- this.index = index;
8885
- return false;
8886
- } else if (delimiters.include(this.peek)) {
8887
- this.next();
8888
- return true;
8889
- }
8890
- return false;
8891
- }
9031
+ // matchMiddleDelimiter(delimiter: '|' | ':' | LatexToken): boolean {
9032
+ // const delimiters = MIDDLE_DELIMITER[delimiter] ?? [delimiter];
9033
+ // if (MIDDLE_DELIMITER_PREFIX.includes(this.peek)) {
9034
+ // const index = this.index;
9035
+ // this.nextToken();
9036
+ // if (delimiters.includes(this.peek)) {
9037
+ // this.nextToken();
9038
+ // return true;
9039
+ // }
9040
+ // this.index = index;
9041
+ // return false;
9042
+ // } else if (delimiters.include(this.peek)) {
9043
+ // this.nextToken();
9044
+ // return true;
9045
+ // }
9046
+ // return false;
9047
+ // }
8892
9048
  /** For error handling, when there is potentially a mismatched delimiter.
8893
9049
  * Return a LaTeX fragment of the expected closing delimiter
9050
+ *
9051
+ * @internal
8894
9052
  */
8895
9053
  matchEnclosureOpen() {
8896
9054
  const defs = this._dictionary.matchfix;
@@ -8914,6 +9072,9 @@ var ComputeEngine = (() => {
8914
9072
  this.index = start;
8915
9073
  return null;
8916
9074
  }
9075
+ /**
9076
+ * Used for error handling
9077
+ * @internal */
8917
9078
  matchEnclosureClose() {
8918
9079
  const defs = this._dictionary.matchfix;
8919
9080
  if (defs.length === 0)
@@ -8932,7 +9093,7 @@ var ComputeEngine = (() => {
8932
9093
  (x) => OPEN_DELIMITER_PREFIX[x] === peek
8933
9094
  );
8934
9095
  if (prefix)
8935
- this.next();
9096
+ this.nextToken();
8936
9097
  let openDelimiter = [];
8937
9098
  peek = this.peek;
8938
9099
  const matchingDelim = Object.keys(CLOSE_DELIMITER).find(
@@ -8943,7 +9104,7 @@ var ComputeEngine = (() => {
8943
9104
  if (prefix)
8944
9105
  openDelimiter = [prefix, ...openDelimiter];
8945
9106
  if (openDelimiter.length > 0) {
8946
- this.next();
9107
+ this.nextToken();
8947
9108
  return tokensToString(openDelimiter);
8948
9109
  }
8949
9110
  }
@@ -8955,7 +9116,7 @@ var ComputeEngine = (() => {
8955
9116
  * optionally followed multiple times by a separator and another expression,
8956
9117
  * and finally a closing matching operator.
8957
9118
  */
8958
- matchEnclosure() {
9119
+ parseEnclosure() {
8959
9120
  const defs = this._dictionary.matchfix;
8960
9121
  if (defs.length === 0)
8961
9122
  return null;
@@ -8966,7 +9127,7 @@ var ComputeEngine = (() => {
8966
9127
  if (!this.matchAll(def.openDelimiter))
8967
9128
  continue;
8968
9129
  this.addBoundary(def.closeDelimiter);
8969
- const body2 = this.matchExpression();
9130
+ const body2 = this.parseExpression();
8970
9131
  this.skipSpace();
8971
9132
  if (!this.matchBoundary()) {
8972
9133
  this.removeBoundary();
@@ -8991,12 +9152,12 @@ var ComputeEngine = (() => {
8991
9152
  }
8992
9153
  this.addBoundary(closeDelimiter);
8993
9154
  const bodyStart = this.index;
8994
- let body = this.matchExpression();
9155
+ let body = this.parseExpression();
8995
9156
  this.skipSpace();
8996
9157
  if (!this.matchBoundary()) {
8997
9158
  this.removeBoundary();
8998
9159
  this.index = bodyStart;
8999
- body = this.matchExpression();
9160
+ body = this.parseExpression();
9000
9161
  if (!this.matchAll(closeDelimiter)) {
9001
9162
  if (!this.atEnd)
9002
9163
  continue;
@@ -9011,52 +9172,74 @@ var ComputeEngine = (() => {
9011
9172
  this.index = start;
9012
9173
  return null;
9013
9174
  }
9014
- matchIdentifier() {
9015
- return matchIdentifier(this);
9016
- }
9017
9175
  /**
9018
- * A function is an identifier followed by arguments
9019
- * - a single letter identifier with explicit arguments `f(x)`
9020
- * - a multiletter identifier with explicit arguments `\mathrm{floor}(x)`
9021
- * - an identifier: `\mathrm{floor}`
9022
- * - a command with implicit arguments: `\cos x` (via a custom parser)
9023
- *
9176
+ * A generic expression is used for dictionary entries that take do
9177
+ * some complex (non-standard) parsing. This includes trig functions (to
9178
+ * parse implicit arguments), and integrals (to parse the integrand and
9179
+ * limits and the "dx" terminator).
9024
9180
  */
9025
- matchFunction(until) {
9181
+ parseGenericExpression(until) {
9026
9182
  if (this.atTerminator(until))
9027
9183
  return null;
9028
9184
  const start = this.index;
9029
- const fnDefs = this.peekDefinitions("function");
9030
- if (fnDefs) {
9031
- for (const [def, tokenCount] of fnDefs) {
9032
- this.index = start + tokenCount;
9033
- if (typeof def.parse === "function") {
9034
- const result = def.parse(this, until);
9035
- if (result)
9036
- return result;
9037
- } else {
9038
- return this.matchFunctionSuffix(def.name);
9039
- }
9185
+ let expr = null;
9186
+ const fnDefs = this.peekDefinitions("expression") ?? [];
9187
+ for (const [def, tokenCount] of fnDefs) {
9188
+ this.index = start + tokenCount;
9189
+ if (typeof def.parse === "function") {
9190
+ expr = def.parse(this, until);
9191
+ if (expr !== null)
9192
+ return expr;
9193
+ } else {
9194
+ return def.name;
9040
9195
  }
9041
9196
  }
9042
9197
  this.index = start;
9043
- const fn = this.matchIdentifier();
9044
- if (fn === null)
9198
+ return null;
9199
+ }
9200
+ /**
9201
+ * A function is an identifier followed by postfix operators
9202
+ * (`\prime`...) and some arguments.
9203
+ */
9204
+ parseFunction(until) {
9205
+ if (this.atTerminator(until))
9045
9206
  return null;
9046
- if (this.options.parseUnknownIdentifier?.(fn, this) !== "function") {
9207
+ const start = this.index;
9208
+ let fn = null;
9209
+ const fnDefs = this.peekDefinitions("function") ?? [];
9210
+ for (const [def, tokenCount] of fnDefs) {
9211
+ this.index = start + tokenCount;
9212
+ if (typeof def.parse === "function") {
9213
+ fn = def.parse(this, until);
9214
+ if (fn !== null)
9215
+ break;
9216
+ } else {
9217
+ fn = def.name;
9218
+ break;
9219
+ }
9220
+ }
9221
+ if (fn === null) {
9047
9222
  this.index = start;
9048
- return null;
9223
+ fn = matchIdentifier(this);
9224
+ if (!this.isFunctionHead(fn)) {
9225
+ this.index = start;
9226
+ return null;
9227
+ }
9049
9228
  }
9050
- return this.matchFunctionSuffix(fn);
9229
+ do {
9230
+ const pf = this.parsePostfixOperator(fn);
9231
+ if (pf === null)
9232
+ break;
9233
+ fn = pf;
9234
+ } while (true);
9235
+ const seq = this.isFunctionHead(fn) ? this.parseArguments() : null;
9236
+ return seq ? [fn, ...seq] : fn;
9051
9237
  }
9052
- /**
9053
- * A symbol is an identifier or a custom definition
9054
- */
9055
- matchSymbol(until) {
9238
+ parseSymbol(until) {
9056
9239
  if (this.atTerminator(until))
9057
9240
  return null;
9058
9241
  const start = this.index;
9059
- const defs = this.peekDefinitions("identifier");
9242
+ const defs = this.peekDefinitions("symbol");
9060
9243
  if (defs) {
9061
9244
  for (const [def, tokenCount] of defs) {
9062
9245
  this.index = start + tokenCount;
@@ -9069,7 +9252,7 @@ var ComputeEngine = (() => {
9069
9252
  }
9070
9253
  }
9071
9254
  this.index = start;
9072
- const id = this.matchIdentifier();
9255
+ const id = matchIdentifier(this);
9073
9256
  if (id === null)
9074
9257
  return null;
9075
9258
  if (this.options.parseUnknownIdentifier?.(id, this) === "symbol")
@@ -9077,57 +9260,19 @@ var ComputeEngine = (() => {
9077
9260
  this.index = start;
9078
9261
  return null;
9079
9262
  }
9080
- matchLatexOptionalGroup() {
9081
- const index = this.index;
9082
- this.skipSpaceTokens();
9083
- if (this.match("[")) {
9084
- this.addBoundary(["]"]);
9085
- const expr = this.matchExpression();
9086
- this.skipSpace();
9087
- if (this.matchBoundary())
9088
- return expr;
9089
- return this.boundaryError("expected-closing-delimiter");
9090
- }
9091
- this.index = index;
9092
- return null;
9093
- }
9094
- // Some LaTeX commands (but not all) can accept an argument without braces,
9095
- // for example `^` , `\sqrt` or `\frac`.
9096
- matchSingleAtomArgument() {
9097
- const excluding = [...'!"#$%&(),/;:?@[]`|~'.split(""), "\\left", "\\bigl"];
9098
- if (excluding.includes(this.peek))
9099
- return null;
9100
- if (/^[0-9]$/.test(this.peek))
9101
- return parseInt(this.next());
9102
- if (/^[^\\#]$/.test(this.peek) && isValidIdentifier(this.peek))
9103
- return this.next();
9104
- const sym = this.matchSymbol();
9105
- if (sym)
9106
- return sym;
9107
- return null;
9108
- }
9109
- matchLatexGroup() {
9110
- const start = this.index;
9111
- this.skipSpaceTokens();
9112
- if (this.match("<{>")) {
9113
- this.addBoundary(["<}>"]);
9114
- const expr = this.matchExpression();
9115
- this.skipSpace();
9116
- if (this.matchBoundary())
9117
- return expr ?? ["Sequence"];
9118
- const from = this.index;
9119
- while (!this.matchBoundary() && !this.atEnd)
9120
- this.next();
9121
- const err = this.error("syntax-error", from);
9122
- return expr ? ["Sequence", expr, err] : err;
9123
- }
9124
- this.index = start;
9125
- return null;
9126
- }
9127
- matchSupsub(lhs) {
9263
+ /**
9264
+ * Parse a sequence superfix/subfix operator, e.g. `^{*}`
9265
+ *
9266
+ * Superfix and subfix need special handling:
9267
+ *
9268
+ * - they act mostly like an infix operator, but they are commutative, i.e.
9269
+ * `x_a^b` should be parsed identically to `x^b_a`.
9270
+ *
9271
+ * - furthermore, in LaTeX `x^a^b` parses the same as `x^a{}^b`.
9272
+ *
9273
+ */
9274
+ parseSupsub(lhs) {
9128
9275
  console.assert(lhs !== null);
9129
- if (lhs === null)
9130
- return null;
9131
9276
  const index = this.index;
9132
9277
  this.skipSpace();
9133
9278
  const superscripts = [];
@@ -9139,7 +9284,7 @@ var ComputeEngine = (() => {
9139
9284
  if (this.match("_") || this.match("^"))
9140
9285
  subscripts.push(this.error("syntax-error", subIndex));
9141
9286
  else {
9142
- const sub2 = this.matchLatexGroup() ?? this.matchSingleAtomArgument() ?? this.matchStringArgument();
9287
+ const sub2 = this.parseGroup() ?? this.parseToken() ?? this.parseStringGroup();
9143
9288
  if (sub2 === null)
9144
9289
  return this.error("missing", index);
9145
9290
  subscripts.push(sub2);
@@ -9149,7 +9294,7 @@ var ComputeEngine = (() => {
9149
9294
  if (this.match("_") || this.match("^"))
9150
9295
  superscripts.push(this.error("syntax-error", subIndex));
9151
9296
  else {
9152
- const sup = this.matchLatexGroup() ?? this.matchSingleAtomArgument();
9297
+ const sup = this.parseGroup() ?? this.parseToken();
9153
9298
  if (sup === null)
9154
9299
  return this.error("missing", index);
9155
9300
  superscripts.push(sup);
@@ -9173,7 +9318,7 @@ var ComputeEngine = (() => {
9173
9318
  ];
9174
9319
  for (const def of defs) {
9175
9320
  if (typeof def.parse === "function")
9176
- result = def.parse(this, { minPrec: 0 }, arg);
9321
+ result = def.parse(this, arg, { minPrec: 0 });
9177
9322
  else
9178
9323
  result = arg;
9179
9324
  if (result)
@@ -9191,7 +9336,7 @@ var ComputeEngine = (() => {
9191
9336
  ];
9192
9337
  for (const def of defs) {
9193
9338
  if (typeof def.parse === "function")
9194
- result = def.parse(this, { minPrec: 0 }, arg);
9339
+ result = def.parse(this, arg, { minPrec: 0 });
9195
9340
  else
9196
9341
  result = arg;
9197
9342
  if (result)
@@ -9203,7 +9348,7 @@ var ComputeEngine = (() => {
9203
9348
  this.index = index;
9204
9349
  return result;
9205
9350
  }
9206
- matchPostfix(lhs, until) {
9351
+ parsePostfixOperator(lhs, until) {
9207
9352
  console.assert(lhs !== null);
9208
9353
  if (lhs === null)
9209
9354
  return null;
@@ -9225,119 +9370,32 @@ var ComputeEngine = (() => {
9225
9370
  * Not suitable for general purpose text, e.g. argument of a `\text{}
9226
9371
  * command. See `matchChar()` instead.
9227
9372
  */
9228
- matchString() {
9373
+ parseStringGroupContent() {
9374
+ const start = this.index;
9229
9375
  let result = "";
9230
- while (!this.atBoundary) {
9231
- const token = this.peek;
9376
+ let level = 0;
9377
+ while (!this.atBoundary || level > 0) {
9378
+ const token = this.nextToken();
9232
9379
  if (token === "<$>" || token === "<$$>") {
9380
+ this.index = start;
9233
9381
  return "";
9382
+ }
9383
+ if (token === "<{>") {
9384
+ level += 1;
9385
+ result += "\\{";
9386
+ } else if (token === "<}>") {
9387
+ level -= 1;
9388
+ result += "\\}";
9234
9389
  } else if (token === "<space>") {
9235
- this.next();
9236
9390
  result += " ";
9237
9391
  } else if (token[0] === "\\") {
9238
- result += this.next();
9239
- } else {
9240
- result += this.next();
9241
- }
9242
- }
9243
- return result;
9244
- }
9245
- /** Match a string as an argument (in a `{}` pair) */
9246
- matchStringArgument() {
9247
- const start = this.index;
9248
- this.skipSpaceTokens();
9249
- if (this.match("<{>")) {
9250
- this.addBoundary(["<}>"]);
9251
- while (this.match("<space>")) {
9252
- }
9253
- const arg = this.matchString();
9254
- if (this.matchBoundary())
9255
- return arg.trimEnd();
9256
- this.removeBoundary();
9257
- }
9258
- this.index = start;
9259
- return null;
9260
- }
9261
- /**
9262
- * Match an expression in a tabular format, where rows are separated by `\\`
9263
- * and columns by `&`.
9264
- *
9265
- * Return rows of sparse columns: empty rows are indicated with `Nothing`,
9266
- * and empty cells are also indicated with `Nothing`.
9267
- */
9268
- matchTabular() {
9269
- const result = [];
9270
- let row = [];
9271
- let expr = null;
9272
- while (!this.atBoundary) {
9273
- this.skipSpace();
9274
- if (this.match("&")) {
9275
- row.push(expr ?? "Nothing");
9276
- expr = null;
9277
- } else if (this.match("\\\\") || this.match("\\cr")) {
9278
- this.skipSpace();
9279
- this.matchLatexOptionalGroup();
9280
- if (expr !== null)
9281
- row.push(expr);
9282
- result.push(row);
9283
- row = [];
9284
- expr = null;
9392
+ result += token;
9285
9393
  } else {
9286
- const cell = [];
9287
- let peek = this.peek;
9288
- while (peek !== "&" && peek !== "\\\\" && peek !== "\\cr" && !this.atBoundary) {
9289
- expr = this.matchExpression({
9290
- condition: (p) => {
9291
- const peek2 = p.peek;
9292
- return peek2 === "&" || peek2 === "\\\\" || peek2 === "\\cr";
9293
- }
9294
- });
9295
- if (expr)
9296
- cell.push(expr);
9297
- else {
9298
- cell.push(["Error", ["'unexpected-token'", peek]]);
9299
- this.next();
9300
- }
9301
- this.skipSpace();
9302
- peek = this.peek;
9303
- }
9304
- if (cell.length > 1)
9305
- expr = ["Sequence", ...cell];
9306
- else
9307
- expr = cell[0] ?? "Nothing";
9394
+ result += token;
9308
9395
  }
9309
9396
  }
9310
- if (expr !== null)
9311
- row.push(expr);
9312
- if (row.length > 0)
9313
- result.push(row);
9314
9397
  return result;
9315
9398
  }
9316
- matchEnvironment() {
9317
- const index = this.index;
9318
- if (!this.match("\\begin"))
9319
- return null;
9320
- const name = this.matchStringArgument();
9321
- if (name === null)
9322
- return this.error("expected-environment-name", index);
9323
- this.addBoundary(["\\end", "<{>", ...name.split(""), "<}>"]);
9324
- const def = this._dictionary.environment.get(name);
9325
- if (!def) {
9326
- this.matchTabular();
9327
- this.skipSpace();
9328
- if (!this.matchBoundary())
9329
- return this.boundaryError("unbalanced-environment");
9330
- return this.error(["unknown-environment", { str: name }], index);
9331
- }
9332
- const expr = def.parse(this, [], []);
9333
- this.skipSpace();
9334
- if (!this.matchBoundary())
9335
- return this.boundaryError("unbalanced-environment");
9336
- if (expr !== null)
9337
- return this.decorate(expr, index);
9338
- this.index = index;
9339
- return null;
9340
- }
9341
9399
  /**
9342
9400
  * Apply an invisible operator between two expressions.
9343
9401
  *
@@ -9360,12 +9418,18 @@ var ComputeEngine = (() => {
9360
9418
  * => lhs is a number, rhs is a number, but not a literal
9361
9419
  */
9362
9420
  applyInvisibleOperator(until, lhs) {
9363
- if (lhs === null || head(lhs) === "Error" || symbol(lhs) === "Nothing" || isEmptySequence(lhs) || this.atTerminator(until) || this.options.applyInvisibleOperator === null)
9421
+ if (lhs === null || this.options.applyInvisibleOperator === null || head(lhs) === "Error" || symbol(lhs) === "Nothing" || isEmptySequence(lhs) || this.atTerminator(until))
9364
9422
  return null;
9423
+ if (this.isFunctionHead(lhs)) {
9424
+ const args = this.parseArguments("enclosure", until);
9425
+ if (args === null)
9426
+ return null;
9427
+ return [lhs, ...args];
9428
+ }
9365
9429
  if (this.peekDefinitions("operator") !== null)
9366
9430
  return null;
9367
9431
  const start = this.index;
9368
- const rhs = this.matchExpression({ ...until, minPrec: 390 });
9432
+ const rhs = this.parseExpression({ ...until, minPrec: 390 });
9369
9433
  if (rhs === null || symbol(rhs) === "Nothing" || isEmptySequence(rhs)) {
9370
9434
  this.index = start;
9371
9435
  return null;
@@ -9374,13 +9438,9 @@ var ComputeEngine = (() => {
9374
9438
  return applyAssociativeOperator("Sequence", lhs, rhs);
9375
9439
  if (typeof this.options.applyInvisibleOperator === "function")
9376
9440
  return this.options.applyInvisibleOperator(this, lhs, rhs);
9377
- const lhsSymbol = symbol(lhs);
9378
- if (lhsSymbol) {
9379
- const isFunction = this.options.parseUnknownIdentifier(lhsSymbol, this) === "function";
9380
- if (isFunction) {
9381
- const seq = getSequence(rhs);
9382
- return seq ? [lhs, ...seq] : lhsSymbol;
9383
- }
9441
+ if (this.isFunctionHead(lhs)) {
9442
+ const seq = getSequence(rhs);
9443
+ return seq ? [lhs, ...seq] : lhs;
9384
9444
  }
9385
9445
  const lhsNumber = machineValue(lhs);
9386
9446
  if (lhsNumber !== null && Number.isInteger(lhsNumber)) {
@@ -9393,7 +9453,7 @@ var ComputeEngine = (() => {
9393
9453
  }
9394
9454
  if (head(rhs) === "Delimiter") {
9395
9455
  if (head(op(rhs, 1)) === "Sequence")
9396
- return [lhsSymbol ?? lhs, ...ops(op(rhs, 1)) ?? []];
9456
+ return [lhs, ...ops(op(rhs, 1)) ?? []];
9397
9457
  if (!op(rhs, 1) || symbol(op(rhs, 1)) === "Nothing")
9398
9458
  return applyAssociativeOperator(
9399
9459
  "Sequence",
@@ -9405,7 +9465,13 @@ var ComputeEngine = (() => {
9405
9465
  return applyAssociativeOperator("Sequence", lhs, rhs);
9406
9466
  return applyAssociativeOperator("Multiply", lhs, rhs);
9407
9467
  }
9408
- matchUnexpectedLatexCommand() {
9468
+ /**
9469
+ * This is an error handling method. We've encountered a LaTeX command
9470
+ * but were not able to match it to any entry in the LaTeX dictionary,
9471
+ * or ran into it in an unexpected context (postfix operator lacking an
9472
+ * argument, for example)
9473
+ */
9474
+ parseUnexpectedLatexCommand() {
9409
9475
  const start = this.index;
9410
9476
  let opDefs = this.peekDefinitions("operator");
9411
9477
  if (opDefs) {
@@ -9434,7 +9500,7 @@ var ComputeEngine = (() => {
9434
9500
  if (def.name)
9435
9501
  return [
9436
9502
  def.name,
9437
- this.matchExpression() ?? this.error("missing", start)
9503
+ this.parseExpression() ?? this.error("missing", start)
9438
9504
  ];
9439
9505
  return this.error("unexpected-operator", start);
9440
9506
  }
@@ -9443,11 +9509,9 @@ var ComputeEngine = (() => {
9443
9509
  const [def, n] = opDefs[0];
9444
9510
  this.index += n;
9445
9511
  if (typeof def.parse === "function") {
9446
- const result = def.parse(
9447
- this,
9448
- { minPrec: 0 },
9449
- this.error("missing", start)
9450
- );
9512
+ const result = def.parse(this, this.error("missing", start), {
9513
+ minPrec: 0
9514
+ });
9451
9515
  if (result)
9452
9516
  return result;
9453
9517
  }
@@ -9455,7 +9519,7 @@ var ComputeEngine = (() => {
9455
9519
  return [
9456
9520
  def.name,
9457
9521
  this.error("missing", start),
9458
- this.matchExpression() ?? this.error("missing", start)
9522
+ this.parseExpression() ?? this.error("missing", start)
9459
9523
  ];
9460
9524
  return this.error("unexpected-operator", start);
9461
9525
  }
@@ -9463,10 +9527,10 @@ var ComputeEngine = (() => {
9463
9527
  const command = this.peek;
9464
9528
  if (!command || command[0] !== "\\")
9465
9529
  return null;
9466
- this.next();
9530
+ this.nextToken();
9467
9531
  this.skipSpaceTokens();
9468
9532
  if (command === "\\end") {
9469
- const name = this.matchStringArgument();
9533
+ const name = this.parseStringGroup();
9470
9534
  if (name === null)
9471
9535
  return this.error("expected-environment-name", start);
9472
9536
  return this.error(["unbalanced-environment", { str: name }], start);
@@ -9478,7 +9542,7 @@ var ComputeEngine = (() => {
9478
9542
  level += 1;
9479
9543
  if (this.peek === "]")
9480
9544
  level -= 1;
9481
- this.next();
9545
+ this.nextToken();
9482
9546
  }
9483
9547
  this.match("]");
9484
9548
  }
@@ -9504,7 +9568,7 @@ var ComputeEngine = (() => {
9504
9568
  level += 1;
9505
9569
  if (this.peek === "<}>")
9506
9570
  level -= 1;
9507
- this.next();
9571
+ this.nextToken();
9508
9572
  }
9509
9573
  this.match("<}>");
9510
9574
  }
@@ -9512,15 +9576,20 @@ var ComputeEngine = (() => {
9512
9576
  }
9513
9577
  /**
9514
9578
  * <primary> :=
9515
- * (<number> | <symbol> | <environment> | <matchfix-expr>) <subsup>* <postfix-operator>*
9579
+ * (<number> | <symbol> | <environment> | <matchfix-expr>)
9580
+ * <subsup>* <postfix-operator>*
9516
9581
  *
9517
- * <symbol> ::= (<symbol-id> | (<latex-command><latex-arguments>)) <arguments>
9582
+ * <symbol> ::=
9583
+ * (<symbol-id> | (<latex-command><latex-arguments>)) <arguments>
9518
9584
  *
9519
9585
  * <matchfix-expr> :=
9520
- * <matchfix-op-open> <expression> [<matchfix-op-separator> <expression>] <matchfix-op-close>
9586
+ * <matchfix-op-open>
9587
+ * <expression>
9588
+ * (<matchfix-op-separator> <expression>)*
9589
+ * <matchfix-op-close>
9521
9590
  *
9522
9591
  */
9523
- matchPrimary(until) {
9592
+ parsePrimary(until) {
9524
9593
  if (this.atBoundary)
9525
9594
  return null;
9526
9595
  if (this.atTerminator(until))
@@ -9530,7 +9599,7 @@ var ComputeEngine = (() => {
9530
9599
  if (this.match("<}>"))
9531
9600
  return this.error("unexpected-closing-delimiter", start);
9532
9601
  if (this.match("<{>")) {
9533
- result = this.matchExpression({ condition: (p) => p.peek === "<}>" });
9602
+ result = this.parseExpression({ condition: (p) => p.peek === "<}>" });
9534
9603
  if (result === null)
9535
9604
  return this.error("expected-expression", start);
9536
9605
  if (!this.match("<}>")) {
@@ -9541,25 +9610,25 @@ var ComputeEngine = (() => {
9541
9610
  }
9542
9611
  }
9543
9612
  if (result === null) {
9544
- const num = this.matchNumber();
9545
- if (num)
9613
+ const num = this.parseNumber();
9614
+ if (num !== null)
9546
9615
  result = { num };
9547
9616
  }
9548
- result ?? (result = this.matchEnclosure());
9549
- result ?? (result = this.matchEnvironment());
9617
+ result ?? (result = this.parseEnclosure());
9618
+ result ?? (result = this.parseEnvironment());
9550
9619
  if (result === null && this.matchAll(this._positiveInfinityTokens))
9551
9620
  result = { num: "+Infinity" };
9552
9621
  if (result === null && this.matchAll(this._negativeInfinityTokens))
9553
9622
  result = { num: "-Infinity" };
9554
9623
  if (result === null && this.matchAll(this._notANumberTokens))
9555
9624
  result = { num: "NaN" };
9556
- result ?? (result = this.matchFunction(until) ?? this.matchSymbol(until) ?? matchInvalidIdentifier(this));
9625
+ result ?? (result = this.parseGenericExpression(until) ?? this.parseFunction(until) ?? this.parseSymbol(until) ?? parseInvalidIdentifier(this));
9557
9626
  if (result !== null) {
9558
9627
  result = this.decorate(result, start);
9559
9628
  let postfix = null;
9560
9629
  let index = this.index;
9561
9630
  do {
9562
- postfix = this.matchPostfix(result, until);
9631
+ postfix = this.parsePostfixOperator(result, until);
9563
9632
  result = postfix ?? result;
9564
9633
  if (this.index === index && postfix !== null) {
9565
9634
  console.assert(this.index !== index, "No token consumed");
@@ -9568,9 +9637,8 @@ var ComputeEngine = (() => {
9568
9637
  index = this.index;
9569
9638
  } while (postfix !== null);
9570
9639
  }
9571
- result ?? (result = this.matchUnexpectedLatexCommand());
9572
9640
  if (result !== null)
9573
- result = this.matchSupsub(result);
9641
+ result = this.parseSupsub(result);
9574
9642
  return this.decorate(result, start);
9575
9643
  }
9576
9644
  /**
@@ -9581,9 +9649,10 @@ var ComputeEngine = (() => {
9581
9649
  * | <prefix-op> <primary>
9582
9650
  * | <primary> <infix-op> <expression>
9583
9651
  *
9584
- * Stop when an operator of precedence less than `until.minPrec` is encountered
9652
+ * Stop when an operator of precedence less than `until.minPrec`
9653
+ * is encountered
9585
9654
  */
9586
- matchExpression(until) {
9655
+ parseExpression(until) {
9587
9656
  const start = this.index;
9588
9657
  this.skipSpace();
9589
9658
  if (this.atBoundary) {
@@ -9593,9 +9662,9 @@ var ComputeEngine = (() => {
9593
9662
  until ?? (until = { minPrec: 0 });
9594
9663
  if (until.minPrec === void 0)
9595
9664
  until.minPrec = 0;
9596
- let lhs = this.matchPrefixOperator({ ...until, minPrec: 0 });
9665
+ let lhs = this.parsePrefixOperator({ ...until, minPrec: 0 });
9597
9666
  if (lhs === null) {
9598
- lhs = this.matchPrimary(until);
9667
+ lhs = this.parsePrimary(until);
9599
9668
  if (head(lhs) === "Sequence" && nops(lhs) === 0)
9600
9669
  lhs = null;
9601
9670
  }
@@ -9603,7 +9672,7 @@ var ComputeEngine = (() => {
9603
9672
  let done = false;
9604
9673
  while (!done && !this.atTerminator(until)) {
9605
9674
  this.skipSpace();
9606
- let result = this.matchInfixOperator(lhs, until);
9675
+ let result = this.parseInfixOperator(lhs, until);
9607
9676
  if (result === null) {
9608
9677
  result = this.applyInvisibleOperator(until, lhs);
9609
9678
  }
@@ -9614,6 +9683,7 @@ var ComputeEngine = (() => {
9614
9683
  }
9615
9684
  }
9616
9685
  }
9686
+ lhs ?? (lhs = this.parseUnexpectedLatexCommand());
9617
9687
  return this.decorate(lhs, start);
9618
9688
  }
9619
9689
  /**
@@ -9648,18 +9718,19 @@ var ComputeEngine = (() => {
9648
9718
  const latex = this.latex(fromToken, this.index);
9649
9719
  return latex ? ["Error", msg, ["Latex", { str: latex }]] : ["Error", msg];
9650
9720
  }
9721
+ isFunctionHead(expr) {
9722
+ if (expr === null)
9723
+ return false;
9724
+ const s = symbol(expr);
9725
+ if (!s)
9726
+ return this.computeEngine.box(expr).domain.isFunction;
9727
+ if (this.computeEngine && this.computeEngine.lookupFunction(s) !== void 0)
9728
+ return true;
9729
+ if (this.options.parseUnknownIdentifier?.(s, this) === "function")
9730
+ return true;
9731
+ return false;
9732
+ }
9651
9733
  };
9652
- function countPrimeLevel(parser) {
9653
- if (parser.match("\\tripleprime"))
9654
- return 3;
9655
- if (parser.match("\\doubleprime"))
9656
- return 2;
9657
- if (parser.match("\\prime"))
9658
- return 1;
9659
- if (parser.match("'"))
9660
- return 1;
9661
- return 0;
9662
- }
9663
9734
 
9664
9735
  // src/compute-engine/latex-syntax/serialize-number.ts
9665
9736
  function formatFractionalPart(m, options) {
@@ -10003,7 +10074,7 @@ var ComputeEngine = (() => {
10003
10074
  const name = head(expr);
10004
10075
  if (typeof name === "string" && name !== "Delimiter" && name !== "Subscript") {
10005
10076
  const def = this.dictionary.name.get(name);
10006
- if (def && (def.kind === "identifier" || def.kind === "prefix" || def.kind === "infix" || def.kind === "postfix") && def.precedence < prec)
10077
+ if (def && (def.kind === "symbol" || def.kind === "prefix" || def.kind === "infix" || def.kind === "postfix") && def.precedence < prec)
10007
10078
  return this.wrapString(
10008
10079
  this.serialize(expr),
10009
10080
  this.options.applyFunctionStyle(expr, this.level)
@@ -10083,8 +10154,11 @@ var ComputeEngine = (() => {
10083
10154
  if (typeof h === "string" && h.length > 0 && h[0] === "\\") {
10084
10155
  return joinLatex([h, ...args.map((x) => `{${this.serialize(x)}}`)]);
10085
10156
  }
10086
- if (typeof h === "string")
10157
+ if (typeof h === "string") {
10158
+ if (h.length === 1)
10159
+ return serializeIdentifier(h) + this.wrapArguments(expr);
10087
10160
  return serializeIdentifier(h, "upright") + this.wrapArguments(expr);
10161
+ }
10088
10162
  const style = this.options.applyFunctionStyle(expr, this.level);
10089
10163
  return "\\mathrm{Apply}" + this.wrapString(
10090
10164
  this.serialize(h) + ", " + this.serialize(["List", ...args]),
@@ -10111,10 +10185,12 @@ var ComputeEngine = (() => {
10111
10185
  const symbolName = symbol(expr);
10112
10186
  if (symbolName !== null) {
10113
10187
  const def = this.dictionary.name.get(symbolName);
10114
- if (def?.kind === "identifier")
10188
+ if (def?.kind === "symbol")
10115
10189
  return this.serializeSymbol(expr, def);
10116
10190
  if (def?.kind === "function")
10117
10191
  return this.serializeFunction(expr, def);
10192
+ if (typeof def?.serialize === "function")
10193
+ return def.serialize(this, expr);
10118
10194
  }
10119
10195
  const dict = dictionary(expr);
10120
10196
  if (dict !== null)
@@ -10127,7 +10203,7 @@ var ComputeEngine = (() => {
10127
10203
  return def.serialize(this, expr);
10128
10204
  if (def.kind === "infix" || def.kind === "postfix" || def.kind === "prefix")
10129
10205
  return serializeOperator(this, expr, def);
10130
- if (def.kind === "identifier")
10206
+ if (def.kind === "symbol")
10131
10207
  return this.serializeSymbol(expr, def);
10132
10208
  if (def.kind === "function")
10133
10209
  return this.serializeFunction(expr, def);
@@ -10391,7 +10467,7 @@ var ComputeEngine = (() => {
10391
10467
  ...DEFAULT_SERIALIZE_LATEX_OPTIONS,
10392
10468
  ...opts
10393
10469
  };
10394
- this.dictionary = indexLatexDictionary(
10470
+ this._dictionary = indexLatexDictionary(
10395
10471
  options.dictionary ?? _LatexSyntax.getDictionary(),
10396
10472
  (sig) => this.onError([sig])
10397
10473
  );
@@ -10412,16 +10488,16 @@ var ComputeEngine = (() => {
10412
10488
  }
10413
10489
  if (!DEFAULT_LATEX_DICTIONARY[category])
10414
10490
  return [];
10415
- return [...DEFAULT_LATEX_DICTIONARY[category]];
10491
+ return Object.freeze([...DEFAULT_LATEX_DICTIONARY[category]]);
10416
10492
  }
10417
10493
  parse(latex) {
10418
10494
  const parser = new _Parser(
10419
10495
  tokenize(latex, []),
10420
10496
  this.options,
10421
- this.dictionary,
10497
+ this._dictionary,
10422
10498
  this.computeEngine
10423
10499
  );
10424
- let expr = parser.matchExpression();
10500
+ let expr = parser.parseExpression();
10425
10501
  if (!parser.atEnd) {
10426
10502
  const opDefs = parser.peekDefinitions("infix");
10427
10503
  if (opDefs) {
@@ -10430,8 +10506,8 @@ var ComputeEngine = (() => {
10430
10506
  parser.index += n;
10431
10507
  const result = def.parse(
10432
10508
  parser,
10433
- { minPrec: 0 },
10434
- expr ?? parser.error("missing", start)
10509
+ expr ?? parser.error("missing", start),
10510
+ { minPrec: 0 }
10435
10511
  );
10436
10512
  if (result)
10437
10513
  return result;
@@ -10445,7 +10521,7 @@ var ComputeEngine = (() => {
10445
10521
  parser.index = start;
10446
10522
  }
10447
10523
  const index = parser.index;
10448
- const id = parser.matchIdentifier();
10524
+ const id = matchIdentifier(parser);
10449
10525
  if (id) {
10450
10526
  const idError = parser.error(["unexpected-identifier", id], index);
10451
10527
  return expr ? ["Sequence", expr, idError] : idError;
@@ -10467,9 +10543,9 @@ var ComputeEngine = (() => {
10467
10543
  return expr ? ["Sequence", expr, enclosureError] : enclosureError;
10468
10544
  }
10469
10545
  const rest = parser.index;
10470
- const token = parser.next();
10546
+ const token = parser.nextToken();
10471
10547
  while (!parser.atEnd)
10472
- parser.next();
10548
+ parser.nextToken();
10473
10549
  if (!token)
10474
10550
  return parser.error("syntax-error", rest);
10475
10551
  const error = parser.error(
@@ -10502,7 +10578,7 @@ var ComputeEngine = (() => {
10502
10578
  return this._serializer;
10503
10579
  this._serializer = new Serializer(
10504
10580
  this.options,
10505
- this.dictionary,
10581
+ this._dictionary,
10506
10582
  this.onError
10507
10583
  );
10508
10584
  return this._serializer;
@@ -13076,6 +13152,14 @@ var ComputeEngine = (() => {
13076
13152
  gDomainLiterals[dom] = new Set(result);
13077
13153
  return result;
13078
13154
  }
13155
+ function domainSetsLibrary() {
13156
+ const table = {};
13157
+ for (const dom of Object.keys(DOMAIN_LITERAL)) {
13158
+ if (dom !== "Domain" && dom !== "Nothing" && dom !== "String" && dom !== "Symbol" && dom !== "List" && dom !== "Tuple" && dom !== "Sequence")
13159
+ table[dom] = { domain: "Set" };
13160
+ }
13161
+ return table;
13162
+ }
13079
13163
 
13080
13164
  // src/compute-engine/boxed-expression/abstract-boxed-expression.ts
13081
13165
  var import_complex6 = __toESM(require_complex());
@@ -19244,7 +19328,7 @@ var ComputeEngine = (() => {
19244
19328
  e: {
19245
19329
  domain: "TranscendentalNumber",
19246
19330
  constant: true,
19247
- holdUntil: "N",
19331
+ holdUntil: "never",
19248
19332
  value: "ExponentialE"
19249
19333
  },
19250
19334
  i: {
@@ -19276,7 +19360,7 @@ var ComputeEngine = (() => {
19276
19360
  ImaginaryUnit: {
19277
19361
  domain: "ImaginaryNumber",
19278
19362
  constant: true,
19279
- holdUntil: "never",
19363
+ holdUntil: "evaluate",
19280
19364
  wikidata: "Q193796",
19281
19365
  flags: { imaginary: true },
19282
19366
  value: ["Complex", 0, 1]
@@ -21338,8 +21422,8 @@ var ComputeEngine = (() => {
21338
21422
  [
21339
21423
  [1, 8],
21340
21424
  {
21341
- Sin: "$\\frac\\sqrt{2-\\sqrt2}{2}$",
21342
- Cos: "$\\frac {\\sqrt {2+{\\sqrt {2}}}}{2}$",
21425
+ Sin: "$\\frac{\\sqrt{2-\\sqrt2}}{2}$",
21426
+ Cos: "$\\frac{\\sqrt {2+{\\sqrt {2}}}}{2}$",
21343
21427
  Tan: "$\\sqrt{2} - 1$",
21344
21428
  Cot: "$\\sqrt{2} + 1$",
21345
21429
  Sec: "$\\sqrt{ 4 - 2\\sqrt{2}}$",
@@ -22442,7 +22526,19 @@ var ComputeEngine = (() => {
22442
22526
  return !!def && typeof def === "object" && ("domain" in def || "value" in def || "constant" in def);
22443
22527
  }
22444
22528
  function isFunctionDefinition(def) {
22445
- return !!def && typeof def === "object" && ("complexity" in def || "numeric" in def || "signature" in def);
22529
+ if (def === void 0 || def === null)
22530
+ return false;
22531
+ if (typeof def !== "object")
22532
+ return false;
22533
+ if ("complexity" in def || "numeric" in def || "signature" in def)
22534
+ return true;
22535
+ if (!("domain" in def))
22536
+ return false;
22537
+ if (def.domain === void 0)
22538
+ return false;
22539
+ if (typeof def.domain === "string")
22540
+ return def.domain === "Function";
22541
+ return def.domain.isFunction;
22446
22542
  }
22447
22543
 
22448
22544
  // src/compute-engine/library/library.ts
@@ -22522,7 +22618,7 @@ var ComputeEngine = (() => {
22522
22618
  // @todo // volume, speed, area
22523
22619
  "domains": [],
22524
22620
  "core": CORE_LIBRARY,
22525
- "collections": [SETS_LIBRARY, COLLECTIONS_LIBRARY],
22621
+ "collections": [SETS_LIBRARY, COLLECTIONS_LIBRARY, domainSetsLibrary()],
22526
22622
  // 'domains': getDomainsDictionary(),
22527
22623
  "linear-algebra": [],
22528
22624
  //@todo // 'linear-algebra': [
@@ -23822,16 +23918,6 @@ ${JSON.stringify(entry)}`
23822
23918
  this._tolerance = NUMERIC_TOLERANCE;
23823
23919
  this._bignumTolerance = this.bignum(this._tolerance);
23824
23920
  }
23825
- /** @internal */
23826
- bignum(a) {
23827
- if (typeof a === "bigint")
23828
- return new this._bignum(a.toString());
23829
- return new this._bignum(a);
23830
- }
23831
- /** @internal */
23832
- complex(a, b) {
23833
- return new import_complex19.Complex(a, b);
23834
- }
23835
23921
  chop(n) {
23836
23922
  if (typeof n === "number" && Math.abs(n) <= this._tolerance)
23837
23923
  return 0;
@@ -23841,6 +23927,20 @@ ${JSON.stringify(entry)}`
23841
23927
  return 0;
23842
23928
  return n;
23843
23929
  }
23930
+ bignum(a) {
23931
+ if (typeof a === "bigint")
23932
+ return new this._bignum(a.toString());
23933
+ return new this._bignum(a);
23934
+ }
23935
+ complex(a, b) {
23936
+ return new import_complex19.Complex(a, b);
23937
+ }
23938
+ isBignum(a) {
23939
+ return a instanceof Decimal;
23940
+ }
23941
+ isComplex(a) {
23942
+ return a instanceof import_complex19.Complex;
23943
+ }
23844
23944
  get latexSyntax() {
23845
23945
  if (!this._latexSyntax)
23846
23946
  this._latexSyntax = new LatexSyntax({
@@ -24528,10 +24628,10 @@ ${JSON.stringify(entry)}`
24528
24628
  };
24529
24629
 
24530
24630
  // src/compute-engine.ts
24531
- var version = "0.12.5";
24631
+ var version = "0.12.6";
24532
24632
  globalThis[Symbol.for("io.cortexjs.compute-engine")] = {
24533
24633
  ComputeEngine: ComputeEngine.prototype.constructor,
24534
- version: "0.12.5"
24634
+ version: "0.12.6"
24535
24635
  };
24536
24636
  return __toCommonJS(compute_engine_exports);
24537
24637
  })();