Diff: STRATO-apps/wordpress_03/app/wp-includes/js/dist/latex-to-mathml.js

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + /******/ (() => { // webpackBootstrap
2 + /******/ "use strict";
3 + /******/ // The require scope
4 + /******/ var __webpack_require__ = {};
5 + /******/
6 + /************************************************************************/
7 + /******/ /* webpack/runtime/define property getters */
8 + /******/ (() => {
9 + /******/ // define getter functions for harmony exports
10 + /******/ __webpack_require__.d = (exports, definition) => {
11 + /******/ for(var key in definition) {
12 + /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13 + /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14 + /******/ }
15 + /******/ }
16 + /******/ };
17 + /******/ })();
18 + /******/
19 + /******/ /* webpack/runtime/hasOwnProperty shorthand */
20 + /******/ (() => {
21 + /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
22 + /******/ })();
23 + /******/
24 + /******/ /* webpack/runtime/make namespace object */
25 + /******/ (() => {
26 + /******/ // define __esModule on exports
27 + /******/ __webpack_require__.r = (exports) => {
28 + /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
29 + /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30 + /******/ }
31 + /******/ Object.defineProperty(exports, '__esModule', { value: true });
32 + /******/ };
33 + /******/ })();
34 + /******/
35 + /************************************************************************/
36 + var __webpack_exports__ = {};
37 + // ESM COMPAT FLAG
38 + __webpack_require__.r(__webpack_exports__);
39 +
40 + // EXPORTS
41 + __webpack_require__.d(__webpack_exports__, {
42 + "default": () => (/* binding */ latexToMathML)
43 + });
44 +
45 + ;// ./node_modules/temml/dist/temml.mjs
46 + /**
47 + * This is the ParseError class, which is the main error thrown by Temml
48 + * functions when something has gone wrong. This is used to distinguish internal
49 + * errors from errors in the expression that the user provided.
50 + *
51 + * If possible, a caller should provide a Token or ParseNode with information
52 + * about where in the source string the problem occurred.
53 + */
54 + class ParseError {
55 + constructor(
56 + message, // The error message
57 + token // An object providing position information
58 + ) {
59 + let error = " " + message;
60 + let start;
61 +
62 + const loc = token && token.loc;
63 + if (loc && loc.start <= loc.end) {
64 + // If we have the input and a position, make the error a bit fancier
65 +
66 + // Get the input
67 + const input = loc.lexer.input;
68 +
69 + // Prepend some information
70 + start = loc.start;
71 + const end = loc.end;
72 + if (start === input.length) {
73 + error += " at end of input: ";
74 + } else {
75 + error += " at position " + (start + 1) + ": ";
76 + }
77 +
78 + // Underline token in question using combining underscores
79 + const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
80 +
81 + // Extract some context from the input and add it to the error
82 + let left;
83 + if (start > 15) {
84 + left = "…" + input.slice(start - 15, start);
85 + } else {
86 + left = input.slice(0, start);
87 + }
88 + let right;
89 + if (end + 15 < input.length) {
90 + right = input.slice(end, end + 15) + "…";
91 + } else {
92 + right = input.slice(end);
93 + }
94 + error += left + underlined + right;
95 + }
96 +
97 + // Some hackery to make ParseError a prototype of Error
98 + // See http://stackoverflow.com/a/8460753
99 + const self = new Error(error);
100 + self.name = "ParseError";
101 + self.__proto__ = ParseError.prototype;
102 + self.position = start;
103 + return self;
104 + }
105 + }
106 +
107 + ParseError.prototype.__proto__ = Error.prototype;
108 +
109 + //
110 + /**
111 + * This file contains a list of utility functions which are useful in other
112 + * files.
113 + */
114 +
115 + /**
116 + * Provide a default value if a setting is undefined
117 + */
118 + const deflt = function(setting, defaultIfUndefined) {
119 + return setting === undefined ? defaultIfUndefined : setting;
120 + };
121 +
122 + // hyphenate and escape adapted from Facebook's React under Apache 2 license
123 +
124 + const uppercase = /([A-Z])/g;
125 + const hyphenate = function(str) {
126 + return str.replace(uppercase, "-$1").toLowerCase();
127 + };
128 +
129 + const ESCAPE_LOOKUP = {
130 + "&": "&amp;",
131 + ">": "&gt;",
132 + "<": "&lt;",
133 + '"': "&quot;",
134 + "'": "&#x27;"
135 + };
136 +
137 + const ESCAPE_REGEX = /[&><"']/g;
138 +
139 + /**
140 + * Escapes text to prevent scripting attacks.
141 + */
142 + function temml_escape(text) {
143 + return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
144 + }
145 +
146 + /**
147 + * Sometimes we want to pull out the innermost element of a group. In most
148 + * cases, this will just be the group itself, but when ordgroups and colors have
149 + * a single element, we want to pull that out.
150 + */
151 + const getBaseElem = function(group) {
152 + if (group.type === "ordgroup") {
153 + if (group.body.length === 1) {
154 + return getBaseElem(group.body[0]);
155 + } else {
156 + return group;
157 + }
158 + } else if (group.type === "color") {
159 + if (group.body.length === 1) {
160 + return getBaseElem(group.body[0]);
161 + } else {
162 + return group;
163 + }
164 + } else if (group.type === "font") {
165 + return getBaseElem(group.body);
166 + } else {
167 + return group;
168 + }
169 + };
170 +
171 + /**
172 + * TeXbook algorithms often reference "character boxes", which are simply groups
173 + * with a single character in them. To decide if something is a character box,
174 + * we find its innermost group, and see if it is a single character.
175 + */
176 + const isCharacterBox = function(group) {
177 + const baseElem = getBaseElem(group);
178 +
179 + // These are all the types of groups which hold single characters
180 + return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom"
181 + };
182 +
183 + const assert = function(value) {
184 + if (!value) {
185 + throw new Error("Expected non-null, but got " + String(value));
186 + }
187 + return value;
188 + };
189 +
190 + /**
191 + * Return the protocol of a URL, or "_relative" if the URL does not specify a
192 + * protocol (and thus is relative), or `null` if URL has invalid protocol
193 + * (so should be outright rejected).
194 + */
195 + const protocolFromUrl = function(url) {
196 + // Check for possible leading protocol.
197 + // https://url.spec.whatwg.org/#url-parsing strips leading whitespace
198 + // (\x00) or C0 control (\x00-\x1F) characters.
199 + // eslint-disable-next-line no-control-regex
200 + const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|&#0*58|&#x0*3a|&colon)/i.exec(url);
201 + if (!protocol) {
202 + return "_relative";
203 + }
204 + // Reject weird colons
205 + if (protocol[2] !== ":") {
206 + return null;
207 + }
208 + // Reject invalid characters in scheme according to
209 + // https://datatracker.ietf.org/doc/html/rfc3986#section-3.1
210 + if (!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol[1])) {
211 + return null;
212 + }
213 + // Lowercase the protocol
214 + return protocol[1].toLowerCase();
215 + };
216 +
217 + /**
218 + * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook
219 + * gives an acceptable rounding error of 100sp (which would be the nearest
220 + * 1/6551.6em with our ptPerEm = 10):
221 + * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69
222 + */
223 + const round = function(n) {
224 + return +n.toFixed(4);
225 + };
226 +
227 + var utils = {
228 + deflt,
229 + escape: temml_escape,
230 + hyphenate,
231 + getBaseElem,
232 + isCharacterBox,
233 + protocolFromUrl,
234 + round
235 + };
236 +
237 + /**
238 + * This is a module for storing settings passed into Temml. It correctly handles
239 + * default settings.
240 + */
241 +
242 +
243 + /**
244 + * The main Settings object
245 + */
246 + class Settings {
247 + constructor(options) {
248 + // allow null options
249 + options = options || {};
250 + this.displayMode = utils.deflt(options.displayMode, false); // boolean
251 + this.annotate = utils.deflt(options.annotate, false); // boolean
252 + this.leqno = utils.deflt(options.leqno, false); // boolean
253 + this.throwOnError = utils.deflt(options.throwOnError, false); // boolean
254 + this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string
255 + this.macros = options.macros || {};
256 + this.wrap = utils.deflt(options.wrap, "tex"); // "tex" | "="
257 + this.xml = utils.deflt(options.xml, false); // boolean
258 + this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean
259 + this.strict = utils.deflt(options.strict, false); // boolean
260 + this.trust = utils.deflt(options.trust, false); // trust context. See html.js.
261 + this.maxSize = (options.maxSize === undefined
262 + ? [Infinity, Infinity]
263 + : Array.isArray(options.maxSize)
264 + ? options.maxSize
265 + : [Infinity, Infinity]
266 + );
267 + this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number
268 + }
269 +
270 + /**
271 + * Check whether to test potentially dangerous input, and return
272 + * `true` (trusted) or `false` (untrusted). The sole argument `context`
273 + * should be an object with `command` field specifying the relevant LaTeX
274 + * command (as a string starting with `\`), and any other arguments, etc.
275 + * If `context` has a `url` field, a `protocol` field will automatically
276 + * get added by this function (changing the specified object).
277 + */
278 + isTrusted(context) {
279 + if (context.url && !context.protocol) {
280 + const protocol = utils.protocolFromUrl(context.url);
281 + if (protocol == null) {
282 + return false
283 + }
284 + context.protocol = protocol;
285 + }
286 + const trust = typeof this.trust === "function" ? this.trust(context) : this.trust;
287 + return Boolean(trust);
288 + }
289 + }
290 +
291 + /**
292 + * All registered functions.
293 + * `functions.js` just exports this same dictionary again and makes it public.
294 + * `Parser.js` requires this dictionary.
295 + */
296 + const _functions = {};
297 +
298 + /**
299 + * All MathML builders. Should be only used in the `define*` and the `build*ML`
300 + * functions.
301 + */
302 + const _mathmlGroupBuilders = {};
303 +
304 + function defineFunction({
305 + type,
306 + names,
307 + props,
308 + handler,
309 + mathmlBuilder
310 + }) {
311 + // Set default values of functions
312 + const data = {
313 + type,
314 + numArgs: props.numArgs,
315 + argTypes: props.argTypes,
316 + allowedInArgument: !!props.allowedInArgument,
317 + allowedInText: !!props.allowedInText,
318 + allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath,
319 + numOptionalArgs: props.numOptionalArgs || 0,
320 + infix: !!props.infix,
321 + primitive: !!props.primitive,
322 + handler: handler
323 + };
324 + for (let i = 0; i < names.length; ++i) {
325 + _functions[names[i]] = data;
326 + }
327 + if (type) {
328 + if (mathmlBuilder) {
329 + _mathmlGroupBuilders[type] = mathmlBuilder;
330 + }
331 + }
332 + }
333 +
334 + /**
335 + * Use this to register only the MathML builder for a function(e.g.
336 + * if the function's ParseNode is generated in Parser.js rather than via a
337 + * stand-alone handler provided to `defineFunction`).
338 + */
339 + function defineFunctionBuilders({ type, mathmlBuilder }) {
340 + defineFunction({
341 + type,
342 + names: [],
343 + props: { numArgs: 0 },
344 + handler() {
345 + throw new Error("Should never be called.")
346 + },
347 + mathmlBuilder
348 + });
349 + }
350 +
351 + const normalizeArgument = function(arg) {
352 + return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg
353 + };
354 +
355 + // Since the corresponding buildMathML function expects a
356 + // list of elements, we normalize for different kinds of arguments
357 + const ordargument = function(arg) {
358 + return arg.type === "ordgroup" ? arg.body : [arg]
359 + };
360 +
361 + /**
362 + * This node represents a document fragment, which contains elements, but when
363 + * placed into the DOM doesn't have any representation itself. It only contains
364 + * children and doesn't have any DOM node properties.
365 + */
366 + class DocumentFragment {
367 + constructor(children) {
368 + this.children = children;
369 + this.classes = [];
370 + this.style = {};
371 + }
372 +
373 + hasClass(className) {
374 + return this.classes.includes(className);
375 + }
376 +
377 + /** Convert the fragment into a node. */
378 + toNode() {
379 + const frag = document.createDocumentFragment();
380 +
381 + for (let i = 0; i < this.children.length; i++) {
382 + frag.appendChild(this.children[i].toNode());
383 + }
384 +
385 + return frag;
386 + }
387 +
388 + /** Convert the fragment into HTML markup. */
389 + toMarkup() {
390 + let markup = "";
391 +
392 + // Simply concatenate the markup for the children together.
393 + for (let i = 0; i < this.children.length; i++) {
394 + markup += this.children[i].toMarkup();
395 + }
396 +
397 + return markup;
398 + }
399 +
400 + /**
401 + * Converts the math node into a string, similar to innerText. Applies to
402 + * MathDomNode's only.
403 + */
404 + toText() {
405 + // To avoid this, we would subclass documentFragment separately for
406 + // MathML, but polyfills for subclassing is expensive per PR 1469.
407 + const toText = (child) => child.toText();
408 + return this.children.map(toText).join("");
409 + }
410 + }
411 +
412 + /**
413 + * These objects store the data about the DOM nodes we create, as well as some
414 + * extra data. They can then be transformed into real DOM nodes with the
415 + * `toNode` function or HTML markup using `toMarkup`. They are useful for both
416 + * storing extra properties on the nodes, as well as providing a way to easily
417 + * work with the DOM.
418 + *
419 + * Similar functions for working with MathML nodes exist in mathMLTree.js.
420 + *
421 + */
422 +
423 + /**
424 + * Create an HTML className based on a list of classes. In addition to joining
425 + * with spaces, we also remove empty classes.
426 + */
427 + const createClass = function(classes) {
428 + return classes.filter((cls) => cls).join(" ");
429 + };
430 +
431 + const initNode = function(classes, style) {
432 + this.classes = classes || [];
433 + this.attributes = {};
434 + this.style = style || {};
435 + };
436 +
437 + /**
438 + * Convert into an HTML node
439 + */
440 + const toNode = function(tagName) {
441 + const node = document.createElement(tagName);
442 +
443 + // Apply the class
444 + node.className = createClass(this.classes);
445 +
446 + // Apply inline styles
447 + for (const style in this.style) {
448 + if (Object.prototype.hasOwnProperty.call(this.style, style )) {
449 + node.style[style] = this.style[style];
450 + }
451 + }
452 +
453 + // Apply attributes
454 + for (const attr in this.attributes) {
455 + if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) {
456 + node.setAttribute(attr, this.attributes[attr]);
457 + }
458 + }
459 +
460 + // Append the children, also as HTML nodes
461 + for (let i = 0; i < this.children.length; i++) {
462 + node.appendChild(this.children[i].toNode());
463 + }
464 +
465 + return node;
466 + };
467 +
468 + /**
469 + * Convert into an HTML markup string
470 + */
471 + const toMarkup = function(tagName) {
472 + let markup = `<${tagName}`;
473 +
474 + // Add the class
475 + if (this.classes.length) {
476 + markup += ` class="${utils.escape(createClass(this.classes))}"`;
477 + }
478 +
479 + let styles = "";
480 +
481 + // Add the styles, after hyphenation
482 + for (const style in this.style) {
483 + if (Object.prototype.hasOwnProperty.call(this.style, style )) {
484 + styles += `${utils.hyphenate(style)}:${this.style[style]};`;
485 + }
486 + }
487 +
488 + if (styles) {
489 + markup += ` style="${styles}"`;
490 + }
491 +
492 + // Add the attributes
493 + for (const attr in this.attributes) {
494 + if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) {
495 + markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`;
496 + }
497 + }
498 +
499 + markup += ">";
500 +
501 + // Add the markup of the children, also as markup
502 + for (let i = 0; i < this.children.length; i++) {
503 + markup += this.children[i].toMarkup();
504 + }
505 +
506 + markup += `</${tagName}>`;
507 +
508 + return markup;
509 + };
510 +
511 + /**
512 + * This node represents a span node, with a className, a list of children, and
513 + * an inline style.
514 + *
515 + */
516 + class Span {
517 + constructor(classes, children, style) {
518 + initNode.call(this, classes, style);
519 + this.children = children || [];
520 + }
521 +
522 + setAttribute(attribute, value) {
523 + this.attributes[attribute] = value;
524 + }
525 +
526 + toNode() {
527 + return toNode.call(this, "span");
528 + }
529 +
530 + toMarkup() {
531 + return toMarkup.call(this, "span");
532 + }
533 + }
534 +
535 + let TextNode$1 = class TextNode {
536 + constructor(text) {
537 + this.text = text;
538 + }
539 + toNode() {
540 + return document.createTextNode(this.text);
541 + }
542 + toMarkup() {
543 + return utils.escape(this.text);
544 + }
545 + };
546 +
547 + // Create an <a href="…"> node.
548 + class AnchorNode {
549 + constructor(href, classes, children) {
550 + this.href = href;
551 + this.classes = classes;
552 + this.children = children || [];
553 + }
554 +
555 + toNode() {
556 + const node = document.createElement("a");
557 + node.setAttribute("href", this.href);
558 + if (this.classes.length > 0) {
559 + node.className = createClass(this.classes);
560 + }
561 + for (let i = 0; i < this.children.length; i++) {
562 + node.appendChild(this.children[i].toNode());
563 + }
564 + return node
565 + }
566 +
567 + toMarkup() {
568 + let markup = `<a href='${utils.escape(this.href)}'`;
569 + if (this.classes.length > 0) {
570 + markup += ` class="${utils.escape(createClass(this.classes))}"`;
571 + }
572 + markup += ">";
573 + for (let i = 0; i < this.children.length; i++) {
574 + markup += this.children[i].toMarkup();
575 + }
576 + markup += "</a>";
577 + return markup
578 + }
579 + }
580 +
581 + /*
582 + * This node represents an image embed (<img>) element.
583 + */
584 + class Img {
585 + constructor(src, alt, style) {
586 + this.alt = alt;
587 + this.src = src;
588 + this.classes = ["mord"];
589 + this.style = style;
590 + }
591 +
592 + hasClass(className) {
593 + return this.classes.includes(className);
594 + }
595 +
596 + toNode() {
597 + const node = document.createElement("img");
598 + node.src = this.src;
599 + node.alt = this.alt;
600 + node.className = "mord";
601 +
602 + // Apply inline styles
603 + for (const style in this.style) {
604 + if (Object.prototype.hasOwnProperty.call(this.style, style )) {
605 + node.style[style] = this.style[style];
606 + }
607 + }
608 +
609 + return node;
610 + }
611 +
612 + toMarkup() {
613 + let markup = `<img src='${this.src}' alt='${this.alt}'`;
614 +
615 + // Add the styles, after hyphenation
616 + let styles = "";
617 + for (const style in this.style) {
618 + if (Object.prototype.hasOwnProperty.call(this.style, style )) {
619 + styles += `${utils.hyphenate(style)}:${this.style[style]};`;
620 + }
621 + }
622 + if (styles) {
623 + markup += ` style="${utils.escape(styles)}"`;
624 + }
625 +
626 + markup += ">";
627 + return markup;
628 + }
629 + }
630 +
631 + //
632 + /**
633 + * These objects store data about MathML nodes.
634 + * The `toNode` and `toMarkup` functions create namespaced DOM nodes and
635 + * HTML text markup respectively.
636 + */
637 +
638 +
639 + function newDocumentFragment(children) {
640 + return new DocumentFragment(children);
641 + }
642 +
643 + /**
644 + * This node represents a general purpose MathML node of any type,
645 + * for example, `"mo"` or `"mspace"`, corresponding to `<mo>` and
646 + * `<mspace>` tags).
647 + */
648 + class MathNode {
649 + constructor(type, children, classes, style) {
650 + this.type = type;
651 + this.attributes = {};
652 + this.children = children || [];
653 + this.classes = classes || [];
654 + this.style = style || {}; // Used for <mstyle> elements
655 + this.label = "";
656 + }
657 +
658 + /**
659 + * Sets an attribute on a MathML node. MathML depends on attributes to convey a
660 + * semantic content, so this is used heavily.
661 + */
662 + setAttribute(name, value) {
663 + this.attributes[name] = value;
664 + }
665 +
666 + /**
667 + * Gets an attribute on a MathML node.
668 + */
669 + getAttribute(name) {
670 + return this.attributes[name];
671 + }
672 +
673 + setLabel(value) {
674 + this.label = value;
675 + }
676 +
677 + /**
678 + * Converts the math node into a MathML-namespaced DOM element.
679 + */
680 + toNode() {
681 + const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type);
682 +
683 + for (const attr in this.attributes) {
684 + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
685 + node.setAttribute(attr, this.attributes[attr]);
686 + }
687 + }
688 +
689 + if (this.classes.length > 0) {
690 + node.className = createClass(this.classes);
691 + }
692 +
693 + // Apply inline styles
694 + for (const style in this.style) {
695 + if (Object.prototype.hasOwnProperty.call(this.style, style )) {
696 + node.style[style] = this.style[style];
697 + }
698 + }
699 +
700 + for (let i = 0; i < this.children.length; i++) {
701 + node.appendChild(this.children[i].toNode());
702 + }
703 +
704 + return node;
705 + }
706 +
707 + /**
708 + * Converts the math node into an HTML markup string.
709 + */
710 + toMarkup() {
711 + let markup = "<" + this.type;
712 +
713 + // Add the attributes
714 + for (const attr in this.attributes) {
715 + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
716 + markup += " " + attr + '="';
717 + markup += utils.escape(this.attributes[attr]);
718 + markup += '"';
719 + }
720 + }
721 +
722 + if (this.classes.length > 0) {
723 + markup += ` class="${utils.escape(createClass(this.classes))}"`;
724 + }
725 +
726 + let styles = "";
727 +
728 + // Add the styles, after hyphenation
729 + for (const style in this.style) {
730 + if (Object.prototype.hasOwnProperty.call(this.style, style )) {
731 + styles += `${utils.hyphenate(style)}:${this.style[style]};`;
732 + }
733 + }
734 +
735 + if (styles) {
736 + markup += ` style="${styles}"`;
737 + }
738 +
739 + markup += ">";
740 +
741 + for (let i = 0; i < this.children.length; i++) {
742 + markup += this.children[i].toMarkup();
743 + }
744 +
745 + markup += "</" + this.type + ">";
746 +
747 + return markup;
748 + }
749 +
750 + /**
751 + * Converts the math node into a string, similar to innerText, but escaped.
752 + */
753 + toText() {
754 + return this.children.map((child) => child.toText()).join("");
755 + }
756 + }
757 +
758 + /**
759 + * This node represents a piece of text.
760 + */
761 + class TextNode {
762 + constructor(text) {
763 + this.text = text;
764 + }
765 +
766 + /**
767 + * Converts the text node into a DOM text node.
768 + */
769 + toNode() {
770 + return document.createTextNode(this.text);
771 + }
772 +
773 + /**
774 + * Converts the text node into escaped HTML markup
775 + * (representing the text itself).
776 + */
777 + toMarkup() {
778 + return utils.escape(this.toText());
779 + }
780 +
781 + /**
782 + * Converts the text node into a string
783 + * (representing the text itself).
784 + */
785 + toText() {
786 + return this.text;
787 + }
788 + }
789 +
790 + // Do not make an <mrow> the only child of a <mstyle>.
791 + // An <mstyle> acts as its own implicit <mrow>.
792 + const wrapWithMstyle = expression => {
793 + let node;
794 + if (expression.length === 1 && expression[0].type === "mrow") {
795 + node = expression.pop();
796 + node.type = "mstyle";
797 + } else {
798 + node = new MathNode("mstyle", expression);
799 + }
800 + return node
801 + };
802 +
803 + var mathMLTree = {
804 + MathNode,
805 + TextNode,
806 + newDocumentFragment
807 + };
808 +
809 + /**
810 + * This file provides support for building horizontal stretchy elements.
811 + */
812 +
813 +
814 + // TODO: Remove when Chromium stretches \widetilde & \widehat
815 + const estimatedWidth = node => {
816 + let width = 0;
817 + if (node.body) {
818 + for (const item of node.body) {
819 + width += estimatedWidth(item);
820 + }
821 + } else if (node.type === "supsub") {
822 + width += estimatedWidth(node.base);
823 + if (node.sub) { width += 0.7 * estimatedWidth(node.sub); }
824 + if (node.sup) { width += 0.7 * estimatedWidth(node.sup); }
825 + } else if (node.type === "mathord" || node.type === "textord") {
826 + for (const ch of node.text.split('')) {
827 + const codePoint = ch.codePointAt(0);
828 + if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) {
829 + width += 0.56; // lower case latin or greek. Use advance width of letter n
830 + } else if (0x2F < codePoint && codePoint < 0x3A) {
831 + width += 0.50; // numerals.
832 + } else {
833 + width += 0.92; // advance width of letter M
834 + }
835 + }
836 + } else {
837 + width += 1.0;
838 + }
839 + return width
840 + };
841 +
842 + const stretchyCodePoint = {
843 + widehat: "^",
844 + widecheck: "ˇ",
845 + widetilde: "~",
846 + wideparen: "⏜", // \u23dc
847 + utilde: "~",
848 + overleftarrow: "\u2190",
849 + underleftarrow: "\u2190",
850 + xleftarrow: "\u2190",
851 + overrightarrow: "\u2192",
852 + underrightarrow: "\u2192",
853 + xrightarrow: "\u2192",
854 + underbrace: "\u23df",
855 + overbrace: "\u23de",
856 + overgroup: "\u23e0",
857 + overparen: "⏜",
858 + undergroup: "\u23e1",
859 + underparen: "\u23dd",
860 + overleftrightarrow: "\u2194",
861 + underleftrightarrow: "\u2194",
862 + xleftrightarrow: "\u2194",
863 + Overrightarrow: "\u21d2",
864 + xRightarrow: "\u21d2",
865 + overleftharpoon: "\u21bc",
866 + xleftharpoonup: "\u21bc",
867 + overrightharpoon: "\u21c0",
868 + xrightharpoonup: "\u21c0",
869 + xLeftarrow: "\u21d0",
870 + xLeftrightarrow: "\u21d4",
871 + xhookleftarrow: "\u21a9",
872 + xhookrightarrow: "\u21aa",
873 + xmapsto: "\u21a6",
874 + xrightharpoondown: "\u21c1",
875 + xleftharpoondown: "\u21bd",
876 + xtwoheadleftarrow: "\u219e",
877 + xtwoheadrightarrow: "\u21a0",
878 + xlongequal: "=",
879 + xrightleftarrows: "\u21c4",
880 + yields: "\u2192",
881 + yieldsLeft: "\u2190",
882 + mesomerism: "\u2194",
883 + longrightharpoonup: "\u21c0",
884 + longleftharpoondown: "\u21bd",
885 + eqrightharpoonup: "\u21c0",
886 + eqleftharpoondown: "\u21bd",
887 + "\\cdrightarrow": "\u2192",
888 + "\\cdleftarrow": "\u2190",
889 + "\\cdlongequal": "="
890 + };
891 +
892 + const mathMLnode = function(label) {
893 + const child = new mathMLTree.TextNode(stretchyCodePoint[label.slice(1)]);
894 + const node = new mathMLTree.MathNode("mo", [child]);
895 + node.setAttribute("stretchy", "true");
896 + return node
897 + };
898 +
899 + const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"];
900 +
901 + // TODO: Remove when Chromium stretches \widetilde & \widehat
902 + const accentNode = (group) => {
903 + const mo = mathMLnode(group.label);
904 + if (crookedWides.includes(group.label)) {
905 + const width = estimatedWidth(group.base);
906 + if (1 < width && width < 1.6) {
907 + mo.classes.push("tml-crooked-2");
908 + } else if (1.6 <= width && width < 2.5) {
909 + mo.classes.push("tml-crooked-3");
910 + } else if (2.5 <= width) {
911 + mo.classes.push("tml-crooked-4");
912 + }
913 + }
914 + return mo
915 + };
916 +
917 + var stretchy = {
918 + mathMLnode,
919 + accentNode
920 + };
921 +
922 + /**
923 + * This file holds a list of all no-argument functions and single-character
924 + * symbols (like 'a' or ';').
925 + *
926 + * For each of the symbols, there are two properties they can have:
927 + * - group (required): the ParseNode group type the symbol should have (i.e.
928 + "textord", "mathord", etc).
929 + * - replace: the character that this symbol or function should be
930 + * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi
931 + * character in the main font).
932 + *
933 + * The outermost map in the table indicates what mode the symbols should be
934 + * accepted in (e.g. "math" or "text").
935 + */
936 +
937 + // Some of these have a "-token" suffix since these are also used as `ParseNode`
938 + // types for raw text tokens, and we want to avoid conflicts with higher-level
939 + // `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
940 + // looking up the `symbols` map.
941 + const ATOMS = {
942 + bin: 1,
943 + close: 1,
944 + inner: 1,
945 + open: 1,
946 + punct: 1,
947 + rel: 1
948 + };
949 + const NON_ATOMS = {
950 + "accent-token": 1,
951 + mathord: 1,
952 + "op-token": 1,
953 + spacing: 1,
954 + textord: 1
955 + };
956 +
957 + const symbols = {
958 + math: {},
959 + text: {}
960 + };
961 +
962 + /** `acceptUnicodeChar = true` is only applicable if `replace` is set. */
963 + function defineSymbol(mode, group, replace, name, acceptUnicodeChar) {
964 + symbols[mode][name] = { group, replace };
965 +
966 + if (acceptUnicodeChar && replace) {
967 + symbols[mode][replace] = symbols[mode][name];
968 + }
969 + }
970 +
971 + // Some abbreviations for commonly used strings.
972 + // This helps minify the code, and also spotting typos using jshint.
973 +
974 + // modes:
975 + const math = "math";
976 + const temml_text = "text";
977 +
978 + // groups:
979 + const accent = "accent-token";
980 + const bin = "bin";
981 + const temml_close = "close";
982 + const inner = "inner";
983 + const mathord = "mathord";
984 + const op = "op-token";
985 + const temml_open = "open";
986 + const punct = "punct";
987 + const rel = "rel";
988 + const spacing = "spacing";
989 + const textord = "textord";
990 +
991 + // Now comes the symbol table
992 +
993 + // Relation Symbols
994 + defineSymbol(math, rel, "\u2261", "\\equiv", true);
995 + defineSymbol(math, rel, "\u227a", "\\prec", true);
996 + defineSymbol(math, rel, "\u227b", "\\succ", true);
997 + defineSymbol(math, rel, "\u223c", "\\sim", true);
998 + defineSymbol(math, rel, "\u27c2", "\\perp", true);
999 + defineSymbol(math, rel, "\u2aaf", "\\preceq", true);
1000 + defineSymbol(math, rel, "\u2ab0", "\\succeq", true);
1001 + defineSymbol(math, rel, "\u2243", "\\simeq", true);
1002 + defineSymbol(math, rel, "\u224c", "\\backcong", true);
1003 + defineSymbol(math, rel, "|", "\\mid", true);
1004 + defineSymbol(math, rel, "\u226a", "\\ll", true);
1005 + defineSymbol(math, rel, "\u226b", "\\gg", true);
1006 + defineSymbol(math, rel, "\u224d", "\\asymp", true);
1007 + defineSymbol(math, rel, "\u2225", "\\parallel");
1008 + defineSymbol(math, rel, "\u2323", "\\smile", true);
1009 + defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true);
1010 + defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true);
1011 + defineSymbol(math, rel, "\u2250", "\\doteq", true);
1012 + defineSymbol(math, rel, "\u2322", "\\frown", true);
1013 + defineSymbol(math, rel, "\u220b", "\\ni", true);
1014 + defineSymbol(math, rel, "\u220c", "\\notni", true);
1015 + defineSymbol(math, rel, "\u221d", "\\propto", true);
1016 + defineSymbol(math, rel, "\u22a2", "\\vdash", true);
1017 + defineSymbol(math, rel, "\u22a3", "\\dashv", true);
1018 + defineSymbol(math, rel, "\u220b", "\\owns");
1019 + defineSymbol(math, rel, "\u2258", "\\arceq", true);
1020 + defineSymbol(math, rel, "\u2259", "\\wedgeq", true);
1021 + defineSymbol(math, rel, "\u225a", "\\veeeq", true);
1022 + defineSymbol(math, rel, "\u225b", "\\stareq", true);
1023 + defineSymbol(math, rel, "\u225d", "\\eqdef", true);
1024 + defineSymbol(math, rel, "\u225e", "\\measeq", true);
1025 + defineSymbol(math, rel, "\u225f", "\\questeq", true);
1026 + defineSymbol(math, rel, "\u2260", "\\ne", true);
1027 + defineSymbol(math, rel, "\u2260", "\\neq");
1028 + // unicodemath
1029 + defineSymbol(math, rel, "\u2a75", "\\eqeq", true);
1030 + defineSymbol(math, rel, "\u2a76", "\\eqeqeq", true);
1031 + // mathtools.sty
1032 + defineSymbol(math, rel, "\u2237", "\\dblcolon", true);
1033 + defineSymbol(math, rel, "\u2254", "\\coloneqq", true);
1034 + defineSymbol(math, rel, "\u2255", "\\eqqcolon", true);
1035 + defineSymbol(math, rel, "\u2239", "\\eqcolon", true);
1036 + defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true);
1037 +
1038 + // Punctuation
1039 + defineSymbol(math, punct, "\u002e", "\\ldotp");
1040 + defineSymbol(math, punct, "\u00b7", "\\cdotp");
1041 +
1042 + // Misc Symbols
1043 + defineSymbol(math, textord, "\u0023", "\\#");
1044 + defineSymbol(temml_text, textord, "\u0023", "\\#");
1045 + defineSymbol(math, textord, "\u0026", "\\&");
1046 + defineSymbol(temml_text, textord, "\u0026", "\\&");
1047 + defineSymbol(math, textord, "\u2135", "\\aleph", true);
1048 + defineSymbol(math, textord, "\u2200", "\\forall", true);
1049 + defineSymbol(math, textord, "\u210f", "\\hbar", true);
1050 + defineSymbol(math, textord, "\u2203", "\\exists", true);
1051 + // ∇ is actually a unary operator, not binary. But this works.
1052 + defineSymbol(math, bin, "\u2207", "\\nabla", true);
1053 + defineSymbol(math, textord, "\u266d", "\\flat", true);
1054 + defineSymbol(math, textord, "\u2113", "\\ell", true);
1055 + defineSymbol(math, textord, "\u266e", "\\natural", true);
1056 + defineSymbol(math, textord, "Å", "\\Angstrom", true);
1057 + defineSymbol(temml_text, textord, "Å", "\\Angstrom", true);
1058 + defineSymbol(math, textord, "\u2663", "\\clubsuit", true);
1059 + defineSymbol(math, textord, "\u2667", "\\varclubsuit", true);
1060 + defineSymbol(math, textord, "\u2118", "\\wp", true);
1061 + defineSymbol(math, textord, "\u266f", "\\sharp", true);
1062 + defineSymbol(math, textord, "\u2662", "\\diamondsuit", true);
1063 + defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true);
1064 + defineSymbol(math, textord, "\u211c", "\\Re", true);
1065 + defineSymbol(math, textord, "\u2661", "\\heartsuit", true);
1066 + defineSymbol(math, textord, "\u2665", "\\varheartsuit", true);
1067 + defineSymbol(math, textord, "\u2111", "\\Im", true);
1068 + defineSymbol(math, textord, "\u2660", "\\spadesuit", true);
1069 + defineSymbol(math, textord, "\u2664", "\\varspadesuit", true);
1070 + defineSymbol(math, textord, "\u2640", "\\female", true);
1071 + defineSymbol(math, textord, "\u2642", "\\male", true);
1072 + defineSymbol(math, textord, "\u00a7", "\\S", true);
1073 + defineSymbol(temml_text, textord, "\u00a7", "\\S");
1074 + defineSymbol(math, textord, "\u00b6", "\\P", true);
1075 + defineSymbol(temml_text, textord, "\u00b6", "\\P");
1076 + defineSymbol(temml_text, textord, "\u263a", "\\smiley", true);
1077 + defineSymbol(math, textord, "\u263a", "\\smiley", true);
1078 +
1079 + // Math and Text
1080 + defineSymbol(math, textord, "\u2020", "\\dag");
1081 + defineSymbol(temml_text, textord, "\u2020", "\\dag");
1082 + defineSymbol(temml_text, textord, "\u2020", "\\textdagger");
1083 + defineSymbol(math, textord, "\u2021", "\\ddag");
1084 + defineSymbol(temml_text, textord, "\u2021", "\\ddag");
1085 + defineSymbol(temml_text, textord, "\u2021", "\\textdaggerdbl");
1086 +
1087 + // Large Delimiters
1088 + defineSymbol(math, temml_close, "\u23b1", "\\rmoustache", true);
1089 + defineSymbol(math, temml_open, "\u23b0", "\\lmoustache", true);
1090 + defineSymbol(math, temml_close, "\u27ef", "\\rgroup", true);
1091 + defineSymbol(math, temml_open, "\u27ee", "\\lgroup", true);
1092 +
1093 + // Binary Operators
1094 + defineSymbol(math, bin, "\u2213", "\\mp", true);
1095 + defineSymbol(math, bin, "\u2296", "\\ominus", true);
1096 + defineSymbol(math, bin, "\u228e", "\\uplus", true);
1097 + defineSymbol(math, bin, "\u2293", "\\sqcap", true);
1098 + defineSymbol(math, bin, "\u2217", "\\ast");
1099 + defineSymbol(math, bin, "\u2294", "\\sqcup", true);
1100 + defineSymbol(math, bin, "\u25ef", "\\bigcirc", true);
1101 + defineSymbol(math, bin, "\u2219", "\\bullet", true);
1102 + defineSymbol(math, bin, "\u2021", "\\ddagger");
1103 + defineSymbol(math, bin, "\u2240", "\\wr", true);
1104 + defineSymbol(math, bin, "\u2a3f", "\\amalg");
1105 + defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath
1106 + defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd
1107 +
1108 + // Arrow Symbols
1109 + defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true);
1110 + defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true);
1111 + defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true);
1112 + defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true);
1113 + defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true);
1114 + defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true);
1115 + defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true);
1116 + defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true);
1117 + defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true);
1118 + defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true);
1119 + defineSymbol(math, rel, "\u21a4", "\\mapsfrom", true);
1120 + defineSymbol(math, rel, "\u21a6", "\\mapsto", true);
1121 + defineSymbol(math, rel, "\u27fc", "\\longmapsto", true);
1122 + defineSymbol(math, rel, "\u2197", "\\nearrow", true);
1123 + defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true);
1124 + defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true);
1125 + defineSymbol(math, rel, "\u2198", "\\searrow", true);
1126 + defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true);
1127 + defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true);
1128 + defineSymbol(math, rel, "\u2199", "\\swarrow", true);
1129 + defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true);
1130 + defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true);
1131 + defineSymbol(math, rel, "\u2196", "\\nwarrow", true);
1132 + defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true);
1133 + defineSymbol(math, mathord, "\u21af", "\\lightning", true);
1134 + defineSymbol(math, mathord, "\u220E", "\\QED", true);
1135 + defineSymbol(math, mathord, "\u2030", "\\permil", true);
1136 + defineSymbol(temml_text, textord, "\u2030", "\\permil");
1137 + defineSymbol(math, mathord, "\u2609", "\\astrosun", true);
1138 + defineSymbol(math, mathord, "\u263c", "\\sun", true);
1139 + defineSymbol(math, mathord, "\u263e", "\\leftmoon", true);
1140 + defineSymbol(math, mathord, "\u263d", "\\rightmoon", true);
1141 + defineSymbol(math, mathord, "\u2295", "\\Earth");
1142 +
1143 + // AMS Negated Binary Relations
1144 + defineSymbol(math, rel, "\u226e", "\\nless", true);
1145 + // Symbol names preceeded by "@" each have a corresponding macro.
1146 + defineSymbol(math, rel, "\u2a87", "\\lneq", true);
1147 + defineSymbol(math, rel, "\u2268", "\\lneqq", true);
1148 + defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq");
1149 + defineSymbol(math, rel, "\u22e6", "\\lnsim", true);
1150 + defineSymbol(math, rel, "\u2a89", "\\lnapprox", true);
1151 + defineSymbol(math, rel, "\u2280", "\\nprec", true);
1152 + // unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym.
1153 + defineSymbol(math, rel, "\u22e0", "\\npreceq", true);
1154 + defineSymbol(math, rel, "\u22e8", "\\precnsim", true);
1155 + defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true);
1156 + defineSymbol(math, rel, "\u2241", "\\nsim", true);
1157 + defineSymbol(math, rel, "\u2224", "\\nmid", true);
1158 + defineSymbol(math, rel, "\u2224", "\\nshortmid");
1159 + defineSymbol(math, rel, "\u22ac", "\\nvdash", true);
1160 + defineSymbol(math, rel, "\u22ad", "\\nvDash", true);
1161 + defineSymbol(math, rel, "\u22ea", "\\ntriangleleft");
1162 + defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true);
1163 + defineSymbol(math, rel, "\u2284", "\\nsubset", true);
1164 + defineSymbol(math, rel, "\u2285", "\\nsupset", true);
1165 + defineSymbol(math, rel, "\u228a", "\\subsetneq", true);
1166 + defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq");
1167 + defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true);
1168 + defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq");
1169 + defineSymbol(math, rel, "\u226f", "\\ngtr", true);
1170 + defineSymbol(math, rel, "\u2a88", "\\gneq", true);
1171 + defineSymbol(math, rel, "\u2269", "\\gneqq", true);
1172 + defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq");
1173 + defineSymbol(math, rel, "\u22e7", "\\gnsim", true);
1174 + defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true);
1175 + defineSymbol(math, rel, "\u2281", "\\nsucc", true);
1176 + // unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym.
1177 + defineSymbol(math, rel, "\u22e1", "\\nsucceq", true);
1178 + defineSymbol(math, rel, "\u22e9", "\\succnsim", true);
1179 + defineSymbol(math, rel, "\u2aba", "\\succnapprox", true);
1180 + // unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym.
1181 + defineSymbol(math, rel, "\u2246", "\\ncong", true);
1182 + defineSymbol(math, rel, "\u2226", "\\nparallel", true);
1183 + defineSymbol(math, rel, "\u2226", "\\nshortparallel");
1184 + defineSymbol(math, rel, "\u22af", "\\nVDash", true);
1185 + defineSymbol(math, rel, "\u22eb", "\\ntriangleright");
1186 + defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true);
1187 + defineSymbol(math, rel, "\u228b", "\\supsetneq", true);
1188 + defineSymbol(math, rel, "\u228b", "\\varsupsetneq");
1189 + defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true);
1190 + defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq");
1191 + defineSymbol(math, rel, "\u22ae", "\\nVdash", true);
1192 + defineSymbol(math, rel, "\u2ab5", "\\precneqq", true);
1193 + defineSymbol(math, rel, "\u2ab6", "\\succneqq", true);
1194 + defineSymbol(math, bin, "\u22b4", "\\unlhd");
1195 + defineSymbol(math, bin, "\u22b5", "\\unrhd");
1196 +
1197 + // AMS Negated Arrows
1198 + defineSymbol(math, rel, "\u219a", "\\nleftarrow", true);
1199 + defineSymbol(math, rel, "\u219b", "\\nrightarrow", true);
1200 + defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true);
1201 + defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true);
1202 + defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true);
1203 + defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true);
1204 +
1205 + // AMS Misc
1206 + defineSymbol(math, rel, "\u25b3", "\\vartriangle");
1207 + defineSymbol(math, textord, "\u210f", "\\hslash");
1208 + defineSymbol(math, textord, "\u25bd", "\\triangledown");
1209 + defineSymbol(math, textord, "\u25ca", "\\lozenge");
1210 + defineSymbol(math, textord, "\u24c8", "\\circledS");
1211 + defineSymbol(math, textord, "\u00ae", "\\circledR", true);
1212 + defineSymbol(temml_text, textord, "\u00ae", "\\circledR");
1213 + defineSymbol(temml_text, textord, "\u00ae", "\\textregistered");
1214 + defineSymbol(math, textord, "\u2221", "\\measuredangle", true);
1215 + defineSymbol(math, textord, "\u2204", "\\nexists");
1216 + defineSymbol(math, textord, "\u2127", "\\mho");
1217 + defineSymbol(math, textord, "\u2132", "\\Finv", true);
1218 + defineSymbol(math, textord, "\u2141", "\\Game", true);
1219 + defineSymbol(math, textord, "\u2035", "\\backprime");
1220 + defineSymbol(math, textord, "\u2036", "\\backdprime");
1221 + defineSymbol(math, textord, "\u2037", "\\backtrprime");
1222 + defineSymbol(math, textord, "\u25b2", "\\blacktriangle");
1223 + defineSymbol(math, textord, "\u25bc", "\\blacktriangledown");
1224 + defineSymbol(math, textord, "\u25a0", "\\blacksquare");
1225 + defineSymbol(math, textord, "\u29eb", "\\blacklozenge");
1226 + defineSymbol(math, textord, "\u2605", "\\bigstar");
1227 + defineSymbol(math, textord, "\u2222", "\\sphericalangle", true);
1228 + defineSymbol(math, textord, "\u2201", "\\complement", true);
1229 + // unicode-math maps U+F0 to \matheth. We map to AMS function \eth
1230 + defineSymbol(math, textord, "\u00f0", "\\eth", true);
1231 + defineSymbol(temml_text, textord, "\u00f0", "\u00f0");
1232 + defineSymbol(math, textord, "\u2571", "\\diagup");
1233 + defineSymbol(math, textord, "\u2572", "\\diagdown");
1234 + defineSymbol(math, textord, "\u25a1", "\\square");
1235 + defineSymbol(math, textord, "\u25a1", "\\Box");
1236 + defineSymbol(math, textord, "\u25ca", "\\Diamond");
1237 + // unicode-math maps U+A5 to \mathyen. We map to AMS function \yen
1238 + defineSymbol(math, textord, "\u00a5", "\\yen", true);
1239 + defineSymbol(temml_text, textord, "\u00a5", "\\yen", true);
1240 + defineSymbol(math, textord, "\u2713", "\\checkmark", true);
1241 + defineSymbol(temml_text, textord, "\u2713", "\\checkmark");
1242 + defineSymbol(math, textord, "\u2717", "\\ballotx", true);
1243 + defineSymbol(temml_text, textord, "\u2717", "\\ballotx");
1244 + defineSymbol(temml_text, textord, "\u2022", "\\textbullet");
1245 +
1246 + // AMS Hebrew
1247 + defineSymbol(math, textord, "\u2136", "\\beth", true);
1248 + defineSymbol(math, textord, "\u2138", "\\daleth", true);
1249 + defineSymbol(math, textord, "\u2137", "\\gimel", true);
1250 +
1251 + // AMS Greek
1252 + defineSymbol(math, textord, "\u03dd", "\\digamma", true);
1253 + defineSymbol(math, textord, "\u03f0", "\\varkappa");
1254 +
1255 + // AMS Delimiters
1256 + defineSymbol(math, temml_open, "\u231C", "\\ulcorner", true);
1257 + defineSymbol(math, temml_close, "\u231D", "\\urcorner", true);
1258 + defineSymbol(math, temml_open, "\u231E", "\\llcorner", true);
1259 + defineSymbol(math, temml_close, "\u231F", "\\lrcorner", true);
1260 +
1261 + // AMS Binary Relations
1262 + defineSymbol(math, rel, "\u2266", "\\leqq", true);
1263 + defineSymbol(math, rel, "\u2a7d", "\\leqslant", true);
1264 + defineSymbol(math, rel, "\u2a95", "\\eqslantless", true);
1265 + defineSymbol(math, rel, "\u2272", "\\lesssim", true);
1266 + defineSymbol(math, rel, "\u2a85", "\\lessapprox", true);
1267 + defineSymbol(math, rel, "\u224a", "\\approxeq", true);
1268 + defineSymbol(math, bin, "\u22d6", "\\lessdot");
1269 + defineSymbol(math, rel, "\u22d8", "\\lll", true);
1270 + defineSymbol(math, rel, "\u2276", "\\lessgtr", true);
1271 + defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true);
1272 + defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true);
1273 + defineSymbol(math, rel, "\u2251", "\\doteqdot");
1274 + defineSymbol(math, rel, "\u2253", "\\risingdotseq", true);
1275 + defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true);
1276 + defineSymbol(math, rel, "\u223d", "\\backsim", true);
1277 + defineSymbol(math, rel, "\u22cd", "\\backsimeq", true);
1278 + defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true);
1279 + defineSymbol(math, rel, "\u22d0", "\\Subset", true);
1280 + defineSymbol(math, rel, "\u228f", "\\sqsubset", true);
1281 + defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true);
1282 + defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true);
1283 + defineSymbol(math, rel, "\u227e", "\\precsim", true);
1284 + defineSymbol(math, rel, "\u2ab7", "\\precapprox", true);
1285 + defineSymbol(math, rel, "\u22b2", "\\vartriangleleft");
1286 + defineSymbol(math, rel, "\u22b4", "\\trianglelefteq");
1287 + defineSymbol(math, rel, "\u22a8", "\\vDash", true);
1288 + defineSymbol(math, rel, "\u22ab", "\\VDash", true);
1289 + defineSymbol(math, rel, "\u22aa", "\\Vvdash", true);
1290 + defineSymbol(math, rel, "\u2323", "\\smallsmile");
1291 + defineSymbol(math, rel, "\u2322", "\\smallfrown");
1292 + defineSymbol(math, rel, "\u224f", "\\bumpeq", true);
1293 + defineSymbol(math, rel, "\u224e", "\\Bumpeq", true);
1294 + defineSymbol(math, rel, "\u2267", "\\geqq", true);
1295 + defineSymbol(math, rel, "\u2a7e", "\\geqslant", true);
1296 + defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true);
1297 + defineSymbol(math, rel, "\u2273", "\\gtrsim", true);
1298 + defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true);
1299 + defineSymbol(math, bin, "\u22d7", "\\gtrdot");
1300 + defineSymbol(math, rel, "\u22d9", "\\ggg", true);
1301 + defineSymbol(math, rel, "\u2277", "\\gtrless", true);
1302 + defineSymbol(math, rel, "\u22db", "\\gtreqless", true);
1303 + defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true);
1304 + defineSymbol(math, rel, "\u2256", "\\eqcirc", true);
1305 + defineSymbol(math, rel, "\u2257", "\\circeq", true);
1306 + defineSymbol(math, rel, "\u225c", "\\triangleq", true);
1307 + defineSymbol(math, rel, "\u223c", "\\thicksim");
1308 + defineSymbol(math, rel, "\u2248", "\\thickapprox");
1309 + defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true);
1310 + defineSymbol(math, rel, "\u22d1", "\\Supset", true);
1311 + defineSymbol(math, rel, "\u2290", "\\sqsupset", true);
1312 + defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true);
1313 + defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true);
1314 + defineSymbol(math, rel, "\u227f", "\\succsim", true);
1315 + defineSymbol(math, rel, "\u2ab8", "\\succapprox", true);
1316 + defineSymbol(math, rel, "\u22b3", "\\vartriangleright");
1317 + defineSymbol(math, rel, "\u22b5", "\\trianglerighteq");
1318 + defineSymbol(math, rel, "\u22a9", "\\Vdash", true);
1319 + defineSymbol(math, rel, "\u2223", "\\shortmid");
1320 + defineSymbol(math, rel, "\u2225", "\\shortparallel");
1321 + defineSymbol(math, rel, "\u226c", "\\between", true);
1322 + defineSymbol(math, rel, "\u22d4", "\\pitchfork", true);
1323 + defineSymbol(math, rel, "\u221d", "\\varpropto");
1324 + defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft");
1325 + // unicode-math says that \therefore is a mathord atom.
1326 + // We kept the amssymb atom type, which is rel.
1327 + defineSymbol(math, rel, "\u2234", "\\therefore", true);
1328 + defineSymbol(math, rel, "\u220d", "\\backepsilon");
1329 + defineSymbol(math, rel, "\u25b6", "\\blacktriangleright");
1330 + // unicode-math says that \because is a mathord atom.
1331 + // We kept the amssymb atom type, which is rel.
1332 + defineSymbol(math, rel, "\u2235", "\\because", true);
1333 + defineSymbol(math, rel, "\u22d8", "\\llless");
1334 + defineSymbol(math, rel, "\u22d9", "\\gggtr");
1335 + defineSymbol(math, bin, "\u22b2", "\\lhd");
1336 + defineSymbol(math, bin, "\u22b3", "\\rhd");
1337 + defineSymbol(math, rel, "\u2242", "\\eqsim", true);
1338 + defineSymbol(math, rel, "\u2251", "\\Doteq", true);
1339 + defineSymbol(math, rel, "\u297d", "\\strictif", true);
1340 + defineSymbol(math, rel, "\u297c", "\\strictfi", true);
1341 +
1342 + // AMS Binary Operators
1343 + defineSymbol(math, bin, "\u2214", "\\dotplus", true);
1344 + defineSymbol(math, bin, "\u2216", "\\smallsetminus");
1345 + defineSymbol(math, bin, "\u22d2", "\\Cap", true);
1346 + defineSymbol(math, bin, "\u22d3", "\\Cup", true);
1347 + defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true);
1348 + defineSymbol(math, bin, "\u229f", "\\boxminus", true);
1349 + defineSymbol(math, bin, "\u229e", "\\boxplus", true);
1350 + defineSymbol(math, bin, "\u29C4", "\\boxslash", true);
1351 + defineSymbol(math, bin, "\u22c7", "\\divideontimes", true);
1352 + defineSymbol(math, bin, "\u22c9", "\\ltimes", true);
1353 + defineSymbol(math, bin, "\u22ca", "\\rtimes", true);
1354 + defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true);
1355 + defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true);
1356 + defineSymbol(math, bin, "\u22cf", "\\curlywedge", true);
1357 + defineSymbol(math, bin, "\u22ce", "\\curlyvee", true);
1358 + defineSymbol(math, bin, "\u229d", "\\circleddash", true);
1359 + defineSymbol(math, bin, "\u229b", "\\circledast", true);
1360 + defineSymbol(math, bin, "\u22ba", "\\intercal", true);
1361 + defineSymbol(math, bin, "\u22d2", "\\doublecap");
1362 + defineSymbol(math, bin, "\u22d3", "\\doublecup");
1363 + defineSymbol(math, bin, "\u22a0", "\\boxtimes", true);
1364 + defineSymbol(math, bin, "\u22c8", "\\bowtie", true);
1365 + defineSymbol(math, bin, "\u22c8", "\\Join");
1366 + defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true);
1367 + defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true);
1368 + defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true);
1369 +
1370 + // stix Binary Operators
1371 + defineSymbol(math, bin, "\u2238", "\\dotminus", true);
1372 + defineSymbol(math, bin, "\u27D1", "\\wedgedot", true);
1373 + defineSymbol(math, bin, "\u27C7", "\\veedot", true);
1374 + defineSymbol(math, bin, "\u2A62", "\\doublebarvee", true);
1375 + defineSymbol(math, bin, "\u2A63", "\\veedoublebar", true);
1376 + defineSymbol(math, bin, "\u2A5F", "\\wedgebar", true);
1377 + defineSymbol(math, bin, "\u2A60", "\\wedgedoublebar", true);
1378 + defineSymbol(math, bin, "\u2A54", "\\Vee", true);
1379 + defineSymbol(math, bin, "\u2A53", "\\Wedge", true);
1380 + defineSymbol(math, bin, "\u2A43", "\\barcap", true);
1381 + defineSymbol(math, bin, "\u2A42", "\\barcup", true);
1382 + defineSymbol(math, bin, "\u2A48", "\\capbarcup", true);
1383 + defineSymbol(math, bin, "\u2A40", "\\capdot", true);
1384 + defineSymbol(math, bin, "\u2A47", "\\capovercup", true);
1385 + defineSymbol(math, bin, "\u2A46", "\\cupovercap", true);
1386 + defineSymbol(math, bin, "\u2A4D", "\\closedvarcap", true);
1387 + defineSymbol(math, bin, "\u2A4C", "\\closedvarcup", true);
1388 + defineSymbol(math, bin, "\u2A2A", "\\minusdot", true);
1389 + defineSymbol(math, bin, "\u2A2B", "\\minusfdots", true);
1390 + defineSymbol(math, bin, "\u2A2C", "\\minusrdots", true);
1391 + defineSymbol(math, bin, "\u22BB", "\\Xor", true);
1392 + defineSymbol(math, bin, "\u22BC", "\\Nand", true);
1393 + defineSymbol(math, bin, "\u22BD", "\\Nor", true);
1394 + defineSymbol(math, bin, "\u22BD", "\\barvee");
1395 + defineSymbol(math, bin, "\u2AF4", "\\interleave", true);
1396 + defineSymbol(math, bin, "\u29E2", "\\shuffle", true);
1397 + defineSymbol(math, bin, "\u2AF6", "\\threedotcolon", true);
1398 + defineSymbol(math, bin, "\u2982", "\\typecolon", true);
1399 + defineSymbol(math, bin, "\u223E", "\\invlazys", true);
1400 + defineSymbol(math, bin, "\u2A4B", "\\twocaps", true);
1401 + defineSymbol(math, bin, "\u2A4A", "\\twocups", true);
1402 + defineSymbol(math, bin, "\u2A4E", "\\Sqcap", true);
1403 + defineSymbol(math, bin, "\u2A4F", "\\Sqcup", true);
1404 + defineSymbol(math, bin, "\u2A56", "\\veeonvee", true);
1405 + defineSymbol(math, bin, "\u2A55", "\\wedgeonwedge", true);
1406 + defineSymbol(math, bin, "\u29D7", "\\blackhourglass", true);
1407 + defineSymbol(math, bin, "\u29C6", "\\boxast", true);
1408 + defineSymbol(math, bin, "\u29C8", "\\boxbox", true);
1409 + defineSymbol(math, bin, "\u29C7", "\\boxcircle", true);
1410 + defineSymbol(math, bin, "\u229C", "\\circledequal", true);
1411 + defineSymbol(math, bin, "\u29B7", "\\circledparallel", true);
1412 + defineSymbol(math, bin, "\u29B6", "\\circledvert", true);
1413 + defineSymbol(math, bin, "\u29B5", "\\circlehbar", true);
1414 + defineSymbol(math, bin, "\u27E1", "\\concavediamond", true);
1415 + defineSymbol(math, bin, "\u27E2", "\\concavediamondtickleft", true);
1416 + defineSymbol(math, bin, "\u27E3", "\\concavediamondtickright", true);
1417 + defineSymbol(math, bin, "\u22C4", "\\diamond", true);
1418 + defineSymbol(math, bin, "\u29D6", "\\hourglass", true);
1419 + defineSymbol(math, bin, "\u27E0", "\\lozengeminus", true);
1420 + defineSymbol(math, bin, "\u233D", "\\obar", true);
1421 + defineSymbol(math, bin, "\u29B8", "\\obslash", true);
1422 + defineSymbol(math, bin, "\u2A38", "\\odiv", true);
1423 + defineSymbol(math, bin, "\u29C1", "\\ogreaterthan", true);
1424 + defineSymbol(math, bin, "\u29C0", "\\olessthan", true);
1425 + defineSymbol(math, bin, "\u29B9", "\\operp", true);
1426 + defineSymbol(math, bin, "\u2A37", "\\Otimes", true);
1427 + defineSymbol(math, bin, "\u2A36", "\\otimeshat", true);
1428 + defineSymbol(math, bin, "\u22C6", "\\star", true);
1429 + defineSymbol(math, bin, "\u25B3", "\\triangle", true);
1430 + defineSymbol(math, bin, "\u2A3A", "\\triangleminus", true);
1431 + defineSymbol(math, bin, "\u2A39", "\\triangleplus", true);
1432 + defineSymbol(math, bin, "\u2A3B", "\\triangletimes", true);
1433 + defineSymbol(math, bin, "\u27E4", "\\whitesquaretickleft", true);
1434 + defineSymbol(math, bin, "\u27E5", "\\whitesquaretickright", true);
1435 + defineSymbol(math, bin, "\u2A33", "\\smashtimes", true);
1436 +
1437 + // AMS Arrows
1438 + // Note: unicode-math maps \u21e2 to their own function \rightdasharrow.
1439 + // We'll map it to AMS function \dashrightarrow. It produces the same atom.
1440 + defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true);
1441 + // unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym.
1442 + defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true);
1443 + defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true);
1444 + defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true);
1445 + defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true);
1446 + defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true);
1447 + defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true);
1448 + defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true);
1449 + defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true);
1450 + defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true);
1451 + // unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym.
1452 + defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true);
1453 + defineSymbol(math, rel, "\u21b0", "\\Lsh", true);
1454 + defineSymbol(math, rel, "\u21c8", "\\upuparrows", true);
1455 + defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true);
1456 + defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true);
1457 + defineSymbol(math, rel, "\u22b6", "\\origof", true);
1458 + defineSymbol(math, rel, "\u22b7", "\\imageof", true);
1459 + defineSymbol(math, rel, "\u22b8", "\\multimap", true);
1460 + defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true);
1461 + defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true);
1462 + defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true);
1463 + defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true);
1464 + defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true);
1465 + defineSymbol(math, rel, "\u21ac", "\\looparrowright", true);
1466 + defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true);
1467 + // unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym.
1468 + defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true);
1469 + defineSymbol(math, rel, "\u21b1", "\\Rsh", true);
1470 + defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true);
1471 + defineSymbol(math, rel, "\u21be", "\\upharpoonright", true);
1472 + defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true);
1473 + defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true);
1474 + defineSymbol(math, rel, "\u21dd", "\\leadsto");
1475 + defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true);
1476 + defineSymbol(math, rel, "\u21be", "\\restriction");
1477 +
1478 + defineSymbol(math, textord, "\u2018", "`");
1479 + defineSymbol(math, textord, "$", "\\$");
1480 + defineSymbol(temml_text, textord, "$", "\\$");
1481 + defineSymbol(temml_text, textord, "$", "\\textdollar");
1482 + defineSymbol(math, textord, "¢", "\\cent");
1483 + defineSymbol(temml_text, textord, "¢", "\\cent");
1484 + defineSymbol(math, textord, "%", "\\%");
1485 + defineSymbol(temml_text, textord, "%", "\\%");
1486 + defineSymbol(math, textord, "_", "\\_");
1487 + defineSymbol(temml_text, textord, "_", "\\_");
1488 + defineSymbol(temml_text, textord, "_", "\\textunderscore");
1489 + defineSymbol(temml_text, textord, "\u2423", "\\textvisiblespace", true);
1490 + defineSymbol(math, textord, "\u2220", "\\angle", true);
1491 + defineSymbol(math, textord, "\u221e", "\\infty", true);
1492 + defineSymbol(math, textord, "\u2032", "\\prime");
1493 + defineSymbol(math, textord, "\u2033", "\\dprime");
1494 + defineSymbol(math, textord, "\u2034", "\\trprime");
1495 + defineSymbol(math, textord, "\u2057", "\\qprime");
1496 + defineSymbol(math, textord, "\u25b3", "\\triangle");
1497 + defineSymbol(temml_text, textord, "\u0391", "\\Alpha", true);
1498 + defineSymbol(temml_text, textord, "\u0392", "\\Beta", true);
1499 + defineSymbol(temml_text, textord, "\u0393", "\\Gamma", true);
1500 + defineSymbol(temml_text, textord, "\u0394", "\\Delta", true);
1501 + defineSymbol(temml_text, textord, "\u0395", "\\Epsilon", true);
1502 + defineSymbol(temml_text, textord, "\u0396", "\\Zeta", true);
1503 + defineSymbol(temml_text, textord, "\u0397", "\\Eta", true);
1504 + defineSymbol(temml_text, textord, "\u0398", "\\Theta", true);
1505 + defineSymbol(temml_text, textord, "\u0399", "\\Iota", true);
1506 + defineSymbol(temml_text, textord, "\u039a", "\\Kappa", true);
1507 + defineSymbol(temml_text, textord, "\u039b", "\\Lambda", true);
1508 + defineSymbol(temml_text, textord, "\u039c", "\\Mu", true);
1509 + defineSymbol(temml_text, textord, "\u039d", "\\Nu", true);
1510 + defineSymbol(temml_text, textord, "\u039e", "\\Xi", true);
1511 + defineSymbol(temml_text, textord, "\u039f", "\\Omicron", true);
1512 + defineSymbol(temml_text, textord, "\u03a0", "\\Pi", true);
1513 + defineSymbol(temml_text, textord, "\u03a1", "\\Rho", true);
1514 + defineSymbol(temml_text, textord, "\u03a3", "\\Sigma", true);
1515 + defineSymbol(temml_text, textord, "\u03a4", "\\Tau", true);
1516 + defineSymbol(temml_text, textord, "\u03a5", "\\Upsilon", true);
1517 + defineSymbol(temml_text, textord, "\u03a6", "\\Phi", true);
1518 + defineSymbol(temml_text, textord, "\u03a7", "\\Chi", true);
1519 + defineSymbol(temml_text, textord, "\u03a8", "\\Psi", true);
1520 + defineSymbol(temml_text, textord, "\u03a9", "\\Omega", true);
1521 + defineSymbol(math, mathord, "\u0391", "\\Alpha", true);
1522 + defineSymbol(math, mathord, "\u0392", "\\Beta", true);
1523 + defineSymbol(math, mathord, "\u0393", "\\Gamma", true);
1524 + defineSymbol(math, mathord, "\u0394", "\\Delta", true);
1525 + defineSymbol(math, mathord, "\u0395", "\\Epsilon", true);
1526 + defineSymbol(math, mathord, "\u0396", "\\Zeta", true);
1527 + defineSymbol(math, mathord, "\u0397", "\\Eta", true);
1528 + defineSymbol(math, mathord, "\u0398", "\\Theta", true);
1529 + defineSymbol(math, mathord, "\u0399", "\\Iota", true);
1530 + defineSymbol(math, mathord, "\u039a", "\\Kappa", true);
1531 + defineSymbol(math, mathord, "\u039b", "\\Lambda", true);
1532 + defineSymbol(math, mathord, "\u039c", "\\Mu", true);
1533 + defineSymbol(math, mathord, "\u039d", "\\Nu", true);
1534 + defineSymbol(math, mathord, "\u039e", "\\Xi", true);
1535 + defineSymbol(math, mathord, "\u039f", "\\Omicron", true);
1536 + defineSymbol(math, mathord, "\u03a0", "\\Pi", true);
1537 + defineSymbol(math, mathord, "\u03a1", "\\Rho", true);
1538 + defineSymbol(math, mathord, "\u03a3", "\\Sigma", true);
1539 + defineSymbol(math, mathord, "\u03a4", "\\Tau", true);
1540 + defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true);
1541 + defineSymbol(math, mathord, "\u03a6", "\\Phi", true);
1542 + defineSymbol(math, mathord, "\u03a7", "\\Chi", true);
1543 + defineSymbol(math, mathord, "\u03a8", "\\Psi", true);
1544 + defineSymbol(math, mathord, "\u03a9", "\\Omega", true);
1545 + defineSymbol(math, temml_open, "\u00ac", "\\neg", true);
1546 + defineSymbol(math, temml_open, "\u00ac", "\\lnot");
1547 + defineSymbol(math, textord, "\u22a4", "\\top");
1548 + defineSymbol(math, textord, "\u22a5", "\\bot");
1549 + defineSymbol(math, textord, "\u2205", "\\emptyset");
1550 + defineSymbol(math, textord, "\u2300", "\\varnothing");
1551 + defineSymbol(math, mathord, "\u03b1", "\\alpha", true);
1552 + defineSymbol(math, mathord, "\u03b2", "\\beta", true);
1553 + defineSymbol(math, mathord, "\u03b3", "\\gamma", true);
1554 + defineSymbol(math, mathord, "\u03b4", "\\delta", true);
1555 + defineSymbol(math, mathord, "\u03f5", "\\epsilon", true);
1556 + defineSymbol(math, mathord, "\u03b6", "\\zeta", true);
1557 + defineSymbol(math, mathord, "\u03b7", "\\eta", true);
1558 + defineSymbol(math, mathord, "\u03b8", "\\theta", true);
1559 + defineSymbol(math, mathord, "\u03b9", "\\iota", true);
1560 + defineSymbol(math, mathord, "\u03ba", "\\kappa", true);
1561 + defineSymbol(math, mathord, "\u03bb", "\\lambda", true);
1562 + defineSymbol(math, mathord, "\u03bc", "\\mu", true);
1563 + defineSymbol(math, mathord, "\u03bd", "\\nu", true);
1564 + defineSymbol(math, mathord, "\u03be", "\\xi", true);
1565 + defineSymbol(math, mathord, "\u03bf", "\\omicron", true);
1566 + defineSymbol(math, mathord, "\u03c0", "\\pi", true);
1567 + defineSymbol(math, mathord, "\u03c1", "\\rho", true);
1568 + defineSymbol(math, mathord, "\u03c3", "\\sigma", true);
1569 + defineSymbol(math, mathord, "\u03c4", "\\tau", true);
1570 + defineSymbol(math, mathord, "\u03c5", "\\upsilon", true);
1571 + defineSymbol(math, mathord, "\u03d5", "\\phi", true);
1572 + defineSymbol(math, mathord, "\u03c7", "\\chi", true);
1573 + defineSymbol(math, mathord, "\u03c8", "\\psi", true);
1574 + defineSymbol(math, mathord, "\u03c9", "\\omega", true);
1575 + defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true);
1576 + defineSymbol(math, mathord, "\u03d1", "\\vartheta", true);
1577 + defineSymbol(math, mathord, "\u03d6", "\\varpi", true);
1578 + defineSymbol(math, mathord, "\u03f1", "\\varrho", true);
1579 + defineSymbol(math, mathord, "\u03c2", "\\varsigma", true);
1580 + defineSymbol(math, mathord, "\u03c6", "\\varphi", true);
1581 + defineSymbol(math, mathord, "\u03d8", "\\Coppa", true);
1582 + defineSymbol(math, mathord, "\u03d9", "\\coppa", true);
1583 + defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true);
1584 + defineSymbol(math, mathord, "\u03de", "\\Koppa", true);
1585 + defineSymbol(math, mathord, "\u03df", "\\koppa", true);
1586 + defineSymbol(math, mathord, "\u03e0", "\\Sampi", true);
1587 + defineSymbol(math, mathord, "\u03e1", "\\sampi", true);
1588 + defineSymbol(math, mathord, "\u03da", "\\Stigma", true);
1589 + defineSymbol(math, mathord, "\u03db", "\\stigma", true);
1590 + defineSymbol(math, mathord, "\u2aeb", "\\Bot");
1591 + defineSymbol(math, bin, "\u2217", "\u2217", true);
1592 + defineSymbol(math, bin, "+", "+");
1593 + defineSymbol(math, bin, "\u2217", "*");
1594 + defineSymbol(math, bin, "\u2044", "/", true);
1595 + defineSymbol(math, bin, "\u2044", "\u2044");
1596 + defineSymbol(math, bin, "\u2212", "-", true);
1597 + defineSymbol(math, bin, "\u22c5", "\\cdot", true);
1598 + defineSymbol(math, bin, "\u2218", "\\circ", true);
1599 + defineSymbol(math, bin, "\u00f7", "\\div", true);
1600 + defineSymbol(math, bin, "\u00b1", "\\pm", true);
1601 + defineSymbol(math, bin, "\u00d7", "\\times", true);
1602 + defineSymbol(math, bin, "\u2229", "\\cap", true);
1603 + defineSymbol(math, bin, "\u222a", "\\cup", true);
1604 + defineSymbol(math, bin, "\u2216", "\\setminus", true);
1605 + defineSymbol(math, bin, "\u2227", "\\land");
1606 + defineSymbol(math, bin, "\u2228", "\\lor");
1607 + defineSymbol(math, bin, "\u2227", "\\wedge", true);
1608 + defineSymbol(math, bin, "\u2228", "\\vee", true);
1609 + defineSymbol(math, temml_open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages
1610 + defineSymbol(math, temml_close, "\u27e7", "\\rrbracket", true);
1611 + defineSymbol(math, temml_open, "\u27e8", "\\langle", true);
1612 + defineSymbol(math, temml_open, "\u27ea", "\\lAngle", true);
1613 + defineSymbol(math, temml_open, "\u2989", "\\llangle", true);
1614 + defineSymbol(math, temml_open, "|", "\\lvert");
1615 + defineSymbol(math, temml_open, "\u2016", "\\lVert", true);
1616 + defineSymbol(math, textord, "!", "\\oc"); // cmll package
1617 + defineSymbol(math, textord, "?", "\\wn");
1618 + defineSymbol(math, textord, "\u2193", "\\shpos");
1619 + defineSymbol(math, textord, "\u2195", "\\shift");
1620 + defineSymbol(math, textord, "\u2191", "\\shneg");
1621 + defineSymbol(math, temml_close, "?", "?");
1622 + defineSymbol(math, temml_close, "!", "!");
1623 + defineSymbol(math, temml_close, "‼", "‼");
1624 + defineSymbol(math, temml_close, "\u27e9", "\\rangle", true);
1625 + defineSymbol(math, temml_close, "\u27eb", "\\rAngle", true);
1626 + defineSymbol(math, temml_close, "\u298a", "\\rrangle", true);
1627 + defineSymbol(math, temml_close, "|", "\\rvert");
1628 + defineSymbol(math, temml_close, "\u2016", "\\rVert");
1629 + defineSymbol(math, temml_open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages
1630 + defineSymbol(math, temml_close, "\u2984", "\\rBrace", true);
1631 + defineSymbol(math, rel, "=", "\\equal", true);
1632 + defineSymbol(math, rel, ":", ":");
1633 + defineSymbol(math, rel, "\u2248", "\\approx", true);
1634 + defineSymbol(math, rel, "\u2245", "\\cong", true);
1635 + defineSymbol(math, rel, "\u2265", "\\ge");
1636 + defineSymbol(math, rel, "\u2265", "\\geq", true);
1637 + defineSymbol(math, rel, "\u2190", "\\gets");
1638 + defineSymbol(math, rel, ">", "\\gt", true);
1639 + defineSymbol(math, rel, "\u2208", "\\in", true);
1640 + defineSymbol(math, rel, "\u2209", "\\notin", true);
1641 + defineSymbol(math, rel, "\ue020", "\\@not");
1642 + defineSymbol(math, rel, "\u2282", "\\subset", true);
1643 + defineSymbol(math, rel, "\u2283", "\\supset", true);
1644 + defineSymbol(math, rel, "\u2286", "\\subseteq", true);
1645 + defineSymbol(math, rel, "\u2287", "\\supseteq", true);
1646 + defineSymbol(math, rel, "\u2288", "\\nsubseteq", true);
1647 + defineSymbol(math, rel, "\u2288", "\\nsubseteqq");
1648 + defineSymbol(math, rel, "\u2289", "\\nsupseteq", true);
1649 + defineSymbol(math, rel, "\u2289", "\\nsupseteqq");
1650 + defineSymbol(math, rel, "\u22a8", "\\models");
1651 + defineSymbol(math, rel, "\u2190", "\\leftarrow", true);
1652 + defineSymbol(math, rel, "\u2264", "\\le");
1653 + defineSymbol(math, rel, "\u2264", "\\leq", true);
1654 + defineSymbol(math, rel, "<", "\\lt", true);
1655 + defineSymbol(math, rel, "\u2192", "\\rightarrow", true);
1656 + defineSymbol(math, rel, "\u2192", "\\to");
1657 + defineSymbol(math, rel, "\u2271", "\\ngeq", true);
1658 + defineSymbol(math, rel, "\u2271", "\\ngeqq");
1659 + defineSymbol(math, rel, "\u2271", "\\ngeqslant");
1660 + defineSymbol(math, rel, "\u2270", "\\nleq", true);
1661 + defineSymbol(math, rel, "\u2270", "\\nleqq");
1662 + defineSymbol(math, rel, "\u2270", "\\nleqslant");
1663 + defineSymbol(math, rel, "\u2aeb", "\\Perp", true); //cmll package
1664 + defineSymbol(math, spacing, "\u00a0", "\\ ");
1665 + defineSymbol(math, spacing, "\u00a0", "\\space");
1666 + // Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{%
1667 + defineSymbol(math, spacing, "\u00a0", "\\nobreakspace");
1668 + defineSymbol(temml_text, spacing, "\u00a0", "\\ ");
1669 + defineSymbol(temml_text, spacing, "\u00a0", " ");
1670 + defineSymbol(temml_text, spacing, "\u00a0", "\\space");
1671 + defineSymbol(temml_text, spacing, "\u00a0", "\\nobreakspace");
1672 + defineSymbol(math, spacing, null, "\\nobreak");
1673 + defineSymbol(math, spacing, null, "\\allowbreak");
1674 + defineSymbol(math, punct, ",", ",");
1675 + defineSymbol(temml_text, punct, ":", ":");
1676 + defineSymbol(math, punct, ";", ";");
1677 + defineSymbol(math, bin, "\u22bc", "\\barwedge");
1678 + defineSymbol(math, bin, "\u22bb", "\\veebar");
1679 + defineSymbol(math, bin, "\u2299", "\\odot", true);
1680 + // Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here.
1681 + defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus");
1682 + defineSymbol(math, bin, "\u2297", "\\otimes", true);
1683 + defineSymbol(math, textord, "\u2202", "\\partial", true);
1684 + defineSymbol(math, bin, "\u2298", "\\oslash", true);
1685 + defineSymbol(math, bin, "\u229a", "\\circledcirc", true);
1686 + defineSymbol(math, bin, "\u22a1", "\\boxdot", true);
1687 + defineSymbol(math, bin, "\u25b3", "\\bigtriangleup");
1688 + defineSymbol(math, bin, "\u25bd", "\\bigtriangledown");
1689 + defineSymbol(math, bin, "\u2020", "\\dagger");
1690 + defineSymbol(math, bin, "\u22c4", "\\diamond");
1691 + defineSymbol(math, bin, "\u25c3", "\\triangleleft");
1692 + defineSymbol(math, bin, "\u25b9", "\\triangleright");
1693 + defineSymbol(math, temml_open, "{", "\\{");
1694 + defineSymbol(temml_text, textord, "{", "\\{");
1695 + defineSymbol(temml_text, textord, "{", "\\textbraceleft");
1696 + defineSymbol(math, temml_close, "}", "\\}");
1697 + defineSymbol(temml_text, textord, "}", "\\}");
1698 + defineSymbol(temml_text, textord, "}", "\\textbraceright");
1699 + defineSymbol(math, temml_open, "{", "\\lbrace");
1700 + defineSymbol(math, temml_close, "}", "\\rbrace");
1701 + defineSymbol(math, temml_open, "[", "\\lbrack", true);
1702 + defineSymbol(temml_text, textord, "[", "\\lbrack", true);
1703 + defineSymbol(math, temml_close, "]", "\\rbrack", true);
1704 + defineSymbol(temml_text, textord, "]", "\\rbrack", true);
1705 + defineSymbol(math, temml_open, "(", "\\lparen", true);
1706 + defineSymbol(math, temml_close, ")", "\\rparen", true);
1707 + defineSymbol(math, temml_open, "⦇", "\\llparenthesis", true);
1708 + defineSymbol(math, temml_close, "⦈", "\\rrparenthesis", true);
1709 + defineSymbol(temml_text, textord, "<", "\\textless", true); // in T1 fontenc
1710 + defineSymbol(temml_text, textord, ">", "\\textgreater", true); // in T1 fontenc
1711 + defineSymbol(math, temml_open, "\u230a", "\\lfloor", true);
1712 + defineSymbol(math, temml_close, "\u230b", "\\rfloor", true);
1713 + defineSymbol(math, temml_open, "\u2308", "\\lceil", true);
1714 + defineSymbol(math, temml_close, "\u2309", "\\rceil", true);
1715 + defineSymbol(math, textord, "\\", "\\backslash");
1716 + defineSymbol(math, textord, "|", "|");
1717 + defineSymbol(math, textord, "|", "\\vert");
1718 + defineSymbol(temml_text, textord, "|", "\\textbar", true); // in T1 fontenc
1719 + defineSymbol(math, textord, "\u2016", "\\|");
1720 + defineSymbol(math, textord, "\u2016", "\\Vert");
1721 + defineSymbol(temml_text, textord, "\u2016", "\\textbardbl");
1722 + defineSymbol(temml_text, textord, "~", "\\textasciitilde");
1723 + defineSymbol(temml_text, textord, "\\", "\\textbackslash");
1724 + defineSymbol(temml_text, textord, "^", "\\textasciicircum");
1725 + defineSymbol(math, rel, "\u2191", "\\uparrow", true);
1726 + defineSymbol(math, rel, "\u21d1", "\\Uparrow", true);
1727 + defineSymbol(math, rel, "\u2193", "\\downarrow", true);
1728 + defineSymbol(math, rel, "\u21d3", "\\Downarrow", true);
1729 + defineSymbol(math, rel, "\u2195", "\\updownarrow", true);
1730 + defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true);
1731 + defineSymbol(math, op, "\u2210", "\\coprod");
1732 + defineSymbol(math, op, "\u22c1", "\\bigvee");
1733 + defineSymbol(math, op, "\u22c0", "\\bigwedge");
1734 + defineSymbol(math, op, "\u2a04", "\\biguplus");
1735 + defineSymbol(math, op, "\u2a04", "\\bigcupplus");
1736 + defineSymbol(math, op, "\u2a03", "\\bigcupdot");
1737 + defineSymbol(math, op, "\u2a07", "\\bigdoublevee");
1738 + defineSymbol(math, op, "\u2a08", "\\bigdoublewedge");
1739 + defineSymbol(math, op, "\u22c2", "\\bigcap");
1740 + defineSymbol(math, op, "\u22c3", "\\bigcup");
1741 + defineSymbol(math, op, "\u222b", "\\int");
1742 + defineSymbol(math, op, "\u222b", "\\intop");
1743 + defineSymbol(math, op, "\u222c", "\\iint");
1744 + defineSymbol(math, op, "\u222d", "\\iiint");
1745 + defineSymbol(math, op, "\u220f", "\\prod");
1746 + defineSymbol(math, op, "\u2211", "\\sum");
1747 + defineSymbol(math, op, "\u2a02", "\\bigotimes");
1748 + defineSymbol(math, op, "\u2a01", "\\bigoplus");
1749 + defineSymbol(math, op, "\u2a00", "\\bigodot");
1750 + defineSymbol(math, op, "\u2a09", "\\bigtimes");
1751 + defineSymbol(math, op, "\u222e", "\\oint");
1752 + defineSymbol(math, op, "\u222f", "\\oiint");
1753 + defineSymbol(math, op, "\u2230", "\\oiiint");
1754 + defineSymbol(math, op, "\u2231", "\\intclockwise");
1755 + defineSymbol(math, op, "\u2232", "\\varointclockwise");
1756 + defineSymbol(math, op, "\u2a0c", "\\iiiint");
1757 + defineSymbol(math, op, "\u2a0d", "\\intbar");
1758 + defineSymbol(math, op, "\u2a0e", "\\intBar");
1759 + defineSymbol(math, op, "\u2a0f", "\\fint");
1760 + defineSymbol(math, op, "\u2a12", "\\rppolint");
1761 + defineSymbol(math, op, "\u2a13", "\\scpolint");
1762 + defineSymbol(math, op, "\u2a15", "\\pointint");
1763 + defineSymbol(math, op, "\u2a16", "\\sqint");
1764 + defineSymbol(math, op, "\u2a17", "\\intlarhk");
1765 + defineSymbol(math, op, "\u2a18", "\\intx");
1766 + defineSymbol(math, op, "\u2a19", "\\intcap");
1767 + defineSymbol(math, op, "\u2a1a", "\\intcup");
1768 + defineSymbol(math, op, "\u2a05", "\\bigsqcap");
1769 + defineSymbol(math, op, "\u2a06", "\\bigsqcup");
1770 + defineSymbol(math, op, "\u222b", "\\smallint");
1771 + defineSymbol(temml_text, inner, "\u2026", "\\textellipsis");
1772 + defineSymbol(math, inner, "\u2026", "\\mathellipsis");
1773 + defineSymbol(temml_text, inner, "\u2026", "\\ldots", true);
1774 + defineSymbol(math, inner, "\u2026", "\\ldots", true);
1775 + defineSymbol(math, inner, "\u22f0", "\\iddots", true);
1776 + defineSymbol(math, inner, "\u22ef", "\\@cdots", true);
1777 + defineSymbol(math, inner, "\u22f1", "\\ddots", true);
1778 + defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro
1779 + defineSymbol(temml_text, textord, "\u22ee", "\\varvdots");
1780 + defineSymbol(math, accent, "\u02ca", "\\acute");
1781 + defineSymbol(math, accent, "\u0060", "\\grave");
1782 + defineSymbol(math, accent, "\u00a8", "\\ddot");
1783 + defineSymbol(math, accent, "\u2026", "\\dddot");
1784 + defineSymbol(math, accent, "\u2026\u002e", "\\ddddot");
1785 + defineSymbol(math, accent, "\u007e", "\\tilde");
1786 + defineSymbol(math, accent, "\u203e", "\\bar");
1787 + defineSymbol(math, accent, "\u02d8", "\\breve");
1788 + defineSymbol(math, accent, "\u02c7", "\\check");
1789 + defineSymbol(math, accent, "\u005e", "\\hat");
1790 + defineSymbol(math, accent, "\u2192", "\\vec");
1791 + defineSymbol(math, accent, "\u02d9", "\\dot");
1792 + defineSymbol(math, accent, "\u02da", "\\mathring");
1793 + defineSymbol(math, mathord, "\u0131", "\\imath", true);
1794 + defineSymbol(math, mathord, "\u0237", "\\jmath", true);
1795 + defineSymbol(math, textord, "\u0131", "\u0131");
1796 + defineSymbol(math, textord, "\u0237", "\u0237");
1797 + defineSymbol(temml_text, textord, "\u0131", "\\i", true);
1798 + defineSymbol(temml_text, textord, "\u0237", "\\j", true);
1799 + defineSymbol(temml_text, textord, "\u00df", "\\ss", true);
1800 + defineSymbol(temml_text, textord, "\u00e6", "\\ae", true);
1801 + defineSymbol(temml_text, textord, "\u0153", "\\oe", true);
1802 + defineSymbol(temml_text, textord, "\u00f8", "\\o", true);
1803 + defineSymbol(math, mathord, "\u00f8", "\\o", true);
1804 + defineSymbol(temml_text, textord, "\u00c6", "\\AE", true);
1805 + defineSymbol(temml_text, textord, "\u0152", "\\OE", true);
1806 + defineSymbol(temml_text, textord, "\u00d8", "\\O", true);
1807 + defineSymbol(math, mathord, "\u00d8", "\\O", true);
1808 + defineSymbol(temml_text, accent, "\u02ca", "\\'"); // acute
1809 + defineSymbol(temml_text, accent, "\u02cb", "\\`"); // grave
1810 + defineSymbol(temml_text, accent, "\u02c6", "\\^"); // circumflex
1811 + defineSymbol(temml_text, accent, "\u02dc", "\\~"); // tilde
1812 + defineSymbol(temml_text, accent, "\u02c9", "\\="); // macron
1813 + defineSymbol(temml_text, accent, "\u02d8", "\\u"); // breve
1814 + defineSymbol(temml_text, accent, "\u02d9", "\\."); // dot above
1815 + defineSymbol(temml_text, accent, "\u00b8", "\\c"); // cedilla
1816 + defineSymbol(temml_text, accent, "\u02da", "\\r"); // ring above
1817 + defineSymbol(temml_text, accent, "\u02c7", "\\v"); // caron
1818 + defineSymbol(temml_text, accent, "\u00a8", '\\"'); // diaresis
1819 + defineSymbol(temml_text, accent, "\u02dd", "\\H"); // double acute
1820 + defineSymbol(math, accent, "\u02ca", "\\'"); // acute
1821 + defineSymbol(math, accent, "\u02cb", "\\`"); // grave
1822 + defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex
1823 + defineSymbol(math, accent, "\u02dc", "\\~"); // tilde
1824 + defineSymbol(math, accent, "\u02c9", "\\="); // macron
1825 + defineSymbol(math, accent, "\u02d8", "\\u"); // breve
1826 + defineSymbol(math, accent, "\u02d9", "\\."); // dot above
1827 + defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla
1828 + defineSymbol(math, accent, "\u02da", "\\r"); // ring above
1829 + defineSymbol(math, accent, "\u02c7", "\\v"); // caron
1830 + defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis
1831 + defineSymbol(math, accent, "\u02dd", "\\H"); // double acute
1832 +
1833 + // These ligatures are detected and created in Parser.js's `formLigatures`.
1834 + const ligatures = {
1835 + "--": true,
1836 + "---": true,
1837 + "``": true,
1838 + "''": true
1839 + };
1840 +
1841 + defineSymbol(temml_text, textord, "\u2013", "--", true);
1842 + defineSymbol(temml_text, textord, "\u2013", "\\textendash");
1843 + defineSymbol(temml_text, textord, "\u2014", "---", true);
1844 + defineSymbol(temml_text, textord, "\u2014", "\\textemdash");
1845 + defineSymbol(temml_text, textord, "\u2018", "`", true);
1846 + defineSymbol(temml_text, textord, "\u2018", "\\textquoteleft");
1847 + defineSymbol(temml_text, textord, "\u2019", "'", true);
1848 + defineSymbol(temml_text, textord, "\u2019", "\\textquoteright");
1849 + defineSymbol(temml_text, textord, "\u201c", "``", true);
1850 + defineSymbol(temml_text, textord, "\u201c", "\\textquotedblleft");
1851 + defineSymbol(temml_text, textord, "\u201d", "''", true);
1852 + defineSymbol(temml_text, textord, "\u201d", "\\textquotedblright");
1853 + // \degree from gensymb package
1854 + defineSymbol(math, textord, "\u00b0", "\\degree", true);
1855 + defineSymbol(temml_text, textord, "\u00b0", "\\degree");
1856 + // \textdegree from inputenc package
1857 + defineSymbol(temml_text, textord, "\u00b0", "\\textdegree", true);
1858 + // TODO: In LaTeX, \pounds can generate a different character in text and math
1859 + // mode, but among our fonts, only Main-Regular defines this character "163".
1860 + defineSymbol(math, textord, "\u00a3", "\\pounds");
1861 + defineSymbol(math, textord, "\u00a3", "\\mathsterling", true);
1862 + defineSymbol(temml_text, textord, "\u00a3", "\\pounds");
1863 + defineSymbol(temml_text, textord, "\u00a3", "\\textsterling", true);
1864 + defineSymbol(math, textord, "\u2720", "\\maltese");
1865 + defineSymbol(temml_text, textord, "\u2720", "\\maltese");
1866 + defineSymbol(math, textord, "\u20ac", "\\euro", true);
1867 + defineSymbol(temml_text, textord, "\u20ac", "\\euro", true);
1868 + defineSymbol(temml_text, textord, "\u20ac", "\\texteuro");
1869 + defineSymbol(math, textord, "\u00a9", "\\copyright", true);
1870 + defineSymbol(temml_text, textord, "\u00a9", "\\textcopyright");
1871 + defineSymbol(math, textord, "\u2300", "\\diameter", true);
1872 + defineSymbol(temml_text, textord, "\u2300", "\\diameter");
1873 +
1874 + // Italic Greek
1875 + defineSymbol(math, textord, "𝛤", "\\varGamma");
1876 + defineSymbol(math, textord, "𝛥", "\\varDelta");
1877 + defineSymbol(math, textord, "𝛩", "\\varTheta");
1878 + defineSymbol(math, textord, "𝛬", "\\varLambda");
1879 + defineSymbol(math, textord, "𝛯", "\\varXi");
1880 + defineSymbol(math, textord, "𝛱", "\\varPi");
1881 + defineSymbol(math, textord, "𝛴", "\\varSigma");
1882 + defineSymbol(math, textord, "𝛶", "\\varUpsilon");
1883 + defineSymbol(math, textord, "𝛷", "\\varPhi");
1884 + defineSymbol(math, textord, "𝛹", "\\varPsi");
1885 + defineSymbol(math, textord, "𝛺", "\\varOmega");
1886 + defineSymbol(temml_text, textord, "𝛤", "\\varGamma");
1887 + defineSymbol(temml_text, textord, "𝛥", "\\varDelta");
1888 + defineSymbol(temml_text, textord, "𝛩", "\\varTheta");
1889 + defineSymbol(temml_text, textord, "𝛬", "\\varLambda");
1890 + defineSymbol(temml_text, textord, "𝛯", "\\varXi");
1891 + defineSymbol(temml_text, textord, "𝛱", "\\varPi");
1892 + defineSymbol(temml_text, textord, "𝛴", "\\varSigma");
1893 + defineSymbol(temml_text, textord, "𝛶", "\\varUpsilon");
1894 + defineSymbol(temml_text, textord, "𝛷", "\\varPhi");
1895 + defineSymbol(temml_text, textord, "𝛹", "\\varPsi");
1896 + defineSymbol(temml_text, textord, "𝛺", "\\varOmega");
1897 +
1898 +
1899 + // There are lots of symbols which are the same, so we add them in afterwards.
1900 + // All of these are textords in math mode
1901 + const mathTextSymbols = '0123456789/@."';
1902 + for (let i = 0; i < mathTextSymbols.length; i++) {
1903 + const ch = mathTextSymbols.charAt(i);
1904 + defineSymbol(math, textord, ch, ch);
1905 + }
1906 +
1907 + // All of these are textords in text mode
1908 + const textSymbols = '0123456789!@*()-=+";:?/.,';
1909 + for (let i = 0; i < textSymbols.length; i++) {
1910 + const ch = textSymbols.charAt(i);
1911 + defineSymbol(temml_text, textord, ch, ch);
1912 + }
1913 +
1914 + // All of these are textords in text mode, and mathords in math mode
1915 + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1916 + for (let i = 0; i < letters.length; i++) {
1917 + const ch = letters.charAt(i);
1918 + defineSymbol(math, mathord, ch, ch);
1919 + defineSymbol(temml_text, textord, ch, ch);
1920 + }
1921 +
1922 + // Some more letters in Unicode Basic Multilingual Plane.
1923 + const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ";
1924 + for (let i = 0; i < narrow.length; i++) {
1925 + const ch = narrow.charAt(i);
1926 + defineSymbol(math, mathord, ch, ch);
1927 + defineSymbol(temml_text, textord, ch, ch);
1928 + }
1929 +
1930 + // The next loop loads wide (surrogate pair) characters.
1931 + // We support some letters in the Unicode range U+1D400 to U+1D7FF,
1932 + // Mathematical Alphanumeric Symbols.
1933 + let wideChar = "";
1934 + for (let i = 0; i < letters.length; i++) {
1935 + // The hex numbers in the next line are a surrogate pair.
1936 + // 0xD835 is the high surrogate for all letters in the range we support.
1937 + // 0xDC00 is the low surrogate for bold A.
1938 + wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold
1939 + defineSymbol(math, mathord, wideChar, wideChar);
1940 + defineSymbol(temml_text, textord, wideChar, wideChar);
1941 +
1942 + wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic
1943 + defineSymbol(math, mathord, wideChar, wideChar);
1944 + defineSymbol(temml_text, textord, wideChar, wideChar);
1945 +
1946 + wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic
1947 + defineSymbol(math, mathord, wideChar, wideChar);
1948 + defineSymbol(temml_text, textord, wideChar, wideChar);
1949 +
1950 + wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur
1951 + defineSymbol(math, mathord, wideChar, wideChar);
1952 + defineSymbol(temml_text, textord, wideChar, wideChar);
1953 +
1954 + wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif
1955 + defineSymbol(math, mathord, wideChar, wideChar);
1956 + defineSymbol(temml_text, textord, wideChar, wideChar);
1957 +
1958 + wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold
1959 + defineSymbol(math, mathord, wideChar, wideChar);
1960 + defineSymbol(temml_text, textord, wideChar, wideChar);
1961 +
1962 + wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic
1963 + defineSymbol(math, mathord, wideChar, wideChar);
1964 + defineSymbol(temml_text, textord, wideChar, wideChar);
1965 +
1966 + wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace
1967 + defineSymbol(math, mathord, wideChar, wideChar);
1968 + defineSymbol(temml_text, textord, wideChar, wideChar);
1969 +
1970 + wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck
1971 + defineSymbol(math, mathord, wideChar, wideChar);
1972 + defineSymbol(temml_text, textord, wideChar, wideChar);
1973 +
1974 + const ch = letters.charAt(i);
1975 + wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic
1976 + defineSymbol(math, mathord, ch, wideChar);
1977 + defineSymbol(temml_text, textord, ch, wideChar);
1978 + }
1979 +
1980 + // Next, some wide character numerals
1981 + for (let i = 0; i < 10; i++) {
1982 + wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold
1983 + defineSymbol(math, mathord, wideChar, wideChar);
1984 + defineSymbol(temml_text, textord, wideChar, wideChar);
1985 +
1986 + wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif
1987 + defineSymbol(math, mathord, wideChar, wideChar);
1988 + defineSymbol(temml_text, textord, wideChar, wideChar);
1989 +
1990 + wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans
1991 + defineSymbol(math, mathord, wideChar, wideChar);
1992 + defineSymbol(temml_text, textord, wideChar, wideChar);
1993 +
1994 + wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace
1995 + defineSymbol(math, mathord, wideChar, wideChar);
1996 + defineSymbol(temml_text, textord, wideChar, wideChar);
1997 + }
1998 +
1999 + /*
2000 + * Neither Firefox nor Chrome support hard line breaks or soft line breaks.
2001 + * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs)
2002 + * So Temml has work-arounds for both hard and soft breaks.
2003 + * The work-arounds sadly do not work simultaneously. Any top-level hard
2004 + * break makes soft line breaks impossible.
2005 + *
2006 + * Hard breaks are simulated by creating a <mtable> and putting each line in its own <mtr>.
2007 + *
2008 + * To create soft line breaks, Temml avoids using the <semantics> and <annotation> tags.
2009 + * Then the top level of a <math> element can be occupied by <mrow> elements, and the browser
2010 + * will break after a <mrow> if the expression extends beyond the container limit.
2011 + *
2012 + * The default is for soft line breaks after each top-level binary or
2013 + * relational operator, per TeXbook p. 173. So we gather the expression into <mrow>s so that
2014 + * each <mrow> ends in a binary or relational operator.
2015 + *
2016 + * An option is for soft line breaks before an "=" sign. That changes the <mrow>s.
2017 + *
2018 + * Soft line breaks will not work in Chromium and Safari, only Firefox.
2019 + *
2020 + * Hopefully browsers will someday do their own linebreaking and we will be able to delete
2021 + * much of this module.
2022 + */
2023 +
2024 + const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
2025 + const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
2026 +
2027 + function setLineBreaks(expression, wrapMode, isDisplayMode) {
2028 + const mtrs = [];
2029 + let mrows = [];
2030 + let block = [];
2031 + let numTopLevelEquals = 0;
2032 + let i = 0;
2033 + let level = 0;
2034 + while (i < expression.length) {
2035 + while (expression[i] instanceof DocumentFragment) {
2036 + expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
2037 + }
2038 + const node = expression[i];
2039 + if (node.attributes && node.attributes.linebreak &&
2040 + node.attributes.linebreak === "newline") {
2041 + // A hard line break. Create a <mtr> for the current block.
2042 + if (block.length > 0) {
2043 + mrows.push(new mathMLTree.MathNode("mrow", block));
2044 + }
2045 + mrows.push(node);
2046 + block = [];
2047 + const mtd = new mathMLTree.MathNode("mtd", mrows);
2048 + mtd.style.textAlign = "left";
2049 + mtrs.push(new mathMLTree.MathNode("mtr", [mtd]));
2050 + mrows = [];
2051 + i += 1;
2052 + continue
2053 + }
2054 + block.push(node);
2055 + if (node.type && node.type === "mo" && node.children.length === 1 &&
2056 + !Object.hasOwn(node.attributes, "movablelimits")) {
2057 + const ch = node.children[0].text;
2058 + if (openDelims.indexOf(ch) > -1) {
2059 + level += 1;
2060 + } else if (closeDelims.indexOf(ch) > -1) {
2061 + level -= 1;
2062 + } else if (level === 0 && wrapMode === "=" && ch === "=") {
2063 + numTopLevelEquals += 1;
2064 + if (numTopLevelEquals > 1) {
2065 + block.pop();
2066 + // Start a new block. (Insert a soft linebreak.)
2067 + const element = new mathMLTree.MathNode("mrow", block);
2068 + mrows.push(element);
2069 + block = [node];
2070 + }
2071 + } else if (level === 0 && wrapMode === "tex" && ch !== "∇") {
2072 + // Check if the following node is a \nobreak text node, e.g. "~""
2073 + const next = i < expression.length - 1 ? expression[i + 1] : null;
2074 + let glueIsFreeOfNobreak = true;
2075 + if (
2076 + !(
2077 + next &&
2078 + next.type === "mtext" &&
2079 + next.attributes.linebreak &&
2080 + next.attributes.linebreak === "nobreak"
2081 + )
2082 + ) {
2083 + // We may need to start a new block.
2084 + // First, put any post-operator glue on same line as operator.
2085 + for (let j = i + 1; j < expression.length; j++) {
2086 + const nd = expression[j];
2087 + if (
2088 + nd.type &&
2089 + nd.type === "mspace" &&
2090 + !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
2091 + ) {
2092 + block.push(nd);
2093 + i += 1;
2094 + if (
2095 + nd.attributes &&
2096 + nd.attributes.linebreak &&
2097 + nd.attributes.linebreak === "nobreak"
2098 + ) {
2099 + glueIsFreeOfNobreak = false;
2100 + }
2101 + } else {
2102 + break;
2103 + }
2104 + }
2105 + }
2106 + if (glueIsFreeOfNobreak) {
2107 + // Start a new block. (Insert a soft linebreak.)
2108 + const element = new mathMLTree.MathNode("mrow", block);
2109 + mrows.push(element);
2110 + block = [];
2111 + }
2112 + }
2113 + }
2114 + i += 1;
2115 + }
2116 + if (block.length > 0) {
2117 + const element = new mathMLTree.MathNode("mrow", block);
2118 + mrows.push(element);
2119 + }
2120 + if (mtrs.length > 0) {
2121 + const mtd = new mathMLTree.MathNode("mtd", mrows);
2122 + mtd.style.textAlign = "left";
2123 + const mtr = new mathMLTree.MathNode("mtr", [mtd]);
2124 + mtrs.push(mtr);
2125 + const mtable = new mathMLTree.MathNode("mtable", mtrs);
2126 + if (!isDisplayMode) {
2127 + mtable.setAttribute("columnalign", "left");
2128 + mtable.setAttribute("rowspacing", "0em");
2129 + }
2130 + return mtable
2131 + }
2132 + return mathMLTree.newDocumentFragment(mrows);
2133 + }
2134 +
2135 + /**
2136 + * This file converts a parse tree into a corresponding MathML tree. The main
2137 + * entry point is the `buildMathML` function, which takes a parse tree from the
2138 + * parser.
2139 + */
2140 +
2141 +
2142 + /**
2143 + * Takes a symbol and converts it into a MathML text node after performing
2144 + * optional replacement from symbols.js.
2145 + */
2146 + const makeText = function(text, mode, style) {
2147 + if (
2148 + symbols[mode][text] &&
2149 + symbols[mode][text].replace &&
2150 + text.charCodeAt(0) !== 0xd835 &&
2151 + !(
2152 + Object.prototype.hasOwnProperty.call(ligatures, text) &&
2153 + style &&
2154 + ((style.fontFamily && style.fontFamily.slice(4, 6) === "tt") ||
2155 + (style.font && style.font.slice(4, 6) === "tt"))
2156 + )
2157 + ) {
2158 + text = symbols[mode][text].replace;
2159 + }
2160 +
2161 + return new mathMLTree.TextNode(text);
2162 + };
2163 +
2164 + const copyChar = (newRow, child) => {
2165 + if (newRow.children.length === 0 ||
2166 + newRow.children[newRow.children.length - 1].type !== "mtext") {
2167 + const mtext = new mathMLTree.MathNode(
2168 + "mtext",
2169 + [new mathMLTree.TextNode(child.children[0].text)]
2170 + );
2171 + newRow.children.push(mtext);
2172 + } else {
2173 + newRow.children[newRow.children.length - 1].children[0].text += child.children[0].text;
2174 + }
2175 + };
2176 +
2177 + const consolidateText = mrow => {
2178 + // If possible, consolidate adjacent <mtext> elements into a single element.
2179 + if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow }
2180 + if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{}
2181 + const newRow = new mathMLTree.MathNode("mrow");
2182 + for (let i = 0; i < mrow.children.length; i++) {
2183 + const child = mrow.children[i];
2184 + if (child.type === "mtext" && Object.keys(child.attributes).length === 0) {
2185 + copyChar(newRow, child);
2186 + } else if (child.type === "mrow") {
2187 + // We'll also check the children of an mrow. One level only. No recursion.
2188 + let canConsolidate = true;
2189 + for (let j = 0; j < child.children.length; j++) {
2190 + const grandChild = child.children[j];
2191 + if (grandChild.type !== "mtext" || Object.keys(child.attributes).length !== 0) {
2192 + canConsolidate = false;
2193 + break
2194 + }
2195 + }
2196 + if (canConsolidate) {
2197 + for (let j = 0; j < child.children.length; j++) {
2198 + const grandChild = child.children[j];
2199 + copyChar(newRow, grandChild);
2200 + }
2201 + } else {
2202 + newRow.children.push(child);
2203 + }
2204 + } else {
2205 + newRow.children.push(child);
2206 + }
2207 + }
2208 + for (let i = 0; i < newRow.children.length; i++) {
2209 + if (newRow.children[i].type === "mtext") {
2210 + const mtext = newRow.children[i];
2211 + // Firefox does not render a space at either end of an <mtext> string.
2212 + // To get proper rendering, we replace leading or trailing spaces with no-break spaces.
2213 + if (mtext.children[0].text.charAt(0) === " ") {
2214 + mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1);
2215 + }
2216 + const L = mtext.children[0].text.length;
2217 + if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") {
2218 + mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0";
2219 + }
2220 + for (const [key, value] of Object.entries(mrow.attributes)) {
2221 + mtext.attributes[key] = value;
2222 + }
2223 + }
2224 + }
2225 + if (newRow.children.length === 1 && newRow.children[0].type === "mtext") {
2226 + return newRow.children[0]; // A consolidated <mtext>
2227 + } else {
2228 + return newRow
2229 + }
2230 + };
2231 +
2232 + /**
2233 + * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
2234 + * unless the array has length 1. Always returns a single node.
2235 + */
2236 + const makeRow = function(body, semisimple = false) {
2237 + if (body.length === 1 && !(body[0] instanceof DocumentFragment)) {
2238 + return body[0];
2239 + } else if (!semisimple) {
2240 + // Suppress spacing on <mo> nodes at both ends of the row.
2241 + if (body[0] instanceof MathNode && body[0].type === "mo" && !body[0].attributes.fence) {
2242 + body[0].attributes.lspace = "0em";
2243 + body[0].attributes.rspace = "0em";
2244 + }
2245 + const end = body.length - 1;
2246 + if (body[end] instanceof MathNode && body[end].type === "mo" && !body[end].attributes.fence) {
2247 + body[end].attributes.lspace = "0em";
2248 + body[end].attributes.rspace = "0em";
2249 + }
2250 + }
2251 + return new mathMLTree.MathNode("mrow", body);
2252 + };
2253 +
2254 + /**
2255 + * Check for <mi>.</mi> which is how a dot renders in MathML,
2256 + * or <mo separator="true" lspace="0em" rspace="0em">,</mo>
2257 + * which is how a braced comma {,} renders in MathML
2258 + */
2259 + function isNumberPunctuation(group) {
2260 + if (!group) {
2261 + return false
2262 + }
2263 + if (group.type === 'mi' && group.children.length === 1) {
2264 + const child = group.children[0];
2265 + return child instanceof TextNode && child.text === '.'
2266 + } else if (group.type === "mtext" && group.children.length === 1) {
2267 + const child = group.children[0];
2268 + return child instanceof TextNode && child.text === '\u2008' // punctuation space
2269 + } else if (group.type === 'mo' && group.children.length === 1 &&
2270 + group.getAttribute('separator') === 'true' &&
2271 + group.getAttribute('lspace') === '0em' &&
2272 + group.getAttribute('rspace') === '0em') {
2273 + const child = group.children[0];
2274 + return child instanceof TextNode && child.text === ','
2275 + } else {
2276 + return false
2277 + }
2278 + }
2279 + const isComma = (expression, i) => {
2280 + const node = expression[i];
2281 + const followingNode = expression[i + 1];
2282 + return (node.type === "atom" && node.text === ",") &&
2283 + // Don't consolidate if there is a space after the comma.
2284 + node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
2285 + };
2286 +
2287 + const isRel = item => {
2288 + return (item.type === "atom" && item.family === "rel") ||
2289 + (item.type === "mclass" && item.mclass === "mrel")
2290 + };
2291 +
2292 + /**
2293 + * Takes a list of nodes, builds them, and returns a list of the generated
2294 + * MathML nodes. Also do a couple chores along the way:
2295 + * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}.
2296 + * (2) Suppress spacing between two adjacent relations.
2297 + */
2298 + const buildExpression = function(expression, style, semisimple = false) {
2299 + if (!semisimple && expression.length === 1) {
2300 + const group = buildGroup$1(expression[0], style);
2301 + if (group instanceof MathNode && group.type === "mo") {
2302 + // When TeX writers want to suppress spacing on an operator,
2303 + // they often put the operator by itself inside braces.
2304 + group.setAttribute("lspace", "0em");
2305 + group.setAttribute("rspace", "0em");
2306 + }
2307 + return [group];
2308 + }
2309 +
2310 + const groups = [];
2311 + const groupArray = [];
2312 + let lastGroup;
2313 + for (let i = 0; i < expression.length; i++) {
2314 + groupArray.push(buildGroup$1(expression[i], style));
2315 + }
2316 +
2317 + for (let i = 0; i < groupArray.length; i++) {
2318 + const group = groupArray[i];
2319 +
2320 + // Suppress spacing between adjacent relations
2321 + if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) {
2322 + group.setAttribute("rspace", "0em");
2323 + }
2324 + if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) {
2325 + group.setAttribute("lspace", "0em");
2326 + }
2327 +
2328 + // Concatenate numbers
2329 + if (group.type === 'mn' && lastGroup && lastGroup.type === 'mn') {
2330 + // Concatenate <mn>...</mn> followed by <mi>.</mi>
2331 + lastGroup.children.push(...group.children);
2332 + continue
2333 + } else if (isNumberPunctuation(group) && lastGroup && lastGroup.type === 'mn') {
2334 + // Concatenate <mn>...</mn> followed by <mi>.</mi>
2335 + lastGroup.children.push(...group.children);
2336 + continue
2337 + } else if (lastGroup && lastGroup.type === "mn" && i < groupArray.length - 1 &&
2338 + groupArray[i + 1].type === "mn" && isComma(expression, i)) {
2339 + lastGroup.children.push(...group.children);
2340 + continue
2341 + } else if (group.type === 'mn' && isNumberPunctuation(lastGroup)) {
2342 + // Concatenate <mi>.</mi> followed by <mn>...</mn>
2343 + group.children = [...lastGroup.children, ...group.children];
2344 + groups.pop();
2345 + } else if ((group.type === 'msup' || group.type === 'msub') &&
2346 + group.children.length >= 1 && lastGroup &&
2347 + (lastGroup.type === 'mn' || isNumberPunctuation(lastGroup))) {
2348 + // Put preceding <mn>...</mn> or <mi>.</mi> inside base of
2349 + // <msup><mn>...base...</mn>...exponent...</msup> (or <msub>)
2350 + const base = group.children[0];
2351 + if (base instanceof MathNode && base.type === 'mn' && lastGroup) {
2352 + base.children = [...lastGroup.children, ...base.children];
2353 + groups.pop();
2354 + }
2355 + }
2356 + groups.push(group);
2357 + lastGroup = group;
2358 + }
2359 + return groups
2360 + };
2361 +
2362 + /**
2363 + * Equivalent to buildExpression, but wraps the elements in an <mrow>
2364 + * if there's more than one. Returns a single node instead of an array.
2365 + */
2366 + const buildExpressionRow = function(expression, style, semisimple = false) {
2367 + return makeRow(buildExpression(expression, style, semisimple), semisimple);
2368 + };
2369 +
2370 + /**
2371 + * Takes a group from the parser and calls the appropriate groupBuilders function
2372 + * on it to produce a MathML node.
2373 + */
2374 + const buildGroup$1 = function(group, style) {
2375 + if (!group) {
2376 + return new mathMLTree.MathNode("mrow");
2377 + }
2378 +
2379 + if (_mathmlGroupBuilders[group.type]) {
2380 + // Call the groupBuilders function
2381 + const result = _mathmlGroupBuilders[group.type](group, style);
2382 + return result;
2383 + } else {
2384 + throw new ParseError("Got group of unknown type: '" + group.type + "'");
2385 + }
2386 + };
2387 +
2388 + const glue$1 = _ => {
2389 + return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" })
2390 + };
2391 +
2392 + const labelContainers = ["mrow", "mtd", "mtable", "mtr"];
2393 + const getLabel = parent => {
2394 + for (const node of parent.children) {
2395 + if (node.type && labelContainers.includes(node.type)) {
2396 + if (node.classes && node.classes[0] === "tml-label") {
2397 + const label = node.label;
2398 + return label
2399 + } else {
2400 + const label = getLabel(node);
2401 + if (label) { return label }
2402 + }
2403 + } else if (!node.type) {
2404 + const label = getLabel(node);
2405 + if (label) { return label }
2406 + }
2407 + }
2408 + };
2409 +
2410 + const taggedExpression = (expression, tag, style, leqno) => {
2411 + tag = buildExpressionRow(tag[0].body, style);
2412 + tag = consolidateText(tag);
2413 + tag.classes.push("tml-tag");
2414 +
2415 + const label = getLabel(expression); // from a \label{} function.
2416 + expression = new mathMLTree.MathNode("mtd", [expression]);
2417 + const rowArray = [glue$1(), expression, glue$1()];
2418 + rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right");
2419 + rowArray[leqno ? 0 : 2].children.push(tag);
2420 + const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]);
2421 + if (label) { mtr.setAttribute("id", label); }
2422 + const table = new mathMLTree.MathNode("mtable", [mtr]);
2423 + table.style.width = "100%";
2424 + table.setAttribute("displaystyle", "true");
2425 + return table
2426 + };
2427 +
2428 + /**
2429 + * Takes a full parse tree and settings and builds a MathML representation of
2430 + * it.
2431 + */
2432 + function buildMathML(tree, texExpression, style, settings) {
2433 + // Strip off outer tag wrapper for processing below.
2434 + let tag = null;
2435 + if (tree.length === 1 && tree[0].type === "tag") {
2436 + tag = tree[0].tag;
2437 + tree = tree[0].body;
2438 + }
2439 +
2440 + const expression = buildExpression(tree, style);
2441 +
2442 + if (expression.length === 1 && expression[0] instanceof AnchorNode) {
2443 + return expression[0]
2444 + }
2445 +
2446 + const wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap;
2447 +
2448 + const n1 = expression.length === 0 ? null : expression[0];
2449 + let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode)
2450 + ? expression[0]
2451 + : setLineBreaks(expression, wrap, settings.displayMode);
2452 +
2453 + if (tag) {
2454 + wrapper = taggedExpression(wrapper, tag, style, settings.leqno);
2455 + }
2456 +
2457 + if (settings.annotate) {
2458 + // Build a TeX annotation of the source
2459 + const annotation = new mathMLTree.MathNode(
2460 + "annotation", [new mathMLTree.TextNode(texExpression)]);
2461 + annotation.setAttribute("encoding", "application/x-tex");
2462 + wrapper = new mathMLTree.MathNode("semantics", [wrapper, annotation]);
2463 + }
2464 +
2465 + const math = new mathMLTree.MathNode("math", [wrapper]);
2466 +
2467 + if (settings.xml) {
2468 + math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");
2469 + }
2470 + if (wrapper.style.width) {
2471 + math.style.width = "100%";
2472 + }
2473 + if (settings.displayMode) {
2474 + math.setAttribute("display", "block");
2475 + math.style.display = "block math"; // necessary in Chromium.
2476 + // Firefox and Safari do not recognize display: "block math".
2477 + // Set a class so that the CSS file can set display: block.
2478 + math.classes = ["tml-display"];
2479 + }
2480 + return math;
2481 + }
2482 +
2483 + const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳";
2484 + const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ"
2485 + + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭";
2486 + const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota",
2487 + "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi",
2488 + "\\omega", "\\imath", "\\jmath"]);
2489 + const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta",
2490 + "\\lambda", "\\theta", "\\psi"]);
2491 +
2492 + const mathmlBuilder$a = (group, style) => {
2493 + const accentNode = group.isStretchy
2494 + ? stretchy.accentNode(group)
2495 + : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]);
2496 +
2497 + if (group.label === "\\vec") {
2498 + accentNode.style.transform = "scale(0.75) translate(10%, 30%)";
2499 + } else {
2500 + accentNode.style.mathStyle = "normal";
2501 + accentNode.style.mathDepth = "0";
2502 + if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) {
2503 + let shift = "";
2504 + const ch = group.base.text;
2505 + if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift"; }
2506 + if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift"; }
2507 + if (shift) { accentNode.classes.push(shift); }
2508 + }
2509 + }
2510 + if (!group.isStretchy) {
2511 + accentNode.setAttribute("stretchy", "false");
2512 + }
2513 +
2514 + const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"),
2515 + [buildGroup$1(group.base, style), accentNode]
2516 + );
2517 +
2518 + return node;
2519 + };
2520 +
2521 + const nonStretchyAccents = new Set([
2522 + "\\acute",
2523 + "\\grave",
2524 + "\\ddot",
2525 + "\\dddot",
2526 + "\\ddddot",
2527 + "\\tilde",
2528 + "\\bar",
2529 + "\\breve",
2530 + "\\check",
2531 + "\\hat",
2532 + "\\vec",
2533 + "\\dot",
2534 + "\\mathring"
2535 + ]);
2536 +
2537 + const needWebkitShift = new Set([
2538 + "\\acute",
2539 + "\\bar",
2540 + "\\breve",
2541 + "\\check",
2542 + "\\dot",
2543 + "\\ddot",
2544 + "\\grave",
2545 + "\\hat",
2546 + "\\mathring",
2547 + "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
2548 + ]);
2549 +
2550 + const combiningChar = {
2551 + "\\`": "\u0300",
2552 + "\\'": "\u0301",
2553 + "\\^": "\u0302",
2554 + "\\~": "\u0303",
2555 + "\\=": "\u0304",
2556 + "\\u": "\u0306",
2557 + "\\.": "\u0307",
2558 + '\\"': "\u0308",
2559 + "\\r": "\u030A",
2560 + "\\H": "\u030B",
2561 + "\\v": "\u030C"
2562 + };
2563 +
2564 + // Accents
2565 + defineFunction({
2566 + type: "accent",
2567 + names: [
2568 + "\\acute",
2569 + "\\grave",
2570 + "\\ddot",
2571 + "\\dddot",
2572 + "\\ddddot",
2573 + "\\tilde",
2574 + "\\bar",
2575 + "\\breve",
2576 + "\\check",
2577 + "\\hat",
2578 + "\\vec",
2579 + "\\dot",
2580 + "\\mathring",
2581 + "\\overparen",
2582 + "\\widecheck",
2583 + "\\widehat",
2584 + "\\wideparen",
2585 + "\\widetilde",
2586 + "\\overrightarrow",
2587 + "\\overleftarrow",
2588 + "\\Overrightarrow",
2589 + "\\overleftrightarrow",
2590 + "\\overgroup",
2591 + "\\overleftharpoon",
2592 + "\\overrightharpoon"
2593 + ],
2594 + props: {
2595 + numArgs: 1
2596 + },
2597 + handler: (context, args) => {
2598 + const base = normalizeArgument(args[0]);
2599 +
2600 + const isStretchy = !nonStretchyAccents.has(context.funcName);
2601 +
2602 + return {
2603 + type: "accent",
2604 + mode: context.parser.mode,
2605 + label: context.funcName,
2606 + isStretchy: isStretchy,
2607 + base: base
2608 + };
2609 + },
2610 + mathmlBuilder: mathmlBuilder$a
2611 + });
2612 +
2613 + // Text-mode accents
2614 + defineFunction({
2615 + type: "accent",
2616 + names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"],
2617 + props: {
2618 + numArgs: 1,
2619 + allowedInText: true,
2620 + allowedInMath: true,
2621 + argTypes: ["primitive"]
2622 + },
2623 + handler: (context, args) => {
2624 + const base = normalizeArgument(args[0]);
2625 + const mode = context.parser.mode;
2626 +
2627 + if (mode === "math" && context.parser.settings.strict) {
2628 + // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning.
2629 + // eslint-disable-next-line no-console
2630 + console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`);
2631 + }
2632 +
2633 + if (mode === "text" && base.text && base.text.length === 1
2634 + && context.funcName in combiningChar && smalls.indexOf(base.text) > -1) {
2635 + // Return a combining accent character
2636 + return {
2637 + type: "textord",
2638 + mode: "text",
2639 + text: base.text + combiningChar[context.funcName]
2640 + }
2641 + } else {
2642 + // Build up the accent
2643 + return {
2644 + type: "accent",
2645 + mode: mode,
2646 + label: context.funcName,
2647 + isStretchy: false,
2648 + base: base
2649 + }
2650 + }
2651 + },
2652 + mathmlBuilder: mathmlBuilder$a
2653 + });
2654 +
2655 + defineFunction({
2656 + type: "accentUnder",
2657 + names: [
2658 + "\\underleftarrow",
2659 + "\\underrightarrow",
2660 + "\\underleftrightarrow",
2661 + "\\undergroup",
2662 + "\\underparen",
2663 + "\\utilde"
2664 + ],
2665 + props: {
2666 + numArgs: 1
2667 + },
2668 + handler: ({ parser, funcName }, args) => {
2669 + const base = args[0];
2670 + return {
2671 + type: "accentUnder",
2672 + mode: parser.mode,
2673 + label: funcName,
2674 + base: base
2675 + };
2676 + },
2677 + mathmlBuilder: (group, style) => {
2678 + const accentNode = stretchy.accentNode(group);
2679 + accentNode.style["math-depth"] = 0;
2680 + const node = new mathMLTree.MathNode("munder", [
2681 + buildGroup$1(group.base, style),
2682 + accentNode
2683 + ]);
2684 + return node;
2685 + }
2686 + });
2687 +
2688 + /**
2689 + * This file does conversion between units. In particular, it provides
2690 + * calculateSize to convert other units into CSS units.
2691 + */
2692 +
2693 +
2694 + const ptPerUnit = {
2695 + // Convert to CSS (Postscipt) points, not TeX points
2696 + // https://en.wikibooks.org/wiki/LaTeX/Lengths and
2697 + // https://tex.stackexchange.com/a/8263
2698 + pt: 800 / 803, // convert TeX point to CSS (Postscript) point
2699 + pc: (12 * 800) / 803, // pica
2700 + dd: ((1238 / 1157) * 800) / 803, // didot
2701 + cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot)
2702 + nd: ((685 / 642) * 800) / 803, // new didot
2703 + nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot)
2704 + sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit)
2705 + mm: (25.4 / 72),
2706 + cm: (2.54 / 72),
2707 + in: (1 / 72),
2708 + px: (96 / 72)
2709 + };
2710 +
2711 + /**
2712 + * Determine whether the specified unit (either a string defining the unit
2713 + * or a "size" parse node containing a unit field) is valid.
2714 + */
2715 + const validUnits = [
2716 + "em",
2717 + "ex",
2718 + "mu",
2719 + "pt",
2720 + "mm",
2721 + "cm",
2722 + "in",
2723 + "px",
2724 + "bp",
2725 + "pc",
2726 + "dd",
2727 + "cc",
2728 + "nd",
2729 + "nc",
2730 + "sp"
2731 + ];
2732 +
2733 + const validUnit = function(unit) {
2734 + if (typeof unit !== "string") {
2735 + unit = unit.unit;
2736 + }
2737 + return validUnits.indexOf(unit) > -1
2738 + };
2739 +
2740 + const emScale = styleLevel => {
2741 + const scriptLevel = Math.max(styleLevel - 1, 0);
2742 + return [1, 0.7, 0.5][scriptLevel]
2743 + };
2744 +
2745 + /*
2746 + * Convert a "size" parse node (with numeric "number" and string "unit" fields,
2747 + * as parsed by functions.js argType "size") into a CSS value.
2748 + */
2749 + const calculateSize = function(sizeValue, style) {
2750 + let number = sizeValue.number;
2751 + if (style.maxSize[0] < 0 && number > 0) {
2752 + return { number: 0, unit: "em" }
2753 + }
2754 + const unit = sizeValue.unit;
2755 + switch (unit) {
2756 + case "mm":
2757 + case "cm":
2758 + case "in":
2759 + case "px": {
2760 + const numInCssPts = number * ptPerUnit[unit];
2761 + if (numInCssPts > style.maxSize[1]) {
2762 + return { number: style.maxSize[1], unit: "pt" }
2763 + }
2764 + return { number, unit }; // absolute CSS units.
2765 + }
2766 + case "em":
2767 + case "ex": {
2768 + // In TeX, em and ex do not change size in \scriptstyle.
2769 + if (unit === "ex") { number *= 0.431; }
2770 + number = Math.min(number / emScale(style.level), style.maxSize[0]);
2771 + return { number: utils.round(number), unit: "em" };
2772 + }
2773 + case "bp": {
2774 + if (number > style.maxSize[1]) { number = style.maxSize[1]; }
2775 + return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch).
2776 + }
2777 + case "pt":
2778 + case "pc":
2779 + case "dd":
2780 + case "cc":
2781 + case "nd":
2782 + case "nc":
2783 + case "sp": {
2784 + number = Math.min(number * ptPerUnit[unit], style.maxSize[1]);
2785 + return { number: utils.round(number), unit: "pt" }
2786 + }
2787 + case "mu": {
2788 + number = Math.min(number / 18, style.maxSize[0]);
2789 + return { number: utils.round(number), unit: "em" }
2790 + }
2791 + default:
2792 + throw new ParseError("Invalid unit: '" + unit + "'")
2793 + }
2794 + };
2795 +
2796 + // Helper functions
2797 +
2798 + const padding$2 = width => {
2799 + const node = new mathMLTree.MathNode("mspace");
2800 + node.setAttribute("width", width + "em");
2801 + return node
2802 + };
2803 +
2804 + const paddedNode = (group, lspace = 0.3, rspace = 0, mustSmash = false) => {
2805 + if (group == null && rspace === 0) { return padding$2(lspace) }
2806 + const row = group ? [group] : [];
2807 + if (lspace !== 0) { row.unshift(padding$2(lspace)); }
2808 + if (rspace > 0) { row.push(padding$2(rspace)); }
2809 + if (mustSmash) {
2810 + // Used for the bottom arrow in a {CD} environment
2811 + const mpadded = new mathMLTree.MathNode("mpadded", row);
2812 + mpadded.setAttribute("height", "0");
2813 + return mpadded
2814 + } else {
2815 + return new mathMLTree.MathNode("mrow", row)
2816 + }
2817 + };
2818 +
2819 + const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel);
2820 +
2821 + const munderoverNode = (fName, body, below, style) => {
2822 + const arrowNode = stretchy.mathMLnode(fName);
2823 + // Is this the short part of a mhchem equilibrium arrow?
2824 + const isEq = fName.slice(1, 3) === "eq";
2825 + const minWidth = fName.charAt(1) === "x"
2826 + ? "1.75" // mathtools extensible arrows are ≥ 1.75em long
2827 + : fName.slice(2, 4) === "cd"
2828 + ? "3.0" // cd package arrows
2829 + : isEq
2830 + ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow
2831 + : "2.0"; // other mhchem arrows
2832 + // TODO: When Firefox supports minsize, use the next line.
2833 + //arrowNode.setAttribute("minsize", String(minWidth) + "em")
2834 + arrowNode.setAttribute("lspace", "0");
2835 + arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0"));
2836 +
2837 + // <munderover> upper and lower labels are set to scriptlevel by MathML
2838 + // So we have to adjust our label dimensions accordingly.
2839 + const labelStyle = style.withLevel(style.level < 2 ? 2 : 3);
2840 + const minArrowWidth = labelSize(minWidth, labelStyle.level);
2841 + // The dummyNode will be inside a <mover> inside a <mover>
2842 + // So it will be at scriptlevel 3
2843 + const dummyWidth = labelSize(minWidth, 3);
2844 + const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0);
2845 + const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0);
2846 + // The arrow is a little longer than the label. Set a spacer length.
2847 + const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4);
2848 + let upperNode;
2849 + let lowerNode;
2850 +
2851 + const gotUpper = (body && body.body &&
2852 + // \hphantom visible content
2853 + (body.body.body || body.body.length > 0));
2854 + if (gotUpper) {
2855 + let label = buildGroup$1(body, labelStyle);
2856 + const mustSmash = (fName === "\\\\cdrightarrow" || fName === "\\\\cdleftarrow");
2857 + label = paddedNode(label, space, space, mustSmash);
2858 + // Since Firefox does not support minsize, stack a invisible node
2859 + // on top of the label. Its width will serve as a min-width.
2860 + // TODO: Refactor this after Firefox supports minsize.
2861 + upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]);
2862 + }
2863 + const gotLower = (below && below.body &&
2864 + (below.body.body || below.body.length > 0));
2865 + if (gotLower) {
2866 + let label = buildGroup$1(below, labelStyle);
2867 + label = paddedNode(label, space, space);
2868 + lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]);
2869 + }
2870 +
2871 + let node;
2872 + if (!gotUpper && !gotLower) {
2873 + node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]);
2874 + } else if (gotUpper && gotLower) {
2875 + node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]);
2876 + } else if (gotUpper) {
2877 + node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]);
2878 + } else {
2879 + node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]);
2880 + }
2881 + if (minWidth === "3.0") { node.style.height = "1em"; } // CD environment
2882 + node.setAttribute("accent", "false"); // Necessary for MS Word
2883 + return node
2884 + };
2885 +
2886 + // Stretchy arrows with an optional argument
2887 + defineFunction({
2888 + type: "xArrow",
2889 + names: [
2890 + "\\xleftarrow",
2891 + "\\xrightarrow",
2892 + "\\xLeftarrow",
2893 + "\\xRightarrow",
2894 + "\\xleftrightarrow",
2895 + "\\xLeftrightarrow",
2896 + "\\xhookleftarrow",
2897 + "\\xhookrightarrow",
2898 + "\\xmapsto",
2899 + "\\xrightharpoondown",
2900 + "\\xrightharpoonup",
2901 + "\\xleftharpoondown",
2902 + "\\xleftharpoonup",
2903 + "\\xlongequal",
2904 + "\\xtwoheadrightarrow",
2905 + "\\xtwoheadleftarrow",
2906 + // The next 5 functions are here only to support mhchem
2907 + "\\yields",
2908 + "\\yieldsLeft",
2909 + "\\mesomerism",
2910 + "\\longrightharpoonup",
2911 + "\\longleftharpoondown",
2912 + // The next 3 functions are here only to support the {CD} environment.
2913 + "\\\\cdrightarrow",
2914 + "\\\\cdleftarrow",
2915 + "\\\\cdlongequal"
2916 + ],
2917 + props: {
2918 + numArgs: 1,
2919 + numOptionalArgs: 1
2920 + },
2921 + handler({ parser, funcName }, args, optArgs) {
2922 + return {
2923 + type: "xArrow",
2924 + mode: parser.mode,
2925 + name: funcName,
2926 + body: args[0],
2927 + below: optArgs[0]
2928 + };
2929 + },
2930 + mathmlBuilder(group, style) {
2931 + // Build the arrow and its labels.
2932 + const node = munderoverNode(group.name, group.body, group.below, style);
2933 + // Create operator spacing for a relation.
2934 + const row = [node];
2935 + row.unshift(padding$2(0.2778));
2936 + row.push(padding$2(0.2778));
2937 + return new mathMLTree.MathNode("mrow", row)
2938 + }
2939 + });
2940 +
2941 + const arrowComponent = {
2942 + "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"],
2943 + "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"],
2944 + "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"],
2945 + "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"],
2946 + // The next three all get the same harpoon glyphs. Only the lengths and paddings differ.
2947 + "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"],
2948 + "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"],
2949 + "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"]
2950 + };
2951 +
2952 + // Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄.
2953 + // So we stack a pair of single arrows.
2954 + defineFunction({
2955 + type: "stackedArrow",
2956 + names: [
2957 + "\\xtofrom", // expfeil
2958 + "\\xleftrightharpoons", // mathtools
2959 + "\\xrightleftharpoons", // mathtools
2960 + "\\yieldsLeftRight", // mhchem
2961 + "\\equilibrium", // mhchem
2962 + "\\equilibriumRight",
2963 + "\\equilibriumLeft"
2964 + ],
2965 + props: {
2966 + numArgs: 1,
2967 + numOptionalArgs: 1
2968 + },
2969 + handler({ parser, funcName }, args, optArgs) {
2970 + const lowerArrowBody = args[0]
2971 + ? {
2972 + type: "hphantom",
2973 + mode: parser.mode,
2974 + body: args[0]
2975 + }
2976 + : null;
2977 + const upperArrowBelow = optArgs[0]
2978 + ? {
2979 + type: "hphantom",
2980 + mode: parser.mode,
2981 + body: optArgs[0]
2982 + }
2983 + : null;
2984 + return {
2985 + type: "stackedArrow",
2986 + mode: parser.mode,
2987 + name: funcName,
2988 + body: args[0],
2989 + upperArrowBelow,
2990 + lowerArrowBody,
2991 + below: optArgs[0]
2992 + };
2993 + },
2994 + mathmlBuilder(group, style) {
2995 + const topLabel = arrowComponent[group.name][0];
2996 + const botLabel = arrowComponent[group.name][1];
2997 + const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style);
2998 + const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style);
2999 + let wrapper;
3000 +
3001 + const raiseNode = new mathMLTree.MathNode("mpadded", [topArrow]);
3002 + raiseNode.setAttribute("voffset", "0.3em");
3003 + raiseNode.setAttribute("height", "+0.3em");
3004 + raiseNode.setAttribute("depth", "-0.3em");
3005 + // One of the arrows is given ~zero width. so the other has the same horzontal alignment.
3006 + if (group.name === "\\equilibriumLeft") {
3007 + const botNode = new mathMLTree.MathNode("mpadded", [botArrow]);
3008 + botNode.setAttribute("width", "0.5em");
3009 + wrapper = new mathMLTree.MathNode(
3010 + "mpadded",
3011 + [padding$2(0.2778), botNode, raiseNode, padding$2(0.2778)]
3012 + );
3013 + } else {
3014 + raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0"));
3015 + wrapper = new mathMLTree.MathNode(
3016 + "mpadded",
3017 + [padding$2(0.2778), raiseNode, botArrow, padding$2(0.2778)]
3018 + );
3019 + }
3020 +
3021 + wrapper.setAttribute("voffset", "-0.18em");
3022 + wrapper.setAttribute("height", "-0.18em");
3023 + wrapper.setAttribute("depth", "+0.18em");
3024 + return wrapper
3025 + }
3026 + });
3027 +
3028 + /**
3029 + * Asserts that the node is of the given type and returns it with stricter
3030 + * typing. Throws if the node's type does not match.
3031 + */
3032 + function assertNodeType(node, type) {
3033 + if (!node || node.type !== type) {
3034 + throw new Error(
3035 + `Expected node of type ${type}, but got ` +
3036 + (node ? `node of type ${node.type}` : String(node))
3037 + );
3038 + }
3039 + return node;
3040 + }
3041 +
3042 + /**
3043 + * Returns the node more strictly typed iff it is of the given type. Otherwise,
3044 + * returns null.
3045 + */
3046 + function assertSymbolNodeType(node) {
3047 + const typedNode = checkSymbolNodeType(node);
3048 + if (!typedNode) {
3049 + throw new Error(
3050 + `Expected node of symbol group type, but got ` +
3051 + (node ? `node of type ${node.type}` : String(node))
3052 + );
3053 + }
3054 + return typedNode;
3055 + }
3056 +
3057 + /**
3058 + * Returns the node more strictly typed iff it is of the given type. Otherwise,
3059 + * returns null.
3060 + */
3061 + function checkSymbolNodeType(node) {
3062 + if (node && (node.type === "atom" ||
3063 + Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) {
3064 + return node;
3065 + }
3066 + return null;
3067 + }
3068 +
3069 + const cdArrowFunctionName = {
3070 + ">": "\\\\cdrightarrow",
3071 + "<": "\\\\cdleftarrow",
3072 + "=": "\\\\cdlongequal",
3073 + A: "\\uparrow",
3074 + V: "\\downarrow",
3075 + "|": "\\Vert",
3076 + ".": "no arrow"
3077 + };
3078 +
3079 + const newCell = () => {
3080 + // Create an empty cell, to be filled below with parse nodes.
3081 + return { type: "styling", body: [], mode: "math", scriptLevel: "display" };
3082 + };
3083 +
3084 + const isStartOfArrow = (node) => {
3085 + return node.type === "textord" && node.text === "@";
3086 + };
3087 +
3088 + const isLabelEnd = (node, endChar) => {
3089 + return (node.type === "mathord" || node.type === "atom") && node.text === endChar;
3090 + };
3091 +
3092 + function cdArrow(arrowChar, labels, parser) {
3093 + // Return a parse tree of an arrow and its labels.
3094 + // This acts in a way similar to a macro expansion.
3095 + const funcName = cdArrowFunctionName[arrowChar];
3096 + switch (funcName) {
3097 + case "\\\\cdrightarrow":
3098 + case "\\\\cdleftarrow":
3099 + return parser.callFunction(funcName, [labels[0]], [labels[1]]);
3100 + case "\\uparrow":
3101 + case "\\downarrow": {
3102 + const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []);
3103 + const bareArrow = {
3104 + type: "atom",
3105 + text: funcName,
3106 + mode: "math",
3107 + family: "rel"
3108 + };
3109 + const sizedArrow = parser.callFunction("\\Big", [bareArrow], []);
3110 + const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []);
3111 + const arrowGroup = {
3112 + type: "ordgroup",
3113 + mode: "math",
3114 + body: [leftLabel, sizedArrow, rightLabel],
3115 + semisimple: true
3116 + };
3117 + return parser.callFunction("\\\\cdparent", [arrowGroup], []);
3118 + }
3119 + case "\\\\cdlongequal":
3120 + return parser.callFunction("\\\\cdlongequal", [], []);
3121 + case "\\Vert": {
3122 + const arrow = { type: "textord", text: "\\Vert", mode: "math" };
3123 + return parser.callFunction("\\Big", [arrow], []);
3124 + }
3125 + default:
3126 + return { type: "textord", text: " ", mode: "math" };
3127 + }
3128 + }
3129 +
3130 + function parseCD(parser) {
3131 + // Get the array's parse nodes with \\ temporarily mapped to \cr.
3132 + const parsedRows = [];
3133 + parser.gullet.beginGroup();
3134 + parser.gullet.macros.set("\\cr", "\\\\\\relax");
3135 + parser.gullet.beginGroup();
3136 + while (true) {
3137 + // Get the parse nodes for the next row.
3138 + parsedRows.push(parser.parseExpression(false, "\\\\"));
3139 + parser.gullet.endGroup();
3140 + parser.gullet.beginGroup();
3141 + const next = parser.fetch().text;
3142 + if (next === "&" || next === "\\\\") {
3143 + parser.consume();
3144 + } else if (next === "\\end") {
3145 + if (parsedRows[parsedRows.length - 1].length === 0) {
3146 + parsedRows.pop(); // final row ended in \\
3147 + }
3148 + break;
3149 + } else {
3150 + throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken);
3151 + }
3152 + }
3153 +
3154 + let row = [];
3155 + const body = [row];
3156 +
3157 + // Loop thru the parse nodes. Collect them into cells and arrows.
3158 + for (let i = 0; i < parsedRows.length; i++) {
3159 + // Start a new row.
3160 + const rowNodes = parsedRows[i];
3161 + // Create the first cell.
3162 + let cell = newCell();
3163 +
3164 + for (let j = 0; j < rowNodes.length; j++) {
3165 + if (!isStartOfArrow(rowNodes[j])) {
3166 + // If a parseNode is not an arrow, it goes into a cell.
3167 + cell.body.push(rowNodes[j]);
3168 + } else {
3169 + // Parse node j is an "@", the start of an arrow.
3170 + // Before starting on the arrow, push the cell into `row`.
3171 + row.push(cell);
3172 +
3173 + // Now collect parseNodes into an arrow.
3174 + // The character after "@" defines the arrow type.
3175 + j += 1;
3176 + const arrowChar = assertSymbolNodeType(rowNodes[j]).text;
3177 +
3178 + // Create two empty label nodes. We may or may not use them.
3179 + const labels = new Array(2);
3180 + labels[0] = { type: "ordgroup", mode: "math", body: [] };
3181 + labels[1] = { type: "ordgroup", mode: "math", body: [] };
3182 +
3183 + // Process the arrow.
3184 + if ("=|.".indexOf(arrowChar) > -1) ; else if ("<>AV".indexOf(arrowChar) > -1) {
3185 + // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take
3186 + // two optional labels. E.g. the right-point arrow syntax is
3187 + // really: @>{optional label}>{optional label}>
3188 + // Collect parseNodes into labels.
3189 + for (let labelNum = 0; labelNum < 2; labelNum++) {
3190 + let inLabel = true;
3191 + for (let k = j + 1; k < rowNodes.length; k++) {
3192 + if (isLabelEnd(rowNodes[k], arrowChar)) {
3193 + inLabel = false;
3194 + j = k;
3195 + break;
3196 + }
3197 + if (isStartOfArrow(rowNodes[k])) {
3198 + throw new ParseError(
3199 + "Missing a " + arrowChar + " character to complete a CD arrow.",
3200 + rowNodes[k]
3201 + );
3202 + }
3203 +
3204 + labels[labelNum].body.push(rowNodes[k]);
3205 + }
3206 + if (inLabel) {
3207 + // isLabelEnd never returned a true.
3208 + throw new ParseError(
3209 + "Missing a " + arrowChar + " character to complete a CD arrow.",
3210 + rowNodes[j]
3211 + );
3212 + }
3213 + }
3214 + } else {
3215 + throw new ParseError(`Expected one of "<>AV=|." after @.`);
3216 + }
3217 +
3218 + // Now join the arrow to its labels.
3219 + const arrow = cdArrow(arrowChar, labels, parser);
3220 +
3221 + // Wrap the arrow in a styling node
3222 + row.push(arrow);
3223 + // In CD's syntax, cells are implicit. That is, everything that
3224 + // is not an arrow gets collected into a cell. So create an empty
3225 + // cell now. It will collect upcoming parseNodes.
3226 + cell = newCell();
3227 + }
3228 + }
3229 + if (i % 2 === 0) {
3230 + // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell
3231 + // The last cell is not yet pushed into `row`, so:
3232 + row.push(cell);
3233 + } else {
3234 + // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow
3235 + // Remove the empty cell that was placed at the beginning of `row`.
3236 + row.shift();
3237 + }
3238 + row = [];
3239 + body.push(row);
3240 + }
3241 + body.pop();
3242 +
3243 + // End row group
3244 + parser.gullet.endGroup();
3245 + // End array group defining \\
3246 + parser.gullet.endGroup();
3247 +
3248 + return {
3249 + type: "array",
3250 + mode: "math",
3251 + body,
3252 + tags: null,
3253 + labels: new Array(body.length + 1).fill(""),
3254 + envClasses: ["jot", "cd"],
3255 + cols: [],
3256 + hLinesBeforeRow: new Array(body.length + 1).fill([])
3257 + };
3258 + }
3259 +
3260 + // The functions below are not available for general use.
3261 + // They are here only for internal use by the {CD} environment in placing labels
3262 + // next to vertical arrows.
3263 +
3264 + // We don't need any such functions for horizontal arrows because we can reuse
3265 + // the functionality that already exists for extensible arrows.
3266 +
3267 + defineFunction({
3268 + type: "cdlabel",
3269 + names: ["\\\\cdleft", "\\\\cdright"],
3270 + props: {
3271 + numArgs: 1
3272 + },
3273 + handler({ parser, funcName }, args) {
3274 + return {
3275 + type: "cdlabel",
3276 + mode: parser.mode,
3277 + side: funcName.slice(4),
3278 + label: args[0]
3279 + };
3280 + },
3281 + mathmlBuilder(group, style) {
3282 + if (group.label.body.length === 0) {
3283 + return new mathMLTree.MathNode("mrow", style) // empty label
3284 + }
3285 + // Abuse an <mtable> to create vertically centered content.
3286 + const mtd = new mathMLTree.MathNode("mtd", [buildGroup$1(group.label, style)]);
3287 + mtd.style.padding = "0";
3288 + const mtr = new mathMLTree.MathNode("mtr", [mtd]);
3289 + const mtable = new mathMLTree.MathNode("mtable", [mtr]);
3290 + const label = new mathMLTree.MathNode("mpadded", [mtable]);
3291 + // Set the label width to zero so that the arrow will be centered under the corner cell.
3292 + label.setAttribute("width", "0");
3293 + label.setAttribute("displaystyle", "false");
3294 + label.setAttribute("scriptlevel", "1");
3295 + if (group.side === "left") {
3296 + label.style.display = "flex";
3297 + label.style.justifyContent = "flex-end";
3298 + }
3299 + return label;
3300 + }
3301 + });
3302 +
3303 + defineFunction({
3304 + type: "cdlabelparent",
3305 + names: ["\\\\cdparent"],
3306 + props: {
3307 + numArgs: 1
3308 + },
3309 + handler({ parser }, args) {
3310 + return {
3311 + type: "cdlabelparent",
3312 + mode: parser.mode,
3313 + fragment: args[0]
3314 + };
3315 + },
3316 + mathmlBuilder(group, style) {
3317 + return new mathMLTree.MathNode("mrow", [buildGroup$1(group.fragment, style)]);
3318 + }
3319 + });
3320 +
3321 + // \@char is an internal function that takes a grouped decimal argument like
3322 + // {123} and converts into symbol with code 123. It is used by the *macro*
3323 + // \char defined in macros.js.
3324 + defineFunction({
3325 + type: "textord",
3326 + names: ["\\@char"],
3327 + props: {
3328 + numArgs: 1,
3329 + allowedInText: true
3330 + },
3331 + handler({ parser, token }, args) {
3332 + const arg = assertNodeType(args[0], "ordgroup");
3333 + const group = arg.body;
3334 + let number = "";
3335 + for (let i = 0; i < group.length; i++) {
3336 + const node = assertNodeType(group[i], "textord");
3337 + number += node.text;
3338 + }
3339 + const code = parseInt(number);
3340 + if (isNaN(code)) {
3341 + throw new ParseError(`\\@char has non-numeric argument ${number}`, token)
3342 + }
3343 + return {
3344 + type: "textord",
3345 + mode: parser.mode,
3346 + text: String.fromCodePoint(code)
3347 + }
3348 + }
3349 + });
3350 +
3351 + // Helpers
3352 + const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i;
3353 + const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i;
3354 + const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/;
3355 + const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/;
3356 + const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i;
3357 + const toHex = num => {
3358 + let str = num.toString(16);
3359 + if (str.length === 1) { str = "0" + str; }
3360 + return str
3361 + };
3362 +
3363 + // Colors from Tables 4.1 and 4.2 of the xcolor package.
3364 + // Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx.
3365 + // Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable
3366 + // conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274.
3367 + const xcolors = JSON.parse(`{
3368 + "Apricot": "#ffb484",
3369 + "Aquamarine": "#08b4bc",
3370 + "Bittersweet": "#c84c14",
3371 + "blue": "#0000FF",
3372 + "Blue": "#303494",
3373 + "BlueGreen": "#08b4bc",
3374 + "BlueViolet": "#503c94",
3375 + "BrickRed": "#b8341c",
3376 + "brown": "#BF8040",
3377 + "Brown": "#802404",
3378 + "BurntOrange": "#f8941c",
3379 + "CadetBlue": "#78749c",
3380 + "CarnationPink": "#f884b4",
3381 + "Cerulean": "#08a4e4",
3382 + "CornflowerBlue": "#40ace4",
3383 + "cyan": "#00FFFF",
3384 + "Cyan": "#08acec",
3385 + "Dandelion": "#ffbc44",
3386 + "darkgray": "#404040",
3387 + "DarkOrchid": "#a8548c",
3388 + "Emerald": "#08ac9c",
3389 + "ForestGreen": "#089c54",
3390 + "Fuchsia": "#90348c",
3391 + "Goldenrod": "#ffdc44",
3392 + "gray": "#808080",
3393 + "Gray": "#98949c",
3394 + "green": "#00FF00",
3395 + "Green": "#08a44c",
3396 + "GreenYellow": "#e0e474",
3397 + "JungleGreen": "#08ac9c",
3398 + "Lavender": "#f89cc4",
3399 + "lightgray": "#c0c0c0",
3400 + "lime": "#BFFF00",
3401 + "LimeGreen": "#90c43c",
3402 + "magenta": "#FF00FF",
3403 + "Magenta": "#f0048c",
3404 + "Mahogany": "#b0341c",
3405 + "Maroon": "#b03434",
3406 + "Melon": "#f89c7c",
3407 + "MidnightBlue": "#086494",
3408 + "Mulberry": "#b03c94",
3409 + "NavyBlue": "#086cbc",
3410 + "olive": "#7F7F00",
3411 + "OliveGreen": "#407c34",
3412 + "orange": "#FF8000",
3413 + "Orange": "#f8843c",
3414 + "OrangeRed": "#f0145c",
3415 + "Orchid": "#b074ac",
3416 + "Peach": "#f8945c",
3417 + "Periwinkle": "#8074bc",
3418 + "PineGreen": "#088c74",
3419 + "pink": "#ff7f7f",
3420 + "Plum": "#98248c",
3421 + "ProcessBlue": "#08b4ec",
3422 + "purple": "#BF0040",
3423 + "Purple": "#a0449c",
3424 + "RawSienna": "#983c04",
3425 + "red": "#ff0000",
3426 + "Red": "#f01c24",
3427 + "RedOrange": "#f86434",
3428 + "RedViolet": "#a0246c",
3429 + "Rhodamine": "#f0549c",
3430 + "Royallue": "#0874bc",
3431 + "RoyalPurple": "#683c9c",
3432 + "RubineRed": "#f0047c",
3433 + "Salmon": "#f8948c",
3434 + "SeaGreen": "#30bc9c",
3435 + "Sepia": "#701404",
3436 + "SkyBlue": "#48c4dc",
3437 + "SpringGreen": "#c8dc64",
3438 + "Tan": "#e09c74",
3439 + "teal": "#007F7F",
3440 + "TealBlue": "#08acb4",
3441 + "Thistle": "#d884b4",
3442 + "Turquoise": "#08b4cc",
3443 + "violet": "#800080",
3444 + "Violet": "#60449c",
3445 + "VioletRed": "#f054a4",
3446 + "WildStrawberry": "#f0246c",
3447 + "yellow": "#FFFF00",
3448 + "Yellow": "#fff404",
3449 + "YellowGreen": "#98cc6c",
3450 + "YellowOrange": "#ffa41c"
3451 + }`);
3452 +
3453 + const colorFromSpec = (model, spec) => {
3454 + let color = "";
3455 + if (model === "HTML") {
3456 + if (!htmlRegEx.test(spec)) {
3457 + throw new ParseError("Invalid HTML input.")
3458 + }
3459 + color = spec;
3460 + } else if (model === "RGB") {
3461 + if (!RGBregEx.test(spec)) {
3462 + throw new ParseError("Invalid RGB input.")
3463 + }
3464 + spec.split(",").map(e => { color += toHex(Number(e.trim())); });
3465 + } else {
3466 + if (!rgbRegEx.test(spec)) {
3467 + throw new ParseError("Invalid rbg input.")
3468 + }
3469 + spec.split(",").map(e => {
3470 + const num = Number(e.trim());
3471 + if (num > 1) { throw new ParseError("Color rgb input must be < 1.") }
3472 + color += toHex(Number((num * 255).toFixed(0)));
3473 + });
3474 + }
3475 + if (color.charAt(0) !== "#") { color = "#" + color; }
3476 + return color
3477 + };
3478 +
3479 + const validateColor = (color, macros, token) => {
3480 + const macroName = `\\\\color@${color}`; // from \defineColor.
3481 + const match = htmlOrNameRegEx.exec(color);
3482 + if (!match) { throw new ParseError("Invalid color: '" + color + "'", token) }
3483 + // We allow a 6-digit HTML color spec without a leading "#".
3484 + // This follows the xcolor package's HTML color model.
3485 + // Predefined color names are all missed by this RegEx pattern.
3486 + if (xcolorHtmlRegEx.test(color)) {
3487 + return "#" + color
3488 + } else if (color.charAt(0) === "#") {
3489 + return color
3490 + } else if (macros.has(macroName)) {
3491 + color = macros.get(macroName).tokens[0].text;
3492 + } else if (xcolors[color]) {
3493 + color = xcolors[color];
3494 + }
3495 + return color
3496 + };
3497 +
3498 + const mathmlBuilder$9 = (group, style) => {
3499 + // In LaTeX, color is not supposed to change the spacing of any node.
3500 + // So instead of wrapping the group in an <mstyle>, we apply
3501 + // the color individually to each node and return a document fragment.
3502 + let expr = buildExpression(group.body, style.withColor(group.color));
3503 + expr = expr.map(e => {
3504 + e.style.color = group.color;
3505 + return e
3506 + });
3507 + return mathMLTree.newDocumentFragment(expr)
3508 + };
3509 +
3510 + defineFunction({
3511 + type: "color",
3512 + names: ["\\textcolor"],
3513 + props: {
3514 + numArgs: 2,
3515 + numOptionalArgs: 1,
3516 + allowedInText: true,
3517 + argTypes: ["raw", "raw", "original"]
3518 + },
3519 + handler({ parser, token }, args, optArgs) {
3520 + const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string;
3521 + let color = "";
3522 + if (model) {
3523 + const spec = assertNodeType(args[0], "raw").string;
3524 + color = colorFromSpec(model, spec);
3525 + } else {
3526 + color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token);
3527 + }
3528 + const body = args[1];
3529 + return {
3530 + type: "color",
3531 + mode: parser.mode,
3532 + color,
3533 + isTextColor: true,
3534 + body: ordargument(body)
3535 + }
3536 + },
3537 + mathmlBuilder: mathmlBuilder$9
3538 + });
3539 +
3540 + defineFunction({
3541 + type: "color",
3542 + names: ["\\color"],
3543 + props: {
3544 + numArgs: 1,
3545 + numOptionalArgs: 1,
3546 + allowedInText: true,
3547 + argTypes: ["raw", "raw"]
3548 + },
3549 + handler({ parser, breakOnTokenText, token }, args, optArgs) {
3550 + const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string;
3551 + let color = "";
3552 + if (model) {
3553 + const spec = assertNodeType(args[0], "raw").string;
3554 + color = colorFromSpec(model, spec);
3555 + } else {
3556 + color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token);
3557 + }
3558 +
3559 + // Parse out the implicit body that should be colored.
3560 + const body = parser.parseExpression(true, breakOnTokenText, true);
3561 +
3562 + return {
3563 + type: "color",
3564 + mode: parser.mode,
3565 + color,
3566 + isTextColor: false,
3567 + body
3568 + }
3569 + },
3570 + mathmlBuilder: mathmlBuilder$9
3571 + });
3572 +
3573 + defineFunction({
3574 + type: "color",
3575 + names: ["\\definecolor"],
3576 + props: {
3577 + numArgs: 3,
3578 + allowedInText: true,
3579 + argTypes: ["raw", "raw", "raw"]
3580 + },
3581 + handler({ parser, funcName, token }, args) {
3582 + const name = assertNodeType(args[0], "raw").string;
3583 + if (!/^[A-Za-z]+$/.test(name)) {
3584 + throw new ParseError("Color name must be latin letters.", token)
3585 + }
3586 + const model = assertNodeType(args[1], "raw").string;
3587 + if (!["HTML", "RGB", "rgb"].includes(model)) {
3588 + throw new ParseError("Color model must be HTML, RGB, or rgb.", token)
3589 + }
3590 + const spec = assertNodeType(args[2], "raw").string;
3591 + const color = colorFromSpec(model, spec);
3592 + parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 });
3593 + return { type: "internal", mode: parser.mode }
3594 + }
3595 + // No mathmlBuilder. The point of \definecolor is to set a macro.
3596 + });
3597 +
3598 + // Row breaks within tabular environments, and line breaks at top level
3599 +
3600 +
3601 + // \DeclareRobustCommand\\{...\@xnewline}
3602 + defineFunction({
3603 + type: "cr",
3604 + names: ["\\\\"],
3605 + props: {
3606 + numArgs: 0,
3607 + numOptionalArgs: 0,
3608 + allowedInText: true
3609 + },
3610 +
3611 + handler({ parser }, args, optArgs) {
3612 + const size = parser.gullet.future().text === "[" ? parser.parseSizeGroup(true) : null;
3613 + const newLine = !parser.settings.displayMode;
3614 + return {
3615 + type: "cr",
3616 + mode: parser.mode,
3617 + newLine,
3618 + size: size && assertNodeType(size, "size").value
3619 + }
3620 + },
3621 +
3622 + // The following builder is called only at the top level,
3623 + // not within tabular/array environments.
3624 +
3625 + mathmlBuilder(group, style) {
3626 + // MathML 3.0 calls for newline to occur in an <mo> or an <mspace>.
3627 + // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking
3628 + const node = new mathMLTree.MathNode("mo");
3629 + if (group.newLine) {
3630 + node.setAttribute("linebreak", "newline");
3631 + if (group.size) {
3632 + const size = calculateSize(group.size, style);
3633 + node.setAttribute("height", size.number + size.unit);
3634 + }
3635 + }
3636 + return node
3637 + }
3638 + });
3639 +
3640 + const globalMap = {
3641 + "\\global": "\\global",
3642 + "\\long": "\\\\globallong",
3643 + "\\\\globallong": "\\\\globallong",
3644 + "\\def": "\\gdef",
3645 + "\\gdef": "\\gdef",
3646 + "\\edef": "\\xdef",
3647 + "\\xdef": "\\xdef",
3648 + "\\let": "\\\\globallet",
3649 + "\\futurelet": "\\\\globalfuture"
3650 + };
3651 +
3652 + const checkControlSequence = (tok) => {
3653 + const name = tok.text;
3654 + if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) {
3655 + throw new ParseError("Expected a control sequence", tok);
3656 + }
3657 + return name;
3658 + };
3659 +
3660 + const getRHS = (parser) => {
3661 + let tok = parser.gullet.popToken();
3662 + if (tok.text === "=") {
3663 + // consume optional equals
3664 + tok = parser.gullet.popToken();
3665 + if (tok.text === " ") {
3666 + // consume one optional space
3667 + tok = parser.gullet.popToken();
3668 + }
3669 + }
3670 + return tok;
3671 + };
3672 +
3673 + const letCommand = (parser, name, tok, global) => {
3674 + let macro = parser.gullet.macros.get(tok.text);
3675 + if (macro == null) {
3676 + // don't expand it later even if a macro with the same name is defined
3677 + // e.g., \let\foo=\frac \def\frac{\relax} \frac12
3678 + tok.noexpand = true;
3679 + macro = {
3680 + tokens: [tok],
3681 + numArgs: 0,
3682 + // reproduce the same behavior in expansion
3683 + unexpandable: !parser.gullet.isExpandable(tok.text)
3684 + };
3685 + }
3686 + parser.gullet.macros.set(name, macro, global);
3687 + };
3688 +
3689 + // <assignment> -> <non-macro assignment>|<macro assignment>
3690 + // <non-macro assignment> -> <simple assignment>|\global<non-macro assignment>
3691 + // <macro assignment> -> <definition>|<prefix><macro assignment>
3692 + // <prefix> -> \global|\long|\outer
3693 + defineFunction({
3694 + type: "internal",
3695 + names: [
3696 + "\\global",
3697 + "\\long",
3698 + "\\\\globallong" // can’t be entered directly
3699 + ],
3700 + props: {
3701 + numArgs: 0,
3702 + allowedInText: true
3703 + },
3704 + handler({ parser, funcName }) {
3705 + parser.consumeSpaces();
3706 + const token = parser.fetch();
3707 + if (globalMap[token.text]) {
3708 + // Temml doesn't have \par, so ignore \long
3709 + if (funcName === "\\global" || funcName === "\\\\globallong") {
3710 + token.text = globalMap[token.text];
3711 + }
3712 + return assertNodeType(parser.parseFunction(), "internal");
3713 + }
3714 + throw new ParseError(`Invalid token after macro prefix`, token);
3715 + }
3716 + });
3717 +
3718 + // Basic support for macro definitions: \def, \gdef, \edef, \xdef
3719 + // <definition> -> <def><control sequence><definition text>
3720 + // <def> -> \def|\gdef|\edef|\xdef
3721 + // <definition text> -> <parameter text><left brace><balanced text><right brace>
3722 + defineFunction({
3723 + type: "internal",
3724 + names: ["\\def", "\\gdef", "\\edef", "\\xdef"],
3725 + props: {
3726 + numArgs: 0,
3727 + allowedInText: true,
3728 + primitive: true
3729 + },
3730 + handler({ parser, funcName }) {
3731 + let tok = parser.gullet.popToken();
3732 + const name = tok.text;
3733 + if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) {
3734 + throw new ParseError("Expected a control sequence", tok);
3735 + }
3736 +
3737 + let numArgs = 0;
3738 + let insert;
3739 + const delimiters = [[]];
3740 + // <parameter text> contains no braces
3741 + while (parser.gullet.future().text !== "{") {
3742 + tok = parser.gullet.popToken();
3743 + if (tok.text === "#") {
3744 + // If the very last character of the <parameter text> is #, so that
3745 + // this # is immediately followed by {, TeX will behave as if the {
3746 + // had been inserted at the right end of both the parameter text
3747 + // and the replacement text.
3748 + if (parser.gullet.future().text === "{") {
3749 + insert = parser.gullet.future();
3750 + delimiters[numArgs].push("{");
3751 + break;
3752 + }
3753 +
3754 + // A parameter, the first appearance of # must be followed by 1,
3755 + // the next by 2, and so on; up to nine #’s are allowed
3756 + tok = parser.gullet.popToken();
3757 + if (!/^[1-9]$/.test(tok.text)) {
3758 + throw new ParseError(`Invalid argument number "${tok.text}"`);
3759 + }
3760 + if (parseInt(tok.text) !== numArgs + 1) {
3761 + throw new ParseError(`Argument number "${tok.text}" out of order`);
3762 + }
3763 + numArgs++;
3764 + delimiters.push([]);
3765 + } else if (tok.text === "EOF") {
3766 + throw new ParseError("Expected a macro definition");
3767 + } else {
3768 + delimiters[numArgs].push(tok.text);
3769 + }
3770 + }
3771 + // replacement text, enclosed in '{' and '}' and properly nested
3772 + let { tokens } = parser.gullet.consumeArg();
3773 + if (insert) {
3774 + tokens.unshift(insert);
3775 + }
3776 +
3777 + if (funcName === "\\edef" || funcName === "\\xdef") {
3778 + tokens = parser.gullet.expandTokens(tokens);
3779 + if (tokens.length > parser.gullet.settings.maxExpand) {
3780 + throw new ParseError("Too many expansions in an " + funcName);
3781 + }
3782 + tokens.reverse(); // to fit in with stack order
3783 + }
3784 + // Final arg is the expansion of the macro
3785 + parser.gullet.macros.set(
3786 + name,
3787 + { tokens, numArgs, delimiters },
3788 + funcName === globalMap[funcName]
3789 + );
3790 + return { type: "internal", mode: parser.mode };
3791 + }
3792 + });
3793 +
3794 + // <simple assignment> -> <let assignment>
3795 + // <let assignment> -> \futurelet<control sequence><token><token>
3796 + // | \let<control sequence><equals><one optional space><token>
3797 + // <equals> -> <optional spaces>|<optional spaces>=
3798 + defineFunction({
3799 + type: "internal",
3800 + names: [
3801 + "\\let",
3802 + "\\\\globallet" // can’t be entered directly
3803 + ],
3804 + props: {
3805 + numArgs: 0,
3806 + allowedInText: true,
3807 + primitive: true
3808 + },
3809 + handler({ parser, funcName }) {
3810 + const name = checkControlSequence(parser.gullet.popToken());
3811 + parser.gullet.consumeSpaces();
3812 + const tok = getRHS(parser);
3813 + letCommand(parser, name, tok, funcName === "\\\\globallet");
3814 + return { type: "internal", mode: parser.mode };
3815 + }
3816 + });
3817 +
3818 + // ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf
3819 + defineFunction({
3820 + type: "internal",
3821 + names: [
3822 + "\\futurelet",
3823 + "\\\\globalfuture" // can’t be entered directly
3824 + ],
3825 + props: {
3826 + numArgs: 0,
3827 + allowedInText: true,
3828 + primitive: true
3829 + },
3830 + handler({ parser, funcName }) {
3831 + const name = checkControlSequence(parser.gullet.popToken());
3832 + const middle = parser.gullet.popToken();
3833 + const tok = parser.gullet.popToken();
3834 + letCommand(parser, name, tok, funcName === "\\\\globalfuture");
3835 + parser.gullet.pushToken(tok);
3836 + parser.gullet.pushToken(middle);
3837 + return { type: "internal", mode: parser.mode };
3838 + }
3839 + });
3840 +
3841 + defineFunction({
3842 + type: "internal",
3843 + names: ["\\newcommand", "\\renewcommand", "\\providecommand"],
3844 + props: {
3845 + numArgs: 0,
3846 + allowedInText: true,
3847 + primitive: true
3848 + },
3849 + handler({ parser, funcName }) {
3850 + let name = "";
3851 + const tok = parser.gullet.popToken();
3852 + if (tok.text === "{") {
3853 + name = checkControlSequence(parser.gullet.popToken());
3854 + parser.gullet.popToken();
3855 + } else {
3856 + name = checkControlSequence(tok);
3857 + }
3858 +
3859 + const exists = parser.gullet.isDefined(name);
3860 + if (exists && funcName === "\\newcommand") {
3861 + throw new ParseError(
3862 + `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand`
3863 + );
3864 + }
3865 + if (!exists && funcName === "\\renewcommand") {
3866 + throw new ParseError(
3867 + `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand`
3868 + );
3869 + }
3870 +
3871 + let numArgs = 0;
3872 + if (parser.gullet.future().text === "[") {
3873 + let tok = parser.gullet.popToken();
3874 + tok = parser.gullet.popToken();
3875 + if (!/^[0-9]$/.test(tok.text)) {
3876 + throw new ParseError(`Invalid number of arguments: "${tok.text}"`);
3877 + }
3878 + numArgs = parseInt(tok.text);
3879 + tok = parser.gullet.popToken();
3880 + if (tok.text !== "]") {
3881 + throw new ParseError(`Invalid argument "${tok.text}"`);
3882 + }
3883 + }
3884 +
3885 + // replacement text, enclosed in '{' and '}' and properly nested
3886 + const { tokens } = parser.gullet.consumeArg();
3887 +
3888 + if (!(funcName === "\\providecommand" && parser.gullet.macros.has(name))) {
3889 + // Ignore \providecommand
3890 + parser.gullet.macros.set(
3891 + name,
3892 + { tokens, numArgs }
3893 + );
3894 + }
3895 +
3896 + return { type: "internal", mode: parser.mode };
3897 +
3898 + }
3899 + });
3900 +
3901 + // Extra data needed for the delimiter handler down below
3902 + const delimiterSizes = {
3903 + "\\bigl": { mclass: "mopen", size: 1 },
3904 + "\\Bigl": { mclass: "mopen", size: 2 },
3905 + "\\biggl": { mclass: "mopen", size: 3 },
3906 + "\\Biggl": { mclass: "mopen", size: 4 },
3907 + "\\bigr": { mclass: "mclose", size: 1 },
3908 + "\\Bigr": { mclass: "mclose", size: 2 },
3909 + "\\biggr": { mclass: "mclose", size: 3 },
3910 + "\\Biggr": { mclass: "mclose", size: 4 },
3911 + "\\bigm": { mclass: "mrel", size: 1 },
3912 + "\\Bigm": { mclass: "mrel", size: 2 },
3913 + "\\biggm": { mclass: "mrel", size: 3 },
3914 + "\\Biggm": { mclass: "mrel", size: 4 },
3915 + "\\big": { mclass: "mord", size: 1 },
3916 + "\\Big": { mclass: "mord", size: 2 },
3917 + "\\bigg": { mclass: "mord", size: 3 },
3918 + "\\Bigg": { mclass: "mord", size: 4 }
3919 + };
3920 +
3921 + const delimiters = [
3922 + "(",
3923 + "\\lparen",
3924 + ")",
3925 + "\\rparen",
3926 + "[",
3927 + "\\lbrack",
3928 + "]",
3929 + "\\rbrack",
3930 + "\\{",
3931 + "\\lbrace",
3932 + "\\}",
3933 + "\\rbrace",
3934 + "⦇",
3935 + "\\llparenthesis",
3936 + "⦈",
3937 + "\\rrparenthesis",
3938 + "\\lfloor",
3939 + "\\rfloor",
3940 + "\u230a",
3941 + "\u230b",
3942 + "\\lceil",
3943 + "\\rceil",
3944 + "\u2308",
3945 + "\u2309",
3946 + "<",
3947 + ">",
3948 + "\\langle",
3949 + "\u27e8",
3950 + "\\rangle",
3951 + "\u27e9",
3952 + "\\lAngle",
3953 + "\u27ea",
3954 + "\\rAngle",
3955 + "\u27eb",
3956 + "\\llangle",
3957 + "⦉",
3958 + "\\rrangle",
3959 + "⦊",
3960 + "\\lt",
3961 + "\\gt",
3962 + "\\lvert",
3963 + "\\rvert",
3964 + "\\lVert",
3965 + "\\rVert",
3966 + "\\lgroup",
3967 + "\\rgroup",
3968 + "\u27ee",
3969 + "\u27ef",
3970 + "\\lmoustache",
3971 + "\\rmoustache",
3972 + "\u23b0",
3973 + "\u23b1",
3974 + "\\llbracket",
3975 + "\\rrbracket",
3976 + "\u27e6",
3977 + "\u27e6",
3978 + "\\lBrace",
3979 + "\\rBrace",
3980 + "\u2983",
3981 + "\u2984",
3982 + "/",
3983 + "\\backslash",
3984 + "|",
3985 + "\\vert",
3986 + "\\|",
3987 + "\\Vert",
3988 + "\u2016",
3989 + "\\uparrow",
3990 + "\\Uparrow",
3991 + "\\downarrow",
3992 + "\\Downarrow",
3993 + "\\updownarrow",
3994 + "\\Updownarrow",
3995 + "."
3996 + ];
3997 +
3998 + // Export isDelimiter for benefit of parser.
3999 + const dels = ["}", "\\left", "\\middle", "\\right"];
4000 + const isDelimiter = str => str.length > 0 &&
4001 + (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str));
4002 +
4003 + // Metrics of the different sizes. Found by looking at TeX's output of
4004 + // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
4005 + // Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
4006 + const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
4007 +
4008 + // Delimiter functions
4009 + function checkDelimiter(delim, context) {
4010 + const symDelim = checkSymbolNodeType(delim);
4011 + if (symDelim && delimiters.includes(symDelim.text)) {
4012 + // If a character is not in the MathML operator dictionary, it will not stretch.
4013 + // Replace such characters w/characters that will stretch.
4014 + if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; }
4015 + if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; }
4016 + return symDelim;
4017 + } else if (symDelim) {
4018 + throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
4019 + } else {
4020 + throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim);
4021 + }
4022 + }
4023 +
4024 + // / \
4025 + const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
4026 +
4027 + defineFunction({
4028 + type: "delimsizing",
4029 + names: [
4030 + "\\bigl",
4031 + "\\Bigl",
4032 + "\\biggl",
4033 + "\\Biggl",
4034 + "\\bigr",
4035 + "\\Bigr",
4036 + "\\biggr",
4037 + "\\Biggr",
4038 + "\\bigm",
4039 + "\\Bigm",
4040 + "\\biggm",
4041 + "\\Biggm",
4042 + "\\big",
4043 + "\\Big",
4044 + "\\bigg",
4045 + "\\Bigg"
4046 + ],
4047 + props: {
4048 + numArgs: 1,
4049 + argTypes: ["primitive"]
4050 + },
4051 + handler: (context, args) => {
4052 + const delim = checkDelimiter(args[0], context);
4053 +
4054 + return {
4055 + type: "delimsizing",
4056 + mode: context.parser.mode,
4057 + size: delimiterSizes[context.funcName].size,
4058 + mclass: delimiterSizes[context.funcName].mclass,
4059 + delim: delim.text
4060 + };
4061 + },
4062 + mathmlBuilder: (group) => {
4063 + const children = [];
4064 +
4065 + if (group.delim === ".") { group.delim = ""; }
4066 + children.push(makeText(group.delim, group.mode));
4067 +
4068 + const node = new mathMLTree.MathNode("mo", children);
4069 +
4070 + if (group.mclass === "mopen" || group.mclass === "mclose") {
4071 + // Only some of the delimsizing functions act as fences, and they
4072 + // return "mopen" or "mclose" mclass.
4073 + node.setAttribute("fence", "true");
4074 + } else {
4075 + // Explicitly disable fencing if it's not a fence, to override the
4076 + // defaults.
4077 + node.setAttribute("fence", "false");
4078 + }
4079 + if (needExplicitStretch.includes(group.delim) || group.delim.indexOf("arrow") > -1) {
4080 + // We have to explicitly set stretchy to true.
4081 + node.setAttribute("stretchy", "true");
4082 + }
4083 + node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
4084 + node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
4085 + node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em");
4086 + return node;
4087 + }
4088 + });
4089 +
4090 + function assertParsed(group) {
4091 + if (!group.body) {
4092 + throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
4093 + }
4094 + }
4095 +
4096 + defineFunction({
4097 + type: "leftright-right",
4098 + names: ["\\right"],
4099 + props: {
4100 + numArgs: 1,
4101 + argTypes: ["primitive"]
4102 + },
4103 + handler: (context, args) => {
4104 + return {
4105 + type: "leftright-right",
4106 + mode: context.parser.mode,
4107 + delim: checkDelimiter(args[0], context).text
4108 + };
4109 + }
4110 + });
4111 +
4112 + defineFunction({
4113 + type: "leftright",
4114 + names: ["\\left"],
4115 + props: {
4116 + numArgs: 1,
4117 + argTypes: ["primitive"]
4118 + },
4119 + handler: (context, args) => {
4120 + const delim = checkDelimiter(args[0], context);
4121 +
4122 + const parser = context.parser;
4123 + // Parse out the implicit body
4124 + ++parser.leftrightDepth;
4125 + // parseExpression stops before '\\right' or `\\middle`
4126 + let body = parser.parseExpression(false, null, true);
4127 + let nextToken = parser.fetch();
4128 + while (nextToken.text === "\\middle") {
4129 + // `\middle`, from the ε-TeX package, ends one group and starts another group.
4130 + // We had to parse this expression with `breakOnMiddle` enabled in order
4131 + // to get TeX-compliant parsing of \over.
4132 + // But we do not want, at this point, to end on \middle, so continue
4133 + // to parse until we fetch a `\right`.
4134 + parser.consume();
4135 + const middle = parser.fetch().text;
4136 + if (!symbols.math[middle]) {
4137 + throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`);
4138 + }
4139 + checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
4140 + body.push({ type: "middle", mode: "math", delim: middle });
4141 + parser.consume();
4142 + body = body.concat(parser.parseExpression(false, null, true));
4143 + nextToken = parser.fetch();
4144 + }
4145 + --parser.leftrightDepth;
4146 + // Check the next token
4147 + parser.expect("\\right", false);
4148 + const right = assertNodeType(parser.parseFunction(), "leftright-right");
4149 + return {
4150 + type: "leftright",
4151 + mode: parser.mode,
4152 + body,
4153 + left: delim.text,
4154 + right: right.delim
4155 + };
4156 + },
4157 + mathmlBuilder: (group, style) => {
4158 + assertParsed(group);
4159 + const inner = buildExpression(group.body, style);
4160 +
4161 + if (group.left === ".") { group.left = ""; }
4162 + const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]);
4163 + leftNode.setAttribute("fence", "true");
4164 + leftNode.setAttribute("form", "prefix");
4165 + if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
4166 + leftNode.setAttribute("stretchy", "true");
4167 + }
4168 + inner.unshift(leftNode);
4169 +
4170 + if (group.right === ".") { group.right = ""; }
4171 + const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]);
4172 + rightNode.setAttribute("fence", "true");
4173 + rightNode.setAttribute("form", "postfix");
4174 + if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
4175 + rightNode.setAttribute("stretchy", "true");
4176 + }
4177 + if (group.body.length > 0) {
4178 + const lastElement = group.body[group.body.length - 1];
4179 + if (lastElement.type === "color" && !lastElement.isTextColor) {
4180 + // \color is a switch. If the last element is of type "color" then
4181 + // the user set the \color switch and left it on.
4182 + // A \right delimiter turns the switch off, but the delimiter itself gets the color.
4183 + rightNode.setAttribute("mathcolor", lastElement.color);
4184 + }
4185 + }
4186 + inner.push(rightNode);
4187 +
4188 + return makeRow(inner);
4189 + }
4190 + });
4191 +
4192 + defineFunction({
4193 + type: "middle",
4194 + names: ["\\middle"],
4195 + props: {
4196 + numArgs: 1,
4197 + argTypes: ["primitive"]
4198 + },
4199 + handler: (context, args) => {
4200 + const delim = checkDelimiter(args[0], context);
4201 + if (!context.parser.leftrightDepth) {
4202 + throw new ParseError("\\middle without preceding \\left", delim);
4203 + }
4204 +
4205 + return {
4206 + type: "middle",
4207 + mode: context.parser.mode,
4208 + delim: delim.text
4209 + };
4210 + },
4211 + mathmlBuilder: (group, style) => {
4212 + const textNode = makeText(group.delim, group.mode);
4213 + const middleNode = new mathMLTree.MathNode("mo", [textNode]);
4214 + middleNode.setAttribute("fence", "true");
4215 + if (group.delim.indexOf("arrow") > -1) {
4216 + middleNode.setAttribute("stretchy", "true");
4217 + }
4218 + // The next line is not semantically correct, but
4219 + // Chromium fails to stretch if it is not there.
4220 + middleNode.setAttribute("form", "prefix");
4221 + // MathML gives 5/18em spacing to each <mo> element.
4222 + // \middle should get delimiter spacing instead.
4223 + middleNode.setAttribute("lspace", "0.05em");
4224 + middleNode.setAttribute("rspace", "0.05em");
4225 + return middleNode;
4226 + }
4227 + });
4228 +
4229 + const padding$1 = _ => {
4230 + const node = new mathMLTree.MathNode("mspace");
4231 + node.setAttribute("width", "3pt");
4232 + return node
4233 + };
4234 +
4235 + const mathmlBuilder$8 = (group, style) => {
4236 + let node;
4237 + if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") {
4238 + // MathML core does not support +width attribute in <mpadded>.
4239 + // Firefox does not reliably add side padding.
4240 + // Insert <mspace>
4241 + node = new mathMLTree.MathNode("mrow", [
4242 + padding$1(),
4243 + buildGroup$1(group.body, style),
4244 + padding$1()
4245 + ]);
4246 + } else {
4247 + node = new mathMLTree.MathNode("menclose", [buildGroup$1(group.body, style)]);
4248 + }
4249 + switch (group.label) {
4250 + case "\\overline":
4251 + node.setAttribute("notation", "top"); // for Firefox & WebKit
4252 + node.classes.push("tml-overline"); // for Chromium
4253 + break
4254 + case "\\underline":
4255 + node.setAttribute("notation", "bottom");
4256 + node.classes.push("tml-underline");
4257 + break
4258 + case "\\cancel":
4259 + node.setAttribute("notation", "updiagonalstrike");
4260 + node.children.push(new mathMLTree.MathNode("mrow", [], ["tml-cancel", "upstrike"]));
4261 + break
4262 + case "\\bcancel":
4263 + node.setAttribute("notation", "downdiagonalstrike");
4264 + node.children.push(new mathMLTree.MathNode("mrow", [], ["tml-cancel", "downstrike"]));
4265 + break
4266 + case "\\sout":
4267 + node.setAttribute("notation", "horizontalstrike");
4268 + node.children.push(new mathMLTree.MathNode("mrow", [], ["tml-cancel", "sout"]));
4269 + break
4270 + case "\\xcancel":
4271 + node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
4272 + node.classes.push("tml-xcancel");
4273 + break
4274 + case "\\longdiv":
4275 + node.setAttribute("notation", "longdiv");
4276 + node.classes.push("longdiv-top");
4277 + node.children.push(new mathMLTree.MathNode("mrow", [], ["longdiv-arc"]));
4278 + break
4279 + case "\\phase":
4280 + node.setAttribute("notation", "phasorangle");
4281 + node.classes.push("phasor-bottom");
4282 + node.children.push(new mathMLTree.MathNode("mrow", [], ["phasor-angle"]));
4283 + break
4284 + case "\\textcircled":
4285 + node.setAttribute("notation", "circle");
4286 + node.classes.push("circle-pad");
4287 + node.children.push(new mathMLTree.MathNode("mrow", [], ["textcircle"]));
4288 + break
4289 + case "\\angl":
4290 + node.setAttribute("notation", "actuarial");
4291 + node.classes.push("actuarial");
4292 + break
4293 + case "\\boxed":
4294 + // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
4295 + node.setAttribute("notation", "box");
4296 + node.classes.push("tml-box");
4297 + node.setAttribute("scriptlevel", "0");
4298 + node.setAttribute("displaystyle", "true");
4299 + break
4300 + case "\\fbox":
4301 + node.setAttribute("notation", "box");
4302 + node.classes.push("tml-fbox");
4303 + break
4304 + case "\\fcolorbox":
4305 + case "\\colorbox": {
4306 + // <menclose> doesn't have a good notation option for \colorbox.
4307 + // So use <mpadded> instead. Set some attributes that come
4308 + // included with <menclose>.
4309 + //const fboxsep = 3; // 3 pt from LaTeX source2e
4310 + //node.setAttribute("height", `+${2 * fboxsep}pt`)
4311 + //node.setAttribute("voffset", `${fboxsep}pt`)
4312 + const style = { padding: "3pt 0 3pt 0" };
4313 +
4314 + if (group.label === "\\fcolorbox") {
4315 + style.border = "0.0667em solid " + String(group.borderColor);
4316 + }
4317 + node.style = style;
4318 + break
4319 + }
4320 + }
4321 + if (group.backgroundColor) {
4322 + node.setAttribute("mathbackground", group.backgroundColor);
4323 + }
4324 + return node;
4325 + };
4326 +
4327 + defineFunction({
4328 + type: "enclose",
4329 + names: ["\\colorbox"],
4330 + props: {
4331 + numArgs: 2,
4332 + numOptionalArgs: 1,
4333 + allowedInText: true,
4334 + argTypes: ["raw", "raw", "text"]
4335 + },
4336 + handler({ parser, funcName }, args, optArgs) {
4337 + const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string;
4338 + let color = "";
4339 + if (model) {
4340 + const spec = assertNodeType(args[0], "raw").string;
4341 + color = colorFromSpec(model, spec);
4342 + } else {
4343 + color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros);
4344 + }
4345 + const body = args[1];
4346 + return {
4347 + type: "enclose",
4348 + mode: parser.mode,
4349 + label: funcName,
4350 + backgroundColor: color,
4351 + body
4352 + };
4353 + },
4354 + mathmlBuilder: mathmlBuilder$8
4355 + });
4356 +
4357 + defineFunction({
4358 + type: "enclose",
4359 + names: ["\\fcolorbox"],
4360 + props: {
4361 + numArgs: 3,
4362 + numOptionalArgs: 1,
4363 + allowedInText: true,
4364 + argTypes: ["raw", "raw", "raw", "text"]
4365 + },
4366 + handler({ parser, funcName }, args, optArgs) {
4367 + const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string;
4368 + let borderColor = "";
4369 + let backgroundColor;
4370 + if (model) {
4371 + const borderSpec = assertNodeType(args[0], "raw").string;
4372 + const backgroundSpec = assertNodeType(args[0], "raw").string;
4373 + borderColor = colorFromSpec(model, borderSpec);
4374 + backgroundColor = colorFromSpec(model, backgroundSpec);
4375 + } else {
4376 + borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros);
4377 + backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros);
4378 + }
4379 + const body = args[2];
4380 + return {
4381 + type: "enclose",
4382 + mode: parser.mode,
4383 + label: funcName,
4384 + backgroundColor,
4385 + borderColor,
4386 + body
4387 + };
4388 + },
4389 + mathmlBuilder: mathmlBuilder$8
4390 + });
4391 +
4392 + defineFunction({
4393 + type: "enclose",
4394 + names: ["\\fbox"],
4395 + props: {
4396 + numArgs: 1,
4397 + argTypes: ["hbox"],
4398 + allowedInText: true
4399 + },
4400 + handler({ parser }, args) {
4401 + return {
4402 + type: "enclose",
4403 + mode: parser.mode,
4404 + label: "\\fbox",
4405 + body: args[0]
4406 + };
4407 + }
4408 + });
4409 +
4410 + defineFunction({
4411 + type: "enclose",
4412 + names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline",
4413 + "\\boxed", "\\longdiv", "\\phase"],
4414 + props: {
4415 + numArgs: 1
4416 + },
4417 + handler({ parser, funcName }, args) {
4418 + const body = args[0];
4419 + return {
4420 + type: "enclose",
4421 + mode: parser.mode,
4422 + label: funcName,
4423 + body
4424 + };
4425 + },
4426 + mathmlBuilder: mathmlBuilder$8
4427 + });
4428 +
4429 + defineFunction({
4430 + type: "enclose",
4431 + names: ["\\underline"],
4432 + props: {
4433 + numArgs: 1,
4434 + allowedInText: true
4435 + },
4436 + handler({ parser, funcName }, args) {
4437 + const body = args[0];
4438 + return {
4439 + type: "enclose",
4440 + mode: parser.mode,
4441 + label: funcName,
4442 + body
4443 + };
4444 + },
4445 + mathmlBuilder: mathmlBuilder$8
4446 + });
4447 +
4448 +
4449 + defineFunction({
4450 + type: "enclose",
4451 + names: ["\\textcircled"],
4452 + props: {
4453 + numArgs: 1,
4454 + argTypes: ["text"],
4455 + allowedInArgument: true,
4456 + allowedInText: true
4457 + },
4458 + handler({ parser, funcName }, args) {
4459 + const body = args[0];
4460 + return {
4461 + type: "enclose",
4462 + mode: parser.mode,
4463 + label: funcName,
4464 + body
4465 + };
4466 + },
4467 + mathmlBuilder: mathmlBuilder$8
4468 + });
4469 +
4470 + /**
4471 + * All registered environments.
4472 + * `environments.js` exports this same dictionary again and makes it public.
4473 + * `Parser.js` requires this dictionary via `environments.js`.
4474 + */
4475 + const _environments = {};
4476 +
4477 + function defineEnvironment({ type, names, props, handler, mathmlBuilder }) {
4478 + // Set default values of environments.
4479 + const data = {
4480 + type,
4481 + numArgs: props.numArgs || 0,
4482 + allowedInText: false,
4483 + numOptionalArgs: 0,
4484 + handler
4485 + };
4486 + for (let i = 0; i < names.length; ++i) {
4487 + _environments[names[i]] = data;
4488 + }
4489 + if (mathmlBuilder) {
4490 + _mathmlGroupBuilders[type] = mathmlBuilder;
4491 + }
4492 + }
4493 +
4494 + /**
4495 + * Lexing or parsing positional information for error reporting.
4496 + * This object is immutable.
4497 + */
4498 + class SourceLocation {
4499 + constructor(lexer, start, end) {
4500 + this.lexer = lexer; // Lexer holding the input string.
4501 + this.start = start; // Start offset, zero-based inclusive.
4502 + this.end = end; // End offset, zero-based exclusive.
4503 + }
4504 +
4505 + /**
4506 + * Merges two `SourceLocation`s from location providers, given they are
4507 + * provided in order of appearance.
4508 + * - Returns the first one's location if only the first is provided.
4509 + * - Returns a merged range of the first and the last if both are provided
4510 + * and their lexers match.
4511 + * - Otherwise, returns null.
4512 + */
4513 + static range(first, second) {
4514 + if (!second) {
4515 + return first && first.loc;
4516 + } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) {
4517 + return null;
4518 + } else {
4519 + return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end);
4520 + }
4521 + }
4522 + }
4523 +
4524 + /**
4525 + * Interface required to break circular dependency between Token, Lexer, and
4526 + * ParseError.
4527 + */
4528 +
4529 + /**
4530 + * The resulting token returned from `lex`.
4531 + *
4532 + * It consists of the token text plus some position information.
4533 + * The position information is essentially a range in an input string,
4534 + * but instead of referencing the bare input string, we refer to the lexer.
4535 + * That way it is possible to attach extra metadata to the input string,
4536 + * like for example a file name or similar.
4537 + *
4538 + * The position information is optional, so it is OK to construct synthetic
4539 + * tokens if appropriate. Not providing available position information may
4540 + * lead to degraded error reporting, though.
4541 + */
4542 + class Token {
4543 + constructor(
4544 + text, // the text of this token
4545 + loc
4546 + ) {
4547 + this.text = text;
4548 + this.loc = loc;
4549 + }
4550 +
4551 + /**
4552 + * Given a pair of tokens (this and endToken), compute a `Token` encompassing
4553 + * the whole input range enclosed by these two.
4554 + */
4555 + range(
4556 + endToken, // last token of the range, inclusive
4557 + text // the text of the newly constructed token
4558 + ) {
4559 + return new Token(text, SourceLocation.range(this, endToken));
4560 + }
4561 + }
4562 +
4563 + // In TeX, there are actually three sets of dimensions, one for each of
4564 + // textstyle, scriptstyle, and scriptscriptstyle. These are
4565 + // provided in the the arrays below, in that order.
4566 + //
4567 +
4568 + // Math style is not quite the same thing as script level.
4569 + const StyleLevel = {
4570 + DISPLAY: 0,
4571 + TEXT: 1,
4572 + SCRIPT: 2,
4573 + SCRIPTSCRIPT: 3
4574 + };
4575 +
4576 + /**
4577 + * All registered global/built-in macros.
4578 + * `macros.js` exports this same dictionary again and makes it public.
4579 + * `Parser.js` requires this dictionary via `macros.js`.
4580 + */
4581 + const _macros = {};
4582 +
4583 + // This function might one day accept an additional argument and do more things.
4584 + function defineMacro(name, body) {
4585 + _macros[name] = body;
4586 + }
4587 +
4588 + /**
4589 + * Predefined macros for Temml.
4590 + * This can be used to define some commands in terms of others.
4591 + */
4592 +
4593 + const macros = _macros;
4594 +
4595 + //////////////////////////////////////////////////////////////////////
4596 + // macro tools
4597 +
4598 + defineMacro("\\noexpand", function(context) {
4599 + // The expansion is the token itself; but that token is interpreted
4600 + // as if its meaning were ‘\relax’ if it is a control sequence that
4601 + // would ordinarily be expanded by TeX’s expansion rules.
4602 + const t = context.popToken();
4603 + if (context.isExpandable(t.text)) {
4604 + t.noexpand = true;
4605 + t.treatAsRelax = true;
4606 + }
4607 + return { tokens: [t], numArgs: 0 };
4608 + });
4609 +
4610 + defineMacro("\\expandafter", function(context) {
4611 + // TeX first reads the token that comes immediately after \expandafter,
4612 + // without expanding it; let’s call this token t. Then TeX reads the
4613 + // token that comes after t (and possibly more tokens, if that token
4614 + // has an argument), replacing it by its expansion. Finally TeX puts
4615 + // t back in front of that expansion.
4616 + const t = context.popToken();
4617 + context.expandOnce(true); // expand only an expandable token
4618 + return { tokens: [t], numArgs: 0 };
4619 + });
4620 +
4621 + // LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2
4622 + // TeX source: \long\def\@firstoftwo#1#2{#1}
4623 + defineMacro("\\@firstoftwo", function(context) {
4624 + const args = context.consumeArgs(2);
4625 + return { tokens: args[0], numArgs: 0 };
4626 + });
4627 +
4628 + // LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1
4629 + // TeX source: \long\def\@secondoftwo#1#2{#2}
4630 + defineMacro("\\@secondoftwo", function(context) {
4631 + const args = context.consumeArgs(2);
4632 + return { tokens: args[1], numArgs: 0 };
4633 + });
4634 +
4635 + // LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded)
4636 + // symbol that isn't a space, consuming any spaces but not consuming the
4637 + // first nonspace character. If that nonspace character matches #1, then
4638 + // the macro expands to #2; otherwise, it expands to #3.
4639 + defineMacro("\\@ifnextchar", function(context) {
4640 + const args = context.consumeArgs(3); // symbol, if, else
4641 + context.consumeSpaces();
4642 + const nextToken = context.future();
4643 + if (args[0].length === 1 && args[0][0].text === nextToken.text) {
4644 + return { tokens: args[1], numArgs: 0 };
4645 + } else {
4646 + return { tokens: args[2], numArgs: 0 };
4647 + }
4648 + });
4649 +
4650 + // LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol.
4651 + // If it is `*`, then it consumes the symbol, and the macro expands to #1;
4652 + // otherwise, the macro expands to #2 (without consuming the symbol).
4653 + // TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}}
4654 + defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}");
4655 +
4656 + // LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode
4657 + defineMacro("\\TextOrMath", function(context) {
4658 + const args = context.consumeArgs(2);
4659 + if (context.mode === "text") {
4660 + return { tokens: args[0], numArgs: 0 };
4661 + } else {
4662 + return { tokens: args[1], numArgs: 0 };
4663 + }
4664 + });
4665 +
4666 + const stringFromArg = arg => {
4667 + // Reverse the order of the arg and return a string.
4668 + let str = "";
4669 + for (let i = arg.length - 1; i > -1; i--) {
4670 + str += arg[i].text;
4671 + }
4672 + return str
4673 + };
4674 +
4675 + // Lookup table for parsing numbers in base 8 through 16
4676 + const digitToNumber = {
4677 + 0: 0,
4678 + 1: 1,
4679 + 2: 2,
4680 + 3: 3,
4681 + 4: 4,
4682 + 5: 5,
4683 + 6: 6,
4684 + 7: 7,
4685 + 8: 8,
4686 + 9: 9,
4687 + a: 10,
4688 + A: 10,
4689 + b: 11,
4690 + B: 11,
4691 + c: 12,
4692 + C: 12,
4693 + d: 13,
4694 + D: 13,
4695 + e: 14,
4696 + E: 14,
4697 + f: 15,
4698 + F: 15
4699 + };
4700 +
4701 + const nextCharNumber = context => {
4702 + const numStr = context.future().text;
4703 + if (numStr === "EOF") { return [null, ""] }
4704 + return [digitToNumber[numStr.charAt(0)], numStr]
4705 + };
4706 +
4707 + const appendCharNumbers = (number, numStr, base) => {
4708 + for (let i = 1; i < numStr.length; i++) {
4709 + const digit = digitToNumber[numStr.charAt(i)];
4710 + number *= base;
4711 + number += digit;
4712 + }
4713 + return number
4714 + };
4715 +
4716 + // TeX \char makes a literal character (catcode 12) using the following forms:
4717 + // (see The TeXBook, p. 43)
4718 + // \char123 -- decimal
4719 + // \char'123 -- octal
4720 + // \char"123 -- hex
4721 + // \char`x -- character that can be written (i.e. isn't active)
4722 + // \char`\x -- character that cannot be written (e.g. %)
4723 + // These all refer to characters from the font, so we turn them into special
4724 + // calls to a function \@char dealt with in the Parser.
4725 + defineMacro("\\char", function(context) {
4726 + let token = context.popToken();
4727 + let base;
4728 + let number = "";
4729 + if (token.text === "'") {
4730 + base = 8;
4731 + token = context.popToken();
4732 + } else if (token.text === '"') {
4733 + base = 16;
4734 + token = context.popToken();
4735 + } else if (token.text === "`") {
4736 + token = context.popToken();
4737 + if (token.text[0] === "\\") {
4738 + number = token.text.charCodeAt(1);
4739 + } else if (token.text === "EOF") {
4740 + throw new ParseError("\\char` missing argument");
4741 + } else {
4742 + number = token.text.charCodeAt(0);
4743 + }
4744 + } else {
4745 + base = 10;
4746 + }
4747 + if (base) {
4748 + // Parse a number in the given base, starting with first `token`.
4749 + let numStr = token.text;
4750 + number = digitToNumber[numStr.charAt(0)];
4751 + if (number == null || number >= base) {
4752 + throw new ParseError(`Invalid base-${base} digit ${token.text}`);
4753 + }
4754 + number = appendCharNumbers(number, numStr, base);
4755 + let digit;
4756 + [digit, numStr] = nextCharNumber(context);
4757 + while (digit != null && digit < base) {
4758 + number *= base;
4759 + number += digit;
4760 + number = appendCharNumbers(number, numStr, base);
4761 + context.popToken();
4762 + [digit, numStr] = nextCharNumber(context);
4763 + }
4764 + }
4765 + return `\\@char{${number}}`;
4766 + });
4767 +
4768 + function recreateArgStr(context) {
4769 + // Recreate the macro's original argument string from the array of parse tokens.
4770 + const tokens = context.consumeArgs(1)[0];
4771 + let str = "";
4772 + let expectedLoc = tokens[tokens.length - 1].loc.start;
4773 + for (let i = tokens.length - 1; i >= 0; i--) {
4774 + const actualLoc = tokens[i].loc.start;
4775 + if (actualLoc > expectedLoc) {
4776 + // context.consumeArgs has eaten a space.
4777 + str += " ";
4778 + expectedLoc = actualLoc;
4779 + }
4780 + str += tokens[i].text;
4781 + expectedLoc += tokens[i].text.length;
4782 + }
4783 + return str
4784 + }
4785 +
4786 + // The Latin Modern font renders <mi>√</mi> at the wrong vertical alignment.
4787 + // This macro provides a better rendering.
4788 + defineMacro("\\surd", '\\sqrt{\\vphantom{|}}');
4789 +
4790 + // See comment for \oplus in symbols.js.
4791 + defineMacro("\u2295", "\\oplus");
4792 +
4793 + // Since Temml has no \par, ignore \long.
4794 + defineMacro("\\long", "");
4795 +
4796 + //////////////////////////////////////////////////////////////////////
4797 + // Grouping
4798 + // \let\bgroup={ \let\egroup=}
4799 + defineMacro("\\bgroup", "{");
4800 + defineMacro("\\egroup", "}");
4801 +
4802 + // Symbols from latex.ltx:
4803 + // \def~{\nobreakspace{}}
4804 + // \def\lq{`}
4805 + // \def\rq{'}
4806 + // \def \aa {\r a}
4807 + defineMacro("~", "\\nobreakspace");
4808 + defineMacro("\\lq", "`");
4809 + defineMacro("\\rq", "'");
4810 + defineMacro("\\aa", "\\r a");
4811 +
4812 + defineMacro("\\Bbbk", "\\Bbb{k}");
4813 +
4814 + // \mathstrut from the TeXbook, p 360
4815 + defineMacro("\\mathstrut", "\\vphantom{(}");
4816 +
4817 + // \underbar from TeXbook p 353
4818 + defineMacro("\\underbar", "\\underline{\\text{#1}}");
4819 +
4820 + //////////////////////////////////////////////////////////////////////
4821 + // LaTeX_2ε
4822 +
4823 + // \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@
4824 + // \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
4825 + // We'll call \varvdots, which gets a glyph from symbols.js.
4826 + // The zero-width rule gets us an equivalent to the vertical 6pt kern.
4827 + defineMacro("\\vdots", "{\\varvdots\\rule{0pt}{15pt}}");
4828 + defineMacro("\u22ee", "\\vdots");
4829 +
4830 + // {array} environment gaps
4831 + defineMacro("\\arraystretch", "1"); // line spacing factor times 12pt
4832 + defineMacro("\\arraycolsep", "6pt"); // half the width separating columns
4833 +
4834 + //////////////////////////////////////////////////////////////////////
4835 + // amsmath.sty
4836 + // http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf
4837 +
4838 + //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
4839 + defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}");
4840 +
4841 + // \def\iff{\DOTSB\;\Longleftrightarrow\;}
4842 + // \def\implies{\DOTSB\;\Longrightarrow\;}
4843 + // \def\impliedby{\DOTSB\;\Longleftarrow\;}
4844 + defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;");
4845 + defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;");
4846 + defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;");
4847 +
4848 + // AMSMath's automatic \dots, based on \mdots@@ macro.
4849 + const dotsByToken = {
4850 + ",": "\\dotsc",
4851 + "\\not": "\\dotsb",
4852 + // \keybin@ checks for the following:
4853 + "+": "\\dotsb",
4854 + "=": "\\dotsb",
4855 + "<": "\\dotsb",
4856 + ">": "\\dotsb",
4857 + "-": "\\dotsb",
4858 + "*": "\\dotsb",
4859 + ":": "\\dotsb",
4860 + // Symbols whose definition starts with \DOTSB:
4861 + "\\DOTSB": "\\dotsb",
4862 + "\\coprod": "\\dotsb",
4863 + "\\bigvee": "\\dotsb",
4864 + "\\bigwedge": "\\dotsb",
4865 + "\\biguplus": "\\dotsb",
4866 + "\\bigcap": "\\dotsb",
4867 + "\\bigcup": "\\dotsb",
4868 + "\\prod": "\\dotsb",
4869 + "\\sum": "\\dotsb",
4870 + "\\bigotimes": "\\dotsb",
4871 + "\\bigoplus": "\\dotsb",
4872 + "\\bigodot": "\\dotsb",
4873 + "\\bigsqcap": "\\dotsb",
4874 + "\\bigsqcup": "\\dotsb",
4875 + "\\bigtimes": "\\dotsb",
4876 + "\\And": "\\dotsb",
4877 + "\\longrightarrow": "\\dotsb",
4878 + "\\Longrightarrow": "\\dotsb",
4879 + "\\longleftarrow": "\\dotsb",
4880 + "\\Longleftarrow": "\\dotsb",
4881 + "\\longleftrightarrow": "\\dotsb",
4882 + "\\Longleftrightarrow": "\\dotsb",
4883 + "\\mapsto": "\\dotsb",
4884 + "\\longmapsto": "\\dotsb",
4885 + "\\hookrightarrow": "\\dotsb",
4886 + "\\doteq": "\\dotsb",
4887 + // Symbols whose definition starts with \mathbin:
4888 + "\\mathbin": "\\dotsb",
4889 + // Symbols whose definition starts with \mathrel:
4890 + "\\mathrel": "\\dotsb",
4891 + "\\relbar": "\\dotsb",
4892 + "\\Relbar": "\\dotsb",
4893 + "\\xrightarrow": "\\dotsb",
4894 + "\\xleftarrow": "\\dotsb",
4895 + // Symbols whose definition starts with \DOTSI:
4896 + "\\DOTSI": "\\dotsi",
4897 + "\\int": "\\dotsi",
4898 + "\\oint": "\\dotsi",
4899 + "\\iint": "\\dotsi",
4900 + "\\iiint": "\\dotsi",
4901 + "\\iiiint": "\\dotsi",
4902 + "\\idotsint": "\\dotsi",
4903 + // Symbols whose definition starts with \DOTSX:
4904 + "\\DOTSX": "\\dotsx"
4905 + };
4906 +
4907 + defineMacro("\\dots", function(context) {
4908 + // TODO: If used in text mode, should expand to \textellipsis.
4909 + // However, in Temml, \textellipsis and \ldots behave the same
4910 + // (in text mode), and it's unlikely we'd see any of the math commands
4911 + // that affect the behavior of \dots when in text mode. So fine for now
4912 + // (until we support \ifmmode ... \else ... \fi).
4913 + let thedots = "\\dotso";
4914 + const next = context.expandAfterFuture().text;
4915 + if (next in dotsByToken) {
4916 + thedots = dotsByToken[next];
4917 + } else if (next.slice(0, 4) === "\\not") {
4918 + thedots = "\\dotsb";
4919 + } else if (next in symbols.math) {
4920 + if (["bin", "rel"].includes(symbols.math[next].group)) {
4921 + thedots = "\\dotsb";
4922 + }
4923 + }
4924 + return thedots;
4925 + });
4926 +
4927 + const spaceAfterDots = {
4928 + // \rightdelim@ checks for the following:
4929 + ")": true,
4930 + "]": true,
4931 + "\\rbrack": true,
4932 + "\\}": true,
4933 + "\\rbrace": true,
4934 + "\\rangle": true,
4935 + "\\rceil": true,
4936 + "\\rfloor": true,
4937 + "\\rgroup": true,
4938 + "\\rmoustache": true,
4939 + "\\right": true,
4940 + "\\bigr": true,
4941 + "\\biggr": true,
4942 + "\\Bigr": true,
4943 + "\\Biggr": true,
4944 + // \extra@ also tests for the following:
4945 + $: true,
4946 + // \extrap@ checks for the following:
4947 + ";": true,
4948 + ".": true,
4949 + ",": true
4950 + };
4951 +
4952 + defineMacro("\\dotso", function(context) {
4953 + const next = context.future().text;
4954 + if (next in spaceAfterDots) {
4955 + return "\\ldots\\,";
4956 + } else {
4957 + return "\\ldots";
4958 + }
4959 + });
4960 +
4961 + defineMacro("\\dotsc", function(context) {
4962 + const next = context.future().text;
4963 + // \dotsc uses \extra@ but not \extrap@, instead specially checking for
4964 + // ';' and '.', but doesn't check for ','.
4965 + if (next in spaceAfterDots && next !== ",") {
4966 + return "\\ldots\\,";
4967 + } else {
4968 + return "\\ldots";
4969 + }
4970 + });
4971 +
4972 + defineMacro("\\cdots", function(context) {
4973 + const next = context.future().text;
4974 + if (next in spaceAfterDots) {
4975 + return "\\@cdots\\,";
4976 + } else {
4977 + return "\\@cdots";
4978 + }
4979 + });
4980 +
4981 + defineMacro("\\dotsb", "\\cdots");
4982 + defineMacro("\\dotsm", "\\cdots");
4983 + defineMacro("\\dotsi", "\\!\\cdots");
4984 + defineMacro("\\idotsint", "\\dotsi");
4985 + // amsmath doesn't actually define \dotsx, but \dots followed by a macro
4986 + // starting with \DOTSX implies \dotso, and then \extra@ detects this case
4987 + // and forces the added `\,`.
4988 + defineMacro("\\dotsx", "\\ldots\\,");
4989 +
4990 + // \let\DOTSI\relax
4991 + // \let\DOTSB\relax
4992 + // \let\DOTSX\relax
4993 + defineMacro("\\DOTSI", "\\relax");
4994 + defineMacro("\\DOTSB", "\\relax");
4995 + defineMacro("\\DOTSX", "\\relax");
4996 +
4997 + // Spacing, based on amsmath.sty's override of LaTeX defaults
4998 + // \DeclareRobustCommand{\tmspace}[3]{%
4999 + // \ifmmode\mskip#1#2\else\kern#1#3\fi\relax}
5000 + defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax");
5001 + // \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}}
5002 + // TODO: math mode should use \thinmuskip
5003 + defineMacro("\\,", "{\\tmspace+{3mu}{.1667em}}");
5004 + // \let\thinspace\,
5005 + defineMacro("\\thinspace", "\\,");
5006 + // \def\>{\mskip\medmuskip}
5007 + // \renewcommand{\:}{\tmspace+\medmuskip{.2222em}}
5008 + // TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu
5009 + defineMacro("\\>", "\\mskip{4mu}");
5010 + defineMacro("\\:", "{\\tmspace+{4mu}{.2222em}}");
5011 + // \let\medspace\:
5012 + defineMacro("\\medspace", "\\:");
5013 + // \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}}
5014 + // TODO: math mode should use \thickmuskip = 5mu plus 5mu
5015 + defineMacro("\\;", "{\\tmspace+{5mu}{.2777em}}");
5016 + // \let\thickspace\;
5017 + defineMacro("\\thickspace", "\\;");
5018 + // \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}}
5019 + // TODO: math mode should use \thinmuskip
5020 + defineMacro("\\!", "{\\tmspace-{3mu}{.1667em}}");
5021 + // \let\negthinspace\!
5022 + defineMacro("\\negthinspace", "\\!");
5023 + // \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}}
5024 + // TODO: math mode should use \medmuskip
5025 + defineMacro("\\negmedspace", "{\\tmspace-{4mu}{.2222em}}");
5026 + // \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}}
5027 + // TODO: math mode should use \thickmuskip
5028 + defineMacro("\\negthickspace", "{\\tmspace-{5mu}{.277em}}");
5029 + // \def\enspace{\kern.5em }
5030 + defineMacro("\\enspace", "\\kern.5em ");
5031 + // \def\enskip{\hskip.5em\relax}
5032 + defineMacro("\\enskip", "\\hskip.5em\\relax");
5033 + // \def\quad{\hskip1em\relax}
5034 + defineMacro("\\quad", "\\hskip1em\\relax");
5035 + // \def\qquad{\hskip2em\relax}
5036 + defineMacro("\\qquad", "\\hskip2em\\relax");
5037 +
5038 + defineMacro("\\AA", "\\TextOrMath{\\Angstrom}{\\mathring{A}}\\relax");
5039 +
5040 + // \tag@in@display form of \tag
5041 + defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren");
5042 + defineMacro("\\tag@paren", "\\tag@literal{({#1})}");
5043 + defineMacro("\\tag@literal", (context) => {
5044 + if (context.macros.get("\\df@tag")) {
5045 + throw new ParseError("Multiple \\tag");
5046 + }
5047 + return "\\gdef\\df@tag{\\text{#1}}";
5048 + });
5049 + defineMacro("\\notag", "\\nonumber");
5050 + defineMacro("\\nonumber", "\\gdef\\@eqnsw{0}");
5051 +
5052 + // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin
5053 + // {\operator@font mod}\penalty900
5054 + // \mkern5mu\nonscript\mskip-\medmuskip}
5055 + // \newcommand{\pod}[1]{\allowbreak
5056 + // \if@display\mkern18mu\else\mkern8mu\fi(#1)}
5057 + // \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}}
5058 + // \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu
5059 + // \else\mkern12mu\fi{\operator@font mod}\,\,#1}
5060 + // TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu
5061 + defineMacro("\\bmod", "\\mathbin{\\text{mod}}");
5062 + defineMacro(
5063 + "\\pod",
5064 + "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"
5065 + );
5066 + defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}");
5067 + defineMacro(
5068 + "\\mod",
5069 + "\\allowbreak" +
5070 + "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" +
5071 + "{\\rm mod}\\,\\,#1"
5072 + );
5073 +
5074 + //////////////////////////////////////////////////////////////////////
5075 + // LaTeX source2e
5076 +
5077 + // \expandafter\let\expandafter\@normalcr
5078 + // \csname\expandafter\@gobble\string\\ \endcsname
5079 + // \DeclareRobustCommand\newline{\@normalcr\relax}
5080 + defineMacro("\\newline", "\\\\\\relax");
5081 +
5082 + // \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
5083 + // TODO: Doesn't normally work in math mode because \@ fails.
5084 + defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}");
5085 +
5086 + defineMacro(
5087 + "\\LaTeX",
5088 + "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX"
5089 + );
5090 +
5091 + defineMacro(
5092 + "\\Temml",
5093 + // eslint-disable-next-line max-len
5094 + "\\textrm{T}\\kern-0.2em\\lower{0.2em}{\\textrm{E}}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
5095 + );
5096 +
5097 + // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
5098 + // \def\@hspace#1{\hskip #1\relax}
5099 + // \def\@hspacer#1{\vrule \@width\z@\nobreak
5100 + // \hskip #1\hskip \z@skip}
5101 + defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace");
5102 + defineMacro("\\@hspace", "\\hskip #1\\relax");
5103 + defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax");
5104 +
5105 + defineMacro("\\colon", `\\mathpunct{\\char"3a}`);
5106 +
5107 + //////////////////////////////////////////////////////////////////////
5108 + // mathtools.sty
5109 +
5110 + defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}");
5111 +
5112 + //\providecommand\ordinarycolon{:}
5113 + defineMacro("\\ordinarycolon", `\\char"3a`);
5114 + // Raise to center on the math axis, as closely as possible.
5115 + defineMacro("\\vcentcolon", "\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}");
5116 + // \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}}
5117 + defineMacro("\\coloneq", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}');
5118 + // \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}}
5119 + defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}');
5120 + // \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon}
5121 + defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}');
5122 + // \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon}
5123 + defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}');
5124 + // \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx}
5125 + defineMacro("\\colonapprox", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}');
5126 + // \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx}
5127 + defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}');
5128 + // \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim}
5129 + defineMacro("\\colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}');
5130 + // \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim}
5131 + defineMacro("\\Colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}');
5132 +
5133 + //////////////////////////////////////////////////////////////////////
5134 + // colonequals.sty
5135 +
5136 + // Alternate names for mathtools's macros:
5137 + defineMacro("\\ratio", "\\vcentcolon");
5138 + defineMacro("\\coloncolon", "\\dblcolon");
5139 + defineMacro("\\colonequals", "\\coloneqq");
5140 + defineMacro("\\coloncolonequals", "\\Coloneqq");
5141 + defineMacro("\\equalscolon", "\\eqqcolon");
5142 + defineMacro("\\equalscoloncolon", "\\Eqqcolon");
5143 + defineMacro("\\colonminus", "\\coloneq");
5144 + defineMacro("\\coloncolonminus", "\\Coloneq");
5145 + defineMacro("\\minuscolon", "\\eqcolon");
5146 + defineMacro("\\minuscoloncolon", "\\Eqcolon");
5147 + // \colonapprox name is same in mathtools and colonequals.
5148 + defineMacro("\\coloncolonapprox", "\\Colonapprox");
5149 + // \colonsim name is same in mathtools and colonequals.
5150 + defineMacro("\\coloncolonsim", "\\Colonsim");
5151 +
5152 + // Present in newtxmath, pxfonts and txfonts
5153 + defineMacro("\\notni", "\\mathrel{\\char`\u220C}");
5154 + defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}");
5155 + defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}");
5156 +
5157 + //////////////////////////////////////////////////////////////////////
5158 + // From amsopn.sty
5159 + defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}");
5160 + defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}");
5161 + defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}");
5162 + defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}");
5163 + defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}");
5164 + defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}");
5165 +
5166 + defineMacro("\\centerdot", "{\\medspace\\rule{0.167em}{0.189em}\\medspace}");
5167 +
5168 + //////////////////////////////////////////////////////////////////////
5169 + // statmath.sty
5170 + // https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf
5171 +
5172 + defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}");
5173 + defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}");
5174 + defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}");
5175 +
5176 + //////////////////////////////////////////////////////////////////////
5177 + // MnSymbol.sty
5178 +
5179 + defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}");
5180 +
5181 + //////////////////////////////////////////////////////////////////////
5182 + // braket.sty
5183 + // http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf
5184 +
5185 + defineMacro("\\bra", "\\mathinner{\\langle{#1}|}");
5186 + defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}");
5187 + defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}");
5188 + defineMacro("\\Bra", "\\left\\langle#1\\right|");
5189 + defineMacro("\\Ket", "\\left|#1\\right\\rangle");
5190 + // A helper for \Braket and \Set
5191 + const replaceVert = (argStr, match) => {
5192 + const ch = match[0] === "|" ? "\\vert" : "\\Vert";
5193 + const replaceStr = `}\\,\\middle${ch}\\,{`;
5194 + return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length)
5195 + };
5196 + defineMacro("\\Braket", function(context) {
5197 + let argStr = recreateArgStr(context);
5198 + const regEx = /\|\||\||\\\|/g;
5199 + let match;
5200 + while ((match = regEx.exec(argStr)) !== null) {
5201 + argStr = replaceVert(argStr, match);
5202 + }
5203 + return "\\left\\langle{" + argStr + "}\\right\\rangle"
5204 + });
5205 + defineMacro("\\Set", function(context) {
5206 + let argStr = recreateArgStr(context);
5207 + const match = /\|\||\||\\\|/.exec(argStr);
5208 + if (match) {
5209 + argStr = replaceVert(argStr, match);
5210 + }
5211 + return "\\left\\{\\:{" + argStr + "}\\:\\right\\}"
5212 + });
5213 + defineMacro("\\set", function(context) {
5214 + const argStr = recreateArgStr(context);
5215 + return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}"
5216 + });
5217 +
5218 + //////////////////////////////////////////////////////////////////////
5219 + // actuarialangle.dtx
5220 + defineMacro("\\angln", "{\\angl n}");
5221 +
5222 + //////////////////////////////////////////////////////////////////////
5223 + // derivative.sty
5224 + defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator");
5225 + defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}");
5226 + defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1");
5227 + defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator");
5228 +
5229 + const pdvHelper = args => {
5230 + const numerator = args[0][0].text;
5231 + const denoms = stringFromArg(args[1]).split(",");
5232 + const power = String(denoms.length);
5233 + const numOp = power === "1" ? "\\partial" : `\\partial^${power}`;
5234 + let denominator = "";
5235 + denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,";});
5236 + return [numerator, numOp, denominator.replace(/\\,$/, "")]
5237 + };
5238 + defineMacro("\\pdv@numerator", function(context) {
5239 + const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2));
5240 + return `\\frac{${numOp} ${numerator}}{${denominator}}`
5241 + });
5242 + defineMacro("\\pdv@next", function(context) {
5243 + const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2));
5244 + return `\\frac{${numOp}}{${denominator}} ${numerator}`
5245 + });
5246 +
5247 + //////////////////////////////////////////////////////////////////////
5248 + // upgreek.dtx
5249 + defineMacro("\\upalpha", "\\up@greek{\\alpha}");
5250 + defineMacro("\\upbeta", "\\up@greek{\\beta}");
5251 + defineMacro("\\upgamma", "\\up@greek{\\gamma}");
5252 + defineMacro("\\updelta", "\\up@greek{\\delta}");
5253 + defineMacro("\\upepsilon", "\\up@greek{\\epsilon}");
5254 + defineMacro("\\upzeta", "\\up@greek{\\zeta}");
5255 + defineMacro("\\upeta", "\\up@greek{\\eta}");
5256 + defineMacro("\\uptheta", "\\up@greek{\\theta}");
5257 + defineMacro("\\upiota", "\\up@greek{\\iota}");
5258 + defineMacro("\\upkappa", "\\up@greek{\\kappa}");
5259 + defineMacro("\\uplambda", "\\up@greek{\\lambda}");
5260 + defineMacro("\\upmu", "\\up@greek{\\mu}");
5261 + defineMacro("\\upnu", "\\up@greek{\\nu}");
5262 + defineMacro("\\upxi", "\\up@greek{\\xi}");
5263 + defineMacro("\\upomicron", "\\up@greek{\\omicron}");
5264 + defineMacro("\\uppi", "\\up@greek{\\pi}");
5265 + defineMacro("\\upalpha", "\\up@greek{\\alpha}");
5266 + defineMacro("\\uprho", "\\up@greek{\\rho}");
5267 + defineMacro("\\upsigma", "\\up@greek{\\sigma}");
5268 + defineMacro("\\uptau", "\\up@greek{\\tau}");
5269 + defineMacro("\\upupsilon", "\\up@greek{\\upsilon}");
5270 + defineMacro("\\upphi", "\\up@greek{\\phi}");
5271 + defineMacro("\\upchi", "\\up@greek{\\chi}");
5272 + defineMacro("\\uppsi", "\\up@greek{\\psi}");
5273 + defineMacro("\\upomega", "\\up@greek{\\omega}");
5274 +
5275 + //////////////////////////////////////////////////////////////////////
5276 + // cmll package
5277 + defineMacro("\\invamp", '\\mathbin{\\char"214b}');
5278 + defineMacro("\\parr", '\\mathbin{\\char"214b}');
5279 + defineMacro("\\with", '\\mathbin{\\char"26}');
5280 + defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}');
5281 + defineMacro("\\multimapboth", '\\mathrel{\\char"29df}');
5282 + defineMacro("\\scoh", '{\\mkern5mu\\char"2322\\mkern5mu}');
5283 + defineMacro("\\sincoh", '{\\mkern5mu\\char"2323\\mkern5mu}');
5284 + defineMacro("\\coh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}}
5285 + {\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}`);
5286 + defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}}
5287 + {\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}`);
5288 +
5289 +
5290 + //////////////////////////////////////////////////////////////////////
5291 + // chemstyle package
5292 + defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}");
5293 +
5294 + /* eslint-disable */
5295 + /* -*- Mode: JavaScript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
5296 + /* vim: set ts=2 et sw=2 tw=80: */
5297 +
5298 + /*************************************************************
5299 + *
5300 + * Temml mhchem.js
5301 + *
5302 + * This file implements a Temml version of mhchem version 3.3.0.
5303 + * It is adapted from MathJax/extensions/TeX/mhchem.js
5304 + * It differs from the MathJax version as follows:
5305 + * 1. The interface is changed so that it can be called from Temml, not MathJax.
5306 + * 2. \rlap and \llap are replaced with \mathrlap and \mathllap.
5307 + * 3. The reaction arrow code is simplified. All reaction arrows are rendered
5308 + * using Temml extensible arrows instead of building non-extensible arrows.
5309 + * 4. The ~bond forms are composed entirely of \rule elements.
5310 + * 5. Two dashes in _getBond are wrapped in braces to suppress spacing. i.e., {-}
5311 + * 6. The electron dot uses \textbullet instead of \bullet.
5312 + * 7. \smash[T] has been removed. (WebKit hides anything inside \smash{…})
5313 + *
5314 + * This code, as other Temml code, is released under the MIT license.
5315 + *
5316 + * /*************************************************************
5317 + *
5318 + * MathJax/extensions/TeX/mhchem.js
5319 + *
5320 + * Implements the \ce command for handling chemical formulas
5321 + * from the mhchem LaTeX package.
5322 + *
5323 + * ---------------------------------------------------------------------
5324 + *
5325 + * Copyright (c) 2011-2015 The MathJax Consortium
5326 + * Copyright (c) 2015-2018 Martin Hensel
5327 + *
5328 + * Licensed under the Apache License, Version 2.0 (the "License");
5329 + * you may not use this file except in compliance with the License.
5330 + * You may obtain a copy of the License at
5331 + *
5332 + * http://www.apache.org/licenses/LICENSE-2.0
5333 + *
5334 + * Unless required by applicable law or agreed to in writing, software
5335 + * distributed under the License is distributed on an "AS IS" BASIS,
5336 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5337 + * See the License for the specific language governing permissions and
5338 + * limitations under the License.
5339 + */
5340 +
5341 + //
5342 + // Coding Style
5343 + // - use '' for identifiers that can by minified/uglified
5344 + // - use "" for strings that need to stay untouched
5345 +
5346 + // version: "3.3.0" for MathJax and Temml
5347 +
5348 +
5349 + // Add \ce, \pu, and \tripleDash to the Temml macros.
5350 +
5351 + defineMacro("\\ce", function(context) {
5352 + return chemParse(context.consumeArgs(1)[0], "ce")
5353 + });
5354 +
5355 + defineMacro("\\pu", function(context) {
5356 + return chemParse(context.consumeArgs(1)[0], "pu");
5357 + });
5358 +
5359 + // Math fonts do not include glyphs for the ~ form of bonds. So we'll send path geometry
5360 + // So we'll compose characters built from \rule elements.
5361 + defineMacro("\\uniDash", `{\\rule{0.672em}{0.06em}}`)
5362 + defineMacro("\\triDash", `{\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}}`)
5363 + defineMacro("\\tripleDash", `\\kern0.075em\\raise0.25em{\\triDash}\\kern0.075em`)
5364 + defineMacro("\\tripleDashOverLine", `\\kern0.075em\\mathrlap{\\raise0.125em{\\uniDash}}\\raise0.34em{\\triDash}\\kern0.075em`)
5365 + defineMacro("\\tripleDashOverDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\triDash}}\\raise0.27em{\\uniDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`)
5366 + defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\uniDash}}\\raise0.27em{\\triDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`)
5367 +
5368 + //
5369 + // This is the main function for handing the \ce and \pu commands.
5370 + // It takes the argument to \ce or \pu and returns the corresponding TeX string.
5371 + //
5372 +
5373 + var chemParse = function (tokens, stateMachine) {
5374 + // Recreate the argument string from Temml's array of tokens.
5375 + var str = "";
5376 + var expectedLoc = tokens.length && tokens[tokens.length - 1].loc.start
5377 + for (var i = tokens.length - 1; i >= 0; i--) {
5378 + if(tokens[i].loc.start > expectedLoc) {
5379 + // context.consumeArgs has eaten a space.
5380 + str += " ";
5381 + expectedLoc = tokens[i].loc.start;
5382 + }
5383 + str += tokens[i].text;
5384 + expectedLoc += tokens[i].text.length;
5385 + }
5386 + // Call the mhchem core parser.
5387 + var tex = texify.go(mhchemParser.go(str, stateMachine));
5388 + return tex;
5389 + };
5390 +
5391 + //
5392 + // Core parser for mhchem syntax (recursive)
5393 + //
5394 + /** @type {MhchemParser} */
5395 + var mhchemParser = {
5396 + //
5397 + // Parses mchem \ce syntax
5398 + //
5399 + // Call like
5400 + // go("H2O");
5401 + //
5402 + go: function (input, stateMachine) {
5403 + if (!input) { return []; }
5404 + if (stateMachine === undefined) { stateMachine = 'ce'; }
5405 + var state = '0';
5406 +
5407 + //
5408 + // String buffers for parsing:
5409 + //
5410 + // buffer.a == amount
5411 + // buffer.o == element
5412 + // buffer.b == left-side superscript
5413 + // buffer.p == left-side subscript
5414 + // buffer.q == right-side subscript
5415 + // buffer.d == right-side superscript
5416 + //
5417 + // buffer.r == arrow
5418 + // buffer.rdt == arrow, script above, type
5419 + // buffer.rd == arrow, script above, content
5420 + // buffer.rqt == arrow, script below, type
5421 + // buffer.rq == arrow, script below, content
5422 + //
5423 + // buffer.text_
5424 + // buffer.rm
5425 + // etc.
5426 + //
5427 + // buffer.parenthesisLevel == int, starting at 0
5428 + // buffer.sb == bool, space before
5429 + // buffer.beginsWithBond == bool
5430 + //
5431 + // These letters are also used as state names.
5432 + //
5433 + // Other states:
5434 + // 0 == begin of main part (arrow/operator unlikely)
5435 + // 1 == next entity
5436 + // 2 == next entity (arrow/operator unlikely)
5437 + // 3 == next atom
5438 + // c == macro
5439 + //
5440 + /** @type {Buffer} */
5441 + var buffer = {};
5442 + buffer['parenthesisLevel'] = 0;
5443 +
5444 + input = input.replace(/\n/g, " ");
5445 + input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-");
5446 + input = input.replace(/[\u2026]/g, "...");
5447 +
5448 + //
5449 + // Looks through mhchemParser.transitions, to execute a matching action
5450 + // (recursive)
5451 + //
5452 + var lastInput;
5453 + var watchdog = 10;
5454 + /** @type {ParserOutput[]} */
5455 + var output = [];
5456 + while (true) {
5457 + if (lastInput !== input) {
5458 + watchdog = 10;
5459 + lastInput = input;
5460 + } else {
5461 + watchdog--;
5462 + }
5463 + //
5464 + // Find actions in transition table
5465 + //
5466 + var machine = mhchemParser.stateMachines[stateMachine];
5467 + var t = machine.transitions[state] || machine.transitions['*'];
5468 + iterateTransitions:
5469 + for (var i=0; i<t.length; i++) {
5470 + var matches = mhchemParser.patterns.match_(t[i].pattern, input);
5471 + if (matches) {
5472 + //
5473 + // Execute actions
5474 + //
5475 + var task = t[i].task;
5476 + for (var iA=0; iA<task.action_.length; iA++) {
5477 + var o;
5478 + //
5479 + // Find and execute action
5480 + //
5481 + if (machine.actions[task.action_[iA].type_]) {
5482 + o = machine.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option);
5483 + } else if (mhchemParser.actions[task.action_[iA].type_]) {
5484 + o = mhchemParser.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option);
5485 + } else {
5486 + throw ["MhchemBugA", "mhchem bug A. Please report. (" + task.action_[iA].type_ + ")"]; // Trying to use non-existing action
5487 + }
5488 + //
5489 + // Add output
5490 + //
5491 + mhchemParser.concatArray(output, o);
5492 + }
5493 + //
5494 + // Set next state,
5495 + // Shorten input,
5496 + // Continue with next character
5497 + // (= apply only one transition per position)
5498 + //
5499 + state = task.nextState || state;
5500 + if (input.length > 0) {
5501 + if (!task.revisit) {
5502 + input = matches.remainder;
5503 + }
5504 + if (!task.toContinue) {
5505 + break iterateTransitions;
5506 + }
5507 + } else {
5508 + return output;
5509 + }
5510 + }
5511 + }
5512 + //
5513 + // Prevent infinite loop
5514 + //
5515 + if (watchdog <= 0) {
5516 + throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character
5517 + }
5518 + }
5519 + },
5520 + concatArray: function (a, b) {
5521 + if (b) {
5522 + if (Array.isArray(b)) {
5523 + for (var iB=0; iB<b.length; iB++) {
5524 + a.push(b[iB]);
5525 + }
5526 + } else {
5527 + a.push(b);
5528 + }
5529 + }
5530 + },
5531 +
5532 + patterns: {
5533 + //
5534 + // Matching patterns
5535 + // either regexps or function that return null or {match_:"a", remainder:"bc"}
5536 + //
5537 + patterns: {
5538 + // property names must not look like integers ("2") for correct property traversal order, later on
5539 + 'empty': /^$/,
5540 + 'else': /^./,
5541 + 'else2': /^./,
5542 + 'space': /^\s/,
5543 + 'space A': /^\s(?=[A-Z\\$])/,
5544 + 'space$': /^\s$/,
5545 + 'a-z': /^[a-z]/,
5546 + 'x': /^x/,
5547 + 'x$': /^x$/,
5548 + 'i$': /^i$/,
5549 + 'letters': /^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/,
5550 + '\\greek': /^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/,
5551 + 'one lowercase latin letter $': /^(?:([a-z])(?:$|[^a-zA-Z]))$/,
5552 + '$one lowercase latin letter$ $': /^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/,
5553 + 'one lowercase greek letter $': /^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/,
5554 + 'digits': /^[0-9]+/,
5555 + '-9.,9': /^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/,
5556 + '-9.,9 no missing 0': /^[+\-]?[0-9]+(?:[.,][0-9]+)?/,
5557 + '(-)(9.,9)(e)(99)': function (input) {
5558 + var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/);
5559 + if (m && m[0]) {
5560 + return { match_: m.splice(1), remainder: input.substr(m[0].length) };
5561 + }
5562 + return null;
5563 + },
5564 + '(-)(9)^(-9)': function (input) {
5565 + var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/);
5566 + if (m && m[0]) {
5567 + return { match_: m.splice(1), remainder: input.substr(m[0].length) };
5568 + }
5569 + return null;
5570 + },
5571 + 'state of aggregation $': function (input) { // ... or crystal system
5572 + var a = mhchemParser.patterns.findObserveGroups(input, "", /^\([a-z]{1,3}(?=[\),])/, ")", ""); // (aq), (aq,$\infty$), (aq, sat)
5573 + if (a && a.remainder.match(/^($|[\s,;\)\]\}])/)) { return a; } // AND end of 'phrase'
5574 + var m = input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/); // OR crystal system ($o$) (\ca$c$)
5575 + if (m) {
5576 + return { match_: m[0], remainder: input.substr(m[0].length) };
5577 + }
5578 + return null;
5579 + },
5580 + '_{(state of aggregation)}$': /^_\{(\([a-z]{1,3}\))\}/,
5581 + '{[(': /^(?:\\\{|\[|\()/,
5582 + ')]}': /^(?:\)|\]|\\\})/,
5583 + ', ': /^[,;]\s*/,
5584 + ',': /^[,;]/,
5585 + '.': /^[.]/,
5586 + '. ': /^([.\u22C5\u00B7\u2022])\s*/,
5587 + '...': /^\.\.\.(?=$|[^.])/,
5588 + '* ': /^([*])\s*/,
5589 + '^{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "^{", "", "", "}"); },
5590 + '^($...$)': function (input) { return mhchemParser.patterns.findObserveGroups(input, "^", "$", "$", ""); },
5591 + '^a': /^\^([0-9]+|[^\\_])/,
5592 + '^\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); },
5593 + '^\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", ""); },
5594 + '^\\x': /^\^(\\[a-zA-Z]+)\s*/,
5595 + '^(-1)': /^\^(-?\d+)/,
5596 + '\'': /^'/,
5597 + '_{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "_{", "", "", "}"); },
5598 + '_($...$)': function (input) { return mhchemParser.patterns.findObserveGroups(input, "_", "$", "$", ""); },
5599 + '_9': /^_([+\-]?[0-9]+|[^\\])/,
5600 + '_\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); },
5601 + '_\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", ""); },
5602 + '_\\x': /^_(\\[a-zA-Z]+)\s*/,
5603 + '^_': /^(?:\^(?=_)|\_(?=\^)|[\^_]$)/,
5604 + '{}': /^\{\}/,
5605 + '{...}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", "{", "}", ""); },
5606 + '{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "{", "", "", "}"); },
5607 + '$...$': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); },
5608 + '${(...)}$': function (input) { return mhchemParser.patterns.findObserveGroups(input, "${", "", "", "}$"); },
5609 + '$(...)$': function (input) { return mhchemParser.patterns.findObserveGroups(input, "$", "", "", "$"); },
5610 + '=<>': /^[=<>]/,
5611 + '#': /^[#\u2261]/,
5612 + '+': /^\+/,
5613 + '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation
5614 + '-9': /^-(?=[0-9])/,
5615 + '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,
5616 + '-': /^-/,
5617 + 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,
5618 + 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,
5619 + 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,
5620 + '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); },
5621 + '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,
5622 + 'CMT': /^[CMT](?=\[)/,
5623 + '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); },
5624 + '1st-level escape': /^(&|\\\\|\\hline)\s*/,
5625 + '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before
5626 + '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); },
5627 + '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); },
5628 + '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/,
5629 + '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,
5630 + 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway
5631 + 'others': /^[\/~|]/,
5632 + '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); },
5633 + '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); },
5634 + '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); },
5635 + '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); },
5636 + '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); },
5637 + '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); },
5638 + '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); },
5639 + '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); },
5640 + 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,
5641 + 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge
5642 + 'roman numeral': /^[IVX]+/,
5643 + '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,
5644 + 'amount': function (input) {
5645 + var match;
5646 + // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing
5647 + match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/);
5648 + if (match) {
5649 + return { match_: match[0], remainder: input.substr(match[0].length) };
5650 + }
5651 + var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", "");
5652 + if (a) { // e.g. $2n-1$, $-$
5653 + match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/);
5654 + if (match) {
5655 + return { match_: match[0], remainder: input.substr(match[0].length) };
5656 + }
5657 + }
5658 + return null;
5659 + },
5660 + 'amount2': function (input) { return this['amount'](input); },
5661 + '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/,
5662 + 'formula$': function (input) {
5663 + if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula
5664 + var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);
5665 + if (match) {
5666 + return { match_: match[0], remainder: input.substr(match[0].length) };
5667 + }
5668 + return null;
5669 + },
5670 + 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,
5671 + '/': /^\s*(\/)\s*/,
5672 + '//': /^\s*(\/\/)\s*/,
5673 + '*': /^\s*[*.]\s*/
5674 + },
5675 + findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) {
5676 + /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */
5677 + var _match = function (input, pattern) {
5678 + if (typeof pattern === "string") {
5679 + if (input.indexOf(pattern) !== 0) { return null; }
5680 + return pattern;
5681 + } else {
5682 + var match = input.match(pattern);
5683 + if (!match) { return null; }
5684 + return match[0];
5685 + }
5686 + };
5687 + /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */
5688 + var _findObserveGroups = function (input, i, endChars) {
5689 + var braces = 0;
5690 + while (i < input.length) {
5691 + var a = input.charAt(i);
5692 + var match = _match(input.substr(i), endChars);
5693 + if (match !== null && braces === 0) {
5694 + return { endMatchBegin: i, endMatchEnd: i + match.length };
5695 + } else if (a === "{") {
5696 + braces++;
5697 + } else if (a === "}") {
5698 + if (braces === 0) {
5699 + throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"];
5700 + } else {
5701 + braces--;
5702 + }
5703 + }
5704 + i++;
5705 + }
5706 + if (braces > 0) {
5707 + return null;
5708 + }
5709 + return null;
5710 + };
5711 + var match = _match(input, begExcl);
5712 + if (match === null) { return null; }
5713 + input = input.substr(match.length);
5714 + match = _match(input, begIncl);
5715 + if (match === null) { return null; }
5716 + var e = _findObserveGroups(input, match.length, endIncl || endExcl);
5717 + if (e === null) { return null; }
5718 + var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin));
5719 + if (!(beg2Excl || beg2Incl)) {
5720 + return {
5721 + match_: match1,
5722 + remainder: input.substr(e.endMatchEnd)
5723 + };
5724 + } else {
5725 + var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl);
5726 + if (group2 === null) { return null; }
5727 + /** @type {string[]} */
5728 + var matchRet = [match1, group2.match_];
5729 + return {
5730 + match_: (combine ? matchRet.join("") : matchRet),
5731 + remainder: group2.remainder
5732 + };
5733 + }
5734 + },
5735 +
5736 + //
5737 + // Matching function
5738 + // e.g. match("a", input) will look for the regexp called "a" and see if it matches
5739 + // returns null or {match_:"a", remainder:"bc"}
5740 + //
5741 + match_: function (m, input) {
5742 + var pattern = mhchemParser.patterns.patterns[m];
5743 + if (pattern === undefined) {
5744 + throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern
5745 + } else if (typeof pattern === "function") {
5746 + return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser
5747 + } else { // RegExp
5748 + var match = input.match(pattern);
5749 + if (match) {
5750 + var mm;
5751 + if (match[2]) {
5752 + mm = [ match[1], match[2] ];
5753 + } else if (match[1]) {
5754 + mm = match[1];
5755 + } else {
5756 + mm = match[0];
5757 + }
5758 + return { match_: mm, remainder: input.substr(match[0].length) };
5759 + }
5760 + return null;
5761 + }
5762 + }
5763 + },
5764 +
5765 + //
5766 + // Generic state machine actions
5767 + //
5768 + actions: {
5769 + 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; },
5770 + 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; },
5771 + 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; },
5772 + 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; },
5773 + 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; },
5774 + 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; },
5775 + 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; },
5776 + 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; },
5777 + 'insert': function (buffer, m, a) { return { type_: a }; },
5778 + 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; },
5779 + 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; },
5780 + 'copy': function (buffer, m) { return m; },
5781 + 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; },
5782 + 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); },
5783 + '{text}': function (buffer, m) {
5784 + var ret = [ "{" ];
5785 + mhchemParser.concatArray(ret, mhchemParser.go(m, 'text'));
5786 + ret.push("}");
5787 + return ret;
5788 + },
5789 + 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); },
5790 + 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); },
5791 + 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; },
5792 + 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; },
5793 + 'ce': function (buffer, m) { return mhchemParser.go(m); },
5794 + '1/2': function (buffer, m) {
5795 + /** @type {ParserOutput[]} */
5796 + var ret = [];
5797 + if (m.match(/^[+\-]/)) {
5798 + ret.push(m.substr(0, 1));
5799 + m = m.substr(1);
5800 + }
5801 + var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);
5802 + n[1] = n[1].replace(/\$/g, "");
5803 + ret.push({ type_: 'frac', p1: n[1], p2: n[2] });
5804 + if (n[3]) {
5805 + n[3] = n[3].replace(/\$/g, "");
5806 + ret.push({ type_: 'tex-math', p1: n[3] });
5807 + }
5808 + return ret;
5809 + },
5810 + '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); }
5811 + },
5812 + //
5813 + // createTransitions
5814 + // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] }
5815 + // with expansion of 'a|b' to 'a' and 'b' (at 2 places)
5816 + //
5817 + createTransitions: function (o) {
5818 + var pattern, state;
5819 + /** @type {string[]} */
5820 + var stateArray;
5821 + var i;
5822 + //
5823 + // 1. Collect all states
5824 + //
5825 + /** @type {Transitions} */
5826 + var transitions = {};
5827 + for (pattern in o) {
5828 + for (state in o[pattern]) {
5829 + stateArray = state.split("|");
5830 + o[pattern][state].stateArray = stateArray;
5831 + for (i=0; i<stateArray.length; i++) {
5832 + transitions[stateArray[i]] = [];
5833 + }
5834 + }
5835 + }
5836 + //
5837 + // 2. Fill states
5838 + //
5839 + for (pattern in o) {
5840 + for (state in o[pattern]) {
5841 + stateArray = o[pattern][state].stateArray || [];
5842 + for (i=0; i<stateArray.length; i++) {
5843 + //
5844 + // 2a. Normalize actions into array: 'text=' ==> [{type_:'text='}]
5845 + // (Note to myself: Resolving the function here would be problematic. It would need .bind (for *this*) and currying (for *option*).)
5846 + //
5847 + /** @type {any} */
5848 + var p = o[pattern][state];
5849 + if (p.action_) {
5850 + p.action_ = [].concat(p.action_);
5851 + for (var k=0; k<p.action_.length; k++) {
5852 + if (typeof p.action_[k] === "string") {
5853 + p.action_[k] = { type_: p.action_[k] };
5854 + }
5855 + }
5856 + } else {
5857 + p.action_ = [];
5858 + }
5859 + //
5860 + // 2.b Multi-insert
5861 + //
5862 + var patternArray = pattern.split("|");
5863 + for (var j=0; j<patternArray.length; j++) {
5864 + if (stateArray[i] === '*') { // insert into all
5865 + for (var t in transitions) {
5866 + transitions[t].push({ pattern: patternArray[j], task: p });
5867 + }
5868 + } else {
5869 + transitions[stateArray[i]].push({ pattern: patternArray[j], task: p });
5870 + }
5871 + }
5872 + }
5873 + }
5874 + }
5875 + return transitions;
5876 + },
5877 + stateMachines: {}
5878 + };
5879 +
5880 + //
5881 + // Definition of state machines
5882 + //
5883 + mhchemParser.stateMachines = {
5884 + //
5885 + // \ce state machines
5886 + //
5887 + //#region ce
5888 + 'ce': { // main parser
5889 + transitions: mhchemParser.createTransitions({
5890 + 'empty': {
5891 + '*': { action_: 'output' } },
5892 + 'else': {
5893 + '0|1|2': { action_: 'beginsWithBond=false', revisit: true, toContinue: true } },
5894 + 'oxidation$': {
5895 + '0': { action_: 'oxidation-output' } },
5896 + 'CMT': {
5897 + 'r': { action_: 'rdt=', nextState: 'rt' },
5898 + 'rd': { action_: 'rqt=', nextState: 'rdt' } },
5899 + 'arrowUpDown': {
5900 + '0|1|2|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '1' } },
5901 + 'uprightEntities': {
5902 + '0|1|2': { action_: [ 'o=', 'output' ], nextState: '1' } },
5903 + 'orbital': {
5904 + '0|1|2|3': { action_: 'o=', nextState: 'o' } },
5905 + '->': {
5906 + '0|1|2|3': { action_: 'r=', nextState: 'r' },
5907 + 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' },
5908 + '*': { action_: [ 'output', 'r=' ], nextState: 'r' } },
5909 + '+': {
5910 + 'o': { action_: 'd= kv', nextState: 'd' },
5911 + 'd|D': { action_: 'd=', nextState: 'd' },
5912 + 'q': { action_: 'd=', nextState: 'qd' },
5913 + 'qd|qD': { action_: 'd=', nextState: 'qd' },
5914 + 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' },
5915 + '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } },
5916 + 'amount': {
5917 + '0|2': { action_: 'a=', nextState: 'a' } },
5918 + 'pm-operator': {
5919 + '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } },
5920 + 'operator': {
5921 + '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } },
5922 + '-$': {
5923 + 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' },
5924 + 'd': { action_: 'd=', nextState: 'd' },
5925 + 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' },
5926 + 'q': { action_: 'd=', nextState: 'qd' },
5927 + 'qd': { action_: 'd=', nextState: 'qd' },
5928 + 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } },
5929 + '-9': {
5930 + '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } },
5931 + '- orbital overlap': {
5932 + 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' },
5933 + 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } },
5934 + '-': {
5935 + '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' },
5936 + '3': { action_: { type_: 'bond', option: "-" } },
5937 + 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' },
5938 + 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' },
5939 + 'b': { action_: 'b=' },
5940 + 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' },
5941 + 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' },
5942 + 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' },
5943 + 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } },
5944 + 'amount2': {
5945 + '1|3': { action_: 'a=', nextState: 'a' } },
5946 + 'letters': {
5947 + '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' },
5948 + 'q|dq': { action_: ['output', 'o='], nextState: 'o' },
5949 + 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } },
5950 + 'digits': {
5951 + 'o': { action_: 'q=', nextState: 'q' },
5952 + 'd|D': { action_: 'q=', nextState: 'dq' },
5953 + 'q': { action_: [ 'output', 'o=' ], nextState: 'o' },
5954 + 'a': { action_: 'o=', nextState: 'o' } },
5955 + 'space A': {
5956 + 'b|p|bp': {} },
5957 + 'space': {
5958 + 'a': { nextState: 'as' },
5959 + '0': { action_: 'sb=false' },
5960 + '1|2': { action_: 'sb=true' },
5961 + 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' },
5962 + '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} },
5963 + '1st-level escape': {
5964 + '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] },
5965 + '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } },
5966 + '[(...)]': {
5967 + 'r|rt': { action_: 'rd=', nextState: 'rd' },
5968 + 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } },
5969 + '...': {
5970 + 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' },
5971 + '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } },
5972 + '. |* ': {
5973 + '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } },
5974 + 'state of aggregation $': {
5975 + '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } },
5976 + '{[(': {
5977 + 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' },
5978 + '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' },
5979 + '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } },
5980 + ')]}': {
5981 + '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' },
5982 + 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } },
5983 + ', ': {
5984 + '*': { action_: [ 'output', 'comma' ], nextState: '0' } },
5985 + '^_': { // ^ and _ without a sensible argument
5986 + '*': { } },
5987 + '^{(...)}|^($...$)': {
5988 + '0|1|2|as': { action_: 'b=', nextState: 'b' },
5989 + 'p': { action_: 'b=', nextState: 'bp' },
5990 + '3|o': { action_: 'd= kv', nextState: 'D' },
5991 + 'q': { action_: 'd=', nextState: 'qD' },
5992 + 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } },
5993 + '^a|^\\x{}{}|^\\x{}|^\\x|\'': {
5994 + '0|1|2|as': { action_: 'b=', nextState: 'b' },
5995 + 'p': { action_: 'b=', nextState: 'bp' },
5996 + '3|o': { action_: 'd= kv', nextState: 'd' },
5997 + 'q': { action_: 'd=', nextState: 'qd' },
5998 + 'd|qd|D|qD': { action_: 'd=' },
5999 + 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } },
6000 + '_{(state of aggregation)}$': {
6001 + 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } },
6002 + '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': {
6003 + '0|1|2|as': { action_: 'p=', nextState: 'p' },
6004 + 'b': { action_: 'p=', nextState: 'bp' },
6005 + '3|o': { action_: 'q=', nextState: 'q' },
6006 + 'd|D': { action_: 'q=', nextState: 'dq' },
6007 + 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } },
6008 + '=<>': {
6009 + '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } },
6010 + '#': {
6011 + '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } },
6012 + '{}': {
6013 + '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } },
6014 + '{...}': {
6015 + '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' },
6016 + 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } },
6017 + '$...$': {
6018 + 'a': { action_: 'a=' }, // 2$n$
6019 + '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount'
6020 + 'as|o': { action_: 'o=' },
6021 + 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } },
6022 + '\\bond{(...)}': {
6023 + '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } },
6024 + '\\frac{(...)}': {
6025 + '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } },
6026 + '\\overset{(...)}': {
6027 + '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } },
6028 + '\\underset{(...)}': {
6029 + '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } },
6030 + '\\underbrace{(...)}': {
6031 + '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } },
6032 + '\\color{(...)}{(...)}1|\\color(...){(...)}2': {
6033 + '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } },
6034 + '\\color{(...)}0': {
6035 + '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } },
6036 + '\\ce{(...)}': {
6037 + '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } },
6038 + '\\,': {
6039 + '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } },
6040 + '\\x{}{}|\\x{}|\\x': {
6041 + '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' },
6042 + '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } },
6043 + 'others': {
6044 + '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } },
6045 + 'else2': {
6046 + 'a': { action_: 'a to o', nextState: 'o', revisit: true },
6047 + 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true },
6048 + 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true },
6049 + '*': { action_: [ 'output', 'copy' ], nextState: '3' } }
6050 + }),
6051 + actions: {
6052 + 'o after d': function (buffer, m) {
6053 + var ret;
6054 + if ((buffer.d || "").match(/^[0-9]+$/)) {
6055 + var tmp = buffer.d;
6056 + buffer.d = undefined;
6057 + ret = this['output'](buffer);
6058 + buffer.b = tmp;
6059 + } else {
6060 + ret = this['output'](buffer);
6061 + }
6062 + mhchemParser.actions['o='](buffer, m);
6063 + return ret;
6064 + },
6065 + 'd= kv': function (buffer, m) {
6066 + buffer.d = m;
6067 + buffer.dType = 'kv';
6068 + },
6069 + 'charge or bond': function (buffer, m) {
6070 + if (buffer['beginsWithBond']) {
6071 + /** @type {ParserOutput[]} */
6072 + var ret = [];
6073 + mhchemParser.concatArray(ret, this['output'](buffer));
6074 + mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-"));
6075 + return ret;
6076 + } else {
6077 + buffer.d = m;
6078 + }
6079 + },
6080 + '- after o/d': function (buffer, m, isAfterD) {
6081 + var c1 = mhchemParser.patterns.match_('orbital', buffer.o || "");
6082 + var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || "");
6083 + var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || "");
6084 + var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || "");
6085 + var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 );
6086 + if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) {
6087 + buffer.o = '$' + buffer.o + '$';
6088 + }
6089 + /** @type {ParserOutput[]} */
6090 + var ret = [];
6091 + if (hyphenFollows) {
6092 + mhchemParser.concatArray(ret, this['output'](buffer));
6093 + ret.push({ type_: 'hyphen' });
6094 + } else {
6095 + c1 = mhchemParser.patterns.match_('digits', buffer.d || "");
6096 + if (isAfterD && c1 && c1.remainder==='') {
6097 + mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m));
6098 + mhchemParser.concatArray(ret, this['output'](buffer));
6099 + } else {
6100 + mhchemParser.concatArray(ret, this['output'](buffer));
6101 + mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-"));
6102 + }
6103 + }
6104 + return ret;
6105 + },
6106 + 'a to o': function (buffer) {
6107 + buffer.o = buffer.a;
6108 + buffer.a = undefined;
6109 + },
6110 + 'sb=true': function (buffer) { buffer.sb = true; },
6111 + 'sb=false': function (buffer) { buffer.sb = false; },
6112 + 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; },
6113 + 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; },
6114 + 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; },
6115 + 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; },
6116 + 'state of aggregation': function (buffer, m) {
6117 + return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') };
6118 + },
6119 + 'comma': function (buffer, m) {
6120 + var a = m.replace(/\s*$/, '');
6121 + var withSpace = (a !== m);
6122 + if (withSpace && buffer['parenthesisLevel'] === 0) {
6123 + return { type_: 'comma enumeration L', p1: a };
6124 + } else {
6125 + return { type_: 'comma enumeration M', p1: a };
6126 + }
6127 + },
6128 + 'output': function (buffer, m, entityFollows) {
6129 + // entityFollows:
6130 + // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb)
6131 + // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1)
6132 + // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as)
6133 + /** @type {ParserOutput | ParserOutput[]} */
6134 + var ret;
6135 + if (!buffer.r) {
6136 + ret = [];
6137 + if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) {
6138 + //ret = [];
6139 + } else {
6140 + if (buffer.sb) {
6141 + ret.push({ type_: 'entitySkip' });
6142 + }
6143 + if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) {
6144 + buffer.o = buffer.a;
6145 + buffer.a = undefined;
6146 + } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) {
6147 + buffer.o = buffer.a;
6148 + buffer.d = buffer.b;
6149 + buffer.q = buffer.p;
6150 + buffer.a = buffer.b = buffer.p = undefined;
6151 + } else {
6152 + if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) {
6153 + buffer.dType = 'oxidation';
6154 + } else if (buffer.o && buffer.dType==='kv' && !buffer.q) {
6155 + buffer.dType = undefined;
6156 + }
6157 + }
6158 + ret.push({
6159 + type_: 'chemfive',
6160 + a: mhchemParser.go(buffer.a, 'a'),
6161 + b: mhchemParser.go(buffer.b, 'bd'),
6162 + p: mhchemParser.go(buffer.p, 'pq'),
6163 + o: mhchemParser.go(buffer.o, 'o'),
6164 + q: mhchemParser.go(buffer.q, 'pq'),
6165 + d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')),
6166 + dType: buffer.dType
6167 + });
6168 + }
6169 + } else { // r
6170 + /** @type {ParserOutput[]} */
6171 + var rd;
6172 + if (buffer.rdt === 'M') {
6173 + rd = mhchemParser.go(buffer.rd, 'tex-math');
6174 + } else if (buffer.rdt === 'T') {
6175 + rd = [ { type_: 'text', p1: buffer.rd || "" } ];
6176 + } else {
6177 + rd = mhchemParser.go(buffer.rd);
6178 + }
6179 + /** @type {ParserOutput[]} */
6180 + var rq;
6181 + if (buffer.rqt === 'M') {
6182 + rq = mhchemParser.go(buffer.rq, 'tex-math');
6183 + } else if (buffer.rqt === 'T') {
6184 + rq = [ { type_: 'text', p1: buffer.rq || ""} ];
6185 + } else {
6186 + rq = mhchemParser.go(buffer.rq);
6187 + }
6188 + ret = {
6189 + type_: 'arrow',
6190 + r: buffer.r,
6191 + rd: rd,
6192 + rq: rq
6193 + };
6194 + }
6195 + for (var p in buffer) {
6196 + if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') {
6197 + delete buffer[p];
6198 + }
6199 + }
6200 + return ret;
6201 + },
6202 + 'oxidation-output': function (buffer, m) {
6203 + var ret = [ "{" ];
6204 + mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation'));
6205 + ret.push("}");
6206 + return ret;
6207 + },
6208 + 'frac-output': function (buffer, m) {
6209 + return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) };
6210 + },
6211 + 'overset-output': function (buffer, m) {
6212 + return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) };
6213 + },
6214 + 'underset-output': function (buffer, m) {
6215 + return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) };
6216 + },
6217 + 'underbrace-output': function (buffer, m) {
6218 + return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) };
6219 + },
6220 + 'color-output': function (buffer, m) {
6221 + return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) };
6222 + },
6223 + 'r=': function (buffer, m) { buffer.r = m; },
6224 + 'rdt=': function (buffer, m) { buffer.rdt = m; },
6225 + 'rd=': function (buffer, m) { buffer.rd = m; },
6226 + 'rqt=': function (buffer, m) { buffer.rqt = m; },
6227 + 'rq=': function (buffer, m) { buffer.rq = m; },
6228 + 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }
6229 + }
6230 + },
6231 + 'a': {
6232 + transitions: mhchemParser.createTransitions({
6233 + 'empty': {
6234 + '*': {} },
6235 + '1/2$': {
6236 + '0': { action_: '1/2' } },
6237 + 'else': {
6238 + '0': { nextState: '1', revisit: true } },
6239 + '$(...)$': {
6240 + '*': { action_: 'tex-math tight', nextState: '1' } },
6241 + ',': {
6242 + '*': { action_: { type_: 'insert', option: 'commaDecimal' } } },
6243 + 'else2': {
6244 + '*': { action_: 'copy' } }
6245 + }),
6246 + actions: {}
6247 + },
6248 + 'o': {
6249 + transitions: mhchemParser.createTransitions({
6250 + 'empty': {
6251 + '*': {} },
6252 + '1/2$': {
6253 + '0': { action_: '1/2' } },
6254 + 'else': {
6255 + '0': { nextState: '1', revisit: true } },
6256 + 'letters': {
6257 + '*': { action_: 'rm' } },
6258 + '\\ca': {
6259 + '*': { action_: { type_: 'insert', option: 'circa' } } },
6260 + '\\x{}{}|\\x{}|\\x': {
6261 + '*': { action_: 'copy' } },
6262 + '${(...)}$|$(...)$': {
6263 + '*': { action_: 'tex-math' } },
6264 + '{(...)}': {
6265 + '*': { action_: '{text}' } },
6266 + 'else2': {
6267 + '*': { action_: 'copy' } }
6268 + }),
6269 + actions: {}
6270 + },
6271 + 'text': {
6272 + transitions: mhchemParser.createTransitions({
6273 + 'empty': {
6274 + '*': { action_: 'output' } },
6275 + '{...}': {
6276 + '*': { action_: 'text=' } },
6277 + '${(...)}$|$(...)$': {
6278 + '*': { action_: 'tex-math' } },
6279 + '\\greek': {
6280 + '*': { action_: [ 'output', 'rm' ] } },
6281 + '\\,|\\x{}{}|\\x{}|\\x': {
6282 + '*': { action_: [ 'output', 'copy' ] } },
6283 + 'else': {
6284 + '*': { action_: 'text=' } }
6285 + }),
6286 + actions: {
6287 + 'output': function (buffer) {
6288 + if (buffer.text_) {
6289 + /** @type {ParserOutput} */
6290 + var ret = { type_: 'text', p1: buffer.text_ };
6291 + for (var p in buffer) { delete buffer[p]; }
6292 + return ret;
6293 + }
6294 + }
6295 + }
6296 + },
6297 + 'pq': {
6298 + transitions: mhchemParser.createTransitions({
6299 + 'empty': {
6300 + '*': {} },
6301 + 'state of aggregation $': {
6302 + '*': { action_: 'state of aggregation' } },
6303 + 'i$': {
6304 + '0': { nextState: '!f', revisit: true } },
6305 + '(KV letters),': {
6306 + '0': { action_: 'rm', nextState: '0' } },
6307 + 'formula$': {
6308 + '0': { nextState: 'f', revisit: true } },
6309 + '1/2$': {
6310 + '0': { action_: '1/2' } },
6311 + 'else': {
6312 + '0': { nextState: '!f', revisit: true } },
6313 + '${(...)}$|$(...)$': {
6314 + '*': { action_: 'tex-math' } },
6315 + '{(...)}': {
6316 + '*': { action_: 'text' } },
6317 + 'a-z': {
6318 + 'f': { action_: 'tex-math' } },
6319 + 'letters': {
6320 + '*': { action_: 'rm' } },
6321 + '-9.,9': {
6322 + '*': { action_: '9,9' } },
6323 + ',': {
6324 + '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } },
6325 + '\\color{(...)}{(...)}1|\\color(...){(...)}2': {
6326 + '*': { action_: 'color-output' } },
6327 + '\\color{(...)}0': {
6328 + '*': { action_: 'color0-output' } },
6329 + '\\ce{(...)}': {
6330 + '*': { action_: 'ce' } },
6331 + '\\,|\\x{}{}|\\x{}|\\x': {
6332 + '*': { action_: 'copy' } },
6333 + 'else2': {
6334 + '*': { action_: 'copy' } }
6335 + }),
6336 + actions: {
6337 + 'state of aggregation': function (buffer, m) {
6338 + return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') };
6339 + },
6340 + 'color-output': function (buffer, m) {
6341 + return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') };
6342 + }
6343 + }
6344 + },
6345 + 'bd': {
6346 + transitions: mhchemParser.createTransitions({
6347 + 'empty': {
6348 + '*': {} },
6349 + 'x$': {
6350 + '0': { nextState: '!f', revisit: true } },
6351 + 'formula$': {
6352 + '0': { nextState: 'f', revisit: true } },
6353 + 'else': {
6354 + '0': { nextState: '!f', revisit: true } },
6355 + '-9.,9 no missing 0': {
6356 + '*': { action_: '9,9' } },
6357 + '.': {
6358 + '*': { action_: { type_: 'insert', option: 'electron dot' } } },
6359 + 'a-z': {
6360 + 'f': { action_: 'tex-math' } },
6361 + 'x': {
6362 + '*': { action_: { type_: 'insert', option: 'KV x' } } },
6363 + 'letters': {
6364 + '*': { action_: 'rm' } },
6365 + '\'': {
6366 + '*': { action_: { type_: 'insert', option: 'prime' } } },
6367 + '${(...)}$|$(...)$': {
6368 + '*': { action_: 'tex-math' } },
6369 + '{(...)}': {
6370 + '*': { action_: 'text' } },
6371 + '\\color{(...)}{(...)}1|\\color(...){(...)}2': {
6372 + '*': { action_: 'color-output' } },
6373 + '\\color{(...)}0': {
6374 + '*': { action_: 'color0-output' } },
6375 + '\\ce{(...)}': {
6376 + '*': { action_: 'ce' } },
6377 + '\\,|\\x{}{}|\\x{}|\\x': {
6378 + '*': { action_: 'copy' } },
6379 + 'else2': {
6380 + '*': { action_: 'copy' } }
6381 + }),
6382 + actions: {
6383 + 'color-output': function (buffer, m) {
6384 + return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') };
6385 + }
6386 + }
6387 + },
6388 + 'oxidation': {
6389 + transitions: mhchemParser.createTransitions({
6390 + 'empty': {
6391 + '*': {} },
6392 + 'roman numeral': {
6393 + '*': { action_: 'roman-numeral' } },
6394 + '${(...)}$|$(...)$': {
6395 + '*': { action_: 'tex-math' } },
6396 + 'else': {
6397 + '*': { action_: 'copy' } }
6398 + }),
6399 + actions: {
6400 + 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; }
6401 + }
6402 + },
6403 + 'tex-math': {
6404 + transitions: mhchemParser.createTransitions({
6405 + 'empty': {
6406 + '*': { action_: 'output' } },
6407 + '\\ce{(...)}': {
6408 + '*': { action_: [ 'output', 'ce' ] } },
6409 + '{...}|\\,|\\x{}{}|\\x{}|\\x': {
6410 + '*': { action_: 'o=' } },
6411 + 'else': {
6412 + '*': { action_: 'o=' } }
6413 + }),
6414 + actions: {
6415 + 'output': function (buffer) {
6416 + if (buffer.o) {
6417 + /** @type {ParserOutput} */
6418 + var ret = { type_: 'tex-math', p1: buffer.o };
6419 + for (var p in buffer) { delete buffer[p]; }
6420 + return ret;
6421 + }
6422 + }
6423 + }
6424 + },
6425 + 'tex-math tight': {
6426 + transitions: mhchemParser.createTransitions({
6427 + 'empty': {
6428 + '*': { action_: 'output' } },
6429 + '\\ce{(...)}': {
6430 + '*': { action_: [ 'output', 'ce' ] } },
6431 + '{...}|\\,|\\x{}{}|\\x{}|\\x': {
6432 + '*': { action_: 'o=' } },
6433 + '-|+': {
6434 + '*': { action_: 'tight operator' } },
6435 + 'else': {
6436 + '*': { action_: 'o=' } }
6437 + }),
6438 + actions: {
6439 + 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; },
6440 + 'output': function (buffer) {
6441 + if (buffer.o) {
6442 + /** @type {ParserOutput} */
6443 + var ret = { type_: 'tex-math', p1: buffer.o };
6444 + for (var p in buffer) { delete buffer[p]; }
6445 + return ret;
6446 + }
6447 + }
6448 + }
6449 + },
6450 + '9,9': {
6451 + transitions: mhchemParser.createTransitions({
6452 + 'empty': {
6453 + '*': {} },
6454 + ',': {
6455 + '*': { action_: 'comma' } },
6456 + 'else': {
6457 + '*': { action_: 'copy' } }
6458 + }),
6459 + actions: {
6460 + 'comma': function () { return { type_: 'commaDecimal' }; }
6461 + }
6462 + },
6463 + //#endregion
6464 + //
6465 + // \pu state machines
6466 + //
6467 + //#region pu
6468 + 'pu': {
6469 + transitions: mhchemParser.createTransitions({
6470 + 'empty': {
6471 + '*': { action_: 'output' } },
6472 + 'space$': {
6473 + '*': { action_: [ 'output', 'space' ] } },
6474 + '{[(|)]}': {
6475 + '0|a': { action_: 'copy' } },
6476 + '(-)(9)^(-9)': {
6477 + '0': { action_: 'number^', nextState: 'a' } },
6478 + '(-)(9.,9)(e)(99)': {
6479 + '0': { action_: 'enumber', nextState: 'a' } },
6480 + 'space': {
6481 + '0|a': {} },
6482 + 'pm-operator': {
6483 + '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } },
6484 + 'operator': {
6485 + '0|a': { action_: 'copy', nextState: '0' } },
6486 + '//': {
6487 + 'd': { action_: 'o=', nextState: '/' } },
6488 + '/': {
6489 + 'd': { action_: 'o=', nextState: '/' } },
6490 + '{...}|else': {
6491 + '0|d': { action_: 'd=', nextState: 'd' },
6492 + 'a': { action_: [ 'space', 'd=' ], nextState: 'd' },
6493 + '/|q': { action_: 'q=', nextState: 'q' } }
6494 + }),
6495 + actions: {
6496 + 'enumber': function (buffer, m) {
6497 + /** @type {ParserOutput[]} */
6498 + var ret = [];
6499 + if (m[0] === "+-" || m[0] === "+/-") {
6500 + ret.push("\\pm ");
6501 + } else if (m[0]) {
6502 + ret.push(m[0]);
6503 + }
6504 + if (m[1]) {
6505 + mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9'));
6506 + if (m[2]) {
6507 + if (m[2].match(/[,.]/)) {
6508 + mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9'));
6509 + } else {
6510 + ret.push(m[2]);
6511 + }
6512 + }
6513 + m[3] = m[4] || m[3];
6514 + if (m[3]) {
6515 + m[3] = m[3].trim();
6516 + if (m[3] === "e" || m[3].substr(0, 1) === "*") {
6517 + ret.push({ type_: 'cdot' });
6518 + } else {
6519 + ret.push({ type_: 'times' });
6520 + }
6521 + }
6522 + }
6523 + if (m[3]) {
6524 + ret.push("10^{"+m[5]+"}");
6525 + }
6526 + return ret;
6527 + },
6528 + 'number^': function (buffer, m) {
6529 + /** @type {ParserOutput[]} */
6530 + var ret = [];
6531 + if (m[0] === "+-" || m[0] === "+/-") {
6532 + ret.push("\\pm ");
6533 + } else if (m[0]) {
6534 + ret.push(m[0]);
6535 + }
6536 + mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9'));
6537 + ret.push("^{"+m[2]+"}");
6538 + return ret;
6539 + },
6540 + 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; },
6541 + 'space': function () { return { type_: 'pu-space-1' }; },
6542 + 'output': function (buffer) {
6543 + /** @type {ParserOutput | ParserOutput[]} */
6544 + var ret;
6545 + var md = mhchemParser.patterns.match_('{(...)}', buffer.d || "");
6546 + if (md && md.remainder === '') { buffer.d = md.match_; }
6547 + var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || "");
6548 + if (mq && mq.remainder === '') { buffer.q = mq.match_; }
6549 + if (buffer.d) {
6550 + buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C");
6551 + buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F");
6552 + }
6553 + if (buffer.q) { // fraction
6554 + buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C");
6555 + buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F");
6556 + var b5 = {
6557 + d: mhchemParser.go(buffer.d, 'pu'),
6558 + q: mhchemParser.go(buffer.q, 'pu')
6559 + };
6560 + if (buffer.o === '//') {
6561 + ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q };
6562 + } else {
6563 + ret = b5.d;
6564 + if (b5.d.length > 1 || b5.q.length > 1) {
6565 + ret.push({ type_: ' / ' });
6566 + } else {
6567 + ret.push({ type_: '/' });
6568 + }
6569 + mhchemParser.concatArray(ret, b5.q);
6570 + }
6571 + } else { // no fraction
6572 + ret = mhchemParser.go(buffer.d, 'pu-2');
6573 + }
6574 + for (var p in buffer) { delete buffer[p]; }
6575 + return ret;
6576 + }
6577 + }
6578 + },
6579 + 'pu-2': {
6580 + transitions: mhchemParser.createTransitions({
6581 + 'empty': {
6582 + '*': { action_: 'output' } },
6583 + '*': {
6584 + '*': { action_: [ 'output', 'cdot' ], nextState: '0' } },
6585 + '\\x': {
6586 + '*': { action_: 'rm=' } },
6587 + 'space': {
6588 + '*': { action_: [ 'output', 'space' ], nextState: '0' } },
6589 + '^{(...)}|^(-1)': {
6590 + '1': { action_: '^(-1)' } },
6591 + '-9.,9': {
6592 + '0': { action_: 'rm=', nextState: '0' },
6593 + '1': { action_: '^(-1)', nextState: '0' } },
6594 + '{...}|else': {
6595 + '*': { action_: 'rm=', nextState: '1' } }
6596 + }),
6597 + actions: {
6598 + 'cdot': function () { return { type_: 'tight cdot' }; },
6599 + '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; },
6600 + 'space': function () { return { type_: 'pu-space-2' }; },
6601 + 'output': function (buffer) {
6602 + /** @type {ParserOutput | ParserOutput[]} */
6603 + var ret = [];
6604 + if (buffer.rm) {
6605 + var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || "");
6606 + if (mrm && mrm.remainder === '') {
6607 + ret = mhchemParser.go(mrm.match_, 'pu');
6608 + } else {
6609 + ret = { type_: 'rm', p1: buffer.rm };
6610 + }
6611 + }
6612 + for (var p in buffer) { delete buffer[p]; }
6613 + return ret;
6614 + }
6615 + }
6616 + },
6617 + 'pu-9,9': {
6618 + transitions: mhchemParser.createTransitions({
6619 + 'empty': {
6620 + '0': { action_: 'output-0' },
6621 + 'o': { action_: 'output-o' } },
6622 + ',': {
6623 + '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } },
6624 + '.': {
6625 + '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } },
6626 + 'else': {
6627 + '*': { action_: 'text=' } }
6628 + }),
6629 + actions: {
6630 + 'comma': function () { return { type_: 'commaDecimal' }; },
6631 + 'output-0': function (buffer) {
6632 + /** @type {ParserOutput[]} */
6633 + var ret = [];
6634 + buffer.text_ = buffer.text_ || "";
6635 + if (buffer.text_.length > 4) {
6636 + var a = buffer.text_.length % 3;
6637 + if (a === 0) { a = 3; }
6638 + for (var i=buffer.text_.length-3; i>0; i-=3) {
6639 + ret.push(buffer.text_.substr(i, 3));
6640 + ret.push({ type_: '1000 separator' });
6641 + }
6642 + ret.push(buffer.text_.substr(0, a));
6643 + ret.reverse();
6644 + } else {
6645 + ret.push(buffer.text_);
6646 + }
6647 + for (var p in buffer) { delete buffer[p]; }
6648 + return ret;
6649 + },
6650 + 'output-o': function (buffer) {
6651 + /** @type {ParserOutput[]} */
6652 + var ret = [];
6653 + buffer.text_ = buffer.text_ || "";
6654 + if (buffer.text_.length > 4) {
6655 + var a = buffer.text_.length - 3;
6656 + for (var i=0; i<a; i+=3) {
6657 + ret.push(buffer.text_.substr(i, 3));
6658 + ret.push({ type_: '1000 separator' });
6659 + }
6660 + ret.push(buffer.text_.substr(i));
6661 + } else {
6662 + ret.push(buffer.text_);
6663 + }
6664 + for (var p in buffer) { delete buffer[p]; }
6665 + return ret;
6666 + }
6667 + }
6668 + }
6669 + //#endregion
6670 + };
6671 +
6672 + //
6673 + // texify: Take MhchemParser output and convert it to TeX
6674 + //
6675 + /** @type {Texify} */
6676 + var texify = {
6677 + go: function (input, isInner) { // (recursive, max 4 levels)
6678 + if (!input) { return ""; }
6679 + var res = "";
6680 + var cee = false;
6681 + for (var i=0; i < input.length; i++) {
6682 + var inputi = input[i];
6683 + if (typeof inputi === "string") {
6684 + res += inputi;
6685 + } else {
6686 + res += texify._go2(inputi);
6687 + if (inputi.type_ === '1st-level escape') { cee = true; }
6688 + }
6689 + }
6690 + if (!isInner && !cee && res) {
6691 + res = "{" + res + "}";
6692 + }
6693 + return res;
6694 + },
6695 + _goInner: function (input) {
6696 + if (!input) { return input; }
6697 + return texify.go(input, true);
6698 + },
6699 + _go2: function (buf) {
6700 + /** @type {undefined | string} */
6701 + var res;
6702 + switch (buf.type_) {
6703 + case 'chemfive':
6704 + res = "";
6705 + var b5 = {
6706 + a: texify._goInner(buf.a),
6707 + b: texify._goInner(buf.b),
6708 + p: texify._goInner(buf.p),
6709 + o: texify._goInner(buf.o),
6710 + q: texify._goInner(buf.q),
6711 + d: texify._goInner(buf.d)
6712 + };
6713 + //
6714 + // a
6715 + //
6716 + if (b5.a) {
6717 + if (b5.a.match(/^[+\-]/)) { b5.a = "{"+b5.a+"}"; }
6718 + res += b5.a + "\\,";
6719 + }
6720 + //
6721 + // b and p
6722 + //
6723 + if (b5.b || b5.p) {
6724 + res += "{\\vphantom{X}}";
6725 + res += "^{\\hphantom{"+(b5.b||"")+"}}_{\\hphantom{"+(b5.p||"")+"}}";
6726 + res += "{\\vphantom{X}}";
6727 + // In the next two lines, I've removed \smash[t] (ron)
6728 + // TODO: Revert \smash[t] when WebKit properly renders <mpadded> w/height="0"
6729 + //res += "^{\\smash[t]{\\vphantom{2}}\\mathllap{"+(b5.b||"")+"}}";
6730 + res += "^{\\vphantom{2}\\mathllap{"+(b5.b||"")+"}}";
6731 + //res += "_{\\vphantom{2}\\mathllap{\\smash[t]{"+(b5.p||"")+"}}}";
6732 + res += "_{\\vphantom{2}\\mathllap{"+(b5.p||"")+"}}";
6733 + }
6734 + //
6735 + // o
6736 + //
6737 + if (b5.o) {
6738 + if (b5.o.match(/^[+\-]/)) { b5.o = "{"+b5.o+"}"; }
6739 + res += b5.o;
6740 + }
6741 + //
6742 + // q and d
6743 + //
6744 + if (buf.dType === 'kv') {
6745 + if (b5.d || b5.q) {
6746 + res += "{\\vphantom{X}}";
6747 + }
6748 + if (b5.d) {
6749 + res += "^{"+b5.d+"}";
6750 + }
6751 + if (b5.q) {
6752 + // In the next line, I've removed \smash[t] (ron)
6753 + // TODO: Revert \smash[t] when WebKit properly renders <mpadded> w/height="0"
6754 + //res += "_{\\smash[t]{"+b5.q+"}}";
6755 + res += "_{"+b5.q+"}";
6756 + }
6757 + } else if (buf.dType === 'oxidation') {
6758 + if (b5.d) {
6759 + res += "{\\vphantom{X}}";
6760 + res += "^{"+b5.d+"}";
6761 + }
6762 + if (b5.q) {
6763 + // A Firefox bug adds a bogus depth to <mphantom>, so we change \vphantom{X} to {}
6764 + // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed.
6765 + // res += "{\\vphantom{X}}";
6766 + res += "{{}}";
6767 + // In the next line, I've removed \smash[t] (ron)
6768 + // TODO: Revert \smash[t] when WebKit properly renders <mpadded> w/height="0"
6769 + //res += "_{\\smash[t]{"+b5.q+"}}";
6770 + res += "_{"+b5.q+"}";
6771 + }
6772 + } else {
6773 + if (b5.q) {
6774 + // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed.
6775 + // res += "{\\vphantom{X}}";
6776 + res += "{{}}";
6777 + // In the next line, I've removed \smash[t] (ron)
6778 + // TODO: Revert \smash[t] when WebKit properly renders <mpadded> w/height="0"
6779 + //res += "_{\\smash[t]{"+b5.q+"}}";
6780 + res += "_{"+b5.q+"}";
6781 + }
6782 + if (b5.d) {
6783 + // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed.
6784 + // res += "{\\vphantom{X}}";
6785 + res += "{{}}";
6786 + res += "^{"+b5.d+"}";
6787 + }
6788 + }
6789 + break;
6790 + case 'rm':
6791 + res = "\\mathrm{"+buf.p1+"}";
6792 + break;
6793 + case 'text':
6794 + if (buf.p1.match(/[\^_]/)) {
6795 + buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}");
6796 + res = "\\mathrm{"+buf.p1+"}";
6797 + } else {
6798 + res = "\\text{"+buf.p1+"}";
6799 + }
6800 + break;
6801 + case 'roman numeral':
6802 + res = "\\mathrm{"+buf.p1+"}";
6803 + break;
6804 + case 'state of aggregation':
6805 + res = "\\mskip2mu "+texify._goInner(buf.p1);
6806 + break;
6807 + case 'state of aggregation subscript':
6808 + res = "\\mskip1mu "+texify._goInner(buf.p1);
6809 + break;
6810 + case 'bond':
6811 + res = texify._getBond(buf.kind_);
6812 + if (!res) {
6813 + throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"];
6814 + }
6815 + break;
6816 + case 'frac':
6817 + var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}";
6818 + res = "\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}";
6819 + break;
6820 + case 'pu-frac':
6821 + var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
6822 + res = "\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}";
6823 + break;
6824 + case 'tex-math':
6825 + res = buf.p1 + " ";
6826 + break;
6827 + case 'frac-ce':
6828 + res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
6829 + break;
6830 + case 'overset':
6831 + res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
6832 + break;
6833 + case 'underset':
6834 + res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
6835 + break;
6836 + case 'underbrace':
6837 + res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}";
6838 + break;
6839 + case 'color':
6840 + res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}";
6841 + break;
6842 + case 'color0':
6843 + res = "\\color{" + buf.color + "}";
6844 + break;
6845 + case 'arrow':
6846 + var b6 = {
6847 + rd: texify._goInner(buf.rd),
6848 + rq: texify._goInner(buf.rq)
6849 + };
6850 + var arrow = texify._getArrow(buf.r);
6851 + if (b6.rq) { arrow += "[{\\rm " + b6.rq + "}]"; }
6852 + if (b6.rd) {
6853 + arrow += "{\\rm " + b6.rd + "}";
6854 + } else {
6855 + arrow += "{}";
6856 + }
6857 + res = arrow;
6858 + break;
6859 + case 'operator':
6860 + res = texify._getOperator(buf.kind_);
6861 + break;
6862 + case '1st-level escape':
6863 + res = buf.p1+" "; // &, \\\\, \\hlin
6864 + break;
6865 + case 'space':
6866 + res = " ";
6867 + break;
6868 + case 'entitySkip':
6869 + res = "~";
6870 + break;
6871 + case 'pu-space-1':
6872 + res = "~";
6873 + break;
6874 + case 'pu-space-2':
6875 + res = "\\mkern3mu ";
6876 + break;
6877 + case '1000 separator':
6878 + res = "\\mkern2mu ";
6879 + break;
6880 + case 'commaDecimal':
6881 + res = "{,}";
6882 + break;
6883 + case 'comma enumeration L':
6884 + res = "{"+buf.p1+"}\\mkern6mu ";
6885 + break;
6886 + case 'comma enumeration M':
6887 + res = "{"+buf.p1+"}\\mkern3mu ";
6888 + break;
6889 + case 'comma enumeration S':
6890 + res = "{"+buf.p1+"}\\mkern1mu ";
6891 + break;
6892 + case 'hyphen':
6893 + res = "\\text{-}";
6894 + break;
6895 + case 'addition compound':
6896 + res = "\\,{\\cdot}\\,";
6897 + break;
6898 + case 'electron dot':
6899 + res = "\\mkern1mu \\text{\\textbullet}\\mkern1mu ";
6900 + break;
6901 + case 'KV x':
6902 + res = "{\\times}";
6903 + break;
6904 + case 'prime':
6905 + res = "\\prime ";
6906 + break;
6907 + case 'cdot':
6908 + res = "\\cdot ";
6909 + break;
6910 + case 'tight cdot':
6911 + res = "\\mkern1mu{\\cdot}\\mkern1mu ";
6912 + break;
6913 + case 'times':
6914 + res = "\\times ";
6915 + break;
6916 + case 'circa':
6917 + res = "{\\sim}";
6918 + break;
6919 + case '^':
6920 + res = "uparrow";
6921 + break;
6922 + case 'v':
6923 + res = "downarrow";
6924 + break;
6925 + case 'ellipsis':
6926 + res = "\\ldots ";
6927 + break;
6928 + case '/':
6929 + res = "/";
6930 + break;
6931 + case ' / ':
6932 + res = "\\,/\\,";
6933 + break;
6934 + default:
6935 + assertNever(buf);
6936 + throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output
6937 + }
6938 + assertString(res);
6939 + return res;
6940 + },
6941 + _getArrow: function (a) {
6942 + switch (a) {
6943 + case "->": return "\\yields";
6944 + case "\u2192": return "\\yields";
6945 + case "\u27F6": return "\\yields";
6946 + case "<-": return "\\yieldsLeft";
6947 + case "<->": return "\\mesomerism";
6948 + case "<-->": return "\\yieldsLeftRight";
6949 + case "<=>": return "\\equilibrium";
6950 + case "\u21CC": return "\\equilibrium";
6951 + case "<=>>": return "\\equilibriumRight";
6952 + case "<<=>": return "\\equilibriumLeft";
6953 + default:
6954 + assertNever(a);
6955 + throw ["MhchemBugT", "mhchem bug T. Please report."];
6956 + }
6957 + },
6958 + _getBond: function (a) {
6959 + switch (a) {
6960 + case "-": return "{-}";
6961 + case "1": return "{-}";
6962 + case "=": return "{=}";
6963 + case "2": return "{=}";
6964 + case "#": return "{\\equiv}";
6965 + case "3": return "{\\equiv}";
6966 + case "~": return "{\\tripleDash}";
6967 + case "~-": return "{\\tripleDashOverLine}";
6968 + case "~=": return "{\\tripleDashOverDoubleLine}";
6969 + case "~--": return "{\\tripleDashOverDoubleLine}";
6970 + case "-~-": return "{\\tripleDashBetweenDoubleLine}";
6971 + case "...": return "{{\\cdot}{\\cdot}{\\cdot}}";
6972 + case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";
6973 + case "->": return "{\\rightarrow}";
6974 + case "<-": return "{\\leftarrow}";
6975 + case "<": return "{<}";
6976 + case ">": return "{>}";
6977 + default:
6978 + assertNever(a);
6979 + throw ["MhchemBugT", "mhchem bug T. Please report."];
6980 + }
6981 + },
6982 + _getOperator: function (a) {
6983 + switch (a) {
6984 + case "+": return " {}+{} ";
6985 + case "-": return " {}-{} ";
6986 + case "=": return " {}={} ";
6987 + case "<": return " {}<{} ";
6988 + case ">": return " {}>{} ";
6989 + case "<<": return " {}\\ll{} ";
6990 + case ">>": return " {}\\gg{} ";
6991 + case "\\pm": return " {}\\pm{} ";
6992 + case "\\approx": return " {}\\approx{} ";
6993 + case "$\\approx$": return " {}\\approx{} ";
6994 + case "v": return " \\downarrow{} ";
6995 + case "(v)": return " \\downarrow{} ";
6996 + case "^": return " \\uparrow{} ";
6997 + case "(^)": return " \\uparrow{} ";
6998 + default:
6999 + assertNever(a);
7000 + throw ["MhchemBugT", "mhchem bug T. Please report."];
7001 + }
7002 + }
7003 + };
7004 +
7005 + //
7006 + // Helpers for code analysis
7007 + // Will show type error at calling position
7008 + //
7009 + /** @param {number} a */
7010 + function assertNever(a) {}
7011 + /** @param {string} a */
7012 + function assertString(a) {}
7013 +
7014 + /* eslint-disable no-undef */
7015 +
7016 + //////////////////////////////////////////////////////////////////////
7017 + // texvc.sty
7018 +
7019 + // The texvc package contains macros available in mediawiki pages.
7020 + // We omit the functions deprecated at
7021 + // https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax
7022 +
7023 + // We also omit texvc's \O, which conflicts with \text{\O}
7024 +
7025 + defineMacro("\\darr", "\\downarrow");
7026 + defineMacro("\\dArr", "\\Downarrow");
7027 + defineMacro("\\Darr", "\\Downarrow");
7028 + defineMacro("\\lang", "\\langle");
7029 + defineMacro("\\rang", "\\rangle");
7030 + defineMacro("\\uarr", "\\uparrow");
7031 + defineMacro("\\uArr", "\\Uparrow");
7032 + defineMacro("\\Uarr", "\\Uparrow");
7033 + defineMacro("\\N", "\\mathbb{N}");
7034 + defineMacro("\\R", "\\mathbb{R}");
7035 + defineMacro("\\Z", "\\mathbb{Z}");
7036 + defineMacro("\\alef", "\\aleph");
7037 + defineMacro("\\alefsym", "\\aleph");
7038 + defineMacro("\\bull", "\\bullet");
7039 + defineMacro("\\clubs", "\\clubsuit");
7040 + defineMacro("\\cnums", "\\mathbb{C}");
7041 + defineMacro("\\Complex", "\\mathbb{C}");
7042 + defineMacro("\\Dagger", "\\ddagger");
7043 + defineMacro("\\diamonds", "\\diamondsuit");
7044 + defineMacro("\\empty", "\\emptyset");
7045 + defineMacro("\\exist", "\\exists");
7046 + defineMacro("\\harr", "\\leftrightarrow");
7047 + defineMacro("\\hArr", "\\Leftrightarrow");
7048 + defineMacro("\\Harr", "\\Leftrightarrow");
7049 + defineMacro("\\hearts", "\\heartsuit");
7050 + defineMacro("\\image", "\\Im");
7051 + defineMacro("\\infin", "\\infty");
7052 + defineMacro("\\isin", "\\in");
7053 + defineMacro("\\larr", "\\leftarrow");
7054 + defineMacro("\\lArr", "\\Leftarrow");
7055 + defineMacro("\\Larr", "\\Leftarrow");
7056 + defineMacro("\\lrarr", "\\leftrightarrow");
7057 + defineMacro("\\lrArr", "\\Leftrightarrow");
7058 + defineMacro("\\Lrarr", "\\Leftrightarrow");
7059 + defineMacro("\\natnums", "\\mathbb{N}");
7060 + defineMacro("\\plusmn", "\\pm");
7061 + defineMacro("\\rarr", "\\rightarrow");
7062 + defineMacro("\\rArr", "\\Rightarrow");
7063 + defineMacro("\\Rarr", "\\Rightarrow");
7064 + defineMacro("\\real", "\\Re");
7065 + defineMacro("\\reals", "\\mathbb{R}");
7066 + defineMacro("\\Reals", "\\mathbb{R}");
7067 + defineMacro("\\sdot", "\\cdot");
7068 + defineMacro("\\sect", "\\S");
7069 + defineMacro("\\spades", "\\spadesuit");
7070 + defineMacro("\\sub", "\\subset");
7071 + defineMacro("\\sube", "\\subseteq");
7072 + defineMacro("\\supe", "\\supseteq");
7073 + defineMacro("\\thetasym", "\\vartheta");
7074 + defineMacro("\\weierp", "\\wp");
7075 +
7076 + /* eslint-disable no-undef */
7077 +
7078 + /****************************************************
7079 + *
7080 + * physics.js
7081 + *
7082 + * Implements the Physics Package for LaTeX input.
7083 + *
7084 + * ---------------------------------------------------------------------
7085 + *
7086 + * The original version of this file is licensed as follows:
7087 + * Copyright (c) 2015-2016 Kolen Cheung <https://github.com/ickc/MathJax-third-party-extensions>.
7088 + *
7089 + * Licensed under the Apache License, Version 2.0 (the "License");
7090 + * you may not use this file except in compliance with the License.
7091 + * You may obtain a copy of the License at
7092 + *
7093 + * http://www.apache.org/licenses/LICENSE-2.0
7094 + *
7095 + * Unless required by applicable law or agreed to in writing, software
7096 + * distributed under the License is distributed on an "AS IS" BASIS,
7097 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7098 + * See the License for the specific language governing permissions and
7099 + * limitations under the License.
7100 + *
7101 + * ---------------------------------------------------------------------
7102 + *
7103 + * This file has been revised from the original in the following ways:
7104 + * 1. The interface is changed so that it can be called from Temml, not MathJax.
7105 + * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters.
7106 + *
7107 + * This revision of the file is released under the MIT license.
7108 + * https://mit-license.org/
7109 + */
7110 + defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}");
7111 + defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}");
7112 + defineMacro("\\pqty", "{\\left( #1 \\right)}");
7113 + defineMacro("\\bqty", "{\\left[ #1 \\right]}");
7114 + defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}");
7115 + defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}");
7116 + defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}");
7117 + defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}");
7118 + defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}");
7119 + defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}");
7120 + defineMacro("\\eval", "{\\left.#1 \\right\\vert}");
7121 + defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}");
7122 + defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}");
7123 + defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}");
7124 + defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}");
7125 + defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}");
7126 + defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}");
7127 + defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}");
7128 + defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}");
7129 + defineMacro("\\vb", "{\\boldsymbol{ #1 }}");
7130 + defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}");
7131 + defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}");
7132 + defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}");
7133 + defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}");
7134 + defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}");
7135 + defineMacro("\\vdot", "{\\boldsymbol\\cdot}");
7136 + defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}");
7137 + defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}");
7138 + defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}");
7139 + defineMacro("\\gradient", "{\\boldsymbol\\nabla}");
7140 + defineMacro("\\grad", "{\\boldsymbol\\nabla}");
7141 + defineMacro("\\divergence", "{\\grad\\vdot}");
7142 + //defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div
7143 + defineMacro("\\curl", "{\\grad\\cross}");
7144 + defineMacro("\\laplacian", "\\nabla^2");
7145 + defineMacro("\\tr", "{\\operatorname{tr}}");
7146 + defineMacro("\\Tr", "{\\operatorname{Tr}}");
7147 + defineMacro("\\rank", "{\\operatorname{rank}}");
7148 + defineMacro("\\erf", "{\\operatorname{erf}}");
7149 + defineMacro("\\Res", "{\\operatorname{Res}}");
7150 + defineMacro("\\principalvalue", "{\\mathcal{P}}");
7151 + defineMacro("\\pv", "{\\mathcal{P}}");
7152 + defineMacro("\\PV", "{\\operatorname{P.V.}}");
7153 + // Temml does not use the next two lines. They conflict with LaTeX letters.
7154 + //defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}");
7155 + //defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}");
7156 + defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}");
7157 + defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}");
7158 + defineMacro("\\qcomma", "{\\text{,}\\quad}");
7159 + defineMacro("\\qc", "{\\text{,}\\quad}");
7160 + defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}");
7161 + defineMacro("\\qif", "{\\quad\\text{if}\\quad}");
7162 + defineMacro("\\qthen", "{\\quad\\text{then}\\quad}");
7163 + defineMacro("\\qelse", "{\\quad\\text{else}\\quad}");
7164 + defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}");
7165 + defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}");
7166 + defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}");
7167 + defineMacro("\\qusing", "{\\quad\\text{using}\\quad}");
7168 + defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}");
7169 + defineMacro("\\qsince", "{\\quad\\text{since}\\quad}");
7170 + defineMacro("\\qlet", "{\\quad\\text{let}\\quad}");
7171 + defineMacro("\\qfor", "{\\quad\\text{for}\\quad}");
7172 + defineMacro("\\qall", "{\\quad\\text{all}\\quad}");
7173 + defineMacro("\\qeven", "{\\quad\\text{even}\\quad}");
7174 + defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}");
7175 + defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}");
7176 + defineMacro("\\qand", "{\\quad\\text{and}\\quad}");
7177 + defineMacro("\\qor", "{\\quad\\text{or}\\quad}");
7178 + defineMacro("\\qas", "{\\quad\\text{as}\\quad}");
7179 + defineMacro("\\qin", "{\\quad\\text{in}\\quad}");
7180 + defineMacro("\\differential", "{\\text{d}}");
7181 + defineMacro("\\dd", "{\\text{d}}");
7182 + defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}");
7183 + defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}");
7184 + defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}");
7185 + defineMacro("\\variation", "{\\delta}");
7186 + defineMacro("\\var", "{\\delta}");
7187 + defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}");
7188 + defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}");
7189 + defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}");
7190 + defineMacro("\\outerproduct",
7191 + "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}");
7192 + defineMacro("\\dyad",
7193 + "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}");
7194 + defineMacro("\\ketbra",
7195 + "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}");
7196 + defineMacro("\\op",
7197 + "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}");
7198 + defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}");
7199 + defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}");
7200 + defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}");
7201 + defineMacro("\\matrixelement",
7202 + "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}");
7203 + defineMacro("\\matrixel",
7204 + "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}");
7205 + defineMacro("\\mel",
7206 + "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}");
7207 +
7208 + // Helper functions
7209 + function getHLines(parser) {
7210 + // Return an array. The array length = number of hlines.
7211 + // Each element in the array tells if the line is dashed.
7212 + const hlineInfo = [];
7213 + parser.consumeSpaces();
7214 + let nxt = parser.fetch().text;
7215 + if (nxt === "\\relax") {
7216 + parser.consume();
7217 + parser.consumeSpaces();
7218 + nxt = parser.fetch().text;
7219 + }
7220 + while (nxt === "\\hline" || nxt === "\\hdashline") {
7221 + parser.consume();
7222 + hlineInfo.push(nxt === "\\hdashline");
7223 + parser.consumeSpaces();
7224 + nxt = parser.fetch().text;
7225 + }
7226 + return hlineInfo;
7227 + }
7228 +
7229 + const validateAmsEnvironmentContext = context => {
7230 + const settings = context.parser.settings;
7231 + if (!settings.displayMode) {
7232 + throw new ParseError(`{${context.envName}} can be used only in display mode.`);
7233 + }
7234 + };
7235 +
7236 + const sizeRegEx$1 = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/;
7237 + const arrayGaps = macros => {
7238 + let arraystretch = macros.get("\\arraystretch");
7239 + if (typeof arraystretch !== "string") {
7240 + arraystretch = stringFromArg(arraystretch.tokens);
7241 + }
7242 + arraystretch = isNaN(arraystretch) ? null : Number(arraystretch);
7243 + let arraycolsepStr = macros.get("\\arraycolsep");
7244 + if (typeof arraycolsepStr !== "string") {
7245 + arraycolsepStr = stringFromArg(arraycolsepStr.tokens);
7246 + }
7247 + const match = sizeRegEx$1.exec(arraycolsepStr);
7248 + const arraycolsep = match
7249 + ? { number: +(match[1] + match[2]), unit: match[3] }
7250 + : null;
7251 + return [arraystretch, arraycolsep]
7252 + };
7253 +
7254 + const checkCellForLabels = cell => {
7255 + // Check if the author wrote a \tag{} inside this cell.
7256 + let rowLabel = "";
7257 + for (let i = 0; i < cell.length; i++) {
7258 + if (cell[i].type === "label") {
7259 + if (rowLabel) { throw new ParseError(("Multiple \\labels in one row")) }
7260 + rowLabel = cell[i].string;
7261 + }
7262 + }
7263 + return rowLabel
7264 + };
7265 +
7266 + // autoTag (an argument to parseArray) can be one of three values:
7267 + // * undefined: Regular (not-top-level) array; no tags on each row
7268 + // * true: Automatic equation numbering, overridable by \tag
7269 + // * false: Tags allowed on each row, but no automatic numbering
7270 + // This function *doesn't* work with the "split" environment name.
7271 + function getAutoTag(name) {
7272 + if (name.indexOf("ed") === -1) {
7273 + return name.indexOf("*") === -1;
7274 + }
7275 + // return undefined;
7276 + }
7277 +
7278 + /**
7279 + * Parse the body of the environment, with rows delimited by \\ and
7280 + * columns delimited by &, and create a nested list in row-major order
7281 + * with one group per cell. If given an optional argument scriptLevel
7282 + * ("text", "display", etc.), then each cell is cast into that scriptLevel.
7283 + */
7284 + function parseArray(
7285 + parser,
7286 + {
7287 + cols, // [{ type: string , align: l|c|r|null }]
7288 + envClasses, // align(ed|at|edat) | array | cases | cd | small | multline
7289 + autoTag, // boolean
7290 + singleRow, // boolean
7291 + emptySingleRow, // boolean
7292 + maxNumCols, // number
7293 + leqno, // boolean
7294 + arraystretch, // number | null
7295 + arraycolsep // size value | null
7296 + },
7297 + scriptLevel
7298 + ) {
7299 + parser.gullet.beginGroup();
7300 + if (!singleRow) {
7301 + // \cr is equivalent to \\ without the optional size argument (see below)
7302 + // TODO: provide helpful error when \cr is used outside array environment
7303 + parser.gullet.macros.set("\\cr", "\\\\\\relax");
7304 + }
7305 +
7306 + // Start group for first cell
7307 + parser.gullet.beginGroup();
7308 +
7309 + let row = [];
7310 + const body = [row];
7311 + const rowGaps = [];
7312 + const labels = [];
7313 +
7314 + const hLinesBeforeRow = [];
7315 +
7316 + const tags = (autoTag != null ? [] : undefined);
7317 +
7318 + // amsmath uses \global\@eqnswtrue and \global\@eqnswfalse to represent
7319 + // whether this row should have an equation number. Simulate this with
7320 + // a \@eqnsw macro set to 1 or 0.
7321 + function beginRow() {
7322 + if (autoTag) {
7323 + parser.gullet.macros.set("\\@eqnsw", "1", true);
7324 + }
7325 + }
7326 + function endRow() {
7327 + if (tags) {
7328 + if (parser.gullet.macros.get("\\df@tag")) {
7329 + tags.push(parser.subparse([new Token("\\df@tag")]));
7330 + parser.gullet.macros.set("\\df@tag", undefined, true);
7331 + } else {
7332 + tags.push(Boolean(autoTag) &&
7333 + parser.gullet.macros.get("\\@eqnsw") === "1");
7334 + }
7335 + }
7336 + }
7337 + beginRow();
7338 +
7339 + // Test for \hline at the top of the array.
7340 + hLinesBeforeRow.push(getHLines(parser));
7341 +
7342 + while (true) {
7343 + // Parse each cell in its own group (namespace)
7344 + let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\");
7345 + parser.gullet.endGroup();
7346 + parser.gullet.beginGroup();
7347 +
7348 + cell = {
7349 + type: "ordgroup",
7350 + mode: parser.mode,
7351 + body: cell,
7352 + semisimple: true
7353 + };
7354 + row.push(cell);
7355 + const next = parser.fetch().text;
7356 + if (next === "&") {
7357 + if (maxNumCols && row.length === maxNumCols) {
7358 + if (envClasses.includes("array")) {
7359 + if (parser.settings.strict) {
7360 + throw new ParseError("Too few columns " + "specified in the {array} column argument.",
7361 + parser.nextToken)
7362 + }
7363 + } else if (maxNumCols === 2) {
7364 + throw new ParseError("The split environment accepts no more than two columns",
7365 + parser.nextToken);
7366 + } else {
7367 + throw new ParseError("The equation environment accepts only one column",
7368 + parser.nextToken)
7369 + }
7370 + }
7371 + parser.consume();
7372 + } else if (next === "\\end") {
7373 + endRow();
7374 + // Arrays terminate newlines with `\crcr` which consumes a `\cr` if
7375 + // the last line is empty. However, AMS environments keep the
7376 + // empty row if it's the only one.
7377 + // NOTE: Currently, `cell` is the last item added into `row`.
7378 + if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) {
7379 + body.pop();
7380 + }
7381 + labels.push(checkCellForLabels(cell.body));
7382 + if (hLinesBeforeRow.length < body.length + 1) {
7383 + hLinesBeforeRow.push([]);
7384 + }
7385 + break;
7386 + } else if (next === "\\\\") {
7387 + parser.consume();
7388 + let size;
7389 + // \def\Let@{\let\\\math@cr}
7390 + // \def\math@cr{...\math@cr@}
7391 + // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}}
7392 + // \def\math@cr@@[#1]{...\math@cr@@@...}
7393 + // \def\math@cr@@@{\cr}
7394 + if (parser.gullet.future().text !== " ") {
7395 + size = parser.parseSizeGroup(true);
7396 + }
7397 + rowGaps.push(size ? size.value : null);
7398 + endRow();
7399 +
7400 + labels.push(checkCellForLabels(cell.body));
7401 +
7402 + // check for \hline(s) following the row separator
7403 + hLinesBeforeRow.push(getHLines(parser));
7404 +
7405 + row = [];
7406 + body.push(row);
7407 + beginRow();
7408 + } else {
7409 + throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken);
7410 + }
7411 + }
7412 +
7413 + // End cell group
7414 + parser.gullet.endGroup();
7415 + // End array group defining \cr
7416 + parser.gullet.endGroup();
7417 +
7418 + return {
7419 + type: "array",
7420 + mode: parser.mode,
7421 + body,
7422 + cols,
7423 + rowGaps,
7424 + hLinesBeforeRow,
7425 + envClasses,
7426 + autoTag,
7427 + scriptLevel,
7428 + tags,
7429 + labels,
7430 + leqno,
7431 + arraystretch,
7432 + arraycolsep
7433 + };
7434 + }
7435 +
7436 + // Decides on a scriptLevel for cells in an array according to whether the given
7437 + // environment name starts with the letter 'd'.
7438 + function dCellStyle(envName) {
7439 + return envName.slice(0, 1) === "d" ? "display" : "text"
7440 + }
7441 +
7442 + const alignMap = {
7443 + c: "center ",
7444 + l: "left ",
7445 + r: "right "
7446 + };
7447 +
7448 + const glue = group => {
7449 + const glueNode = new mathMLTree.MathNode("mtd", []);
7450 + glueNode.style = { padding: "0", width: "50%" };
7451 + if (group.envClasses.includes("multline")) {
7452 + glueNode.style.width = "7.5%";
7453 + }
7454 + return glueNode
7455 + };
7456 +
7457 + const mathmlBuilder$7 = function(group, style) {
7458 + const tbl = [];
7459 + const numRows = group.body.length;
7460 + const hlines = group.hLinesBeforeRow;
7461 +
7462 + for (let i = 0; i < numRows; i++) {
7463 + const rw = group.body[i];
7464 + const row = [];
7465 + const cellLevel = group.scriptLevel === "text"
7466 + ? StyleLevel.TEXT
7467 + : group.scriptLevel === "script"
7468 + ? StyleLevel.SCRIPT
7469 + : StyleLevel.DISPLAY;
7470 +
7471 + for (let j = 0; j < rw.length; j++) {
7472 + const mtd = new mathMLTree.MathNode(
7473 + "mtd",
7474 + [buildGroup$1(rw[j], style.withLevel(cellLevel))]
7475 + );
7476 +
7477 + if (group.envClasses.includes("multline")) {
7478 + const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center";
7479 + mtd.setAttribute("columnalign", align);
7480 + if (align !== "center") {
7481 + mtd.classes.push("tml-" + align);
7482 + }
7483 + }
7484 + row.push(mtd);
7485 + }
7486 + const numColumns = group.body[0].length;
7487 + // Fill out a short row with empty <mtd> elements.
7488 + for (let k = 0; k < numColumns - rw.length; k++) {
7489 + row.push(new mathMLTree.MathNode("mtd", [], style));
7490 + }
7491 + if (group.autoTag) {
7492 + const tag = group.tags[i];
7493 + let tagElement;
7494 + if (tag === true) { // automatic numbering
7495 + tagElement = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]);
7496 + } else if (tag === false) {
7497 + // \nonumber/\notag or starred environment
7498 + tagElement = new mathMLTree.MathNode("mtext", [], []);
7499 + } else { // manual \tag
7500 + tagElement = buildExpressionRow(tag[0].body, style.withLevel(cellLevel), true);
7501 + tagElement = consolidateText(tagElement);
7502 + tagElement.classes = ["tml-tag"];
7503 + }
7504 + if (tagElement) {
7505 + row.unshift(glue(group));
7506 + row.push(glue(group));
7507 + if (group.leqno) {
7508 + row[0].children.push(tagElement);
7509 + row[0].classes.push("tml-left");
7510 + } else {
7511 + row[row.length - 1].children.push(tagElement);
7512 + row[row.length - 1].classes.push("tml-right");
7513 + }
7514 + }
7515 + }
7516 + const mtr = new mathMLTree.MathNode("mtr", row, []);
7517 + const label = group.labels.shift();
7518 + if (label && group.tags && group.tags[i]) {
7519 + mtr.setAttribute("id", label);
7520 + if (Array.isArray(group.tags[i])) { mtr.classes.push("tml-tageqn"); }
7521 + }
7522 +
7523 + // Write horizontal rules
7524 + if (i === 0 && hlines[0].length > 0) {
7525 + if (hlines[0].length === 2) {
7526 + mtr.children.forEach(cell => { cell.style.borderTop = "0.15em double"; });
7527 + } else {
7528 + mtr.children.forEach(cell => {
7529 + cell.style.borderTop = hlines[0][0] ? "0.06em dashed" : "0.06em solid";
7530 + });
7531 + }
7532 + }
7533 + if (hlines[i + 1].length > 0) {
7534 + if (hlines[i + 1].length === 2) {
7535 + mtr.children.forEach(cell => { cell.style.borderBottom = "0.15em double"; });
7536 + } else {
7537 + mtr.children.forEach(cell => {
7538 + cell.style.borderBottom = hlines[i + 1][0] ? "0.06em dashed" : "0.06em solid";
7539 + });
7540 + }
7541 + }
7542 + tbl.push(mtr);
7543 + }
7544 +
7545 + if (group.envClasses.length > 0) {
7546 + if (group.arraystretch && group.arraystretch !== 1) {
7547 + // In LaTeX, \arraystretch is a factor applied to a 12pt strut height.
7548 + // It defines a baseline to baseline distance.
7549 + // Here, we do an approximation of that approach.
7550 + const pad = String(1.4 * group.arraystretch - 0.8) + "ex";
7551 + for (let i = 0; i < tbl.length; i++) {
7552 + for (let j = 0; j < tbl[i].children.length; j++) {
7553 + tbl[i].children[j].style.paddingTop = pad;
7554 + tbl[i].children[j].style.paddingBottom = pad;
7555 + }
7556 + }
7557 + }
7558 + let sidePadding = group.envClasses.includes("abut")
7559 + ? "0"
7560 + : group.envClasses.includes("cases")
7561 + ? "0"
7562 + : group.envClasses.includes("small")
7563 + ? "0.1389"
7564 + : group.envClasses.includes("cd")
7565 + ? "0.25"
7566 + : "0.4"; // default side padding
7567 + let sidePadUnit = "em";
7568 + if (group.arraycolsep) {
7569 + const arraySidePad = calculateSize(group.arraycolsep, style);
7570 + sidePadding = arraySidePad.number.toFixed(4);
7571 + sidePadUnit = arraySidePad.unit;
7572 + }
7573 +
7574 + const numCols = tbl.length === 0 ? 0 : tbl[0].children.length;
7575 +
7576 + const sidePad = (j, hand) => {
7577 + if (j === 0 && hand === 0) { return "0" }
7578 + if (j === numCols - 1 && hand === 1) { return "0" }
7579 + if (group.envClasses[0] !== "align") { return sidePadding }
7580 + if (hand === 1) { return "0" }
7581 + if (group.autoTag) {
7582 + return (j % 2) ? "1" : "0"
7583 + } else {
7584 + return (j % 2) ? "0" : "1"
7585 + }
7586 + };
7587 +
7588 + // Side padding
7589 + for (let i = 0; i < tbl.length; i++) {
7590 + for (let j = 0; j < tbl[i].children.length; j++) {
7591 + tbl[i].children[j].style.paddingLeft = `${sidePad(j, 0)}${sidePadUnit}`;
7592 + tbl[i].children[j].style.paddingRight = `${sidePad(j, 1)}${sidePadUnit}`;
7593 + }
7594 + }
7595 +
7596 + // Justification
7597 + const align = group.envClasses.includes("align") || group.envClasses.includes("alignat");
7598 + for (let i = 0; i < tbl.length; i++) {
7599 + const row = tbl[i];
7600 + if (align) {
7601 + for (let j = 0; j < row.children.length; j++) {
7602 + // Chromium does not recognize text-align: left. Use -webkit-
7603 + // TODO: Remove -webkit- when Chromium no longer needs it.
7604 + row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")];
7605 + }
7606 + if (group.autoTag) {
7607 + const k = group.leqno ? 0 : row.children.length - 1;
7608 + row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")];
7609 + }
7610 + }
7611 + if (row.children.length > 1 && group.envClasses.includes("cases")) {
7612 + row.children[1].style.paddingLeft = "1em";
7613 + }
7614 +
7615 + if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) {
7616 + for (const cell of row.children) {
7617 + cell.classes.push("tml-left");
7618 + }
7619 + }
7620 + }
7621 + } else {
7622 + // Set zero padding on side of the matrix
7623 + for (let i = 0; i < tbl.length; i++) {
7624 + tbl[i].children[0].style.paddingLeft = "0em";
7625 + if (tbl[i].children.length === tbl[0].children.length) {
7626 + tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em";
7627 + }
7628 + }
7629 + }
7630 +
7631 + let table = new mathMLTree.MathNode("mtable", tbl);
7632 + if (group.envClasses.length > 0) {
7633 + // Top & bottom padding
7634 + if (group.envClasses.includes("jot")) {
7635 + table.classes.push("tml-jot");
7636 + } else if (group.envClasses.includes("small")) {
7637 + table.classes.push("tml-small");
7638 + }
7639 + }
7640 + if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); }
7641 +
7642 + if (group.autoTag || group.envClasses.includes("multline")) {
7643 + table.style.width = "100%";
7644 + }
7645 +
7646 + // Column separator lines and column alignment
7647 + let align = "";
7648 +
7649 + if (group.cols && group.cols.length > 0) {
7650 + const cols = group.cols;
7651 + let prevTypeWasAlign = false;
7652 + let iStart = 0;
7653 + let iEnd = cols.length;
7654 +
7655 + while (cols[iStart].type === "separator") {
7656 + iStart += 1;
7657 + }
7658 + while (cols[iEnd - 1].type === "separator") {
7659 + iEnd -= 1;
7660 + }
7661 +
7662 + if (cols[0].type === "separator") {
7663 + const sep = cols[1].type === "separator"
7664 + ? "0.15em double"
7665 + : cols[0].separator === "|"
7666 + ? "0.06em solid "
7667 + : "0.06em dashed ";
7668 + for (const row of table.children) {
7669 + row.children[0].style.borderLeft = sep;
7670 + }
7671 + }
7672 + let iCol = group.autoTag ? 0 : -1;
7673 + for (let i = iStart; i < iEnd; i++) {
7674 + if (cols[i].type === "align") {
7675 + const colAlign = alignMap[cols[i].align];
7676 + align += colAlign;
7677 + iCol += 1;
7678 + for (const row of table.children) {
7679 + if (colAlign.trim() !== "center" && iCol < row.children.length) {
7680 + row.children[iCol].classes = ["tml-" + colAlign.trim()];
7681 + }
7682 + }
7683 + prevTypeWasAlign = true;
7684 + } else if (cols[i].type === "separator") {
7685 + // MathML accepts only single lines between cells.
7686 + // So we read only the first of consecutive separators.
7687 + if (prevTypeWasAlign) {
7688 + const sep = cols[i + 1].type === "separator"
7689 + ? "0.15em double"
7690 + : cols[i].separator === "|"
7691 + ? "0.06em solid"
7692 + : "0.06em dashed";
7693 + for (const row of table.children) {
7694 + if (iCol < row.children.length) {
7695 + row.children[iCol].style.borderRight = sep;
7696 + }
7697 + }
7698 + }
7699 + prevTypeWasAlign = false;
7700 + }
7701 + }
7702 + if (cols[cols.length - 1].type === "separator") {
7703 + const sep = cols[cols.length - 2].type === "separator"
7704 + ? "0.15em double"
7705 + : cols[cols.length - 1].separator === "|"
7706 + ? "0.06em solid"
7707 + : "0.06em dashed";
7708 + for (const row of table.children) {
7709 + row.children[row.children.length - 1].style.borderRight = sep;
7710 + row.children[row.children.length - 1].style.paddingRight = "0.4em";
7711 + }
7712 + }
7713 + }
7714 + if (group.autoTag) {
7715 + // allow for glue cells on each side
7716 + align = "left " + (align.length > 0 ? align : "center ") + "right ";
7717 + }
7718 + if (align) {
7719 + // Firefox reads this attribute, not the -webkit-left|right written above.
7720 + // TODO: When Chrome no longer needs "-webkit-", use CSS and delete the next line.
7721 + table.setAttribute("columnalign", align.trim());
7722 + }
7723 +
7724 + if (group.envClasses.includes("small")) {
7725 + // A small array. Wrap in scriptstyle.
7726 + table = new mathMLTree.MathNode("mstyle", [table]);
7727 + table.setAttribute("scriptlevel", "1");
7728 + }
7729 +
7730 + return table
7731 + };
7732 +
7733 + // Convenience function for align, align*, aligned, alignat, alignat*, alignedat, split.
7734 + const alignedHandler = function(context, args) {
7735 + if (context.envName.indexOf("ed") === -1) {
7736 + validateAmsEnvironmentContext(context);
7737 + }
7738 + const isSplit = context.envName === "split";
7739 + const cols = [];
7740 + const res = parseArray(
7741 + context.parser,
7742 + {
7743 + cols,
7744 + emptySingleRow: true,
7745 + autoTag: isSplit ? undefined : getAutoTag(context.envName),
7746 + envClasses: ["abut", "jot"], // set row spacing & provisional column spacing
7747 + maxNumCols: context.envName === "split" ? 2 : undefined,
7748 + leqno: context.parser.settings.leqno
7749 + },
7750 + "display"
7751 + );
7752 +
7753 + // Determining number of columns.
7754 + // 1. If the first argument is given, we use it as a number of columns,
7755 + // and makes sure that each row doesn't exceed that number.
7756 + // 2. Otherwise, just count number of columns = maximum number
7757 + // of cells in each row ("aligned" mode -- isAligned will be true).
7758 + //
7759 + // At the same time, prepend empty group {} at beginning of every second
7760 + // cell in each row (starting with second cell) so that operators become
7761 + // binary. This behavior is implemented in amsmath's \start@aligned.
7762 + let numMaths;
7763 + let numCols = 0;
7764 + const isAlignedAt = context.envName.indexOf("at") > -1;
7765 + if (args[0] && isAlignedAt) {
7766 + // alignat environment takes an argument w/ number of columns
7767 + let arg0 = "";
7768 + for (let i = 0; i < args[0].body.length; i++) {
7769 + const textord = assertNodeType(args[0].body[i], "textord");
7770 + arg0 += textord.text;
7771 + }
7772 + if (isNaN(arg0)) {
7773 + throw new ParseError("The alignat enviroment requires a numeric first argument.")
7774 + }
7775 + numMaths = Number(arg0);
7776 + numCols = numMaths * 2;
7777 + }
7778 + res.body.forEach(function(row) {
7779 + if (isAlignedAt) {
7780 + // Case 1
7781 + const curMaths = row.length / 2;
7782 + if (numMaths < curMaths) {
7783 + throw new ParseError(
7784 + "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`,
7785 + row[0]
7786 + );
7787 + }
7788 + } else if (numCols < row.length) {
7789 + // Case 2
7790 + numCols = row.length;
7791 + }
7792 + });
7793 +
7794 + // Adjusting alignment.
7795 + // In aligned mode, we add one \qquad between columns;
7796 + // otherwise we add nothing.
7797 + for (let i = 0; i < numCols; ++i) {
7798 + let align = "r";
7799 + if (i % 2 === 1) {
7800 + align = "l";
7801 + }
7802 + cols[i] = {
7803 + type: "align",
7804 + align: align
7805 + };
7806 + }
7807 + if (context.envName === "split") ; else if (isAlignedAt) {
7808 + res.envClasses.push("alignat"); // Sets justification
7809 + } else {
7810 + res.envClasses[0] = "align"; // Sets column spacing & justification
7811 + }
7812 + return res;
7813 + };
7814 +
7815 + // Arrays are part of LaTeX, defined in lttab.dtx so its documentation
7816 + // is part of the source2e.pdf file of LaTeX2e source documentation.
7817 + // {darray} is an {array} environment where cells are set in \displaystyle,
7818 + // as defined in nccmath.sty.
7819 + defineEnvironment({
7820 + type: "array",
7821 + names: ["array", "darray"],
7822 + props: {
7823 + numArgs: 1
7824 + },
7825 + handler(context, args) {
7826 + // Since no types are specified above, the two possibilities are
7827 + // - The argument is wrapped in {} or [], in which case Parser's
7828 + // parseGroup() returns an "ordgroup" wrapping some symbol node.
7829 + // - The argument is a bare symbol node.
7830 + const symNode = checkSymbolNodeType(args[0]);
7831 + const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body;
7832 + const cols = colalign.map(function(nde) {
7833 + const node = assertSymbolNodeType(nde);
7834 + const ca = node.text;
7835 + if ("lcr".indexOf(ca) !== -1) {
7836 + return {
7837 + type: "align",
7838 + align: ca
7839 + };
7840 + } else if (ca === "|") {
7841 + return {
7842 + type: "separator",
7843 + separator: "|"
7844 + };
7845 + } else if (ca === ":") {
7846 + return {
7847 + type: "separator",
7848 + separator: ":"
7849 + };
7850 + }
7851 + throw new ParseError("Unknown column alignment: " + ca, nde);
7852 + });
7853 + const [arraystretch, arraycolsep] = arrayGaps(context.parser.gullet.macros);
7854 + const res = {
7855 + cols,
7856 + envClasses: ["array"],
7857 + maxNumCols: cols.length,
7858 + arraystretch,
7859 + arraycolsep
7860 + };
7861 + return parseArray(context.parser, res, dCellStyle(context.envName));
7862 + },
7863 + mathmlBuilder: mathmlBuilder$7
7864 + });
7865 +
7866 + // The matrix environments of amsmath builds on the array environment
7867 + // of LaTeX, which is discussed above.
7868 + // The mathtools package adds starred versions of the same environments.
7869 + // These have an optional argument to choose left|center|right justification.
7870 + defineEnvironment({
7871 + type: "array",
7872 + names: [
7873 + "matrix",
7874 + "pmatrix",
7875 + "bmatrix",
7876 + "Bmatrix",
7877 + "vmatrix",
7878 + "Vmatrix",
7879 + "matrix*",
7880 + "pmatrix*",
7881 + "bmatrix*",
7882 + "Bmatrix*",
7883 + "vmatrix*",
7884 + "Vmatrix*"
7885 + ],
7886 + props: {
7887 + numArgs: 0
7888 + },
7889 + handler(context) {
7890 + const delimiters = {
7891 + matrix: null,
7892 + pmatrix: ["(", ")"],
7893 + bmatrix: ["[", "]"],
7894 + Bmatrix: ["\\{", "\\}"],
7895 + vmatrix: ["|", "|"],
7896 + Vmatrix: ["\\Vert", "\\Vert"]
7897 + }[context.envName.replace("*", "")];
7898 + // \hskip -\arraycolsep in amsmath
7899 + let colAlign = "c";
7900 + const payload = {
7901 + envClasses: [],
7902 + cols: []
7903 + };
7904 + if (context.envName.charAt(context.envName.length - 1) === "*") {
7905 + // It's one of the mathtools starred functions.
7906 + // Parse the optional alignment argument.
7907 + const parser = context.parser;
7908 + parser.consumeSpaces();
7909 + if (parser.fetch().text === "[") {
7910 + parser.consume();
7911 + parser.consumeSpaces();
7912 + colAlign = parser.fetch().text;
7913 + if ("lcr".indexOf(colAlign) === -1) {
7914 + throw new ParseError("Expected l or c or r", parser.nextToken);
7915 + }
7916 + parser.consume();
7917 + parser.consumeSpaces();
7918 + parser.expect("]");
7919 + parser.consume();
7920 + payload.cols = [];
7921 + }
7922 + }
7923 + const res = parseArray(context.parser, payload, "text");
7924 + res.cols = new Array(res.body[0].length).fill({ type: "align", align: colAlign });
7925 + const [arraystretch, arraycolsep] = arrayGaps(context.parser.gullet.macros);
7926 + return delimiters
7927 + ? {
7928 + type: "leftright",
7929 + mode: context.mode,
7930 + body: [res],
7931 + left: delimiters[0],
7932 + right: delimiters[1],
7933 + rightColor: undefined, // \right uninfluenced by \color in array
7934 + arraystretch,
7935 + arraycolsep
7936 + }
7937 + : res;
7938 + },
7939 + mathmlBuilder: mathmlBuilder$7
7940 + });
7941 +
7942 + defineEnvironment({
7943 + type: "array",
7944 + names: ["smallmatrix"],
7945 + props: {
7946 + numArgs: 0
7947 + },
7948 + handler(context) {
7949 + const payload = { type: "small" };
7950 + const res = parseArray(context.parser, payload, "script");
7951 + res.envClasses = ["small"];
7952 + return res;
7953 + },
7954 + mathmlBuilder: mathmlBuilder$7
7955 + });
7956 +
7957 + defineEnvironment({
7958 + type: "array",
7959 + names: ["subarray"],
7960 + props: {
7961 + numArgs: 1
7962 + },
7963 + handler(context, args) {
7964 + // Parsing of {subarray} is similar to {array}
7965 + const symNode = checkSymbolNodeType(args[0]);
7966 + const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body;
7967 + const cols = colalign.map(function(nde) {
7968 + const node = assertSymbolNodeType(nde);
7969 + const ca = node.text;
7970 + // {subarray} only recognizes "l" & "c"
7971 + if ("lc".indexOf(ca) !== -1) {
7972 + return {
7973 + type: "align",
7974 + align: ca
7975 + };
7976 + }
7977 + throw new ParseError("Unknown column alignment: " + ca, nde);
7978 + });
7979 + if (cols.length > 1) {
7980 + throw new ParseError("{subarray} can contain only one column");
7981 + }
7982 + let res = {
7983 + cols,
7984 + envClasses: ["small"]
7985 + };
7986 + res = parseArray(context.parser, res, "script");
7987 + if (res.body.length > 0 && res.body[0].length > 1) {
7988 + throw new ParseError("{subarray} can contain only one column");
7989 + }
7990 + return res;
7991 + },
7992 + mathmlBuilder: mathmlBuilder$7
7993 + });
7994 +
7995 + // A cases environment (in amsmath.sty) is almost equivalent to
7996 + // \def
7997 + // \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
7998 + // {dcases} is a {cases} environment where cells are set in \displaystyle,
7999 + // as defined in mathtools.sty.
8000 + // {rcases} is another mathtools environment. It's brace is on the right side.
8001 + defineEnvironment({
8002 + type: "array",
8003 + names: ["cases", "dcases", "rcases", "drcases"],
8004 + props: {
8005 + numArgs: 0
8006 + },
8007 + handler(context) {
8008 + const payload = {
8009 + cols: [],
8010 + envClasses: ["cases"]
8011 + };
8012 + const res = parseArray(context.parser, payload, dCellStyle(context.envName));
8013 + return {
8014 + type: "leftright",
8015 + mode: context.mode,
8016 + body: [res],
8017 + left: context.envName.indexOf("r") > -1 ? "." : "\\{",
8018 + right: context.envName.indexOf("r") > -1 ? "\\}" : ".",
8019 + rightColor: undefined
8020 + };
8021 + },
8022 + mathmlBuilder: mathmlBuilder$7
8023 + });
8024 +
8025 + // In the align environment, one uses ampersands, &, to specify number of
8026 + // columns in each row, and to locate spacing between each column.
8027 + // align gets automatic numbering. align* and aligned do not.
8028 + // The alignedat environment can be used in math mode.
8029 + defineEnvironment({
8030 + type: "array",
8031 + names: ["align", "align*", "aligned", "split"],
8032 + props: {
8033 + numArgs: 0
8034 + },
8035 + handler: alignedHandler,
8036 + mathmlBuilder: mathmlBuilder$7
8037 + });
8038 +
8039 + // alignat environment is like an align environment, but one must explicitly
8040 + // specify maximum number of columns in each row, and can adjust where spacing occurs.
8041 + defineEnvironment({
8042 + type: "array",
8043 + names: ["alignat", "alignat*", "alignedat"],
8044 + props: {
8045 + numArgs: 1
8046 + },
8047 + handler: alignedHandler,
8048 + mathmlBuilder: mathmlBuilder$7
8049 + });
8050 +
8051 + // A gathered environment is like an array environment with one centered
8052 + // column, but where rows are considered lines so get \jot line spacing
8053 + // and contents are set in \displaystyle.
8054 + defineEnvironment({
8055 + type: "array",
8056 + names: ["gathered", "gather", "gather*"],
8057 + props: {
8058 + numArgs: 0
8059 + },
8060 + handler(context) {
8061 + if (context.envName !== "gathered") {
8062 + validateAmsEnvironmentContext(context);
8063 + }
8064 + const res = {
8065 + cols: [],
8066 + envClasses: ["abut", "jot"],
8067 + autoTag: getAutoTag(context.envName),
8068 + emptySingleRow: true,
8069 + leqno: context.parser.settings.leqno
8070 + };
8071 + return parseArray(context.parser, res, "display");
8072 + },
8073 + mathmlBuilder: mathmlBuilder$7
8074 + });
8075 +
8076 + defineEnvironment({
8077 + type: "array",
8078 + names: ["equation", "equation*"],
8079 + props: {
8080 + numArgs: 0
8081 + },
8082 + handler(context) {
8083 + validateAmsEnvironmentContext(context);
8084 + const res = {
8085 + autoTag: getAutoTag(context.envName),
8086 + emptySingleRow: true,
8087 + singleRow: true,
8088 + maxNumCols: 1,
8089 + envClasses: ["align"],
8090 + leqno: context.parser.settings.leqno
8091 + };
8092 + return parseArray(context.parser, res, "display");
8093 + },
8094 + mathmlBuilder: mathmlBuilder$7
8095 + });
8096 +
8097 + defineEnvironment({
8098 + type: "array",
8099 + names: ["multline", "multline*"],
8100 + props: {
8101 + numArgs: 0
8102 + },
8103 + handler(context) {
8104 + validateAmsEnvironmentContext(context);
8105 + const res = {
8106 + autoTag: context.envName === "multline",
8107 + maxNumCols: 1,
8108 + envClasses: ["jot", "multline"],
8109 + leqno: context.parser.settings.leqno
8110 + };
8111 + return parseArray(context.parser, res, "display");
8112 + },
8113 + mathmlBuilder: mathmlBuilder$7
8114 + });
8115 +
8116 + defineEnvironment({
8117 + type: "array",
8118 + names: ["CD"],
8119 + props: {
8120 + numArgs: 0
8121 + },
8122 + handler(context) {
8123 + validateAmsEnvironmentContext(context);
8124 + return parseCD(context.parser);
8125 + },
8126 + mathmlBuilder: mathmlBuilder$7
8127 + });
8128 +
8129 + // Catch \hline outside array environment
8130 + defineFunction({
8131 + type: "text", // Doesn't matter what this is.
8132 + names: ["\\hline", "\\hdashline"],
8133 + props: {
8134 + numArgs: 0,
8135 + allowedInText: true,
8136 + allowedInMath: true
8137 + },
8138 + handler(context, args) {
8139 + throw new ParseError(`${context.funcName} valid only within array environment`);
8140 + }
8141 + });
8142 +
8143 + const environments = _environments;
8144 +
8145 + // Environment delimiters. HTML/MathML rendering is defined in the corresponding
8146 + // defineEnvironment definitions.
8147 + defineFunction({
8148 + type: "environment",
8149 + names: ["\\begin", "\\end"],
8150 + props: {
8151 + numArgs: 1,
8152 + argTypes: ["text"]
8153 + },
8154 + handler({ parser, funcName }, args) {
8155 + const nameGroup = args[0];
8156 + if (nameGroup.type !== "ordgroup") {
8157 + throw new ParseError("Invalid environment name", nameGroup);
8158 + }
8159 + let envName = "";
8160 + for (let i = 0; i < nameGroup.body.length; ++i) {
8161 + envName += assertNodeType(nameGroup.body[i], "textord").text;
8162 + }
8163 +
8164 + if (funcName === "\\begin") {
8165 + // begin...end is similar to left...right
8166 + if (!Object.prototype.hasOwnProperty.call(environments, envName )) {
8167 + throw new ParseError("No such environment: " + envName, nameGroup);
8168 + }
8169 + // Build the environment object. Arguments and other information will
8170 + // be made available to the begin and end methods using properties.
8171 + const env = environments[envName];
8172 + const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env);
8173 + const context = {
8174 + mode: parser.mode,
8175 + envName,
8176 + parser
8177 + };
8178 + const result = env.handler(context, args, optArgs);
8179 + parser.expect("\\end", false);
8180 + const endNameToken = parser.nextToken;
8181 + const end = assertNodeType(parser.parseFunction(), "environment");
8182 + if (end.name !== envName) {
8183 + throw new ParseError(
8184 + `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`,
8185 + endNameToken
8186 + );
8187 + }
8188 + return result;
8189 + }
8190 +
8191 + return {
8192 + type: "environment",
8193 + mode: parser.mode,
8194 + name: envName,
8195 + nameGroup
8196 + };
8197 + }
8198 + });
8199 +
8200 + defineFunction({
8201 + type: "envTag",
8202 + names: ["\\env@tag"],
8203 + props: {
8204 + numArgs: 1,
8205 + argTypes: ["math"]
8206 + },
8207 + handler({ parser }, args) {
8208 + return {
8209 + type: "envTag",
8210 + mode: parser.mode,
8211 + body: args[0]
8212 + };
8213 + },
8214 + mathmlBuilder(group, style) {
8215 + return new mathMLTree.MathNode("mrow");
8216 + }
8217 + });
8218 +
8219 + defineFunction({
8220 + type: "noTag",
8221 + names: ["\\env@notag"],
8222 + props: {
8223 + numArgs: 0
8224 + },
8225 + handler({ parser }) {
8226 + return {
8227 + type: "noTag",
8228 + mode: parser.mode
8229 + };
8230 + },
8231 + mathmlBuilder(group, style) {
8232 + return new mathMLTree.MathNode("mrow");
8233 + }
8234 + });
8235 +
8236 + const isLongVariableName = (group, font) => {
8237 + if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) {
8238 + return false
8239 + }
8240 + if (group.body.body[0].type !== "mathord") { return false }
8241 + for (let i = 1; i < group.body.body.length; i++) {
8242 + const parseNodeType = group.body.body[i].type;
8243 + if (!(parseNodeType === "mathord" ||
8244 + (parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) {
8245 + return false
8246 + }
8247 + }
8248 + return true
8249 + };
8250 +
8251 + const mathmlBuilder$6 = (group, style) => {
8252 + const font = group.font;
8253 + const newStyle = style.withFont(font);
8254 + const mathGroup = buildGroup$1(group.body, newStyle);
8255 +
8256 + if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
8257 + if (font === "boldsymbol" && ["mo", "mpadded", "mrow"].includes(mathGroup.type)) {
8258 + mathGroup.style.fontWeight = "bold";
8259 + return mathGroup
8260 + }
8261 + // Check if it is possible to consolidate elements into a single <mi> element.
8262 + if (isLongVariableName(group, font)) {
8263 + // This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js
8264 + // wraps <mi> elements with <mrow>s to work around a Firefox bug.
8265 + const mi = mathGroup.children[0].children[0];
8266 + delete mi.attributes.mathvariant;
8267 + for (let i = 1; i < mathGroup.children.length; i++) {
8268 + mi.children[0].text += mathGroup.children[i].type === "mn"
8269 + ? mathGroup.children[i].children[0].text
8270 + : mathGroup.children[i].children[0].children[0].text;
8271 + }
8272 + // Wrap in a <mrow> to prevent the same Firefox bug.
8273 + const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b"));
8274 + return new mathMLTree.MathNode("mrow", [bogus, mi])
8275 + }
8276 + let canConsolidate = mathGroup.children[0].type === "mo";
8277 + for (let i = 1; i < mathGroup.children.length; i++) {
8278 + if (mathGroup.children[i].type === "mo" && font === "boldsymbol") {
8279 + mathGroup.children[i].style.fontWeight = "bold";
8280 + }
8281 + if (mathGroup.children[i].type !== "mi") { canConsolidate = false; }
8282 + const localVariant = mathGroup.children[i].attributes &&
8283 + mathGroup.children[i].attributes.mathvariant || "";
8284 + if (localVariant !== "normal") { canConsolidate = false; }
8285 + }
8286 + if (!canConsolidate) { return mathGroup }
8287 + // Consolidate the <mi> elements.
8288 + const mi = mathGroup.children[0];
8289 + for (let i = 1; i < mathGroup.children.length; i++) {
8290 + mi.children.push(mathGroup.children[i].children[0]);
8291 + }
8292 + if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") {
8293 + // Workaround for a Firefox bug that renders spurious space around
8294 + // a <mi mathvariant="normal">
8295 + // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097
8296 + // We insert a text node that contains a zero-width space and wrap in an mrow.
8297 + // TODO: Get rid of this <mi> workaround when the Firefox bug is fixed.
8298 + const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b"));
8299 + return new mathMLTree.MathNode("mrow", [bogus, mi])
8300 + }
8301 + return mi
8302 + };
8303 +
8304 + const fontAliases = {
8305 + "\\Bbb": "\\mathbb",
8306 + "\\bold": "\\mathbf",
8307 + "\\frak": "\\mathfrak",
8308 + "\\bm": "\\boldsymbol"
8309 + };
8310 +
8311 + defineFunction({
8312 + type: "font",
8313 + names: [
8314 + // styles
8315 + "\\mathrm",
8316 + "\\mathit",
8317 + "\\mathbf",
8318 + "\\mathnormal",
8319 + "\\up@greek",
8320 + "\\boldsymbol",
8321 +
8322 + // families
8323 + "\\mathbb",
8324 + "\\mathcal",
8325 + "\\mathfrak",
8326 + "\\mathscr",
8327 + "\\mathsf",
8328 + "\\mathsfit",
8329 + "\\mathtt",
8330 +
8331 + // aliases
8332 + "\\Bbb",
8333 + "\\bm",
8334 + "\\bold",
8335 + "\\frak"
8336 + ],
8337 + props: {
8338 + numArgs: 1,
8339 + allowedInArgument: true
8340 + },
8341 + handler: ({ parser, funcName }, args) => {
8342 + const body = normalizeArgument(args[0]);
8343 + let func = funcName;
8344 + if (func in fontAliases) {
8345 + func = fontAliases[func];
8346 + }
8347 + return {
8348 + type: "font",
8349 + mode: parser.mode,
8350 + font: func.slice(1),
8351 + body
8352 + };
8353 + },
8354 + mathmlBuilder: mathmlBuilder$6
8355 + });
8356 +
8357 + // Old font changing functions
8358 + defineFunction({
8359 + type: "font",
8360 + names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
8361 + props: {
8362 + numArgs: 0,
8363 + allowedInText: true
8364 + },
8365 + handler: ({ parser, funcName, breakOnTokenText }, args) => {
8366 + const { mode } = parser;
8367 + const body = parser.parseExpression(true, breakOnTokenText, true);
8368 + const fontStyle = `math${funcName.slice(1)}`;
8369 +
8370 + return {
8371 + type: "font",
8372 + mode: mode,
8373 + font: fontStyle,
8374 + body: {
8375 + type: "ordgroup",
8376 + mode: parser.mode,
8377 + body
8378 + }
8379 + };
8380 + },
8381 + mathmlBuilder: mathmlBuilder$6
8382 + });
8383 +
8384 + const stylArray = ["display", "text", "script", "scriptscript"];
8385 + const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
8386 +
8387 + const mathmlBuilder$5 = (group, style) => {
8388 + // Track the scriptLevel of the numerator and denominator.
8389 + // We may need that info for \mathchoice or for adjusting em dimensions.
8390 + const childOptions = group.scriptLevel === "auto"
8391 + ? style.incrementLevel()
8392 + : group.scriptLevel === "display"
8393 + ? style.withLevel(StyleLevel.TEXT)
8394 + : group.scriptLevel === "text"
8395 + ? style.withLevel(StyleLevel.SCRIPT)
8396 + : style.withLevel(StyleLevel.SCRIPTSCRIPT);
8397 +
8398 + // Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
8399 + // So we check for levels that Chromium shrinks too small.
8400 + // If necessary, set an explicit fraction depth.
8401 + const numer = buildGroup$1(group.numer, childOptions);
8402 + const denom = buildGroup$1(group.denom, childOptions);
8403 + if (style.level === 3) {
8404 + numer.style.mathDepth = "2";
8405 + numer.setAttribute("scriptlevel", "2");
8406 + denom.style.mathDepth = "2";
8407 + denom.setAttribute("scriptlevel", "2");
8408 + }
8409 +
8410 + let node = new mathMLTree.MathNode("mfrac", [numer, denom]);
8411 +
8412 + if (!group.hasBarLine) {
8413 + node.setAttribute("linethickness", "0px");
8414 + } else if (group.barSize) {
8415 + const ruleWidth = calculateSize(group.barSize, style);
8416 + node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit);
8417 + }
8418 +
8419 + if (group.leftDelim != null || group.rightDelim != null) {
8420 + const withDelims = [];
8421 +
8422 + if (group.leftDelim != null) {
8423 + const leftOp = new mathMLTree.MathNode("mo", [
8424 + new mathMLTree.TextNode(group.leftDelim.replace("\\", ""))
8425 + ]);
8426 + leftOp.setAttribute("fence", "true");
8427 + withDelims.push(leftOp);
8428 + }
8429 +
8430 + withDelims.push(node);
8431 +
8432 + if (group.rightDelim != null) {
8433 + const rightOp = new mathMLTree.MathNode("mo", [
8434 + new mathMLTree.TextNode(group.rightDelim.replace("\\", ""))
8435 + ]);
8436 + rightOp.setAttribute("fence", "true");
8437 + withDelims.push(rightOp);
8438 + }
8439 +
8440 + node = makeRow(withDelims);
8441 + }
8442 +
8443 + if (group.scriptLevel !== "auto") {
8444 + node = new mathMLTree.MathNode("mstyle", [node]);
8445 + node.setAttribute("displaystyle", String(group.scriptLevel === "display"));
8446 + node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]);
8447 + }
8448 +
8449 + return node;
8450 + };
8451 +
8452 + defineFunction({
8453 + type: "genfrac",
8454 + names: [
8455 + "\\dfrac",
8456 + "\\frac",
8457 + "\\tfrac",
8458 + "\\dbinom",
8459 + "\\binom",
8460 + "\\tbinom",
8461 + "\\\\atopfrac", // can’t be entered directly
8462 + "\\\\bracefrac",
8463 + "\\\\brackfrac" // ditto
8464 + ],
8465 + props: {
8466 + numArgs: 2,
8467 + allowedInArgument: true
8468 + },
8469 + handler: ({ parser, funcName }, args) => {
8470 + const numer = args[0];
8471 + const denom = args[1];
8472 + let hasBarLine = false;
8473 + let leftDelim = null;
8474 + let rightDelim = null;
8475 + let scriptLevel = "auto";
8476 +
8477 + switch (funcName) {
8478 + case "\\dfrac":
8479 + case "\\frac":
8480 + case "\\tfrac":
8481 + hasBarLine = true;
8482 + break;
8483 + case "\\\\atopfrac":
8484 + hasBarLine = false;
8485 + break;
8486 + case "\\dbinom":
8487 + case "\\binom":
8488 + case "\\tbinom":
8489 + leftDelim = "(";
8490 + rightDelim = ")";
8491 + break;
8492 + case "\\\\bracefrac":
8493 + leftDelim = "\\{";
8494 + rightDelim = "\\}";
8495 + break;
8496 + case "\\\\brackfrac":
8497 + leftDelim = "[";
8498 + rightDelim = "]";
8499 + break;
8500 + default:
8501 + throw new Error("Unrecognized genfrac command");
8502 + }
8503 +
8504 + switch (funcName) {
8505 + case "\\dfrac":
8506 + case "\\dbinom":
8507 + scriptLevel = "display";
8508 + break;
8509 + case "\\tfrac":
8510 + case "\\tbinom":
8511 + scriptLevel = "text";
8512 + break;
8513 + }
8514 +
8515 + return {
8516 + type: "genfrac",
8517 + mode: parser.mode,
8518 + continued: false,
8519 + numer,
8520 + denom,
8521 + hasBarLine,
8522 + leftDelim,
8523 + rightDelim,
8524 + scriptLevel,
8525 + barSize: null
8526 + };
8527 + },
8528 + mathmlBuilder: mathmlBuilder$5
8529 + });
8530 +
8531 + defineFunction({
8532 + type: "genfrac",
8533 + names: ["\\cfrac"],
8534 + props: {
8535 + numArgs: 2
8536 + },
8537 + handler: ({ parser, funcName }, args) => {
8538 + const numer = args[0];
8539 + const denom = args[1];
8540 +
8541 + return {
8542 + type: "genfrac",
8543 + mode: parser.mode,
8544 + continued: true,
8545 + numer,
8546 + denom,
8547 + hasBarLine: true,
8548 + leftDelim: null,
8549 + rightDelim: null,
8550 + scriptLevel: "display",
8551 + barSize: null
8552 + };
8553 + }
8554 + });
8555 +
8556 + // Infix generalized fractions -- these are not rendered directly, but replaced
8557 + // immediately by one of the variants above.
8558 + defineFunction({
8559 + type: "infix",
8560 + names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"],
8561 + props: {
8562 + numArgs: 0,
8563 + infix: true
8564 + },
8565 + handler({ parser, funcName, token }) {
8566 + let replaceWith;
8567 + switch (funcName) {
8568 + case "\\over":
8569 + replaceWith = "\\frac";
8570 + break;
8571 + case "\\choose":
8572 + replaceWith = "\\binom";
8573 + break;
8574 + case "\\atop":
8575 + replaceWith = "\\\\atopfrac";
8576 + break;
8577 + case "\\brace":
8578 + replaceWith = "\\\\bracefrac";
8579 + break;
8580 + case "\\brack":
8581 + replaceWith = "\\\\brackfrac";
8582 + break;
8583 + default:
8584 + throw new Error("Unrecognized infix genfrac command");
8585 + }
8586 + return {
8587 + type: "infix",
8588 + mode: parser.mode,
8589 + replaceWith,
8590 + token
8591 + };
8592 + }
8593 + });
8594 +
8595 + const delimFromValue = function(delimString) {
8596 + let delim = null;
8597 + if (delimString.length > 0) {
8598 + delim = delimString;
8599 + delim = delim === "." ? null : delim;
8600 + }
8601 + return delim;
8602 + };
8603 +
8604 + defineFunction({
8605 + type: "genfrac",
8606 + names: ["\\genfrac"],
8607 + props: {
8608 + numArgs: 6,
8609 + allowedInArgument: true,
8610 + argTypes: ["math", "math", "size", "text", "math", "math"]
8611 + },
8612 + handler({ parser }, args) {
8613 + const numer = args[4];
8614 + const denom = args[5];
8615 +
8616 + // Look into the parse nodes to get the desired delimiters.
8617 + const leftNode = normalizeArgument(args[0]);
8618 + const leftDelim = leftNode.type === "atom" && leftNode.family === "open"
8619 + ? delimFromValue(leftNode.text)
8620 + : null;
8621 + const rightNode = normalizeArgument(args[1]);
8622 + const rightDelim =
8623 + rightNode.type === "atom" && rightNode.family === "close"
8624 + ? delimFromValue(rightNode.text)
8625 + : null;
8626 +
8627 + const barNode = assertNodeType(args[2], "size");
8628 + let hasBarLine;
8629 + let barSize = null;
8630 + if (barNode.isBlank) {
8631 + // \genfrac acts differently than \above.
8632 + // \genfrac treats an empty size group as a signal to use a
8633 + // standard bar size. \above would see size = 0 and omit the bar.
8634 + hasBarLine = true;
8635 + } else {
8636 + barSize = barNode.value;
8637 + hasBarLine = barSize.number > 0;
8638 + }
8639 +
8640 + // Find out if we want displaystyle, textstyle, etc.
8641 + let scriptLevel = "auto";
8642 + let styl = args[3];
8643 + if (styl.type === "ordgroup") {
8644 + if (styl.body.length > 0) {
8645 + const textOrd = assertNodeType(styl.body[0], "textord");
8646 + scriptLevel = stylArray[Number(textOrd.text)];
8647 + }
8648 + } else {
8649 + styl = assertNodeType(styl, "textord");
8650 + scriptLevel = stylArray[Number(styl.text)];
8651 + }
8652 +
8653 + return {
8654 + type: "genfrac",
8655 + mode: parser.mode,
8656 + numer,
8657 + denom,
8658 + continued: false,
8659 + hasBarLine,
8660 + barSize,
8661 + leftDelim,
8662 + rightDelim,
8663 + scriptLevel
8664 + };
8665 + },
8666 + mathmlBuilder: mathmlBuilder$5
8667 + });
8668 +
8669 + // \above is an infix fraction that also defines a fraction bar size.
8670 + defineFunction({
8671 + type: "infix",
8672 + names: ["\\above"],
8673 + props: {
8674 + numArgs: 1,
8675 + argTypes: ["size"],
8676 + infix: true
8677 + },
8678 + handler({ parser, funcName, token }, args) {
8679 + return {
8680 + type: "infix",
8681 + mode: parser.mode,
8682 + replaceWith: "\\\\abovefrac",
8683 + barSize: assertNodeType(args[0], "size").value,
8684 + token
8685 + };
8686 + }
8687 + });
8688 +
8689 + defineFunction({
8690 + type: "genfrac",
8691 + names: ["\\\\abovefrac"],
8692 + props: {
8693 + numArgs: 3,
8694 + argTypes: ["math", "size", "math"]
8695 + },
8696 + handler: ({ parser, funcName }, args) => {
8697 + const numer = args[0];
8698 + const barSize = assert(assertNodeType(args[1], "infix").barSize);
8699 + const denom = args[2];
8700 +
8701 + const hasBarLine = barSize.number > 0;
8702 + return {
8703 + type: "genfrac",
8704 + mode: parser.mode,
8705 + numer,
8706 + denom,
8707 + continued: false,
8708 + hasBarLine,
8709 + barSize,
8710 + leftDelim: null,
8711 + rightDelim: null,
8712 + scriptLevel: "auto"
8713 + };
8714 + },
8715 +
8716 + mathmlBuilder: mathmlBuilder$5
8717 + });
8718 +
8719 + // \hbox is provided for compatibility with LaTeX functions that act on a box.
8720 + // This function by itself doesn't do anything but set scriptlevel to \textstyle
8721 + // and prevent a soft line break.
8722 +
8723 + defineFunction({
8724 + type: "hbox",
8725 + names: ["\\hbox"],
8726 + props: {
8727 + numArgs: 1,
8728 + argTypes: ["hbox"],
8729 + allowedInArgument: true,
8730 + allowedInText: false
8731 + },
8732 + handler({ parser }, args) {
8733 + return {
8734 + type: "hbox",
8735 + mode: parser.mode,
8736 + body: ordargument(args[0])
8737 + };
8738 + },
8739 + mathmlBuilder(group, style) {
8740 + const newStyle = style.withLevel(StyleLevel.TEXT);
8741 + const mrow = buildExpressionRow(group.body, newStyle);
8742 + return consolidateText(mrow)
8743 + }
8744 + });
8745 +
8746 + const mathmlBuilder$4 = (group, style) => {
8747 + const accentNode = stretchy.mathMLnode(group.label);
8748 + accentNode.style["math-depth"] = 0;
8749 + return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [
8750 + buildGroup$1(group.base, style),
8751 + accentNode
8752 + ]);
8753 + };
8754 +
8755 + // Horizontal stretchy braces
8756 + defineFunction({
8757 + type: "horizBrace",
8758 + names: ["\\overbrace", "\\underbrace"],
8759 + props: {
8760 + numArgs: 1
8761 + },
8762 + handler({ parser, funcName }, args) {
8763 + return {
8764 + type: "horizBrace",
8765 + mode: parser.mode,
8766 + label: funcName,
8767 + isOver: /^\\over/.test(funcName),
8768 + base: args[0]
8769 + };
8770 + },
8771 + mathmlBuilder: mathmlBuilder$4
8772 + });
8773 +
8774 + defineFunction({
8775 + type: "href",
8776 + names: ["\\href"],
8777 + props: {
8778 + numArgs: 2,
8779 + argTypes: ["url", "original"],
8780 + allowedInText: true
8781 + },
8782 + handler: ({ parser, token }, args) => {
8783 + const body = args[1];
8784 + const href = assertNodeType(args[0], "url").url;
8785 +
8786 + if (
8787 + !parser.settings.isTrusted({
8788 + command: "\\href",
8789 + url: href
8790 + })
8791 + ) {
8792 + throw new ParseError(`Function "\\href" is not trusted`, token)
8793 + }
8794 +
8795 + return {
8796 + type: "href",
8797 + mode: parser.mode,
8798 + href,
8799 + body: ordargument(body)
8800 + };
8801 + },
8802 + mathmlBuilder: (group, style) => {
8803 + const math = new MathNode("math", [buildExpressionRow(group.body, style)]);
8804 + const anchorNode = new AnchorNode(group.href, [], [math]);
8805 + return anchorNode
8806 + }
8807 + });
8808 +
8809 + defineFunction({
8810 + type: "href",
8811 + names: ["\\url"],
8812 + props: {
8813 + numArgs: 1,
8814 + argTypes: ["url"],
8815 + allowedInText: true
8816 + },
8817 + handler: ({ parser, token }, args) => {
8818 + const href = assertNodeType(args[0], "url").url;
8819 +
8820 + if (
8821 + !parser.settings.isTrusted({
8822 + command: "\\url",
8823 + url: href
8824 + })
8825 + ) {
8826 + throw new ParseError(`Function "\\url" is not trusted`, token)
8827 + }
8828 +
8829 + const chars = [];
8830 + for (let i = 0; i < href.length; i++) {
8831 + let c = href[i];
8832 + if (c === "~") {
8833 + c = "\\textasciitilde";
8834 + }
8835 + chars.push({
8836 + type: "textord",
8837 + mode: "text",
8838 + text: c
8839 + });
8840 + }
8841 + const body = {
8842 + type: "text",
8843 + mode: parser.mode,
8844 + font: "\\texttt",
8845 + body: chars
8846 + };
8847 + return {
8848 + type: "href",
8849 + mode: parser.mode,
8850 + href,
8851 + body: ordargument(body)
8852 + };
8853 + }
8854 + });
8855 +
8856 + defineFunction({
8857 + type: "html",
8858 + names: ["\\class", "\\id", "\\style", "\\data"],
8859 + props: {
8860 + numArgs: 2,
8861 + argTypes: ["raw", "original"],
8862 + allowedInText: true
8863 + },
8864 + handler: ({ parser, funcName, token }, args) => {
8865 + const value = assertNodeType(args[0], "raw").string;
8866 + const body = args[1];
8867 +
8868 + if (parser.settings.strict) {
8869 + throw new ParseError(`Function "${funcName}" is disabled in strict mode`, token)
8870 + }
8871 +
8872 + let trustContext;
8873 + const attributes = {};
8874 +
8875 + switch (funcName) {
8876 + case "\\class":
8877 + attributes.class = value;
8878 + trustContext = {
8879 + command: "\\class",
8880 + class: value
8881 + };
8882 + break;
8883 + case "\\id":
8884 + attributes.id = value;
8885 + trustContext = {
8886 + command: "\\id",
8887 + id: value
8888 + };
8889 + break;
8890 + case "\\style":
8891 + attributes.style = value;
8892 + trustContext = {
8893 + command: "\\style",
8894 + style: value
8895 + };
8896 + break;
8897 + case "\\data": {
8898 + const data = value.split(",");
8899 + for (let i = 0; i < data.length; i++) {
8900 + const keyVal = data[i].split("=");
8901 + if (keyVal.length !== 2) {
8902 + throw new ParseError("Error parsing key-value for \\data");
8903 + }
8904 + attributes["data-" + keyVal[0].trim()] = keyVal[1].trim();
8905 + }
8906 +
8907 + trustContext = {
8908 + command: "\\data",
8909 + attributes
8910 + };
8911 + break;
8912 + }
8913 + default:
8914 + throw new Error("Unrecognized html command");
8915 + }
8916 +
8917 + if (!parser.settings.isTrusted(trustContext)) {
8918 + throw new ParseError(`Function "${funcName}" is not trusted`, token)
8919 + }
8920 + return {
8921 + type: "html",
8922 + mode: parser.mode,
8923 + attributes,
8924 + body: ordargument(body)
8925 + };
8926 + },
8927 + mathmlBuilder: (group, style) => {
8928 + const element = buildExpressionRow(group.body, style);
8929 +
8930 + const classes = [];
8931 + if (group.attributes.class) {
8932 + classes.push(...group.attributes.class.trim().split(/\s+/));
8933 + }
8934 + element.classes = classes;
8935 +
8936 + for (const attr in group.attributes) {
8937 + if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) {
8938 + element.setAttribute(attr, group.attributes[attr]);
8939 + }
8940 + }
8941 +
8942 + return element;
8943 + }
8944 + });
8945 +
8946 + const sizeData = function(str) {
8947 + if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) {
8948 + // str is a number with no unit specified.
8949 + // default unit is bp, per graphix package.
8950 + return { number: +str, unit: "bp" }
8951 + } else {
8952 + const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str);
8953 + if (!match) {
8954 + throw new ParseError("Invalid size: '" + str + "' in \\includegraphics");
8955 + }
8956 + const data = {
8957 + number: +(match[1] + match[2]), // sign + magnitude, cast to number
8958 + unit: match[3]
8959 + };
8960 + if (!validUnit(data)) {
8961 + throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics.");
8962 + }
8963 + return data
8964 + }
8965 + };
8966 +
8967 + defineFunction({
8968 + type: "includegraphics",
8969 + names: ["\\includegraphics"],
8970 + props: {
8971 + numArgs: 1,
8972 + numOptionalArgs: 1,
8973 + argTypes: ["raw", "url"],
8974 + allowedInText: false
8975 + },
8976 + handler: ({ parser, token }, args, optArgs) => {
8977 + let width = { number: 0, unit: "em" };
8978 + let height = { number: 0.9, unit: "em" }; // sorta character sized.
8979 + let totalheight = { number: 0, unit: "em" };
8980 + let alt = "";
8981 +
8982 + if (optArgs[0]) {
8983 + const attributeStr = assertNodeType(optArgs[0], "raw").string;
8984 +
8985 + // Parser.js does not parse key/value pairs. We get a string.
8986 + const attributes = attributeStr.split(",");
8987 + for (let i = 0; i < attributes.length; i++) {
8988 + const keyVal = attributes[i].split("=");
8989 + if (keyVal.length === 2) {
8990 + const str = keyVal[1].trim();
8991 + switch (keyVal[0].trim()) {
8992 + case "alt":
8993 + alt = str;
8994 + break
8995 + case "width":
8996 + width = sizeData(str);
8997 + break
8998 + case "height":
8999 + height = sizeData(str);
9000 + break
9001 + case "totalheight":
9002 + totalheight = sizeData(str);
9003 + break
9004 + default:
9005 + throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.")
9006 + }
9007 + }
9008 + }
9009 + }
9010 +
9011 + const src = assertNodeType(args[0], "url").url;
9012 +
9013 + if (alt === "") {
9014 + // No alt given. Use the file name. Strip away the path.
9015 + alt = src;
9016 + alt = alt.replace(/^.*[\\/]/, "");
9017 + alt = alt.substring(0, alt.lastIndexOf("."));
9018 + }
9019 +
9020 + if (
9021 + !parser.settings.isTrusted({
9022 + command: "\\includegraphics",
9023 + url: src
9024 + })
9025 + ) {
9026 + throw new ParseError(`Function "\\includegraphics" is not trusted`, token)
9027 + }
9028 +
9029 + return {
9030 + type: "includegraphics",
9031 + mode: parser.mode,
9032 + alt: alt,
9033 + width: width,
9034 + height: height,
9035 + totalheight: totalheight,
9036 + src: src
9037 + }
9038 + },
9039 + mathmlBuilder: (group, style) => {
9040 + const height = calculateSize(group.height, style);
9041 + const depth = { number: 0, unit: "em" };
9042 +
9043 + if (group.totalheight.number > 0) {
9044 + if (group.totalheight.unit === height.unit &&
9045 + group.totalheight.number > height.number) {
9046 + depth.number = group.totalheight.number - height.number;
9047 + depth.unit = height.unit;
9048 + }
9049 + }
9050 +
9051 + let width = 0;
9052 + if (group.width.number > 0) {
9053 + width = calculateSize(group.width, style);
9054 + }
9055 +
9056 + const graphicStyle = { height: height.number + depth.number + "em" };
9057 + if (width.number > 0) {
9058 + graphicStyle.width = width.number + width.unit;
9059 + }
9060 + if (depth.number > 0) {
9061 + graphicStyle.verticalAlign = -depth.number + depth.unit;
9062 + }
9063 +
9064 + const node = new Img(group.src, group.alt, graphicStyle);
9065 + node.height = height;
9066 + node.depth = depth;
9067 + return new mathMLTree.MathNode("mtext", [node])
9068 + }
9069 + });
9070 +
9071 + // Horizontal spacing commands
9072 +
9073 +
9074 + // TODO: \hskip and \mskip should support plus and minus in lengths
9075 +
9076 + defineFunction({
9077 + type: "kern",
9078 + names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"],
9079 + props: {
9080 + numArgs: 1,
9081 + argTypes: ["size"],
9082 + primitive: true,
9083 + allowedInText: true
9084 + },
9085 + handler({ parser, funcName, token }, args) {
9086 + const size = assertNodeType(args[0], "size");
9087 + if (parser.settings.strict) {
9088 + const mathFunction = funcName[1] === "m"; // \mkern, \mskip
9089 + const muUnit = size.value.unit === "mu";
9090 + if (mathFunction) {
9091 + if (!muUnit) {
9092 + throw new ParseError(`LaTeX's ${funcName} supports only mu units, ` +
9093 + `not ${size.value.unit} units`, token)
9094 + }
9095 + if (parser.mode !== "math") {
9096 + throw new ParseError(`LaTeX's ${funcName} works only in math mode`, token)
9097 + }
9098 + } else {
9099 + // !mathFunction
9100 + if (muUnit) {
9101 + throw new ParseError(`LaTeX's ${funcName} doesn't support mu units`, token)
9102 + }
9103 + }
9104 + }
9105 + return {
9106 + type: "kern",
9107 + mode: parser.mode,
9108 + dimension: size.value
9109 + };
9110 + },
9111 + mathmlBuilder(group, style) {
9112 + const dimension = calculateSize(group.dimension, style);
9113 + const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : "";
9114 + if (group.mode === "text" && ch.length > 0) {
9115 + const character = new mathMLTree.TextNode(ch);
9116 + return new mathMLTree.MathNode("mtext", [character]);
9117 + } else {
9118 + const node = new mathMLTree.MathNode("mspace");
9119 + node.setAttribute("width", dimension.number + dimension.unit);
9120 + if (dimension.number < 0) {
9121 + node.style.marginLeft = dimension.number + dimension.unit;
9122 + }
9123 + return node;
9124 + }
9125 + }
9126 + });
9127 +
9128 + const spaceCharacter = function(width) {
9129 + if (width >= 0.05555 && width <= 0.05556) {
9130 + return "\u200a"; // &VeryThinSpace;
9131 + } else if (width >= 0.1666 && width <= 0.1667) {
9132 + return "\u2009"; // &ThinSpace;
9133 + } else if (width >= 0.2222 && width <= 0.2223) {
9134 + return "\u2005"; // &MediumSpace;
9135 + } else if (width >= 0.2777 && width <= 0.2778) {
9136 + return "\u2005\u200a"; // &ThickSpace;
9137 + } else {
9138 + return "";
9139 + }
9140 + };
9141 +
9142 + // Limit valid characters to a small set, for safety.
9143 + const invalidIdRegEx = /[^A-Za-z_0-9-]/g;
9144 +
9145 + defineFunction({
9146 + type: "label",
9147 + names: ["\\label"],
9148 + props: {
9149 + numArgs: 1,
9150 + argTypes: ["raw"]
9151 + },
9152 + handler({ parser }, args) {
9153 + return {
9154 + type: "label",
9155 + mode: parser.mode,
9156 + string: args[0].string.replace(invalidIdRegEx, "")
9157 + };
9158 + },
9159 + mathmlBuilder(group, style) {
9160 + // Return a no-width, no-ink element with an HTML id.
9161 + const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]);
9162 + if (group.string.length > 0) {
9163 + node.setLabel(group.string);
9164 + }
9165 + return node
9166 + }
9167 + });
9168 +
9169 + // Horizontal overlap functions
9170 +
9171 + const textModeLap = ["\\clap", "\\llap", "\\rlap"];
9172 +
9173 + defineFunction({
9174 + type: "lap",
9175 + names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"],
9176 + props: {
9177 + numArgs: 1,
9178 + allowedInText: true
9179 + },
9180 + handler: ({ parser, funcName, token }, args) => {
9181 + if (textModeLap.includes(funcName)) {
9182 + if (parser.settings.strict && parser.mode !== "text") {
9183 + throw new ParseError(`{${funcName}} can be used only in text mode.
9184 + Try \\math${funcName.slice(1)}`, token)
9185 + }
9186 + funcName = funcName.slice(1);
9187 + } else {
9188 + funcName = funcName.slice(5);
9189 + }
9190 + const body = args[0];
9191 + return {
9192 + type: "lap",
9193 + mode: parser.mode,
9194 + alignment: funcName,
9195 + body
9196 + }
9197 + },
9198 + mathmlBuilder: (group, style) => {
9199 + // mathllap, mathrlap, mathclap
9200 + let strut;
9201 + if (group.alignment === "llap") {
9202 + // We need an invisible strut with the same depth as the group.
9203 + // We can't just read the depth, so we use \vphantom methods.
9204 + const phantomInner = buildExpression(ordargument(group.body), style);
9205 + const phantom = new mathMLTree.MathNode("mphantom", phantomInner);
9206 + strut = new mathMLTree.MathNode("mpadded", [phantom]);
9207 + strut.setAttribute("width", "0px");
9208 + }
9209 +
9210 + const inner = buildGroup$1(group.body, style);
9211 + let node;
9212 + if (group.alignment === "llap") {
9213 + inner.style.position = "absolute";
9214 + inner.style.right = "0";
9215 + inner.style.bottom = `0`; // If we could have read the ink depth, it would go here.
9216 + node = new mathMLTree.MathNode("mpadded", [strut, inner]);
9217 + } else {
9218 + node = new mathMLTree.MathNode("mpadded", [inner]);
9219 + }
9220 +
9221 + if (group.alignment === "rlap") {
9222 + if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") {
9223 + // In Firefox, a <mpadded> squashes the 3/18em padding of a child \frac. Put it back.
9224 + node.setAttribute("lspace", "0.16667em");
9225 + }
9226 + } else {
9227 + const offset = group.alignment === "llap" ? "-1" : "-0.5";
9228 + node.setAttribute("lspace", offset + "width");
9229 + if (group.alignment === "llap") {
9230 + node.style.position = "relative";
9231 + } else {
9232 + node.style.display = "flex";
9233 + node.style.justifyContent = "center";
9234 + }
9235 + }
9236 + node.setAttribute("width", "0px");
9237 + return node
9238 + }
9239 + });
9240 +
9241 + // Switching from text mode back to math mode
9242 + defineFunction({
9243 + type: "ordgroup",
9244 + names: ["\\(", "$"],
9245 + props: {
9246 + numArgs: 0,
9247 + allowedInText: true,
9248 + allowedInMath: false
9249 + },
9250 + handler({ funcName, parser }, args) {
9251 + const outerMode = parser.mode;
9252 + parser.switchMode("math");
9253 + const close = funcName === "\\(" ? "\\)" : "$";
9254 + const body = parser.parseExpression(false, close);
9255 + parser.expect(close);
9256 + parser.switchMode(outerMode);
9257 + return {
9258 + type: "ordgroup",
9259 + mode: parser.mode,
9260 + body
9261 + };
9262 + }
9263 + });
9264 +
9265 + // Check for extra closing math delimiters
9266 + defineFunction({
9267 + type: "text", // Doesn't matter what this is.
9268 + names: ["\\)", "\\]"],
9269 + props: {
9270 + numArgs: 0,
9271 + allowedInText: true,
9272 + allowedInMath: false
9273 + },
9274 + handler(context, token) {
9275 + throw new ParseError(`Mismatched ${context.funcName}`, token);
9276 + }
9277 + });
9278 +
9279 + const chooseStyle = (group, style) => {
9280 + switch (style.level) {
9281 + case StyleLevel.DISPLAY: // 0
9282 + return group.display;
9283 + case StyleLevel.TEXT: // 1
9284 + return group.text;
9285 + case StyleLevel.SCRIPT: // 2
9286 + return group.script;
9287 + case StyleLevel.SCRIPTSCRIPT: // 3
9288 + return group.scriptscript;
9289 + default:
9290 + return group.text;
9291 + }
9292 + };
9293 +
9294 + defineFunction({
9295 + type: "mathchoice",
9296 + names: ["\\mathchoice"],
9297 + props: {
9298 + numArgs: 4,
9299 + primitive: true
9300 + },
9301 + handler: ({ parser }, args) => {
9302 + return {
9303 + type: "mathchoice",
9304 + mode: parser.mode,
9305 + display: ordargument(args[0]),
9306 + text: ordargument(args[1]),
9307 + script: ordargument(args[2]),
9308 + scriptscript: ordargument(args[3])
9309 + };
9310 + },
9311 + mathmlBuilder: (group, style) => {
9312 + const body = chooseStyle(group, style);
9313 + return buildExpressionRow(body, style);
9314 + }
9315 + });
9316 +
9317 + const textAtomTypes = ["text", "textord", "mathord", "atom"];
9318 +
9319 + const padding = width => {
9320 + const node = new mathMLTree.MathNode("mspace");
9321 + node.setAttribute("width", width + "em");
9322 + return node
9323 + };
9324 +
9325 + function mathmlBuilder$3(group, style) {
9326 + let node;
9327 + const inner = buildExpression(group.body, style);
9328 +
9329 + if (group.mclass === "minner") {
9330 + node = new mathMLTree.MathNode("mpadded", inner);
9331 + } else if (group.mclass === "mord") {
9332 + if (group.isCharacterBox || inner[0].type === "mathord") {
9333 + node = inner[0];
9334 + node.type = "mi";
9335 + if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") {
9336 + node.setAttribute("mathvariant", "normal");
9337 + }
9338 + } else {
9339 + node = new mathMLTree.MathNode("mi", inner);
9340 + }
9341 + } else {
9342 + node = new mathMLTree.MathNode("mrow", inner);
9343 + if (group.mustPromote) {
9344 + node = inner[0];
9345 + node.type = "mo";
9346 + if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) {
9347 + node.setAttribute("mathvariant", "italic");
9348 + }
9349 + } else {
9350 + node = new mathMLTree.MathNode("mrow", inner);
9351 + }
9352 +
9353 + // Set spacing based on what is the most likely adjacent atom type.
9354 + // See TeXbook p170.
9355 + const doSpacing = style.level < 2; // Operator spacing is zero inside a (sub|super)script.
9356 + if (node.type === "mrow") {
9357 + if (doSpacing ) {
9358 + if (group.mclass === "mbin") {
9359 + // medium space
9360 + node.children.unshift(padding(0.2222));
9361 + node.children.push(padding(0.2222));
9362 + } else if (group.mclass === "mrel") {
9363 + // thickspace
9364 + node.children.unshift(padding(0.2778));
9365 + node.children.push(padding(0.2778));
9366 + } else if (group.mclass === "mpunct") {
9367 + node.children.push(padding(0.1667));
9368 + } else if (group.mclass === "minner") {
9369 + node.children.unshift(padding(0.0556)); // 1 mu is the most likely option
9370 + node.children.push(padding(0.0556));
9371 + }
9372 + }
9373 + } else {
9374 + if (group.mclass === "mbin") {
9375 + // medium space
9376 + node.attributes.lspace = (doSpacing ? "0.2222em" : "0");
9377 + node.attributes.rspace = (doSpacing ? "0.2222em" : "0");
9378 + } else if (group.mclass === "mrel") {
9379 + // thickspace
9380 + node.attributes.lspace = (doSpacing ? "0.2778em" : "0");
9381 + node.attributes.rspace = (doSpacing ? "0.2778em" : "0");
9382 + } else if (group.mclass === "mpunct") {
9383 + node.attributes.lspace = "0em";
9384 + node.attributes.rspace = (doSpacing ? "0.1667em" : "0");
9385 + } else if (group.mclass === "mopen" || group.mclass === "mclose") {
9386 + node.attributes.lspace = "0em";
9387 + node.attributes.rspace = "0em";
9388 + } else if (group.mclass === "minner" && doSpacing) {
9389 + node.attributes.lspace = "0.0556em"; // 1 mu is the most likely option
9390 + node.attributes.width = "+0.1111em";
9391 + }
9392 + }
9393 +
9394 + if (!(group.mclass === "mopen" || group.mclass === "mclose")) {
9395 + delete node.attributes.stretchy;
9396 + delete node.attributes.form;
9397 + }
9398 + }
9399 + return node;
9400 + }
9401 +
9402 + // Math class commands except \mathop
9403 + defineFunction({
9404 + type: "mclass",
9405 + names: [
9406 + "\\mathord",
9407 + "\\mathbin",
9408 + "\\mathrel",
9409 + "\\mathopen",
9410 + "\\mathclose",
9411 + "\\mathpunct",
9412 + "\\mathinner"
9413 + ],
9414 + props: {
9415 + numArgs: 1,
9416 + primitive: true
9417 + },
9418 + handler({ parser, funcName }, args) {
9419 + const body = args[0];
9420 + const isCharacterBox = utils.isCharacterBox(body);
9421 + // We should not wrap a <mo> around a <mi> or <mord>. That would be invalid MathML.
9422 + // In that case, we instead promote the text contents of the body to the parent.
9423 + let mustPromote = true;
9424 + const mord = { type: "mathord", text: "", mode: parser.mode };
9425 + const arr = (body.body) ? body.body : [body];
9426 + for (const arg of arr) {
9427 + if (textAtomTypes.includes(arg.type)) {
9428 + if (symbols[parser.mode][arg.text]) {
9429 + mord.text += symbols[parser.mode][arg.text].replace;
9430 + } else if (arg.text) {
9431 + mord.text += arg.text;
9432 + } else if (arg.body) {
9433 + arg.body.map(e => { mord.text += e.text; });
9434 + }
9435 + } else {
9436 + mustPromote = false;
9437 + break
9438 + }
9439 + }
9440 + return {
9441 + type: "mclass",
9442 + mode: parser.mode,
9443 + mclass: "m" + funcName.slice(5),
9444 + body: ordargument(mustPromote ? mord : body),
9445 + isCharacterBox,
9446 + mustPromote
9447 + };
9448 + },
9449 + mathmlBuilder: mathmlBuilder$3
9450 + });
9451 +
9452 + const binrelClass = (arg) => {
9453 + // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument.
9454 + // (by rendering separately and with {}s before and after, and measuring
9455 + // the change in spacing). We'll do roughly the same by detecting the
9456 + // atom type directly.
9457 + const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg;
9458 + if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) {
9459 + return "m" + atom.family;
9460 + } else {
9461 + return "mord";
9462 + }
9463 + };
9464 +
9465 + // \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord.
9466 + // This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX.
9467 + defineFunction({
9468 + type: "mclass",
9469 + names: ["\\@binrel"],
9470 + props: {
9471 + numArgs: 2
9472 + },
9473 + handler({ parser }, args) {
9474 + return {
9475 + type: "mclass",
9476 + mode: parser.mode,
9477 + mclass: binrelClass(args[0]),
9478 + body: ordargument(args[1]),
9479 + isCharacterBox: utils.isCharacterBox(args[1])
9480 + };
9481 + }
9482 + });
9483 +
9484 + // Build a relation or stacked op by placing one symbol on top of another
9485 + defineFunction({
9486 + type: "mclass",
9487 + names: ["\\stackrel", "\\overset", "\\underset"],
9488 + props: {
9489 + numArgs: 2
9490 + },
9491 + handler({ parser, funcName }, args) {
9492 + const baseArg = args[1];
9493 + const shiftedArg = args[0];
9494 +
9495 + const baseOp = {
9496 + type: "op",
9497 + mode: baseArg.mode,
9498 + limits: true,
9499 + alwaysHandleSupSub: true,
9500 + parentIsSupSub: false,
9501 + symbol: false,
9502 + stack: true,
9503 + suppressBaseShift: funcName !== "\\stackrel",
9504 + body: ordargument(baseArg)
9505 + };
9506 +
9507 + return {
9508 + type: "supsub",
9509 + mode: shiftedArg.mode,
9510 + base: baseOp,
9511 + sup: funcName === "\\underset" ? null : shiftedArg,
9512 + sub: funcName === "\\underset" ? shiftedArg : null
9513 + };
9514 + },
9515 + mathmlBuilder: mathmlBuilder$3
9516 + });
9517 +
9518 + // Helper function
9519 + const buildGroup = (el, style, noneNode) => {
9520 + if (!el) { return noneNode }
9521 + const node = buildGroup$1(el, style);
9522 + if (node.type === "mrow" && node.children.length === 0) { return noneNode }
9523 + return node
9524 + };
9525 +
9526 + defineFunction({
9527 + type: "multiscript",
9528 + names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript
9529 + props: {
9530 + numArgs: 3
9531 + },
9532 + handler({ parser, funcName, token }, args) {
9533 + if (args[2].body.length === 0) {
9534 + throw new ParseError(funcName + `cannot parse an empty base.`)
9535 + }
9536 + const base = args[2].body[0];
9537 + if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) {
9538 + throw new ParseError(`The base of \\sideset must be a big operator. Try \\prescript.`)
9539 + }
9540 +
9541 + if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") ||
9542 + (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) {
9543 + throw new ParseError("\\sideset can parse only subscripts and " +
9544 + "superscripts in its first two arguments", token)
9545 + }
9546 +
9547 + // The prescripts and postscripts come wrapped in a supsub.
9548 + const prescripts = args[0].body.length > 0 ? args[0].body[0] : null;
9549 + const postscripts = args[1].body.length > 0 ? args[1].body[0] : null;
9550 +
9551 + if (!prescripts && !postscripts) {
9552 + return base
9553 + } else if (!prescripts) {
9554 + // It's not a multi-script. Get a \textstyle supsub.
9555 + return {
9556 + type: "styling",
9557 + mode: parser.mode,
9558 + scriptLevel: "text",
9559 + body: [{
9560 + type: "supsub",
9561 + mode: parser.mode,
9562 + base,
9563 + sup: postscripts.sup,
9564 + sub: postscripts.sub
9565 + }]
9566 + }
9567 + } else {
9568 + return {
9569 + type: "multiscript",
9570 + mode: parser.mode,
9571 + isSideset: funcName === "\\sideset",
9572 + prescripts,
9573 + postscripts,
9574 + base
9575 + }
9576 + }
9577 + },
9578 + mathmlBuilder(group, style) {
9579 + const base = buildGroup$1(group.base, style);
9580 +
9581 + const prescriptsNode = new mathMLTree.MathNode("mprescripts");
9582 + const noneNode = new mathMLTree.MathNode("none");
9583 + let children = [];
9584 +
9585 + const preSub = buildGroup(group.prescripts.sub, style, noneNode);
9586 + const preSup = buildGroup(group.prescripts.sup, style, noneNode);
9587 + if (group.isSideset) {
9588 + // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad.
9589 + preSub.setAttribute("style", "text-align: left;");
9590 + preSup.setAttribute("style", "text-align: left;");
9591 + }
9592 +
9593 + if (group.postscripts) {
9594 + const postSub = buildGroup(group.postscripts.sub, style, noneNode);
9595 + const postSup = buildGroup(group.postscripts.sup, style, noneNode);
9596 + children = [base, postSub, postSup, prescriptsNode, preSub, preSup];
9597 + } else {
9598 + children = [base, prescriptsNode, preSub, preSup];
9599 + }
9600 +
9601 + return new mathMLTree.MathNode("mmultiscripts", children);
9602 + }
9603 + });
9604 +
9605 + defineFunction({
9606 + type: "not",
9607 + names: ["\\not"],
9608 + props: {
9609 + numArgs: 1,
9610 + primitive: true,
9611 + allowedInText: false
9612 + },
9613 + handler({ parser }, args) {
9614 + const isCharacterBox = utils.isCharacterBox(args[0]);
9615 + let body;
9616 + if (isCharacterBox) {
9617 + body = ordargument(args[0]);
9618 + if (body[0].text.charAt(0) === "\\") {
9619 + body[0].text = symbols.math[body[0].text].replace;
9620 + }
9621 + // \u0338 is the Unicode Combining Long Solidus Overlay
9622 + body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1);
9623 + } else {
9624 + // When the argument is not a character box, TeX does an awkward, poorly placed overlay.
9625 + // We'll do the same.
9626 + const notNode = { type: "textord", mode: "math", text: "\u0338" };
9627 + const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } };
9628 + body = [notNode, kernNode, args[0]];
9629 + }
9630 + return {
9631 + type: "not",
9632 + mode: parser.mode,
9633 + body,
9634 + isCharacterBox
9635 + };
9636 + },
9637 + mathmlBuilder(group, style) {
9638 + if (group.isCharacterBox) {
9639 + const inner = buildExpression(group.body, style, true);
9640 + return inner[0]
9641 + } else {
9642 + return buildExpressionRow(group.body, style)
9643 + }
9644 + }
9645 + });
9646 +
9647 + // Limits, symbols
9648 +
9649 + // Some helpers
9650 +
9651 + const ordAtomTypes = ["textord", "mathord", "atom"];
9652 +
9653 + // Most operators have a large successor symbol, but these don't.
9654 + const noSuccessor = ["\\smallint"];
9655 +
9656 + // Math operators (e.g. \sin) need a space between these types and themselves:
9657 + const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright", "font"];
9658 +
9659 + // NOTE: Unlike most `builders`s, this one handles not only "op", but also
9660 + // "supsub" since some of them (like \int) can affect super/subscripting.
9661 +
9662 + const setSpacing = node => {
9663 + // The user wrote a \mathop{…} function. Change spacing from default to OP spacing.
9664 + // The most likely spacing for an OP is a thin space per TeXbook p170.
9665 + node.attributes.lspace = "0.1667em";
9666 + node.attributes.rspace = "0.1667em";
9667 + };
9668 +
9669 + const mathmlBuilder$2 = (group, style) => {
9670 + let node;
9671 +
9672 + if (group.symbol) {
9673 + // This is a symbol. Just add the symbol.
9674 + node = new MathNode("mo", [makeText(group.name, group.mode)]);
9675 + if (noSuccessor.includes(group.name)) {
9676 + node.setAttribute("largeop", "false");
9677 + } else {
9678 + node.setAttribute("movablelimits", "false");
9679 + }
9680 + if (group.fromMathOp) { setSpacing(node); }
9681 + } else if (group.body) {
9682 + // This is an operator with children. Add them.
9683 + node = new MathNode("mo", buildExpression(group.body, style));
9684 + if (group.fromMathOp) { setSpacing(node); }
9685 + } else {
9686 + // This is a text operator. Add all of the characters from the operator's name.
9687 + node = new MathNode("mi", [new TextNode(group.name.slice(1))]);
9688 +
9689 + if (!group.parentIsSupSub) {
9690 + // Append an invisible <mo>&ApplyFunction;</mo>.
9691 + // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
9692 + const operator = new MathNode("mo", [makeText("\u2061", "text")]);
9693 + const row = [node, operator];
9694 + // Set spacing
9695 + if (group.needsLeadingSpace) {
9696 + const lead = new MathNode("mspace");
9697 + lead.setAttribute("width", "0.1667em"); // thin space.
9698 + row.unshift(lead);
9699 + }
9700 + if (!group.isFollowedByDelimiter) {
9701 + const trail = new MathNode("mspace");
9702 + trail.setAttribute("width", "0.1667em"); // thin space.
9703 + row.push(trail);
9704 + }
9705 + node = new MathNode("mrow", row);
9706 + }
9707 + }
9708 +
9709 + return node;
9710 + };
9711 +
9712 + const singleCharBigOps = {
9713 + "\u220F": "\\prod",
9714 + "\u2210": "\\coprod",
9715 + "\u2211": "\\sum",
9716 + "\u22c0": "\\bigwedge",
9717 + "\u22c1": "\\bigvee",
9718 + "\u22c2": "\\bigcap",
9719 + "\u22c3": "\\bigcup",
9720 + "\u2a00": "\\bigodot",
9721 + "\u2a01": "\\bigoplus",
9722 + "\u2a02": "\\bigotimes",
9723 + "\u2a04": "\\biguplus",
9724 + "\u2a05": "\\bigsqcap",
9725 + "\u2a06": "\\bigsqcup",
9726 + "\u2a03": "\\bigcupdot",
9727 + "\u2a07": "\\bigdoublevee",
9728 + "\u2a08": "\\bigdoublewedge",
9729 + "\u2a09": "\\bigtimes"
9730 + };
9731 +
9732 + defineFunction({
9733 + type: "op",
9734 + names: [
9735 + "\\coprod",
9736 + "\\bigvee",
9737 + "\\bigwedge",
9738 + "\\biguplus",
9739 + "\\bigcupplus",
9740 + "\\bigcupdot",
9741 + "\\bigcap",
9742 + "\\bigcup",
9743 + "\\bigdoublevee",
9744 + "\\bigdoublewedge",
9745 + "\\intop",
9746 + "\\prod",
9747 + "\\sum",
9748 + "\\bigotimes",
9749 + "\\bigoplus",
9750 + "\\bigodot",
9751 + "\\bigsqcap",
9752 + "\\bigsqcup",
9753 + "\\bigtimes",
9754 + "\\smallint",
9755 + "\u220F",
9756 + "\u2210",
9757 + "\u2211",
9758 + "\u22c0",
9759 + "\u22c1",
9760 + "\u22c2",
9761 + "\u22c3",
9762 + "\u2a00",
9763 + "\u2a01",
9764 + "\u2a02",
9765 + "\u2a04",
9766 + "\u2a06"
9767 + ],
9768 + props: {
9769 + numArgs: 0
9770 + },
9771 + handler: ({ parser, funcName }, args) => {
9772 + let fName = funcName;
9773 + if (fName.length === 1) {
9774 + fName = singleCharBigOps[fName];
9775 + }
9776 + return {
9777 + type: "op",
9778 + mode: parser.mode,
9779 + limits: true,
9780 + parentIsSupSub: false,
9781 + symbol: true,
9782 + stack: false, // This is true for \stackrel{}, not here.
9783 + name: fName
9784 + };
9785 + },
9786 + mathmlBuilder: mathmlBuilder$2
9787 + });
9788 +
9789 + // Note: calling defineFunction with a type that's already been defined only
9790 + // works because the same mathmlBuilder is being used.
9791 + defineFunction({
9792 + type: "op",
9793 + names: ["\\mathop"],
9794 + props: {
9795 + numArgs: 1,
9796 + primitive: true
9797 + },
9798 + handler: ({ parser }, args) => {
9799 + const body = args[0];
9800 + // It would be convienient to just wrap a <mo> around the argument.
9801 + // But if the argument is a <mi> or <mord>, that would be invalid MathML.
9802 + // In that case, we instead promote the text contents of the body to the parent.
9803 + const arr = (body.body) ? body.body : [body];
9804 + const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type);
9805 + return {
9806 + type: "op",
9807 + mode: parser.mode,
9808 + limits: true,
9809 + parentIsSupSub: false,
9810 + symbol: isSymbol,
9811 + fromMathOp: true,
9812 + stack: false,
9813 + name: isSymbol ? arr[0].text : null,
9814 + body: isSymbol ? null : ordargument(body)
9815 + };
9816 + },
9817 + mathmlBuilder: mathmlBuilder$2
9818 + });
9819 +
9820 + // There are 2 flags for operators; whether they produce limits in
9821 + // displaystyle, and whether they are symbols and should grow in
9822 + // displaystyle. These four groups cover the four possible choices.
9823 +
9824 + const singleCharIntegrals = {
9825 + "\u222b": "\\int",
9826 + "\u222c": "\\iint",
9827 + "\u222d": "\\iiint",
9828 + "\u222e": "\\oint",
9829 + "\u222f": "\\oiint",
9830 + "\u2230": "\\oiiint",
9831 + "\u2231": "\\intclockwise",
9832 + "\u2232": "\\varointclockwise",
9833 + "\u2a0c": "\\iiiint",
9834 + "\u2a0d": "\\intbar",
9835 + "\u2a0e": "\\intBar",
9836 + "\u2a0f": "\\fint",
9837 + "\u2a12": "\\rppolint",
9838 + "\u2a13": "\\scpolint",
9839 + "\u2a15": "\\pointint",
9840 + "\u2a16": "\\sqint",
9841 + "\u2a17": "\\intlarhk",
9842 + "\u2a18": "\\intx",
9843 + "\u2a19": "\\intcap",
9844 + "\u2a1a": "\\intcup"
9845 + };
9846 +
9847 + // No limits, not symbols
9848 + defineFunction({
9849 + type: "op",
9850 + names: [
9851 + "\\arcsin",
9852 + "\\arccos",
9853 + "\\arctan",
9854 + "\\arctg",
9855 + "\\arcctg",
9856 + "\\arg",
9857 + "\\ch",
9858 + "\\cos",
9859 + "\\cosec",
9860 + "\\cosh",
9861 + "\\cot",
9862 + "\\cotg",
9863 + "\\coth",
9864 + "\\csc",
9865 + "\\ctg",
9866 + "\\cth",
9867 + "\\deg",
9868 + "\\dim",
9869 + "\\exp",
9870 + "\\hom",
9871 + "\\ker",
9872 + "\\lg",
9873 + "\\ln",
9874 + "\\log",
9875 + "\\sec",
9876 + "\\sin",
9877 + "\\sinh",
9878 + "\\sh",
9879 + "\\sgn",
9880 + "\\tan",
9881 + "\\tanh",
9882 + "\\tg",
9883 + "\\th"
9884 + ],
9885 + props: {
9886 + numArgs: 0
9887 + },
9888 + handler({ parser, funcName }) {
9889 + const prevAtomType = parser.prevAtomType;
9890 + const next = parser.gullet.future().text;
9891 + return {
9892 + type: "op",
9893 + mode: parser.mode,
9894 + limits: false,
9895 + parentIsSupSub: false,
9896 + symbol: false,
9897 + stack: false,
9898 + isFollowedByDelimiter: isDelimiter(next),
9899 + needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
9900 + name: funcName
9901 + };
9902 + },
9903 + mathmlBuilder: mathmlBuilder$2
9904 + });
9905 +
9906 + // Limits, not symbols
9907 + defineFunction({
9908 + type: "op",
9909 + names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"],
9910 + props: {
9911 + numArgs: 0
9912 + },
9913 + handler({ parser, funcName }) {
9914 + const prevAtomType = parser.prevAtomType;
9915 + const next = parser.gullet.future().text;
9916 + return {
9917 + type: "op",
9918 + mode: parser.mode,
9919 + limits: true,
9920 + parentIsSupSub: false,
9921 + symbol: false,
9922 + stack: false,
9923 + isFollowedByDelimiter: isDelimiter(next),
9924 + needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
9925 + name: funcName
9926 + };
9927 + },
9928 + mathmlBuilder: mathmlBuilder$2
9929 + });
9930 +
9931 + // No limits, symbols
9932 + defineFunction({
9933 + type: "op",
9934 + names: [
9935 + "\\int",
9936 + "\\iint",
9937 + "\\iiint",
9938 + "\\iiiint",
9939 + "\\oint",
9940 + "\\oiint",
9941 + "\\oiiint",
9942 + "\\intclockwise",
9943 + "\\varointclockwise",
9944 + "\\intbar",
9945 + "\\intBar",
9946 + "\\fint",
9947 + "\\rppolint",
9948 + "\\scpolint",
9949 + "\\pointint",
9950 + "\\sqint",
9951 + "\\intlarhk",
9952 + "\\intx",
9953 + "\\intcap",
9954 + "\\intcup",
9955 + "\u222b",
9956 + "\u222c",
9957 + "\u222d",
9958 + "\u222e",
9959 + "\u222f",
9960 + "\u2230",
9961 + "\u2231",
9962 + "\u2232",
9963 + "\u2a0c",
9964 + "\u2a0d",
9965 + "\u2a0e",
9966 + "\u2a0f",
9967 + "\u2a12",
9968 + "\u2a13",
9969 + "\u2a15",
9970 + "\u2a16",
9971 + "\u2a17",
9972 + "\u2a18",
9973 + "\u2a19",
9974 + "\u2a1a"
9975 + ],
9976 + props: {
9977 + numArgs: 0
9978 + },
9979 + handler({ parser, funcName }) {
9980 + let fName = funcName;
9981 + if (fName.length === 1) {
9982 + fName = singleCharIntegrals[fName];
9983 + }
9984 + return {
9985 + type: "op",
9986 + mode: parser.mode,
9987 + limits: false,
9988 + parentIsSupSub: false,
9989 + symbol: true,
9990 + stack: false,
9991 + name: fName
9992 + };
9993 + },
9994 + mathmlBuilder: mathmlBuilder$2
9995 + });
9996 +
9997 + // NOTE: Unlike most builders, this one handles not only
9998 + // "operatorname", but also "supsub" since \operatorname* can
9999 + // affect super/subscripting.
10000 +
10001 + const mathmlBuilder$1 = (group, style) => {
10002 + let expression = buildExpression(group.body, style.withFont("mathrm"));
10003 +
10004 + // Is expression a string or has it something like a fraction?
10005 + let isAllString = true; // default
10006 + for (let i = 0; i < expression.length; i++) {
10007 + let node = expression[i];
10008 + if (node instanceof mathMLTree.MathNode) {
10009 + if (node.type === "mrow" && node.children.length === 1 &&
10010 + node.children[0] instanceof mathMLTree.MathNode) {
10011 + node = node.children[0];
10012 + }
10013 + switch (node.type) {
10014 + case "mi":
10015 + case "mn":
10016 + case "ms":
10017 + case "mtext":
10018 + break; // Do nothing yet.
10019 + case "mspace":
10020 + {
10021 + if (node.attributes.width) {
10022 + const width = node.attributes.width.replace("em", "");
10023 + const ch = spaceCharacter(Number(width));
10024 + if (ch === "") {
10025 + isAllString = false;
10026 + } else {
10027 + expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]);
10028 + }
10029 + }
10030 + }
10031 + break
10032 + case "mo": {
10033 + const child = node.children[0];
10034 + if (node.children.length === 1 && child instanceof mathMLTree.TextNode) {
10035 + child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*");
10036 + } else {
10037 + isAllString = false;
10038 + }
10039 + break
10040 + }
10041 + default:
10042 + isAllString = false;
10043 + }
10044 + } else {
10045 + isAllString = false;
10046 + }
10047 + }
10048 +
10049 + if (isAllString) {
10050 + // Write a single TextNode instead of multiple nested tags.
10051 + const word = expression.map((node) => node.toText()).join("");
10052 + expression = [new mathMLTree.TextNode(word)];
10053 + } else if (
10054 + expression.length === 1
10055 + && ["mover", "munder"].includes(expression[0].type) &&
10056 + (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext")
10057 + ) {
10058 + expression[0].children[0].type = "mi";
10059 + if (group.parentIsSupSub) {
10060 + return new mathMLTree.MathNode("mrow", expression)
10061 + } else {
10062 + const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]);
10063 + return mathMLTree.newDocumentFragment([expression[0], operator])
10064 + }
10065 + }
10066 +
10067 + let wrapper;
10068 + if (isAllString) {
10069 + wrapper = new mathMLTree.MathNode("mi", expression);
10070 + if (expression[0].text.length === 1) {
10071 + wrapper.setAttribute("mathvariant", "normal");
10072 + }
10073 + } else {
10074 + wrapper = new mathMLTree.MathNode("mrow", expression);
10075 + }
10076 +
10077 + if (!group.parentIsSupSub) {
10078 + // Append an <mo>&ApplyFunction;</mo>.
10079 + // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
10080 + const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]);
10081 + const fragment = [wrapper, operator];
10082 + if (group.needsLeadingSpace) {
10083 + // LaTeX gives operator spacing, but a <mi> gets ord spacing.
10084 + // So add a leading space.
10085 + const space = new mathMLTree.MathNode("mspace");
10086 + space.setAttribute("width", "0.1667em"); // thin space.
10087 + fragment.unshift(space);
10088 + }
10089 + if (!group.isFollowedByDelimiter) {
10090 + const trail = new mathMLTree.MathNode("mspace");
10091 + trail.setAttribute("width", "0.1667em"); // thin space.
10092 + fragment.push(trail);
10093 + }
10094 + return mathMLTree.newDocumentFragment(fragment)
10095 + }
10096 +
10097 + return wrapper
10098 + };
10099 +
10100 + // \operatorname
10101 + // amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
10102 + defineFunction({
10103 + type: "operatorname",
10104 + names: ["\\operatorname@", "\\operatornamewithlimits"],
10105 + props: {
10106 + numArgs: 1,
10107 + allowedInArgument: true
10108 + },
10109 + handler: ({ parser, funcName }, args) => {
10110 + const body = args[0];
10111 + const prevAtomType = parser.prevAtomType;
10112 + const next = parser.gullet.future().text;
10113 + return {
10114 + type: "operatorname",
10115 + mode: parser.mode,
10116 + body: ordargument(body),
10117 + alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"),
10118 + limits: false,
10119 + parentIsSupSub: false,
10120 + isFollowedByDelimiter: isDelimiter(next),
10121 + needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType)
10122 + };
10123 + },
10124 + mathmlBuilder: mathmlBuilder$1
10125 + });
10126 +
10127 + defineMacro("\\operatorname",
10128 + "\\@ifstar\\operatornamewithlimits\\operatorname@");
10129 +
10130 + defineFunctionBuilders({
10131 + type: "ordgroup",
10132 + mathmlBuilder(group, style) {
10133 + return buildExpressionRow(group.body, style, group.semisimple);
10134 + }
10135 + });
10136 +
10137 + defineFunction({
10138 + type: "phantom",
10139 + names: ["\\phantom"],
10140 + props: {
10141 + numArgs: 1,
10142 + allowedInText: true
10143 + },
10144 + handler: ({ parser }, args) => {
10145 + const body = args[0];
10146 + return {
10147 + type: "phantom",
10148 + mode: parser.mode,
10149 + body: ordargument(body)
10150 + };
10151 + },
10152 + mathmlBuilder: (group, style) => {
10153 + const inner = buildExpression(group.body, style);
10154 + return new mathMLTree.MathNode("mphantom", inner);
10155 + }
10156 + });
10157 +
10158 + defineFunction({
10159 + type: "hphantom",
10160 + names: ["\\hphantom"],
10161 + props: {
10162 + numArgs: 1,
10163 + allowedInText: true
10164 + },
10165 + handler: ({ parser }, args) => {
10166 + const body = args[0];
10167 + return {
10168 + type: "hphantom",
10169 + mode: parser.mode,
10170 + body
10171 + };
10172 + },
10173 + mathmlBuilder: (group, style) => {
10174 + const inner = buildExpression(ordargument(group.body), style);
10175 + const phantom = new mathMLTree.MathNode("mphantom", inner);
10176 + const node = new mathMLTree.MathNode("mpadded", [phantom]);
10177 + node.setAttribute("height", "0px");
10178 + node.setAttribute("depth", "0px");
10179 + return node;
10180 + }
10181 + });
10182 +
10183 + defineFunction({
10184 + type: "vphantom",
10185 + names: ["\\vphantom"],
10186 + props: {
10187 + numArgs: 1,
10188 + allowedInText: true
10189 + },
10190 + handler: ({ parser }, args) => {
10191 + const body = args[0];
10192 + return {
10193 + type: "vphantom",
10194 + mode: parser.mode,
10195 + body
10196 + };
10197 + },
10198 + mathmlBuilder: (group, style) => {
10199 + const inner = buildExpression(ordargument(group.body), style);
10200 + const phantom = new mathMLTree.MathNode("mphantom", inner);
10201 + const node = new mathMLTree.MathNode("mpadded", [phantom]);
10202 + node.setAttribute("width", "0px");
10203 + return node;
10204 + }
10205 + });
10206 +
10207 + // In LaTeX, \pmb is a simulation of bold font.
10208 + // The version of \pmb in ambsy.sty works by typesetting three copies of the argument
10209 + // with small offsets. We use CSS font-weight:bold.
10210 +
10211 + defineFunction({
10212 + type: "pmb",
10213 + names: ["\\pmb"],
10214 + props: {
10215 + numArgs: 1,
10216 + allowedInText: true
10217 + },
10218 + handler({ parser }, args) {
10219 + return {
10220 + type: "pmb",
10221 + mode: parser.mode,
10222 + body: ordargument(args[0])
10223 + }
10224 + },
10225 + mathmlBuilder(group, style) {
10226 + const inner = buildExpression(group.body, style);
10227 + // Wrap with an <mstyle> element.
10228 + const node = wrapWithMstyle(inner);
10229 + node.setAttribute("style", "font-weight:bold");
10230 + return node
10231 + }
10232 + });
10233 +
10234 + // \raise, \lower, and \raisebox
10235 +
10236 + const mathmlBuilder = (group, style) => {
10237 + const newStyle = style.withLevel(StyleLevel.TEXT);
10238 + const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, newStyle)]);
10239 + const dy = calculateSize(group.dy, style);
10240 + node.setAttribute("voffset", dy.number + dy.unit);
10241 + // Add padding, which acts to increase height in Chromium.
10242 + // TODO: Figure out some way to change height in Firefox w/o breaking Chromium.
10243 + if (dy.number > 0) {
10244 + node.style.padding = dy.number + dy.unit + " 0 0 0";
10245 + } else {
10246 + node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0";
10247 + }
10248 + return node
10249 + };
10250 +
10251 + defineFunction({
10252 + type: "raise",
10253 + names: ["\\raise", "\\lower"],
10254 + props: {
10255 + numArgs: 2,
10256 + argTypes: ["size", "primitive"],
10257 + primitive: true
10258 + },
10259 + handler({ parser, funcName }, args) {
10260 + const amount = assertNodeType(args[0], "size").value;
10261 + if (funcName === "\\lower") { amount.number *= -1; }
10262 + const body = args[1];
10263 + return {
10264 + type: "raise",
10265 + mode: parser.mode,
10266 + dy: amount,
10267 + body
10268 + };
10269 + },
10270 + mathmlBuilder
10271 + });
10272 +
10273 +
10274 + defineFunction({
10275 + type: "raise",
10276 + names: ["\\raisebox"],
10277 + props: {
10278 + numArgs: 2,
10279 + argTypes: ["size", "hbox"],
10280 + allowedInText: true
10281 + },
10282 + handler({ parser, funcName }, args) {
10283 + const amount = assertNodeType(args[0], "size").value;
10284 + const body = args[1];
10285 + return {
10286 + type: "raise",
10287 + mode: parser.mode,
10288 + dy: amount,
10289 + body
10290 + };
10291 + },
10292 + mathmlBuilder
10293 + });
10294 +
10295 + defineFunction({
10296 + type: "ref",
10297 + names: ["\\ref", "\\eqref"],
10298 + props: {
10299 + numArgs: 1,
10300 + argTypes: ["raw"]
10301 + },
10302 + handler({ parser, funcName }, args) {
10303 + return {
10304 + type: "ref",
10305 + mode: parser.mode,
10306 + funcName,
10307 + string: args[0].string.replace(invalidIdRegEx, "")
10308 + };
10309 + },
10310 + mathmlBuilder(group, style) {
10311 + // Create an empty <a> node. Set a class and an href attribute.
10312 + // The post-processor will populate with the target's tag or equation number.
10313 + const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"];
10314 + return new AnchorNode("#" + group.string, classes, null)
10315 + }
10316 + });
10317 +
10318 + defineFunction({
10319 + type: "reflect",
10320 + names: ["\\reflectbox"],
10321 + props: {
10322 + numArgs: 1,
10323 + argTypes: ["hbox"],
10324 + allowedInText: true
10325 + },
10326 + handler({ parser }, args) {
10327 + return {
10328 + type: "reflect",
10329 + mode: parser.mode,
10330 + body: args[0]
10331 + };
10332 + },
10333 + mathmlBuilder(group, style) {
10334 + const node = buildGroup$1(group.body, style);
10335 + node.style.transform = "scaleX(-1)";
10336 + return node
10337 + }
10338 + });
10339 +
10340 + defineFunction({
10341 + type: "internal",
10342 + names: ["\\relax"],
10343 + props: {
10344 + numArgs: 0,
10345 + allowedInText: true
10346 + },
10347 + handler({ parser }) {
10348 + return {
10349 + type: "internal",
10350 + mode: parser.mode
10351 + };
10352 + }
10353 + });
10354 +
10355 + defineFunction({
10356 + type: "rule",
10357 + names: ["\\rule"],
10358 + props: {
10359 + numArgs: 2,
10360 + numOptionalArgs: 1,
10361 + allowedInText: true,
10362 + allowedInMath: true,
10363 + argTypes: ["size", "size", "size"]
10364 + },
10365 + handler({ parser }, args, optArgs) {
10366 + const shift = optArgs[0];
10367 + const width = assertNodeType(args[0], "size");
10368 + const height = assertNodeType(args[1], "size");
10369 + return {
10370 + type: "rule",
10371 + mode: parser.mode,
10372 + shift: shift && assertNodeType(shift, "size").value,
10373 + width: width.value,
10374 + height: height.value
10375 + };
10376 + },
10377 + mathmlBuilder(group, style) {
10378 + const width = calculateSize(group.width, style);
10379 + const height = calculateSize(group.height, style);
10380 + const shift = group.shift
10381 + ? calculateSize(group.shift, style)
10382 + : { number: 0, unit: "em" };
10383 + const color = (style.color && style.getColor()) || "black";
10384 +
10385 + const rule = new mathMLTree.MathNode("mspace");
10386 + if (width.number > 0 && height.number > 0) {
10387 + rule.setAttribute("mathbackground", color);
10388 + }
10389 + rule.setAttribute("width", width.number + width.unit);
10390 + rule.setAttribute("height", height.number + height.unit);
10391 + if (shift.number === 0) { return rule }
10392 +
10393 + const wrapper = new mathMLTree.MathNode("mpadded", [rule]);
10394 + if (shift.number >= 0) {
10395 + wrapper.setAttribute("height", "+" + shift.number + shift.unit);
10396 + } else {
10397 + wrapper.setAttribute("height", shift.number + shift.unit);
10398 + wrapper.setAttribute("depth", "+" + -shift.number + shift.unit);
10399 + }
10400 + wrapper.setAttribute("voffset", shift.number + shift.unit);
10401 + return wrapper;
10402 + }
10403 + });
10404 +
10405 + // The size mappings are taken from TeX with \normalsize=10pt.
10406 + // We don't have to track script level. MathML does that.
10407 + const sizeMap = {
10408 + "\\tiny": 0.5,
10409 + "\\sixptsize": 0.6,
10410 + "\\Tiny": 0.6,
10411 + "\\scriptsize": 0.7,
10412 + "\\footnotesize": 0.8,
10413 + "\\small": 0.9,
10414 + "\\normalsize": 1.0,
10415 + "\\large": 1.2,
10416 + "\\Large": 1.44,
10417 + "\\LARGE": 1.728,
10418 + "\\huge": 2.074,
10419 + "\\Huge": 2.488
10420 + };
10421 +
10422 + defineFunction({
10423 + type: "sizing",
10424 + names: [
10425 + "\\tiny",
10426 + "\\sixptsize",
10427 + "\\Tiny",
10428 + "\\scriptsize",
10429 + "\\footnotesize",
10430 + "\\small",
10431 + "\\normalsize",
10432 + "\\large",
10433 + "\\Large",
10434 + "\\LARGE",
10435 + "\\huge",
10436 + "\\Huge"
10437 + ],
10438 + props: {
10439 + numArgs: 0,
10440 + allowedInText: true
10441 + },
10442 + handler: ({ breakOnTokenText, funcName, parser }, args) => {
10443 + if (parser.settings.strict && parser.mode === "math") {
10444 + // eslint-disable-next-line no-console
10445 + console.log(`Temml strict-mode warning: Command ${funcName} is invalid in math mode.`);
10446 + }
10447 + const body = parser.parseExpression(false, breakOnTokenText, true);
10448 + return {
10449 + type: "sizing",
10450 + mode: parser.mode,
10451 + funcName,
10452 + body
10453 + };
10454 + },
10455 + mathmlBuilder: (group, style) => {
10456 + const newStyle = style.withFontSize(sizeMap[group.funcName]);
10457 + const inner = buildExpression(group.body, newStyle);
10458 + // Wrap with an <mstyle> element.
10459 + const node = wrapWithMstyle(inner);
10460 + const factor = (sizeMap[group.funcName] / style.fontSize).toFixed(4);
10461 + node.setAttribute("mathsize", factor + "em");
10462 + return node;
10463 + }
10464 + });
10465 +
10466 + // smash, with optional [tb], as in AMS
10467 +
10468 + defineFunction({
10469 + type: "smash",
10470 + names: ["\\smash"],
10471 + props: {
10472 + numArgs: 1,
10473 + numOptionalArgs: 1,
10474 + allowedInText: true
10475 + },
10476 + handler: ({ parser }, args, optArgs) => {
10477 + let smashHeight = false;
10478 + let smashDepth = false;
10479 + const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup");
10480 + if (tbArg) {
10481 + // Optional [tb] argument is engaged.
10482 + // ref: amsmath: \renewcommand{\smash}[1][tb]{%
10483 + // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}%
10484 + let letter = "";
10485 + for (let i = 0; i < tbArg.body.length; ++i) {
10486 + const node = tbArg.body[i];
10487 + // TODO: Write an AssertSymbolNode
10488 + letter = node.text;
10489 + if (letter === "t") {
10490 + smashHeight = true;
10491 + } else if (letter === "b") {
10492 + smashDepth = true;
10493 + } else {
10494 + smashHeight = false;
10495 + smashDepth = false;
10496 + break;
10497 + }
10498 + }
10499 + } else {
10500 + smashHeight = true;
10501 + smashDepth = true;
10502 + }
10503 +
10504 + const body = args[0];
10505 + return {
10506 + type: "smash",
10507 + mode: parser.mode,
10508 + body,
10509 + smashHeight,
10510 + smashDepth
10511 + };
10512 + },
10513 + mathmlBuilder: (group, style) => {
10514 + const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]);
10515 +
10516 + if (group.smashHeight) {
10517 + node.setAttribute("height", "0px");
10518 + }
10519 +
10520 + if (group.smashDepth) {
10521 + node.setAttribute("depth", "0px");
10522 + }
10523 +
10524 + return node;
10525 + }
10526 + });
10527 +
10528 + defineFunction({
10529 + type: "sqrt",
10530 + names: ["\\sqrt"],
10531 + props: {
10532 + numArgs: 1,
10533 + numOptionalArgs: 1
10534 + },
10535 + handler({ parser }, args, optArgs) {
10536 + const index = optArgs[0];
10537 + const body = args[0];
10538 + return {
10539 + type: "sqrt",
10540 + mode: parser.mode,
10541 + body,
10542 + index
10543 + };
10544 + },
10545 + mathmlBuilder(group, style) {
10546 + const { body, index } = group;
10547 + return index
10548 + ? new mathMLTree.MathNode("mroot", [
10549 + buildGroup$1(body, style),
10550 + buildGroup$1(index, style.incrementLevel())
10551 + ])
10552 + : new mathMLTree.MathNode("msqrt", [buildGroup$1(body, style)]);
10553 + }
10554 + });
10555 +
10556 + const styleMap = {
10557 + display: 0,
10558 + text: 1,
10559 + script: 2,
10560 + scriptscript: 3
10561 + };
10562 +
10563 + const styleAttributes = {
10564 + display: ["0", "true"],
10565 + text: ["0", "false"],
10566 + script: ["1", "false"],
10567 + scriptscript: ["2", "false"]
10568 + };
10569 +
10570 + defineFunction({
10571 + type: "styling",
10572 + names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"],
10573 + props: {
10574 + numArgs: 0,
10575 + allowedInText: true,
10576 + primitive: true
10577 + },
10578 + handler({ breakOnTokenText, funcName, parser }, args) {
10579 + // parse out the implicit body
10580 + const body = parser.parseExpression(true, breakOnTokenText, true);
10581 +
10582 + const scriptLevel = funcName.slice(1, funcName.length - 5);
10583 + return {
10584 + type: "styling",
10585 + mode: parser.mode,
10586 + // Figure out what scriptLevel to use by pulling out the scriptLevel from
10587 + // the function name
10588 + scriptLevel,
10589 + body
10590 + };
10591 + },
10592 + mathmlBuilder(group, style) {
10593 + // Figure out what scriptLevel we're changing to.
10594 + const newStyle = style.withLevel(styleMap[group.scriptLevel]);
10595 + // The style argument in the next line does NOT directly set a MathML script level.
10596 + // It just tracks the style level, in case we need to know it for supsub or mathchoice.
10597 + const inner = buildExpression(group.body, newStyle);
10598 + // Wrap with an <mstyle> element.
10599 + const node = wrapWithMstyle(inner);
10600 +
10601 + const attr = styleAttributes[group.scriptLevel];
10602 +
10603 + // Here is where we set the MathML script level.
10604 + node.setAttribute("scriptlevel", attr[0]);
10605 + node.setAttribute("displaystyle", attr[1]);
10606 +
10607 + return node;
10608 + }
10609 + });
10610 +
10611 + /**
10612 + * Sometimes, groups perform special rules when they have superscripts or
10613 + * subscripts attached to them. This function lets the `supsub` group know that
10614 + * Sometimes, groups perform special rules when they have superscripts or
10615 + * its inner element should handle the superscripts and subscripts instead of
10616 + * handling them itself.
10617 + */
10618 +
10619 + // Helpers
10620 + const symbolRegEx = /^m(over|under|underover)$/;
10621 +
10622 + // Super scripts and subscripts, whose precise placement can depend on other
10623 + // functions that precede them.
10624 + defineFunctionBuilders({
10625 + type: "supsub",
10626 + mathmlBuilder(group, style) {
10627 + // Is the inner group a relevant horizonal brace?
10628 + let isBrace = false;
10629 + let isOver;
10630 + let isSup;
10631 + let appendApplyFunction = false;
10632 + let appendSpace = false;
10633 + let needsLeadingSpace = false;
10634 +
10635 + if (group.base && group.base.type === "horizBrace") {
10636 + isSup = !!group.sup;
10637 + if (isSup === group.base.isOver) {
10638 + isBrace = true;
10639 + isOver = group.base.isOver;
10640 + }
10641 + }
10642 +
10643 + if (group.base && !group.base.stack &&
10644 + (group.base.type === "op" || group.base.type === "operatorname")) {
10645 + group.base.parentIsSupSub = true;
10646 + appendApplyFunction = !group.base.symbol;
10647 + appendSpace = appendApplyFunction && !group.isFollowedByDelimiter;
10648 + needsLeadingSpace = group.base.needsLeadingSpace;
10649 + }
10650 +
10651 + const children = group.base && group.base.stack
10652 + ? [buildGroup$1(group.base.body[0], style)]
10653 + : [buildGroup$1(group.base, style)];
10654 +
10655 + // Note regarding scriptstyle level.
10656 + // (Sub|super)scripts should not shrink beyond MathML scriptlevel 2 aka \scriptscriptstyle
10657 + // Ref: https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes
10658 + // (BTW, MathML scriptlevel 2 is equal to Temml level 3.)
10659 + // But Chromium continues to shrink the (sub|super)scripts. So we explicitly set scriptlevel 2.
10660 +
10661 + const childStyle = style.inSubOrSup();
10662 + if (group.sub) {
10663 + const sub = buildGroup$1(group.sub, childStyle);
10664 + if (style.level === 3) { sub.setAttribute("scriptlevel", "2"); }
10665 + children.push(sub);
10666 + }
10667 +
10668 + if (group.sup) {
10669 + const sup = buildGroup$1(group.sup, childStyle);
10670 + if (style.level === 3) { sup.setAttribute("scriptlevel", "2"); }
10671 + const testNode = sup.type === "mrow" ? sup.children[0] : sup;
10672 + if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
10673 + && group.base && group.base.text && "fF".indexOf(group.base.text) > -1) {
10674 + // Chromium does not address italic correction on prime. Prevent f′ from overlapping.
10675 + testNode.classes.push("prime-pad");
10676 + }
10677 + children.push(sup);
10678 + }
10679 +
10680 + let nodeType;
10681 + if (isBrace) {
10682 + nodeType = isOver ? "mover" : "munder";
10683 + } else if (!group.sub) {
10684 + const base = group.base;
10685 + if (
10686 + base &&
10687 + base.type === "op" &&
10688 + base.limits &&
10689 + (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub)
10690 + ) {
10691 + nodeType = "mover";
10692 + } else if (
10693 + base &&
10694 + base.type === "operatorname" &&
10695 + base.alwaysHandleSupSub &&
10696 + (base.limits || style.level === StyleLevel.DISPLAY)
10697 + ) {
10698 + nodeType = "mover";
10699 + } else {
10700 + nodeType = "msup";
10701 + }
10702 + } else if (!group.sup) {
10703 + const base = group.base;
10704 + if (
10705 + base &&
10706 + base.type === "op" &&
10707 + base.limits &&
10708 + (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub)
10709 + ) {
10710 + nodeType = "munder";
10711 + } else if (
10712 + base &&
10713 + base.type === "operatorname" &&
10714 + base.alwaysHandleSupSub &&
10715 + (base.limits || style.level === StyleLevel.DISPLAY)
10716 + ) {
10717 + nodeType = "munder";
10718 + } else {
10719 + nodeType = "msub";
10720 + }
10721 + } else {
10722 + const base = group.base;
10723 + if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") &&
10724 + (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub)
10725 + ) {
10726 + nodeType = "munderover";
10727 + } else if (
10728 + base &&
10729 + base.type === "operatorname" &&
10730 + base.alwaysHandleSupSub &&
10731 + (style.level === StyleLevel.DISPLAY || base.limits)
10732 + ) {
10733 + nodeType = "munderover";
10734 + } else {
10735 + nodeType = "msubsup";
10736 + }
10737 + }
10738 +
10739 + let node = new mathMLTree.MathNode(nodeType, children);
10740 + if (appendApplyFunction) {
10741 + // Append an <mo>&ApplyFunction;</mo>.
10742 + // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
10743 + const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]);
10744 + if (needsLeadingSpace) {
10745 + const space = new mathMLTree.MathNode("mspace");
10746 + space.setAttribute("width", "0.1667em"); // thin space.
10747 + node = mathMLTree.newDocumentFragment([space, node, operator]);
10748 + } else {
10749 + node = mathMLTree.newDocumentFragment([node, operator]);
10750 + }
10751 + if (appendSpace) {
10752 + const space = new mathMLTree.MathNode("mspace");
10753 + space.setAttribute("width", "0.1667em"); // thin space.
10754 + node.children.push(space);
10755 + }
10756 + } else if (symbolRegEx.test(nodeType)) {
10757 + // Wrap in a <mrow>. Otherwise Firefox stretchy parens will not stretch to include limits.
10758 + node = new mathMLTree.MathNode("mrow", [node]);
10759 + }
10760 +
10761 + return node
10762 + }
10763 + });
10764 +
10765 + // Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js.
10766 +
10767 + const temml_short = ["\\shortmid", "\\nshortmid", "\\shortparallel",
10768 + "\\nshortparallel", "\\smallsetminus"];
10769 +
10770 + const arrows = ["\\Rsh", "\\Lsh", "\\restriction"];
10771 +
10772 + const isArrow = str => {
10773 + if (str.length === 1) {
10774 + const codePoint = str.codePointAt(0);
10775 + return (0x218f < codePoint && codePoint < 0x2200)
10776 + }
10777 + return str.indexOf("arrow") > -1 || str.indexOf("harpoon") > -1 || arrows.includes(str)
10778 + };
10779 +
10780 + defineFunctionBuilders({
10781 + type: "atom",
10782 + mathmlBuilder(group, style) {
10783 + const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]);
10784 + if (group.family === "punct") {
10785 + node.setAttribute("separator", "true");
10786 + } else if (group.family === "open" || group.family === "close") {
10787 + // Delims built here should not stretch vertically.
10788 + // See delimsizing.js for stretchy delims.
10789 + if (group.family === "open") {
10790 + node.setAttribute("form", "prefix");
10791 + // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong.
10792 + node.setAttribute("stretchy", "false");
10793 + } else if (group.family === "close") {
10794 + node.setAttribute("form", "postfix");
10795 + node.setAttribute("stretchy", "false");
10796 + }
10797 + } else if (group.text === "\\mid") {
10798 + // Firefox messes up this spacing if at the end of an <mrow>. See it explicitly.
10799 + node.setAttribute("lspace", "0.22em"); // medium space
10800 + node.setAttribute("rspace", "0.22em");
10801 + node.setAttribute("stretchy", "false");
10802 + } else if (group.family === "rel" && isArrow(group.text)) {
10803 + node.setAttribute("stretchy", "false");
10804 + } else if (temml_short.includes(group.text)) {
10805 + node.setAttribute("mathsize", "70%");
10806 + } else if (group.text === ":") {
10807 + // ":" is not in the MathML operator dictionary. Give it BIN spacing.
10808 + node.attributes.lspace = "0.2222em";
10809 + node.attributes.rspace = "0.2222em";
10810 + }
10811 + return node;
10812 + }
10813 + });
10814 +
10815 + /**
10816 + * Maps TeX font commands to "mathvariant" attribute in buildMathML.js
10817 + */
10818 + const fontMap = {
10819 + // styles
10820 + mathbf: "bold",
10821 + mathrm: "normal",
10822 + textit: "italic",
10823 + mathit: "italic",
10824 + mathnormal: "italic",
10825 +
10826 + // families
10827 + mathbb: "double-struck",
10828 + mathcal: "script",
10829 + mathfrak: "fraktur",
10830 + mathscr: "script",
10831 + mathsf: "sans-serif",
10832 + mathtt: "monospace"
10833 + };
10834 +
10835 + /**
10836 + * Returns the math variant as a string or null if none is required.
10837 + */
10838 + const getVariant = function(group, style) {
10839 + // Handle font specifiers as best we can.
10840 + // Chromium does not support the MathML mathvariant attribute.
10841 + // So we'll use Unicode replacement characters instead.
10842 + // But first, determine the math variant.
10843 +
10844 + // Deal with the \textit, \textbf, etc., functions.
10845 + if (style.fontFamily === "texttt") {
10846 + return "monospace"
10847 + } else if (style.fontFamily === "textsc") {
10848 + return "normal"; // handled via character substitution in symbolsOrd.js.
10849 + } else if (style.fontFamily === "textsf") {
10850 + if (style.fontShape === "textit" && style.fontWeight === "textbf") {
10851 + return "sans-serif-bold-italic"
10852 + } else if (style.fontShape === "textit") {
10853 + return "sans-serif-italic"
10854 + } else if (style.fontWeight === "textbf") {
10855 + return "sans-serif-bold"
10856 + } else {
10857 + return "sans-serif"
10858 + }
10859 + } else if (style.fontShape === "textit" && style.fontWeight === "textbf") {
10860 + return "bold-italic"
10861 + } else if (style.fontShape === "textit") {
10862 + return "italic"
10863 + } else if (style.fontWeight === "textbf") {
10864 + return "bold"
10865 + }
10866 +
10867 + // Deal with the \mathit, mathbf, etc, functions.
10868 + const font = style.font;
10869 + if (!font || font === "mathnormal") {
10870 + return null
10871 + }
10872 +
10873 + const mode = group.mode;
10874 + switch (font) {
10875 + case "mathit":
10876 + return "italic"
10877 + case "mathrm": {
10878 + const codePoint = group.text.codePointAt(0);
10879 + // LaTeX \mathrm returns italic for Greek characters.
10880 + return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal"
10881 + }
10882 + case "greekItalic":
10883 + return "italic"
10884 + case "up@greek":
10885 + return "normal"
10886 + case "boldsymbol":
10887 + case "mathboldsymbol":
10888 + return "bold-italic"
10889 + case "mathbf":
10890 + return "bold"
10891 + case "mathbb":
10892 + return "double-struck"
10893 + case "mathfrak":
10894 + return "fraktur"
10895 + case "mathscr":
10896 + case "mathcal":
10897 + return "script"
10898 + case "mathsf":
10899 + return "sans-serif"
10900 + case "mathsfit":
10901 + return "sans-serif-italic"
10902 + case "mathtt":
10903 + return "monospace"
10904 + }
10905 +
10906 + let text = group.text;
10907 + if (symbols[mode][text] && symbols[mode][text].replace) {
10908 + text = symbols[mode][text].replace;
10909 + }
10910 +
10911 + return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null
10912 + };
10913 +
10914 + // Chromium does not support the MathML `mathvariant` attribute.
10915 + // Instead, we replace ASCII characters with Unicode characters that
10916 + // are defined in the font as bold, italic, double-struck, etc.
10917 + // This module identifies those Unicode code points.
10918 +
10919 + // First, a few helpers.
10920 + const script = Object.freeze({
10921 + B: 0x20EA, // Offset from ASCII B to Unicode script B
10922 + E: 0x20EB,
10923 + F: 0x20EB,
10924 + H: 0x20C3,
10925 + I: 0x20C7,
10926 + L: 0x20C6,
10927 + M: 0x20E6,
10928 + R: 0x20C9,
10929 + e: 0x20CA,
10930 + g: 0x20A3,
10931 + o: 0x20C5
10932 + });
10933 +
10934 + const frak = Object.freeze({
10935 + C: 0x20EA,
10936 + H: 0x20C4,
10937 + I: 0x20C8,
10938 + R: 0x20CA,
10939 + Z: 0x20CE
10940 + });
10941 +
10942 + const bbb = Object.freeze({
10943 + C: 0x20BF, // blackboard bold
10944 + H: 0x20C5,
10945 + N: 0x20C7,
10946 + P: 0x20C9,
10947 + Q: 0x20C9,
10948 + R: 0x20CB,
10949 + Z: 0x20CA
10950 + });
10951 +
10952 + const bold = Object.freeze({
10953 + "\u03f5": 0x1D2E7, // lunate epsilon
10954 + "\u03d1": 0x1D30C, // vartheta
10955 + "\u03f0": 0x1D2EE, // varkappa
10956 + "\u03c6": 0x1D319, // varphi
10957 + "\u03f1": 0x1D2EF, // varrho
10958 + "\u03d6": 0x1D30B // varpi
10959 + });
10960 +
10961 + const boldItalic = Object.freeze({
10962 + "\u03f5": 0x1D35B, // lunate epsilon
10963 + "\u03d1": 0x1D380, // vartheta
10964 + "\u03f0": 0x1D362, // varkappa
10965 + "\u03c6": 0x1D38D, // varphi
10966 + "\u03f1": 0x1D363, // varrho
10967 + "\u03d6": 0x1D37F // varpi
10968 + });
10969 +
10970 + const boldsf = Object.freeze({
10971 + "\u03f5": 0x1D395, // lunate epsilon
10972 + "\u03d1": 0x1D3BA, // vartheta
10973 + "\u03f0": 0x1D39C, // varkappa
10974 + "\u03c6": 0x1D3C7, // varphi
10975 + "\u03f1": 0x1D39D, // varrho
10976 + "\u03d6": 0x1D3B9 // varpi
10977 + });
10978 +
10979 + const bisf = Object.freeze({
10980 + "\u03f5": 0x1D3CF, // lunate epsilon
10981 + "\u03d1": 0x1D3F4, // vartheta
10982 + "\u03f0": 0x1D3D6, // varkappa
10983 + "\u03c6": 0x1D401, // varphi
10984 + "\u03f1": 0x1D3D7, // varrho
10985 + "\u03d6": 0x1D3F3 // varpi
10986 + });
10987 +
10988 + // Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf
10989 + const offset = Object.freeze({
10990 + upperCaseLatin: { // A-Z
10991 + "normal": ch => { return 0 },
10992 + "bold": ch => { return 0x1D3BF },
10993 + "italic": ch => { return 0x1D3F3 },
10994 + "bold-italic": ch => { return 0x1D427 },
10995 + "script": ch => { return script[ch] || 0x1D45B },
10996 + "script-bold": ch => { return 0x1D48F },
10997 + "fraktur": ch => { return frak[ch] || 0x1D4C3 },
10998 + "fraktur-bold": ch => { return 0x1D52B },
10999 + "double-struck": ch => { return bbb[ch] || 0x1D4F7 },
11000 + "sans-serif": ch => { return 0x1D55F },
11001 + "sans-serif-bold": ch => { return 0x1D593 },
11002 + "sans-serif-italic": ch => { return 0x1D5C7 },
11003 + "sans-serif-bold-italic": ch => { return 0x1D63C },
11004 + "monospace": ch => { return 0x1D62F }
11005 + },
11006 + lowerCaseLatin: { // a-z
11007 + "normal": ch => { return 0 },
11008 + "bold": ch => { return 0x1D3B9 },
11009 + "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED },
11010 + "bold-italic": ch => { return 0x1D421 },
11011 + "script": ch => { return script[ch] || 0x1D455 },
11012 + "script-bold": ch => { return 0x1D489 },
11013 + "fraktur": ch => { return 0x1D4BD },
11014 + "fraktur-bold": ch => { return 0x1D525 },
11015 + "double-struck": ch => { return 0x1D4F1 },
11016 + "sans-serif": ch => { return 0x1D559 },
11017 + "sans-serif-bold": ch => { return 0x1D58D },
11018 + "sans-serif-italic": ch => { return 0x1D5C1 },
11019 + "sans-serif-bold-italic": ch => { return 0x1D5F5 },
11020 + "monospace": ch => { return 0x1D629 }
11021 + },
11022 + upperCaseGreek: { // A-Ω
11023 + "normal": ch => { return 0 },
11024 + "bold": ch => { return 0x1D317 },
11025 + "italic": ch => { return 0x1D351 },
11026 + // \boldsymbol actually returns upright bold for upperCaseGreek
11027 + "bold-italic": ch => { return 0x1D317 },
11028 + "script": ch => { return 0 },
11029 + "script-bold": ch => { return 0 },
11030 + "fraktur": ch => { return 0 },
11031 + "fraktur-bold": ch => { return 0 },
11032 + "double-struck": ch => { return 0 },
11033 + // Unicode has no code points for regular-weight san-serif Greek. Use bold.
11034 + "sans-serif": ch => { return 0x1D3C5 },
11035 + "sans-serif-bold": ch => { return 0x1D3C5 },
11036 + "sans-serif-italic": ch => { return 0 },
11037 + "sans-serif-bold-italic": ch => { return 0x1D3FF },
11038 + "monospace": ch => { return 0 }
11039 + },
11040 + lowerCaseGreek: { // α-ω
11041 + "normal": ch => { return 0 },
11042 + "bold": ch => { return 0x1D311 },
11043 + "italic": ch => { return 0x1D34B },
11044 + "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 },
11045 + "script": ch => { return 0 },
11046 + "script-bold": ch => { return 0 },
11047 + "fraktur": ch => { return 0 },
11048 + "fraktur-bold": ch => { return 0 },
11049 + "double-struck": ch => { return 0 },
11050 + // Unicode has no code points for regular-weight san-serif Greek. Use bold.
11051 + "sans-serif": ch => { return 0x1D3BF },
11052 + "sans-serif-bold": ch => { return 0x1D3BF },
11053 + "sans-serif-italic": ch => { return 0 },
11054 + "sans-serif-bold-italic": ch => { return 0x1D3F9 },
11055 + "monospace": ch => { return 0 }
11056 + },
11057 + varGreek: { // \varGamma, etc
11058 + "normal": ch => { return 0 },
11059 + "bold": ch => { return bold[ch] || -51 },
11060 + "italic": ch => { return 0 },
11061 + "bold-italic": ch => { return boldItalic[ch] || 0x3A },
11062 + "script": ch => { return 0 },
11063 + "script-bold": ch => { return 0 },
11064 + "fraktur": ch => { return 0 },
11065 + "fraktur-bold": ch => { return 0 },
11066 + "double-struck": ch => { return 0 },
11067 + "sans-serif": ch => { return boldsf[ch] || 0x74 },
11068 + "sans-serif-bold": ch => { return boldsf[ch] || 0x74 },
11069 + "sans-serif-italic": ch => { return 0 },
11070 + "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE },
11071 + "monospace": ch => { return 0 }
11072 + },
11073 + numeral: { // 0-9
11074 + "normal": ch => { return 0 },
11075 + "bold": ch => { return 0x1D79E },
11076 + "italic": ch => { return 0 },
11077 + "bold-italic": ch => { return 0 },
11078 + "script": ch => { return 0 },
11079 + "script-bold": ch => { return 0 },
11080 + "fraktur": ch => { return 0 },
11081 + "fraktur-bold": ch => { return 0 },
11082 + "double-struck": ch => { return 0x1D7A8 },
11083 + "sans-serif": ch => { return 0x1D7B2 },
11084 + "sans-serif-bold": ch => { return 0x1D7BC },
11085 + "sans-serif-italic": ch => { return 0 },
11086 + "sans-serif-bold-italic": ch => { return 0 },
11087 + "monospace": ch => { return 0x1D7C6 }
11088 + }
11089 + });
11090 +
11091 + const variantChar = (ch, variant) => {
11092 + const codePoint = ch.codePointAt(0);
11093 + const block = 0x40 < codePoint && codePoint < 0x5b
11094 + ? "upperCaseLatin"
11095 + : 0x60 < codePoint && codePoint < 0x7b
11096 + ? "lowerCaseLatin"
11097 + : (0x390 < codePoint && codePoint < 0x3AA)
11098 + ? "upperCaseGreek"
11099 + : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
11100 + ? "lowerCaseGreek"
11101 + : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch]
11102 + ? "varGreek"
11103 + : (0x2F < codePoint && codePoint < 0x3A)
11104 + ? "numeral"
11105 + : "other";
11106 + return block === "other"
11107 + ? ch
11108 + : String.fromCodePoint(codePoint + offset[block][variant](ch))
11109 + };
11110 +
11111 + const smallCaps = Object.freeze({
11112 + a: "ᴀ",
11113 + b: "ʙ",
11114 + c: "ᴄ",
11115 + d: "ᴅ",
11116 + e: "ᴇ",
11117 + f: "ꜰ",
11118 + g: "ɢ",
11119 + h: "ʜ",
11120 + i: "ɪ",
11121 + j: "ᴊ",
11122 + k: "ᴋ",
11123 + l: "ʟ",
11124 + m: "ᴍ",
11125 + n: "ɴ",
11126 + o: "ᴏ",
11127 + p: "ᴘ",
11128 + q: "ǫ",
11129 + r: "ʀ",
11130 + s: "s",
11131 + t: "ᴛ",
11132 + u: "ᴜ",
11133 + v: "ᴠ",
11134 + w: "ᴡ",
11135 + x: "x",
11136 + y: "ʏ",
11137 + z: "ᴢ"
11138 + });
11139 +
11140 + // "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
11141 + // src/symbols.js.
11142 +
11143 + const numberRegEx = /^\d(?:[\d,.]*\d)?$/;
11144 + const latinRegEx = /[A-Ba-z]/;
11145 + const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime",
11146 + "\\backprime", "\\backdprime", "\\backtrprime"]);
11147 +
11148 + const italicNumber = (text, variant, tag) => {
11149 + const mn = new mathMLTree.MathNode(tag, [text]);
11150 + const wrapper = new mathMLTree.MathNode("mstyle", [mn]);
11151 + wrapper.style["font-style"] = "italic";
11152 + wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif";
11153 + if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold"; }
11154 + return wrapper
11155 + };
11156 +
11157 + defineFunctionBuilders({
11158 + type: "mathord",
11159 + mathmlBuilder(group, style) {
11160 + const text = makeText(group.text, group.mode, style);
11161 + const codePoint = text.text.codePointAt(0);
11162 + // Test for upper-case Greek
11163 + const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic";
11164 + const variant = getVariant(group, style) || defaultVariant;
11165 + if (variant === "script") {
11166 + text.text = variantChar(text.text, variant);
11167 + return new mathMLTree.MathNode("mi", [text], [style.font])
11168 + } else if (variant !== "italic") {
11169 + text.text = variantChar(text.text, variant);
11170 + }
11171 + let node = new mathMLTree.MathNode("mi", [text]);
11172 + // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf
11173 + if (variant === "normal") {
11174 + node.setAttribute("mathvariant", "normal");
11175 + if (text.text.length === 1) {
11176 + // A Firefox bug will apply spacing here, but there should be none. Fix it.
11177 + node = new mathMLTree.MathNode("mrow", [node]);
11178 + }
11179 + }
11180 + return node
11181 + }
11182 + });
11183 +
11184 + defineFunctionBuilders({
11185 + type: "textord",
11186 + mathmlBuilder(group, style) {
11187 + let ch = group.text;
11188 + const codePoint = ch.codePointAt(0);
11189 + if (style.fontFamily === "textsc") {
11190 + // Convert small latin letters to small caps.
11191 + if (96 < codePoint && codePoint < 123) {
11192 + ch = smallCaps[ch];
11193 + }
11194 + }
11195 + const text = makeText(ch, group.mode, style);
11196 + const variant = getVariant(group, style) || "normal";
11197 +
11198 + let node;
11199 + if (numberRegEx.test(group.text)) {
11200 + const tag = group.mode === "text" ? "mtext" : "mn";
11201 + if (variant === "italic" || variant === "bold-italic") {
11202 + return italicNumber(text, variant, tag)
11203 + } else {
11204 + if (variant !== "normal") {
11205 + text.text = text.text.split("").map(c => variantChar(c, variant)).join("");
11206 + }
11207 + node = new mathMLTree.MathNode(tag, [text]);
11208 + }
11209 + } else if (group.mode === "text") {
11210 + if (variant !== "normal") {
11211 + text.text = variantChar(text.text, variant);
11212 + }
11213 + node = new mathMLTree.MathNode("mtext", [text]);
11214 + } else if (primes.has(group.text)) {
11215 + node = new mathMLTree.MathNode("mo", [text]);
11216 + // TODO: If/when Chromium uses ssty variant for prime, remove the next line.
11217 + node.classes.push("tml-prime");
11218 + } else {
11219 + const origText = text.text;
11220 + if (variant !== "italic") {
11221 + text.text = variantChar(text.text, variant);
11222 + }
11223 + node = new mathMLTree.MathNode("mi", [text]);
11224 + if (text.text === origText && latinRegEx.test(origText)) {
11225 + node.setAttribute("mathvariant", "italic");
11226 + }
11227 + }
11228 + return node
11229 + }
11230 + });
11231 +
11232 + // A map of CSS-based spacing functions to their CSS class.
11233 + const cssSpace = {
11234 + "\\nobreak": "nobreak",
11235 + "\\allowbreak": "allowbreak"
11236 + };
11237 +
11238 + // A lookup table to determine whether a spacing function/symbol should be
11239 + // treated like a regular space character. If a symbol or command is a key
11240 + // in this table, then it should be a regular space character. Furthermore,
11241 + // the associated value may have a `className` specifying an extra CSS class
11242 + // to add to the created `span`.
11243 + const regularSpace = {
11244 + " ": {},
11245 + "\\ ": {},
11246 + "~": {
11247 + className: "nobreak"
11248 + },
11249 + "\\space": {},
11250 + "\\nobreakspace": {
11251 + className: "nobreak"
11252 + }
11253 + };
11254 +
11255 + // ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in
11256 + // src/symbols.js.
11257 + defineFunctionBuilders({
11258 + type: "spacing",
11259 + mathmlBuilder(group, style) {
11260 + let node;
11261 +
11262 + if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) {
11263 + // Firefox does not render a space in a <mtext> </mtext>. So write a no-break space.
11264 + // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node.
11265 + //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " "
11266 + node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]);
11267 + } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) {
11268 + // MathML 3.0 calls for nobreak to occur in an <mo>, not an <mtext>
11269 + // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs
11270 + node = new mathMLTree.MathNode("mo");
11271 + if (group.text === "\\nobreak") {
11272 + node.setAttribute("linebreak", "nobreak");
11273 + }
11274 + } else {
11275 + throw new ParseError(`Unknown type of space "${group.text}"`)
11276 + }
11277 +
11278 + return node
11279 + }
11280 + });
11281 +
11282 + defineFunctionBuilders({
11283 + type: "tag"
11284 + });
11285 +
11286 + // For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js.
11287 + // That way, a \tag can be pulled out of the parse tree and wrapped around the outer node.
11288 +
11289 + // Non-mathy text, possibly in a font
11290 + const textFontFamilies = {
11291 + "\\text": undefined,
11292 + "\\textrm": "textrm",
11293 + "\\textsf": "textsf",
11294 + "\\texttt": "texttt",
11295 + "\\textnormal": "textrm",
11296 + "\\textsc": "textsc" // small caps
11297 + };
11298 +
11299 + const textFontWeights = {
11300 + "\\textbf": "textbf",
11301 + "\\textmd": "textmd"
11302 + };
11303 +
11304 + const textFontShapes = {
11305 + "\\textit": "textit",
11306 + "\\textup": "textup"
11307 + };
11308 +
11309 + const styleWithFont = (group, style) => {
11310 + const font = group.font;
11311 + // Checks if the argument is a font family or a font style.
11312 + if (!font) {
11313 + return style;
11314 + } else if (textFontFamilies[font]) {
11315 + return style.withTextFontFamily(textFontFamilies[font]);
11316 + } else if (textFontWeights[font]) {
11317 + return style.withTextFontWeight(textFontWeights[font]);
11318 + } else if (font === "\\emph") {
11319 + return style.fontShape === "textit"
11320 + ? style.withTextFontShape("textup")
11321 + : style.withTextFontShape("textit")
11322 + }
11323 + return style.withTextFontShape(textFontShapes[font])
11324 + };
11325 +
11326 + defineFunction({
11327 + type: "text",
11328 + names: [
11329 + // Font families
11330 + "\\text",
11331 + "\\textrm",
11332 + "\\textsf",
11333 + "\\texttt",
11334 + "\\textnormal",
11335 + "\\textsc",
11336 + // Font weights
11337 + "\\textbf",
11338 + "\\textmd",
11339 + // Font Shapes
11340 + "\\textit",
11341 + "\\textup",
11342 + "\\emph"
11343 + ],
11344 + props: {
11345 + numArgs: 1,
11346 + argTypes: ["text"],
11347 + allowedInArgument: true,
11348 + allowedInText: true
11349 + },
11350 + handler({ parser, funcName }, args) {
11351 + const body = args[0];
11352 + return {
11353 + type: "text",
11354 + mode: parser.mode,
11355 + body: ordargument(body),
11356 + font: funcName
11357 + };
11358 + },
11359 + mathmlBuilder(group, style) {
11360 + const newStyle = styleWithFont(group, style);
11361 + const mrow = buildExpressionRow(group.body, newStyle);
11362 + return consolidateText(mrow)
11363 + }
11364 + });
11365 +
11366 + // \vcenter: Vertically center the argument group on the math axis.
11367 +
11368 + defineFunction({
11369 + type: "vcenter",
11370 + names: ["\\vcenter"],
11371 + props: {
11372 + numArgs: 1,
11373 + argTypes: ["original"],
11374 + allowedInText: false
11375 + },
11376 + handler({ parser }, args) {
11377 + return {
11378 + type: "vcenter",
11379 + mode: parser.mode,
11380 + body: args[0]
11381 + };
11382 + },
11383 + mathmlBuilder(group, style) {
11384 + // Use a math table to create vertically centered content.
11385 + const mtd = new mathMLTree.MathNode("mtd", [buildGroup$1(group.body, style)]);
11386 + mtd.style.padding = "0";
11387 + const mtr = new mathMLTree.MathNode("mtr", [mtd]);
11388 + return new mathMLTree.MathNode("mtable", [mtr])
11389 + }
11390 + });
11391 +
11392 + defineFunction({
11393 + type: "verb",
11394 + names: ["\\verb"],
11395 + props: {
11396 + numArgs: 0,
11397 + allowedInText: true
11398 + },
11399 + handler(context, args, optArgs) {
11400 + // \verb and \verb* are dealt with directly in Parser.js.
11401 + // If we end up here, it's because of a failure to match the two delimiters
11402 + // in the regex in Lexer.js. LaTeX raises the following error when \verb is
11403 + // terminated by end of line (or file).
11404 + throw new ParseError("\\verb ended by end of line instead of matching delimiter");
11405 + },
11406 + mathmlBuilder(group, style) {
11407 + const text = new mathMLTree.TextNode(makeVerb(group));
11408 + const node = new mathMLTree.MathNode("mtext", [text]);
11409 + node.setAttribute("mathvariant", "monospace");
11410 + return node;
11411 + }
11412 + });
11413 +
11414 + /**
11415 + * Converts verb group into body string.
11416 + *
11417 + * \verb* replaces each space with an open box \u2423
11418 + * \verb replaces each space with a no-break space \xA0
11419 + */
11420 + const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0");
11421 +
11422 + /** Include this to ensure that all functions are defined. */
11423 +
11424 + const functions = _functions;
11425 +
11426 + /**
11427 + * The Lexer class handles tokenizing the input in various ways. Since our
11428 + * parser expects us to be able to backtrack, the lexer allows lexing from any
11429 + * given starting point.
11430 + *
11431 + * Its main exposed function is the `lex` function, which takes a position to
11432 + * lex from and a type of token to lex. It defers to the appropriate `_innerLex`
11433 + * function.
11434 + *
11435 + * The various `_innerLex` functions perform the actual lexing of different
11436 + * kinds.
11437 + */
11438 +
11439 +
11440 + /* The following tokenRegex
11441 + * - matches typical whitespace (but not NBSP etc.) using its first two groups
11442 + * - does not match any control character \x00-\x1f except whitespace
11443 + * - does not match a bare backslash
11444 + * - matches any ASCII character except those just mentioned
11445 + * - does not match the BMP private use area \uE000-\uF8FF
11446 + * - does not match bare surrogate code units
11447 + * - matches any BMP character except for those just described
11448 + * - matches any valid Unicode surrogate pair
11449 + * - mathches numerals
11450 + * - matches a backslash followed by one or more whitespace characters
11451 + * - matches a backslash followed by one or more letters then whitespace
11452 + * - matches a backslash followed by any BMP character
11453 + * Capturing groups:
11454 + * [1] regular whitespace
11455 + * [2] backslash followed by whitespace
11456 + * [3] anything else, which may include:
11457 + * [4] left character of \verb*
11458 + * [5] left character of \verb
11459 + * [6] backslash followed by word, excluding any trailing whitespace
11460 + * Just because the Lexer matches something doesn't mean it's valid input:
11461 + * If there is no matching function or symbol definition, the Parser will
11462 + * still reject the input.
11463 + */
11464 + const spaceRegexString = "[ \r\n\t]";
11465 + const controlWordRegexString = "\\\\[a-zA-Z@]+";
11466 + const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]";
11467 + const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*`;
11468 + const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*";
11469 + const combiningDiacriticalMarkString = "[\u0300-\u036f]";
11470 + const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`);
11471 + const tokenRegexString =
11472 + `(${spaceRegexString}+)|` + // whitespace
11473 + `${controlSpaceRegexString}|` + // whitespace
11474 + "([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
11475 + `${combiningDiacriticalMarkString}*` + // ...plus accents
11476 + "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
11477 + `${combiningDiacriticalMarkString}*` + // ...plus accents
11478 + "|\\\\verb\\*([^]).*?\\4" + // \verb*
11479 + "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred
11480 + `|${controlWordWhitespaceRegexString}` + // \macroName + spaces
11481 + `|${controlSymbolRegexString})`; // \\, \', etc.
11482 +
11483 + /** Main Lexer class */
11484 + class Lexer {
11485 + constructor(input, settings) {
11486 + // Separate accents from characters
11487 + this.input = input;
11488 + this.settings = settings;
11489 + this.tokenRegex = new RegExp(tokenRegexString, 'g');
11490 + // Category codes. The lexer only supports comment characters (14) for now.
11491 + // MacroExpander additionally distinguishes active (13).
11492 + this.catcodes = {
11493 + "%": 14, // comment character
11494 + "~": 13 // active character
11495 + };
11496 + }
11497 +
11498 + setCatcode(char, code) {
11499 + this.catcodes[char] = code;
11500 + }
11501 +
11502 + /**
11503 + * This function lexes a single token.
11504 + */
11505 + lex() {
11506 + const input = this.input;
11507 + const pos = this.tokenRegex.lastIndex;
11508 + if (pos === input.length) {
11509 + return new Token("EOF", new SourceLocation(this, pos, pos));
11510 + }
11511 + const match = this.tokenRegex.exec(input);
11512 + if (match === null || match.index !== pos) {
11513 + throw new ParseError(
11514 + `Unexpected character: '${input[pos]}'`,
11515 + new Token(input[pos], new SourceLocation(this, pos, pos + 1))
11516 + );
11517 + }
11518 + const text = match[6] || match[3] || (match[2] ? "\\ " : " ");
11519 +
11520 + if (this.catcodes[text] === 14) {
11521 + // comment character
11522 + const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex);
11523 + if (nlIndex === -1) {
11524 + this.tokenRegex.lastIndex = input.length; // EOF
11525 + if (this.settings.strict) {
11526 + throw new ParseError("% comment has no terminating newline; LaTeX would " +
11527 + "fail because of commenting the end of math mode")
11528 + }
11529 + } else {
11530 + this.tokenRegex.lastIndex = nlIndex + 1;
11531 + }
11532 + return this.lex();
11533 + }
11534 +
11535 + return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex));
11536 + }
11537 + }
11538 +
11539 + /**
11540 + * A `Namespace` refers to a space of nameable things like macros or lengths,
11541 + * which can be `set` either globally or local to a nested group, using an
11542 + * undo stack similar to how TeX implements this functionality.
11543 + * Performance-wise, `get` and local `set` take constant time, while global
11544 + * `set` takes time proportional to the depth of group nesting.
11545 + */
11546 +
11547 +
11548 + class Namespace {
11549 + /**
11550 + * Both arguments are optional. The first argument is an object of
11551 + * built-in mappings which never change. The second argument is an object
11552 + * of initial (global-level) mappings, which will constantly change
11553 + * according to any global/top-level `set`s done.
11554 + */
11555 + constructor(builtins = {}, globalMacros = {}) {
11556 + this.current = globalMacros;
11557 + this.builtins = builtins;
11558 + this.undefStack = [];
11559 + }
11560 +
11561 + /**
11562 + * Start a new nested group, affecting future local `set`s.
11563 + */
11564 + beginGroup() {
11565 + this.undefStack.push({});
11566 + }
11567 +
11568 + /**
11569 + * End current nested group, restoring values before the group began.
11570 + */
11571 + endGroup() {
11572 + if (this.undefStack.length === 0) {
11573 + throw new ParseError(
11574 + "Unbalanced namespace destruction: attempt " +
11575 + "to pop global namespace; please report this as a bug"
11576 + );
11577 + }
11578 + const undefs = this.undefStack.pop();
11579 + for (const undef in undefs) {
11580 + if (Object.prototype.hasOwnProperty.call(undefs, undef )) {
11581 + if (undefs[undef] === undefined) {
11582 + delete this.current[undef];
11583 + } else {
11584 + this.current[undef] = undefs[undef];
11585 + }
11586 + }
11587 + }
11588 + }
11589 +
11590 + /**
11591 + * Detect whether `name` has a definition. Equivalent to
11592 + * `get(name) != null`.
11593 + */
11594 + has(name) {
11595 + return Object.prototype.hasOwnProperty.call(this.current, name ) ||
11596 + Object.prototype.hasOwnProperty.call(this.builtins, name );
11597 + }
11598 +
11599 + /**
11600 + * Get the current value of a name, or `undefined` if there is no value.
11601 + *
11602 + * Note: Do not use `if (namespace.get(...))` to detect whether a macro
11603 + * is defined, as the definition may be the empty string which evaluates
11604 + * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or
11605 + * `if (namespace.has(...))`.
11606 + */
11607 + get(name) {
11608 + if (Object.prototype.hasOwnProperty.call(this.current, name )) {
11609 + return this.current[name];
11610 + } else {
11611 + return this.builtins[name];
11612 + }
11613 + }
11614 +
11615 + /**
11616 + * Set the current value of a name, and optionally set it globally too.
11617 + * Local set() sets the current value and (when appropriate) adds an undo
11618 + * operation to the undo stack. Global set() may change the undo
11619 + * operation at every level, so takes time linear in their number.
11620 + */
11621 + set(name, value, global = false) {
11622 + if (global) {
11623 + // Global set is equivalent to setting in all groups. Simulate this
11624 + // by destroying any undos currently scheduled for this name,
11625 + // and adding an undo with the *new* value (in case it later gets
11626 + // locally reset within this environment).
11627 + for (let i = 0; i < this.undefStack.length; i++) {
11628 + delete this.undefStack[i][name];
11629 + }
11630 + if (this.undefStack.length > 0) {
11631 + this.undefStack[this.undefStack.length - 1][name] = value;
11632 + }
11633 + } else {
11634 + // Undo this set at end of this group (possibly to `undefined`),
11635 + // unless an undo is already in place, in which case that older
11636 + // value is the correct one.
11637 + const top = this.undefStack[this.undefStack.length - 1];
11638 + if (top && !Object.prototype.hasOwnProperty.call(top, name )) {
11639 + top[name] = this.current[name];
11640 + }
11641 + }
11642 + this.current[name] = value;
11643 + }
11644 + }
11645 +
11646 + /**
11647 + * This file contains the “gullet” where macros are expanded
11648 + * until only non-macro tokens remain.
11649 + */
11650 +
11651 +
11652 + // List of commands that act like macros but aren't defined as a macro,
11653 + // function, or symbol. Used in `isDefined`.
11654 + const implicitCommands = {
11655 + "^": true, // Parser.js
11656 + _: true, // Parser.js
11657 + "\\limits": true, // Parser.js
11658 + "\\nolimits": true // Parser.js
11659 + };
11660 +
11661 + class MacroExpander {
11662 + constructor(input, settings, mode) {
11663 + this.settings = settings;
11664 + this.expansionCount = 0;
11665 + this.feed(input);
11666 + // Make new global namespace
11667 + this.macros = new Namespace(macros, settings.macros);
11668 + this.mode = mode;
11669 + this.stack = []; // contains tokens in REVERSE order
11670 + }
11671 +
11672 + /**
11673 + * Feed a new input string to the same MacroExpander
11674 + * (with existing macros etc.).
11675 + */
11676 + feed(input) {
11677 + this.lexer = new Lexer(input, this.settings);
11678 + }
11679 +
11680 + /**
11681 + * Switches between "text" and "math" modes.
11682 + */
11683 + switchMode(newMode) {
11684 + this.mode = newMode;
11685 + }
11686 +
11687 + /**
11688 + * Start a new group nesting within all namespaces.
11689 + */
11690 + beginGroup() {
11691 + this.macros.beginGroup();
11692 + }
11693 +
11694 + /**
11695 + * End current group nesting within all namespaces.
11696 + */
11697 + endGroup() {
11698 + this.macros.endGroup();
11699 + }
11700 +
11701 + /**
11702 + * Returns the topmost token on the stack, without expanding it.
11703 + * Similar in behavior to TeX's `\futurelet`.
11704 + */
11705 + future() {
11706 + if (this.stack.length === 0) {
11707 + this.pushToken(this.lexer.lex());
11708 + }
11709 + return this.stack[this.stack.length - 1]
11710 + }
11711 +
11712 + /**
11713 + * Remove and return the next unexpanded token.
11714 + */
11715 + popToken() {
11716 + this.future(); // ensure non-empty stack
11717 + return this.stack.pop();
11718 + }
11719 +
11720 + /**
11721 + * Add a given token to the token stack. In particular, this get be used
11722 + * to put back a token returned from one of the other methods.
11723 + */
11724 + pushToken(token) {
11725 + this.stack.push(token);
11726 + }
11727 +
11728 + /**
11729 + * Append an array of tokens to the token stack.
11730 + */
11731 + pushTokens(tokens) {
11732 + this.stack.push(...tokens);
11733 + }
11734 +
11735 + /**
11736 + * Find an macro argument without expanding tokens and append the array of
11737 + * tokens to the token stack. Uses Token as a container for the result.
11738 + */
11739 + scanArgument(isOptional) {
11740 + let start;
11741 + let end;
11742 + let tokens;
11743 + if (isOptional) {
11744 + this.consumeSpaces(); // \@ifnextchar gobbles any space following it
11745 + if (this.future().text !== "[") {
11746 + return null;
11747 + }
11748 + start = this.popToken(); // don't include [ in tokens
11749 + ({ tokens, end } = this.consumeArg(["]"]));
11750 + } else {
11751 + ({ tokens, start, end } = this.consumeArg());
11752 + }
11753 +
11754 + // indicate the end of an argument
11755 + this.pushToken(new Token("EOF", end.loc));
11756 +
11757 + this.pushTokens(tokens);
11758 + return start.range(end, "");
11759 + }
11760 +
11761 + /**
11762 + * Consume all following space tokens, without expansion.
11763 + */
11764 + consumeSpaces() {
11765 + for (;;) {
11766 + const token = this.future();
11767 + if (token.text === " ") {
11768 + this.stack.pop();
11769 + } else {
11770 + break;
11771 + }
11772 + }
11773 + }
11774 +
11775 + /**
11776 + * Consume an argument from the token stream, and return the resulting array
11777 + * of tokens and start/end token.
11778 + */
11779 + consumeArg(delims) {
11780 + // The argument for a delimited parameter is the shortest (possibly
11781 + // empty) sequence of tokens with properly nested {...} groups that is
11782 + // followed ... by this particular list of non-parameter tokens.
11783 + // The argument for an undelimited parameter is the next nonblank
11784 + // token, unless that token is ‘{’, when the argument will be the
11785 + // entire {...} group that follows.
11786 + const tokens = [];
11787 + const isDelimited = delims && delims.length > 0;
11788 + if (!isDelimited) {
11789 + // Ignore spaces between arguments. As the TeXbook says:
11790 + // "After you have said ‘\def\row#1#2{...}’, you are allowed to
11791 + // put spaces between the arguments (e.g., ‘\row x n’), because
11792 + // TeX doesn’t use single spaces as undelimited arguments."
11793 + this.consumeSpaces();
11794 + }
11795 + const start = this.future();
11796 + let tok;
11797 + let depth = 0;
11798 + let match = 0;
11799 + do {
11800 + tok = this.popToken();
11801 + tokens.push(tok);
11802 + if (tok.text === "{") {
11803 + ++depth;
11804 + } else if (tok.text === "}") {
11805 + --depth;
11806 + if (depth === -1) {
11807 + throw new ParseError("Extra }", tok);
11808 + }
11809 + } else if (tok.text === "EOF") {
11810 + throw new ParseError(
11811 + "Unexpected end of input in a macro argument" +
11812 + ", expected '" +
11813 + (delims && isDelimited ? delims[match] : "}") +
11814 + "'",
11815 + tok
11816 + );
11817 + }
11818 + if (delims && isDelimited) {
11819 + if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) {
11820 + ++match;
11821 + if (match === delims.length) {
11822 + // don't include delims in tokens
11823 + tokens.splice(-match, match);
11824 + break;
11825 + }
11826 + } else {
11827 + match = 0;
11828 + }
11829 + }
11830 + } while (depth !== 0 || isDelimited);
11831 + // If the argument found ... has the form ‘{<nested tokens>}’,
11832 + // ... the outermost braces enclosing the argument are removed
11833 + if (start.text === "{" && tokens[tokens.length - 1].text === "}") {
11834 + tokens.pop();
11835 + tokens.shift();
11836 + }
11837 + tokens.reverse(); // to fit in with stack order
11838 + return { tokens, start, end: tok };
11839 + }
11840 +
11841 + /**
11842 + * Consume the specified number of (delimited) arguments from the token
11843 + * stream and return the resulting array of arguments.
11844 + */
11845 + consumeArgs(numArgs, delimiters) {
11846 + if (delimiters) {
11847 + if (delimiters.length !== numArgs + 1) {
11848 + throw new ParseError("The length of delimiters doesn't match the number of args!");
11849 + }
11850 + const delims = delimiters[0];
11851 + for (let i = 0; i < delims.length; i++) {
11852 + const tok = this.popToken();
11853 + if (delims[i] !== tok.text) {
11854 + throw new ParseError("Use of the macro doesn't match its definition", tok);
11855 + }
11856 + }
11857 + }
11858 +
11859 + const args = [];
11860 + for (let i = 0; i < numArgs; i++) {
11861 + args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens);
11862 + }
11863 + return args;
11864 + }
11865 +
11866 + /**
11867 + * Expand the next token only once if possible.
11868 + *
11869 + * If the token is expanded, the resulting tokens will be pushed onto
11870 + * the stack in reverse order, and the number of such tokens will be
11871 + * returned. This number might be zero or positive.
11872 + *
11873 + * If not, the return value is `false`, and the next token remains at the
11874 + * top of the stack.
11875 + *
11876 + * In either case, the next token will be on the top of the stack,
11877 + * or the stack will be empty (in case of empty expansion
11878 + * and no other tokens).
11879 + *
11880 + * Used to implement `expandAfterFuture` and `expandNextToken`.
11881 + *
11882 + * If expandableOnly, only expandable tokens are expanded and
11883 + * an undefined control sequence results in an error.
11884 + */
11885 + expandOnce(expandableOnly) {
11886 + const topToken = this.popToken();
11887 + const name = topToken.text;
11888 + const expansion = !topToken.noexpand ? this._getExpansion(name) : null;
11889 + if (expansion == null || (expandableOnly && expansion.unexpandable)) {
11890 + if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) {
11891 + throw new ParseError("Undefined control sequence: " + name);
11892 + }
11893 + this.pushToken(topToken);
11894 + return false;
11895 + }
11896 + this.expansionCount++;
11897 + if (this.expansionCount > this.settings.maxExpand) {
11898 + throw new ParseError(
11899 + "Too many expansions: infinite loop or " + "need to increase maxExpand setting"
11900 + );
11901 + }
11902 + let tokens = expansion.tokens;
11903 + const args = this.consumeArgs(expansion.numArgs, expansion.delimiters);
11904 + if (expansion.numArgs) {
11905 + // paste arguments in place of the placeholders
11906 + tokens = tokens.slice(); // make a shallow copy
11907 + for (let i = tokens.length - 1; i >= 0; --i) {
11908 + let tok = tokens[i];
11909 + if (tok.text === "#") {
11910 + if (i === 0) {
11911 + throw new ParseError("Incomplete placeholder at end of macro body", tok);
11912 + }
11913 + tok = tokens[--i]; // next token on stack
11914 + if (tok.text === "#") {
11915 + // ## → #
11916 + tokens.splice(i + 1, 1); // drop first #
11917 + } else if (/^[1-9]$/.test(tok.text)) {
11918 + // replace the placeholder with the indicated argument
11919 + tokens.splice(i, 2, ...args[+tok.text - 1]);
11920 + } else {
11921 + throw new ParseError("Not a valid argument number", tok);
11922 + }
11923 + }
11924 + }
11925 + }
11926 + // Concatenate expansion onto top of stack.
11927 + this.pushTokens(tokens);
11928 + return tokens.length;
11929 + }
11930 +
11931 + /**
11932 + * Expand the next token only once (if possible), and return the resulting
11933 + * top token on the stack (without removing anything from the stack).
11934 + * Similar in behavior to TeX's `\expandafter\futurelet`.
11935 + * Equivalent to expandOnce() followed by future().
11936 + */
11937 + expandAfterFuture() {
11938 + this.expandOnce();
11939 + return this.future();
11940 + }
11941 +
11942 + /**
11943 + * Recursively expand first token, then return first non-expandable token.
11944 + */
11945 + expandNextToken() {
11946 + for (;;) {
11947 + if (this.expandOnce() === false) { // fully expanded
11948 + const token = this.stack.pop();
11949 + // The token after \noexpand is interpreted as if its meaning were ‘\relax’
11950 + if (token.treatAsRelax) {
11951 + token.text = "\\relax";
11952 + }
11953 + return token
11954 + }
11955 + }
11956 +
11957 + // This pathway is impossible.
11958 + throw new Error(); // eslint-disable-line no-unreachable
11959 + }
11960 +
11961 + /**
11962 + * Fully expand the given macro name and return the resulting list of
11963 + * tokens, or return `undefined` if no such macro is defined.
11964 + */
11965 + expandMacro(name) {
11966 + return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined;
11967 + }
11968 +
11969 + /**
11970 + * Fully expand the given token stream and return the resulting list of
11971 + * tokens. Note that the input tokens are in reverse order, but the
11972 + * output tokens are in forward order.
11973 + */
11974 + expandTokens(tokens) {
11975 + const output = [];
11976 + const oldStackLength = this.stack.length;
11977 + this.pushTokens(tokens);
11978 + while (this.stack.length > oldStackLength) {
11979 + // Expand only expandable tokens
11980 + if (this.expandOnce(true) === false) { // fully expanded
11981 + const token = this.stack.pop();
11982 + if (token.treatAsRelax) {
11983 + // the expansion of \noexpand is the token itself
11984 + token.noexpand = false;
11985 + token.treatAsRelax = false;
11986 + }
11987 + output.push(token);
11988 + }
11989 + }
11990 + return output;
11991 + }
11992 +
11993 + /**
11994 + * Fully expand the given macro name and return the result as a string,
11995 + * or return `undefined` if no such macro is defined.
11996 + */
11997 + expandMacroAsText(name) {
11998 + const tokens = this.expandMacro(name);
11999 + if (tokens) {
12000 + return tokens.map((token) => token.text).join("");
12001 + } else {
12002 + return tokens;
12003 + }
12004 + }
12005 +
12006 + /**
12007 + * Returns the expanded macro as a reversed array of tokens and a macro
12008 + * argument count. Or returns `null` if no such macro.
12009 + */
12010 + _getExpansion(name) {
12011 + const definition = this.macros.get(name);
12012 + if (definition == null) {
12013 + // mainly checking for undefined here
12014 + return definition;
12015 + }
12016 + // If a single character has an associated catcode other than 13
12017 + // (active character), then don't expand it.
12018 + if (name.length === 1) {
12019 + const catcode = this.lexer.catcodes[name];
12020 + if (catcode != null && catcode !== 13) {
12021 + return
12022 + }
12023 + }
12024 + const expansion = typeof definition === "function" ? definition(this) : definition;
12025 + if (typeof expansion === "string") {
12026 + let numArgs = 0;
12027 + if (expansion.indexOf("#") !== -1) {
12028 + const stripped = expansion.replace(/##/g, "");
12029 + while (stripped.indexOf("#" + (numArgs + 1)) !== -1) {
12030 + ++numArgs;
12031 + }
12032 + }
12033 + const bodyLexer = new Lexer(expansion, this.settings);
12034 + const tokens = [];
12035 + let tok = bodyLexer.lex();
12036 + while (tok.text !== "EOF") {
12037 + tokens.push(tok);
12038 + tok = bodyLexer.lex();
12039 + }
12040 + tokens.reverse(); // to fit in with stack using push and pop
12041 + const expanded = { tokens, numArgs };
12042 + return expanded;
12043 + }
12044 +
12045 + return expansion;
12046 + }
12047 +
12048 + /**
12049 + * Determine whether a command is currently "defined" (has some
12050 + * functionality), meaning that it's a macro (in the current group),
12051 + * a function, a symbol, or one of the special commands listed in
12052 + * `implicitCommands`.
12053 + */
12054 + isDefined(name) {
12055 + return (
12056 + this.macros.has(name) ||
12057 + Object.prototype.hasOwnProperty.call(functions, name ) ||
12058 + Object.prototype.hasOwnProperty.call(symbols.math, name ) ||
12059 + Object.prototype.hasOwnProperty.call(symbols.text, name ) ||
12060 + Object.prototype.hasOwnProperty.call(implicitCommands, name )
12061 + );
12062 + }
12063 +
12064 + /**
12065 + * Determine whether a command is expandable.
12066 + */
12067 + isExpandable(name) {
12068 + const macro = this.macros.get(name);
12069 + return macro != null
12070 + ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable
12071 + : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive;
12072 + }
12073 + }
12074 +
12075 + // Helpers for Parser.js handling of Unicode (sub|super)script characters.
12076 +
12077 + const unicodeSubRegEx = /^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/;
12078 +
12079 + const uSubsAndSups = Object.freeze({
12080 + '₊': '+',
12081 + '₋': '-',
12082 + '₌': '=',
12083 + '₍': '(',
12084 + '₎': ')',
12085 + '₀': '0',
12086 + '₁': '1',
12087 + '₂': '2',
12088 + '₃': '3',
12089 + '₄': '4',
12090 + '₅': '5',
12091 + '₆': '6',
12092 + '₇': '7',
12093 + '₈': '8',
12094 + '₉': '9',
12095 + '\u2090': 'a',
12096 + '\u2091': 'e',
12097 + '\u2095': 'h',
12098 + '\u1D62': 'i',
12099 + '\u2C7C': 'j',
12100 + '\u2096': 'k',
12101 + '\u2097': 'l',
12102 + '\u2098': 'm',
12103 + '\u2099': 'n',
12104 + '\u2092': 'o',
12105 + '\u209A': 'p',
12106 + '\u1D63': 'r',
12107 + '\u209B': 's',
12108 + '\u209C': 't',
12109 + '\u1D64': 'u',
12110 + '\u1D65': 'v',
12111 + '\u2093': 'x',
12112 + '\u1D66': 'β',
12113 + '\u1D67': 'γ',
12114 + '\u1D68': 'ρ',
12115 + '\u1D69': '\u03d5',
12116 + '\u1D6A': 'χ',
12117 + '⁺': '+',
12118 + '⁻': '-',
12119 + '⁼': '=',
12120 + '⁽': '(',
12121 + '⁾': ')',
12122 + '⁰': '0',
12123 + '¹': '1',
12124 + '²': '2',
12125 + '³': '3',
12126 + '⁴': '4',
12127 + '⁵': '5',
12128 + '⁶': '6',
12129 + '⁷': '7',
12130 + '⁸': '8',
12131 + '⁹': '9',
12132 + '\u1D2C': 'A',
12133 + '\u1D2E': 'B',
12134 + '\u1D30': 'D',
12135 + '\u1D31': 'E',
12136 + '\u1D33': 'G',
12137 + '\u1D34': 'H',
12138 + '\u1D35': 'I',
12139 + '\u1D36': 'J',
12140 + '\u1D37': 'K',
12141 + '\u1D38': 'L',
12142 + '\u1D39': 'M',
12143 + '\u1D3A': 'N',
12144 + '\u1D3C': 'O',
12145 + '\u1D3E': 'P',
12146 + '\u1D3F': 'R',
12147 + '\u1D40': 'T',
12148 + '\u1D41': 'U',
12149 + '\u2C7D': 'V',
12150 + '\u1D42': 'W',
12151 + '\u1D43': 'a',
12152 + '\u1D47': 'b',
12153 + '\u1D9C': 'c',
12154 + '\u1D48': 'd',
12155 + '\u1D49': 'e',
12156 + '\u1DA0': 'f',
12157 + '\u1D4D': 'g',
12158 + '\u02B0': 'h',
12159 + '\u2071': 'i',
12160 + '\u02B2': 'j',
12161 + '\u1D4F': 'k',
12162 + '\u02E1': 'l',
12163 + '\u1D50': 'm',
12164 + '\u207F': 'n',
12165 + '\u1D52': 'o',
12166 + '\u1D56': 'p',
12167 + '\u02B3': 'r',
12168 + '\u02E2': 's',
12169 + '\u1D57': 't',
12170 + '\u1D58': 'u',
12171 + '\u1D5B': 'v',
12172 + '\u02B7': 'w',
12173 + '\u02E3': 'x',
12174 + '\u02B8': 'y',
12175 + '\u1DBB': 'z',
12176 + '\u1D5D': 'β',
12177 + '\u1D5E': 'γ',
12178 + '\u1D5F': 'δ',
12179 + '\u1D60': '\u03d5',
12180 + '\u1D61': 'χ',
12181 + '\u1DBF': 'θ'
12182 + });
12183 +
12184 + // Used for Unicode input of calligraphic and script letters
12185 + const asciiFromScript = Object.freeze({
12186 + "\ud835\udc9c": "A",
12187 + "\u212c": "B",
12188 + "\ud835\udc9e": "C",
12189 + "\ud835\udc9f": "D",
12190 + "\u2130": "E",
12191 + "\u2131": "F",
12192 + "\ud835\udca2": "G",
12193 + "\u210B": "H",
12194 + "\u2110": "I",
12195 + "\ud835\udca5": "J",
12196 + "\ud835\udca6": "K",
12197 + "\u2112": "L",
12198 + "\u2133": "M",
12199 + "\ud835\udca9": "N",
12200 + "\ud835\udcaa": "O",
12201 + "\ud835\udcab": "P",
12202 + "\ud835\udcac": "Q",
12203 + "\u211B": "R",
12204 + "\ud835\udcae": "S",
12205 + "\ud835\udcaf": "T",
12206 + "\ud835\udcb0": "U",
12207 + "\ud835\udcb1": "V",
12208 + "\ud835\udcb2": "W",
12209 + "\ud835\udcb3": "X",
12210 + "\ud835\udcb4": "Y",
12211 + "\ud835\udcb5": "Z"
12212 + });
12213 +
12214 + // Mapping of Unicode accent characters to their LaTeX equivalent in text and
12215 + // math mode (when they exist).
12216 + var unicodeAccents = {
12217 + "\u0301": { text: "\\'", math: "\\acute" },
12218 + "\u0300": { text: "\\`", math: "\\grave" },
12219 + "\u0308": { text: '\\"', math: "\\ddot" },
12220 + "\u0303": { text: "\\~", math: "\\tilde" },
12221 + "\u0304": { text: "\\=", math: "\\bar" },
12222 + "\u0306": { text: "\\u", math: "\\breve" },
12223 + "\u030c": { text: "\\v", math: "\\check" },
12224 + "\u0302": { text: "\\^", math: "\\hat" },
12225 + "\u0307": { text: "\\.", math: "\\dot" },
12226 + "\u030a": { text: "\\r", math: "\\mathring" },
12227 + "\u030b": { text: "\\H" },
12228 + '\u0327': { text: '\\c' }
12229 + };
12230 +
12231 + var unicodeSymbols = {
12232 + "á": "á",
12233 + "à": "à",
12234 + "ä": "ä",
12235 + "ǟ": "ǟ",
12236 + "ã": "ã",
12237 + "ā": "ā",
12238 + "ă": "ă",
12239 + "ắ": "ắ",
12240 + "ằ": "ằ",
12241 + "ẵ": "ẵ",
12242 + "ǎ": "ǎ",
12243 + "â": "â",
12244 + "ấ": "ấ",
12245 + "ầ": "ầ",
12246 + "ẫ": "ẫ",
12247 + "ȧ": "ȧ",
12248 + "ǡ": "ǡ",
12249 + "å": "å",
12250 + "ǻ": "ǻ",
12251 + "ḃ": "ḃ",
12252 + "ć": "ć",
12253 + "č": "č",
12254 + "ĉ": "ĉ",
12255 + "ċ": "ċ",
12256 + "ď": "ď",
12257 + "ḋ": "ḋ",
12258 + "é": "é",
12259 + "è": "è",
12260 + "ë": "ë",
12261 + "ẽ": "ẽ",
12262 + "ē": "ē",
12263 + "ḗ": "ḗ",
12264 + "ḕ": "ḕ",
12265 + "ĕ": "ĕ",
12266 + "ě": "ě",
12267 + "ê": "ê",
12268 + "ế": "ế",
12269 + "ề": "ề",
12270 + "ễ": "ễ",
12271 + "ė": "ė",
12272 + "ḟ": "ḟ",
12273 + "ǵ": "ǵ",
12274 + "ḡ": "ḡ",
12275 + "ğ": "ğ",
12276 + "ǧ": "ǧ",
12277 + "ĝ": "ĝ",
12278 + "ġ": "ġ",
12279 + "ḧ": "ḧ",
12280 + "ȟ": "ȟ",
12281 + "ĥ": "ĥ",
12282 + "ḣ": "ḣ",
12283 + "í": "í",
12284 + "ì": "ì",
12285 + "ï": "ï",
12286 + "ḯ": "ḯ",
12287 + "ĩ": "ĩ",
12288 + "ī": "ī",
12289 + "ĭ": "ĭ",
12290 + "ǐ": "ǐ",
12291 + "î": "î",
12292 + "ǰ": "ǰ",
12293 + "ĵ": "ĵ",
12294 + "ḱ": "ḱ",
12295 + "ǩ": "ǩ",
12296 + "ĺ": "ĺ",
12297 + "ľ": "ľ",
12298 + "ḿ": "ḿ",
12299 + "ṁ": "ṁ",
12300 + "ń": "ń",
12301 + "ǹ": "ǹ",
12302 + "ñ": "ñ",
12303 + "ň": "ň",
12304 + "ṅ": "ṅ",
12305 + "ó": "ó",
12306 + "ò": "ò",
12307 + "ö": "ö",
12308 + "ȫ": "ȫ",
12309 + "õ": "õ",
12310 + "ṍ": "ṍ",
12311 + "ṏ": "ṏ",
12312 + "ȭ": "ȭ",
12313 + "ō": "ō",
12314 + "ṓ": "ṓ",
12315 + "ṑ": "ṑ",
12316 + "ŏ": "ŏ",
12317 + "ǒ": "ǒ",
12318 + "ô": "ô",
12319 + "ố": "ố",
12320 + "ồ": "ồ",
12321 + "ỗ": "ỗ",
12322 + "ȯ": "ȯ",
12323 + "ȱ": "ȱ",
12324 + "ő": "ő",
12325 + "ṕ": "ṕ",
12326 + "ṗ": "ṗ",
12327 + "ŕ": "ŕ",
12328 + "ř": "ř",
12329 + "ṙ": "ṙ",
12330 + "ś": "ś",
12331 + "ṥ": "ṥ",
12332 + "š": "š",
12333 + "ṧ": "ṧ",
12334 + "ŝ": "ŝ",
12335 + "ṡ": "ṡ",
12336 + "ẗ": "ẗ",
12337 + "ť": "ť",
12338 + "ṫ": "ṫ",
12339 + "ú": "ú",
12340 + "ù": "ù",
12341 + "ü": "ü",
12342 + "ǘ": "ǘ",
12343 + "ǜ": "ǜ",
12344 + "ǖ": "ǖ",
12345 + "ǚ": "ǚ",
12346 + "ũ": "ũ",
12347 + "ṹ": "ṹ",
12348 + "ū": "ū",
12349 + "ṻ": "ṻ",
12350 + "ŭ": "ŭ",
12351 + "ǔ": "ǔ",
12352 + "û": "û",
12353 + "ů": "ů",
12354 + "ű": "ű",
12355 + "ṽ": "ṽ",
12356 + "ẃ": "ẃ",
12357 + "ẁ": "ẁ",
12358 + "ẅ": "ẅ",
12359 + "ŵ": "ŵ",
12360 + "ẇ": "ẇ",
12361 + "ẘ": "ẘ",
12362 + "ẍ": "ẍ",
12363 + "ẋ": "ẋ",
12364 + "ý": "ý",
12365 + "ỳ": "ỳ",
12366 + "ÿ": "ÿ",
12367 + "ỹ": "ỹ",
12368 + "ȳ": "ȳ",
12369 + "ŷ": "ŷ",
12370 + "ẏ": "ẏ",
12371 + "ẙ": "ẙ",
12372 + "ź": "ź",
12373 + "ž": "ž",
12374 + "ẑ": "ẑ",
12375 + "ż": "ż",
12376 + "Á": "Á",
12377 + "À": "À",
12378 + "Ä": "Ä",
12379 + "Ǟ": "Ǟ",
12380 + "Ã": "Ã",
12381 + "Ā": "Ā",
12382 + "Ă": "Ă",
12383 + "Ắ": "Ắ",
12384 + "Ằ": "Ằ",
12385 + "Ẵ": "Ẵ",
12386 + "Ǎ": "Ǎ",
12387 + "Â": "Â",
12388 + "Ấ": "Ấ",
12389 + "Ầ": "Ầ",
12390 + "Ẫ": "Ẫ",
12391 + "Ȧ": "Ȧ",
12392 + "Ǡ": "Ǡ",
12393 + "Å": "Å",
12394 + "Ǻ": "Ǻ",
12395 + "Ḃ": "Ḃ",
12396 + "Ć": "Ć",
12397 + "Č": "Č",
12398 + "Ĉ": "Ĉ",
12399 + "Ċ": "Ċ",
12400 + "Ď": "Ď",
12401 + "Ḋ": "Ḋ",
12402 + "É": "É",
12403 + "È": "È",
12404 + "Ë": "Ë",
12405 + "Ẽ": "Ẽ",
12406 + "Ē": "Ē",
12407 + "Ḗ": "Ḗ",
12408 + "Ḕ": "Ḕ",
12409 + "Ĕ": "Ĕ",
12410 + "Ě": "Ě",
12411 + "Ê": "Ê",
12412 + "Ế": "Ế",
12413 + "Ề": "Ề",
12414 + "Ễ": "Ễ",
12415 + "Ė": "Ė",
12416 + "Ḟ": "Ḟ",
12417 + "Ǵ": "Ǵ",
12418 + "Ḡ": "Ḡ",
12419 + "Ğ": "Ğ",
12420 + "Ǧ": "Ǧ",
12421 + "Ĝ": "Ĝ",
12422 + "Ġ": "Ġ",
12423 + "Ḧ": "Ḧ",
12424 + "Ȟ": "Ȟ",
12425 + "Ĥ": "Ĥ",
12426 + "Ḣ": "Ḣ",
12427 + "Í": "Í",
12428 + "Ì": "Ì",
12429 + "Ï": "Ï",
12430 + "Ḯ": "Ḯ",
12431 + "Ĩ": "Ĩ",
12432 + "Ī": "Ī",
12433 + "Ĭ": "Ĭ",
12434 + "Ǐ": "Ǐ",
12435 + "Î": "Î",
12436 + "İ": "İ",
12437 + "Ĵ": "Ĵ",
12438 + "Ḱ": "Ḱ",
12439 + "Ǩ": "Ǩ",
12440 + "Ĺ": "Ĺ",
12441 + "Ľ": "Ľ",
12442 + "Ḿ": "Ḿ",
12443 + "Ṁ": "Ṁ",
12444 + "Ń": "Ń",
12445 + "Ǹ": "Ǹ",
12446 + "Ñ": "Ñ",
12447 + "Ň": "Ň",
12448 + "Ṅ": "Ṅ",
12449 + "Ó": "Ó",
12450 + "Ò": "Ò",
12451 + "Ö": "Ö",
12452 + "Ȫ": "Ȫ",
12453 + "Õ": "Õ",
12454 + "Ṍ": "Ṍ",
12455 + "Ṏ": "Ṏ",
12456 + "Ȭ": "Ȭ",
12457 + "Ō": "Ō",
12458 + "Ṓ": "Ṓ",
12459 + "Ṑ": "Ṑ",
12460 + "Ŏ": "Ŏ",
12461 + "Ǒ": "Ǒ",
12462 + "Ô": "Ô",
12463 + "Ố": "Ố",
12464 + "Ồ": "Ồ",
12465 + "Ỗ": "Ỗ",
12466 + "Ȯ": "Ȯ",
12467 + "Ȱ": "Ȱ",
12468 + "Ő": "Ő",
12469 + "Ṕ": "Ṕ",
12470 + "Ṗ": "Ṗ",
12471 + "Ŕ": "Ŕ",
12472 + "Ř": "Ř",
12473 + "Ṙ": "Ṙ",
12474 + "Ś": "Ś",
12475 + "Ṥ": "Ṥ",
12476 + "Š": "Š",
12477 + "Ṧ": "Ṧ",
12478 + "Ŝ": "Ŝ",
12479 + "Ṡ": "Ṡ",
12480 + "Ť": "Ť",
12481 + "Ṫ": "Ṫ",
12482 + "Ú": "Ú",
12483 + "Ù": "Ù",
12484 + "Ü": "Ü",
12485 + "Ǘ": "Ǘ",
12486 + "Ǜ": "Ǜ",
12487 + "Ǖ": "Ǖ",
12488 + "Ǚ": "Ǚ",
12489 + "Ũ": "Ũ",
12490 + "Ṹ": "Ṹ",
12491 + "Ū": "Ū",
12492 + "Ṻ": "Ṻ",
12493 + "Ŭ": "Ŭ",
12494 + "Ǔ": "Ǔ",
12495 + "Û": "Û",
12496 + "Ů": "Ů",
12497 + "Ű": "Ű",
12498 + "Ṽ": "Ṽ",
12499 + "Ẃ": "Ẃ",
12500 + "Ẁ": "Ẁ",
12501 + "Ẅ": "Ẅ",
12502 + "Ŵ": "Ŵ",
12503 + "Ẇ": "Ẇ",
12504 + "Ẍ": "Ẍ",
12505 + "Ẋ": "Ẋ",
12506 + "Ý": "Ý",
12507 + "Ỳ": "Ỳ",
12508 + "Ÿ": "Ÿ",
12509 + "Ỹ": "Ỹ",
12510 + "Ȳ": "Ȳ",
12511 + "Ŷ": "Ŷ",
12512 + "Ẏ": "Ẏ",
12513 + "Ź": "Ź",
12514 + "Ž": "Ž",
12515 + "Ẑ": "Ẑ",
12516 + "Ż": "Ż",
12517 + "ά": "ά",
12518 + "ὰ": "ὰ",
12519 + "ᾱ": "ᾱ",
12520 + "ᾰ": "ᾰ",
12521 + "έ": "έ",
12522 + "ὲ": "ὲ",
12523 + "ή": "ή",
12524 + "ὴ": "ὴ",
12525 + "ί": "ί",
12526 + "ὶ": "ὶ",
12527 + "ϊ": "ϊ",
12528 + "ΐ": "ΐ",
12529 + "ῒ": "ῒ",
12530 + "ῑ": "ῑ",
12531 + "ῐ": "ῐ",
12532 + "ό": "ό",
12533 + "ὸ": "ὸ",
12534 + "ύ": "ύ",
12535 + "ὺ": "ὺ",
12536 + "ϋ": "ϋ",
12537 + "ΰ": "ΰ",
12538 + "ῢ": "ῢ",
12539 + "ῡ": "ῡ",
12540 + "ῠ": "ῠ",
12541 + "ώ": "ώ",
12542 + "ὼ": "ὼ",
12543 + "Ύ": "Ύ",
12544 + "Ὺ": "Ὺ",
12545 + "Ϋ": "Ϋ",
12546 + "Ῡ": "Ῡ",
12547 + "Ῠ": "Ῠ",
12548 + "Ώ": "Ώ",
12549 + "Ὼ": "Ὼ"
12550 + };
12551 +
12552 + /* eslint no-constant-condition:0 */
12553 +
12554 + const binLeftCancellers = ["bin", "op", "open", "punct", "rel"];
12555 + const sizeRegEx = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/;
12556 +
12557 + /**
12558 + * This file contains the parser used to parse out a TeX expression from the
12559 + * input. Since TeX isn't context-free, standard parsers don't work particularly
12560 + * well.
12561 + *
12562 + * The strategy of this parser is as such:
12563 + *
12564 + * The main functions (the `.parse...` ones) take a position in the current
12565 + * parse string to parse tokens from. The lexer (found in Lexer.js, stored at
12566 + * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When
12567 + * individual tokens are needed at a position, the lexer is called to pull out a
12568 + * token, which is then used.
12569 + *
12570 + * The parser has a property called "mode" indicating the mode that
12571 + * the parser is currently in. Currently it has to be one of "math" or
12572 + * "text", which denotes whether the current environment is a math-y
12573 + * one or a text-y one (e.g. inside \text). Currently, this serves to
12574 + * limit the functions which can be used in text mode.
12575 + *
12576 + * The main functions then return an object which contains the useful data that
12577 + * was parsed at its given point, and a new position at the end of the parsed
12578 + * data. The main functions can call each other and continue the parsing by
12579 + * using the returned position as a new starting point.
12580 + *
12581 + * There are also extra `.handle...` functions, which pull out some reused
12582 + * functionality into self-contained functions.
12583 + *
12584 + * The functions return ParseNodes.
12585 + */
12586 +
12587 + class Parser {
12588 + constructor(input, settings, isPreamble = false) {
12589 + // Start in math mode
12590 + this.mode = "math";
12591 + // Create a new macro expander (gullet) and (indirectly via that) also a
12592 + // new lexer (mouth) for this parser (stomach, in the language of TeX)
12593 + this.gullet = new MacroExpander(input, settings, this.mode);
12594 + // Store the settings for use in parsing
12595 + this.settings = settings;
12596 + // Are we defining a preamble?
12597 + this.isPreamble = isPreamble;
12598 + // Count leftright depth (for \middle errors)
12599 + this.leftrightDepth = 0;
12600 + this.prevAtomType = "";
12601 + }
12602 +
12603 + /**
12604 + * Checks a result to make sure it has the right type, and throws an
12605 + * appropriate error otherwise.
12606 + */
12607 + expect(text, consume = true) {
12608 + if (this.fetch().text !== text) {
12609 + throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch());
12610 + }
12611 + if (consume) {
12612 + this.consume();
12613 + }
12614 + }
12615 +
12616 + /**
12617 + * Discards the current lookahead token, considering it consumed.
12618 + */
12619 + consume() {
12620 + this.nextToken = null;
12621 + }
12622 +
12623 + /**
12624 + * Return the current lookahead token, or if there isn't one (at the
12625 + * beginning, or if the previous lookahead token was consume()d),
12626 + * fetch the next token as the new lookahead token and return it.
12627 + */
12628 + fetch() {
12629 + if (this.nextToken == null) {
12630 + this.nextToken = this.gullet.expandNextToken();
12631 + }
12632 + return this.nextToken;
12633 + }
12634 +
12635 + /**
12636 + * Switches between "text" and "math" modes.
12637 + */
12638 + switchMode(newMode) {
12639 + this.mode = newMode;
12640 + this.gullet.switchMode(newMode);
12641 + }
12642 +
12643 + /**
12644 + * Main parsing function, which parses an entire input.
12645 + */
12646 + parse() {
12647 + // Create a group namespace for every $...$, $$...$$, \[...\].)
12648 + // A \def is then valid only within that pair of delimiters.
12649 + this.gullet.beginGroup();
12650 +
12651 + if (this.settings.colorIsTextColor) {
12652 + // Use old \color behavior (same as LaTeX's \textcolor) if requested.
12653 + // We do this within the group for the math expression, so it doesn't
12654 + // pollute settings.macros.
12655 + this.gullet.macros.set("\\color", "\\textcolor");
12656 + }
12657 +
12658 + // Try to parse the input
12659 + const parse = this.parseExpression(false);
12660 +
12661 + // If we succeeded, make sure there's an EOF at the end
12662 + this.expect("EOF");
12663 +
12664 + if (this.isPreamble) {
12665 + const macros = Object.create(null);
12666 + Object.entries(this.gullet.macros.current).forEach(([key, value]) => {
12667 + macros[key] = value;
12668 + });
12669 + this.gullet.endGroup();
12670 + return macros
12671 + }
12672 +
12673 + // The only local macro that we want to save is from \tag.
12674 + const tag = this.gullet.macros.get("\\df@tag");
12675 +
12676 + // End the group namespace for the expression
12677 + this.gullet.endGroup();
12678 +
12679 + if (tag) { this.gullet.macros.current["\\df@tag"] = tag; }
12680 +
12681 + return parse;
12682 + }
12683 +
12684 + static get endOfExpression() {
12685 + return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"];
12686 + }
12687 +
12688 + /**
12689 + * Fully parse a separate sequence of tokens as a separate job.
12690 + * Tokens should be specified in reverse order, as in a MacroDefinition.
12691 + */
12692 + subparse(tokens) {
12693 + // Save the next token from the current job.
12694 + const oldToken = this.nextToken;
12695 + this.consume();
12696 +
12697 + // Run the new job, terminating it with an excess '}'
12698 + this.gullet.pushToken(new Token("}"));
12699 + this.gullet.pushTokens(tokens);
12700 + const parse = this.parseExpression(false);
12701 + this.expect("}");
12702 +
12703 + // Restore the next token from the current job.
12704 + this.nextToken = oldToken;
12705 +
12706 + return parse;
12707 + }
12708 +
12709 + /**
12710 + * Parses an "expression", which is a list of atoms.
12711 + *
12712 + * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
12713 + * happens when functions have higher precedence han infix
12714 + * nodes in implicit parses.
12715 + *
12716 + * `breakOnTokenText`: The text of the token that the expression should end
12717 + * with, or `null` if something else should end the
12718 + * expression.
12719 + *
12720 + * `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group.
12721 + * These groups end just before the usual tokens, but they also
12722 + * end just before `\middle`.
12723 + */
12724 + parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) {
12725 + const body = [];
12726 + this.prevAtomType = "";
12727 + // Keep adding atoms to the body until we can't parse any more atoms (either
12728 + // we reached the end, a }, or a \right)
12729 + while (true) {
12730 + // Ignore spaces in math mode
12731 + if (this.mode === "math") {
12732 + this.consumeSpaces();
12733 + }
12734 + const lex = this.fetch();
12735 + if (Parser.endOfExpression.indexOf(lex.text) !== -1) {
12736 + break;
12737 + }
12738 + if (breakOnTokenText && lex.text === breakOnTokenText) {
12739 + break;
12740 + }
12741 + if (breakOnMiddle && lex.text === "\\middle") {
12742 + break
12743 + }
12744 + if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
12745 + break;
12746 + }
12747 + const atom = this.parseAtom(breakOnTokenText);
12748 + if (!atom) {
12749 + break;
12750 + } else if (atom.type === "internal") {
12751 + continue;
12752 + }
12753 + body.push(atom);
12754 + // Keep a record of the atom type, so that op.js can set correct spacing.
12755 + this.prevAtomType = atom.type === "atom" ? atom.family : atom.type;
12756 + }
12757 + if (this.mode === "text") {
12758 + this.formLigatures(body);
12759 + }
12760 + return this.handleInfixNodes(body);
12761 + }
12762 +
12763 + /**
12764 + * Rewrites infix operators such as \over with corresponding commands such
12765 + * as \frac.
12766 + *
12767 + * There can only be one infix operator per group. If there's more than one
12768 + * then the expression is ambiguous. This can be resolved by adding {}.
12769 + */
12770 + handleInfixNodes(body) {
12771 + let overIndex = -1;
12772 + let funcName;
12773 +
12774 + for (let i = 0; i < body.length; i++) {
12775 + if (body[i].type === "infix") {
12776 + if (overIndex !== -1) {
12777 + throw new ParseError("only one infix operator per group", body[i].token);
12778 + }
12779 + overIndex = i;
12780 + funcName = body[i].replaceWith;
12781 + }
12782 + }
12783 +
12784 + if (overIndex !== -1 && funcName) {
12785 + let numerNode;
12786 + let denomNode;
12787 +
12788 + const numerBody = body.slice(0, overIndex);
12789 + const denomBody = body.slice(overIndex + 1);
12790 +
12791 + if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
12792 + numerNode = numerBody[0];
12793 + } else {
12794 + numerNode = { type: "ordgroup", mode: this.mode, body: numerBody };
12795 + }
12796 +
12797 + if (denomBody.length === 1 && denomBody[0].type === "ordgroup") {
12798 + denomNode = denomBody[0];
12799 + } else {
12800 + denomNode = { type: "ordgroup", mode: this.mode, body: denomBody };
12801 + }
12802 +
12803 + let node;
12804 + if (funcName === "\\\\abovefrac") {
12805 + node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []);
12806 + } else {
12807 + node = this.callFunction(funcName, [numerNode, denomNode], []);
12808 + }
12809 + return [node];
12810 + } else {
12811 + return body;
12812 + }
12813 + }
12814 +
12815 + /**
12816 + * Handle a subscript or superscript with nice errors.
12817 + */
12818 + handleSupSubscript(
12819 + name // For error reporting.
12820 + ) {
12821 + const symbolToken = this.fetch();
12822 + const symbol = symbolToken.text;
12823 + this.consume();
12824 + this.consumeSpaces(); // ignore spaces before sup/subscript argument
12825 + const group = this.parseGroup(name);
12826 +
12827 + if (!group) {
12828 + throw new ParseError("Expected group after '" + symbol + "'", symbolToken);
12829 + }
12830 +
12831 + return group;
12832 + }
12833 +
12834 + /**
12835 + * Converts the textual input of an unsupported command into a text node
12836 + * contained within a color node whose color is determined by errorColor
12837 + */
12838 + formatUnsupportedCmd(text) {
12839 + const textordArray = [];
12840 +
12841 + for (let i = 0; i < text.length; i++) {
12842 + textordArray.push({ type: "textord", mode: "text", text: text[i] });
12843 + }
12844 +
12845 + const textNode = {
12846 + type: "text",
12847 + mode: this.mode,
12848 + body: textordArray
12849 + };
12850 +
12851 + const colorNode = {
12852 + type: "color",
12853 + mode: this.mode,
12854 + color: this.settings.errorColor,
12855 + body: [textNode]
12856 + };
12857 +
12858 + return colorNode;
12859 + }
12860 +
12861 + /**
12862 + * Parses a group with optional super/subscripts.
12863 + */
12864 + parseAtom(breakOnTokenText) {
12865 + // The body of an atom is an implicit group, so that things like
12866 + // \left(x\right)^2 work correctly.
12867 + const base = this.parseGroup("atom", breakOnTokenText);
12868 +
12869 + // In text mode, we don't have superscripts or subscripts
12870 + if (this.mode === "text") {
12871 + return base;
12872 + }
12873 +
12874 + // Note that base may be empty (i.e. null) at this point.
12875 +
12876 + let superscript;
12877 + let subscript;
12878 + while (true) {
12879 + // Guaranteed in math mode, so eat any spaces first.
12880 + this.consumeSpaces();
12881 +
12882 + // Lex the first token
12883 + const lex = this.fetch();
12884 +
12885 + if (lex.text === "\\limits" || lex.text === "\\nolimits") {
12886 + // We got a limit control
12887 + if (base && base.type === "op") {
12888 + const limits = lex.text === "\\limits";
12889 + base.limits = limits;
12890 + base.alwaysHandleSupSub = true;
12891 + } else if (base && base.type === "operatorname") {
12892 + if (base.alwaysHandleSupSub) {
12893 + base.limits = lex.text === "\\limits";
12894 + }
12895 + } else {
12896 + throw new ParseError("Limit controls must follow a math operator", lex);
12897 + }
12898 + this.consume();
12899 + } else if (lex.text === "^") {
12900 + // We got a superscript start
12901 + if (superscript) {
12902 + throw new ParseError("Double superscript", lex);
12903 + }
12904 + superscript = this.handleSupSubscript("superscript");
12905 + } else if (lex.text === "_") {
12906 + // We got a subscript start
12907 + if (subscript) {
12908 + throw new ParseError("Double subscript", lex);
12909 + }
12910 + subscript = this.handleSupSubscript("subscript");
12911 + } else if (lex.text === "'") {
12912 + // We got a prime
12913 + if (superscript) {
12914 + throw new ParseError("Double superscript", lex);
12915 + }
12916 + const prime = { type: "textord", mode: this.mode, text: "\\prime" };
12917 +
12918 + // Many primes can be grouped together, so we handle this here
12919 + const primes = [prime];
12920 + this.consume();
12921 + // Keep lexing tokens until we get something that's not a prime
12922 + while (this.fetch().text === "'") {
12923 + // For each one, add another prime to the list
12924 + primes.push(prime);
12925 + this.consume();
12926 + }
12927 + // If there's a superscript following the primes, combine that
12928 + // superscript in with the primes.
12929 + if (this.fetch().text === "^") {
12930 + primes.push(this.handleSupSubscript("superscript"));
12931 + }
12932 + // Put everything into an ordgroup as the superscript
12933 + superscript = { type: "ordgroup", mode: this.mode, body: primes };
12934 + } else if (uSubsAndSups[lex.text]) {
12935 + // A Unicode subscript or superscript character.
12936 + // We treat these similarly to the unicode-math package.
12937 + // So we render a string of Unicode (sub|super)scripts the
12938 + // same as a (sub|super)script of regular characters.
12939 + const isSub = unicodeSubRegEx.test(lex.text);
12940 + const subsupTokens = [];
12941 + subsupTokens.push(new Token(uSubsAndSups[lex.text]));
12942 + this.consume();
12943 + // Continue fetching tokens to fill out the group.
12944 + while (true) {
12945 + const token = this.fetch().text;
12946 + if (!(uSubsAndSups[token])) { break }
12947 + if (unicodeSubRegEx.test(token) !== isSub) { break }
12948 + subsupTokens.unshift(new Token(uSubsAndSups[token]));
12949 + this.consume();
12950 + }
12951 + // Now create a (sub|super)script.
12952 + const body = this.subparse(subsupTokens);
12953 + if (isSub) {
12954 + subscript = { type: "ordgroup", mode: "math", body };
12955 + } else {
12956 + superscript = { type: "ordgroup", mode: "math", body };
12957 + }
12958 + } else {
12959 + // If it wasn't ^, _, a Unicode (sub|super)script, or ', stop parsing super/subscripts
12960 + break;
12961 + }
12962 + }
12963 +
12964 + if (superscript || subscript) {
12965 + if (base && base.type === "multiscript" && !base.postscripts) {
12966 + // base is the result of a \prescript function.
12967 + // Write the sub- & superscripts into the multiscript element.
12968 + base.postscripts = { sup: superscript, sub: subscript };
12969 + return base
12970 + } else {
12971 + // We got either a superscript or subscript, create a supsub
12972 + const isFollowedByDelimiter = (!base || base.type !== "op" && base.type !== "operatorname")
12973 + ? undefined
12974 + : isDelimiter(this.nextToken.text);
12975 + return {
12976 + type: "supsub",
12977 + mode: this.mode,
12978 + base: base,
12979 + sup: superscript,
12980 + sub: subscript,
12981 + isFollowedByDelimiter
12982 + }
12983 + }
12984 + } else {
12985 + // Otherwise return the original body
12986 + return base;
12987 + }
12988 + }
12989 +
12990 + /**
12991 + * Parses an entire function, including its base and all of its arguments.
12992 + */
12993 + parseFunction(
12994 + breakOnTokenText,
12995 + name // For determining its context
12996 + ) {
12997 + const token = this.fetch();
12998 + const func = token.text;
12999 + const funcData = functions[func];
13000 + if (!funcData) {
13001 + return null;
13002 + }
13003 + this.consume(); // consume command token
13004 +
13005 + if (name && name !== "atom" && !funcData.allowedInArgument) {
13006 + throw new ParseError(
13007 + "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""),
13008 + token
13009 + );
13010 + } else if (this.mode === "text" && !funcData.allowedInText) {
13011 + throw new ParseError("Can't use function '" + func + "' in text mode", token);
13012 + } else if (this.mode === "math" && funcData.allowedInMath === false) {
13013 + throw new ParseError("Can't use function '" + func + "' in math mode", token);
13014 + }
13015 +
13016 + const prevAtomType = this.prevAtomType;
13017 + const { args, optArgs } = this.parseArguments(func, funcData);
13018 + this.prevAtomType = prevAtomType;
13019 + return this.callFunction(func, args, optArgs, token, breakOnTokenText);
13020 + }
13021 +
13022 + /**
13023 + * Call a function handler with a suitable context and arguments.
13024 + */
13025 + callFunction(name, args, optArgs, token, breakOnTokenText) {
13026 + const context = {
13027 + funcName: name,
13028 + parser: this,
13029 + token,
13030 + breakOnTokenText
13031 + };
13032 + const func = functions[name];
13033 + if (func && func.handler) {
13034 + return func.handler(context, args, optArgs);
13035 + } else {
13036 + throw new ParseError(`No function handler for ${name}`);
13037 + }
13038 + }
13039 +
13040 + /**
13041 + * Parses the arguments of a function or environment
13042 + */
13043 + parseArguments(
13044 + func, // Should look like "\name" or "\begin{name}".
13045 + funcData
13046 + ) {
13047 + const totalArgs = funcData.numArgs + funcData.numOptionalArgs;
13048 + if (totalArgs === 0) {
13049 + return { args: [], optArgs: [] };
13050 + }
13051 +
13052 + const args = [];
13053 + const optArgs = [];
13054 +
13055 + for (let i = 0; i < totalArgs; i++) {
13056 + let argType = funcData.argTypes && funcData.argTypes[i];
13057 + const isOptional = i < funcData.numOptionalArgs;
13058 +
13059 + if (
13060 + (funcData.primitive && argType == null) ||
13061 + // \sqrt expands into primitive if optional argument doesn't exist
13062 + (funcData.type === "sqrt" && i === 1 && optArgs[0] == null)
13063 + ) {
13064 + argType = "primitive";
13065 + }
13066 +
13067 + const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional);
13068 + if (isOptional) {
13069 + optArgs.push(arg);
13070 + } else if (arg != null) {
13071 + args.push(arg);
13072 + } else {
13073 + // should be unreachable
13074 + throw new ParseError("Null argument, please report this as a bug");
13075 + }
13076 + }
13077 +
13078 + return { args, optArgs };
13079 + }
13080 +
13081 + /**
13082 + * Parses a group when the mode is changing.
13083 + */
13084 + parseGroupOfType(name, type, optional) {
13085 + switch (type) {
13086 + case "size":
13087 + return this.parseSizeGroup(optional);
13088 + case "url":
13089 + return this.parseUrlGroup(optional);
13090 + case "math":
13091 + case "text":
13092 + return this.parseArgumentGroup(optional, type);
13093 + case "hbox": {
13094 + // hbox argument type wraps the argument in the equivalent of
13095 + // \hbox, which is like \text but switching to \textstyle size.
13096 + const group = this.parseArgumentGroup(optional, "text");
13097 + return group != null
13098 + ? {
13099 + type: "styling",
13100 + mode: group.mode,
13101 + body: [group],
13102 + scriptLevel: "text" // simulate \textstyle
13103 + }
13104 + : null;
13105 + }
13106 + case "raw": {
13107 + const token = this.parseStringGroup("raw", optional);
13108 + return token != null
13109 + ? {
13110 + type: "raw",
13111 + mode: "text",
13112 + string: token.text
13113 + }
13114 + : null;
13115 + }
13116 + case "primitive": {
13117 + if (optional) {
13118 + throw new ParseError("A primitive argument cannot be optional");
13119 + }
13120 + const group = this.parseGroup(name);
13121 + if (group == null) {
13122 + throw new ParseError("Expected group as " + name, this.fetch());
13123 + }
13124 + return group;
13125 + }
13126 + case "original":
13127 + case null:
13128 + case undefined:
13129 + return this.parseArgumentGroup(optional);
13130 + default:
13131 + throw new ParseError("Unknown group type as " + name, this.fetch());
13132 + }
13133 + }
13134 +
13135 + /**
13136 + * Discard any space tokens, fetching the next non-space token.
13137 + */
13138 + consumeSpaces() {
13139 + while (true) {
13140 + const ch = this.fetch().text;
13141 + // \ufe0e is the Unicode variation selector to supress emoji. Ignore it.
13142 + if (ch === " " || ch === "\u00a0" || ch === "\ufe0e") {
13143 + this.consume();
13144 + } else {
13145 + break
13146 + }
13147 + }
13148 + }
13149 +
13150 + /**
13151 + * Parses a group, essentially returning the string formed by the
13152 + * brace-enclosed tokens plus some position information.
13153 + */
13154 + parseStringGroup(
13155 + modeName, // Used to describe the mode in error messages.
13156 + optional
13157 + ) {
13158 + const argToken = this.gullet.scanArgument(optional);
13159 + if (argToken == null) {
13160 + return null;
13161 + }
13162 + let str = "";
13163 + let nextToken;
13164 + while ((nextToken = this.fetch()).text !== "EOF") {
13165 + str += nextToken.text;
13166 + this.consume();
13167 + }
13168 + this.consume(); // consume the end of the argument
13169 + argToken.text = str;
13170 + return argToken;
13171 + }
13172 +
13173 + /**
13174 + * Parses a regex-delimited group: the largest sequence of tokens
13175 + * whose concatenated strings match `regex`. Returns the string
13176 + * formed by the tokens plus some position information.
13177 + */
13178 + parseRegexGroup(
13179 + regex,
13180 + modeName // Used to describe the mode in error messages.
13181 + ) {
13182 + const firstToken = this.fetch();
13183 + let lastToken = firstToken;
13184 + let str = "";
13185 + let nextToken;
13186 + while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) {
13187 + lastToken = nextToken;
13188 + str += lastToken.text;
13189 + this.consume();
13190 + }
13191 + if (str === "") {
13192 + throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken);
13193 + }
13194 + return firstToken.range(lastToken, str);
13195 + }
13196 +
13197 + /**
13198 + * Parses a size specification, consisting of magnitude and unit.
13199 + */
13200 + parseSizeGroup(optional) {
13201 + let res;
13202 + let isBlank = false;
13203 + // don't expand before parseStringGroup
13204 + this.gullet.consumeSpaces();
13205 + if (!optional && this.gullet.future().text !== "{") {
13206 + res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size");
13207 + } else {
13208 + res = this.parseStringGroup("size", optional);
13209 + }
13210 + if (!res) {
13211 + return null;
13212 + }
13213 + if (!optional && res.text.length === 0) {
13214 + // Because we've tested for what is !optional, this block won't
13215 + // affect \kern, \hspace, etc. It will capture the mandatory arguments
13216 + // to \genfrac and \above.
13217 + res.text = "0pt"; // Enable \above{}
13218 + isBlank = true; // This is here specifically for \genfrac
13219 + }
13220 + const match = sizeRegEx.exec(res.text);
13221 + if (!match) {
13222 + throw new ParseError("Invalid size: '" + res.text + "'", res);
13223 + }
13224 + const data = {
13225 + number: +(match[1] + match[2]), // sign + magnitude, cast to number
13226 + unit: match[3]
13227 + };
13228 + if (!validUnit(data)) {
13229 + throw new ParseError("Invalid unit: '" + data.unit + "'", res);
13230 + }
13231 + return {
13232 + type: "size",
13233 + mode: this.mode,
13234 + value: data,
13235 + isBlank
13236 + };
13237 + }
13238 +
13239 + /**
13240 + * Parses an URL, checking escaped letters and allowed protocols,
13241 + * and setting the catcode of % as an active character (as in \hyperref).
13242 + */
13243 + parseUrlGroup(optional) {
13244 + this.gullet.lexer.setCatcode("%", 13); // active character
13245 + this.gullet.lexer.setCatcode("~", 12); // other character
13246 + const res = this.parseStringGroup("url", optional);
13247 + this.gullet.lexer.setCatcode("%", 14); // comment character
13248 + this.gullet.lexer.setCatcode("~", 13); // active character
13249 + if (res == null) {
13250 + return null;
13251 + }
13252 + // hyperref package allows backslashes alone in href, but doesn't
13253 + // generate valid links in such cases; we interpret this as
13254 + // "undefined" behaviour, and keep them as-is. Some browser will
13255 + // replace backslashes with forward slashes.
13256 + let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1");
13257 + url = res.text.replace(/{\u2044}/g, "/");
13258 + return {
13259 + type: "url",
13260 + mode: this.mode,
13261 + url
13262 + };
13263 + }
13264 +
13265 + /**
13266 + * Parses an argument with the mode specified.
13267 + */
13268 + parseArgumentGroup(optional, mode) {
13269 + const argToken = this.gullet.scanArgument(optional);
13270 + if (argToken == null) {
13271 + return null;
13272 + }
13273 + const outerMode = this.mode;
13274 + if (mode) {
13275 + // Switch to specified mode
13276 + this.switchMode(mode);
13277 + }
13278 +
13279 + this.gullet.beginGroup();
13280 + const expression = this.parseExpression(false, "EOF");
13281 + // TODO: find an alternative way to denote the end
13282 + this.expect("EOF"); // expect the end of the argument
13283 + this.gullet.endGroup();
13284 + const result = {
13285 + type: "ordgroup",
13286 + mode: this.mode,
13287 + loc: argToken.loc,
13288 + body: expression
13289 + };
13290 +
13291 + if (mode) {
13292 + // Switch mode back
13293 + this.switchMode(outerMode);
13294 + }
13295 + return result;
13296 + }
13297 +
13298 + /**
13299 + * Parses an ordinary group, which is either a single nucleus (like "x")
13300 + * or an expression in braces (like "{x+y}") or an implicit group, a group
13301 + * that starts at the current position, and ends right before a higher explicit
13302 + * group ends, or at EOF.
13303 + */
13304 + parseGroup(
13305 + name, // For error reporting.
13306 + breakOnTokenText
13307 + ) {
13308 + const firstToken = this.fetch();
13309 + const text = firstToken.text;
13310 +
13311 + let result;
13312 + // Try to parse an open brace or \begingroup
13313 + if (text === "{" || text === "\\begingroup" || text === "\\toggle") {
13314 + this.consume();
13315 + const groupEnd = text === "{"
13316 + ? "}"
13317 + : text === "\\begingroup"
13318 + ? "\\endgroup"
13319 + : "\\endtoggle";
13320 +
13321 + this.gullet.beginGroup();
13322 + // If we get a brace, parse an expression
13323 + const expression = this.parseExpression(false, groupEnd);
13324 + const lastToken = this.fetch();
13325 + this.expect(groupEnd); // Check that we got a matching closing brace
13326 + this.gullet.endGroup();
13327 + result = {
13328 + type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"),
13329 + mode: this.mode,
13330 + loc: SourceLocation.range(firstToken, lastToken),
13331 + body: expression,
13332 + // A group formed by \begingroup...\endgroup is a semi-simple group
13333 + // which doesn't affect spacing in math mode, i.e., is transparent.
13334 + // https://tex.stackexchange.com/questions/1930/
13335 + semisimple: text === "\\begingroup" || undefined
13336 + };
13337 + } else {
13338 + // If there exists a function with this name, parse the function.
13339 + // Otherwise, just return a nucleus
13340 + result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol();
13341 + if (result == null && text[0] === "\\" &&
13342 + !Object.prototype.hasOwnProperty.call(implicitCommands, text )) {
13343 + result = this.formatUnsupportedCmd(text);
13344 + this.consume();
13345 + }
13346 + }
13347 + return result;
13348 + }
13349 +
13350 + /**
13351 + * Form ligature-like combinations of characters for text mode.
13352 + * This includes inputs like "--", "---", "``" and "''".
13353 + * The result will simply replace multiple textord nodes with a single
13354 + * character in each value by a single textord node having multiple
13355 + * characters in its value. The representation is still ASCII source.
13356 + * The group will be modified in place.
13357 + */
13358 + formLigatures(group) {
13359 + let n = group.length - 1;
13360 + for (let i = 0; i < n; ++i) {
13361 + const a = group[i];
13362 + const v = a.text;
13363 + if (v === "-" && group[i + 1].text === "-") {
13364 + if (i + 1 < n && group[i + 2].text === "-") {
13365 + group.splice(i, 3, {
13366 + type: "textord",
13367 + mode: "text",
13368 + loc: SourceLocation.range(a, group[i + 2]),
13369 + text: "---"
13370 + });
13371 + n -= 2;
13372 + } else {
13373 + group.splice(i, 2, {
13374 + type: "textord",
13375 + mode: "text",
13376 + loc: SourceLocation.range(a, group[i + 1]),
13377 + text: "--"
13378 + });
13379 + n -= 1;
13380 + }
13381 + }
13382 + if ((v === "'" || v === "`") && group[i + 1].text === v) {
13383 + group.splice(i, 2, {
13384 + type: "textord",
13385 + mode: "text",
13386 + loc: SourceLocation.range(a, group[i + 1]),
13387 + text: v + v
13388 + });
13389 + n -= 1;
13390 + }
13391 + }
13392 + }
13393 +
13394 + /**
13395 + * Parse a single symbol out of the string. Here, we handle single character
13396 + * symbols and special functions like \verb.
13397 + */
13398 + parseSymbol() {
13399 + const nucleus = this.fetch();
13400 + let text = nucleus.text;
13401 +
13402 + if (/^\\verb[^a-zA-Z]/.test(text)) {
13403 + this.consume();
13404 + let arg = text.slice(5);
13405 + const star = arg.charAt(0) === "*";
13406 + if (star) {
13407 + arg = arg.slice(1);
13408 + }
13409 + // Lexer's tokenRegex is constructed to always have matching
13410 + // first/last characters.
13411 + if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) {
13412 + throw new ParseError(`\\verb assertion failed --
13413 + please report what input caused this bug`);
13414 + }
13415 + arg = arg.slice(1, -1); // remove first and last char
13416 + return {
13417 + type: "verb",
13418 + mode: "text",
13419 + body: arg,
13420 + star
13421 + };
13422 + }
13423 + // At this point, we should have a symbol, possibly with accents.
13424 + // First expand any accented base symbol according to unicodeSymbols.
13425 + if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0]) &&
13426 + this.mode === "math" && !symbols[this.mode][text[0]]) {
13427 + // This behavior is not strict (XeTeX-compatible) in math mode.
13428 + if (this.settings.strict && this.mode === "math") {
13429 + throw new ParseError(`Accented Unicode text character "${text[0]}" used in ` + `math mode`,
13430 + nucleus
13431 + );
13432 + }
13433 + text = unicodeSymbols[text[0]] + text.slice(1);
13434 + }
13435 + // Strip off any combining characters
13436 + const match = this.mode === "math"
13437 + ? combiningDiacriticalMarksEndRegex.exec(text)
13438 + : null;
13439 + if (match) {
13440 + text = text.substring(0, match.index);
13441 + if (text === "i") {
13442 + text = "\u0131"; // dotless i, in math and text mode
13443 + } else if (text === "j") {
13444 + text = "\u0237"; // dotless j, in math and text mode
13445 + }
13446 + }
13447 + // Recognize base symbol
13448 + let symbol;
13449 + if (symbols[this.mode][text]) {
13450 + let group = symbols[this.mode][text].group;
13451 + if (group === "bin" && binLeftCancellers.includes(this.prevAtomType)) {
13452 + // Change from a binary operator to a unary (prefix) operator
13453 + group = "open";
13454 + }
13455 + const loc = SourceLocation.range(nucleus);
13456 + let s;
13457 + if (Object.prototype.hasOwnProperty.call(ATOMS, group )) {
13458 + const family = group;
13459 + s = {
13460 + type: "atom",
13461 + mode: this.mode,
13462 + family,
13463 + loc,
13464 + text
13465 + };
13466 + } else {
13467 + if (asciiFromScript[text]) {
13468 + // Unicode 14 disambiguates chancery from roundhand.
13469 + // See https://www.unicode.org/charts/PDF/U1D400.pdf
13470 + this.consume();
13471 + const nextCode = this.fetch().text.charCodeAt(0);
13472 + // mathcal is Temml default. Use mathscript if called for.
13473 + const font = nextCode === 0xfe01 ? "mathscr" : "mathcal";
13474 + if (nextCode === 0xfe00 || nextCode === 0xfe01) { this.consume(); }
13475 + return {
13476 + type: "font",
13477 + mode: "math",
13478 + font,
13479 + body: { type: "mathord", mode: "math", loc, text: asciiFromScript[text] }
13480 + }
13481 + }
13482 + // Default ord character. No disambiguation necessary.
13483 + s = {
13484 + type: group,
13485 + mode: this.mode,
13486 + loc,
13487 + text
13488 + };
13489 + }
13490 + symbol = s;
13491 + } else if (text.charCodeAt(0) >= 0x80 || combiningDiacriticalMarksEndRegex.exec(text)) {
13492 + // no symbol for e.g. ^
13493 + if (this.settings.strict && this.mode === "math") {
13494 + throw new ParseError(`Unicode text character "${text[0]}" used in math mode`, nucleus)
13495 + }
13496 + // All nonmathematical Unicode characters are rendered as if they
13497 + // are in text mode (wrapped in \text) because that's what it
13498 + // takes to render them in LaTeX.
13499 + symbol = {
13500 + type: "textord",
13501 + mode: "text",
13502 + loc: SourceLocation.range(nucleus),
13503 + text
13504 + };
13505 + } else {
13506 + return null; // EOF, ^, _, {, }, etc.
13507 + }
13508 + this.consume();
13509 + // Transform combining characters into accents
13510 + if (match) {
13511 + for (let i = 0; i < match[0].length; i++) {
13512 + const accent = match[0][i];
13513 + if (!unicodeAccents[accent]) {
13514 + throw new ParseError(`Unknown accent ' ${accent}'`, nucleus);
13515 + }
13516 + const command = unicodeAccents[accent][this.mode] ||
13517 + unicodeAccents[accent].text;
13518 + if (!command) {
13519 + throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus);
13520 + }
13521 + symbol = {
13522 + type: "accent",
13523 + mode: this.mode,
13524 + loc: SourceLocation.range(nucleus),
13525 + label: command,
13526 + isStretchy: false,
13527 + base: symbol
13528 + };
13529 + }
13530 + }
13531 + return symbol;
13532 + }
13533 + }
13534 +
13535 + /**
13536 + * Parses an expression using a Parser, then returns the parsed result.
13537 + */
13538 + const parseTree = function(toParse, settings) {
13539 + if (!(typeof toParse === "string" || toParse instanceof String)) {
13540 + throw new TypeError("Temml can only parse string typed expression")
13541 + }
13542 + const parser = new Parser(toParse, settings);
13543 + // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
13544 + delete parser.gullet.macros.current["\\df@tag"];
13545 +
13546 + let tree = parser.parse();
13547 +
13548 + // LaTeX ignores a \tag placed outside an AMS environment.
13549 + if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
13550 + // If the input used \tag, it will set the \df@tag macro to the tag.
13551 + // In this case, we separately parse the tag and wrap the tree.
13552 + if (parser.gullet.macros.get("\\df@tag")) {
13553 + if (!settings.displayMode) {
13554 + throw new ParseError("\\tag works only in display mode")
13555 + }
13556 + parser.gullet.feed("\\df@tag");
13557 + tree = [
13558 + {
13559 + type: "tag",
13560 + mode: "text",
13561 + body: tree,
13562 + tag: parser.parse()
13563 + }
13564 + ];
13565 + }
13566 + }
13567 +
13568 + return tree
13569 + };
13570 +
13571 + /**
13572 + * This file contains information about the style that the mathmlBuilder carries
13573 + * around with it. Data is held in an `Style` object, and when
13574 + * recursing, a new `Style` object can be created with the `.with*` functions.
13575 + */
13576 +
13577 + const subOrSupLevel = [2, 2, 3, 3];
13578 +
13579 + /**
13580 + * This is the main Style class. It contains the current style.level, color, and font.
13581 + *
13582 + * Style objects should not be modified. To create a new Style with
13583 + * different properties, call a `.with*` method.
13584 + */
13585 + class Style {
13586 + constructor(data) {
13587 + // Style.level can be 0 | 1 | 2 | 3, which correspond to
13588 + // displaystyle, textstyle, scriptstyle, and scriptscriptstyle.
13589 + // style.level usually does not directly set MathML's script level. MathML does that itself.
13590 + // However, Chromium does not stop shrinking after scriptscriptstyle, so we do explicitly
13591 + // set a scriptlevel attribute in those conditions.
13592 + // We also use style.level to track math style so that we can get the correct
13593 + // scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em.
13594 + this.level = data.level;
13595 + this.color = data.color; // string | void
13596 + // A font family applies to a group of fonts (i.e. SansSerif), while a font
13597 + // represents a specific font (i.e. SansSerif Bold).
13598 + // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
13599 + this.font = data.font || ""; // string
13600 + this.fontFamily = data.fontFamily || ""; // string
13601 + this.fontSize = data.fontSize || 1.0; // number
13602 + this.fontWeight = data.fontWeight || "";
13603 + this.fontShape = data.fontShape || "";
13604 + this.maxSize = data.maxSize; // [number, number]
13605 + }
13606 +
13607 + /**
13608 + * Returns a new style object with the same properties as "this". Properties
13609 + * from "extension" will be copied to the new style object.
13610 + */
13611 + extend(extension) {
13612 + const data = {
13613 + level: this.level,
13614 + color: this.color,
13615 + font: this.font,
13616 + fontFamily: this.fontFamily,
13617 + fontSize: this.fontSize,
13618 + fontWeight: this.fontWeight,
13619 + fontShape: this.fontShape,
13620 + maxSize: this.maxSize
13621 + };
13622 +
13623 + for (const key in extension) {
13624 + if (Object.prototype.hasOwnProperty.call(extension, key)) {
13625 + data[key] = extension[key];
13626 + }
13627 + }
13628 +
13629 + return new Style(data);
13630 + }
13631 +
13632 + withLevel(n) {
13633 + return this.extend({
13634 + level: n
13635 + });
13636 + }
13637 +
13638 + incrementLevel() {
13639 + return this.extend({
13640 + level: Math.min(this.level + 1, 3)
13641 + });
13642 + }
13643 +
13644 + inSubOrSup() {
13645 + return this.extend({
13646 + level: subOrSupLevel[this.level]
13647 + })
13648 + }
13649 +
13650 + /**
13651 + * Create a new style object with the given color.
13652 + */
13653 + withColor(color) {
13654 + return this.extend({
13655 + color: color
13656 + });
13657 + }
13658 +
13659 + /**
13660 + * Creates a new style object with the given math font or old text font.
13661 + * @type {[type]}
13662 + */
13663 + withFont(font) {
13664 + return this.extend({
13665 + font
13666 + });
13667 + }
13668 +
13669 + /**
13670 + * Create a new style objects with the given fontFamily.
13671 + */
13672 + withTextFontFamily(fontFamily) {
13673 + return this.extend({
13674 + fontFamily,
13675 + font: ""
13676 + });
13677 + }
13678 +
13679 + /**
13680 + * Creates a new style object with the given font size
13681 + */
13682 + withFontSize(num) {
13683 + return this.extend({
13684 + fontSize: num
13685 + });
13686 + }
13687 +
13688 + /**
13689 + * Creates a new style object with the given font weight
13690 + */
13691 + withTextFontWeight(fontWeight) {
13692 + return this.extend({
13693 + fontWeight,
13694 + font: ""
13695 + });
13696 + }
13697 +
13698 + /**
13699 + * Creates a new style object with the given font weight
13700 + */
13701 + withTextFontShape(fontShape) {
13702 + return this.extend({
13703 + fontShape,
13704 + font: ""
13705 + });
13706 + }
13707 +
13708 + /**
13709 + * Gets the CSS color of the current style object
13710 + */
13711 + getColor() {
13712 + return this.color;
13713 + }
13714 + }
13715 +
13716 + /* Temml Post Process
13717 + * Populate the text contents of each \ref & \eqref
13718 + *
13719 + * As with other Temml code, this file is released under terms of the MIT license.
13720 + * https://mit-license.org/
13721 + */
13722 +
13723 + const version = "0.10.34";
13724 +
13725 + function postProcess(block) {
13726 + const labelMap = {};
13727 + let i = 0;
13728 +
13729 + // Get a collection of the parents of each \tag & auto-numbered equation
13730 + const amsEqns = document.getElementsByClassName('tml-eqn');
13731 + for (let parent of amsEqns) {
13732 + // AMS automatically numbered equation.
13733 + // Assign an id.
13734 + i += 1;
13735 + parent.setAttribute("id", "tml-eqn-" + String(i));
13736 + // No need to write a number into the text content of the element.
13737 + // A CSS counter has done that even if this postProcess() function is not used.
13738 +
13739 + // Find any \label that refers to an AMS automatic eqn number.
13740 + while (true) {
13741 + if (parent.tagName === "mtable") { break }
13742 + const labels = parent.getElementsByClassName("tml-label");
13743 + if (labels.length > 0) {
13744 + const id = parent.attributes.id.value;
13745 + labelMap[id] = String(i);
13746 + break
13747 + } else {
13748 + parent = parent.parentElement;
13749 + }
13750 + }
13751 + }
13752 +
13753 + // Find \labels associated with \tag
13754 + const taggedEqns = document.getElementsByClassName('tml-tageqn');
13755 + for (const parent of taggedEqns) {
13756 + const labels = parent.getElementsByClassName("tml-label");
13757 + if (labels.length > 0) {
13758 + const tags = parent.getElementsByClassName("tml-tag");
13759 + if (tags.length > 0) {
13760 + const id = parent.attributes.id.value;
13761 + labelMap[id] = tags[0].textContent;
13762 + }
13763 + }
13764 + }
13765 +
13766 + // Populate \ref & \eqref text content
13767 + const refs = block.getElementsByClassName("tml-ref");
13768 + [...refs].forEach(ref => {
13769 + const attr = ref.getAttribute("href");
13770 + let str = labelMap[attr.slice(1)];
13771 + if (ref.className.indexOf("tml-eqref") === -1) {
13772 + // \ref. Omit parens.
13773 + str = str.replace(/^\(/, "");
13774 + str = str.replace(/\)$/, "");
13775 + } else {
13776 + // \eqref. Include parens
13777 + if (str.charAt(0) !== "(") { str = "(" + str; }
13778 + if (str.slice(-1) !== ")") { str = str + ")"; }
13779 + }
13780 + const mtext = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtext");
13781 + mtext.appendChild(document.createTextNode(str));
13782 + const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
13783 + math.appendChild(mtext);
13784 + ref.appendChild(math);
13785 + });
13786 + }
13787 +
13788 + /* eslint no-console:0 */
13789 + /**
13790 + * This is the main entry point for Temml. Here, we expose functions for
13791 + * rendering expressions either to DOM nodes or to markup strings.
13792 + *
13793 + * We also expose the ParseError class to check if errors thrown from Temml are
13794 + * errors in the expression, or errors in javascript handling.
13795 + */
13796 +
13797 +
13798 + /**
13799 + * @type {import('./temml').render}
13800 + * Parse and build an expression, and place that expression in the DOM node
13801 + * given.
13802 + */
13803 + let render = function(expression, baseNode, options = {}) {
13804 + baseNode.textContent = "";
13805 + const alreadyInMathElement = baseNode.tagName.toLowerCase() === "math";
13806 + if (alreadyInMathElement) { options.wrap = "none"; }
13807 + const math = renderToMathMLTree(expression, options);
13808 + if (alreadyInMathElement) {
13809 + // The <math> element already exists. Populate it.
13810 + baseNode.textContent = "";
13811 + math.children.forEach(e => { baseNode.appendChild(e.toNode()); });
13812 + } else if (math.children.length > 1) {
13813 + baseNode.textContent = "";
13814 + math.children.forEach(e => { baseNode.appendChild(e.toNode()); });
13815 + } else {
13816 + baseNode.appendChild(math.toNode());
13817 + }
13818 + };
13819 +
13820 + // Temml's styles don't work properly in quirks mode. Print out an error, and
13821 + // disable rendering.
13822 + if (typeof document !== "undefined") {
13823 + if (document.compatMode !== "CSS1Compat") {
13824 + typeof console !== "undefined" &&
13825 + console.warn(
13826 + "Warning: Temml doesn't work in quirks mode. Make sure your " +
13827 + "website has a suitable doctype."
13828 + );
13829 +
13830 + render = function() {
13831 + throw new ParseError("Temml doesn't work in quirks mode.");
13832 + };
13833 + }
13834 + }
13835 +
13836 + /**
13837 + * @type {import('./temml').renderToString}
13838 + * Parse and build an expression, and return the markup for that.
13839 + */
13840 + const renderToString = function(expression, options) {
13841 + const markup = renderToMathMLTree(expression, options).toMarkup();
13842 + return markup;
13843 + };
13844 +
13845 + /**
13846 + * @type {import('./temml').generateParseTree}
13847 + * Parse an expression and return the parse tree.
13848 + */
13849 + const generateParseTree = function(expression, options) {
13850 + const settings = new Settings(options);
13851 + return parseTree(expression, settings);
13852 + };
13853 +
13854 + /**
13855 + * @type {import('./temml').definePreamble}
13856 + * Take an expression which contains a preamble.
13857 + * Parse it and return the macros.
13858 + */
13859 + const definePreamble = function(expression, options) {
13860 + const settings = new Settings(options);
13861 + settings.macros = {};
13862 + if (!(typeof expression === "string" || expression instanceof String)) {
13863 + throw new TypeError("Temml can only parse string typed expression")
13864 + }
13865 + const parser = new Parser(expression, settings, true);
13866 + // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
13867 + delete parser.gullet.macros.current["\\df@tag"];
13868 + const macros = parser.parse();
13869 + return macros
13870 + };
13871 +
13872 + /**
13873 + * If the given error is a Temml ParseError,
13874 + * renders the invalid LaTeX as a span with hover title giving the Temml
13875 + * error message. Otherwise, simply throws the error.
13876 + */
13877 + const renderError = function(error, expression, options) {
13878 + if (options.throwOnError || !(error instanceof ParseError)) {
13879 + throw error;
13880 + }
13881 + const node = new Span(["temml-error"], [new TextNode$1(expression + "\n" + error.toString())]);
13882 + node.style.color = options.errorColor;
13883 + node.style.whiteSpace = "pre-line";
13884 + return node;
13885 + };
13886 +
13887 + /**
13888 + * @type {import('./temml').renderToMathMLTree}
13889 + * Generates and returns the Temml build tree. This is used for advanced
13890 + * use cases (like rendering to custom output).
13891 + */
13892 + const renderToMathMLTree = function(expression, options) {
13893 + const settings = new Settings(options);
13894 + try {
13895 + const tree = parseTree(expression, settings);
13896 + const style = new Style({
13897 + level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT,
13898 + maxSize: settings.maxSize
13899 + });
13900 + return buildMathML(tree, expression, style, settings);
13901 + } catch (error) {
13902 + return renderError(error, expression, settings);
13903 + }
13904 + };
13905 +
13906 + /** @type {import('./temml').default} */
13907 + var temml = {
13908 + /**
13909 + * Current Temml version
13910 + */
13911 + version: version,
13912 + /**
13913 + * Renders the given LaTeX into MathML, and adds
13914 + * it as a child to the specified DOM node.
13915 + */
13916 + render,
13917 + /**
13918 + * Renders the given LaTeX into MathML string,
13919 + * for sending to the client.
13920 + */
13921 + renderToString,
13922 + /**
13923 + * Post-process an entire HTML block.
13924 + * Writes AMS auto-numbers and implements \ref{}.
13925 + * Typcally called once, after a loop has rendered many individual spans.
13926 + */
13927 + postProcess,
13928 + /**
13929 + * Temml error, usually during parsing.
13930 + */
13931 + ParseError,
13932 + /**
13933 + * Creates a set of macros with document-wide scope.
13934 + */
13935 + definePreamble,
13936 + /**
13937 + * Parses the given LaTeX into Temml's internal parse tree structure,
13938 + * without rendering to HTML or MathML.
13939 + *
13940 + * NOTE: This method is not currently recommended for public use.
13941 + * The internal tree representation is unstable and is very likely
13942 + * to change. Use at your own risk.
13943 + */
13944 + __parse: generateParseTree,
13945 + /**
13946 + * Renders the given LaTeX into a MathML internal DOM tree
13947 + * representation, without flattening that representation to a string.
13948 + *
13949 + * NOTE: This method is not currently recommended for public use.
13950 + * The internal tree representation is unstable and is very likely
13951 + * to change. Use at your own risk.
13952 + */
13953 + __renderToMathMLTree: renderToMathMLTree,
13954 + /**
13955 + * adds a new symbol to builtin symbols table
13956 + */
13957 + __defineSymbol: defineSymbol,
13958 + /**
13959 + * adds a new macro to builtin macro list
13960 + */
13961 + __defineMacro: defineMacro
13962 + };
13963 +
13964 +
13965 +
13966 + ;// ./node_modules/@wordpress/latex-to-mathml/build-module/index.js
13967 +
13968 + function latexToMathML(latex, { displayMode = true } = {}) {
13969 + const mathML = temml.renderToString(latex, {
13970 + displayMode,
13971 + annotate: true,
13972 + throwOnError: true
13973 + });
13974 + const doc = document.implementation.createHTMLDocument("");
13975 + doc.body.innerHTML = mathML;
13976 + return doc.body.querySelector("math")?.innerHTML ?? "";
13977 + }
13978 +
13979 +
13980 + (window.wp = window.wp || {}).latexToMathml = __webpack_exports__;
13981 + /******/ })()
13982 + ;