UNPKG

75.6 kBJavaScriptView Raw
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}; //