temml 0.9.2 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/temml.mjs CHANGED
@@ -666,7 +666,7 @@ class TextNode {
666
666
 
667
667
  /**
668
668
  * Converts the text node into a string
669
- * (representing the text iteself).
669
+ * (representing the text itself).
670
670
  */
671
671
  toText() {
672
672
  return this.text;
@@ -843,7 +843,6 @@ defineSymbol(math, rel, "\u226a", "\\ll", true);
843
843
  defineSymbol(math, rel, "\u226b", "\\gg", true);
844
844
  defineSymbol(math, rel, "\u224d", "\\asymp", true);
845
845
  defineSymbol(math, rel, "\u2225", "\\parallel");
846
- defineSymbol(math, rel, "\u22c8", "\\bowtie", true);
847
846
  defineSymbol(math, rel, "\u2323", "\\smile", true);
848
847
  defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true);
849
848
  defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true);
@@ -1160,7 +1159,6 @@ defineSymbol(math, rel, "\u22d9", "\\gggtr");
1160
1159
  defineSymbol(math, bin, "\u22b2", "\\lhd");
1161
1160
  defineSymbol(math, bin, "\u22b3", "\\rhd");
1162
1161
  defineSymbol(math, rel, "\u2242", "\\eqsim", true);
1163
- defineSymbol(math, rel, "\u22c8", "\\Join");
1164
1162
  defineSymbol(math, rel, "\u2251", "\\Doteq", true);
1165
1163
  defineSymbol(math, rel, "\u297d", "\\strictif", true);
1166
1164
  defineSymbol(math, rel, "\u297c", "\\strictfi", true);
@@ -1186,6 +1184,11 @@ defineSymbol(math, bin, "\u22ba", "\\intercal", true);
1186
1184
  defineSymbol(math, bin, "\u22d2", "\\doublecap");
1187
1185
  defineSymbol(math, bin, "\u22d3", "\\doublecup");
1188
1186
  defineSymbol(math, bin, "\u22a0", "\\boxtimes", true);
1187
+ defineSymbol(math, bin, "\u22c8", "\\bowtie", true);
1188
+ defineSymbol(math, bin, "\u22c8", "\\Join");
1189
+ defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true);
1190
+ defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true);
1191
+ defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true);
1189
1192
 
1190
1193
  // AMS Arrows
1191
1194
  // Note: unicode-math maps \u21e2 to their own function \rightdasharrow.
@@ -1232,6 +1235,8 @@ defineSymbol(math, textord, "\u2018", "`");
1232
1235
  defineSymbol(math, textord, "$", "\\$");
1233
1236
  defineSymbol(text, textord, "$", "\\$");
1234
1237
  defineSymbol(text, textord, "$", "\\textdollar");
1238
+ defineSymbol(math, textord, "¢", "\\cent");
1239
+ defineSymbol(text, textord, "¢", "\\cent");
1235
1240
  defineSymbol(math, textord, "%", "\\%");
1236
1241
  defineSymbol(text, textord, "%", "\\%");
1237
1242
  defineSymbol(math, textord, "_", "\\_");
@@ -1888,7 +1893,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode, color) {
1888
1893
  }
1889
1894
 
1890
1895
  /**
1891
- * This file converts a parse tree into a cooresponding MathML tree. The main
1896
+ * This file converts a parse tree into a corresponding MathML tree. The main
1892
1897
  * entry point is the `buildMathML` function, which takes a parse tree from the
1893
1898
  * parser.
1894
1899
  */
@@ -3146,13 +3151,12 @@ defineFunction({
3146
3151
  names: ["\\\\"],
3147
3152
  props: {
3148
3153
  numArgs: 0,
3149
- numOptionalArgs: 1,
3150
- argTypes: ["size"],
3154
+ numOptionalArgs: 0,
3151
3155
  allowedInText: true
3152
3156
  },
3153
3157
 
3154
3158
  handler({ parser }, args, optArgs) {
3155
- const size = optArgs[0];
3159
+ const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null;
3156
3160
  const newLine = !parser.settings.displayMode;
3157
3161
  return {
3158
3162
  type: "cr",
@@ -3520,6 +3524,11 @@ const delimiters = [
3520
3524
  "."
3521
3525
  ];
3522
3526
 
3527
+ // Export isDelimiter for benefit of parser.
3528
+ const dels = ["}", "\\left", "\\middle", "\\right"];
3529
+ const isDelimiter = str => str.length > 0 &&
3530
+ (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
3531
+
3523
3532
  // Metrics of the different sizes. Found by looking at TeX's output of
3524
3533
  // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
3525
3534
  // Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
@@ -4912,7 +4921,6 @@ defineFunction({
4912
4921
  "\\mathscr",
4913
4922
  "\\mathsf",
4914
4923
  "\\mathtt",
4915
- "\\oldstylenums",
4916
4924
 
4917
4925
  // aliases
4918
4926
  "\\Bbb",
@@ -6203,10 +6211,6 @@ const noSuccessor = ["\\smallint"];
6203
6211
  // Math operators (e.g. \sin) need a space between these types and themselves:
6204
6212
  const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
6205
6213
 
6206
- const dels$1 = ["}", "\\left", "\\middle", "\\right"];
6207
- const isDelimiter$1 = str => str.length > 0 &&
6208
- (delimiters.includes(str) || delimiterSizes[str] || dels$1.includes(str));
6209
-
6210
6214
  // NOTE: Unlike most `builders`s, this one handles not only "op", but also
6211
6215
  // "supsub" since some of them (like \int) can affect super/subscripting.
6212
6216
 
@@ -6427,7 +6431,7 @@ defineFunction({
6427
6431
  parentIsSupSub: false,
6428
6432
  symbol: false,
6429
6433
  stack: false,
6430
- isFollowedByDelimiter: isDelimiter$1(next),
6434
+ isFollowedByDelimiter: isDelimiter(next),
6431
6435
  needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
6432
6436
  name: funcName
6433
6437
  };
@@ -6452,7 +6456,7 @@ defineFunction({
6452
6456
  parentIsSupSub: false,
6453
6457
  symbol: false,
6454
6458
  stack: false,
6455
- isFollowedByDelimiter: isDelimiter$1(next),
6459
+ isFollowedByDelimiter: isDelimiter(next),
6456
6460
  needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
6457
6461
  name: funcName
6458
6462
  };
@@ -6538,11 +6542,7 @@ function defineMacro(name, body) {
6538
6542
  _macros[name] = body;
6539
6543
  }
6540
6544
 
6541
- const dels = ["}", "\\left", "\\middle", "\\right"];
6542
- const isDelimiter = str => str.length > 0 &&
6543
- (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
6544
-
6545
- // NOTE: Unlike most builders, this one handles not only
6545
+ // NOTE: Unlike most builders, this one handles not only
6546
6546
  // "operatorname", but also "supsub" since \operatorname* can
6547
6547
  // affect super/subscripting.
6548
6548
 
@@ -6552,8 +6552,12 @@ const mathmlBuilder$1 = (group, style) => {
6552
6552
  // Is expression a string or has it something like a fraction?
6553
6553
  let isAllString = true; // default
6554
6554
  for (let i = 0; i < expression.length; i++) {
6555
- const node = expression[i];
6555
+ let node = expression[i];
6556
6556
  if (node instanceof mathMLTree.MathNode) {
6557
+ if (node.type === "mrow" && node.children.length === 1 &&
6558
+ node.children[0] instanceof mathMLTree.MathNode) {
6559
+ node = node.children[0];
6560
+ }
6557
6561
  switch (node.type) {
6558
6562
  case "mi":
6559
6563
  case "mn":
@@ -6611,7 +6615,9 @@ const mathmlBuilder$1 = (group, style) => {
6611
6615
  let wrapper;
6612
6616
  if (isAllString) {
6613
6617
  wrapper = new mathMLTree.MathNode("mi", expression);
6614
- wrapper.setAttribute("mathvariant", "normal");
6618
+ if (expression[0].text.length === 1) {
6619
+ wrapper.setAttribute("mathvariant", "normal");
6620
+ }
6615
6621
  } else {
6616
6622
  wrapper = new mathMLTree.MathNode("mrow", expression);
6617
6623
  }
@@ -7149,6 +7155,7 @@ defineFunctionBuilders({
7149
7155
  let isOver;
7150
7156
  let isSup;
7151
7157
  let appendApplyFunction = false;
7158
+ let appendSpace = false;
7152
7159
  let needsLeadingSpace = false;
7153
7160
 
7154
7161
  if (group.base && group.base.type === "horizBrace") {
@@ -7163,6 +7170,7 @@ defineFunctionBuilders({
7163
7170
  (group.base.type === "op" || group.base.type === "operatorname")) {
7164
7171
  group.base.parentIsSupSub = true;
7165
7172
  appendApplyFunction = !group.base.symbol;
7173
+ appendSpace = appendApplyFunction && !group.isFollowedByDelimiter;
7166
7174
  needsLeadingSpace = group.base.needsLeadingSpace;
7167
7175
  }
7168
7176
 
@@ -7250,6 +7258,11 @@ defineFunctionBuilders({
7250
7258
  } else {
7251
7259
  node = mathMLTree.newDocumentFragment([node, operator]);
7252
7260
  }
7261
+ if (appendSpace) {
7262
+ const space = new mathMLTree.MathNode("mspace");
7263
+ space.setAttribute("width", "0.1667em"); // thin space.
7264
+ node.children.push(space);
7265
+ }
7253
7266
  } else if (symbolRegEx.test(nodeType)) {
7254
7267
  // Wrap in a <mrow>. Otherwise Firefox stretchy parens will not stretch to include limits.
7255
7268
  node = new mathMLTree.MathNode("mrow", [node]);
@@ -7326,8 +7339,7 @@ const fontMap = {
7326
7339
  mathfrak: "fraktur",
7327
7340
  mathscr: "script",
7328
7341
  mathsf: "sans-serif",
7329
- mathtt: "monospace",
7330
- oldstylenums: "oldstylenums"
7342
+ mathtt: "monospace"
7331
7343
  };
7332
7344
 
7333
7345
  /**
@@ -7397,8 +7409,6 @@ const getVariant = function(group, style) {
7397
7409
  return "sans-serif"
7398
7410
  case "mathtt":
7399
7411
  return "monospace"
7400
- case "oldstylenums":
7401
- return "oldstylenums"
7402
7412
  }
7403
7413
 
7404
7414
  let text = group.text;
@@ -7694,10 +7704,7 @@ defineFunctionBuilders({
7694
7704
  let node;
7695
7705
  if (numberRegEx$1.test(group.text)) {
7696
7706
  const tag = group.mode === "text" ? "mtext" : "mn";
7697
- if (variant === "oldstylenums") {
7698
- const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]);
7699
- node = new mathMLTree.MathNode(tag, [ms]);
7700
- } else if (variant === "italic" || variant === "bold-italic") {
7707
+ if (variant === "italic" || variant === "bold-italic") {
7701
7708
  return italicNumber(text, variant, tag)
7702
7709
  } else {
7703
7710
  if (variant !== "normal") {
@@ -8888,7 +8895,7 @@ defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{
8888
8895
  defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}");
8889
8896
 
8890
8897
  /* eslint-disable */
8891
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
8898
+ /* -*- Mode: JavaScript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
8892
8899
  /* vim: set ts=2 et sw=2 tw=80: */
8893
8900
 
8894
8901
  /*************************************************************
@@ -10585,7 +10592,7 @@ defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap
10585
10592
  };
10586
10593
 
10587
10594
  //
10588
- // Helpers for code anaylsis
10595
+ // Helpers for code analysis
10589
10596
  // Will show type error at calling position
10590
10597
  //
10591
10598
  /** @param {number} a */
@@ -11010,15 +11017,15 @@ class MacroExpander {
11010
11017
  * Expand the next token only once if possible.
11011
11018
  *
11012
11019
  * If the token is expanded, the resulting tokens will be pushed onto
11013
- * the stack in reverse order and will be returned as an array,
11014
- * also in reverse order.
11020
+ * the stack in reverse order, and the number of such tokens will be
11021
+ * returned. This number might be zero or positive.
11015
11022
  *
11016
- * If not, the next token will be returned without removing it
11017
- * from the stack. This case can be detected by a `Token` return value
11018
- * instead of an `Array` return value.
11023
+ * If not, the return value is `false`, and the next token remains at the
11024
+ * top of the stack.
11019
11025
  *
11020
11026
  * In either case, the next token will be on the top of the stack,
11021
- * or the stack will be empty.
11027
+ * or the stack will be empty (in case of empty expansion
11028
+ * and no other tokens).
11022
11029
  *
11023
11030
  * Used to implement `expandAfterFuture` and `expandNextToken`.
11024
11031
  *
@@ -11034,7 +11041,7 @@ class MacroExpander {
11034
11041
  throw new ParseError("Undefined control sequence: " + name);
11035
11042
  }
11036
11043
  this.pushToken(topToken);
11037
- return topToken;
11044
+ return false;
11038
11045
  }
11039
11046
  this.expansionCount++;
11040
11047
  if (this.expansionCount > this.settings.maxExpand) {
@@ -11068,7 +11075,7 @@ class MacroExpander {
11068
11075
  }
11069
11076
  // Concatenate expansion onto top of stack.
11070
11077
  this.pushTokens(tokens);
11071
- return tokens;
11078
+ return tokens.length;
11072
11079
  }
11073
11080
 
11074
11081
  /**
@@ -11087,14 +11094,13 @@ class MacroExpander {
11087
11094
  */
11088
11095
  expandNextToken() {
11089
11096
  for (;;) {
11090
- const expanded = this.expandOnce();
11091
- // expandOnce returns Token if and only if it's fully expanded.
11092
- if (expanded instanceof Token) {
11097
+ if (this.expandOnce() === false) { // fully expanded
11098
+ const token = this.stack.pop();
11093
11099
  // The token after \noexpand is interpreted as if its meaning were ‘\relax’
11094
- if (expanded.treatAsRelax) {
11095
- expanded.text = "\\relax";
11100
+ if (token.treatAsRelax) {
11101
+ token.text = "\\relax";
11096
11102
  }
11097
- return this.stack.pop(); // === expanded
11103
+ return token
11098
11104
  }
11099
11105
  }
11100
11106
 
@@ -11120,15 +11126,15 @@ class MacroExpander {
11120
11126
  const oldStackLength = this.stack.length;
11121
11127
  this.pushTokens(tokens);
11122
11128
  while (this.stack.length > oldStackLength) {
11123
- const expanded = this.expandOnce(true); // expand only expandable tokens
11124
- // expandOnce returns Token if and only if it's fully expanded.
11125
- if (expanded instanceof Token) {
11126
- if (expanded.treatAsRelax) {
11129
+ // Expand only expandable tokens
11130
+ if (this.expandOnce(true) === false) { // fully expanded
11131
+ const token = this.stack.pop();
11132
+ if (token.treatAsRelax) {
11127
11133
  // the expansion of \noexpand is the token itself
11128
- expanded.noexpand = false;
11129
- expanded.treatAsRelax = false;
11134
+ token.noexpand = false;
11135
+ token.treatAsRelax = false;
11130
11136
  }
11131
- output.push(this.stack.pop());
11137
+ output.push(token);
11132
11138
  }
11133
11139
  }
11134
11140
  return output;
@@ -11428,6 +11434,36 @@ const uSubsAndSups = Object.freeze({
11428
11434
  '\u1DBF': 'θ'
11429
11435
  });
11430
11436
 
11437
+ // Used for Unicode input of calligraphic and script letters
11438
+ const asciiFromScript = Object.freeze({
11439
+ "\ud835\udc9c": "A",
11440
+ "\u212c": "B",
11441
+ "\ud835\udc9e": "C",
11442
+ "\ud835\udc9f": "D",
11443
+ "\u2130": "E",
11444
+ "\u2131": "F",
11445
+ "\ud835\udca2": "G",
11446
+ "\u210B": "H",
11447
+ "\u2110": "I",
11448
+ "\ud835\udca5": "J",
11449
+ "\ud835\udca6": "K",
11450
+ "\u2112": "L",
11451
+ "\u2113": "M",
11452
+ "\ud835\udca9": "N",
11453
+ "\ud835\udcaa": "O",
11454
+ "\ud835\udcab": "P",
11455
+ "\ud835\udcac": "Q",
11456
+ "\u211B": "R",
11457
+ "\ud835\udcae": "S",
11458
+ "\ud835\udcaf": "T",
11459
+ "\ud835\udcb0": "U",
11460
+ "\ud835\udcb1": "V",
11461
+ "\ud835\udcb2": "W",
11462
+ "\ud835\udcb3": "X",
11463
+ "\ud835\udcb4": "Y",
11464
+ "\ud835\udcb5": "Z"
11465
+ });
11466
+
11431
11467
  // Mapping of Unicode accent characters to their LaTeX equivalent in text and
11432
11468
  // math mode (when they exist).
11433
11469
  var unicodeAccents = {
@@ -11926,7 +11962,7 @@ class Parser {
11926
11962
  * Parses an "expression", which is a list of atoms.
11927
11963
  *
11928
11964
  * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
11929
- * happens when functions have higher precendence han infix
11965
+ * happens when functions have higher precedence han infix
11930
11966
  * nodes in implicit parses.
11931
11967
  *
11932
11968
  * `breakOnTokenText`: The text of the token that the expression should end
@@ -12177,12 +12213,16 @@ class Parser {
12177
12213
  return base
12178
12214
  } else {
12179
12215
  // We got either a superscript or subscript, create a supsub
12216
+ const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname")
12217
+ ? undefined
12218
+ : isDelimiter(this.nextToken.text);
12180
12219
  return {
12181
12220
  type: "supsub",
12182
12221
  mode: this.mode,
12183
12222
  base: base,
12184
12223
  sup: superscript,
12185
- sub: subscript
12224
+ sub: subscript,
12225
+ isFollowedByDelimiter
12186
12226
  }
12187
12227
  }
12188
12228
  } else {
@@ -12343,7 +12383,7 @@ class Parser {
12343
12383
  while (true) {
12344
12384
  const ch = this.fetch().text;
12345
12385
  // \ufe0e is the Unicode variation selector to supress emoji. Ignore it.
12346
- if (ch === " " || ch === "\ufe0e") {
12386
+ if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") {
12347
12387
  this.consume();
12348
12388
  } else {
12349
12389
  break
@@ -12663,6 +12703,22 @@ class Parser {
12663
12703
  text
12664
12704
  };
12665
12705
  } else {
12706
+ if (asciiFromScript[text]) {
12707
+ // Unicode 14 disambiguates chancery from roundhand.
12708
+ // See https://www.unicode.org/charts/PDF/U1D400.pdf
12709
+ this.consume();
12710
+ const nextCode = this.fetch().text.charCodeAt(0);
12711
+ // mathcal is Temml default. Use mathscript if called for.
12712
+ const font = nextCode === 0xfe01 ? "mathscr" : "mathcal";
12713
+ if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); }
12714
+ return {
12715
+ type: "font",
12716
+ mode: "math",
12717
+ font,
12718
+ body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] }
12719
+ }
12720
+ }
12721
+ // Default ord character. No disambiguation necessary.
12666
12722
  s = {
12667
12723
  type: group,
12668
12724
  mode: this.mode,
@@ -12919,7 +12975,7 @@ class Style {
12919
12975
  * https://mit-license.org/
12920
12976
  */
12921
12977
 
12922
- const version = "0.9.2";
12978
+ const version = "0.10.2";
12923
12979
 
12924
12980
  function postProcess(block) {
12925
12981
  const labelMap = {};
@@ -14,7 +14,7 @@
14
14
  * https://mit-license.org/
15
15
  */
16
16
 
17
- const version = "0.9.2";
17
+ const version = "0.10.2";
18
18
 
19
19
  function postProcess(block) {
20
20
  const labelMap = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temml",
3
- "version": "0.9.2",
3
+ "version": "0.10.2",
4
4
  "description": "TeX to MathML conversion in JavaScript.",
5
5
  "main": "dist/temml.js",
6
6
  "homepage": "https://temml.org",
@@ -8,6 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "git://github.com/ronkok/Temml"
10
10
  },
11
+ "packageManager": "yarn@3.3.1",
11
12
  "files": [
12
13
  "temml.js",
13
14
  "src/",
@@ -230,15 +230,15 @@ export default class MacroExpander {
230
230
  * Expand the next token only once if possible.
231
231
  *
232
232
  * If the token is expanded, the resulting tokens will be pushed onto
233
- * the stack in reverse order and will be returned as an array,
234
- * also in reverse order.
233
+ * the stack in reverse order, and the number of such tokens will be
234
+ * returned. This number might be zero or positive.
235
235
  *
236
- * If not, the next token will be returned without removing it
237
- * from the stack. This case can be detected by a `Token` return value
238
- * instead of an `Array` return value.
236
+ * If not, the return value is `false`, and the next token remains at the
237
+ * top of the stack.
239
238
  *
240
239
  * In either case, the next token will be on the top of the stack,
241
- * or the stack will be empty.
240
+ * or the stack will be empty (in case of empty expansion
241
+ * and no other tokens).
242
242
  *
243
243
  * Used to implement `expandAfterFuture` and `expandNextToken`.
244
244
  *
@@ -254,7 +254,7 @@ export default class MacroExpander {
254
254
  throw new ParseError("Undefined control sequence: " + name);
255
255
  }
256
256
  this.pushToken(topToken);
257
- return topToken;
257
+ return false;
258
258
  }
259
259
  this.expansionCount++;
260
260
  if (this.expansionCount > this.settings.maxExpand) {
@@ -288,7 +288,7 @@ export default class MacroExpander {
288
288
  }
289
289
  // Concatenate expansion onto top of stack.
290
290
  this.pushTokens(tokens);
291
- return tokens;
291
+ return tokens.length;
292
292
  }
293
293
 
294
294
  /**
@@ -307,14 +307,13 @@ export default class MacroExpander {
307
307
  */
308
308
  expandNextToken() {
309
309
  for (;;) {
310
- const expanded = this.expandOnce();
311
- // expandOnce returns Token if and only if it's fully expanded.
312
- if (expanded instanceof Token) {
310
+ if (this.expandOnce() === false) { // fully expanded
311
+ const token = this.stack.pop();
313
312
  // The token after \noexpand is interpreted as if its meaning were ‘\relax’
314
- if (expanded.treatAsRelax) {
315
- expanded.text = "\\relax"
313
+ if (token.treatAsRelax) {
314
+ token.text = "\\relax"
316
315
  }
317
- return this.stack.pop(); // === expanded
316
+ return token
318
317
  }
319
318
  }
320
319
 
@@ -340,15 +339,15 @@ export default class MacroExpander {
340
339
  const oldStackLength = this.stack.length;
341
340
  this.pushTokens(tokens);
342
341
  while (this.stack.length > oldStackLength) {
343
- const expanded = this.expandOnce(true); // expand only expandable tokens
344
- // expandOnce returns Token if and only if it's fully expanded.
345
- if (expanded instanceof Token) {
346
- if (expanded.treatAsRelax) {
342
+ // Expand only expandable tokens
343
+ if (this.expandOnce(true) === false) { // fully expanded
344
+ const token = this.stack.pop();
345
+ if (token.treatAsRelax) {
347
346
  // the expansion of \noexpand is the token itself
348
- expanded.noexpand = false;
349
- expanded.treatAsRelax = false;
347
+ token.noexpand = false;
348
+ token.treatAsRelax = false;
350
349
  }
351
- output.push(this.stack.pop());
350
+ output.push(token);
352
351
  }
353
352
  }
354
353
  return output;
package/src/Parser.js CHANGED
@@ -7,8 +7,10 @@ import { supportedCodepoint } from "./unicodeScripts";
7
7
  import ParseError from "./ParseError";
8
8
  import { combiningDiacriticalMarksEndRegex } from "./Lexer";
9
9
  import { uSubsAndSups, unicodeSubRegEx } from "./unicodeSupOrSub"
10
+ import { asciiFromScript } from "./asciiFromScript"
10
11
  import SourceLocation from "./SourceLocation";
11
12
  import { Token } from "./Token";
13
+ import { isDelimiter } from "./functions/delimsizing"
12
14
 
13
15
  // Pre-evaluate both modules as unicodeSymbols require String.normalize()
14
16
  import unicodeAccents from /*preval*/ "./unicodeAccents";
@@ -172,7 +174,7 @@ export default class Parser {
172
174
  * Parses an "expression", which is a list of atoms.
173
175
  *
174
176
  * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
175
- * happens when functions have higher precendence han infix
177
+ * happens when functions have higher precedence han infix
176
178
  * nodes in implicit parses.
177
179
  *
178
180
  * `breakOnTokenText`: The text of the token that the expression should end
@@ -423,12 +425,16 @@ export default class Parser {
423
425
  return base
424
426
  } else {
425
427
  // We got either a superscript or subscript, create a supsub
428
+ const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname")
429
+ ? undefined
430
+ : isDelimiter(this.nextToken.text);
426
431
  return {
427
432
  type: "supsub",
428
433
  mode: this.mode,
429
434
  base: base,
430
435
  sup: superscript,
431
- sub: subscript
436
+ sub: subscript,
437
+ isFollowedByDelimiter
432
438
  }
433
439
  }
434
440
  } else {
@@ -589,7 +595,7 @@ export default class Parser {
589
595
  while (true) {
590
596
  const ch = this.fetch().text
591
597
  // \ufe0e is the Unicode variation selector to supress emoji. Ignore it.
592
- if (ch === " " || ch === "\ufe0e") {
598
+ if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") {
593
599
  this.consume()
594
600
  } else {
595
601
  break
@@ -909,6 +915,22 @@ export default class Parser {
909
915
  text
910
916
  };
911
917
  } else {
918
+ if (asciiFromScript[text]) {
919
+ // Unicode 14 disambiguates chancery from roundhand.
920
+ // See https://www.unicode.org/charts/PDF/U1D400.pdf
921
+ this.consume()
922
+ const nextCode = this.fetch().text.charCodeAt(0)
923
+ // mathcal is Temml default. Use mathscript if called for.
924
+ const font = nextCode === 0xfe01 ? "mathscr" : "mathcal";
925
+ if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume() }
926
+ return {
927
+ type: "font",
928
+ mode: "math",
929
+ font,
930
+ body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] }
931
+ }
932
+ }
933
+ // Default ord character. No disambiguation necessary.
912
934
  s = {
913
935
  type: group,
914
936
  mode: this.mode,
@@ -0,0 +1,29 @@
1
+ // Used for Unicode input of calligraphic and script letters
2
+ export const asciiFromScript = Object.freeze({
3
+ "\ud835\udc9c": "A",
4
+ "\u212c": "B",
5
+ "\ud835\udc9e": "C",
6
+ "\ud835\udc9f": "D",
7
+ "\u2130": "E",
8
+ "\u2131": "F",
9
+ "\ud835\udca2": "G",
10
+ "\u210B": "H",
11
+ "\u2110": "I",
12
+ "\ud835\udca5": "J",
13
+ "\ud835\udca6": "K",
14
+ "\u2112": "L",
15
+ "\u2113": "M",
16
+ "\ud835\udca9": "N",
17
+ "\ud835\udcaa": "O",
18
+ "\ud835\udcab": "P",
19
+ "\ud835\udcac": "Q",
20
+ "\u211B": "R",
21
+ "\ud835\udcae": "S",
22
+ "\ud835\udcaf": "T",
23
+ "\ud835\udcb0": "U",
24
+ "\ud835\udcb1": "V",
25
+ "\ud835\udcb2": "W",
26
+ "\ud835\udcb3": "X",
27
+ "\ud835\udcb4": "Y",
28
+ "\ud835\udcb5": "Z"
29
+ })
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file converts a parse tree into a cooresponding MathML tree. The main
2
+ * This file converts a parse tree into a corresponding MathML tree. The main
3
3
  * entry point is the `buildMathML` function, which takes a parse tree from the
4
4
  * parser.
5
5
  */
@@ -11,13 +11,12 @@ defineFunction({
11
11
  names: ["\\\\"],
12
12
  props: {
13
13
  numArgs: 0,
14
- numOptionalArgs: 1,
15
- argTypes: ["size"],
14
+ numOptionalArgs: 0,
16
15
  allowedInText: true
17
16
  },
18
17
 
19
18
  handler({ parser }, args, optArgs) {
20
- const size = optArgs[0];
19
+ const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null;
21
20
  const newLine = !parser.settings.displayMode;
22
21
  return {
23
22
  type: "cr",
@@ -89,6 +89,11 @@ export const delimiters = [
89
89
  "."
90
90
  ];
91
91
 
92
+ // Export isDelimiter for benefit of parser.
93
+ const dels = ["}", "\\left", "\\middle", "\\right"]
94
+ export const isDelimiter = str => str.length > 0 &&
95
+ (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str))
96
+
92
97
  // Metrics of the different sizes. Found by looking at TeX's output of
93
98
  // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
94
99
  // Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
@@ -67,7 +67,6 @@ defineFunction({
67
67
  "\\mathscr",
68
68
  "\\mathsf",
69
69
  "\\mathtt",
70
- "\\oldstylenums",
71
70
 
72
71
  // aliases
73
72
  "\\Bbb",