@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
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1029,11 +1029,14 @@ var require_complex = __commonJS({
1029
1029
  });
1030
1030
 
1031
1031
  // src/compute-engine/latex-syntax/public.ts
1032
- function isIdentifierEntry(entry) {
1033
- return !("kind" in entry) || entry.kind === "identifier";
1032
+ function isExpressionEntry(entry) {
1033
+ return !("kind" in entry) || entry.kind === "expression";
1034
+ }
1035
+ function isSymbolEntry(entry) {
1036
+ return "kind" in entry && entry.kind === "symbol";
1034
1037
  }
1035
1038
  function isFunctionEntry(entry) {
1036
- return !("kind" in entry) || entry.kind === "function";
1039
+ return "kind" in entry && entry.kind === "function";
1037
1040
  }
1038
1041
  function isMatchfixEntry(entry) {
1039
1042
  return "kind" in entry && entry.kind === "matchfix";
@@ -4098,9 +4101,9 @@ function applyAssociativeOperator(op3, lhs, rhs, associativity = "both") {
4098
4101
  return [op3, lhs, rhs];
4099
4102
  }
4100
4103
  function getSequence(expr) {
4101
- let h = head(expr);
4102
4104
  if (expr === null)
4103
4105
  return null;
4106
+ let h = head(expr);
4104
4107
  if (h === "Delimiter") {
4105
4108
  expr = op(expr, 1);
4106
4109
  if (expr === null)
@@ -4109,18 +4112,12 @@ function getSequence(expr) {
4109
4112
  return [expr];
4110
4113
  }
4111
4114
  h = head(expr);
4112
- if (h === "Sequence")
4113
- return ops(expr) ?? [];
4114
- return null;
4115
+ if (h !== "Sequence")
4116
+ return null;
4117
+ return ops(expr) ?? [];
4115
4118
  }
4116
4119
  function isEmptySequence(expr) {
4117
- if (expr === null)
4118
- return false;
4119
- if (head(expr) !== "Sequence")
4120
- return false;
4121
- if (nops(expr) !== 0)
4122
- return false;
4123
- return true;
4120
+ return expr !== null && head(expr) === "Sequence" && nops(expr) === 0;
4124
4121
  }
4125
4122
  function missingIfEmpty(expr) {
4126
4123
  if (expr === null || isEmptySequence(expr))
@@ -4231,8 +4228,8 @@ function numeratorDenominator(expr) {
4231
4228
  return [numerator, denominator];
4232
4229
  }
4233
4230
  function parseRoot(parser) {
4234
- const degree = parser.matchLatexOptionalGroup();
4235
- const base = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
4231
+ const degree = parser.parseOptionalGroup();
4232
+ const base = parser.parseGroup() ?? parser.parseToken();
4236
4233
  if (base === null || isEmptySequence(base)) {
4237
4234
  if (degree !== null)
4238
4235
  return ["Root", MISSING, missingIfEmpty(degree)];
@@ -4419,13 +4416,13 @@ function serializeMultiply(serializer, expr) {
4419
4416
  return isNegative ? "-" + result : result;
4420
4417
  }
4421
4418
  function parseFraction(parser) {
4422
- let numer = parser.matchLatexGroup();
4419
+ let numer = parser.parseGroup();
4423
4420
  let denom = null;
4424
4421
  if (numer === null) {
4425
- numer = parser.matchSingleAtomArgument();
4426
- denom = parser.matchSingleAtomArgument();
4422
+ numer = parser.parseToken();
4423
+ denom = parser.parseToken();
4427
4424
  } else {
4428
- denom = parser.matchLatexGroup();
4425
+ denom = parser.parseGroup();
4429
4426
  }
4430
4427
  numer = missingIfEmpty(numer);
4431
4428
  denom = missingIfEmpty(denom);
@@ -4433,7 +4430,7 @@ function parseFraction(parser) {
4433
4430
  const degree = op(numer, 3) ?? null;
4434
4431
  let fn = op(numer, 1);
4435
4432
  if (fn === null)
4436
- fn = missingIfEmpty(parser.matchExpression());
4433
+ fn = missingIfEmpty(parser.parseExpression());
4437
4434
  let vars = [];
4438
4435
  if (head(denom) === "Multiply") {
4439
4436
  for (const arg of ops(denom) ?? []) {
@@ -4562,7 +4559,7 @@ var DEFINITIONS_ARITHMETIC = [
4562
4559
  {
4563
4560
  trigger: ["\\ang"],
4564
4561
  parse: (parser) => {
4565
- const arg = parser.matchLatexGroup();
4562
+ const arg = parser.parseGroup();
4566
4563
  return arg === null ? ["Degrees"] : ["Degrees", arg];
4567
4564
  }
4568
4565
  },
@@ -4579,7 +4576,7 @@ var DEFINITIONS_ARITHMETIC = [
4579
4576
  trigger: ["\\tilde", "<{>", "\\infty", "<}>"],
4580
4577
  parse: "ComplexInfinity"
4581
4578
  },
4582
- { name: "Pi", trigger: ["\\pi"] },
4579
+ { name: "Pi", kind: "symbol", trigger: ["\\pi"] },
4583
4580
  { trigger: ["\u03C0"], parse: "Pi" },
4584
4581
  {
4585
4582
  name: "ExponentialE",
@@ -4590,11 +4587,11 @@ var DEFINITIONS_ARITHMETIC = [
4590
4587
  {
4591
4588
  kind: "function",
4592
4589
  trigger: "exp",
4593
- parse: (parser) => ["Exp", ...parser.matchArguments("enclosure") ?? []]
4590
+ parse: "Exp"
4594
4591
  },
4595
4592
  {
4596
4593
  trigger: "\\exp",
4597
- parse: (parser) => ["Exp", ...parser.matchArguments("enclosure") ?? []]
4594
+ parse: "Exp"
4598
4595
  },
4599
4596
  {
4600
4597
  name: "ImaginaryUnit",
@@ -4615,10 +4612,7 @@ var DEFINITIONS_ARITHMETIC = [
4615
4612
  {
4616
4613
  trigger: "abs",
4617
4614
  kind: "function",
4618
- parse: (parser) => {
4619
- const arg = parser.matchArguments("enclosure");
4620
- return arg === null ? "Abs" : ["Abs", ...arg];
4621
- }
4615
+ parse: "Abs"
4622
4616
  },
4623
4617
  {
4624
4618
  name: "Add",
@@ -4626,10 +4620,10 @@ var DEFINITIONS_ARITHMETIC = [
4626
4620
  kind: "infix",
4627
4621
  associativity: "both",
4628
4622
  precedence: 275,
4629
- parse: (parser, until, lhs) => {
4630
- if (275 < until.minPrec)
4623
+ parse: (parser, lhs, until) => {
4624
+ if (until && 275 < until.minPrec)
4631
4625
  return null;
4632
- const rhs = parser.matchExpression({ ...until, minPrec: 275 });
4626
+ const rhs = parser.parseExpression({ ...until, minPrec: 275 });
4633
4627
  if (rhs === null)
4634
4628
  return null;
4635
4629
  return applyAssociativeOperator("Add", lhs, rhs);
@@ -4641,9 +4635,9 @@ var DEFINITIONS_ARITHMETIC = [
4641
4635
  trigger: ["+"],
4642
4636
  precedence: 275,
4643
4637
  parse: (parser, until) => {
4644
- if (275 < until.minPrec)
4638
+ if (until && 275 < until.minPrec)
4645
4639
  return null;
4646
- return parser.matchExpression({ ...until, minPrec: 400 });
4640
+ return parser.parseExpression({ ...until, minPrec: 400 });
4647
4641
  }
4648
4642
  },
4649
4643
  {
@@ -4652,13 +4646,16 @@ var DEFINITIONS_ARITHMETIC = [
4652
4646
  openDelimiter: "\\lceil",
4653
4647
  closeDelimiter: "\\rceil"
4654
4648
  },
4649
+ {
4650
+ kind: "matchfix",
4651
+ openDelimiter: ["\u2308"],
4652
+ closeDelimiter: ["\u2309"],
4653
+ parse: (_, body) => ["Ceil", body]
4654
+ },
4655
4655
  {
4656
4656
  trigger: "ceil",
4657
4657
  kind: "function",
4658
- parse: (parser) => {
4659
- const arg = parser.matchArguments("enclosure");
4660
- return arg === null ? "Ceil" : ["Ceil", ...arg];
4661
- }
4658
+ parse: "Ceil"
4662
4659
  },
4663
4660
  {
4664
4661
  name: "Complex",
@@ -4744,13 +4741,16 @@ var DEFINITIONS_ARITHMETIC = [
4744
4741
  openDelimiter: "\\lfloor",
4745
4742
  closeDelimiter: "\\rfloor"
4746
4743
  },
4744
+ {
4745
+ kind: "matchfix",
4746
+ openDelimiter: ["\u230A"],
4747
+ closeDelimiter: ["\u230B"],
4748
+ parse: (_, body) => ["Floor", body]
4749
+ },
4747
4750
  {
4748
4751
  trigger: "floor",
4749
4752
  kind: "function",
4750
- parse: (parser) => {
4751
- const arg = parser.matchArguments("enclosure");
4752
- return arg === null ? "Floor" : ["Floor", ...arg];
4753
- }
4753
+ parse: "Floor"
4754
4754
  },
4755
4755
  {
4756
4756
  name: "Gcd",
@@ -4766,9 +4766,9 @@ var DEFINITIONS_ARITHMETIC = [
4766
4766
  trigger: ["\\lg"],
4767
4767
  serialize: (serializer, expr) => "\\log_{10}" + serializer.wrapArguments(expr),
4768
4768
  parse: (parser) => {
4769
- const arg = parser.matchArguments("implicit");
4769
+ const arg = parser.parseArguments("implicit");
4770
4770
  if (arg === null)
4771
- return ["Lg"];
4771
+ return "Lg";
4772
4772
  return ["Log", ...arg, 10];
4773
4773
  }
4774
4774
  },
@@ -4776,9 +4776,9 @@ var DEFINITIONS_ARITHMETIC = [
4776
4776
  name: "Lb",
4777
4777
  trigger: "\\lb",
4778
4778
  parse: (parser) => {
4779
- const arg = parser.matchArguments("implicit");
4779
+ const arg = parser.parseArguments("implicit");
4780
4780
  if (arg === null)
4781
- return ["Log"];
4781
+ return "Log";
4782
4782
  return ["Log", ...arg, 2];
4783
4783
  }
4784
4784
  },
@@ -4829,10 +4829,10 @@ var DEFINITIONS_ARITHMETIC = [
4829
4829
  kind: "infix",
4830
4830
  associativity: "both",
4831
4831
  precedence: 390,
4832
- parse: (parser, terminator, lhs) => {
4833
- if (391 < terminator.minPrec)
4832
+ parse: (parser, lhs, terminator) => {
4833
+ if (terminator && 391 < terminator.minPrec)
4834
4834
  return null;
4835
- const rhs = parser.matchExpression({ ...terminator, minPrec: 392 });
4835
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 392 });
4836
4836
  if (rhs === null)
4837
4837
  return ["Multiply", lhs, MISSING];
4838
4838
  return applyAssociativeOperator("Multiply", lhs, rhs);
@@ -4843,10 +4843,10 @@ var DEFINITIONS_ARITHMETIC = [
4843
4843
  kind: "infix",
4844
4844
  associativity: "both",
4845
4845
  precedence: 390,
4846
- parse: (parser, terminator, lhs) => {
4847
- if (391 < terminator.minPrec)
4846
+ parse: (parser, lhs, terminator) => {
4847
+ if (terminator && 391 < terminator.minPrec)
4848
4848
  return null;
4849
- const rhs = parser.matchExpression({ ...terminator, minPrec: 392 });
4849
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 392 });
4850
4850
  if (rhs === null)
4851
4851
  return ["Multiply", lhs, MISSING];
4852
4852
  return applyAssociativeOperator("Multiply", lhs, rhs);
@@ -4857,9 +4857,9 @@ var DEFINITIONS_ARITHMETIC = [
4857
4857
  trigger: ["-"],
4858
4858
  kind: "prefix",
4859
4859
  parse: (parser, terminator) => {
4860
- if (276 < terminator.minPrec)
4860
+ if (terminator && 276 < terminator.minPrec)
4861
4861
  return null;
4862
- const rhs = parser.matchExpression({ ...terminator, minPrec: 400 });
4862
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4863
4863
  return ["Negate", missingIfEmpty(rhs)];
4864
4864
  },
4865
4865
  precedence: 275
@@ -4921,9 +4921,32 @@ var DEFINITIONS_ARITHMETIC = [
4921
4921
  kind: "prefix",
4922
4922
  precedence: 270,
4923
4923
  parse: (parser, terminator) => {
4924
+ if (terminator && 270 < terminator.minPrec)
4925
+ return null;
4926
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4927
+ return ["PlusMinus", missingIfEmpty(rhs)];
4928
+ }
4929
+ },
4930
+ {
4931
+ trigger: ["\\plusmn"],
4932
+ kind: "infix",
4933
+ associativity: "both",
4934
+ precedence: 270,
4935
+ parse: (parser, lhs, terminator) => {
4924
4936
  if (270 < terminator.minPrec)
4925
4937
  return null;
4926
- const rhs = parser.matchExpression({ ...terminator, minPrec: 400 });
4938
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4939
+ return ["PlusMinus", lhs, missingIfEmpty(rhs)];
4940
+ }
4941
+ },
4942
+ {
4943
+ trigger: ["\\plusmn"],
4944
+ kind: "prefix",
4945
+ precedence: 270,
4946
+ parse: (parser, terminator) => {
4947
+ if (terminator && 270 < terminator.minPrec)
4948
+ return null;
4949
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 400 });
4927
4950
  return ["PlusMinus", missingIfEmpty(rhs)];
4928
4951
  }
4929
4952
  },
@@ -4994,10 +5017,10 @@ var DEFINITIONS_ARITHMETIC = [
4994
5017
  kind: "infix",
4995
5018
  associativity: "both",
4996
5019
  precedence: 275,
4997
- parse: (parser, terminator, lhs) => {
5020
+ parse: (parser, lhs, terminator) => {
4998
5021
  if (276 < terminator.minPrec)
4999
5022
  return null;
5000
- const rhs = parser.matchExpression({ ...terminator, minPrec: 277 });
5023
+ const rhs = parser.parseExpression({ ...terminator, minPrec: 277 });
5001
5024
  return ["Subtract", lhs, missingIfEmpty(rhs)];
5002
5025
  }
5003
5026
  }
@@ -5009,9 +5032,9 @@ function parseBigOp(name, prec) {
5009
5032
  let sub2 = null;
5010
5033
  while (!(sub2 && sup) && (parser.peek === "_" || parser.peek === "^")) {
5011
5034
  if (parser.match("_"))
5012
- sub2 = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
5035
+ sub2 = parser.parseGroup() ?? parser.parseToken();
5013
5036
  else if (parser.match("^"))
5014
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
5037
+ sup = parser.parseGroup() ?? parser.parseToken();
5015
5038
  parser.skipSpace();
5016
5039
  }
5017
5040
  if (sub2 === "Nothing" || isEmptySequence(sub2))
@@ -5029,7 +5052,7 @@ function parseBigOp(name, prec) {
5029
5052
  const sym = symbol(index);
5030
5053
  if (sym)
5031
5054
  parser.computeEngine?.pushScope({ [sym]: { domain: "Integer" } });
5032
- const fn = parser.matchExpression({ minPrec: prec + 1 });
5055
+ const fn = parser.parseExpression({ minPrec: prec + 1 });
5033
5056
  if (sym)
5034
5057
  parser.computeEngine?.popScope();
5035
5058
  if (!fn)
@@ -5090,10 +5113,10 @@ function parseLog(command, parser) {
5090
5113
  let sub2 = null;
5091
5114
  let base = null;
5092
5115
  if (parser.match("_")) {
5093
- sub2 = parser.matchStringArgument() ?? parser.next();
5116
+ sub2 = parser.parseStringGroup()?.trim() ?? parser.nextToken();
5094
5117
  base = Number.parseFloat(sub2 ?? "10");
5095
5118
  }
5096
- const arg = parser.matchArguments("implicit");
5119
+ const arg = parser.parseArguments("implicit");
5097
5120
  if (arg === null)
5098
5121
  return [command];
5099
5122
  if (base === 10)
@@ -5122,7 +5145,7 @@ function parseSequence(parser, terminator, lhs, prec, sep) {
5122
5145
  if (parser.atTerminator(terminator)) {
5123
5146
  result.push("Nothing");
5124
5147
  } else {
5125
- const rhs = parser.matchExpression({ ...terminator, minPrec: prec });
5148
+ const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
5126
5149
  result.push(rhs ?? "Nothing");
5127
5150
  done = rhs === null;
5128
5151
  }
@@ -5142,15 +5165,18 @@ var DEFINITIONS_CORE = [
5142
5165
  //
5143
5166
  {
5144
5167
  trigger: ["\\placeholder"],
5168
+ kind: "symbol",
5145
5169
  parse: (parser) => {
5146
- parser.skipSpaceTokens();
5170
+ while (parser.match("<space>")) {
5171
+ }
5147
5172
  if (parser.match("["))
5148
5173
  while (!parser.match("]") && !parser.atBoundary)
5149
- parser.next();
5150
- parser.skipSpaceTokens();
5174
+ parser.nextToken();
5175
+ while (parser.match("<space>")) {
5176
+ }
5151
5177
  if (parser.match("<{>"))
5152
5178
  while (!parser.match("<}>") && !parser.atBoundary)
5153
- parser.next();
5179
+ parser.nextToken();
5154
5180
  return "Nothing";
5155
5181
  }
5156
5182
  },
@@ -5159,7 +5185,6 @@ var DEFINITIONS_CORE = [
5159
5185
  //
5160
5186
  {
5161
5187
  name: "BaseForm",
5162
- kind: "function",
5163
5188
  serialize: (serializer, expr) => {
5164
5189
  const radix = machineValue(op(expr, 2)) ?? NaN;
5165
5190
  if (isFinite(radix) && radix >= 2 && radix <= 36) {
@@ -5206,9 +5231,9 @@ var DEFINITIONS_CORE = [
5206
5231
  let close = "";
5207
5232
  if (argCount > 1) {
5208
5233
  const op22 = stringValue(op(expr, 2)) ?? "";
5209
- open = op22[0] ?? "";
5210
- close = op22[1] ?? "";
5211
- sep = op22[2] ?? "";
5234
+ open = op22[0] ?? "(";
5235
+ close = op22[1] ?? ")";
5236
+ sep = op22[2] ?? ",";
5212
5237
  }
5213
5238
  const body = head(arg1) === "List" ? serializeSequence(sep)(serializer, arg1) : serializer.serialize(arg1);
5214
5239
  serializer.wrapString(body, style, stringValue(op(expr, 2)) ?? void 0);
@@ -5228,22 +5253,22 @@ var DEFINITIONS_CORE = [
5228
5253
  {
5229
5254
  trigger: ["\\mathtip"],
5230
5255
  parse: (parser) => {
5231
- const op12 = parser.matchLatexGroup();
5232
- const op22 = parser.matchLatexGroup();
5256
+ const op12 = parser.parseGroup();
5257
+ const op22 = parser.parseGroup();
5233
5258
  return op12;
5234
5259
  }
5235
5260
  },
5236
5261
  {
5237
5262
  trigger: ["\\texttip"],
5238
5263
  parse: (parser) => {
5239
- const op12 = parser.matchLatexGroup();
5240
- const op22 = parser.matchLatexGroup();
5264
+ const op12 = parser.parseGroup();
5265
+ const op22 = parser.parseGroup();
5241
5266
  return op12;
5242
5267
  }
5243
5268
  },
5244
5269
  {
5245
5270
  trigger: ["\\error"],
5246
- parse: (parser) => parser.matchLatexGroup()
5271
+ parse: (parser) => parser.parseGroup()
5247
5272
  },
5248
5273
  {
5249
5274
  name: "Error",
@@ -5305,12 +5330,12 @@ var DEFINITIONS_CORE = [
5305
5330
  kind: "matchfix",
5306
5331
  openDelimiter: "[",
5307
5332
  closeDelimiter: "]",
5308
- parse: (_parser, lhs) => {
5309
- if (lhs === null)
5333
+ parse: (_parser, body) => {
5334
+ if (body === null)
5310
5335
  return ["List"];
5311
- if (head(lhs) !== "Sequence" && head(lhs) !== "List")
5312
- return ["List", lhs];
5313
- return ["List", ...ops(lhs) ?? []];
5336
+ if (head(body) !== "Sequence" && head(body) !== "List")
5337
+ return ["List", body];
5338
+ return ["List", ...ops(body) ?? []];
5314
5339
  },
5315
5340
  serialize: (serializer, expr) => {
5316
5341
  return joinLatex([
@@ -5343,8 +5368,8 @@ var DEFINITIONS_CORE = [
5343
5368
  // when the comma operator is used, the lhs and rhs are flattened,
5344
5369
  // i.e. `1,2,3` -> `["Delimiter", ["List", 1, 2, 3], ","]`,
5345
5370
  // and `1, (2, 3)` -> `["Delimiter",
5346
- // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "(", ",", ")"]], ","],
5347
- parse: (parser, terminator, lhs) => {
5371
+ // ["Sequence", 1, ["Delimiter", ["List", 2, 3], "()", ","]]],
5372
+ parse: (parser, lhs, terminator) => {
5348
5373
  const seq = parseSequence(parser, terminator, lhs, 20, ",");
5349
5374
  if (seq === null)
5350
5375
  return null;
@@ -5359,7 +5384,7 @@ var DEFINITIONS_CORE = [
5359
5384
  trigger: [";"],
5360
5385
  kind: "infix",
5361
5386
  precedence: 19,
5362
- parse: (parser, terminator, lhs) => {
5387
+ parse: (parser, lhs, terminator) => {
5363
5388
  const seq = parseSequence(parser, terminator, lhs, 19, ";");
5364
5389
  if (seq === null)
5365
5390
  return null;
@@ -5431,10 +5456,20 @@ var DEFINITIONS_CORE = [
5431
5456
  kind: "postfix",
5432
5457
  parse: (_parser, lhs) => ["Prime", missingIfEmpty(lhs), 2]
5433
5458
  },
5459
+ {
5460
+ trigger: ["^", "\\tripleprime"],
5461
+ kind: "postfix",
5462
+ parse: (_parser, lhs) => ["Prime", missingIfEmpty(lhs), 3]
5463
+ },
5434
5464
  {
5435
5465
  name: "InverseFunction",
5436
- // trigger: '^{-1}',
5437
- // kind: 'postfix',
5466
+ trigger: "^{-1}",
5467
+ kind: "postfix",
5468
+ parse: (parser, lhs) => {
5469
+ if (parser.computeEngine?.box(lhs)?.domain.isFunction)
5470
+ return ["InverseFunction", lhs];
5471
+ return null;
5472
+ },
5438
5473
  serialize: (serializer, expr) => serializer.serialize(op(expr, 1)) + "^{-1}"
5439
5474
  },
5440
5475
  {
@@ -5444,9 +5479,9 @@ var DEFINITIONS_CORE = [
5444
5479
  const base = serializer.serialize(op(expr, 1));
5445
5480
  if (degree === 1)
5446
5481
  return base + "^{\\prime}";
5447
- else if (degree === 2)
5482
+ if (degree === 2)
5448
5483
  return base + "^{\\doubleprime}";
5449
- else if (degree === 3)
5484
+ if (degree === 3)
5450
5485
  return base + "^{\\tripleprime}";
5451
5486
  return base + "^{(" + Number(degree).toString() + ")}";
5452
5487
  }
@@ -5456,7 +5491,7 @@ var DEFINITIONS_CORE = [
5456
5491
  trigger: "cases",
5457
5492
  kind: "environment",
5458
5493
  parse: (parser) => {
5459
- const tabular = parser.matchTabular("cases");
5494
+ const tabular = parser.parseTabular();
5460
5495
  if (!tabular)
5461
5496
  return ["Which"];
5462
5497
  const result = ["Which"];
@@ -5505,9 +5540,9 @@ function parseTextRun(parser, style) {
5505
5540
  runs.push(parseTextRun(parser));
5506
5541
  } else if (parser.match("\\textbf") && parser.match("<{>")) {
5507
5542
  runs.push(parseTextRun(parser, { "font-weight": "bold" }));
5508
- } else if (parser.match("\\color") && parser.match("<{>")) {
5509
- const color = parser.matchColor();
5510
- if (color && parser.match("<}>")) {
5543
+ } else if (parser.match("\\color")) {
5544
+ const color = parser.parseStringGroup();
5545
+ if (color !== null) {
5511
5546
  if (runinStyle !== null && text) {
5512
5547
  runs.push(["Style", text, { dict: runinStyle }]);
5513
5548
  } else if (text) {
@@ -5520,7 +5555,7 @@ function parseTextRun(parser, style) {
5520
5555
  text += " ";
5521
5556
  } else if (parser.match("<$>")) {
5522
5557
  const index = parser.index;
5523
- const expr = parser.matchExpression() ?? ["Sequence"];
5558
+ const expr = parser.parseExpression() ?? ["Sequence"];
5524
5559
  parser.skipSpace();
5525
5560
  if (parser.match("<$>")) {
5526
5561
  runs.push(expr);
@@ -5530,7 +5565,7 @@ function parseTextRun(parser, style) {
5530
5565
  }
5531
5566
  } else if (parser.match("<$$>")) {
5532
5567
  const index = parser.index;
5533
- const expr = parser.matchExpression() ?? ["Sequence"];
5568
+ const expr = parser.parseExpression() ?? ["Sequence"];
5534
5569
  parser.skipSpace();
5535
5570
  if (parser.match("<$$>")) {
5536
5571
  runs.push(expr);
@@ -5539,7 +5574,7 @@ function parseTextRun(parser, style) {
5539
5574
  parser.index = index;
5540
5575
  }
5541
5576
  } else
5542
- text += parser.matchChar() ?? parser.next();
5577
+ text += parser.matchChar() ?? parser.nextToken();
5543
5578
  }
5544
5579
  if (runinStyle !== null && text) {
5545
5580
  runs.push(["Style", `'${text}'`, { dict: runinStyle }]);
@@ -5608,7 +5643,7 @@ function errorContextAsLatex(serializer, error) {
5608
5643
  // src/compute-engine/latex-syntax/dictionary/definitions-inequalities.ts
5609
5644
  var DEFINITIONS_INEQUALITIES = [
5610
5645
  {
5611
- trigger: ["!", "<"],
5646
+ trigger: ["\\not", "<"],
5612
5647
  kind: "infix",
5613
5648
  associativity: "right",
5614
5649
  precedence: 246,
@@ -5790,7 +5825,7 @@ var DEFINITIONS_INEQUALITIES = [
5790
5825
  {
5791
5826
  name: "NotApprox",
5792
5827
  // Note: Mathematica TildeTilde
5793
- trigger: ["\\approx"],
5828
+ trigger: ["\\not", "\\approx"],
5794
5829
  kind: "infix",
5795
5830
  associativity: "right",
5796
5831
  precedence: 247
@@ -5806,7 +5841,7 @@ var DEFINITIONS_INEQUALITIES = [
5806
5841
  {
5807
5842
  name: "NotApproxEqual",
5808
5843
  // Note: Mathematica NotTildeEqual
5809
- trigger: ["!", "\\approxeq"],
5844
+ trigger: ["\\not", "\\approxeq"],
5810
5845
  kind: "infix",
5811
5846
  // Note: no LaTeX symbol for char U+2249
5812
5847
  associativity: "right",
@@ -5894,7 +5929,7 @@ var DEFINITIONS_INEQUALITIES = [
5894
5929
  precedence: 244
5895
5930
  },
5896
5931
  {
5897
- trigger: ["!", ">"],
5932
+ trigger: ["\\not", ">"],
5898
5933
  kind: "infix",
5899
5934
  associativity: "right",
5900
5935
  precedence: 244,
@@ -6057,7 +6092,7 @@ var DEFINITIONS_LOGIC = [
6057
6092
  // src/compute-engine/latex-syntax/dictionary/definitions-other.ts
6058
6093
  function parseSingleArg(cmd) {
6059
6094
  return (parser) => {
6060
- const arg = parser.matchLatexGroup();
6095
+ const arg = parser.parseGroup();
6061
6096
  return arg === null ? [cmd] : [cmd, arg];
6062
6097
  };
6063
6098
  }
@@ -6111,14 +6146,14 @@ var DEFINITIONS_OTHERS = [
6111
6146
  {
6112
6147
  name: "Transpose",
6113
6148
  trigger: ["^", "T"],
6114
- kind: "infix"
6149
+ kind: "postfix"
6115
6150
  // @todo: if lhs is a list/tensor
6116
6151
  },
6117
6152
  {
6118
6153
  // @todo: if lhs is a list/tensor
6119
6154
  name: "ConjugateTranspose",
6120
6155
  trigger: ["^", "H"],
6121
- kind: "infix"
6156
+ kind: "postfix"
6122
6157
  },
6123
6158
  {
6124
6159
  name: "StringJoin",
@@ -6148,9 +6183,9 @@ var DEFINITIONS_OTHERS = [
6148
6183
  while (!done) {
6149
6184
  parser.skipSpace();
6150
6185
  if (parser.match("_")) {
6151
- sub2 = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
6186
+ sub2 = parser.parseGroup() ?? parser.parseToken();
6152
6187
  } else if (parser.match("^")) {
6153
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
6188
+ sup = parser.parseGroup() ?? parser.parseToken();
6154
6189
  } else {
6155
6190
  done = true;
6156
6191
  }
@@ -6160,9 +6195,9 @@ var DEFINITIONS_OTHERS = [
6160
6195
  sub2 = ["List", ...seq];
6161
6196
  if (sub2 === null || sup === null)
6162
6197
  return null;
6163
- let rhs = parser.matchLatexGroup() ?? "Nothing";
6198
+ let rhs = parser.parseGroup() ?? "Nothing";
6164
6199
  if (rhs !== "Nothing" && !isEmptySequence(rhs)) {
6165
- const arg = parser.matchArguments("enclosure") ?? ["Nothing"];
6200
+ const arg = parser.parseArguments() ?? ["Nothing"];
6166
6201
  rhs = [rhs, ...arg];
6167
6202
  }
6168
6203
  return ["PartialDerivative", rhs, sub2, sup];
@@ -6439,7 +6474,7 @@ var DEFINITIONS_OTHERS = [
6439
6474
  // src/compute-engine/latex-syntax/dictionary/definitions-trigonometry.ts
6440
6475
  function parseTrig(op3) {
6441
6476
  return (parser, until) => {
6442
- let head2 = {
6477
+ const head2 = {
6443
6478
  "\\arcsin": "Arcsin",
6444
6479
  "\\arccos": "Arccos",
6445
6480
  "\\arctan": "Arctan",
@@ -6474,37 +6509,11 @@ function parseTrig(op3) {
6474
6509
  }[op3 ?? ""] ?? op3 ?? "";
6475
6510
  if (parser.atTerminator(until))
6476
6511
  return head2;
6477
- let isInverse = false;
6478
- let primeLevel = 0;
6479
- let sup = null;
6480
- parser.skipSpace();
6481
- const start = parser.index;
6482
- if (parser.match("^")) {
6483
- parser.skipSpace();
6484
- const superscriptIndex = parser.index;
6485
- if (parser.matchAll(["<{>", "-", "1", "<}>"]))
6486
- isInverse = true;
6487
- else {
6488
- parser.index = start;
6489
- parser.index = start;
6490
- primeLevel = parser.matchPrimeSuffix();
6491
- if (primeLevel === 0) {
6492
- parser.index = superscriptIndex;
6493
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
6494
- }
6495
- }
6496
- }
6497
- primeLevel += parser.matchPrimeSuffix();
6498
- if (isInverse)
6499
- head2 = ["InverseFunction", head2];
6500
- if (primeLevel === 1)
6501
- head2 = ["Derivative", head2];
6502
- else if (primeLevel > 1)
6503
- head2 = ["Derivative", head2, primeLevel];
6504
- const args = parser.matchArguments("implicit", until);
6505
- if (args === null)
6506
- return sup ? [["Power", [head2], sup]] : head2;
6507
- return sup ? ["Power", [head2, ...args], sup] : [head2, ...args];
6512
+ const fn = parser.parsePostfixOperator(head2, until);
6513
+ if (fn !== null)
6514
+ return fn;
6515
+ const args = parser.parseArguments("implicit", until);
6516
+ return args === null ? head2 : [head2, ...args];
6508
6517
  };
6509
6518
  }
6510
6519
  var DEFINITIONS_TRIGONOMETRY = [
@@ -6533,7 +6542,6 @@ var DEFINITIONS_TRIGONOMETRY = [
6533
6542
  parse: parseTrig("Arccot")
6534
6543
  },
6535
6544
  {
6536
- kind: "function",
6537
6545
  name: "Arcsec",
6538
6546
  trigger: "arcsec",
6539
6547
  parse: parseTrig("Arcsec")
@@ -6734,14 +6742,14 @@ var DEFINITIONS_SETS = [
6734
6742
  // Caution: cartesian product is not associative
6735
6743
  precedence: 390,
6736
6744
  // Same as Multiply?
6737
- parse: (parser, until, lhs) => {
6745
+ parse: (parser, lhs, until) => {
6738
6746
  if (390 < until.minPrec)
6739
6747
  return null;
6740
6748
  const ce = parser.computeEngine;
6741
6749
  if (!ce || !ce.box(lhs).domain.isCompatible("Set"))
6742
6750
  return null;
6743
6751
  const index = parser.index;
6744
- const rhs = parser.matchExpression({ ...until, minPrec: 390 });
6752
+ const rhs = parser.parseExpression({ ...until, minPrec: 390 });
6745
6753
  if (rhs === null || ce.box(lhs).domain.isCompatible("Set") !== true) {
6746
6754
  parser.index = index;
6747
6755
  return null;
@@ -6821,8 +6829,8 @@ var DEFINITIONS_SETS = [
6821
6829
  associativity: "right",
6822
6830
  precedence: 160,
6823
6831
  // As per MathML, lower precedence
6824
- parse: (parser, terminator, lhs) => {
6825
- const rhs = parser.matchExpression(terminator);
6832
+ parse: (parser, lhs, terminator) => {
6833
+ const rhs = parser.parseExpression(terminator);
6826
6834
  return rhs === null ? null : ["Element", rhs, lhs];
6827
6835
  }
6828
6836
  },
@@ -7027,9 +7035,10 @@ function parseIntegral(command, n = 1) {
7027
7035
  let sub2 = null;
7028
7036
  while (!(sub2 !== null && sup !== null) && (parser.peek === "_" || parser.peek === "^")) {
7029
7037
  if (parser.match("_"))
7030
- sub2 = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
7031
- else if (parser.match("^"))
7032
- sup = parser.matchLatexGroup() ?? parser.matchSingleAtomArgument();
7038
+ sub2 = parser.parseGroup() ?? parser.parseToken();
7039
+ else if (parser.match("^")) {
7040
+ sup = parser.parseGroup() ?? parser.parseToken();
7041
+ }
7033
7042
  parser.skipSpace();
7034
7043
  }
7035
7044
  if (sub2 === "Nothing" || isEmptySequence(sub2))
@@ -7105,7 +7114,7 @@ function makeRange(range) {
7105
7114
  function parseIntegralBody(parser, n = 1) {
7106
7115
  const start = parser.index;
7107
7116
  let found = false;
7108
- let fn = parser.matchExpression({
7117
+ let fn = parser.parseExpression({
7109
7118
  minPrec: 266,
7110
7119
  condition: () => {
7111
7120
  if (parser.matchAll(["\\mathrm", "<{>", "d", "<}>"]))
@@ -7115,7 +7124,7 @@ function parseIntegralBody(parser, n = 1) {
7115
7124
  });
7116
7125
  if (!found) {
7117
7126
  parser.index = start;
7118
- fn = parser.matchExpression({
7127
+ fn = parser.parseExpression({
7119
7128
  minPrec: 266,
7120
7129
  condition: () => {
7121
7130
  if (parser.match("d"))
@@ -7132,7 +7141,7 @@ function parseIntegralBody(parser, n = 1) {
7132
7141
  function parseIndexes(parser, n = 1) {
7133
7142
  parser.skipSpace();
7134
7143
  const result = [];
7135
- const index = symbol(parser.matchSymbol());
7144
+ const index = symbol(parser.parseSymbol());
7136
7145
  if (index === null)
7137
7146
  return [];
7138
7147
  result.push(index);
@@ -7251,30 +7260,36 @@ function serializeIntegral(command) {
7251
7260
  }
7252
7261
  var DEFINITIONS_CALCULUS = [
7253
7262
  {
7263
+ kind: "expression",
7254
7264
  name: "Integrate",
7255
7265
  trigger: ["\\int"],
7256
7266
  parse: parseIntegral("Integrate"),
7257
7267
  serialize: serializeIntegral("\\int")
7258
7268
  },
7259
7269
  {
7270
+ kind: "expression",
7260
7271
  trigger: ["\\iint"],
7261
7272
  parse: parseIntegral("Integrate", 2)
7262
7273
  },
7263
7274
  {
7275
+ kind: "expression",
7264
7276
  trigger: ["\\iiint"],
7265
7277
  parse: parseIntegral("Integrate", 3)
7266
7278
  },
7267
7279
  {
7280
+ kind: "expression",
7268
7281
  name: "CircularIntegrate",
7269
7282
  trigger: ["\\oint"],
7270
7283
  parse: parseIntegral("CircularIntegrate"),
7271
7284
  serialize: serializeIntegral("\\oint")
7272
7285
  },
7273
7286
  {
7287
+ kind: "expression",
7274
7288
  trigger: ["\\oiint"],
7275
7289
  parse: parseIntegral("CircularIntegrate", 2)
7276
7290
  },
7277
7291
  {
7292
+ kind: "expression",
7278
7293
  trigger: ["\\oiiint"],
7279
7294
  parse: parseIntegral("CircularIntegrate", 3)
7280
7295
  }
@@ -7380,6 +7395,7 @@ var SYMBOLS = [
7380
7395
  var DEFINITIONS_SYMBOLS = [
7381
7396
  ...SYMBOLS.map(([symbol2, latex, _codepoint]) => {
7382
7397
  return {
7398
+ kind: "symbol",
7383
7399
  name: symbol2,
7384
7400
  trigger: [latex],
7385
7401
  parse: symbol2
@@ -7387,6 +7403,7 @@ var DEFINITIONS_SYMBOLS = [
7387
7403
  }),
7388
7404
  ...SYMBOLS.map(([symbol2, _latex, codepoint]) => {
7389
7405
  return {
7406
+ kind: "symbol",
7390
7407
  trigger: [String.fromCodePoint(codepoint)],
7391
7408
  parse: symbol2
7392
7409
  };
@@ -7415,98 +7432,99 @@ function triggerLength(trigger) {
7415
7432
  return trigger.length;
7416
7433
  return 1;
7417
7434
  }
7435
+ function addEntry(result, entry, onError) {
7436
+ const [trigger, indexedEntry] = makeIndexedEntry(entry, onError);
7437
+ if (indexedEntry === null)
7438
+ return;
7439
+ const kind = "kind" in entry ? entry.kind : "expression";
7440
+ if (trigger && trigger.length === 2 && /[_^]/.test(trigger[0]) && trigger[1] !== "<{>" && kind !== "function" && entry.name) {
7441
+ let parse = entry.parse;
7442
+ if (parse === void 0) {
7443
+ if (kind === "symbol")
7444
+ parse = entry.name;
7445
+ if (kind === "postfix" || kind === "prefix")
7446
+ parse = (_parser, expr) => [entry.name, expr];
7447
+ }
7448
+ addEntry(
7449
+ result,
7450
+ {
7451
+ ...entry,
7452
+ kind,
7453
+ parse,
7454
+ name: void 0,
7455
+ trigger: [trigger[0], "<{>", trigger[1], "<}>"]
7456
+ },
7457
+ onError
7458
+ );
7459
+ }
7460
+ if (indexedEntry.name !== void 0) {
7461
+ if (result.name.has(indexedEntry.name)) {
7462
+ onError({
7463
+ severity: "warning",
7464
+ message: [
7465
+ "invalid-dictionary-entry",
7466
+ indexedEntry.name,
7467
+ "Duplicate definition. The name must be unique, but a trigger can be used by multiple definitions."
7468
+ ]
7469
+ });
7470
+ }
7471
+ result.name.set(indexedEntry.name, indexedEntry);
7472
+ }
7473
+ if (indexedEntry.kind === "matchfix") {
7474
+ result.matchfix.push(indexedEntry);
7475
+ } else if (indexedEntry.kind === "environment") {
7476
+ const triggerString = tokensToString(entry.trigger ?? "");
7477
+ if (result.environment.has(triggerString)) {
7478
+ onError({
7479
+ severity: "warning",
7480
+ message: [
7481
+ "invalid-dictionary-entry",
7482
+ triggerString,
7483
+ "Duplicate environment definition"
7484
+ ]
7485
+ });
7486
+ }
7487
+ result.environment.set(triggerString, indexedEntry);
7488
+ } else if (trigger) {
7489
+ console.assert(entry.trigger);
7490
+ const triggerString = tokensToString(entry.trigger ?? "");
7491
+ const n = triggerLength(trigger);
7492
+ result.lookahead = Math.max(result.lookahead, n);
7493
+ if (indexedEntry.kind === "function") {
7494
+ if (!result.function.has(triggerString))
7495
+ result.function.set(triggerString, [indexedEntry]);
7496
+ else
7497
+ result.function.set(triggerString, [
7498
+ ...result.function.get(triggerString),
7499
+ indexedEntry
7500
+ ]);
7501
+ } else {
7502
+ const kind2 = indexedEntry.kind;
7503
+ if (result[kind2][n] === void 0)
7504
+ result[kind2][n] = /* @__PURE__ */ new Map();
7505
+ const list = result[kind2][n];
7506
+ if (list.has(triggerString))
7507
+ list.get(triggerString).push(indexedEntry);
7508
+ else
7509
+ list.set(triggerString, [indexedEntry]);
7510
+ }
7511
+ }
7512
+ }
7418
7513
  function indexLatexDictionary(dic, onError) {
7419
7514
  const result = {
7420
7515
  lookahead: 1,
7421
7516
  name: /* @__PURE__ */ new Map(),
7517
+ expression: /* @__PURE__ */ new Map(),
7422
7518
  function: /* @__PURE__ */ new Map(),
7423
- identifier: [],
7519
+ symbol: [],
7424
7520
  infix: [],
7425
7521
  prefix: [],
7426
7522
  postfix: [],
7427
7523
  environment: /* @__PURE__ */ new Map(),
7428
7524
  matchfix: []
7429
7525
  };
7430
- for (const entry of dic) {
7431
- const [trigger, indexedEntry] = makeIndexedEntry(entry, onError);
7432
- if (indexedEntry === null)
7433
- continue;
7434
- if (indexedEntry.name !== void 0) {
7435
- if (result.name.has(indexedEntry.name)) {
7436
- onError({
7437
- severity: "warning",
7438
- message: [
7439
- "invalid-dictionary-entry",
7440
- indexedEntry.name,
7441
- "Duplicate definition. The name must be unique, but a trigger can be used by multiple definitions."
7442
- ]
7443
- });
7444
- }
7445
- result.name.set(indexedEntry.name, indexedEntry);
7446
- }
7447
- if (indexedEntry.kind === "matchfix") {
7448
- result.matchfix.push(indexedEntry);
7449
- } else if (indexedEntry.kind === "environment") {
7450
- const triggerString = tokensToString(entry.trigger ?? "");
7451
- if (result.environment.has(triggerString)) {
7452
- onError({
7453
- severity: "warning",
7454
- message: [
7455
- "invalid-dictionary-entry",
7456
- triggerString,
7457
- "Duplicate environment definition"
7458
- ]
7459
- });
7460
- }
7461
- result.environment.set(triggerString, indexedEntry);
7462
- } else if (trigger) {
7463
- console.assert(entry.trigger);
7464
- const triggerString = tokensToString(entry.trigger ?? "");
7465
- const n = triggerLength(trigger);
7466
- result.lookahead = Math.max(result.lookahead, n);
7467
- if (indexedEntry.kind === "function") {
7468
- if (!result.function.has(triggerString))
7469
- result.function.set(triggerString, [indexedEntry]);
7470
- else
7471
- result.function.set(triggerString, [
7472
- ...result.function.get(triggerString),
7473
- indexedEntry
7474
- ]);
7475
- } else if (indexedEntry.kind === "identifier") {
7476
- if (result.identifier[n] === void 0)
7477
- result.identifier[n] = /* @__PURE__ */ new Map();
7478
- const list = result.identifier[n];
7479
- if (list.has(triggerString))
7480
- list.get(triggerString).push(indexedEntry);
7481
- else
7482
- list.set(triggerString, [indexedEntry]);
7483
- } else if (indexedEntry.kind === "prefix") {
7484
- if (result.prefix[n] === void 0)
7485
- result.prefix[n] = /* @__PURE__ */ new Map();
7486
- const list = result.prefix[n];
7487
- if (list.has(triggerString))
7488
- list.get(triggerString).push(indexedEntry);
7489
- else
7490
- list.set(triggerString, [indexedEntry]);
7491
- } else if (indexedEntry.kind === "infix") {
7492
- if (result.infix[n] === void 0)
7493
- result.infix[n] = /* @__PURE__ */ new Map();
7494
- const list = result.infix[n];
7495
- if (list.has(triggerString))
7496
- list.get(triggerString).push(indexedEntry);
7497
- else
7498
- list.set(triggerString, [indexedEntry]);
7499
- } else if (indexedEntry.kind === "postfix") {
7500
- if (result.postfix[n] === void 0)
7501
- result.postfix[n] = /* @__PURE__ */ new Map();
7502
- const list = result.postfix[n];
7503
- if (list.has(triggerString))
7504
- list.get(triggerString).push(indexedEntry);
7505
- else
7506
- list.set(triggerString, [indexedEntry]);
7507
- }
7508
- }
7509
- }
7526
+ for (const entry of dic)
7527
+ addEntry(result, entry, onError);
7510
7528
  return result;
7511
7529
  }
7512
7530
  function makeIndexedEntry(entry, onError) {
@@ -7514,7 +7532,7 @@ function makeIndexedEntry(entry, onError) {
7514
7532
  return [null, null];
7515
7533
  const result = {
7516
7534
  name: entry.name,
7517
- kind: "kind" in entry ? entry.kind : "identifier"
7535
+ kind: "kind" in entry ? entry.kind : "expression"
7518
7536
  };
7519
7537
  if (result.kind === "matchfix" && isMatchfixEntry(entry)) {
7520
7538
  result.openDelimiter = entry.openDelimiter;
@@ -7547,29 +7565,57 @@ function makeIndexedEntry(entry, onError) {
7547
7565
  const triggerString = trigger ? tokensToString(trigger) : "";
7548
7566
  if (result.kind === "function" && isFunctionEntry(entry)) {
7549
7567
  result.serialize = entry.serialize;
7550
- if (triggerString && !entry.serialize)
7551
- result.serialize = (serializer, expr) => `\\mathrm{${triggerString}}${serializer.wrapArguments(expr)}`;
7552
- result.parse = entry.parse;
7553
- if (!result.parse && entry.name)
7554
- result.parse = (parser) => {
7555
- const arg = parser.matchArguments("enclosure");
7556
- return arg === null ? entry.name : [entry.name, ...arg];
7557
- };
7568
+ if (triggerString && !entry.serialize) {
7569
+ if (triggerString.startsWith("\\")) {
7570
+ result.serialize = (serializer, expr) => `${triggerString}${serializer.wrapArguments(expr)}`;
7571
+ } else
7572
+ result.serialize = (serializer, expr) => `\\mathrm{${triggerString}}${serializer.wrapArguments(expr)}`;
7573
+ }
7574
+ if (typeof entry.parse === "function")
7575
+ result.parse = entry.parse;
7576
+ else if (typeof entry.parse === "string")
7577
+ result.parse = () => entry.parse;
7578
+ else if (entry.name)
7579
+ result.parse = () => entry.name;
7558
7580
  return [triggerString, result];
7559
7581
  }
7560
- if (typeof entry.trigger === "string") {
7561
- console.assert(
7562
- entry.parse || trigger.length > 1,
7563
- `Trigger shortcut should produce more than one token. Otherwise, not worth using the shortcut. (${triggerString})`
7564
- );
7582
+ if (result.kind === "expression" && isExpressionEntry(entry)) {
7583
+ result.serialize = entry.serialize ?? triggerString;
7584
+ if (typeof result.serialize === "string") {
7585
+ const serializeExpr = result.serialize;
7586
+ result.serialize = (serializer, expr) => {
7587
+ if (!head(expr))
7588
+ return serializer.serialize(serializeExpr);
7589
+ return `${serializer.serialize(
7590
+ serializeExpr
7591
+ )}${serializer.wrapArguments(expr)}`;
7592
+ };
7593
+ }
7594
+ {
7595
+ if (typeof entry.parse === "function") {
7596
+ result.parse = entry.parse;
7597
+ } else {
7598
+ const parseResult = entry.parse ?? entry.name;
7599
+ result.parse = () => parseResult;
7600
+ }
7601
+ }
7602
+ return [triggerString, result];
7565
7603
  }
7566
- if (result.kind === "identifier" && isIdentifierEntry(entry)) {
7604
+ console.assert(
7605
+ typeof entry.trigger !== "string" || entry.parse || trigger.length > 1 || "kind" in entry && entry.kind === "function",
7606
+ `Trigger shortcuts should produce more than one token. Otherwise, not worth using them. (${triggerString})`
7607
+ );
7608
+ if (result.kind === "symbol" && isSymbolEntry(entry)) {
7567
7609
  result.precedence = entry.precedence ?? 1e4;
7568
7610
  }
7569
7611
  if ((result.kind === "infix" || result.kind === "prefix" || result.kind === "postfix") && (isInfixEntry(entry) || isPrefixEntry(entry) || isPostfixEntry(entry))) {
7570
- if (trigger && (trigger[0] === "^" || trigger[0] === "_"))
7612
+ if (trigger && (trigger[0] === "^" || trigger[0] === "_")) {
7571
7613
  result.precedence = 720;
7572
- else
7614
+ console.assert(
7615
+ entry.precedence === void 0,
7616
+ "'precedence' not allowed with ^ and _ triggers"
7617
+ );
7618
+ } else
7573
7619
  result.precedence = entry.precedence ?? 1e4;
7574
7620
  }
7575
7621
  if (result.kind === "infix" && isInfixEntry(entry)) {
@@ -7582,7 +7628,7 @@ function makeIndexedEntry(entry, onError) {
7582
7628
  } else if (trigger && (trigger[0] === "^" || trigger[0] === "_")) {
7583
7629
  console.assert(!entry.parse);
7584
7630
  const name = entry.parse ?? entry.name;
7585
- result.parse = (_scanner, _terminator, arg) => [
7631
+ result.parse = (_scanner, arg, _terminator) => [
7586
7632
  name,
7587
7633
  missingIfEmpty(op(arg, 1)),
7588
7634
  missingIfEmpty(op(arg, 2))
@@ -7591,11 +7637,11 @@ function makeIndexedEntry(entry, onError) {
7591
7637
  const head2 = entry.parse ?? entry.name;
7592
7638
  const prec = result.precedence;
7593
7639
  const associativity = result.associativity;
7594
- result.parse = (scanner, terminator, lhs) => {
7640
+ result.parse = (scanner, lhs, terminator) => {
7595
7641
  if (prec < terminator.minPrec)
7596
7642
  return null;
7597
7643
  const rhs = missingIfEmpty(
7598
- scanner.matchExpression({
7644
+ scanner.parseExpression({
7599
7645
  ...terminator,
7600
7646
  minPrec: prec
7601
7647
  })
@@ -7607,7 +7653,7 @@ function makeIndexedEntry(entry, onError) {
7607
7653
  if (typeof entry.parse === "function") {
7608
7654
  result.parse = entry.parse;
7609
7655
  } else if (entry.parse !== void 0) {
7610
- console.assert(result.kind === "identifier");
7656
+ console.assert(result.kind === "symbol" || result.kind === "expression");
7611
7657
  result.parse = () => entry.parse;
7612
7658
  } else if (entry.parse === void 0 && entry.name !== void 0) {
7613
7659
  if (result.kind === "postfix") {
@@ -7617,9 +7663,9 @@ function makeIndexedEntry(entry, onError) {
7617
7663
  console.assert(entry.name);
7618
7664
  const head2 = entry.name;
7619
7665
  result.parse = (parser, terminator) => {
7620
- if (prec < terminator.minPrec)
7666
+ if (terminator && prec < terminator.minPrec)
7621
7667
  return null;
7622
- const rhs = parser.matchExpression({ ...terminator, minPrec: prec });
7668
+ const rhs = parser.parseExpression({ ...terminator, minPrec: prec });
7623
7669
  return rhs === null ? null : [head2, rhs];
7624
7670
  };
7625
7671
  }
@@ -7634,7 +7680,7 @@ function makeIndexedEntry(entry, onError) {
7634
7680
  result.serialize = triggerString + "#1";
7635
7681
  } else if (result.kind === "infix") {
7636
7682
  result.serialize = "#1" + triggerString + "#2";
7637
- } else if (result.kind === "identifier") {
7683
+ } else if (result.kind === "symbol") {
7638
7684
  result.serialize = triggerString;
7639
7685
  } else {
7640
7686
  result.serialize = "";
@@ -7764,6 +7810,7 @@ var DEFAULT_LATEX_DICTIONARY = {
7764
7810
  physics: [
7765
7811
  {
7766
7812
  name: "mu0",
7813
+ kind: "symbol",
7767
7814
  trigger: "\\mu_0"
7768
7815
  }
7769
7816
  ],
@@ -7813,6 +7860,7 @@ function matchIdentifierToken(parser, options) {
7813
7860
  special = {
7814
7861
  "+": "plus",
7815
7862
  "-": "minus",
7863
+ "\\plusmn": "pm",
7816
7864
  "\\pm": "pm",
7817
7865
  "\\ast": "ast",
7818
7866
  "\\dag": "dag",
@@ -7828,22 +7876,22 @@ function matchIdentifierToken(parser, options) {
7828
7876
  }[token];
7829
7877
  }
7830
7878
  if (special) {
7831
- parser.next();
7879
+ parser.nextToken();
7832
7880
  return special;
7833
7881
  }
7834
7882
  const i = SYMBOLS.findIndex((x) => x[1] === token);
7835
7883
  if (i >= 0) {
7836
- parser.next();
7884
+ parser.nextToken();
7837
7885
  return SYMBOLS[i][0];
7838
7886
  }
7839
- return parser.matchChar() ?? parser.next();
7887
+ return parser.matchChar() ?? parser.nextToken();
7840
7888
  }
7841
7889
  function matchIdentifierBody(parser) {
7842
7890
  let id = matchPrefixedIdentifier(parser);
7843
7891
  const start = parser.index;
7844
7892
  const prefix = IDENTIFIER_MODIFIER[parser.peek] ?? null;
7845
7893
  if (prefix) {
7846
- parser.next();
7894
+ parser.nextToken();
7847
7895
  if (!parser.match("<{>")) {
7848
7896
  parser.index = start;
7849
7897
  return null;
@@ -7869,7 +7917,7 @@ function matchIdentifierBody(parser) {
7869
7917
  id += next;
7870
7918
  }
7871
7919
  while (!parser.atEnd && /\d/.test(parser.peek))
7872
- id += parser.next();
7920
+ id += parser.nextToken();
7873
7921
  }
7874
7922
  while (!parser.atEnd) {
7875
7923
  if (parser.match("\\degree"))
@@ -7918,7 +7966,7 @@ function matchPrefixedIdentifier(parser) {
7918
7966
  const prefix = IDENTIFIER_PREFIX[parser.peek] ?? null;
7919
7967
  if (prefix === null)
7920
7968
  return null;
7921
- parser.next();
7969
+ parser.nextToken();
7922
7970
  if (parser.match("<{>")) {
7923
7971
  let body = "";
7924
7972
  const digit = {
@@ -7935,7 +7983,7 @@ function matchPrefixedIdentifier(parser) {
7935
7983
  }[parser.peek] ?? "";
7936
7984
  if (digit) {
7937
7985
  body = digit;
7938
- parser.next();
7986
+ parser.nextToken();
7939
7987
  }
7940
7988
  body += matchIdentifierBody(parser);
7941
7989
  if (body === null || !parser.match("<}>")) {
@@ -7949,7 +7997,7 @@ function matchPrefixedIdentifier(parser) {
7949
7997
  parser.index = start;
7950
7998
  return null;
7951
7999
  }
7952
- function matchInvalidIdentifier(parser) {
8000
+ function parseInvalidIdentifier(parser) {
7953
8001
  const start = parser.index;
7954
8002
  const id = matchPrefixedIdentifier(parser);
7955
8003
  if (id === null || isValidIdentifier(id)) {
@@ -7963,13 +8011,13 @@ function matchInvalidIdentifier(parser) {
7963
8011
  }
7964
8012
  function matchIdentifier(parser) {
7965
8013
  if (/^[a-zA-Z]$/.test(parser.peek) || /^\p{XIDS}$/u.test(parser.peek))
7966
- return parser.next();
8014
+ return parser.nextToken();
7967
8015
  const start = parser.index;
7968
8016
  let id = matchPrefixedIdentifier(parser);
7969
8017
  if (!id) {
7970
8018
  id = "";
7971
8019
  while (!parser.atEnd && ONLY_EMOJIS.test(id + parser.peek))
7972
- id += parser.next();
8020
+ id += parser.nextToken();
7973
8021
  }
7974
8022
  if (id) {
7975
8023
  id = id.normalize();
@@ -8016,10 +8064,6 @@ var DELIMITER_SHORTHAND = {
8016
8064
  "\\lmoustache": ["\\lmoustache"],
8017
8065
  "\\rmoustache": ["\\rmoustache"]
8018
8066
  };
8019
- var MIDDLE_DELIMITER = {
8020
- ":": [":", "\\colon"],
8021
- "|": ["|", "\\|", "\\mid", "\\mvert"]
8022
- };
8023
8067
  var OPEN_DELIMITER_PREFIX = {
8024
8068
  "\\left": "\\right",
8025
8069
  "\\bigl": "\\bigr",
@@ -8031,17 +8075,6 @@ var OPEN_DELIMITER_PREFIX = {
8031
8075
  "\\bigg": "\\bigg",
8032
8076
  "\\Bigg": "\\Bigg"
8033
8077
  };
8034
- var MIDDLE_DELIMITER_PREFIX = [
8035
- "\\middle",
8036
- "\\bigm",
8037
- "\\Bigm",
8038
- "\\biggm",
8039
- "\\Biggm",
8040
- "\\big",
8041
- "\\Big",
8042
- "\\bigg",
8043
- "\\Bigg"
8044
- ];
8045
8078
  var CLOSE_DELIMITER = {
8046
8079
  "(": ")",
8047
8080
  "[": "]",
@@ -8196,7 +8229,7 @@ var _Parser = class {
8196
8229
  this._lastPeek = peek;
8197
8230
  return peek;
8198
8231
  }
8199
- next() {
8232
+ nextToken() {
8200
8233
  return this._tokens[this.index++];
8201
8234
  }
8202
8235
  /**
@@ -8249,15 +8282,14 @@ var _Parser = class {
8249
8282
  latexAhead(n) {
8250
8283
  return this.latex(this.index, this.index + n);
8251
8284
  }
8252
- latexBefore() {
8253
- return this.latex(0, this.index);
8254
- }
8255
- latexAfter() {
8256
- return this.latex(this.index);
8257
- }
8285
+ // latexBefore(): string {
8286
+ // return this.latex(0, this.index);
8287
+ // }
8288
+ // latexAfter(): string {
8289
+ // return this.latex(this.index);
8290
+ // }
8258
8291
  /**
8259
- * Return at most `this._dictionary.lookahead` strings made from the tokens
8260
- * ahead.
8292
+ * Return at most `this._dictionary.lookahead` LaTeX tokens.
8261
8293
  *
8262
8294
  * The index in the returned array correspond to the number of tokens.
8263
8295
  * Note that since a token can be longer than one char ('\\pi', but also
@@ -8265,6 +8297,10 @@ var _Parser = class {
8265
8297
  * does not match that index. However, knowing the index is important
8266
8298
  * to know by how many tokens to advance.
8267
8299
  *
8300
+ * For example:
8301
+ *
8302
+ * `[empty, '\\sqrt', '\\sqrt{', '\\sqrt{2', '\\sqrt{2}']`
8303
+ *
8268
8304
  */
8269
8305
  lookAhead() {
8270
8306
  let n = Math.min(
@@ -8283,12 +8319,12 @@ var _Parser = class {
8283
8319
  if (kind === "function") {
8284
8320
  const start = this.index;
8285
8321
  if (this.match("\\operatorname") || this.match("\\mathrm") || this.match("\\mathit")) {
8286
- const fn = this.matchStringArgument();
8322
+ const fn = this.parseStringGroup()?.trim();
8287
8323
  const n = this.index - start;
8288
8324
  this.index = start;
8289
- if (fn !== null && this._dictionary.function.has(fn))
8290
- return this._dictionary.function.get(fn).map((x) => [x, n]);
8291
- return null;
8325
+ if (!fn || !this._dictionary.function.has(fn))
8326
+ return null;
8327
+ return this._dictionary.function.get(fn).map((x) => [x, n]);
8292
8328
  }
8293
8329
  return null;
8294
8330
  } else if (kind === "operator") {
@@ -8321,19 +8357,19 @@ var _Parser = class {
8321
8357
  * instead.
8322
8358
  */
8323
8359
  skipSpace() {
8324
- if (!this.options.skipSpace)
8325
- return false;
8326
8360
  if (!this.atEnd && this.peek === "<{>") {
8327
8361
  const index = this.index;
8328
- this.next();
8362
+ this.nextToken();
8329
8363
  while (this.match("<space>")) {
8330
8364
  }
8331
- if (this.next() === "<}>") {
8365
+ if (this.nextToken() === "<}>") {
8332
8366
  this.skipSpace();
8333
8367
  return true;
8334
8368
  }
8335
8369
  this.index = index;
8336
8370
  }
8371
+ if (!this.options.skipSpace)
8372
+ return false;
8337
8373
  let result = false;
8338
8374
  while (this.match("<space>"))
8339
8375
  result = true;
@@ -8356,11 +8392,36 @@ var _Parser = class {
8356
8392
  "\\quad",
8357
8393
  "\\qquad"
8358
8394
  ].includes(this.peek)) {
8359
- this.next();
8395
+ this.nextToken();
8360
8396
  this.skipVisualSpace();
8361
8397
  }
8362
8398
  this.skipSpace();
8363
8399
  }
8400
+ match(token) {
8401
+ if (this._tokens[this.index] === token) {
8402
+ this.index++;
8403
+ return true;
8404
+ }
8405
+ return false;
8406
+ }
8407
+ matchAll(tokens) {
8408
+ console.assert(Array.isArray(tokens));
8409
+ if (tokens.length === 0)
8410
+ return false;
8411
+ let matched = true;
8412
+ let i = 0;
8413
+ do {
8414
+ matched = this._tokens[this.index + i] === tokens[i++];
8415
+ } while (matched && i < tokens.length);
8416
+ if (matched)
8417
+ this.index += i;
8418
+ return matched;
8419
+ }
8420
+ matchAny(tokens) {
8421
+ if (tokens.includes(this._tokens[this.index]))
8422
+ return this._tokens[this.index++];
8423
+ return "";
8424
+ }
8364
8425
  matchChar() {
8365
8426
  const index = this.index;
8366
8427
  let caretCount = 0;
@@ -8407,7 +8468,7 @@ var _Parser = class {
8407
8468
  } else if (this.match("\\unicode")) {
8408
8469
  this.skipSpaceTokens();
8409
8470
  if (this.peek === "<{>") {
8410
- this.next();
8471
+ this.nextToken();
8411
8472
  const codepoint = this.matchLatexNumber();
8412
8473
  if (this.match("<}>") && codepoint !== null && codepoint >= 0 && codepoint <= 1114111) {
8413
8474
  return String.fromCodePoint(codepoint);
@@ -8422,62 +8483,171 @@ var _Parser = class {
8422
8483
  this.index = index;
8423
8484
  return null;
8424
8485
  }
8425
- matchColor(_background = false) {
8426
- let s = "";
8427
- while (!this.atEnd && this.peek !== "}")
8428
- s += this.next();
8429
- return s;
8430
- }
8431
- matchLatexDimension() {
8432
- return null;
8433
- }
8434
- match(token) {
8435
- if (this._tokens[this.index] === token) {
8436
- this.index++;
8437
- return true;
8486
+ parseGroup() {
8487
+ const start = this.index;
8488
+ this.skipSpaceTokens();
8489
+ if (this.match("<{>")) {
8490
+ this.addBoundary(["<}>"]);
8491
+ const expr = this.parseExpression();
8492
+ this.skipSpace();
8493
+ if (this.matchBoundary())
8494
+ return expr ?? ["Sequence"];
8495
+ const from = this.index;
8496
+ while (!this.matchBoundary() && !this.atEnd)
8497
+ this.nextToken();
8498
+ const err = this.error("syntax-error", from);
8499
+ return expr ? ["Sequence", expr, err] : err;
8438
8500
  }
8439
- return false;
8501
+ this.index = start;
8502
+ return null;
8440
8503
  }
8441
- matchAll(tokens) {
8442
- if (typeof tokens === "string")
8443
- tokens = [tokens];
8444
- if (tokens.length === 0)
8445
- return false;
8446
- let matched = true;
8447
- let i = 0;
8448
- do {
8449
- matched = this._tokens[this.index + i] === tokens[i++];
8450
- } while (matched && i < tokens.length);
8451
- if (matched)
8452
- this.index += i;
8453
- return matched;
8504
+ // Some LaTeX commands (but not all) can accept an argument without braces,
8505
+ // for example `^` , `\sqrt` or `\frac`.
8506
+ // This argument will usually be a single token, but can be a sequence of
8507
+ // tokens (e.g. `\sqrt\frac12` or `\sqrt\mathrm{speed}`).
8508
+ parseToken() {
8509
+ const excluding = [
8510
+ ...'!"#$%&(),/;:?@[]\\`|~'.split(""),
8511
+ "\\left",
8512
+ "\\bigl"
8513
+ ];
8514
+ if (excluding.includes(this.peek))
8515
+ return null;
8516
+ if (/^[0-9]$/.test(this.peek))
8517
+ return parseInt(this.nextToken());
8518
+ const result = this.parseGenericExpression() ?? this.parseSymbol();
8519
+ if (!result)
8520
+ return null;
8521
+ return result;
8454
8522
  }
8455
- matchAny(tokens) {
8456
- if (tokens.includes(this._tokens[this.index]))
8457
- return this._tokens[this.index++];
8458
- return "";
8523
+ parseOptionalGroup() {
8524
+ const index = this.index;
8525
+ this.skipSpaceTokens();
8526
+ if (this.match("[")) {
8527
+ this.addBoundary(["]"]);
8528
+ const expr = this.parseExpression();
8529
+ this.skipSpace();
8530
+ if (this.matchBoundary())
8531
+ return expr;
8532
+ return this.boundaryError("expected-closing-delimiter");
8533
+ }
8534
+ this.index = index;
8535
+ return null;
8459
8536
  }
8460
- matchSequence(tokens) {
8537
+ /**
8538
+ * Parse an expression in a tabular format, where rows are separated by `\\`
8539
+ * and columns by `&`.
8540
+ *
8541
+ * Return rows of sparse columns: empty rows are indicated with `Nothing`,
8542
+ * and empty cells are also indicated with `Nothing`.
8543
+ */
8544
+ parseTabular() {
8461
8545
  const result = [];
8462
- while (tokens.includes(this._tokens[this.index]))
8463
- result.push(this._tokens[this.index++]);
8546
+ let row = [];
8547
+ let expr = null;
8548
+ while (!this.atBoundary) {
8549
+ this.skipSpace();
8550
+ if (this.match("&")) {
8551
+ row.push(expr ?? "Nothing");
8552
+ expr = null;
8553
+ } else if (this.match("\\\\") || this.match("\\cr")) {
8554
+ this.skipSpace();
8555
+ this.parseOptionalGroup();
8556
+ if (expr !== null)
8557
+ row.push(expr);
8558
+ result.push(row);
8559
+ row = [];
8560
+ expr = null;
8561
+ } else {
8562
+ const cell = [];
8563
+ let peek = this.peek;
8564
+ while (peek !== "&" && peek !== "\\\\" && peek !== "\\cr" && !this.atBoundary) {
8565
+ expr = this.parseExpression({
8566
+ condition: (p) => {
8567
+ const peek2 = p.peek;
8568
+ return peek2 === "&" || peek2 === "\\\\" || peek2 === "\\cr";
8569
+ }
8570
+ });
8571
+ if (expr)
8572
+ cell.push(expr);
8573
+ else {
8574
+ cell.push(["Error", ["'unexpected-token'", peek]]);
8575
+ this.nextToken();
8576
+ }
8577
+ this.skipSpace();
8578
+ peek = this.peek;
8579
+ }
8580
+ if (cell.length > 1)
8581
+ expr = ["Sequence", ...cell];
8582
+ else
8583
+ expr = cell[0] ?? "Nothing";
8584
+ }
8585
+ }
8586
+ if (expr !== null)
8587
+ row.push(expr);
8588
+ if (row.length > 0)
8589
+ result.push(row);
8464
8590
  return result;
8465
8591
  }
8466
- matchOptionalSign() {
8592
+ /** Parse a group as a a string, for example for `\operatorname` or `\begin` */
8593
+ parseStringGroup() {
8594
+ const start = this.index;
8595
+ while (this.match("<space>")) {
8596
+ }
8597
+ if (this.match("<{>")) {
8598
+ this.addBoundary(["<}>"]);
8599
+ const arg = this.parseStringGroupContent();
8600
+ if (this.matchBoundary())
8601
+ return arg;
8602
+ this.removeBoundary();
8603
+ }
8604
+ this.index = start;
8605
+ return null;
8606
+ }
8607
+ /** Parse an environment: `\begin{env}...\end{end}`
8608
+ */
8609
+ parseEnvironment() {
8610
+ const index = this.index;
8611
+ if (!this.match("\\begin"))
8612
+ return null;
8613
+ const name = this.parseStringGroup()?.trim();
8614
+ if (!name)
8615
+ return this.error("expected-environment-name", index);
8616
+ this.addBoundary(["\\end", "<{>", ...name.split(""), "<}>"]);
8617
+ const def = this._dictionary.environment.get(name);
8618
+ if (!def) {
8619
+ this.parseTabular();
8620
+ this.skipSpace();
8621
+ if (!this.matchBoundary())
8622
+ return this.boundaryError("unbalanced-environment");
8623
+ return this.error(["unknown-environment", { str: name }], index);
8624
+ }
8625
+ const expr = def.parse(this, [], []);
8626
+ this.skipSpace();
8627
+ if (!this.matchBoundary())
8628
+ return this.boundaryError("unbalanced-environment");
8629
+ if (expr !== null)
8630
+ return this.decorate(expr, index);
8631
+ this.index = index;
8632
+ return null;
8633
+ }
8634
+ /** If the next token matches a `+` or `-` sign, return it and advance the index.
8635
+ * Otherwise return `''` and do not advance */
8636
+ parseOptionalSign() {
8467
8637
  let isNegative = !!this.matchAny(["-", "\u2212"]);
8468
8638
  while (this.matchAny(["+", "\uFE62"]) || this.skipSpace())
8469
8639
  if (this.matchAny(["-", "\u2212"]))
8470
8640
  isNegative = !isNegative;
8471
8641
  return isNegative ? "-" : "+";
8472
8642
  }
8473
- matchDecimalDigits(options) {
8643
+ parseDecimalDigits(options) {
8474
8644
  options ?? (options = {});
8475
8645
  options.withGrouping ?? (options.withGrouping = false);
8476
8646
  const result = [];
8477
8647
  let done = false;
8478
8648
  while (!done) {
8479
8649
  while (/^[0-9]$/.test(this.peek)) {
8480
- result.push(this.next());
8650
+ result.push(this.nextToken());
8481
8651
  this.skipVisualSpace();
8482
8652
  }
8483
8653
  done = true;
@@ -8495,21 +8665,21 @@ var _Parser = class {
8495
8665
  }
8496
8666
  return result.join("");
8497
8667
  }
8498
- matchSignedInteger(options) {
8668
+ parseSignedInteger(options) {
8499
8669
  options ?? (options = {});
8500
8670
  options.withGrouping ?? (options.withGrouping = false);
8501
8671
  const start = this.index;
8502
- const sign2 = this.matchOptionalSign();
8503
- const result = this.matchDecimalDigits(options);
8672
+ const sign2 = this.parseOptionalSign();
8673
+ const result = this.parseDecimalDigits(options);
8504
8674
  if (result)
8505
8675
  return sign2 === "-" ? "-" + result : result;
8506
8676
  this.index = start;
8507
8677
  return "";
8508
8678
  }
8509
- matchExponent() {
8679
+ parseExponent() {
8510
8680
  const start = this.index;
8511
8681
  if (this.matchAny(["e", "E"])) {
8512
- const exponent = this.matchSignedInteger({ withGrouping: false });
8682
+ const exponent = this.parseSignedInteger({ withGrouping: false });
8513
8683
  if (exponent)
8514
8684
  return "e" + exponent;
8515
8685
  }
@@ -8518,10 +8688,10 @@ var _Parser = class {
8518
8688
  this.skipSpaceTokens();
8519
8689
  if (this.match("1") && this.match("0") && this.match("^")) {
8520
8690
  if (/^[0-9]$/.test(this.peek))
8521
- return "e" + this.next();
8691
+ return "e" + this.nextToken();
8522
8692
  if (this.match("<{>")) {
8523
8693
  this.skipSpaceTokens();
8524
- const exponent = this.matchSignedInteger();
8694
+ const exponent = this.parseSignedInteger();
8525
8695
  this.skipSpaceTokens();
8526
8696
  if (this.match("<}>") && exponent)
8527
8697
  return "e" + exponent;
@@ -8537,7 +8707,7 @@ var _Parser = class {
8537
8707
  this.skipSpaceTokens();
8538
8708
  if (this.matchAll(this._beginExponentMarkerTokens)) {
8539
8709
  this.skipSpaceTokens();
8540
- const exponent = this.matchSignedInteger();
8710
+ const exponent = this.parseSignedInteger();
8541
8711
  this.skipSpaceTokens();
8542
8712
  if (this.matchAll(this._endExponentMarkerTokens) && exponent)
8543
8713
  return "e" + exponent;
@@ -8546,11 +8716,11 @@ var _Parser = class {
8546
8716
  this.index = start;
8547
8717
  return "";
8548
8718
  }
8549
- matchRepeatingDecimal() {
8719
+ parseRepeatingDecimal() {
8550
8720
  const start = this.index;
8551
8721
  let repeatingDecimals2 = "";
8552
8722
  if (this.match("(")) {
8553
- repeatingDecimals2 = this.matchDecimalDigits();
8723
+ repeatingDecimals2 = this.parseDecimalDigits();
8554
8724
  if (repeatingDecimals2 && this.match(")"))
8555
8725
  return "(" + repeatingDecimals2 + ")";
8556
8726
  this.index = start;
@@ -8558,7 +8728,7 @@ var _Parser = class {
8558
8728
  }
8559
8729
  this.index = start;
8560
8730
  if (this.matchAll([`\\left`, "("])) {
8561
- repeatingDecimals2 = this.matchDecimalDigits();
8731
+ repeatingDecimals2 = this.parseDecimalDigits();
8562
8732
  if (repeatingDecimals2 && this.matchAll([`\\right`, ")"]))
8563
8733
  return "(" + repeatingDecimals2 + ")";
8564
8734
  this.index = start;
@@ -8566,7 +8736,7 @@ var _Parser = class {
8566
8736
  }
8567
8737
  this.index = start;
8568
8738
  if (this.matchAll([`\\overline`, "<{>"])) {
8569
- repeatingDecimals2 = this.matchDecimalDigits();
8739
+ repeatingDecimals2 = this.parseDecimalDigits();
8570
8740
  if (repeatingDecimals2 && this.match("<}>"))
8571
8741
  return "(" + repeatingDecimals2 + ")";
8572
8742
  this.index = start;
@@ -8574,7 +8744,7 @@ var _Parser = class {
8574
8744
  }
8575
8745
  this.index = start;
8576
8746
  if (this.matchAll(this._beginRepeatingDigitsTokens)) {
8577
- repeatingDecimals2 = this.matchDecimalDigits();
8747
+ repeatingDecimals2 = this.parseDecimalDigits();
8578
8748
  if (repeatingDecimals2 && this.matchAll(this._endRepeatingDigitsTokens))
8579
8749
  return "(" + repeatingDecimals2 + ")";
8580
8750
  this.index = start;
@@ -8583,9 +8753,13 @@ var _Parser = class {
8583
8753
  this.index = start;
8584
8754
  return "";
8585
8755
  }
8586
- matchNumber() {
8756
+ /**
8757
+ * Parse a number, with an optional sign, exponent, decimal marker,
8758
+ * repeating decimals, etc...
8759
+ */
8760
+ parseNumber() {
8587
8761
  if (!this.options.parseNumbers)
8588
- return "";
8762
+ return null;
8589
8763
  const start = this.index;
8590
8764
  this.skipVisualSpace();
8591
8765
  this.match("+");
@@ -8595,32 +8769,32 @@ var _Parser = class {
8595
8769
  const peek = this.peek;
8596
8770
  if (peek !== "\\overline" && peek !== this._beginRepeatingDigitsTokens[0] && !/[0-9\(]/.test(peek)) {
8597
8771
  this.index = start;
8598
- return "";
8772
+ return null;
8599
8773
  }
8600
8774
  dotPrefix = true;
8601
8775
  } else {
8602
- result = this.matchDecimalDigits({ withGrouping: true });
8776
+ result = this.parseDecimalDigits({ withGrouping: true });
8603
8777
  if (!result) {
8604
8778
  this.index = start;
8605
- return "";
8779
+ return null;
8606
8780
  }
8607
8781
  }
8608
8782
  let hasDecimal = true;
8609
8783
  if (!dotPrefix && (this.match(".") || this.matchAll(this._decimalMarkerTokens)))
8610
- result += "." + this.matchDecimalDigits({ withGrouping: true });
8784
+ result += "." + this.parseDecimalDigits({ withGrouping: true });
8611
8785
  else if (dotPrefix)
8612
- result = "0." + this.matchDecimalDigits({ withGrouping: true });
8786
+ result = "0." + this.parseDecimalDigits({ withGrouping: true });
8613
8787
  else
8614
8788
  hasDecimal = false;
8615
8789
  if (hasDecimal) {
8616
- const repeat = this.matchRepeatingDecimal();
8790
+ const repeat = this.parseRepeatingDecimal();
8617
8791
  if (repeat)
8618
8792
  result += repeat;
8619
8793
  else if (this.match("\\ldots") || this.matchAll(this._truncationMarkerTokens)) {
8620
8794
  }
8621
8795
  }
8622
8796
  this.skipVisualSpace();
8623
- return result + this.matchExponent();
8797
+ return result + this.parseExponent();
8624
8798
  }
8625
8799
  /**
8626
8800
  * A Latex number can be a decimal, hex or octal number.
@@ -8639,7 +8813,7 @@ var _Parser = class {
8639
8813
  while (token === "<space>" || token === "+" || token === "-") {
8640
8814
  if (token === "-")
8641
8815
  negative = !negative;
8642
- this.next();
8816
+ this.nextToken();
8643
8817
  token = this.peek;
8644
8818
  }
8645
8819
  let radix = 10;
@@ -8670,7 +8844,7 @@ var _Parser = class {
8670
8844
  ];
8671
8845
  isInteger = true;
8672
8846
  } else if (this.match("`")) {
8673
- token = this.next();
8847
+ token = this.nextToken();
8674
8848
  if (token) {
8675
8849
  if (token.startsWith("\\") && token.length === 2) {
8676
8850
  return (negative ? -1 : 1) * (token.codePointAt(1) ?? 0);
@@ -8681,12 +8855,12 @@ var _Parser = class {
8681
8855
  }
8682
8856
  let value = "";
8683
8857
  while (digits.includes(this.peek)) {
8684
- value += this.next();
8858
+ value += this.nextToken();
8685
8859
  }
8686
8860
  if (!isInteger && this.match(".")) {
8687
8861
  value += ".";
8688
8862
  while (digits.includes(this.peek)) {
8689
- value += this.next();
8863
+ value += this.nextToken();
8690
8864
  }
8691
8865
  }
8692
8866
  const result = isInteger ? Number.parseInt(value, radix) : Number.parseFloat(value);
@@ -8694,7 +8868,7 @@ var _Parser = class {
8694
8868
  return null;
8695
8869
  return negative ? -result : result;
8696
8870
  }
8697
- matchPrefixOperator(until) {
8871
+ parsePrefixOperator(until) {
8698
8872
  if (!until)
8699
8873
  until = { minPrec: 0 };
8700
8874
  if (!until.minPrec)
@@ -8712,7 +8886,7 @@ var _Parser = class {
8712
8886
  this.index = start;
8713
8887
  return null;
8714
8888
  }
8715
- matchInfixOperator(lhs, until) {
8889
+ parseInfixOperator(lhs, until) {
8716
8890
  until ?? (until = { minPrec: 0 });
8717
8891
  if (until.minPrec === void 0)
8718
8892
  until = { ...until, minPrec: 0 };
@@ -8723,7 +8897,7 @@ var _Parser = class {
8723
8897
  for (const [def, n] of defs) {
8724
8898
  if (def.precedence >= until.minPrec) {
8725
8899
  this.index = start + n;
8726
- const rhs = def.parse(this, until, lhs);
8900
+ const rhs = def.parse(this, lhs, until);
8727
8901
  if (rhs)
8728
8902
  return rhs;
8729
8903
  }
@@ -8732,93 +8906,74 @@ var _Parser = class {
8732
8906
  return null;
8733
8907
  }
8734
8908
  /**
8735
- * - 'enclosure' : will look for an argument inside an enclosure (open/close fence)
8909
+ * This returns an array of arguments (as in a function application),
8910
+ * or null if there is no match.
8911
+ *
8912
+ * - 'enclosure' : will look for an argument inside an enclosure
8913
+ * (open/close fence)
8736
8914
  * - 'implicit': either an expression inside a pair of `()`, or just a product
8737
8915
  * (i.e. we interpret `\cos 2x + 1` as `\cos(2x) + 1`)
8738
8916
  *
8739
- * This returns an array of arguments, or null if there is no match.
8740
8917
  */
8741
- matchArguments(kind, until) {
8742
- if (!kind)
8743
- return null;
8918
+ parseArguments(kind = "enclosure", until) {
8744
8919
  if (this.atTerminator(until))
8745
8920
  return null;
8746
8921
  const savedIndex = this.index;
8747
- const group = this.matchEnclosure();
8748
- if (kind === "enclosure")
8922
+ const group = this.parseEnclosure();
8923
+ if (kind === "enclosure") {
8924
+ if (group === null)
8925
+ return null;
8749
8926
  return getSequence(group) ?? [];
8927
+ }
8750
8928
  if (kind === "implicit") {
8751
8929
  if (head(group) === "Delimiter")
8752
8930
  return getSequence(group) ?? [];
8753
- if (group !== null)
8754
- return [group];
8755
- const primary = this.matchExpression({ ...until, minPrec: 390 });
8756
- return primary === null ? null : [primary];
8757
- }
8758
- this.index = savedIndex;
8759
- return null;
8760
- }
8761
- /**
8762
- * A function can be followed by the following suffixes:
8763
- * - a `\prime`, `\doubleprime`, `'`, `(n)` to indicate a derivative
8764
- * - a subscript to indicate an argument
8765
- * - an argument, optionally inside an enclosure
8766
- */
8767
- matchFunctionSuffix(id) {
8768
- let fn = id;
8769
- do {
8770
- const pf = this.matchPostfix(fn);
8771
- if (pf === null)
8772
- break;
8773
- fn = pf;
8774
- } while (true);
8775
- const seq = this.matchArguments("enclosure");
8776
- return seq ? [fn, ...seq] : fn;
8931
+ if (group !== null)
8932
+ return [group];
8933
+ const primary = this.parseExpression({ ...until, minPrec: 390 });
8934
+ return primary === null ? null : [primary];
8935
+ }
8936
+ this.index = savedIndex;
8937
+ return null;
8777
8938
  }
8778
8939
  /** A prime suffix is a sequence of `'`, `\prime` or `\doubleprime`
8779
8940
  * after a function or in a superscript.
8780
8941
  */
8781
- matchPrimeSuffix() {
8782
- this.skipSpace();
8783
- const start = this.index;
8784
- let count = 0;
8785
- if (this.match("^")) {
8786
- if (this.match("<{>")) {
8787
- if (this.match("(")) {
8788
- const n = this.matchNumber();
8789
- if (n && this.match(")"))
8790
- return parseInt(n);
8791
- this.index = start;
8792
- return 0;
8793
- }
8794
- do {
8795
- const c = countPrimeLevel(this);
8796
- if (c === 0)
8797
- break;
8798
- count += c;
8799
- } while (true);
8800
- if (count !== 0 && this.match("<}>"))
8801
- return count;
8802
- this.index = start;
8803
- return 0;
8804
- }
8805
- count = countPrimeLevel(this);
8806
- if (count !== 0)
8807
- return count;
8808
- this.index = start;
8809
- return 0;
8810
- }
8811
- do {
8812
- const c = countPrimeLevel(this);
8813
- if (c === 0)
8814
- break;
8815
- count += c;
8816
- } while (true);
8817
- if (count !== 0)
8818
- return count;
8819
- this.index = start;
8820
- return 0;
8821
- }
8942
+ // matchPrimeSuffix(): number {
8943
+ // this.skipSpace();
8944
+ // const start = this.index;
8945
+ // let count = 0;
8946
+ // if (this.match('^')) {
8947
+ // if (this.match('<{>')) {
8948
+ // if (this.match('(')) {
8949
+ // const n = this.parseNumber();
8950
+ // if (n && this.match(')')) return parseInt(n);
8951
+ // this.index = start;
8952
+ // return 0;
8953
+ // }
8954
+ // do {
8955
+ // const c = countPrimeLevel(this);
8956
+ // if (c === 0) break;
8957
+ // count += c;
8958
+ // } while (true);
8959
+ // if (count !== 0 && this.match('<}>')) return count;
8960
+ // this.index = start;
8961
+ // return 0;
8962
+ // }
8963
+ // count = countPrimeLevel(this);
8964
+ // if (count !== 0) return count;
8965
+ // this.index = start;
8966
+ // return 0;
8967
+ // }
8968
+ // do {
8969
+ // const c = countPrimeLevel(this);
8970
+ // if (c === 0) break;
8971
+ // count += c;
8972
+ // } while (true);
8973
+ // if (count !== 0) return count;
8974
+ // this.index = start;
8975
+ // return 0;
8976
+ // }
8822
8977
  /** If matches the normalized open delimiter, return the
8823
8978
  * expected closing delimiter.
8824
8979
  *
@@ -8831,7 +8986,7 @@ var _Parser = class {
8831
8986
  const index = this.index;
8832
8987
  const closePrefix = OPEN_DELIMITER_PREFIX[this.peek];
8833
8988
  if (closePrefix)
8834
- this.next();
8989
+ this.nextToken();
8835
8990
  const alternatives = DELIMITER_SHORTHAND[openDelim] ?? [openDelim];
8836
8991
  const result = closePrefix ? [closePrefix] : [];
8837
8992
  if (alternatives.includes("||") && this.matchAll(["|", "|"])) {
@@ -8848,28 +9003,30 @@ var _Parser = class {
8848
9003
  } else {
8849
9004
  result.push(closeDelim);
8850
9005
  }
8851
- this.next();
9006
+ this.nextToken();
8852
9007
  return result;
8853
9008
  }
8854
- matchMiddleDelimiter(delimiter) {
8855
- const delimiters = MIDDLE_DELIMITER[delimiter] ?? [delimiter];
8856
- if (MIDDLE_DELIMITER_PREFIX.includes(this.peek)) {
8857
- const index = this.index;
8858
- this.next();
8859
- if (delimiters.includes(this.peek)) {
8860
- this.next();
8861
- return true;
8862
- }
8863
- this.index = index;
8864
- return false;
8865
- } else if (delimiters.include(this.peek)) {
8866
- this.next();
8867
- return true;
8868
- }
8869
- return false;
8870
- }
9009
+ // matchMiddleDelimiter(delimiter: '|' | ':' | LatexToken): boolean {
9010
+ // const delimiters = MIDDLE_DELIMITER[delimiter] ?? [delimiter];
9011
+ // if (MIDDLE_DELIMITER_PREFIX.includes(this.peek)) {
9012
+ // const index = this.index;
9013
+ // this.nextToken();
9014
+ // if (delimiters.includes(this.peek)) {
9015
+ // this.nextToken();
9016
+ // return true;
9017
+ // }
9018
+ // this.index = index;
9019
+ // return false;
9020
+ // } else if (delimiters.include(this.peek)) {
9021
+ // this.nextToken();
9022
+ // return true;
9023
+ // }
9024
+ // return false;
9025
+ // }
8871
9026
  /** For error handling, when there is potentially a mismatched delimiter.
8872
9027
  * Return a LaTeX fragment of the expected closing delimiter
9028
+ *
9029
+ * @internal
8873
9030
  */
8874
9031
  matchEnclosureOpen() {
8875
9032
  const defs = this._dictionary.matchfix;
@@ -8893,6 +9050,9 @@ var _Parser = class {
8893
9050
  this.index = start;
8894
9051
  return null;
8895
9052
  }
9053
+ /**
9054
+ * Used for error handling
9055
+ * @internal */
8896
9056
  matchEnclosureClose() {
8897
9057
  const defs = this._dictionary.matchfix;
8898
9058
  if (defs.length === 0)
@@ -8911,7 +9071,7 @@ var _Parser = class {
8911
9071
  (x) => OPEN_DELIMITER_PREFIX[x] === peek
8912
9072
  );
8913
9073
  if (prefix)
8914
- this.next();
9074
+ this.nextToken();
8915
9075
  let openDelimiter = [];
8916
9076
  peek = this.peek;
8917
9077
  const matchingDelim = Object.keys(CLOSE_DELIMITER).find(
@@ -8922,7 +9082,7 @@ var _Parser = class {
8922
9082
  if (prefix)
8923
9083
  openDelimiter = [prefix, ...openDelimiter];
8924
9084
  if (openDelimiter.length > 0) {
8925
- this.next();
9085
+ this.nextToken();
8926
9086
  return tokensToString(openDelimiter);
8927
9087
  }
8928
9088
  }
@@ -8934,7 +9094,7 @@ var _Parser = class {
8934
9094
  * optionally followed multiple times by a separator and another expression,
8935
9095
  * and finally a closing matching operator.
8936
9096
  */
8937
- matchEnclosure() {
9097
+ parseEnclosure() {
8938
9098
  const defs = this._dictionary.matchfix;
8939
9099
  if (defs.length === 0)
8940
9100
  return null;
@@ -8945,7 +9105,7 @@ var _Parser = class {
8945
9105
  if (!this.matchAll(def.openDelimiter))
8946
9106
  continue;
8947
9107
  this.addBoundary(def.closeDelimiter);
8948
- const body2 = this.matchExpression();
9108
+ const body2 = this.parseExpression();
8949
9109
  this.skipSpace();
8950
9110
  if (!this.matchBoundary()) {
8951
9111
  this.removeBoundary();
@@ -8970,12 +9130,12 @@ var _Parser = class {
8970
9130
  }
8971
9131
  this.addBoundary(closeDelimiter);
8972
9132
  const bodyStart = this.index;
8973
- let body = this.matchExpression();
9133
+ let body = this.parseExpression();
8974
9134
  this.skipSpace();
8975
9135
  if (!this.matchBoundary()) {
8976
9136
  this.removeBoundary();
8977
9137
  this.index = bodyStart;
8978
- body = this.matchExpression();
9138
+ body = this.parseExpression();
8979
9139
  if (!this.matchAll(closeDelimiter)) {
8980
9140
  if (!this.atEnd)
8981
9141
  continue;
@@ -8990,52 +9150,74 @@ var _Parser = class {
8990
9150
  this.index = start;
8991
9151
  return null;
8992
9152
  }
8993
- matchIdentifier() {
8994
- return matchIdentifier(this);
8995
- }
8996
9153
  /**
8997
- * A function is an identifier followed by arguments
8998
- * - a single letter identifier with explicit arguments `f(x)`
8999
- * - a multiletter identifier with explicit arguments `\mathrm{floor}(x)`
9000
- * - an identifier: `\mathrm{floor}`
9001
- * - a command with implicit arguments: `\cos x` (via a custom parser)
9002
- *
9154
+ * A generic expression is used for dictionary entries that take do
9155
+ * some complex (non-standard) parsing. This includes trig functions (to
9156
+ * parse implicit arguments), and integrals (to parse the integrand and
9157
+ * limits and the "dx" terminator).
9003
9158
  */
9004
- matchFunction(until) {
9159
+ parseGenericExpression(until) {
9005
9160
  if (this.atTerminator(until))
9006
9161
  return null;
9007
9162
  const start = this.index;
9008
- const fnDefs = this.peekDefinitions("function");
9009
- if (fnDefs) {
9010
- for (const [def, tokenCount] of fnDefs) {
9011
- this.index = start + tokenCount;
9012
- if (typeof def.parse === "function") {
9013
- const result = def.parse(this, until);
9014
- if (result)
9015
- return result;
9016
- } else {
9017
- return this.matchFunctionSuffix(def.name);
9018
- }
9163
+ let expr = null;
9164
+ const fnDefs = this.peekDefinitions("expression") ?? [];
9165
+ for (const [def, tokenCount] of fnDefs) {
9166
+ this.index = start + tokenCount;
9167
+ if (typeof def.parse === "function") {
9168
+ expr = def.parse(this, until);
9169
+ if (expr !== null)
9170
+ return expr;
9171
+ } else {
9172
+ return def.name;
9019
9173
  }
9020
9174
  }
9021
9175
  this.index = start;
9022
- const fn = this.matchIdentifier();
9023
- if (fn === null)
9176
+ return null;
9177
+ }
9178
+ /**
9179
+ * A function is an identifier followed by postfix operators
9180
+ * (`\prime`...) and some arguments.
9181
+ */
9182
+ parseFunction(until) {
9183
+ if (this.atTerminator(until))
9024
9184
  return null;
9025
- if (this.options.parseUnknownIdentifier?.(fn, this) !== "function") {
9185
+ const start = this.index;
9186
+ let fn = null;
9187
+ const fnDefs = this.peekDefinitions("function") ?? [];
9188
+ for (const [def, tokenCount] of fnDefs) {
9189
+ this.index = start + tokenCount;
9190
+ if (typeof def.parse === "function") {
9191
+ fn = def.parse(this, until);
9192
+ if (fn !== null)
9193
+ break;
9194
+ } else {
9195
+ fn = def.name;
9196
+ break;
9197
+ }
9198
+ }
9199
+ if (fn === null) {
9026
9200
  this.index = start;
9027
- return null;
9201
+ fn = matchIdentifier(this);
9202
+ if (!this.isFunctionHead(fn)) {
9203
+ this.index = start;
9204
+ return null;
9205
+ }
9028
9206
  }
9029
- return this.matchFunctionSuffix(fn);
9207
+ do {
9208
+ const pf = this.parsePostfixOperator(fn);
9209
+ if (pf === null)
9210
+ break;
9211
+ fn = pf;
9212
+ } while (true);
9213
+ const seq = this.isFunctionHead(fn) ? this.parseArguments() : null;
9214
+ return seq ? [fn, ...seq] : fn;
9030
9215
  }
9031
- /**
9032
- * A symbol is an identifier or a custom definition
9033
- */
9034
- matchSymbol(until) {
9216
+ parseSymbol(until) {
9035
9217
  if (this.atTerminator(until))
9036
9218
  return null;
9037
9219
  const start = this.index;
9038
- const defs = this.peekDefinitions("identifier");
9220
+ const defs = this.peekDefinitions("symbol");
9039
9221
  if (defs) {
9040
9222
  for (const [def, tokenCount] of defs) {
9041
9223
  this.index = start + tokenCount;
@@ -9048,7 +9230,7 @@ var _Parser = class {
9048
9230
  }
9049
9231
  }
9050
9232
  this.index = start;
9051
- const id = this.matchIdentifier();
9233
+ const id = matchIdentifier(this);
9052
9234
  if (id === null)
9053
9235
  return null;
9054
9236
  if (this.options.parseUnknownIdentifier?.(id, this) === "symbol")
@@ -9056,57 +9238,19 @@ var _Parser = class {
9056
9238
  this.index = start;
9057
9239
  return null;
9058
9240
  }
9059
- matchLatexOptionalGroup() {
9060
- const index = this.index;
9061
- this.skipSpaceTokens();
9062
- if (this.match("[")) {
9063
- this.addBoundary(["]"]);
9064
- const expr = this.matchExpression();
9065
- this.skipSpace();
9066
- if (this.matchBoundary())
9067
- return expr;
9068
- return this.boundaryError("expected-closing-delimiter");
9069
- }
9070
- this.index = index;
9071
- return null;
9072
- }
9073
- // Some LaTeX commands (but not all) can accept an argument without braces,
9074
- // for example `^` , `\sqrt` or `\frac`.
9075
- matchSingleAtomArgument() {
9076
- const excluding = [...'!"#$%&(),/;:?@[]`|~'.split(""), "\\left", "\\bigl"];
9077
- if (excluding.includes(this.peek))
9078
- return null;
9079
- if (/^[0-9]$/.test(this.peek))
9080
- return parseInt(this.next());
9081
- if (/^[^\\#]$/.test(this.peek) && isValidIdentifier(this.peek))
9082
- return this.next();
9083
- const sym = this.matchSymbol();
9084
- if (sym)
9085
- return sym;
9086
- return null;
9087
- }
9088
- matchLatexGroup() {
9089
- const start = this.index;
9090
- this.skipSpaceTokens();
9091
- if (this.match("<{>")) {
9092
- this.addBoundary(["<}>"]);
9093
- const expr = this.matchExpression();
9094
- this.skipSpace();
9095
- if (this.matchBoundary())
9096
- return expr ?? ["Sequence"];
9097
- const from = this.index;
9098
- while (!this.matchBoundary() && !this.atEnd)
9099
- this.next();
9100
- const err = this.error("syntax-error", from);
9101
- return expr ? ["Sequence", expr, err] : err;
9102
- }
9103
- this.index = start;
9104
- return null;
9105
- }
9106
- matchSupsub(lhs) {
9241
+ /**
9242
+ * Parse a sequence superfix/subfix operator, e.g. `^{*}`
9243
+ *
9244
+ * Superfix and subfix need special handling:
9245
+ *
9246
+ * - they act mostly like an infix operator, but they are commutative, i.e.
9247
+ * `x_a^b` should be parsed identically to `x^b_a`.
9248
+ *
9249
+ * - furthermore, in LaTeX `x^a^b` parses the same as `x^a{}^b`.
9250
+ *
9251
+ */
9252
+ parseSupsub(lhs) {
9107
9253
  console.assert(lhs !== null);
9108
- if (lhs === null)
9109
- return null;
9110
9254
  const index = this.index;
9111
9255
  this.skipSpace();
9112
9256
  const superscripts = [];
@@ -9118,7 +9262,7 @@ var _Parser = class {
9118
9262
  if (this.match("_") || this.match("^"))
9119
9263
  subscripts.push(this.error("syntax-error", subIndex));
9120
9264
  else {
9121
- const sub2 = this.matchLatexGroup() ?? this.matchSingleAtomArgument() ?? this.matchStringArgument();
9265
+ const sub2 = this.parseGroup() ?? this.parseToken() ?? this.parseStringGroup();
9122
9266
  if (sub2 === null)
9123
9267
  return this.error("missing", index);
9124
9268
  subscripts.push(sub2);
@@ -9128,7 +9272,7 @@ var _Parser = class {
9128
9272
  if (this.match("_") || this.match("^"))
9129
9273
  superscripts.push(this.error("syntax-error", subIndex));
9130
9274
  else {
9131
- const sup = this.matchLatexGroup() ?? this.matchSingleAtomArgument();
9275
+ const sup = this.parseGroup() ?? this.parseToken();
9132
9276
  if (sup === null)
9133
9277
  return this.error("missing", index);
9134
9278
  superscripts.push(sup);
@@ -9152,7 +9296,7 @@ var _Parser = class {
9152
9296
  ];
9153
9297
  for (const def of defs) {
9154
9298
  if (typeof def.parse === "function")
9155
- result = def.parse(this, { minPrec: 0 }, arg);
9299
+ result = def.parse(this, arg, { minPrec: 0 });
9156
9300
  else
9157
9301
  result = arg;
9158
9302
  if (result)
@@ -9170,7 +9314,7 @@ var _Parser = class {
9170
9314
  ];
9171
9315
  for (const def of defs) {
9172
9316
  if (typeof def.parse === "function")
9173
- result = def.parse(this, { minPrec: 0 }, arg);
9317
+ result = def.parse(this, arg, { minPrec: 0 });
9174
9318
  else
9175
9319
  result = arg;
9176
9320
  if (result)
@@ -9182,7 +9326,7 @@ var _Parser = class {
9182
9326
  this.index = index;
9183
9327
  return result;
9184
9328
  }
9185
- matchPostfix(lhs, until) {
9329
+ parsePostfixOperator(lhs, until) {
9186
9330
  console.assert(lhs !== null);
9187
9331
  if (lhs === null)
9188
9332
  return null;
@@ -9204,119 +9348,32 @@ var _Parser = class {
9204
9348
  * Not suitable for general purpose text, e.g. argument of a `\text{}
9205
9349
  * command. See `matchChar()` instead.
9206
9350
  */
9207
- matchString() {
9351
+ parseStringGroupContent() {
9352
+ const start = this.index;
9208
9353
  let result = "";
9209
- while (!this.atBoundary) {
9210
- const token = this.peek;
9354
+ let level = 0;
9355
+ while (!this.atBoundary || level > 0) {
9356
+ const token = this.nextToken();
9211
9357
  if (token === "<$>" || token === "<$$>") {
9358
+ this.index = start;
9212
9359
  return "";
9360
+ }
9361
+ if (token === "<{>") {
9362
+ level += 1;
9363
+ result += "\\{";
9364
+ } else if (token === "<}>") {
9365
+ level -= 1;
9366
+ result += "\\}";
9213
9367
  } else if (token === "<space>") {
9214
- this.next();
9215
9368
  result += " ";
9216
9369
  } else if (token[0] === "\\") {
9217
- result += this.next();
9218
- } else {
9219
- result += this.next();
9220
- }
9221
- }
9222
- return result;
9223
- }
9224
- /** Match a string as an argument (in a `{}` pair) */
9225
- matchStringArgument() {
9226
- const start = this.index;
9227
- this.skipSpaceTokens();
9228
- if (this.match("<{>")) {
9229
- this.addBoundary(["<}>"]);
9230
- while (this.match("<space>")) {
9231
- }
9232
- const arg = this.matchString();
9233
- if (this.matchBoundary())
9234
- return arg.trimEnd();
9235
- this.removeBoundary();
9236
- }
9237
- this.index = start;
9238
- return null;
9239
- }
9240
- /**
9241
- * Match an expression in a tabular format, where rows are separated by `\\`
9242
- * and columns by `&`.
9243
- *
9244
- * Return rows of sparse columns: empty rows are indicated with `Nothing`,
9245
- * and empty cells are also indicated with `Nothing`.
9246
- */
9247
- matchTabular() {
9248
- const result = [];
9249
- let row = [];
9250
- let expr = null;
9251
- while (!this.atBoundary) {
9252
- this.skipSpace();
9253
- if (this.match("&")) {
9254
- row.push(expr ?? "Nothing");
9255
- expr = null;
9256
- } else if (this.match("\\\\") || this.match("\\cr")) {
9257
- this.skipSpace();
9258
- this.matchLatexOptionalGroup();
9259
- if (expr !== null)
9260
- row.push(expr);
9261
- result.push(row);
9262
- row = [];
9263
- expr = null;
9370
+ result += token;
9264
9371
  } else {
9265
- const cell = [];
9266
- let peek = this.peek;
9267
- while (peek !== "&" && peek !== "\\\\" && peek !== "\\cr" && !this.atBoundary) {
9268
- expr = this.matchExpression({
9269
- condition: (p) => {
9270
- const peek2 = p.peek;
9271
- return peek2 === "&" || peek2 === "\\\\" || peek2 === "\\cr";
9272
- }
9273
- });
9274
- if (expr)
9275
- cell.push(expr);
9276
- else {
9277
- cell.push(["Error", ["'unexpected-token'", peek]]);
9278
- this.next();
9279
- }
9280
- this.skipSpace();
9281
- peek = this.peek;
9282
- }
9283
- if (cell.length > 1)
9284
- expr = ["Sequence", ...cell];
9285
- else
9286
- expr = cell[0] ?? "Nothing";
9372
+ result += token;
9287
9373
  }
9288
9374
  }
9289
- if (expr !== null)
9290
- row.push(expr);
9291
- if (row.length > 0)
9292
- result.push(row);
9293
9375
  return result;
9294
9376
  }
9295
- matchEnvironment() {
9296
- const index = this.index;
9297
- if (!this.match("\\begin"))
9298
- return null;
9299
- const name = this.matchStringArgument();
9300
- if (name === null)
9301
- return this.error("expected-environment-name", index);
9302
- this.addBoundary(["\\end", "<{>", ...name.split(""), "<}>"]);
9303
- const def = this._dictionary.environment.get(name);
9304
- if (!def) {
9305
- this.matchTabular();
9306
- this.skipSpace();
9307
- if (!this.matchBoundary())
9308
- return this.boundaryError("unbalanced-environment");
9309
- return this.error(["unknown-environment", { str: name }], index);
9310
- }
9311
- const expr = def.parse(this, [], []);
9312
- this.skipSpace();
9313
- if (!this.matchBoundary())
9314
- return this.boundaryError("unbalanced-environment");
9315
- if (expr !== null)
9316
- return this.decorate(expr, index);
9317
- this.index = index;
9318
- return null;
9319
- }
9320
9377
  /**
9321
9378
  * Apply an invisible operator between two expressions.
9322
9379
  *
@@ -9339,12 +9396,18 @@ var _Parser = class {
9339
9396
  * => lhs is a number, rhs is a number, but not a literal
9340
9397
  */
9341
9398
  applyInvisibleOperator(until, lhs) {
9342
- if (lhs === null || head(lhs) === "Error" || symbol(lhs) === "Nothing" || isEmptySequence(lhs) || this.atTerminator(until) || this.options.applyInvisibleOperator === null)
9399
+ if (lhs === null || this.options.applyInvisibleOperator === null || head(lhs) === "Error" || symbol(lhs) === "Nothing" || isEmptySequence(lhs) || this.atTerminator(until))
9343
9400
  return null;
9401
+ if (this.isFunctionHead(lhs)) {
9402
+ const args = this.parseArguments("enclosure", until);
9403
+ if (args === null)
9404
+ return null;
9405
+ return [lhs, ...args];
9406
+ }
9344
9407
  if (this.peekDefinitions("operator") !== null)
9345
9408
  return null;
9346
9409
  const start = this.index;
9347
- const rhs = this.matchExpression({ ...until, minPrec: 390 });
9410
+ const rhs = this.parseExpression({ ...until, minPrec: 390 });
9348
9411
  if (rhs === null || symbol(rhs) === "Nothing" || isEmptySequence(rhs)) {
9349
9412
  this.index = start;
9350
9413
  return null;
@@ -9353,13 +9416,9 @@ var _Parser = class {
9353
9416
  return applyAssociativeOperator("Sequence", lhs, rhs);
9354
9417
  if (typeof this.options.applyInvisibleOperator === "function")
9355
9418
  return this.options.applyInvisibleOperator(this, lhs, rhs);
9356
- const lhsSymbol = symbol(lhs);
9357
- if (lhsSymbol) {
9358
- const isFunction = this.options.parseUnknownIdentifier(lhsSymbol, this) === "function";
9359
- if (isFunction) {
9360
- const seq = getSequence(rhs);
9361
- return seq ? [lhs, ...seq] : lhsSymbol;
9362
- }
9419
+ if (this.isFunctionHead(lhs)) {
9420
+ const seq = getSequence(rhs);
9421
+ return seq ? [lhs, ...seq] : lhs;
9363
9422
  }
9364
9423
  const lhsNumber = machineValue(lhs);
9365
9424
  if (lhsNumber !== null && Number.isInteger(lhsNumber)) {
@@ -9372,7 +9431,7 @@ var _Parser = class {
9372
9431
  }
9373
9432
  if (head(rhs) === "Delimiter") {
9374
9433
  if (head(op(rhs, 1)) === "Sequence")
9375
- return [lhsSymbol ?? lhs, ...ops(op(rhs, 1)) ?? []];
9434
+ return [lhs, ...ops(op(rhs, 1)) ?? []];
9376
9435
  if (!op(rhs, 1) || symbol(op(rhs, 1)) === "Nothing")
9377
9436
  return applyAssociativeOperator(
9378
9437
  "Sequence",
@@ -9384,7 +9443,13 @@ var _Parser = class {
9384
9443
  return applyAssociativeOperator("Sequence", lhs, rhs);
9385
9444
  return applyAssociativeOperator("Multiply", lhs, rhs);
9386
9445
  }
9387
- matchUnexpectedLatexCommand() {
9446
+ /**
9447
+ * This is an error handling method. We've encountered a LaTeX command
9448
+ * but were not able to match it to any entry in the LaTeX dictionary,
9449
+ * or ran into it in an unexpected context (postfix operator lacking an
9450
+ * argument, for example)
9451
+ */
9452
+ parseUnexpectedLatexCommand() {
9388
9453
  const start = this.index;
9389
9454
  let opDefs = this.peekDefinitions("operator");
9390
9455
  if (opDefs) {
@@ -9413,7 +9478,7 @@ var _Parser = class {
9413
9478
  if (def.name)
9414
9479
  return [
9415
9480
  def.name,
9416
- this.matchExpression() ?? this.error("missing", start)
9481
+ this.parseExpression() ?? this.error("missing", start)
9417
9482
  ];
9418
9483
  return this.error("unexpected-operator", start);
9419
9484
  }
@@ -9422,11 +9487,9 @@ var _Parser = class {
9422
9487
  const [def, n] = opDefs[0];
9423
9488
  this.index += n;
9424
9489
  if (typeof def.parse === "function") {
9425
- const result = def.parse(
9426
- this,
9427
- { minPrec: 0 },
9428
- this.error("missing", start)
9429
- );
9490
+ const result = def.parse(this, this.error("missing", start), {
9491
+ minPrec: 0
9492
+ });
9430
9493
  if (result)
9431
9494
  return result;
9432
9495
  }
@@ -9434,7 +9497,7 @@ var _Parser = class {
9434
9497
  return [
9435
9498
  def.name,
9436
9499
  this.error("missing", start),
9437
- this.matchExpression() ?? this.error("missing", start)
9500
+ this.parseExpression() ?? this.error("missing", start)
9438
9501
  ];
9439
9502
  return this.error("unexpected-operator", start);
9440
9503
  }
@@ -9442,10 +9505,10 @@ var _Parser = class {
9442
9505
  const command = this.peek;
9443
9506
  if (!command || command[0] !== "\\")
9444
9507
  return null;
9445
- this.next();
9508
+ this.nextToken();
9446
9509
  this.skipSpaceTokens();
9447
9510
  if (command === "\\end") {
9448
- const name = this.matchStringArgument();
9511
+ const name = this.parseStringGroup();
9449
9512
  if (name === null)
9450
9513
  return this.error("expected-environment-name", start);
9451
9514
  return this.error(["unbalanced-environment", { str: name }], start);
@@ -9457,7 +9520,7 @@ var _Parser = class {
9457
9520
  level += 1;
9458
9521
  if (this.peek === "]")
9459
9522
  level -= 1;
9460
- this.next();
9523
+ this.nextToken();
9461
9524
  }
9462
9525
  this.match("]");
9463
9526
  }
@@ -9483,7 +9546,7 @@ var _Parser = class {
9483
9546
  level += 1;
9484
9547
  if (this.peek === "<}>")
9485
9548
  level -= 1;
9486
- this.next();
9549
+ this.nextToken();
9487
9550
  }
9488
9551
  this.match("<}>");
9489
9552
  }
@@ -9491,15 +9554,20 @@ var _Parser = class {
9491
9554
  }
9492
9555
  /**
9493
9556
  * <primary> :=
9494
- * (<number> | <symbol> | <environment> | <matchfix-expr>) <subsup>* <postfix-operator>*
9557
+ * (<number> | <symbol> | <environment> | <matchfix-expr>)
9558
+ * <subsup>* <postfix-operator>*
9495
9559
  *
9496
- * <symbol> ::= (<symbol-id> | (<latex-command><latex-arguments>)) <arguments>
9560
+ * <symbol> ::=
9561
+ * (<symbol-id> | (<latex-command><latex-arguments>)) <arguments>
9497
9562
  *
9498
9563
  * <matchfix-expr> :=
9499
- * <matchfix-op-open> <expression> [<matchfix-op-separator> <expression>] <matchfix-op-close>
9564
+ * <matchfix-op-open>
9565
+ * <expression>
9566
+ * (<matchfix-op-separator> <expression>)*
9567
+ * <matchfix-op-close>
9500
9568
  *
9501
9569
  */
9502
- matchPrimary(until) {
9570
+ parsePrimary(until) {
9503
9571
  if (this.atBoundary)
9504
9572
  return null;
9505
9573
  if (this.atTerminator(until))
@@ -9509,7 +9577,7 @@ var _Parser = class {
9509
9577
  if (this.match("<}>"))
9510
9578
  return this.error("unexpected-closing-delimiter", start);
9511
9579
  if (this.match("<{>")) {
9512
- result = this.matchExpression({ condition: (p) => p.peek === "<}>" });
9580
+ result = this.parseExpression({ condition: (p) => p.peek === "<}>" });
9513
9581
  if (result === null)
9514
9582
  return this.error("expected-expression", start);
9515
9583
  if (!this.match("<}>")) {
@@ -9520,25 +9588,25 @@ var _Parser = class {
9520
9588
  }
9521
9589
  }
9522
9590
  if (result === null) {
9523
- const num = this.matchNumber();
9524
- if (num)
9591
+ const num = this.parseNumber();
9592
+ if (num !== null)
9525
9593
  result = { num };
9526
9594
  }
9527
- result ?? (result = this.matchEnclosure());
9528
- result ?? (result = this.matchEnvironment());
9595
+ result ?? (result = this.parseEnclosure());
9596
+ result ?? (result = this.parseEnvironment());
9529
9597
  if (result === null && this.matchAll(this._positiveInfinityTokens))
9530
9598
  result = { num: "+Infinity" };
9531
9599
  if (result === null && this.matchAll(this._negativeInfinityTokens))
9532
9600
  result = { num: "-Infinity" };
9533
9601
  if (result === null && this.matchAll(this._notANumberTokens))
9534
9602
  result = { num: "NaN" };
9535
- result ?? (result = this.matchFunction(until) ?? this.matchSymbol(until) ?? matchInvalidIdentifier(this));
9603
+ result ?? (result = this.parseGenericExpression(until) ?? this.parseFunction(until) ?? this.parseSymbol(until) ?? parseInvalidIdentifier(this));
9536
9604
  if (result !== null) {
9537
9605
  result = this.decorate(result, start);
9538
9606
  let postfix = null;
9539
9607
  let index = this.index;
9540
9608
  do {
9541
- postfix = this.matchPostfix(result, until);
9609
+ postfix = this.parsePostfixOperator(result, until);
9542
9610
  result = postfix ?? result;
9543
9611
  if (this.index === index && postfix !== null) {
9544
9612
  console.assert(this.index !== index, "No token consumed");
@@ -9547,9 +9615,8 @@ var _Parser = class {
9547
9615
  index = this.index;
9548
9616
  } while (postfix !== null);
9549
9617
  }
9550
- result ?? (result = this.matchUnexpectedLatexCommand());
9551
9618
  if (result !== null)
9552
- result = this.matchSupsub(result);
9619
+ result = this.parseSupsub(result);
9553
9620
  return this.decorate(result, start);
9554
9621
  }
9555
9622
  /**
@@ -9560,9 +9627,10 @@ var _Parser = class {
9560
9627
  * | <prefix-op> <primary>
9561
9628
  * | <primary> <infix-op> <expression>
9562
9629
  *
9563
- * Stop when an operator of precedence less than `until.minPrec` is encountered
9630
+ * Stop when an operator of precedence less than `until.minPrec`
9631
+ * is encountered
9564
9632
  */
9565
- matchExpression(until) {
9633
+ parseExpression(until) {
9566
9634
  const start = this.index;
9567
9635
  this.skipSpace();
9568
9636
  if (this.atBoundary) {
@@ -9572,9 +9640,9 @@ var _Parser = class {
9572
9640
  until ?? (until = { minPrec: 0 });
9573
9641
  if (until.minPrec === void 0)
9574
9642
  until.minPrec = 0;
9575
- let lhs = this.matchPrefixOperator({ ...until, minPrec: 0 });
9643
+ let lhs = this.parsePrefixOperator({ ...until, minPrec: 0 });
9576
9644
  if (lhs === null) {
9577
- lhs = this.matchPrimary(until);
9645
+ lhs = this.parsePrimary(until);
9578
9646
  if (head(lhs) === "Sequence" && nops(lhs) === 0)
9579
9647
  lhs = null;
9580
9648
  }
@@ -9582,7 +9650,7 @@ var _Parser = class {
9582
9650
  let done = false;
9583
9651
  while (!done && !this.atTerminator(until)) {
9584
9652
  this.skipSpace();
9585
- let result = this.matchInfixOperator(lhs, until);
9653
+ let result = this.parseInfixOperator(lhs, until);
9586
9654
  if (result === null) {
9587
9655
  result = this.applyInvisibleOperator(until, lhs);
9588
9656
  }
@@ -9593,6 +9661,7 @@ var _Parser = class {
9593
9661
  }
9594
9662
  }
9595
9663
  }
9664
+ lhs ?? (lhs = this.parseUnexpectedLatexCommand());
9596
9665
  return this.decorate(lhs, start);
9597
9666
  }
9598
9667
  /**
@@ -9627,18 +9696,19 @@ var _Parser = class {
9627
9696
  const latex = this.latex(fromToken, this.index);
9628
9697
  return latex ? ["Error", msg, ["Latex", { str: latex }]] : ["Error", msg];
9629
9698
  }
9699
+ isFunctionHead(expr) {
9700
+ if (expr === null)
9701
+ return false;
9702
+ const s = symbol(expr);
9703
+ if (!s)
9704
+ return this.computeEngine.box(expr).domain.isFunction;
9705
+ if (this.computeEngine && this.computeEngine.lookupFunction(s) !== void 0)
9706
+ return true;
9707
+ if (this.options.parseUnknownIdentifier?.(s, this) === "function")
9708
+ return true;
9709
+ return false;
9710
+ }
9630
9711
  };
9631
- function countPrimeLevel(parser) {
9632
- if (parser.match("\\tripleprime"))
9633
- return 3;
9634
- if (parser.match("\\doubleprime"))
9635
- return 2;
9636
- if (parser.match("\\prime"))
9637
- return 1;
9638
- if (parser.match("'"))
9639
- return 1;
9640
- return 0;
9641
- }
9642
9712
 
9643
9713
  // src/compute-engine/latex-syntax/serialize-number.ts
9644
9714
  function formatFractionalPart(m, options) {
@@ -9982,7 +10052,7 @@ var Serializer = class {
9982
10052
  const name = head(expr);
9983
10053
  if (typeof name === "string" && name !== "Delimiter" && name !== "Subscript") {
9984
10054
  const def = this.dictionary.name.get(name);
9985
- if (def && (def.kind === "identifier" || def.kind === "prefix" || def.kind === "infix" || def.kind === "postfix") && def.precedence < prec)
10055
+ if (def && (def.kind === "symbol" || def.kind === "prefix" || def.kind === "infix" || def.kind === "postfix") && def.precedence < prec)
9986
10056
  return this.wrapString(
9987
10057
  this.serialize(expr),
9988
10058
  this.options.applyFunctionStyle(expr, this.level)
@@ -10062,8 +10132,11 @@ var Serializer = class {
10062
10132
  if (typeof h === "string" && h.length > 0 && h[0] === "\\") {
10063
10133
  return joinLatex([h, ...args.map((x) => `{${this.serialize(x)}}`)]);
10064
10134
  }
10065
- if (typeof h === "string")
10135
+ if (typeof h === "string") {
10136
+ if (h.length === 1)
10137
+ return serializeIdentifier(h) + this.wrapArguments(expr);
10066
10138
  return serializeIdentifier(h, "upright") + this.wrapArguments(expr);
10139
+ }
10067
10140
  const style = this.options.applyFunctionStyle(expr, this.level);
10068
10141
  return "\\mathrm{Apply}" + this.wrapString(
10069
10142
  this.serialize(h) + ", " + this.serialize(["List", ...args]),
@@ -10090,10 +10163,12 @@ var Serializer = class {
10090
10163
  const symbolName = symbol(expr);
10091
10164
  if (symbolName !== null) {
10092
10165
  const def = this.dictionary.name.get(symbolName);
10093
- if (def?.kind === "identifier")
10166
+ if (def?.kind === "symbol")
10094
10167
  return this.serializeSymbol(expr, def);
10095
10168
  if (def?.kind === "function")
10096
10169
  return this.serializeFunction(expr, def);
10170
+ if (typeof def?.serialize === "function")
10171
+ return def.serialize(this, expr);
10097
10172
  }
10098
10173
  const dict = dictionary(expr);
10099
10174
  if (dict !== null)
@@ -10106,7 +10181,7 @@ var Serializer = class {
10106
10181
  return def.serialize(this, expr);
10107
10182
  if (def.kind === "infix" || def.kind === "postfix" || def.kind === "prefix")
10108
10183
  return serializeOperator(this, expr, def);
10109
- if (def.kind === "identifier")
10184
+ if (def.kind === "symbol")
10110
10185
  return this.serializeSymbol(expr, def);
10111
10186
  if (def.kind === "function")
10112
10187
  return this.serializeFunction(expr, def);
@@ -10370,7 +10445,7 @@ var LatexSyntax = class _LatexSyntax {
10370
10445
  ...DEFAULT_SERIALIZE_LATEX_OPTIONS,
10371
10446
  ...opts
10372
10447
  };
10373
- this.dictionary = indexLatexDictionary(
10448
+ this._dictionary = indexLatexDictionary(
10374
10449
  options.dictionary ?? _LatexSyntax.getDictionary(),
10375
10450
  (sig) => this.onError([sig])
10376
10451
  );
@@ -10391,16 +10466,16 @@ var LatexSyntax = class _LatexSyntax {
10391
10466
  }
10392
10467
  if (!DEFAULT_LATEX_DICTIONARY[category])
10393
10468
  return [];
10394
- return [...DEFAULT_LATEX_DICTIONARY[category]];
10469
+ return Object.freeze([...DEFAULT_LATEX_DICTIONARY[category]]);
10395
10470
  }
10396
10471
  parse(latex) {
10397
10472
  const parser = new _Parser(
10398
10473
  tokenize(latex, []),
10399
10474
  this.options,
10400
- this.dictionary,
10475
+ this._dictionary,
10401
10476
  this.computeEngine
10402
10477
  );
10403
- let expr = parser.matchExpression();
10478
+ let expr = parser.parseExpression();
10404
10479
  if (!parser.atEnd) {
10405
10480
  const opDefs = parser.peekDefinitions("infix");
10406
10481
  if (opDefs) {
@@ -10409,8 +10484,8 @@ var LatexSyntax = class _LatexSyntax {
10409
10484
  parser.index += n;
10410
10485
  const result = def.parse(
10411
10486
  parser,
10412
- { minPrec: 0 },
10413
- expr ?? parser.error("missing", start)
10487
+ expr ?? parser.error("missing", start),
10488
+ { minPrec: 0 }
10414
10489
  );
10415
10490
  if (result)
10416
10491
  return result;
@@ -10424,7 +10499,7 @@ var LatexSyntax = class _LatexSyntax {
10424
10499
  parser.index = start;
10425
10500
  }
10426
10501
  const index = parser.index;
10427
- const id = parser.matchIdentifier();
10502
+ const id = matchIdentifier(parser);
10428
10503
  if (id) {
10429
10504
  const idError = parser.error(["unexpected-identifier", id], index);
10430
10505
  return expr ? ["Sequence", expr, idError] : idError;
@@ -10446,9 +10521,9 @@ var LatexSyntax = class _LatexSyntax {
10446
10521
  return expr ? ["Sequence", expr, enclosureError] : enclosureError;
10447
10522
  }
10448
10523
  const rest = parser.index;
10449
- const token = parser.next();
10524
+ const token = parser.nextToken();
10450
10525
  while (!parser.atEnd)
10451
- parser.next();
10526
+ parser.nextToken();
10452
10527
  if (!token)
10453
10528
  return parser.error("syntax-error", rest);
10454
10529
  const error = parser.error(
@@ -10481,7 +10556,7 @@ var LatexSyntax = class _LatexSyntax {
10481
10556
  return this._serializer;
10482
10557
  this._serializer = new Serializer(
10483
10558
  this.options,
10484
- this.dictionary,
10559
+ this._dictionary,
10485
10560
  this.onError
10486
10561
  );
10487
10562
  return this._serializer;
@@ -13055,6 +13130,14 @@ function ancestors(dom) {
13055
13130
  gDomainLiterals[dom] = new Set(result);
13056
13131
  return result;
13057
13132
  }
13133
+ function domainSetsLibrary() {
13134
+ const table = {};
13135
+ for (const dom of Object.keys(DOMAIN_LITERAL)) {
13136
+ if (dom !== "Domain" && dom !== "Nothing" && dom !== "String" && dom !== "Symbol" && dom !== "List" && dom !== "Tuple" && dom !== "Sequence")
13137
+ table[dom] = { domain: "Set" };
13138
+ }
13139
+ return table;
13140
+ }
13058
13141
 
13059
13142
  // src/compute-engine/boxed-expression/abstract-boxed-expression.ts
13060
13143
  var import_complex6 = __toESM(require_complex());
@@ -19223,7 +19306,7 @@ var ARITHMETIC_LIBRARY = [
19223
19306
  e: {
19224
19307
  domain: "TranscendentalNumber",
19225
19308
  constant: true,
19226
- holdUntil: "N",
19309
+ holdUntil: "never",
19227
19310
  value: "ExponentialE"
19228
19311
  },
19229
19312
  i: {
@@ -19255,7 +19338,7 @@ var ARITHMETIC_LIBRARY = [
19255
19338
  ImaginaryUnit: {
19256
19339
  domain: "ImaginaryNumber",
19257
19340
  constant: true,
19258
- holdUntil: "never",
19341
+ holdUntil: "evaluate",
19259
19342
  wikidata: "Q193796",
19260
19343
  flags: { imaginary: true },
19261
19344
  value: ["Complex", 0, 1]
@@ -21317,8 +21400,8 @@ var CONSTRUCTIBLE_VALUES = [
21317
21400
  [
21318
21401
  [1, 8],
21319
21402
  {
21320
- Sin: "$\\frac\\sqrt{2-\\sqrt2}{2}$",
21321
- Cos: "$\\frac {\\sqrt {2+{\\sqrt {2}}}}{2}$",
21403
+ Sin: "$\\frac{\\sqrt{2-\\sqrt2}}{2}$",
21404
+ Cos: "$\\frac{\\sqrt {2+{\\sqrt {2}}}}{2}$",
21322
21405
  Tan: "$\\sqrt{2} - 1$",
21323
21406
  Cot: "$\\sqrt{2} + 1$",
21324
21407
  Sec: "$\\sqrt{ 4 - 2\\sqrt{2}}$",
@@ -22421,7 +22504,19 @@ function isSymbolDefinition(def) {
22421
22504
  return !!def && typeof def === "object" && ("domain" in def || "value" in def || "constant" in def);
22422
22505
  }
22423
22506
  function isFunctionDefinition(def) {
22424
- return !!def && typeof def === "object" && ("complexity" in def || "numeric" in def || "signature" in def);
22507
+ if (def === void 0 || def === null)
22508
+ return false;
22509
+ if (typeof def !== "object")
22510
+ return false;
22511
+ if ("complexity" in def || "numeric" in def || "signature" in def)
22512
+ return true;
22513
+ if (!("domain" in def))
22514
+ return false;
22515
+ if (def.domain === void 0)
22516
+ return false;
22517
+ if (typeof def.domain === "string")
22518
+ return def.domain === "Function";
22519
+ return def.domain.isFunction;
22425
22520
  }
22426
22521
 
22427
22522
  // src/compute-engine/library/library.ts
@@ -22501,7 +22596,7 @@ var LIBRARIES = {
22501
22596
  // @todo // volume, speed, area
22502
22597
  "domains": [],
22503
22598
  "core": CORE_LIBRARY,
22504
- "collections": [SETS_LIBRARY, COLLECTIONS_LIBRARY],
22599
+ "collections": [SETS_LIBRARY, COLLECTIONS_LIBRARY, domainSetsLibrary()],
22505
22600
  // 'domains': getDomainsDictionary(),
22506
22601
  "linear-algebra": [],
22507
22602
  //@todo // 'linear-algebra': [
@@ -23801,16 +23896,6 @@ var ComputeEngine = class _ComputeEngine {
23801
23896
  this._tolerance = NUMERIC_TOLERANCE;
23802
23897
  this._bignumTolerance = this.bignum(this._tolerance);
23803
23898
  }
23804
- /** @internal */
23805
- bignum(a) {
23806
- if (typeof a === "bigint")
23807
- return new this._bignum(a.toString());
23808
- return new this._bignum(a);
23809
- }
23810
- /** @internal */
23811
- complex(a, b) {
23812
- return new import_complex19.Complex(a, b);
23813
- }
23814
23899
  chop(n) {
23815
23900
  if (typeof n === "number" && Math.abs(n) <= this._tolerance)
23816
23901
  return 0;
@@ -23820,6 +23905,20 @@ var ComputeEngine = class _ComputeEngine {
23820
23905
  return 0;
23821
23906
  return n;
23822
23907
  }
23908
+ bignum(a) {
23909
+ if (typeof a === "bigint")
23910
+ return new this._bignum(a.toString());
23911
+ return new this._bignum(a);
23912
+ }
23913
+ complex(a, b) {
23914
+ return new import_complex19.Complex(a, b);
23915
+ }
23916
+ isBignum(a) {
23917
+ return a instanceof Decimal;
23918
+ }
23919
+ isComplex(a) {
23920
+ return a instanceof import_complex19.Complex;
23921
+ }
23823
23922
  get latexSyntax() {
23824
23923
  if (!this._latexSyntax)
23825
23924
  this._latexSyntax = new LatexSyntax({
@@ -24507,20 +24606,21 @@ var ComputeEngine = class _ComputeEngine {
24507
24606
  };
24508
24607
 
24509
24608
  // src/compute-engine.ts
24510
- var version = "0.12.5";
24609
+ var version = "0.12.6";
24511
24610
  globalThis[Symbol.for("io.cortexjs.compute-engine")] = {
24512
24611
  ComputeEngine: ComputeEngine.prototype.constructor,
24513
- version: "0.12.5"
24612
+ version: "0.12.6"
24514
24613
  };
24515
24614
  export {
24516
24615
  ComputeEngine,
24517
24616
  isEnvironmentEntry,
24617
+ isExpressionEntry,
24518
24618
  isFunctionEntry,
24519
- isIdentifierEntry,
24520
24619
  isInfixEntry,
24521
24620
  isMatchfixEntry,
24522
24621
  isPostfixEntry,
24523
24622
  isPrefixEntry,
24623
+ isSymbolEntry,
24524
24624
  version
24525
24625
  };
24526
24626
  /*! Bundled license information: