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