@danielsimonjr/mathts-expression 0.11.1 → 0.12.0

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.
@@ -35,7 +35,16 @@ export interface EvaluateOptions {
35
35
  * evaluate('x^2', { x: 3 }); // 9
36
36
  * ```
37
37
  */
38
- export declare function createEvaluate(parseFn: (expr: string) => MathNode, mathScope: Record<string, unknown>): {
38
+ export declare function createEvaluate(parseFn: (expr: string) => MathNode, mathScope: Record<string, unknown>,
39
+ /**
40
+ * Optional fingerprint of the state `parseFn` depends on besides the text
41
+ * (for example the live `number` / `precision` config, which decides the
42
+ * numeric type of literals at parse time). Called on every evaluate; its
43
+ * value becomes part of the cache key, so a parse made under one config is
44
+ * never reused under another. Omit when `parseFn` is a pure function of its
45
+ * input.
46
+ */
47
+ cacheKey?: () => string): {
39
48
  (expr: string, scope?: Record<string, unknown> | Scope, options?: EvaluateOptions): unknown;
40
49
  (exprs: string[], scope?: Record<string, unknown> | Scope, options?: EvaluateOptions): unknown[];
41
50
  };
@@ -1 +1 @@
1
- {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/evaluator/evaluate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAuHD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;WAW1B,MAAM,UACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,YAC7B,eAAe,GACxB,OAAO;YAUD,MAAM,EAAE,UACP,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,YAC7B,eAAe,GACxB,OAAO,EAAE;EA0Bb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,eAAe,GACxB,kBAAkB,CAMpB"}
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/evaluator/evaluate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAmJD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;AAClC;;;;;;;GAOG;AACH,QAAQ,CAAC,EAAE,MAAM,MAAM;WAWf,MAAM,UACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,YAC7B,eAAe,GACxB,OAAO;YAUD,MAAM,EAAE,UACP,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,YAC7B,eAAe,GACxB,OAAO,EAAE;EA2Cb;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,eAAe,GACxB,kBAAkB,CAMpB"}
package/dist/index.js CHANGED
@@ -470,7 +470,7 @@ const MAX_EXPRESSION_LENGTH = 1e6;
470
470
  //#endregion
471
471
  //#region src/parse.ts
472
472
  const name$45 = "parse";
473
- const createParse = /* #__PURE__ */ factory(name$45, [
473
+ const dependencies$45 = [
474
474
  "typed",
475
475
  "numeric",
476
476
  "config",
@@ -489,7 +489,47 @@ const createParse = /* #__PURE__ */ factory(name$45, [
489
489
  "RangeNode",
490
490
  "RelationalNode",
491
491
  "SymbolNode"
492
- ], ({ typed, numeric, config, AccessorNode, ArrayNode, AssignmentNode, BlockNode, ConditionalNode, ConstantNode, FunctionAssignmentNode, FunctionNode, IndexNode, ObjectNode, OperatorNode, ParenthesisNode, RangeNode, RelationalNode, SymbolNode }) => {
492
+ ];
493
+ const RELATIONAL_OPERATORS = Object.freeze({
494
+ "==": "equal",
495
+ "!=": "unequal",
496
+ "<": "smaller",
497
+ ">": "larger",
498
+ "<=": "smallerEq",
499
+ ">=": "largerEq"
500
+ });
501
+ const SHIFT_OPERATORS = Object.freeze({
502
+ "<<": "leftShift",
503
+ ">>": "rightArithShift",
504
+ ">>>": "rightLogShift"
505
+ });
506
+ const CONVERSION_OPERATORS = Object.freeze({
507
+ to: "to",
508
+ in: "to"
509
+ });
510
+ const ADD_SUBTRACT_OPERATORS = Object.freeze({
511
+ "+": "add",
512
+ "-": "subtract"
513
+ });
514
+ const MULTIPLY_DIVIDE_OPERATORS = Object.freeze({
515
+ "*": "multiply",
516
+ ".*": "dotMultiply",
517
+ "/": "divide",
518
+ "./": "dotDivide",
519
+ "%": "mod",
520
+ mod: "mod"
521
+ });
522
+ const UNARY_OPERATORS = Object.freeze({
523
+ "-": "unaryMinus",
524
+ "+": "unaryPlus",
525
+ "~": "bitNot",
526
+ not: "not"
527
+ });
528
+ const POSTFIX_OPERATORS = Object.freeze({
529
+ "!": "factorial",
530
+ "'": "ctranspose"
531
+ });
532
+ const createParse = /* #__PURE__ */ factory(name$45, dependencies$45, ({ typed, numeric, config, AccessorNode, ArrayNode, AssignmentNode, BlockNode, ConditionalNode, ConstantNode, FunctionAssignmentNode, FunctionNode, IndexNode, ObjectNode, OperatorNode, ParenthesisNode, RangeNode, RelationalNode, SymbolNode }) => {
493
533
  const parse = typed(name$45, {
494
534
  string: function(expression) {
495
535
  if (expression.length > 1e6) throw new SyntaxError(`expression exceeds ${MAX_EXPRESSION_LENGTH} characters`);
@@ -931,18 +971,10 @@ const createParse = /* #__PURE__ */ factory(name$45, [
931
971
  function parseRelational(state) {
932
972
  const params = [parseShift(state)];
933
973
  const conditionals = [];
934
- const operators = {
935
- "==": "equal",
936
- "!=": "unequal",
937
- "<": "smaller",
938
- ">": "larger",
939
- "<=": "smallerEq",
940
- ">=": "largerEq"
941
- };
942
- while (hasOwnProperty(operators, state.token)) {
974
+ while (hasOwnProperty(RELATIONAL_OPERATORS, state.token)) {
943
975
  const cond = {
944
976
  name: state.token,
945
- fn: operators[state.token]
977
+ fn: RELATIONAL_OPERATORS[state.token]
946
978
  };
947
979
  conditionals.push(cond);
948
980
  getTokenSkipNewline(state);
@@ -958,14 +990,9 @@ const createParse = /* #__PURE__ */ factory(name$45, [
958
990
  let fn;
959
991
  let params;
960
992
  node = parseConversion(state);
961
- const operators = {
962
- "<<": "leftShift",
963
- ">>": "rightArithShift",
964
- ">>>": "rightLogShift"
965
- };
966
- while (hasOwnProperty(operators, state.token)) {
993
+ while (hasOwnProperty(SHIFT_OPERATORS, state.token)) {
967
994
  name = state.token;
968
- fn = operators[name];
995
+ fn = SHIFT_OPERATORS[name];
969
996
  getTokenSkipNewline(state);
970
997
  params = [node, parseConversion(state)];
971
998
  node = new OperatorNode(name, fn, params);
@@ -978,13 +1005,9 @@ const createParse = /* #__PURE__ */ factory(name$45, [
978
1005
  let fn;
979
1006
  let params;
980
1007
  node = parseRange(state);
981
- const operators = {
982
- to: "to",
983
- in: "to"
984
- };
985
- while (hasOwnProperty(operators, state.token)) {
1008
+ while (hasOwnProperty(CONVERSION_OPERATORS, state.token)) {
986
1009
  name = state.token;
987
- fn = operators[name];
1010
+ fn = CONVERSION_OPERATORS[name];
988
1011
  getTokenSkipNewline(state);
989
1012
  if (name === "in" && "])},;".includes(state.token)) node = new OperatorNode("*", "multiply", [node, new SymbolNode("in")], true);
990
1013
  else {
@@ -1019,13 +1042,9 @@ const createParse = /* #__PURE__ */ factory(name$45, [
1019
1042
  let fn;
1020
1043
  let params;
1021
1044
  node = parseMultiplyDivideModulus(state);
1022
- const operators = {
1023
- "+": "add",
1024
- "-": "subtract"
1025
- };
1026
- while (hasOwnProperty(operators, state.token)) {
1045
+ while (hasOwnProperty(ADD_SUBTRACT_OPERATORS, state.token)) {
1027
1046
  name = state.token;
1028
- fn = operators[name];
1047
+ fn = ADD_SUBTRACT_OPERATORS[name];
1029
1048
  getTokenSkipNewline(state);
1030
1049
  const rightNode = parseMultiplyDivideModulus(state);
1031
1050
  if (rightNode.isPercentage) params = [node, new OperatorNode("*", "multiply", [node, rightNode])];
@@ -1040,17 +1059,9 @@ const createParse = /* #__PURE__ */ factory(name$45, [
1040
1059
  let name;
1041
1060
  let fn;
1042
1061
  node = parseImplicitMultiplication(state);
1043
- const operators = {
1044
- "*": "multiply",
1045
- ".*": "dotMultiply",
1046
- "/": "divide",
1047
- "./": "dotDivide",
1048
- "%": "mod",
1049
- mod: "mod"
1050
- };
1051
- while (true) if (hasOwnProperty(operators, state.token)) {
1062
+ while (true) if (hasOwnProperty(MULTIPLY_DIVIDE_OPERATORS, state.token)) {
1052
1063
  name = state.token;
1053
- fn = operators[name];
1064
+ fn = MULTIPLY_DIVIDE_OPERATORS[name];
1054
1065
  getTokenSkipNewline(state);
1055
1066
  last = parseImplicitMultiplication(state);
1056
1067
  node = new OperatorNode(name, fn, [node, last]);
@@ -1121,14 +1132,8 @@ const createParse = /* #__PURE__ */ factory(name$45, [
1121
1132
  let name;
1122
1133
  let params;
1123
1134
  let fn;
1124
- const operators = {
1125
- "-": "unaryMinus",
1126
- "+": "unaryPlus",
1127
- "~": "bitNot",
1128
- not: "not"
1129
- };
1130
- if (hasOwnProperty(operators, state.token)) {
1131
- fn = operators[state.token];
1135
+ if (hasOwnProperty(UNARY_OPERATORS, state.token)) {
1136
+ fn = UNARY_OPERATORS[state.token];
1132
1137
  name = state.token;
1133
1138
  getTokenSkipNewline(state);
1134
1139
  params = [parseUnary(state)];
@@ -1165,13 +1170,9 @@ const createParse = /* #__PURE__ */ factory(name$45, [
1165
1170
  let fn;
1166
1171
  let params;
1167
1172
  node = parseCustomNodes(state);
1168
- const operators = {
1169
- "!": "factorial",
1170
- "'": "ctranspose"
1171
- };
1172
- while (hasOwnProperty(operators, state.token)) {
1173
+ while (hasOwnProperty(POSTFIX_OPERATORS, state.token)) {
1173
1174
  name = state.token;
1174
- fn = operators[name];
1175
+ fn = POSTFIX_OPERATORS[name];
1175
1176
  getToken(state);
1176
1177
  params = [node];
1177
1178
  node = new OperatorNode(name, fn, params);
@@ -7564,15 +7565,45 @@ function validateAst(node, depth = 0) {
7564
7565
  for (const k of Object.keys(properties)) validateAst(properties[k], depth + 1);
7565
7566
  }
7566
7567
  }
7567
- function createEvaluate(parseFn, mathScope) {
7568
+ const COMPILE_CACHE_SIZE = 256;
7569
+ const compileCaches = /* @__PURE__ */ new WeakMap();
7570
+ function cacheFor(mathScope, parseFn) {
7571
+ let byParser = compileCaches.get(mathScope);
7572
+ if (!byParser) {
7573
+ byParser = /* @__PURE__ */ new WeakMap();
7574
+ compileCaches.set(mathScope, byParser);
7575
+ }
7576
+ let cache = byParser.get(parseFn);
7577
+ if (!cache) {
7578
+ cache = /* @__PURE__ */ new Map();
7579
+ byParser.set(parseFn, cache);
7580
+ }
7581
+ return cache;
7582
+ }
7583
+ function createEvaluate(parseFn, mathScope, cacheKey) {
7568
7584
  function evaluate(exprOrExprs, scope, options) {
7569
7585
  if (Array.isArray(exprOrExprs)) return exprOrExprs.map((expr) => evaluateOne(expr, scope, options));
7570
7586
  return evaluateOne(exprOrExprs, scope, options);
7571
7587
  }
7588
+ const cache = cacheFor(mathScope, parseFn);
7572
7589
  function evaluateOne(expr, scope, options) {
7573
- const node = parseFn(expr);
7574
- if (!options || options.unsafe !== true) validateAst(node);
7575
- return compile(node, mathScope).evaluate(scope);
7590
+ const unsafe = options?.unsafe === true;
7591
+ const key = (unsafe ? "u:" : "s:") + (cacheKey ? cacheKey() + "\0" : "") + expr;
7592
+ let compiled = cache.get(key);
7593
+ if (compiled !== void 0) {
7594
+ cache.delete(key);
7595
+ cache.set(key, compiled);
7596
+ } else {
7597
+ const node = parseFn(expr);
7598
+ if (!unsafe) validateAst(node);
7599
+ compiled = compile(node, mathScope);
7600
+ cache.set(key, compiled);
7601
+ if (cache.size > COMPILE_CACHE_SIZE) {
7602
+ const oldest = cache.keys().next().value;
7603
+ if (oldest !== void 0) cache.delete(oldest);
7604
+ }
7605
+ }
7606
+ return compiled.evaluate(scope);
7576
7607
  }
7577
7608
  return evaluate;
7578
7609
  }
@@ -7878,6 +7909,17 @@ function errorTransform(err) {
7878
7909
  return err;
7879
7910
  }
7880
7911
  //#endregion
7912
+ //#region src/node/utils/describeType.ts
7913
+ function describeType(value) {
7914
+ if (value === null) return "null";
7915
+ if (Array.isArray(value)) return "array";
7916
+ if (typeof value === "object") {
7917
+ const name = value.constructor?.name;
7918
+ return typeof name === "string" && name !== "" ? name : "object";
7919
+ }
7920
+ return typeof value;
7921
+ }
7922
+ //#endregion
7881
7923
  //#region src/node/utils/stringSubset.ts
7882
7924
  function getStringSubset(str, index, invalidIndexMessage = "Index expected") {
7883
7925
  if (!isIndex(index)) throw new TypeError(invalidIndexMessage);
@@ -7931,9 +7973,9 @@ function accessFactory({ subset }) {
7931
7973
  else if (object && typeof object.subset === "function") return object.subset(index);
7932
7974
  else if (typeof object === "string") return getStringSubset(object, index);
7933
7975
  else if (typeof object === "object") {
7934
- if (!index.isObjectProperty()) throw new TypeError("Cannot apply a numeric index as object property");
7976
+ if (!index.isObjectProperty()) throw new TypeError(`Cannot apply a numeric index as object property (object is ${describeType(object)})`);
7935
7977
  return getSafeProperty(object, index.getObjectProperty());
7936
- } else throw new TypeError("Cannot apply index: unsupported type of object");
7978
+ } else throw new TypeError(`Cannot apply index: unsupported type of object (got ${describeType(object)})`);
7937
7979
  } catch (err) {
7938
7980
  throw errorTransform(err);
7939
7981
  }
@@ -8025,6 +8067,12 @@ const createAccessorNode = /* #__PURE__ */ factory(name$40, ["subset", "Node"],
8025
8067
  if (needParenthesis(this.object)) object = "\\left(' + object + '\\right)";
8026
8068
  return object + this.index.toTex(options);
8027
8069
  }
8070
+ _toMathML() {
8071
+ let object = this.object.toMathML();
8072
+ if (needParenthesis(this.object)) object = `<mrow><mo>(</mo>${object}<mo>)</mo></mrow>`;
8073
+ if (this.index.dotNotation) return `<mrow>${object}${this.index.toMathML()}</mrow>`;
8074
+ return `<msub><mrow>${object}</mrow>${this.index.toMathML()}</msub>`;
8075
+ }
8028
8076
  toJSON() {
8029
8077
  return {
8030
8078
  mathjs: name$40,
@@ -8109,6 +8157,26 @@ const createArrayNode = /* #__PURE__ */ factory(name$39, ["Node"], ({ Node }) =>
8109
8157
  return node.toHTML(options);
8110
8158
  }).join("<span class=\"math-separator\">,</span>") + "<span class=\"math-parenthesis math-square-parenthesis\">]</span>";
8111
8159
  }
8160
+ _toMathML() {
8161
+ const tableOf = (rows) => "<mrow><mo>[</mo><mtable>" + rows.map((row) => "<mtr>" + row.map((cell) => `<mtd>${cell}</mtd>`).join("") + "</mtr>").join("") + "</mtable><mo>]</mo></mrow>";
8162
+ const build = (items, nested) => {
8163
+ const mixedItems = items.some(isArrayNode) && !items.every(isArrayNode);
8164
+ const itemsFormRow = nested || mixedItems;
8165
+ const pieces = items.map((node) => {
8166
+ const arrayItems = node.items;
8167
+ if (arrayItems) {
8168
+ const sub = build(arrayItems, !nested);
8169
+ return sub.wrapped ? [tableOf(sub.rows)] : sub.rows[0];
8170
+ }
8171
+ return [node.toMathML()];
8172
+ });
8173
+ return {
8174
+ wrapped: mixedItems || !itemsFormRow || itemsFormRow && !nested,
8175
+ rows: itemsFormRow ? [pieces.flat()] : pieces
8176
+ };
8177
+ };
8178
+ return tableOf(build(this.items, false).rows);
8179
+ }
8112
8180
  _toTex(options) {
8113
8181
  function itemsToTex(items, nested) {
8114
8182
  const mixedItems = items.some(isArrayNode) && !items.every(isArrayNode);
@@ -8142,10 +8210,10 @@ function assignFactory({ subset }) {
8142
8210
  } else if (object && typeof object.subset === "function") return object.subset(index, value);
8143
8211
  else if (typeof object === "string") return setStringSubset(object, index, String(value));
8144
8212
  else if (typeof object === "object") {
8145
- if (!index.isObjectProperty()) throw TypeError("Cannot apply a numeric index as object property");
8213
+ if (!index.isObjectProperty()) throw TypeError(`Cannot apply a numeric index as object property (object is ${describeType(object)})`);
8146
8214
  setSafeProperty(object, index.getObjectProperty(), value);
8147
8215
  return object;
8148
- } else throw new TypeError("Cannot apply index: unsupported type of object");
8216
+ } else throw new TypeError(`Cannot apply index: unsupported type of object (got ${describeType(object)})`);
8149
8217
  } catch (err) {
8150
8218
  throw errorTransform(err);
8151
8219
  }
@@ -8392,6 +8460,9 @@ const createBlockNode = /* #__PURE__ */ factory(name$37, ["ResultSet", "Node"],
8392
8460
  return param.node.toHTML(options) + (param.visible ? "" : "<span class=\"math-separator\">;</span>");
8393
8461
  }).join("<span class=\"math-separator\"><br /></span>");
8394
8462
  }
8463
+ _toMathML() {
8464
+ return `<mrow>${this.blocks.map((param) => param.node.toMathML() + (param.visible ? "" : "<mo>;</mo>")).join("<mspace width=\"1em\"/>")}</mrow>`;
8465
+ }
8395
8466
  _toTex(options) {
8396
8467
  return this.blocks.map(function(param) {
8397
8468
  return param.node.toTex(options) + (param.visible ? "" : ";");
@@ -8486,6 +8557,9 @@ const createConditionalNode = /* #__PURE__ */ factory(name$36, ["Node"], ({ Node
8486
8557
  const parenClose = "<span class=\"math-parenthesis math-round-parenthesis\">)</span>";
8487
8558
  return formatConditionalBranches(this, options, (node) => node.toHTML(options), (inner) => parenOpen + inner + parenClose, (condition, trueExpr, falseExpr) => condition + "<span class=\"math-operator math-conditional-operator\">?</span>" + trueExpr + "<span class=\"math-operator math-conditional-operator\">:</span>" + falseExpr);
8488
8559
  }
8560
+ _toMathML() {
8561
+ return `<mrow><mo>{</mo><mtable columnalign="left left"><mtr><mtd>${this.trueExpr.toMathML()}</mtd><mtd><mtext>if </mtext>${this.condition.toMathML()}</mtd></mtr><mtr><mtd>${this.falseExpr.toMathML()}</mtd><mtd><mtext>otherwise</mtext></mtd></mtr></mtable></mrow>`;
8562
+ }
8489
8563
  _toTex(options) {
8490
8564
  return "\\begin{cases} {" + this.trueExpr.toTex(options) + "}, &\\quad{\\text{if }\\;" + this.condition.toTex(options) + "}\\\\{" + this.falseExpr.toTex(options) + "}, &\\quad{\\text{otherwise}}\\end{cases}";
8491
8565
  }
@@ -9011,6 +9085,12 @@ const createFunctionAssignmentNode = /* #__PURE__ */ factory(name$34, ["typed",
9011
9085
  if (needParenthesis(this, parenthesis, options && options.implicit)) expr = "<span class=\"math-parenthesis math-round-parenthesis\">(</span>" + expr + "<span class=\"math-parenthesis math-round-parenthesis\">)</span>";
9012
9086
  return "<span class=\"math-function\">" + escape(this.name) + "</span><span class=\"math-parenthesis math-round-parenthesis\">(</span>" + params.join("<span class=\"math-separator\">,</span>") + "<span class=\"math-parenthesis math-round-parenthesis\">)</span><span class=\"math-operator math-assignment-operator math-variable-assignment-operator math-binary-operator\">=</span>" + expr;
9013
9087
  }
9088
+ _toMathML() {
9089
+ let expr = this.expr.toMathML();
9090
+ if (needParenthesis(this, "keep", void 0)) expr = `<mrow><mo>(</mo>${expr}<mo>)</mo></mrow>`;
9091
+ const params = this.params.map((p) => toMathMLSymbol(p)).join("<mo>,</mo>");
9092
+ return `<mrow>${toMathMLSymbol(this.name)}<mo>&#x2061;</mo><mrow><mo>(</mo>${params}<mo>)</mo></mrow><mo>=</mo>${expr}</mrow>`;
9093
+ }
9014
9094
  _toTex(options) {
9015
9095
  const parenthesis = options && options.parenthesis ? options.parenthesis : "keep";
9016
9096
  let expr = this.expr.toTex(options);
@@ -9031,11 +9111,18 @@ function createSubScope(parentScope, args) {
9031
9111
  //#endregion
9032
9112
  //#region src/node/FunctionNode.ts
9033
9113
  const name$33 = "FunctionNode";
9034
- const createFunctionNode = /* #__PURE__ */ factory(name$33, [
9114
+ const dependencies$33 = [
9035
9115
  "math",
9036
9116
  "Node",
9037
9117
  "SymbolNode"
9038
- ], ({ math, Node, SymbolNode }) => {
9118
+ ];
9119
+ function isMissingMember(object, prop) {
9120
+ if (!(prop in Object(object))) return true;
9121
+ if (isSafeMethod(object, prop)) return false;
9122
+ if (isSafeProperty(object, prop)) return getSafeProperty(object, prop) === void 0;
9123
+ return false;
9124
+ }
9125
+ const createFunctionNode = /* #__PURE__ */ factory(name$33, dependencies$33, ({ math, Node, SymbolNode }) => {
9039
9126
  const strin = (entity) => format(entity, { truncate: 78 });
9040
9127
  function expandTemplate(template, node, options) {
9041
9128
  let latex = "";
@@ -9171,7 +9258,7 @@ const createFunctionNode = /* #__PURE__ */ factory(name$33, [
9171
9258
  const rawArgs = this.args;
9172
9259
  return function evalFunctionNode(scope, args, context) {
9173
9260
  const object = evalObject(scope, args, context);
9174
- if (fromOptionalChaining && (object == null || object[prop] === void 0)) return;
9261
+ if (fromOptionalChaining && (object == null || isMissingMember(object, prop))) return;
9175
9262
  const fn = getSafeMethod(object, prop);
9176
9263
  if (fn?.rawArgs) return fn(rawArgs, math, createSubScope(scope, args));
9177
9264
  else {
@@ -9296,6 +9383,15 @@ const createFunctionNode = /* #__PURE__ */ factory(name$33, [
9296
9383
  });
9297
9384
  //#endregion
9298
9385
  //#region src/node/IndexNode.ts
9386
+ function coerceIndexValue(value) {
9387
+ if (isBigNumber(value)) {
9388
+ const big = value;
9389
+ const n = big.toNumber();
9390
+ if (!big.isInteger() || !Number.isSafeInteger(n)) throw new RangeError(`Index must be an integer within the safe range, got BigNumber ${big.toString()}`);
9391
+ return n;
9392
+ }
9393
+ return value;
9394
+ }
9299
9395
  const name$32 = "IndexNode";
9300
9396
  const createIndexNode = /* #__PURE__ */ factory(name$32, ["Node", "size"], ({ Node, size }) => {
9301
9397
  class IndexNode extends Node {
@@ -9333,7 +9429,7 @@ const createIndexNode = /* #__PURE__ */ factory(name$32, ["Node", "size"], ({ No
9333
9429
  const index = getSafeProperty(math, "index");
9334
9430
  return function evalIndexNode(scope, args, context) {
9335
9431
  const dimensions = map(evalDimensions, function(evalDimension) {
9336
- return evalDimension(scope, args, context);
9432
+ return coerceIndexValue(evalDimension(scope, args, context));
9337
9433
  });
9338
9434
  return index(...dimensions);
9339
9435
  };
@@ -9374,6 +9470,10 @@ const createIndexNode = /* #__PURE__ */ factory(name$32, ["Node", "size"], ({ No
9374
9470
  if (this.dotNotation) return "<span class=\"math-operator math-accessor-operator\">.</span><span class=\"math-symbol math-property\">" + escape(this.getObjectProperty()) + "</span>";
9375
9471
  else return "<span class=\"math-parenthesis math-square-parenthesis\">[</span>" + dimensions.join("<span class=\"math-separator\">,</span>") + "<span class=\"math-parenthesis math-square-parenthesis\">]</span>";
9376
9472
  }
9473
+ _toMathML() {
9474
+ if (this.dotNotation) return `<mo>.</mo>${toMathMLSymbol(String(this.getObjectProperty()))}`;
9475
+ return `<mrow>${this.dimensions.map((range) => range.toMathML()).join("<mo>,</mo>")}</mrow>`;
9476
+ }
9377
9477
  _toTex(options) {
9378
9478
  const dimensions = this.dimensions.map(function(range) {
9379
9479
  return range.toTex(options);
@@ -9453,6 +9553,9 @@ const createObjectNode = /* #__PURE__ */ factory(name$31, ["Node"], ({ Node }) =
9453
9553
  _toHTML(options) {
9454
9554
  return renderObjectEntries(this.properties, (key, node) => "<span class=\"math-symbol math-property\">" + escape(key) + "</span><span class=\"math-operator math-assignment-operator math-property-assignment-operator math-binary-operator\">:</span>" + node.toHTML(options), "<span class=\"math-separator\">,</span>", (joined) => "<span class=\"math-parenthesis math-curly-parenthesis\">{</span>" + joined + "<span class=\"math-parenthesis math-curly-parenthesis\">}</span>");
9455
9555
  }
9556
+ _toMathML() {
9557
+ return renderObjectEntries(this.properties, (key, node) => `<mtr><mtd><mtext>${escapeMathML(key)}:</mtext></mtd><mtd>${node.toMathML()}</mtd></mtr>`, "", (joined) => `<mrow><mo>{</mo><mtable columnalign="left left">${joined}</mtable><mo>}</mo></mrow>`);
9558
+ }
9456
9559
  _toTex(options) {
9457
9560
  return renderObjectEntries(this.properties, (key, node) => "\\mathbf{" + key + ":} & " + node.toTex(options) + "\\\\", "\n", (joined) => "\\left\\{\\begin{array}{ll}" + joined + "\\end{array}\\right\\}");
9458
9561
  }
@@ -9974,6 +10077,14 @@ const createRangeNode = /* #__PURE__ */ factory(name$28, ["Node"], ({ Node }) =>
9974
10077
  const parenClose = "<span class=\"math-parenthesis math-round-parenthesis\">)</span>";
9975
10078
  return formatRangeDisplay(this, options, (child) => child.toHTML(options), (inner) => parenOpen + inner + parenClose, () => "<span class=\"math-operator math-range-operator\">:</span>");
9976
10079
  }
10080
+ _toMathML() {
10081
+ const parens = calculateNecessaryParentheses(this, "keep", "hide");
10082
+ const wrap = (s, need) => need ? `<mrow><mo>(</mo>${s}<mo>)</mo></mrow>` : s;
10083
+ let str = wrap(this.start.toMathML(), parens.start);
10084
+ if (this.step) str += "<mo>:</mo>" + wrap(this.step.toMathML(), parens.step);
10085
+ str += "<mo>:</mo>" + wrap(this.end.toMathML(), parens.end);
10086
+ return `<mrow>${str}</mrow>`;
10087
+ }
9977
10088
  _toTex(options) {
9978
10089
  const parenthesis = options && options.parenthesis ? options.parenthesis : "keep";
9979
10090
  const parens = calculateNecessaryParentheses(this, parenthesis, options && options.implicit || "hide");