1import katex from '../katex.mjs';
2
3/* eslint-disable */
4
5/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
6
7/* vim: set ts=2 et sw=2 tw=80: */
8
9/*************************************************************
10 *
11 *  KaTeX mhchem.js
12 *
13 *  This file implements a KaTeX version of mhchem version 3.3.0.
14 *  It is adapted from MathJax/extensions/TeX/mhchem.js
15 *  It differs from the MathJax version as follows:
16 *    1. The interface is changed so that it can be called from KaTeX, not MathJax.
17 *    2. \rlap and \llap are replaced with \mathrlap and \mathllap.
18 *    3. Four lines of code are edited in order to use \raisebox instead of \raise.
19 *    4. The reaction arrow code is simplified. All reaction arrows are rendered
20 *       using KaTeX extensible arrows instead of building non-extensible arrows.
21 *    5. \tripledash vertical alignment is slightly adjusted.
22 *
23 *    This code, as other KaTeX code, is released under the MIT license.
24 * 
25 * /*************************************************************
26 *
27 *  MathJax/extensions/TeX/mhchem.js
28 *
29 *  Implements the \ce command for handling chemical formulas
30 *  from the mhchem LaTeX package.
31 *
32 *  ---------------------------------------------------------------------
33 *
34 *  Copyright (c) 2011-2015 The MathJax Consortium
35 *  Copyright (c) 2015-2018 Martin Hensel
36 *
37 *  Licensed under the Apache License, Version 2.0 (the "License");
38 *  you may not use this file except in compliance with the License.
39 *  You may obtain a copy of the License at
40 *
41 *      http://www.apache.org/licenses/LICENSE-2.0
42 *
43 *  Unless required by applicable law or agreed to in writing, software
44 *  distributed under the License is distributed on an "AS IS" BASIS,
45 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 *  See the License for the specific language governing permissions and
47 *  limitations under the License.
48 */
49//
50// Coding Style
51//   - use '' for identifiers that can by minified/uglified
52//   - use "" for strings that need to stay untouched
53// version: "3.3.0" for MathJax and KaTeX
54// Add \ce, \pu, and \tripledash to the KaTeX macros.
55katex.__defineMacro("\\ce", function (context) {
56  return chemParse(context.consumeArgs(1)[0], "ce");
57});
58
59katex.__defineMacro("\\pu", function (context) {
60  return chemParse(context.consumeArgs(1)[0], "pu");
61}); //  Needed for \bond for the ~ forms
62//  Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not 
63//  a mathematical minus, U+2212. So we need that extra 0.56.
64
65
66katex.__defineMacro("\\tripledash", "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu" + "\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}");
67//  This is the main function for handing the \ce and \pu commands.
68//  It takes the argument to \ce or \pu and returns the corresponding TeX string.
69//
70
71var chemParse = function chemParse(tokens, stateMachine) {
72  // Recreate the argument string from KaTeX's array of tokens.
73  var str = "";
74  var expectedLoc = tokens[tokens.length - 1].loc.start;
75
76  for (var i = tokens.length - 1; i >= 0; i--) {
77    if (tokens[i].loc.start > expectedLoc) {
78      // context.consumeArgs has eaten a space.
79      str += " ";
80      expectedLoc = tokens[i].loc.start;
81    }
82
83    str += tokens[i].text;
84    expectedLoc += tokens[i].text.length;
85  }
86
87  var tex = texify.go(mhchemParser.go(str, stateMachine));
88  return tex;
89}; //
90// Core parser for mhchem syntax  (recursive)
91//
92
93/** @type {MhchemParser} */
94
95
96var mhchemParser = {
97  //
98  // Parses mchem \ce syntax
99  //
100  // Call like
101  //   go("H2O");
102  //
103  go: function go(input, stateMachine) {
104    if (!input) {
105      return [];
106    }
107
108    if (stateMachine === undefined) {
109      stateMachine = 'ce';
110    }
111
112    var state = '0'; //
113    // String buffers for parsing:
114    //
115    // buffer.a == amount
116    // buffer.o == element
117    // buffer.b == left-side superscript
118    // buffer.p == left-side subscript
119    // buffer.q == right-side subscript
120    // buffer.d == right-side superscript
121    //
122    // buffer.r == arrow
123    // buffer.rdt == arrow, script above, type
124    // buffer.rd == arrow, script above, content
125    // buffer.rqt == arrow, script below, type
126    // buffer.rq == arrow, script below, content
127    //
128    // buffer.text_
129    // buffer.rm
130    // etc.
131    //
132    // buffer.parenthesisLevel == int, starting at 0
133    // buffer.sb == bool, space before
134    // buffer.beginsWithBond == bool
135    //
136    // These letters are also used as state names.
137    //
138    // Other states:
139    // 0 == begin of main part (arrow/operator unlikely)
140    // 1 == next entity
141    // 2 == next entity (arrow/operator unlikely)
142    // 3 == next atom
143    // c == macro
144    //
145
146    /** @type {Buffer} */
147
148    var buffer = {};
149    buffer['parenthesisLevel'] = 0;
150    input = input.replace(/\n/g, " ");
151    input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-");
152    input = input.replace(/[\u2026]/g, "..."); //
153    // Looks through mhchemParser.transitions, to execute a matching action
154    // (recursive)
155    //
156
157    var lastInput;
158    var watchdog = 10;
159    /** @type {ParserOutput[]} */
160
161    var output = [];
162
163    while (true) {
164      if (lastInput !== input) {
165        watchdog = 10;
166        lastInput = input;
167      } else {
168        watchdog--;
169      } //
170      // Find actions in transition table
171      //
172
173
174      var machine = mhchemParser.stateMachines[stateMachine];
175      var t = machine.transitions[state] || machine.transitions['*'];
176
177      iterateTransitions: for (var i = 0; i < t.length; i++) {
178        var matches = mhchemParser.patterns.match_(t[i].pattern, input);
179
180        if (matches) {
181          //
182          // Execute actions
183          //
184          var task = t[i].task;
185
186          for (var iA = 0; iA < task.action_.length; iA++) {
187            var o; //
188            // Find and execute action
189            //
190
191            if (machine.actions[task.action_[iA].type_]) {
192              o = machine.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option);
193            } else if (mhchemParser.actions[task.action_[iA].type_]) {
194              o = mhchemParser.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option);
195            } else {
196              throw ["MhchemBugA", "mhchem bug A. Please report. (" + task.action_[iA].type_ + ")"]; // Trying to use non-existing action
197            } //
198            // Add output
199            //
200
201
202            mhchemParser.concatArray(output, o);
203          } //
204          // Set next state,
205          // Shorten input,
206          // Continue with next character
207          //   (= apply only one transition per position)
208          //
209
210
211          state = task.nextState || state;
212
213          if (input.length > 0) {
214            if (!task.revisit) {
215              input = matches.remainder;
216            }
217
218            if (!task.toContinue) {
219              break iterateTransitions;
220            }
221          } else {
222            return output;
223          }
224        }
225      } //
226      // Prevent infinite loop
227      //
228
229
230      if (watchdog <= 0) {
231        throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character
232      }
233    }
234  },
235  concatArray: function concatArray(a, b) {
236    if (b) {
237      if (Array.isArray(b)) {
238        for (var iB = 0; iB < b.length; iB++) {
239          a.push(b[iB]);
240        }
241      } else {
242        a.push(b);
243      }
244    }
245  },
246  patterns: {
247    //
248    // Matching patterns
249    // either regexps or function that return null or {match_:"a", remainder:"bc"}
250    //
251    patterns: {
252      // property names must not look like integers ("2") for correct property traversal order, later on
253      'empty': /^$/,
254      'else': /^./,
255      'else2': /^./,
256      'space': /^\s/,
257      'space A': /^\s(?=[A-Z\\$])/,
258      'space$': /^\s$/,
259      'a-z': /^[a-z]/,
260      'x': /^x/,
261      'x$': /^x$/,
262      'i$': /^i$/,
263      '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]))))+/,
264      '\\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]))/,
265      'one lowercase latin letter $': /^(?:([a-z])(?:$|[^a-zA-Z]))$/,
266      '$one lowercase latin letter$ $': /^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/,
267      '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]))$/,
268      'digits': /^[0-9]+/,
269      '-9.,9': /^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/,
270      '-9.,9 no missing 0': /^[+\-]?[0-9]+(?:[.,][0-9]+)?/,
271      '(-)(9.,9)(e)(99)': function e99(input) {
272        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]+\}))?/);
273
274        if (m && m[0]) {
275          return {
276            match_: m.splice(1),
277            remainder: input.substr(m[0].length)
278          };
279        }
280
281        return null;
282      },
283      '(-)(9)^(-9)': function _(input) {
284        var m = input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/);
285
286        if (m && m[0]) {
287          return {
288            match_: m.splice(1),
289            remainder: input.substr(m[0].length)
290          };
291        }
292
293        return null;
294      },
295      'state of aggregation $': function stateOfAggregation$(input) {
296        // ... or crystal system
297        var a = mhchemParser.patterns.findObserveGroups(input, "", /^\([a-z]{1,3}(?=[\),])/, ")", ""); // (aq), (aq,$\infty$), (aq, sat)
298
299        if (a && a.remainder.match(/^($|[\s,;\)\]\}])/)) {
300          return a;
301        } //  AND end of 'phrase'
302
303
304        var m = input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/); // OR crystal system ($o$) (\ca$c$)
305
306        if (m) {
307          return {
308            match_: m[0],
309            remainder: input.substr(m[0].length)
310          };
311        }
312
313        return null;
314      },
315      '_{(state of aggregation)}$': /^_\{(\([a-z]{1,3}\))\}/,
316      '{[(': /^(?:\\\{|\[|\()/,
317      ')]}': /^(?:\)|\]|\\\})/,
318      ', ': /^[,;]\s*/,
319      ',': /^[,;]/,
320      '.': /^[.]/,
321      '. ': /^([.\u22C5\u00B7\u2022])\s*/,
322      '...': /^\.\.\.(?=$|[^.])/,
323      '* ': /^([*])\s*/,
324      '^{(...)}': function _(input) {
325        return mhchemParser.patterns.findObserveGroups(input, "^{", "", "", "}");
326      },
327      '^($...$)': function $$(input) {
328        return mhchemParser.patterns.findObserveGroups(input, "^", "$", "$", "");
329      },
330      '^a': /^\^([0-9]+|[^\\_])/,
331      '^\\x{}{}': function x(input) {
332        return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true);
333      },
334      '^\\x{}': function x(input) {
335        return mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", "");
336      },
337      '^\\x': /^\^(\\[a-zA-Z]+)\s*/,
338      '^(-1)': /^\^(-?\d+)/,
339      '\'': /^'/,
340      '_{(...)}': function _(input) {
341        return mhchemParser.patterns.findObserveGroups(input, "_{", "", "", "}");
342      },
343      '_($...$)': function _$$(input) {
344        return mhchemParser.patterns.findObserveGroups(input, "_", "$", "$", "");
345      },
346      '_9': /^_([+\-]?[0-9]+|[^\\])/,
347      '_\\x{}{}': function _X(input) {
348        return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true);
349      },
350      '_\\x{}': function _X(input) {
351        return mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", "");
352      },
353      '_\\x': /^_(\\[a-zA-Z]+)\s*/,
354      '^_': /^(?:\^(?=_)|\_(?=\^)|[\^_]$)/,
355      '{}': /^\{\}/,
356      '{...}': function _(input) {
357        return mhchemParser.patterns.findObserveGroups(input, "", "{", "}", "");
358      },
359      '{(...)}': function _(input) {
360        return mhchemParser.patterns.findObserveGroups(input, "{", "", "", "}");
361      },
362      '$...$': function $$(input) {
363        return mhchemParser.patterns.findObserveGroups(input, "", "$", "$", "");
364      },
365      '${(...)}$': function $$(input) {
366        return mhchemParser.patterns.findObserveGroups(input, "${", "", "", "}$");
367      },
368      '$(...)$': function $$(input) {
369        return mhchemParser.patterns.findObserveGroups(input, "$", "", "", "$");
370      },
371      '=<>': /^[=<>]/,
372      '#': /^[#\u2261]/,
373      '+': /^\+/,
374      '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/,
375      // -space -, -; -] -/ -$ -state-of-aggregation
376      '-9': /^-(?=[0-9])/,
377      '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,
378      '-': /^-/,
379      'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,
380      'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,
381      'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,
382      '\\bond{(...)}': function bond(input) {
383        return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}");
384      },
385      '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,
386      'CMT': /^[CMT](?=\[)/,
387      '[(...)]': function _(input) {
388        return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]");
389      },
390      '1st-level escape': /^(&|\\\\|\\hline)\s*/,
391      '\\,': /^(?:\\[,\ ;:])/,
392      // \\x - but output no space before
393      '\\x{}{}': function x(input) {
394        return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true);
395      },
396      '\\x{}': function x(input) {
397        return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "");
398      },
399      '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/,
400      '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,
401      'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,
402      // only those with numbers in front, because the others will be formatted correctly anyway
403      'others': /^[\/~|]/,
404      '\\frac{(...)}': function frac(input) {
405        return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}");
406      },
407      '\\overset{(...)}': function overset(input) {
408        return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}");
409      },
410      '\\underset{(...)}': function underset(input) {
411        return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}");
412      },
413      '\\underbrace{(...)}': function underbrace(input) {
414        return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}");
415      },
416      '\\color{(...)}0': function color0(input) {
417        return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}");
418      },
419      '\\color{(...)}{(...)}1': function color1(input) {
420        return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}");
421      },
422      '\\color(...){(...)}2': function color2(input) {
423        return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}");
424      },
425      '\\ce{(...)}': function ce(input) {
426        return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}");
427      },
428      'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,
429      'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,
430      // 0 could be oxidation or charge
431      'roman numeral': /^[IVX]+/,
432      '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,
433      'amount': function amount(input) {
434        var match; // e.g. 2, 0.5, 1/2, -2, n/2, +;  $a$ could be added later in parsing
435
436        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))/);
437
438        if (match) {
439          return {
440            match_: match[0],
441            remainder: input.substr(match[0].length)
442          };
443        }
444
445        var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", "");
446
447        if (a) {
448          // e.g. $2n-1$, $-$
449          match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/);
450
451          if (match) {
452            return {
453              match_: match[0],
454              remainder: input.substr(match[0].length)
455            };
456          }
457        }
458
459        return null;
460      },
461      'amount2': function amount2(input) {
462        return this['amount'](input);
463      },
464      '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/,
465      'formula$': function formula$(input) {
466        if (input.match(/^\([a-z]+\)$/)) {
467          return null;
468        } // state of aggregation = no formula
469
470
471        var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);
472
473        if (match) {
474          return {
475            match_: match[0],
476            remainder: input.substr(match[0].length)
477          };
478        }
479
480        return null;
481      },
482      'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,
483      '/': /^\s*(\/)\s*/,
484      '//': /^\s*(\/\/)\s*/,
485      '*': /^\s*[*.]\s*/
486    },
487    findObserveGroups: function findObserveGroups(input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) {
488      /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */
489      var _match = function _match(input, pattern) {
490        if (typeof pattern === "string") {
491          if (input.indexOf(pattern) !== 0) {
492            return null;
493          }
494
495          return pattern;
496        } else {
497          var match = input.match(pattern);
498
499          if (!match) {
500            return null;
501          }
502
503          return match[0];
504        }
505      };
506      /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */
507
508
509      var _findObserveGroups = function _findObserveGroups(input, i, endChars) {
510        var braces = 0;
511
512        while (i < input.length) {
513          var a = input.charAt(i);
514
515          var match = _match(input.substr(i), endChars);
516
517          if (match !== null && braces === 0) {
518            return {
519              endMatchBegin: i,
520              endMatchEnd: i + match.length
521            };
522          } else if (a === "{") {
523            braces++;
524          } else if (a === "}") {
525            if (braces === 0) {
526              throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"];
527            } else {
528              braces--;
529            }
530          }
531
532          i++;
533        }
534
535        if (braces > 0) {
536          return null;
537        }
538
539        return null;
540      };
541
542      var match = _match(input, begExcl);
543
544      if (match === null) {
545        return null;
546      }
547
548      input = input.substr(match.length);
549      match = _match(input, begIncl);
550
551      if (match === null) {
552        return null;
553      }
554
555      var e = _findObserveGroups(input, match.length, endIncl || endExcl);
556
557      if (e === null) {
558        return null;
559      }
560
561      var match1 = input.substring(0, endIncl ? e.endMatchEnd : e.endMatchBegin);
562
563      if (!(beg2Excl || beg2Incl)) {
564        return {
565          match_: match1,
566          remainder: input.substr(e.endMatchEnd)
567        };
568      } else {
569        var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl);
570
571        if (group2 === null) {
572          return null;
573        }
574        /** @type {string[]} */
575
576
577        var matchRet = [match1, group2.match_];
578        return {
579          match_: combine ? matchRet.join("") : matchRet,
580          remainder: group2.remainder
581        };
582      }
583    },
584    //
585    // Matching function
586    // e.g. match("a", input) will look for the regexp called "a" and see if it matches
587    // returns null or {match_:"a", remainder:"bc"}
588    //
589    match_: function match_(m, input) {
590      var pattern = mhchemParser.patterns.patterns[m];
591
592      if (pattern === undefined) {
593        throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern
594      } else if (typeof pattern === "function") {
595        return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser
596      } else {
597        // RegExp
598        var match = input.match(pattern);
599
600        if (match) {
601          var mm;
602
603          if (match[2]) {
604            mm = [match[1], match[2]];
605          } else if (match[1]) {
606            mm = match[1];
607          } else {
608            mm = match[0];
609          }
610
611          return {
612            match_: mm,
613            remainder: input.substr(match[0].length)
614          };
615        }
616
617        return null;
618      }
619    }
620  },
621  //
622  // Generic state machine actions
623  //
624  actions: {
625    'a=': function a(buffer, m) {
626      buffer.a = (buffer.a || "") + m;
627    },
628    'b=': function b(buffer, m) {
629      buffer.b = (buffer.b || "") + m;
630    },
631    'p=': function p(buffer, m) {
632      buffer.p = (buffer.p || "") + m;
633    },
634    'o=': function o(buffer, m) {
635      buffer.o = (buffer.o || "") + m;
636    },
637    'q=': function q(buffer, m) {
638      buffer.q = (buffer.q || "") + m;
639    },
640    'd=': function d(buffer, m) {
641      buffer.d = (buffer.d || "") + m;
642    },
643    'rm=': function rm(buffer, m) {
644      buffer.rm = (buffer.rm || "") + m;
645    },
646    'text=': function text(buffer, m) {
647      buffer.text_ = (buffer.text_ || "") + m;
648    },
649    'insert': function insert(buffer, m, a) {
650      return {
651        type_: a
652      };
653    },
654    'insert+p1': function insertP1(buffer, m, a) {
655      return {
656        type_: a,
657        p1: m
658      };
659    },
660    'insert+p1+p2': function insertP1P2(buffer, m, a) {
661      return {
662        type_: a,
663        p1: m[0],
664        p2: m[1]
665      };
666    },
667    'copy': function copy(buffer, m) {
668      return m;
669    },
670    'rm': function rm(buffer, m) {
671      return {
672        type_: 'rm',
673        p1: m || ""
674      };
675    },
676    'text': function text(buffer, m) {
677      return mhchemParser.go(m, 'text');
678    },
679    '{text}': function text(buffer, m) {
680      var ret = ["{"];
681      mhchemParser.concatArray(ret, mhchemParser.go(m, 'text'));
682      ret.push("}");
683      return ret;
684    },
685    'tex-math': function texMath(buffer, m) {
686      return mhchemParser.go(m, 'tex-math');
687    },
688    'tex-math tight': function texMathTight(buffer, m) {
689      return mhchemParser.go(m, 'tex-math tight');
690    },
691    'bond': function bond(buffer, m, k) {
692      return {
693        type_: 'bond',
694        kind_: k || m
695      };
696    },
697    'color0-output': function color0Output(buffer, m) {
698      return {
699        type_: 'color0',
700        color: m[0]
701      };
702    },
703    'ce': function ce(buffer, m) {
704      return mhchemParser.go(m);
705    },
706    '1/2': function _(buffer, m) {
707      /** @type {ParserOutput[]} */
708      var ret = [];
709
710      if (m.match(/^[+\-]/)) {
711        ret.push(m.substr(0, 1));
712        m = m.substr(1);
713      }
714
715      var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);
716      n[1] = n[1].replace(/\$/g, "");
717      ret.push({
718        type_: 'frac',
719        p1: n[1],
720        p2: n[2]
721      });
722
723      if (n[3]) {
724        n[3] = n[3].replace(/\$/g, "");
725        ret.push({
726          type_: 'tex-math',
727          p1: n[3]
728        });
729      }
730
731      return ret;
732    },
733    '9,9': function _(buffer, m) {
734      return mhchemParser.go(m, '9,9');
735    }
736  },
737  //
738  // createTransitions
739  // convert  { 'letter': { 'state': { action_: 'output' } } }  to  { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] }
740  // with expansion of 'a|b' to 'a' and 'b' (at 2 places)
741  //
742  createTransitions: function createTransitions(o) {
743    var pattern, state;
744    /** @type {string[]} */
745
746    var stateArray;
747    var i; //
748    // 1. Collect all states
749    //
750
751    /** @type {Transitions} */
752
753    var transitions = {};
754
755    for (pattern in o) {
756      for (state in o[pattern]) {
757        stateArray = state.split("|");
758        o[pattern][state].stateArray = stateArray;
759
760        for (i = 0; i < stateArray.length; i++) {
761          transitions[stateArray[i]] = [];
762        }
763      }
764    } //
765    // 2. Fill states
766    //
767
768
769    for (pattern in o) {
770      for (state in o[pattern]) {
771        stateArray = o[pattern][state].stateArray || [];
772
773        for (i = 0; i < stateArray.length; i++) {
774          //
775          // 2a. Normalize actions into array:  'text=' ==> [{type_:'text='}]
776          // (Note to myself: Resolving the function here would be problematic. It would need .bind (for *this*) and currying (for *option*).)
777          //
778
779          /** @type {any} */
780          var p = o[pattern][state];
781
782          if (p.action_) {
783            p.action_ = [].concat(p.action_);
784
785            for (var k = 0; k < p.action_.length; k++) {
786              if (typeof p.action_[k] === "string") {
787                p.action_[k] = {
788                  type_: p.action_[k]
789                };
790              }
791            }
792          } else {
793            p.action_ = [];
794          } //
795          // 2.b Multi-insert
796          //
797
798
799          var patternArray = pattern.split("|");
800
801          for (var j = 0; j < patternArray.length; j++) {
802            if (stateArray[i] === '*') {
803              // insert into all
804              for (var t in transitions) {
805                transitions[t].push({
806                  pattern: patternArray[j],
807                  task: p
808                });
809              }
810            } else {
811              transitions[stateArray[i]].push({
812                pattern: patternArray[j],
813                task: p
814              });
815            }
816          }
817        }
818      }
819    }
820
821    return transitions;
822  },
823  stateMachines: {}
824}; //
825// Definition of state machines
826//
827
828mhchemParser.stateMachines = {
829  //
830  // \ce state machines
831  //
832  //#region ce
833  'ce': {
834    // main parser
835    transitions: mhchemParser.createTransitions({
836      'empty': {
837        '*': {
838          action_: 'output'
839        }
840      },
841      'else': {
842        '0|1|2': {
843          action_: 'beginsWithBond=false',
844          revisit: true,
845          toContinue: true
846        }
847      },
848      'oxidation$': {
849        '0': {
850          action_: 'oxidation-output'
851        }
852      },
853      'CMT': {
854        'r': {
855          action_: 'rdt=',
856          nextState: 'rt'
857        },
858        'rd': {
859          action_: 'rqt=',
860          nextState: 'rdt'
861        }
862      },
863      'arrowUpDown': {
864        '0|1|2|as': {
865          action_: ['sb=false', 'output', 'operator'],
866          nextState: '1'
867        }
868      },
869      'uprightEntities': {
870        '0|1|2': {
871          action_: ['o=', 'output'],
872          nextState: '1'
873        }
874      },
875      'orbital': {
876        '0|1|2|3': {
877          action_: 'o=',
878          nextState: 'o'
879        }
880      },
881      '->': {
882        '0|1|2|3': {
883          action_: 'r=',
884          nextState: 'r'
885        },
886        'a|as': {
887          action_: ['output', 'r='],
888          nextState: 'r'
889        },
890        '*': {
891          action_: ['output', 'r='],
892          nextState: 'r'
893        }
894      },
895      '+': {
896        'o': {
897          action_: 'd= kv',
898          nextState: 'd'
899        },
900        'd|D': {
901          action_: 'd=',
902          nextState: 'd'
903        },
904        'q': {
905          action_: 'd=',
906          nextState: 'qd'
907        },
908        'qd|qD': {
909          action_: 'd=',
910          nextState: 'qd'
911        },
912        'dq': {
913          action_: ['output', 'd='],
914          nextState: 'd'
915        },
916        '3': {
917          action_: ['sb=false', 'output', 'operator'],
918          nextState: '0'
919        }
920      },
921      'amount': {
922        '0|2': {
923          action_: 'a=',
924          nextState: 'a'
925        }
926      },
927      'pm-operator': {
928        '0|1|2|a|as': {
929          action_: ['sb=false', 'output', {
930            type_: 'operator',
931            option: '\\pm'
932          }],
933          nextState: '0'
934        }
935      },
936      'operator': {
937        '0|1|2|a|as': {
938          action_: ['sb=false', 'output', 'operator'],
939          nextState: '0'
940        }
941      },
942      '-$': {
943        'o|q': {
944          action_: ['charge or bond', 'output'],
945          nextState: 'qd'
946        },
947        'd': {
948          action_: 'd=',
949          nextState: 'd'
950        },
951        'D': {
952          action_: ['output', {
953            type_: 'bond',
954            option: "-"
955          }],
956          nextState: '3'
957        },
958        'q': {
959          action_: 'd=',
960          nextState: 'qd'
961        },
962        'qd': {
963          action_: 'd=',
964          nextState: 'qd'
965        },
966        'qD|dq': {
967          action_: ['output', {
968            type_: 'bond',
969            option: "-"
970          }],
971          nextState: '3'
972        }
973      },
974      '-9': {
975        '3|o': {
976          action_: ['output', {
977            type_: 'insert',
978            option: 'hyphen'
979          }],
980          nextState: '3'
981        }
982      },
983      '- orbital overlap': {
984        'o': {
985          action_: ['output', {
986            type_: 'insert',
987            option: 'hyphen'
988          }],
989          nextState: '2'
990        },
991        'd': {
992          action_: ['output', {
993            type_: 'insert',
994            option: 'hyphen'
995          }],
996          nextState: '2'
997        }
998      },
999      '-': {
1000        '0|1|2': {
1001          action_: [{
1002            type_: 'output',
1003            option: 1
1004          }, 'beginsWithBond=true', {
1005            type_: 'bond',
1006            option: "-"
1007          }],
1008          nextState: '3'
1009        },
1010        '3': {
1011          action_: {
1012            type_: 'bond',
1013            option: "-"
1014          }
1015        },
1016        'a': {
1017          action_: ['output', {
1018            type_: 'insert',
1019            option: 'hyphen'
1020          }],
1021          nextState: '2'
1022        },
1023        'as': {
1024          action_: [{
1025            type_: 'output',
1026            option: 2
1027          }, {
1028            type_: 'bond',
1029            option: "-"
1030          }],
1031          nextState: '3'
1032        },
1033        'b': {
1034          action_: 'b='
1035        },
1036        'o': {
1037          action_: {
1038            type_: '- after o/d',
1039            option: false
1040          },
1041          nextState: '2'
1042        },
1043        'q': {
1044          action_: {
1045            type_: '- after o/d',
1046            option: false
1047          },
1048          nextState: '2'
1049        },
1050        'd|qd|dq': {
1051          action_: {
1052            type_: '- after o/d',
1053            option: true
1054          },
1055          nextState: '2'
1056        },
1057        'D|qD|p': {
1058          action_: ['output', {
1059            type_: 'bond',
1060            option: "-"
1061          }],
1062          nextState: '3'
1063        }
1064      },
1065      'amount2': {
1066        '1|3': {
1067          action_: 'a=',
1068          nextState: 'a'
1069        }
1070      },
1071      'letters': {
1072        '0|1|2|3|a|as|b|p|bp|o': {
1073          action_: 'o=',
1074          nextState: 'o'
1075        },
1076        'q|dq': {
1077          action_: ['output', 'o='],
1078          nextState: 'o'
1079        },
1080        'd|D|qd|qD': {
1081          action_: 'o after d',
1082          nextState: 'o'
1083        }
1084      },
1085      'digits': {
1086        'o': {
1087          action_: 'q=',
1088          nextState: 'q'
1089        },
1090        'd|D': {
1091          action_: 'q=',
1092          nextState: 'dq'
1093        },
1094        'q': {
1095          action_: ['output', 'o='],
1096          nextState: 'o'
1097        },
1098        'a': {
1099          action_: 'o=',
1100          nextState: 'o'
1101        }
1102      },
1103      'space A': {
1104        'b|p|bp': {}
1105      },
1106      'space': {
1107        'a': {
1108          nextState: 'as'
1109        },
1110        '0': {
1111          action_: 'sb=false'
1112        },
1113        '1|2': {
1114          action_: 'sb=true'
1115        },
1116        'r|rt|rd|rdt|rdq': {
1117          action_: 'output',
1118          nextState: '0'
1119        },
1120        '*': {
1121          action_: ['output', 'sb=true'],
1122          nextState: '1'
1123        }
1124      },
1125      '1st-level escape': {
1126        '1|2': {
1127          action_: ['output', {
1128            type_: 'insert+p1',
1129            option: '1st-level escape'
1130          }]
1131        },
1132        '*': {
1133          action_: ['output', {
1134            type_: 'insert+p1',
1135            option: '1st-level escape'
1136          }],
1137          nextState: '0'
1138        }
1139      },
1140      '[(...)]': {
1141        'r|rt': {
1142          action_: 'rd=',
1143          nextState: 'rd'
1144        },
1145        'rd|rdt': {
1146          action_: 'rq=',
1147          nextState: 'rdq'
1148        }
1149      },
1150      '...': {
1151        'o|d|D|dq|qd|qD': {
1152          action_: ['output', {
1153            type_: 'bond',
1154            option: "..."
1155          }],
1156          nextState: '3'
1157        },
1158        '*': {
1159          action_: [{
1160            type_: 'output',
1161            option: 1
1162          }, {
1163            type_: 'insert',
1164            option: 'ellipsis'
1165          }],
1166          nextState: '1'
1167        }
1168      },
1169      '. |* ': {
1170        '*': {
1171          action_: ['output', {
1172            type_: 'insert',
1173            option: 'addition compound'
1174          }],
1175          nextState: '1'
1176        }
1177      },
1178      'state of aggregation $': {
1179        '*': {
1180          action_: ['output', 'state of aggregation'],
1181          nextState: '1'
1182        }
1183      },
1184      '{[(': {
1185        'a|as|o': {
1186          action_: ['o=', 'output', 'parenthesisLevel++'],
1187          nextState: '2'
1188        },
1189        '0|1|2|3': {
1190          action_: ['o=', 'output', 'parenthesisLevel++'],
1191          nextState: '2'
1192        },
1193        '*': {
1194          action_: ['output', 'o=', 'output', 'parenthesisLevel++'],
1195          nextState: '2'
1196        }
1197      },
1198      ')]}': {
1199        '0|1|2|3|b|p|bp|o': {
1200          action_: ['o=', 'parenthesisLevel--'],
1201          nextState: 'o'
1202        },
1203        'a|as|d|D|q|qd|qD|dq': {
1204          action_: ['output', 'o=', 'parenthesisLevel--'],
1205          nextState: 'o'
1206        }
1207      },
1208      ', ': {
1209        '*': {
1210          action_: ['output', 'comma'],
1211          nextState: '0'
1212        }
1213      },
1214      '^_': {
1215        // ^ and _ without a sensible argument
1216        '*': {}
1217      },
1218      '^{(...)}|^($...$)': {
1219        '0|1|2|as': {
1220          action_: 'b=',
1221          nextState: 'b'
1222        },
1223        'p': {
1224          action_: 'b=',
1225          nextState: 'bp'
1226        },
1227        '3|o': {
1228          action_: 'd= kv',
1229          nextState: 'D'
1230        },
1231        'q': {
1232          action_: 'd=',
1233          nextState: 'qD'
1234        },
1235        'd|D|qd|qD|dq': {
1236          action_: ['output', 'd='],
1237          nextState: 'D'
1238        }
1239      },
1240      '^a|^\\x{}{}|^\\x{}|^\\x|\'': {
1241        '0|1|2|as': {
1242          action_: 'b=',
1243          nextState: 'b'
1244        },
1245        'p': {
1246          action_: 'b=',
1247          nextState: 'bp'
1248        },
1249        '3|o': {
1250          action_: 'd= kv',
1251          nextState: 'd'
1252        },
1253        'q': {
1254          action_: 'd=',
1255          nextState: 'qd'
1256        },
1257        'd|qd|D|qD': {
1258          action_: 'd='
1259        },
1260        'dq': {
1261          action_: ['output', 'd='],
1262          nextState: 'd'
1263        }
1264      },
1265      '_{(state of aggregation)}$': {
1266        'd|D|q|qd|qD|dq': {
1267          action_: ['output', 'q='],
1268          nextState: 'q'
1269        }
1270      },
1271      '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': {
1272        '0|1|2|as': {
1273          action_: 'p=',
1274          nextState: 'p'
1275        },
1276        'b': {
1277          action_: 'p=',
1278          nextState: 'bp'
1279        },
1280        '3|o': {
1281          action_: 'q=',
1282          nextState: 'q'
1283        },
1284        'd|D': {
1285          action_: 'q=',
1286          nextState: 'dq'
1287        },
1288        'q|qd|qD|dq': {
1289          action_: ['output', 'q='],
1290          nextState: 'q'
1291        }
1292      },
1293      '=<>': {
1294        '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': {
1295          action_: [{
1296            type_: 'output',
1297            option: 2
1298          }, 'bond'],
1299          nextState: '3'
1300        }
1301      },
1302      '#': {
1303        '0|1|2|3|a|as|o': {
1304          action_: [{
1305            type_: 'output',
1306            option: 2
1307          }, {
1308            type_: 'bond',
1309            option: "#"
1310          }],
1311          nextState: '3'
1312        }
1313      },
1314      '{}': {
1315        '*': {
1316          action_: {
1317            type_: 'output',
1318            option: 1
1319          },
1320          nextState: '1'
1321        }
1322      },
1323      '{...}': {
1324        '0|1|2|3|a|as|b|p|bp': {
1325          action_: 'o=',
1326          nextState: 'o'
1327        },
1328        'o|d|D|q|qd|qD|dq': {
1329          action_: ['output', 'o='],
1330          nextState: 'o'
1331        }
1332      },
1333      '$...$': {
1334        'a': {
1335          action_: 'a='
1336        },
1337        // 2$n$
1338        '0|1|2|3|as|b|p|bp|o': {
1339          action_: 'o=',
1340          nextState: 'o'
1341        },
1342        // not 'amount'
1343        'as|o': {
1344          action_: 'o='
1345        },
1346        'q|d|D|qd|qD|dq': {
1347          action_: ['output', 'o='],
1348          nextState: 'o'
1349        }
1350      },
1351      '\\bond{(...)}': {
1352        '*': {
1353          action_: [{
1354            type_: 'output',
1355            option: 2
1356          }, 'bond'],
1357          nextState: "3"
1358        }
1359      },
1360      '\\frac{(...)}': {
1361        '*': {
1362          action_: [{
1363            type_: 'output',
1364            option: 1
1365          }, 'frac-output'],
1366          nextState: '3'
1367        }
1368      },
1369      '\\overset{(...)}': {
1370        '*': {
1371          action_: [{
1372            type_: 'output',
1373            option: 2
1374          }, 'overset-output'],
1375          nextState: '3'
1376        }
1377      },
1378      '\\underset{(...)}': {
1379        '*': {
1380          action_: [{
1381            type_: 'output',
1382            option: 2
1383          }, 'underset-output'],
1384          nextState: '3'
1385        }
1386      },
1387      '\\underbrace{(...)}': {
1388        '*': {
1389          action_: [{
1390            type_: 'output',
1391            option: 2
1392          }, 'underbrace-output'],
1393          nextState: '3'
1394        }
1395      },
1396      '\\color{(...)}{(...)}1|\\color(...){(...)}2': {
1397        '*': {
1398          action_: [{
1399            type_: 'output',
1400            option: 2
1401          }, 'color-output'],
1402          nextState: '3'
1403        }
1404      },
1405      '\\color{(...)}0': {
1406        '*': {
1407          action_: [{
1408            type_: 'output',
1409            option: 2
1410          }, 'color0-output']
1411        }
1412      },
1413      '\\ce{(...)}': {
1414        '*': {
1415          action_: [{
1416            type_: 'output',
1417            option: 2
1418          }, 'ce'],
1419          nextState: '3'
1420        }
1421      },
1422      '\\,': {
1423        '*': {
1424          action_: [{
1425            type_: 'output',
1426            option: 1
1427          }, 'copy'],
1428          nextState: '1'
1429        }
1430      },
1431      '\\x{}{}|\\x{}|\\x': {
1432        '0|1|2|3|a|as|b|p|bp|o|c0': {
1433          action_: ['o=', 'output'],
1434          nextState: '3'
1435        },
1436        '*': {
1437          action_: ['output', 'o=', 'output'],
1438          nextState: '3'
1439        }
1440      },
1441      'others': {
1442        '*': {
1443          action_: [{
1444            type_: 'output',
1445            option: 1
1446          }, 'copy'],
1447          nextState: '3'
1448        }
1449      },
1450      'else2': {
1451        'a': {
1452          action_: 'a to o',
1453          nextState: 'o',
1454          revisit: true
1455        },
1456        'as': {
1457          action_: ['output', 'sb=true'],
1458          nextState: '1',
1459          revisit: true
1460        },
1461        'r|rt|rd|rdt|rdq': {
1462          action_: ['output'],
1463          nextState: '0',
1464          revisit: true
1465        },
1466        '*': {
1467          action_: ['output', 'copy'],
1468          nextState: '3'
1469        }
1470      }
1471    }),
1472    actions: {
1473      'o after d': function oAfterD(buffer, m) {
1474        var ret;
1475
1476        if ((buffer.d || "").match(/^[0-9]+$/)) {
1477          var tmp = buffer.d;
1478          buffer.d = undefined;
1479          ret = this['output'](buffer);
1480          buffer.b = tmp;
1481        } else {
1482          ret = this['output'](buffer);
1483        }
1484
1485        mhchemParser.actions['o='](buffer, m);
1486        return ret;
1487      },
1488      'd= kv': function dKv(buffer, m) {
1489        buffer.d = m;
1490        buffer.dType = 'kv';
1491      },
1492      'charge or bond': function chargeOrBond(buffer, m) {
1493        if (buffer['beginsWithBond']) {
1494          /** @type {ParserOutput[]} */
1495          var ret = [];
1496          mhchemParser.concatArray(ret, this['output'](buffer));
1497          mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-"));
1498          return ret;
1499        } else {
1500          buffer.d = m;
1501        }
1502      },
1503      '- after o/d': function afterOD(buffer, m, isAfterD) {
1504        var c1 = mhchemParser.patterns.match_('orbital', buffer.o || "");
1505        var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || "");
1506        var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || "");
1507        var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || "");
1508        var hyphenFollows = m === "-" && (c1 && c1.remainder === "" || c2 || c3 || c4);
1509
1510        if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) {
1511          buffer.o = '$' + buffer.o + '$';
1512        }
1513        /** @type {ParserOutput[]} */
1514
1515
1516        var ret = [];
1517
1518        if (hyphenFollows) {
1519          mhchemParser.concatArray(ret, this['output'](buffer));
1520          ret.push({
1521            type_: 'hyphen'
1522          });
1523        } else {
1524          c1 = mhchemParser.patterns.match_('digits', buffer.d || "");
1525
1526          if (isAfterD && c1 && c1.remainder === '') {
1527            mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m));
1528            mhchemParser.concatArray(ret, this['output'](buffer));
1529          } else {
1530            mhchemParser.concatArray(ret, this['output'](buffer));
1531            mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-"));
1532          }
1533        }
1534
1535        return ret;
1536      },
1537      'a to o': function aToO(buffer) {
1538        buffer.o = buffer.a;
1539        buffer.a = undefined;
1540      },
1541      'sb=true': function sbTrue(buffer) {
1542        buffer.sb = true;
1543      },
1544      'sb=false': function sbFalse(buffer) {
1545        buffer.sb = false;
1546      },
1547      'beginsWithBond=true': function beginsWithBondTrue(buffer) {
1548        buffer['beginsWithBond'] = true;
1549      },
1550      'beginsWithBond=false': function beginsWithBondFalse(buffer) {
1551        buffer['beginsWithBond'] = false;
1552      },
1553      'parenthesisLevel++': function parenthesisLevel(buffer) {
1554        buffer['parenthesisLevel']++;
1555      },
1556      'parenthesisLevel--': function parenthesisLevel(buffer) {
1557        buffer['parenthesisLevel']--;
1558      },
1559      'state of aggregation': function stateOfAggregation(buffer, m) {
1560        return {
1561          type_: 'state of aggregation',
1562          p1: mhchemParser.go(m, 'o')
1563        };
1564      },
1565      'comma': function comma(buffer, m) {
1566        var a = m.replace(/\s*$/, '');
1567        var withSpace = a !== m;
1568
1569        if (withSpace && buffer['parenthesisLevel'] === 0) {
1570          return {
1571            type_: 'comma enumeration L',
1572            p1: a
1573          };
1574        } else {
1575          return {
1576            type_: 'comma enumeration M',
1577            p1: a
1578          };
1579        }
1580      },
1581      'output': function output(buffer, m, entityFollows) {
1582        // entityFollows:
1583        //   undefined = if we have nothing else to output, also ignore the just read space (buffer.sb)
1584        //   1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1)
1585        //   2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as)
1586
1587        /** @type {ParserOutput | ParserOutput[]} */
1588        var ret;
1589
1590        if (!buffer.r) {
1591          ret = [];
1592
1593          if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) ; else {
1594            if (buffer.sb) {
1595              ret.push({
1596                type_: 'entitySkip'
1597              });
1598            }
1599
1600            if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows !== 2) {
1601              buffer.o = buffer.a;
1602              buffer.a = undefined;
1603            } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) {
1604              buffer.o = buffer.a;
1605              buffer.d = buffer.b;
1606              buffer.q = buffer.p;
1607              buffer.a = buffer.b = buffer.p = undefined;
1608            } else {
1609              if (buffer.o && buffer.dType === 'kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) {
1610                buffer.dType = 'oxidation';
1611              } else if (buffer.o && buffer.dType === 'kv' && !buffer.q) {
1612                buffer.dType = undefined;
1613              }
1614            }
1615
1616            ret.push({
1617              type_: 'chemfive',
1618              a: mhchemParser.go(buffer.a, 'a'),
1619              b: mhchemParser.go(buffer.b, 'bd'),
1620              p: mhchemParser.go(buffer.p, 'pq'),
1621              o: mhchemParser.go(buffer.o, 'o'),
1622              q: mhchemParser.go(buffer.q, 'pq'),
1623              d: mhchemParser.go(buffer.d, buffer.dType === 'oxidation' ? 'oxidation' : 'bd'),
1624              dType: buffer.dType
1625            });
1626          }
1627        } else {
1628          // r
1629
1630          /** @type {ParserOutput[]} */
1631          var rd;
1632
1633          if (buffer.rdt === 'M') {
1634            rd = mhchemParser.go(buffer.rd, 'tex-math');
1635          } else if (buffer.rdt === 'T') {
1636            rd = [{
1637              type_: 'text',
1638              p1: buffer.rd || ""
1639            }];
1640          } else {
1641            rd = mhchemParser.go(buffer.rd);
1642          }
1643          /** @type {ParserOutput[]} */
1644
1645
1646          var rq;
1647
1648          if (buffer.rqt === 'M') {
1649            rq = mhchemParser.go(buffer.rq, 'tex-math');
1650          } else if (buffer.rqt === 'T') {
1651            rq = [{
1652              type_: 'text',
1653              p1: buffer.rq || ""
1654            }];
1655          } else {
1656            rq = mhchemParser.go(buffer.rq);
1657          }
1658
1659          ret = {
1660            type_: 'arrow',
1661            r: buffer.r,
1662            rd: rd,
1663            rq: rq
1664          };
1665        }
1666
1667        for (var p in buffer) {
1668          if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') {
1669            delete buffer[p];
1670          }
1671        }
1672
1673        return ret;
1674      },
1675      'oxidation-output': function oxidationOutput(buffer, m) {
1676        var ret = ["{"];
1677        mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation'));
1678        ret.push("}");
1679        return ret;
1680      },
1681      'frac-output': function fracOutput(buffer, m) {
1682        return {
1683          type_: 'frac-ce',
1684          p1: mhchemParser.go(m[0]),
1685          p2: mhchemParser.go(m[1])
1686        };
1687      },
1688      'overset-output': function oversetOutput(buffer, m) {
1689        return {
1690          type_: 'overset',
1691          p1: mhchemParser.go(m[0]),
1692          p2: mhchemParser.go(m[1])
1693        };
1694      },
1695      'underset-output': function undersetOutput(buffer, m) {
1696        return {
1697          type_: 'underset',
1698          p1: mhchemParser.go(m[0]),
1699          p2: mhchemParser.go(m[1])
1700        };
1701      },
1702      'underbrace-output': function underbraceOutput(buffer, m) {
1703        return {
1704          type_: 'underbrace',
1705          p1: mhchemParser.go(m[0]),
1706          p2: mhchemParser.go(m[1])
1707        };
1708      },
1709      'color-output': function colorOutput(buffer, m) {
1710        return {
1711          type_: 'color',
1712          color1: m[0],
1713          color2: mhchemParser.go(m[1])
1714        };
1715      },
1716      'r=': function r(buffer, m) {
1717        buffer.r = m;
1718      },
1719      'rdt=': function rdt(buffer, m) {
1720        buffer.rdt = m;
1721      },
1722      'rd=': function rd(buffer, m) {
1723        buffer.rd = m;
1724      },
1725      'rqt=': function rqt(buffer, m) {
1726        buffer.rqt = m;
1727      },
1728      'rq=': function rq(buffer, m) {
1729        buffer.rq = m;
1730      },
1731      'operator': function operator(buffer, m, p1) {
1732        return {
1733          type_: 'operator',
1734          kind_: p1 || m
1735        };
1736      }
1737    }
1738  },
1739  'a': {
1740    transitions: mhchemParser.createTransitions({
1741      'empty': {
1742        '*': {}
1743      },
1744      '1/2$': {
1745        '0': {
1746          action_: '1/2'
1747        }
1748      },
1749      'else': {
1750        '0': {
1751          nextState: '1',
1752          revisit: true
1753        }
1754      },
1755      '$(...)$': {
1756        '*': {
1757          action_: 'tex-math tight',
1758          nextState: '1'
1759        }
1760      },
1761      ',': {
1762        '*': {
1763          action_: {
1764            type_: 'insert',
1765            option: 'commaDecimal'
1766          }
1767        }
1768      },
1769      'else2': {
1770        '*': {
1771          action_: 'copy'
1772        }
1773      }
1774    }),
1775    actions: {}
1776  },
1777  'o': {
1778    transitions: mhchemParser.createTransitions({
1779      'empty': {
1780        '*': {}
1781      },
1782      '1/2$': {
1783        '0': {
1784          action_: '1/2'
1785        }
1786      },
1787      'else': {
1788        '0': {
1789          nextState: '1',
1790          revisit: true
1791        }
1792      },
1793      'letters': {
1794        '*': {
1795          action_: 'rm'
1796        }
1797      },
1798      '\\ca': {
1799        '*': {
1800          action_: {
1801            type_: 'insert',
1802            option: 'circa'
1803          }
1804        }
1805      },
1806      '\\x{}{}|\\x{}|\\x': {
1807        '*': {
1808          action_: 'copy'
1809        }
1810      },
1811      '${(...)}$|$(...)$': {
1812        '*': {
1813          action_: 'tex-math'
1814        }
1815      },
1816      '{(...)}': {
1817        '*': {
1818          action_: '{text}'
1819        }
1820      },
1821      'else2': {
1822        '*': {
1823          action_: 'copy'
1824        }
1825      }
1826    }),
1827    actions: {}
1828  },
1829  'text': {
1830    transitions: mhchemParser.createTransitions({
1831      'empty': {
1832        '*': {
1833          action_: 'output'
1834        }
1835      },
1836      '{...}': {
1837        '*': {
1838          action_: 'text='
1839        }
1840      },
1841      '${(...)}$|$(...)$': {
1842        '*': {
1843          action_: 'tex-math'
1844        }
1845      },
1846      '\\greek': {
1847        '*': {
1848          action_: ['output', 'rm']
1849        }
1850      },
1851      '\\,|\\x{}{}|\\x{}|\\x': {
1852        '*': {
1853          action_: ['output', 'copy']
1854        }
1855      },
1856      'else': {
1857        '*': {
1858          action_: 'text='
1859        }
1860      }
1861    }),
1862    actions: {
1863      'output': function output(buffer) {
1864        if (buffer.text_) {
1865          /** @type {ParserOutput} */
1866          var ret = {
1867            type_: 'text',
1868            p1: buffer.text_
1869          };
1870
1871          for (var p in buffer) {
1872            delete buffer[p];
1873          }
1874
1875          return ret;
1876        }
1877      }
1878    }
1879  },
1880  'pq': {
1881    transitions: mhchemParser.createTransitions({
1882      'empty': {
1883        '*': {}
1884      },
1885      'state of aggregation $': {
1886        '*': {
1887          action_: 'state of aggregation'
1888        }
1889      },
1890      'i$': {
1891        '0': {
1892          nextState: '!f',
1893          revisit: true
1894        }
1895      },
1896      '(KV letters),': {
1897        '0': {
1898          action_: 'rm',
1899          nextState: '0'
1900        }
1901      },
1902      'formula$': {
1903        '0': {
1904          nextState: 'f',
1905          revisit: true
1906        }
1907      },
1908      '1/2$': {
1909        '0': {
1910          action_: '1/2'
1911        }
1912      },
1913      'else': {
1914        '0': {
1915          nextState: '!f',
1916          revisit: true
1917        }
1918      },
1919      '${(...)}$|$(...)$': {
1920        '*': {
1921          action_: 'tex-math'
1922        }
1923      },
1924      '{(...)}': {
1925        '*': {
1926          action_: 'text'
1927        }
1928      },
1929      'a-z': {
1930        'f': {
1931          action_: 'tex-math'
1932        }
1933      },
1934      'letters': {
1935        '*': {
1936          action_: 'rm'
1937        }
1938      },
1939      '-9.,9': {
1940        '*': {
1941          action_: '9,9'
1942        }
1943      },
1944      ',': {
1945        '*': {
1946          action_: {
1947            type_: 'insert+p1',
1948            option: 'comma enumeration S'
1949          }
1950        }
1951      },
1952      '\\color{(...)}{(...)}1|\\color(...){(...)}2': {
1953        '*': {
1954          action_: 'color-output'
1955        }
1956      },
1957      '\\color{(...)}0': {
1958        '*': {
1959          action_: 'color0-output'
1960        }
1961      },
1962      '\\ce{(...)}': {
1963        '*': {
1964          action_: 'ce'
1965        }
1966      },
1967      '\\,|\\x{}{}|\\x{}|\\x': {
1968        '*': {
1969          action_: 'copy'
1970        }
1971      },
1972      'else2': {
1973        '*': {
1974          action_: 'copy'
1975        }
1976      }
1977    }),
1978    actions: {
1979      'state of aggregation': function stateOfAggregation(buffer, m) {
1980        return {
1981          type_: 'state of aggregation subscript',
1982          p1: mhchemParser.go(m, 'o')
1983        };
1984      },
1985      'color-output': function colorOutput(buffer, m) {
1986        return {
1987          type_: 'color',
1988          color1: m[0],
1989          color2: mhchemParser.go(m[1], 'pq')
1990        };
1991      }
1992    }
1993  },
1994  'bd': {
1995    transitions: mhchemParser.createTransitions({
1996      'empty': {
1997        '*': {}
1998      },
1999      'x$': {
2000        '0': {
2001          nextState: '!f',
2002          revisit: true
2003        }
2004      },
2005      'formula$': {
2006        '0': {
2007          nextState: 'f',
2008          revisit: true
2009        }
2010      },
2011      'else': {
2012        '0': {
2013          nextState: '!f',
2014          revisit: true
2015        }
2016      },
2017      '-9.,9 no missing 0': {
2018        '*': {
2019          action_: '9,9'
2020        }
2021      },
2022      '.': {
2023        '*': {
2024          action_: {
2025            type_: 'insert',
2026            option: 'electron dot'
2027          }
2028        }
2029      },
2030      'a-z': {
2031        'f': {
2032          action_: 'tex-math'
2033        }
2034      },
2035      'x': {
2036        '*': {
2037          action_: {
2038            type_: 'insert',
2039            option: 'KV x'
2040          }
2041        }
2042      },
2043      'letters': {
2044        '*': {
2045          action_: 'rm'
2046        }
2047      },
2048      '\'': {
2049        '*': {
2050          action_: {
2051            type_: 'insert',
2052            option: 'prime'
2053          }
2054        }
2055      },
2056      '${(...)}$|$(...)$': {
2057        '*': {
2058          action_: 'tex-math'
2059        }
2060      },
2061      '{(...)}': {
2062        '*': {
2063          action_: 'text'
2064        }
2065      },
2066      '\\color{(...)}{(...)}1|\\color(...){(...)}2': {
2067        '*': {
2068          action_: 'color-output'
2069        }
2070      },
2071      '\\color{(...)}0': {
2072        '*': {
2073          action_: 'color0-output'
2074        }
2075      },
2076      '\\ce{(...)}': {
2077        '*': {
2078          action_: 'ce'
2079        }
2080      },
2081      '\\,|\\x{}{}|\\x{}|\\x': {
2082        '*': {
2083          action_: 'copy'
2084        }
2085      },
2086      'else2': {
2087        '*': {
2088          action_: 'copy'
2089        }
2090      }
2091    }),
2092    actions: {
2093      'color-output': function colorOutput(buffer, m) {
2094        return {
2095          type_: 'color',
2096          color1: m[0],
2097          color2: mhchemParser.go(m[1], 'bd')
2098        };
2099      }
2100    }
2101  },
2102  'oxidation': {
2103    transitions: mhchemParser.createTransitions({
2104      'empty': {
2105        '*': {}
2106      },
2107      'roman numeral': {
2108        '*': {
2109          action_: 'roman-numeral'
2110        }
2111      },
2112      '${(...)}$|$(...)$': {
2113        '*': {
2114          action_: 'tex-math'
2115        }
2116      },
2117      'else': {
2118        '*': {
2119          action_: 'copy'
2120        }
2121      }
2122    }),
2123    actions: {
2124      'roman-numeral': function romanNumeral(buffer, m) {
2125        return {
2126          type_: 'roman numeral',
2127          p1: m || ""
2128        };
2129      }
2130    }
2131  },
2132  'tex-math': {
2133    transitions: mhchemParser.createTransitions({
2134      'empty': {
2135        '*': {
2136          action_: 'output'
2137        }
2138      },
2139      '\\ce{(...)}': {
2140        '*': {
2141          action_: ['output', 'ce']
2142        }
2143      },
2144      '{...}|\\,|\\x{}{}|\\x{}|\\x': {
2145        '*': {
2146          action_: 'o='
2147        }
2148      },
2149      'else': {
2150        '*': {
2151          action_: 'o='
2152        }
2153      }
2154    }),
2155    actions: {
2156      'output': function output(buffer) {
2157        if (buffer.o) {
2158          /** @type {ParserOutput} */
2159          var ret = {
2160            type_: 'tex-math',
2161            p1: buffer.o
2162          };
2163
2164          for (var p in buffer) {
2165            delete buffer[p];
2166          }
2167
2168          return ret;
2169        }
2170      }
2171    }
2172  },
2173  'tex-math tight': {
2174    transitions: mhchemParser.createTransitions({
2175      'empty': {
2176        '*': {
2177          action_: 'output'
2178        }
2179      },
2180      '\\ce{(...)}': {
2181        '*': {
2182          action_: ['output', 'ce']
2183        }
2184      },
2185      '{...}|\\,|\\x{}{}|\\x{}|\\x': {
2186        '*': {
2187          action_: 'o='
2188        }
2189      },
2190      '-|+': {
2191        '*': {
2192          action_: 'tight operator'
2193        }
2194      },
2195      'else': {
2196        '*': {
2197          action_: 'o='
2198        }
2199      }
2200    }),
2201    actions: {
2202      'tight operator': function tightOperator(buffer, m) {
2203        buffer.o = (buffer.o || "") + "{" + m + "}";
2204      },
2205      'output': function output(buffer) {
2206        if (buffer.o) {
2207          /** @type {ParserOutput} */
2208          var ret = {
2209            type_: 'tex-math',
2210            p1: buffer.o
2211          };
2212
2213          for (var p in buffer) {
2214            delete buffer[p];
2215          }
2216
2217          return ret;
2218        }
2219      }
2220    }
2221  },
2222  '9,9': {
2223    transitions: mhchemParser.createTransitions({
2224      'empty': {
2225        '*': {}
2226      },
2227      ',': {
2228        '*': {
2229          action_: 'comma'
2230        }
2231      },
2232      'else': {
2233        '*': {
2234          action_: 'copy'
2235        }
2236      }
2237    }),
2238    actions: {
2239      'comma': function comma() {
2240        return {
2241          type_: 'commaDecimal'
2242        };
2243      }
2244    }
2245  },
2246  //#endregion
2247  //
2248  // \pu state machines
2249  //
2250  //#region pu
2251  'pu': {
2252    transitions: mhchemParser.createTransitions({
2253      'empty': {
2254        '*': {
2255          action_: 'output'
2256        }
2257      },
2258      'space$': {
2259        '*': {
2260          action_: ['output', 'space']
2261        }
2262      },
2263      '{[(|)]}': {
2264        '0|a': {
2265          action_: 'copy'
2266        }
2267      },
2268      '(-)(9)^(-9)': {
2269        '0': {
2270          action_: 'number^',
2271          nextState: 'a'
2272        }
2273      },
2274      '(-)(9.,9)(e)(99)': {
2275        '0': {
2276          action_: 'enumber',
2277          nextState: 'a'
2278        }
2279      },
2280      'space': {
2281        '0|a': {}
2282      },
2283      'pm-operator': {
2284        '0|a': {
2285          action_: {
2286            type_: 'operator',
2287            option: '\\pm'
2288          },
2289          nextState: '0'
2290        }
2291      },
2292      'operator': {
2293        '0|a': {
2294          action_: 'copy',
2295          nextState: '0'
2296        }
2297      },
2298      '//': {
2299        'd': {
2300          action_: 'o=',
2301          nextState: '/'
2302        }
2303      },
2304      '/': {
2305        'd': {
2306          action_: 'o=',
2307          nextState: '/'
2308        }
2309      },
2310      '{...}|else': {
2311        '0|d': {
2312          action_: 'd=',
2313          nextState: 'd'
2314        },
2315        'a': {
2316          action_: ['space', 'd='],
2317          nextState: 'd'
2318        },
2319        '/|q': {
2320          action_: 'q=',
2321          nextState: 'q'
2322        }
2323      }
2324    }),
2325    actions: {
2326      'enumber': function enumber(buffer, m) {
2327        /** @type {ParserOutput[]} */
2328        var ret = [];
2329
2330        if (m[0] === "+-" || m[0] === "+/-") {
2331          ret.push("\\pm ");
2332        } else if (m[0]) {
2333          ret.push(m[0]);
2334        }
2335
2336        if (m[1]) {
2337          mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9'));
2338
2339          if (m[2]) {
2340            if (m[2].match(/[,.]/)) {
2341              mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9'));
2342            } else {
2343              ret.push(m[2]);
2344            }
2345          }
2346
2347          m[3] = m[4] || m[3];
2348
2349          if (m[3]) {
2350            m[3] = m[3].trim();
2351
2352            if (m[3] === "e" || m[3].substr(0, 1) === "*") {
2353              ret.push({
2354                type_: 'cdot'
2355              });
2356            } else {
2357              ret.push({
2358                type_: 'times'
2359              });
2360            }
2361          }
2362        }
2363
2364        if (m[3]) {
2365          ret.push("10^{" + m[5] + "}");
2366        }
2367
2368        return ret;
2369      },
2370      'number^': function number(buffer, m) {
2371        /** @type {ParserOutput[]} */
2372        var ret = [];
2373
2374        if (m[0] === "+-" || m[0] === "+/-") {
2375          ret.push("\\pm ");
2376        } else if (m[0]) {
2377          ret.push(m[0]);
2378        }
2379
2380        mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9'));
2381        ret.push("^{" + m[2] + "}");
2382        return ret;
2383      },
2384      'operator': function operator(buffer, m, p1) {
2385        return {
2386          type_: 'operator',
2387          kind_: p1 || m
2388        };
2389      },
2390      'space': function space() {
2391        return {
2392          type_: 'pu-space-1'
2393        };
2394      },
2395      'output': function output(buffer) {
2396        /** @type {ParserOutput | ParserOutput[]} */
2397        var ret;
2398        var md = mhchemParser.patterns.match_('{(...)}', buffer.d || "");
2399
2400        if (md && md.remainder === '') {
2401          buffer.d = md.match_;
2402        }
2403
2404        var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || "");
2405
2406        if (mq && mq.remainder === '') {
2407          buffer.q = mq.match_;
2408        }
2409
2410        if (buffer.d) {
2411          buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C");
2412          buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F");
2413        }
2414
2415        if (buffer.q) {
2416          // fraction
2417          buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C");
2418          buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F");
2419          var b5 = {
2420            d: mhchemParser.go(buffer.d, 'pu'),
2421            q: mhchemParser.go(buffer.q, 'pu')
2422          };
2423
2424          if (buffer.o === '//') {
2425            ret = {
2426              type_: 'pu-frac',
2427              p1: b5.d,
2428              p2: b5.q
2429            };
2430          } else {
2431            ret = b5.d;
2432
2433            if (b5.d.length > 1 || b5.q.length > 1) {
2434              ret.push({
2435                type_: ' / '
2436              });
2437            } else {
2438              ret.push({
2439                type_: '/'
2440              });
2441            }
2442
2443            mhchemParser.concatArray(ret, b5.q);
2444          }
2445        } else {
2446          // no fraction
2447          ret = mhchemParser.go(buffer.d, 'pu-2');
2448        }
2449
2450        for (var p in buffer) {
2451          delete buffer[p];
2452        }
2453
2454        return ret;
2455      }
2456    }
2457  },
2458  'pu-2': {
2459    transitions: mhchemParser.createTransitions({
2460      'empty': {
2461        '*': {
2462          action_: 'output'
2463        }
2464      },
2465      '*': {
2466        '*': {
2467          action_: ['output', 'cdot'],
2468          nextState: '0'
2469        }
2470      },
2471      '\\x': {
2472        '*': {
2473          action_: 'rm='
2474        }
2475      },
2476      'space': {
2477        '*': {
2478          action_: ['output', 'space'],
2479          nextState: '0'
2480        }
2481      },
2482      '^{(...)}|^(-1)': {
2483        '1': {
2484          action_: '^(-1)'
2485        }
2486      },
2487      '-9.,9': {
2488        '0': {
2489          action_: 'rm=',
2490          nextState: '0'
2491        },
2492        '1': {
2493          action_: '^(-1)',
2494          nextState: '0'
2495        }
2496      },
2497      '{...}|else': {
2498        '*': {
2499          action_: 'rm=',
2500          nextState: '1'
2501        }
2502      }
2503    }),
2504    actions: {
2505      'cdot': function cdot() {
2506        return {
2507          type_: 'tight cdot'
2508        };
2509      },
2510      '^(-1)': function _(buffer, m) {
2511        buffer.rm += "^{" + m + "}";
2512      },
2513      'space': function space() {
2514        return {
2515          type_: 'pu-space-2'
2516        };
2517      },
2518      'output': function output(buffer) {
2519        /** @type {ParserOutput | ParserOutput[]} */
2520        var ret = [];
2521
2522        if (buffer.rm) {
2523          var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || "");
2524
2525          if (mrm && mrm.remainder === '') {
2526            ret = mhchemParser.go(mrm.match_, 'pu');
2527          } else {
2528            ret = {
2529              type_: 'rm',
2530              p1: buffer.rm
2531            };
2532          }
2533        }
2534
2535        for (var p in buffer) {
2536          delete buffer[p];
2537        }
2538
2539        return ret;
2540      }
2541    }
2542  },
2543  'pu-9,9': {
2544    transitions: mhchemParser.createTransitions({
2545      'empty': {
2546        '0': {
2547          action_: 'output-0'
2548        },
2549        'o': {
2550          action_: 'output-o'
2551        }
2552      },
2553      ',': {
2554        '0': {
2555          action_: ['output-0', 'comma'],
2556          nextState: 'o'
2557        }
2558      },
2559      '.': {
2560        '0': {
2561          action_: ['output-0', 'copy'],
2562          nextState: 'o'
2563        }
2564      },
2565      'else': {
2566        '*': {
2567          action_: 'text='
2568        }
2569      }
2570    }),
2571    actions: {
2572      'comma': function comma() {
2573        return {
2574          type_: 'commaDecimal'
2575        };
2576      },
2577      'output-0': function output0(buffer) {
2578        /** @type {ParserOutput[]} */
2579        var ret = [];
2580        buffer.text_ = buffer.text_ || "";
2581
2582        if (buffer.text_.length > 4) {
2583          var a = buffer.text_.length % 3;
2584
2585          if (a === 0) {
2586            a = 3;
2587          }
2588
2589          for (var i = buffer.text_.length - 3; i > 0; i -= 3) {
2590            ret.push(buffer.text_.substr(i, 3));
2591            ret.push({
2592              type_: '1000 separator'
2593            });
2594          }
2595
2596          ret.push(buffer.text_.substr(0, a));
2597          ret.reverse();
2598        } else {
2599          ret.push(buffer.text_);
2600        }
2601
2602        for (var p in buffer) {
2603          delete buffer[p];
2604        }
2605
2606        return ret;
2607      },
2608      'output-o': function outputO(buffer) {
2609        /** @type {ParserOutput[]} */
2610        var ret = [];
2611        buffer.text_ = buffer.text_ || "";
2612
2613        if (buffer.text_.length > 4) {
2614          var a = buffer.text_.length - 3;
2615
2616          for (var i = 0; i < a; i += 3) {
2617            ret.push(buffer.text_.substr(i, 3));
2618            ret.push({
2619              type_: '1000 separator'
2620            });
2621          }
2622
2623          ret.push(buffer.text_.substr(i));
2624        } else {
2625          ret.push(buffer.text_);
2626        }
2627
2628        for (var p in buffer) {
2629          delete buffer[p];
2630        }
2631
2632        return ret;
2633      }
2634    } //#endregion
2635
2636  }
2637}; //
2638// texify: Take MhchemParser output and convert it to TeX
2639//
2640
2641/** @type {Texify} */
2642
2643var texify = {
2644  go: function go(input, isInner) {
2645    // (recursive, max 4 levels)
2646    if (!input) {
2647      return "";
2648    }
2649
2650    var res = "";
2651    var cee = false;
2652
2653    for (var i = 0; i < input.length; i++) {
2654      var inputi = input[i];
2655
2656      if (typeof inputi === "string") {
2657        res += inputi;
2658      } else {
2659        res += texify._go2(inputi);
2660
2661        if (inputi.type_ === '1st-level escape') {
2662          cee = true;
2663        }
2664      }
2665    }
2666
2667    if (!isInner && !cee && res) {
2668      res = "{" + res + "}";
2669    }
2670
2671    return res;
2672  },
2673  _goInner: function _goInner(input) {
2674    if (!input) {
2675      return input;
2676    }
2677
2678    return texify.go(input, true);
2679  },
2680  _go2: function _go2(buf) {
2681    /** @type {undefined | string} */
2682    var res;
2683
2684    switch (buf.type_) {
2685      case 'chemfive':
2686        res = "";
2687        var b5 = {
2688          a: texify._goInner(buf.a),
2689          b: texify._goInner(buf.b),
2690          p: texify._goInner(buf.p),
2691          o: texify._goInner(buf.o),
2692          q: texify._goInner(buf.q),
2693          d: texify._goInner(buf.d)
2694        }; //
2695        // a
2696        //
2697
2698        if (b5.a) {
2699          if (b5.a.match(/^[+\-]/)) {
2700            b5.a = "{" + b5.a + "}";
2701          }
2702
2703          res += b5.a + "\\,";
2704        } //
2705        // b and p
2706        //
2707
2708
2709        if (b5.b || b5.p) {
2710          res += "{\\vphantom{X}}";
2711          res += "^{\\hphantom{" + (b5.b || "") + "}}_{\\hphantom{" + (b5.p || "") + "}}";
2712          res += "{\\vphantom{X}}";
2713          res += "^{\\smash[t]{\\vphantom{2}}\\mathllap{" + (b5.b || "") + "}}";
2714          res += "_{\\vphantom{2}\\mathllap{\\smash[t]{" + (b5.p || "") + "}}}";
2715        } //
2716        // o
2717        //
2718
2719
2720        if (b5.o) {
2721          if (b5.o.match(/^[+\-]/)) {
2722            b5.o = "{" + b5.o + "}";
2723          }
2724
2725          res += b5.o;
2726        } //
2727        // q and d
2728        //
2729
2730
2731        if (buf.dType === 'kv') {
2732          if (b5.d || b5.q) {
2733            res += "{\\vphantom{X}}";
2734          }
2735
2736          if (b5.d) {
2737            res += "^{" + b5.d + "}";
2738          }
2739
2740          if (b5.q) {
2741            res += "_{\\smash[t]{" + b5.q + "}}";
2742          }
2743        } else if (buf.dType === 'oxidation') {
2744          if (b5.d) {
2745            res += "{\\vphantom{X}}";
2746            res += "^{" + b5.d + "}";
2747          }
2748
2749          if (b5.q) {
2750            res += "{\\vphantom{X}}";
2751            res += "_{\\smash[t]{" + b5.q + "}}";
2752          }
2753        } else {
2754          if (b5.q) {
2755            res += "{\\vphantom{X}}";
2756            res += "_{\\smash[t]{" + b5.q + "}}";
2757          }
2758
2759          if (b5.d) {
2760            res += "{\\vphantom{X}}";
2761            res += "^{" + b5.d + "}";
2762          }
2763        }
2764
2765        break;
2766
2767      case 'rm':
2768        res = "\\mathrm{" + buf.p1 + "}";
2769        break;
2770
2771      case 'text':
2772        if (buf.p1.match(/[\^_]/)) {
2773          buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}");
2774          res = "\\mathrm{" + buf.p1 + "}";
2775        } else {
2776          res = "\\text{" + buf.p1 + "}";
2777        }
2778
2779        break;
2780
2781      case 'roman numeral':
2782        res = "\\mathrm{" + buf.p1 + "}";
2783        break;
2784
2785      case 'state of aggregation':
2786        res = "\\mskip2mu " + texify._goInner(buf.p1);
2787        break;
2788
2789      case 'state of aggregation subscript':
2790        res = "\\mskip1mu " + texify._goInner(buf.p1);
2791        break;
2792
2793      case 'bond':
2794        res = texify._getBond(buf.kind_);
2795
2796        if (!res) {
2797          throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"];
2798        }
2799
2800        break;
2801
2802      case 'frac':
2803        var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}";
2804        res = "\\mathchoice{\\textstyle" + c + "}{" + c + "}{" + c + "}{" + c + "}";
2805        break;
2806
2807      case 'pu-frac':
2808        var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
2809        res = "\\mathchoice{\\textstyle" + d + "}{" + d + "}{" + d + "}{" + d + "}";
2810        break;
2811
2812      case 'tex-math':
2813        res = buf.p1 + " ";
2814        break;
2815
2816      case 'frac-ce':
2817        res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
2818        break;
2819
2820      case 'overset':
2821        res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
2822        break;
2823
2824      case 'underset':
2825        res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}";
2826        break;
2827
2828      case 'underbrace':
2829        res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}";
2830        break;
2831
2832      case 'color':
2833        res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}";
2834        break;
2835
2836      case 'color0':
2837        res = "\\color{" + buf.color + "}";
2838        break;
2839
2840      case 'arrow':
2841        var b6 = {
2842          rd: texify._goInner(buf.rd),
2843          rq: texify._goInner(buf.rq)
2844        };
2845
2846        var arrow = "\\x" + texify._getArrow(buf.r);
2847
2848        if (b6.rq) {
2849          arrow += "[{" + b6.rq + "}]";
2850        }
2851
2852        if (b6.rd) {
2853          arrow += "{" + b6.rd + "}";
2854        } else {
2855          arrow += "{}";
2856        }
2857
2858        res = arrow;
2859        break;
2860
2861      case 'operator':
2862        res = texify._getOperator(buf.kind_);
2863        break;
2864
2865      case '1st-level escape':
2866        res = buf.p1 + " "; // &, \\\\, \\hlin
2867
2868        break;
2869
2870      case 'space':
2871        res = " ";
2872        break;
2873
2874      case 'entitySkip':
2875        res = "~";
2876        break;
2877
2878      case 'pu-space-1':
2879        res = "~";
2880        break;
2881
2882      case 'pu-space-2':
2883        res = "\\mkern3mu ";
2884        break;
2885
2886      case '1000 separator':
2887        res = "\\mkern2mu ";
2888        break;
2889
2890      case 'commaDecimal':
2891        res = "{,}";
2892        break;
2893
2894      case 'comma enumeration L':
2895        res = "{" + buf.p1 + "}\\mkern6mu ";
2896        break;
2897
2898      case 'comma enumeration M':
2899        res = "{" + buf.p1 + "}\\mkern3mu ";
2900        break;
2901
2902      case 'comma enumeration S':
2903        res = "{" + buf.p1 + "}\\mkern1mu ";
2904        break;
2905
2906      case 'hyphen':
2907        res = "\\text{-}";
2908        break;
2909
2910      case 'addition compound':
2911        res = "\\,{\\cdot}\\,";
2912        break;
2913
2914      case 'electron dot':
2915        res = "\\mkern1mu \\bullet\\mkern1mu ";
2916        break;
2917
2918      case 'KV x':
2919        res = "{\\times}";
2920        break;
2921
2922      case 'prime':
2923        res = "\\prime ";
2924        break;
2925
2926      case 'cdot':
2927        res = "\\cdot ";
2928        break;
2929
2930      case 'tight cdot':
2931        res = "\\mkern1mu{\\cdot}\\mkern1mu ";
2932        break;
2933
2934      case 'times':
2935        res = "\\times ";
2936        break;
2937
2938      case 'circa':
2939        res = "{\\sim}";
2940        break;
2941
2942      case '^':
2943        res = "uparrow";
2944        break;
2945
2946      case 'v':
2947        res = "downarrow";
2948        break;
2949
2950      case 'ellipsis':
2951        res = "\\ldots ";
2952        break;
2953
2954      case '/':
2955        res = "/";
2956        break;
2957
2958      case ' / ':
2959        res = "\\,/\\,";
2960        break;
2961
2962      default:
2963        throw ["MhchemBugT", "mhchem bug T. Please report."];
2964      // Missing texify rule or unknown MhchemParser output
2965    }
2966    return res;
2967  },
2968  _getArrow: function _getArrow(a) {
2969    switch (a) {
2970      case "->":
2971        return "rightarrow";
2972
2973      case "\u2192":
2974        return "rightarrow";
2975
2976      case "\u27F6":
2977        return "rightarrow";
2978
2979      case "<-":
2980        return "leftarrow";
2981
2982      case "<->":
2983        return "leftrightarrow";
2984
2985      case "<-->":
2986        return "rightleftarrows";
2987
2988      case "<=>":
2989        return "rightleftharpoons";
2990
2991      case "\u21CC":
2992        return "rightleftharpoons";
2993
2994      case "<=>>":
2995        return "rightequilibrium";
2996
2997      case "<<=>":
2998        return "leftequilibrium";
2999
3000      default:
3001        throw ["MhchemBugT", "mhchem bug T. Please report."];
3002    }
3003  },
3004  _getBond: function _getBond(a) {
3005    switch (a) {
3006      case "-":
3007        return "{-}";
3008
3009      case "1":
3010        return "{-}";
3011
3012      case "=":
3013        return "{=}";
3014
3015      case "2":
3016        return "{=}";
3017
3018      case "#":
3019        return "{\\equiv}";
3020
3021      case "3":
3022        return "{\\equiv}";
3023
3024      case "~":
3025        return "{\\tripledash}";
3026
3027      case "~-":
3028        return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";
3029
3030      case "~=":
3031        return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";
3032
3033      case "~--":
3034        return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";
3035
3036      case "-~-":
3037        return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";
3038
3039      case "...":
3040        return "{{\\cdot}{\\cdot}{\\cdot}}";
3041
3042      case "....":
3043        return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";
3044
3045      case "->":
3046        return "{\\rightarrow}";
3047
3048      case "<-":
3049        return "{\\leftarrow}";
3050
3051      case "<":
3052        return "{<}";
3053
3054      case ">":
3055        return "{>}";
3056
3057      default:
3058        throw ["MhchemBugT", "mhchem bug T. Please report."];
3059    }
3060  },
3061  _getOperator: function _getOperator(a) {
3062    switch (a) {
3063      case "+":
3064        return " {}+{} ";
3065
3066      case "-":
3067        return " {}-{} ";
3068
3069      case "=":
3070        return " {}={} ";
3071
3072      case "<":
3073        return " {}<{} ";
3074
3075      case ">":
3076        return " {}>{} ";
3077
3078      case "<<":
3079        return " {}\\ll{} ";
3080
3081      case ">>":
3082        return " {}\\gg{} ";
3083
3084      case "\\pm":
3085        return " {}\\pm{} ";
3086
3087      case "\\approx":
3088        return " {}\\approx{} ";
3089
3090      case "$\\approx$":
3091        return " {}\\approx{} ";
3092
3093      case "v":
3094        return " \\downarrow{} ";
3095
3096      case "(v)":
3097        return " \\downarrow{} ";
3098
3099      case "^":
3100        return " \\uparrow{} ";
3101
3102      case "(^)":
3103        return " \\uparrow{} ";
3104
3105      default:
3106        throw ["MhchemBugT", "mhchem bug T. Please report."];
3107    }
3108  }
3109}; //
3110