UNPKG

mhchemparser

Version:

Parser to convert mhchem syntax to LaTeX syntax, for downstream inclusion in MathJax, KaTeX and similar projects.

1,020 lines (1,019 loc) 78.1 kB
/*! ************************************************************************* * * mhchemParser.ts * 4.2.1 * * Parser for the \ce command and \pu command for MathJax and Co. * * mhchem's \ce is a tool for writing beautiful chemical equations easily. * mhchem's \pu is a tool for writing physical units easily. * * ---------------------------------------------------------------------- * * Copyright (c) 2015-2023 Martin Hensel * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ---------------------------------------------------------------------- * * https://github.com/mhchem/mhchemParser * */ export class mhchemParser { static toTex(input, type) { return _mhchemTexify.go(_mhchemParser.go(input, type), type !== "tex"); } } function _mhchemCreateTransitions(o) { let pattern, state; let transitions = {}; for (pattern in o) { for (state in o[pattern]) { let stateArray = state.split("|"); o[pattern][state].stateArray = stateArray; for (let i = 0; i < stateArray.length; i++) { transitions[stateArray[i]] = []; } } } for (pattern in o) { for (state in o[pattern]) { let stateArray = o[pattern][state].stateArray || []; for (let i = 0; i < stateArray.length; i++) { const p = o[pattern][state]; p.action_ = [].concat(p.action_); for (let k = 0; k < p.action_.length; k++) { if (typeof p.action_[k] === "string") { p.action_[k] = { type_: p.action_[k] }; } } const patternArray = pattern.split("|"); for (let j = 0; j < patternArray.length; j++) { if (stateArray[i] === '*') { let t; for (t in transitions) { transitions[t].push({ pattern: patternArray[j], task: p }); } } else { transitions[stateArray[i]].push({ pattern: patternArray[j], task: p }); } } } } } return transitions; } ; const _mhchemParser = { go: function (input, stateMachine) { if (!input) { return []; } if (stateMachine === undefined) { stateMachine = 'ce'; } let state = '0'; let buffer = {}; buffer['parenthesisLevel'] = 0; input = input.replace(/\n/g, " "); input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); input = input.replace(/[\u2026]/g, "..."); let lastInput; let watchdog = 10; let output = []; while (true) { if (lastInput !== input) { watchdog = 10; lastInput = input; } else { watchdog--; } let machine = _mhchemParser.stateMachines[stateMachine]; let t = machine.transitions[state] || machine.transitions['*']; iterateTransitions: for (let i = 0; i < t.length; i++) { let matches = _mhchemParser.patterns.match_(t[i].pattern, input); if (matches) { const task = t[i].task; for (let iA = 0; iA < task.action_.length; iA++) { let o; if (machine.actions[task.action_[iA].type_]) { o = machine.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option); } else if (_mhchemParser.actions[task.action_[iA].type_]) { o = _mhchemParser.actions[task.action_[iA].type_](buffer, matches.match_, task.action_[iA].option); } else { throw ["MhchemBugA", "mhchem bug A. Please report. (" + task.action_[iA].type_ + ")"]; } _mhchemParser.concatArray(output, o); } state = task.nextState || state; if (input.length > 0) { if (!task.revisit) { input = matches.remainder; } if (!task.toContinue) { break iterateTransitions; } } else { return output; } } } if (watchdog <= 0) { throw ["MhchemBugU", "mhchem bug U. Please report."]; } } }, concatArray: function (a, b) { if (b) { if (Array.isArray(b)) { for (let iB = 0; iB < b.length; iB++) { a.push(b[iB]); } } else { a.push(b); } } }, patterns: { patterns: { 'empty': /^$/, 'else': /^./, 'else2': /^./, 'space': /^\s/, 'space A': /^\s(?=[A-Z\\$])/, 'space$': /^\s$/, 'a-z': /^[a-z]/, 'x': /^x/, 'x$': /^x$/, 'i$': /^i$/, '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]))))+/, '\\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]))/, 'one lowercase latin letter $': /^(?:([a-z])(?:$|[^a-zA-Z]))$/, '$one lowercase latin letter$ $': /^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/, '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]))$/, 'digits': /^[0-9]+/, '-9.,9': /^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/, '-9.,9 no missing 0': /^[+\-]?[0-9]+(?:[.,][0-9]+)?/, '(-)(9.,9)(e)(99)': function (input) { const match = 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]+\}))?/); if (match && match[0]) { return { match_: match.slice(1), remainder: input.substr(match[0].length) }; } return null; }, '(-)(9)^(-9)': /^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/, 'state of aggregation $': function (input) { const a = _mhchemParser.patterns.findObserveGroups(input, "", /^\([a-z]{1,3}(?=[\),])/, ")", ""); if (a && a.remainder.match(/^($|[\s,;\)\]\}])/)) { return a; } const match = input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/); if (match) { return { match_: match[0], remainder: input.substr(match[0].length) }; } return null; }, '_{(state of aggregation)}$': /^_\{(\([a-z]{1,3}\))\}/, '{[(': /^(?:\\\{|\[|\()/, ')]}': /^(?:\)|\]|\\\})/, ', ': /^[,;]\s*/, ',': /^[,;]/, '.': /^[.]/, '. __* ': /^([.\u22C5\u00B7\u2022]|[*])\s*/, '...': /^\.\.\.(?=$|[^.])/, '^{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "^{", "", "", "}"); }, '^($...$)': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "^", "$", "$", ""); }, '^a': /^\^([0-9]+|[^\\_])/, '^\\x{}{}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, '^\\x{}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "^", /^\\[a-zA-Z]+\{/, "}", ""); }, '^\\x': /^\^(\\[a-zA-Z]+)\s*/, '^(-1)': /^\^(-?\d+)/, '\'': /^'/, '_{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "_{", "", "", "}"); }, '_($...$)': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "_", "$", "$", ""); }, '_9': /^_([+\-]?[0-9]+|[^\\])/, '_\\x{}{}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, '_\\x{}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "_", /^\\[a-zA-Z]+\{/, "}", ""); }, '_\\x': /^_(\\[a-zA-Z]+)\s*/, '^_': /^(?:\^(?=_)|\_(?=\^)|[\^_]$)/, '{}^': /^\{\}(?=\^)/, '{}': /^\{\}/, '{...}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "", "{", "}", ""); }, '{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "{", "", "", "}"); }, '$...$': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); }, '${(...)}$__$(...)$': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "${", "", "", "}$") || _mhchemParser.patterns.findObserveGroups(input, "$", "", "", "$"); }, '=<>': /^[=<>]/, '#': /^[#\u2261]/, '+': /^\+/, '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, '-9': /^-(?=[0-9])/, '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, '-': /^-/, 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, '\\bond{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, 'CMT': /^[CMT](?=\[)/, '[(...)]': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, '1st-level escape': /^(&|\\\\|\\hline)\s*/, '\\,': /^(?:\\[,\ ;:])/, '\\x{}{}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, '\\x{}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, 'others': /^[\/~|]/, '\\frac{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, '\\overset{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, '\\underset{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, '\\underbrace{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, '\\color{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, '\\color{(...)}{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}") || _mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, '\\ce{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, '\\pu{(...)}': function (input) { return _mhchemParser.patterns.findObserveGroups(input, "\\pu{", "", "", "}"); }, 'oxidation$': /^(?:[+-][IVX]+|(?:\\pm|\$\\pm\$|\+-|\+\/-)\s*0)$/, 'd-oxidation$': /^(?:[+-]?[IVX]+|(?:\\pm|\$\\pm\$|\+-|\+\/-)\s*0)$/, '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, 'amount': function (input) { let match; 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))/); if (match) { return { match_: match[0], remainder: input.substr(match[0].length) }; } const a = _mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); if (a) { match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); if (match) { return { match_: match[0], remainder: input.substr(match[0].length) }; } } return null; }, 'amount2': function (input) { return this['amount'](input); }, '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, 'formula$': function (input) { if (input.match(/^\([a-z]+\)$/)) { return null; } const match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); if (match) { return { match_: match[0], remainder: input.substr(match[0].length) }; } return null; }, 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, '/': /^\s*(\/)\s*/, '//': /^\s*(\/\/)\s*/, '*': /^\s*[*.]\s*/ }, findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { const _match = function (input, pattern) { if (typeof pattern === "string") { if (input.indexOf(pattern) !== 0) { return null; } return pattern; } else { const match = input.match(pattern); if (!match) { return null; } return match[0]; } }; const _findObserveGroups = function (input, i, endChars) { let braces = 0; while (i < input.length) { let a = input.charAt(i); const match = _match(input.substr(i), endChars); if (match !== null && braces === 0) { return { endMatchBegin: i, endMatchEnd: i + match.length }; } else if (a === "{") { braces++; } else if (a === "}") { if (braces === 0) { throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; } else { braces--; } } i++; } if (braces > 0) { return null; } return null; }; let match = _match(input, begExcl); if (match === null) { return null; } input = input.substr(match.length); match = _match(input, begIncl); if (match === null) { return null; } const e = _findObserveGroups(input, match.length, endIncl || endExcl); if (e === null) { return null; } const match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); if (!(beg2Excl || beg2Incl)) { return { match_: match1, remainder: input.substr(e.endMatchEnd) }; } else { const group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); if (group2 === null) { return null; } const matchRet = [match1, group2.match_]; return { match_: (combine ? matchRet.join("") : matchRet), remainder: group2.remainder }; } }, match_: function (m, input) { const pattern = _mhchemParser.patterns.patterns[m]; if (pattern === undefined) { throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; } else if (typeof pattern === "function") { return _mhchemParser.patterns.patterns[m](input); } else { const match = input.match(pattern); if (match) { if (match.length > 2) { return { match_: match.slice(1), remainder: input.substr(match[0].length) }; } else { return { match_: match[1] || match[0], remainder: input.substr(match[0].length) }; } } return null; } } }, actions: { 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; return undefined; }, 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; return undefined; }, 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; return undefined; }, 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; return undefined; }, 'o=+p1': function (buffer, _m, a) { buffer.o = (buffer.o || "") + a; return undefined; }, 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; return undefined; }, 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; return undefined; }, 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; return undefined; }, 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; return undefined; }, 'insert': function (_buffer, _m, a) { return { type_: a }; }, 'insert+p1': function (_buffer, m, a) { return { type_: a, p1: m }; }, 'insert+p1+p2': function (_buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, 'copy': function (_buffer, m) { return m; }, 'write': function (_buffer, _m, a) { return a; }, 'rm': function (_buffer, m) { return { type_: 'rm', p1: m }; }, 'text': function (_buffer, m) { return _mhchemParser.go(m, 'text'); }, 'tex-math': function (_buffer, m) { return _mhchemParser.go(m, 'tex-math'); }, 'tex-math tight': function (_buffer, m) { return _mhchemParser.go(m, 'tex-math tight'); }, 'bond': function (_buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, 'color0-output': function (_buffer, m) { return { type_: 'color0', color: m }; }, 'ce': function (_buffer, m) { return _mhchemParser.go(m, 'ce'); }, 'pu': function (_buffer, m) { return _mhchemParser.go(m, 'pu'); }, '1/2': function (_buffer, m) { let ret = []; if (m.match(/^[+\-]/)) { ret.push(m.substr(0, 1)); m = m.substr(1); } const n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); n[1] = n[1].replace(/\$/g, ""); ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); if (n[3]) { n[3] = n[3].replace(/\$/g, ""); ret.push({ type_: 'tex-math', p1: n[3] }); } return ret; }, '9,9': function (_buffer, m) { return _mhchemParser.go(m, '9,9'); } }, stateMachines: { 'tex': { transitions: _mhchemCreateTransitions({ 'empty': { '0': { action_: 'copy' } }, '\\ce{(...)}': { '0': { action_: [{ type_: 'write', option: "{" }, 'ce', { type_: 'write', option: "}" }] } }, '\\pu{(...)}': { '0': { action_: [{ type_: 'write', option: "{" }, 'pu', { type_: 'write', option: "}" }] } }, 'else': { '0': { action_: 'copy' } }, }), actions: {} }, 'ce': { transitions: _mhchemCreateTransitions({ 'empty': { '*': { action_: 'output' } }, 'else': { '0|1|2': { action_: 'beginsWithBond=false', revisit: true, toContinue: true } }, 'oxidation$': { '0': { action_: 'oxidation-output' } }, 'CMT': { 'r': { action_: 'rdt=', nextState: 'rt' }, 'rd': { action_: 'rqt=', nextState: 'rdt' } }, 'arrowUpDown': { '0|1|2|as': { action_: ['sb=false', 'output', 'operator'], nextState: '1' } }, 'uprightEntities': { '0|1|2': { action_: ['o=', 'output'], nextState: '1' } }, 'orbital': { '0|1|2|3': { action_: 'o=', nextState: 'o' } }, '->': { '0|1|2|3': { action_: 'r=', nextState: 'r' }, 'a|as': { action_: ['output', 'r='], nextState: 'r' }, '*': { action_: ['output', 'r='], nextState: 'r' } }, '+': { 'o': { action_: 'd= kv', nextState: 'd' }, 'd|D': { action_: 'd=', nextState: 'd' }, 'q': { action_: 'd=', nextState: 'qd' }, 'qd|qD': { action_: 'd=', nextState: 'qd' }, 'dq': { action_: ['output', 'd='], nextState: 'd' }, '3': { action_: ['sb=false', 'output', 'operator'], nextState: '0' } }, 'amount': { '0|2': { action_: 'a=', nextState: 'a' } }, 'pm-operator': { '0|1|2|a|as': { action_: ['sb=false', 'output', { type_: 'operator', option: '\\pm' }], nextState: '0' } }, 'operator': { '0|1|2|a|as': { action_: ['sb=false', 'output', 'operator'], nextState: '0' } }, '-$': { 'o|q': { action_: ['charge or bond', 'output'], nextState: 'qd' }, 'd': { action_: 'd=', nextState: 'd' }, 'D': { action_: ['output', { type_: 'bond', option: "-" }], nextState: '3' }, 'q': { action_: 'd=', nextState: 'qd' }, 'qd': { action_: 'd=', nextState: 'qd' }, 'qD|dq': { action_: ['output', { type_: 'bond', option: "-" }], nextState: '3' } }, '-9': { '3|o': { action_: ['output', { type_: 'insert', option: 'hyphen' }], nextState: '3' } }, '- orbital overlap': { 'o': { action_: ['output', { type_: 'insert', option: 'hyphen' }], nextState: '2' }, 'd': { action_: ['output', { type_: 'insert', option: 'hyphen' }], nextState: '2' } }, '-': { '0|1|2': { action_: [{ type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" }], nextState: '3' }, '3': { action_: { type_: 'bond', option: "-" } }, 'a': { action_: ['output', { type_: 'insert', option: 'hyphen' }], nextState: '2' }, 'as': { action_: [{ type_: 'output', option: 2 }, { type_: 'bond', option: "-" }], nextState: '3' }, 'b': { action_: 'b=' }, 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, 'D|qD|p': { action_: ['output', { type_: 'bond', option: "-" }], nextState: '3' } }, 'amount2': { '1|3': { action_: 'a=', nextState: 'a' } }, 'letters': { '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, 'digits': { 'o': { action_: 'q=', nextState: 'q' }, 'd|D': { action_: 'q=', nextState: 'dq' }, 'q': { action_: ['output', 'o='], nextState: 'o' }, 'a': { action_: 'o=', nextState: 'o' } }, 'space A': { 'b|p|bp': { action_: [] } }, 'space': { 'a': { action_: [], nextState: 'as' }, '0': { action_: 'sb=false' }, '1|2': { action_: 'sb=true' }, 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, '*': { action_: ['output', 'sb=true'], nextState: '1' } }, '1st-level escape': { '1|2': { action_: ['output', { type_: 'insert+p1', option: '1st-level escape' }] }, '*': { action_: ['output', { type_: 'insert+p1', option: '1st-level escape' }], nextState: '0' } }, '[(...)]': { 'r|rt': { action_: 'rd=', nextState: 'rd' }, 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, '...': { 'o|d|D|dq|qd|qD': { action_: ['output', { type_: 'bond', option: "..." }], nextState: '3' }, '*': { action_: [{ type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' }], nextState: '1' } }, '. __* ': { '*': { action_: ['output', { type_: 'insert', option: 'addition compound' }], nextState: '1' } }, 'state of aggregation $': { '*': { action_: ['output', 'state of aggregation'], nextState: '1' } }, '{[(': { 'a|as|o': { action_: ['o=', 'output', 'parenthesisLevel++'], nextState: '2' }, '0|1|2|3': { action_: ['o=', 'output', 'parenthesisLevel++'], nextState: '2' }, '*': { action_: ['output', 'o=', 'output', 'parenthesisLevel++'], nextState: '2' } }, ')]}': { '0|1|2|3|b|p|bp|o': { action_: ['o=', 'parenthesisLevel--'], nextState: 'o' }, 'a|as|d|D|q|qd|qD|dq': { action_: ['output', 'o=', 'parenthesisLevel--'], nextState: 'o' } }, ', ': { '*': { action_: ['output', 'comma'], nextState: '0' } }, '^_': { '*': { action_: [] } }, '^{(...)}|^($...$)': { '0|1|2|as': { action_: 'b=', nextState: 'b' }, 'p': { action_: 'b=', nextState: 'bp' }, '3|o': { action_: 'd= kv', nextState: 'D' }, 'q': { action_: 'd=', nextState: 'qD' }, 'd|D|qd|qD|dq': { action_: ['output', 'd='], nextState: 'D' } }, '^a|^\\x{}{}|^\\x{}|^\\x|\'': { '0|1|2|as': { action_: 'b=', nextState: 'b' }, 'p': { action_: 'b=', nextState: 'bp' }, '3|o': { action_: 'd= kv', nextState: 'd' }, 'q': { action_: 'd=', nextState: 'qd' }, 'd|qd|D|qD': { action_: 'd=' }, 'dq': { action_: ['output', 'd='], nextState: 'd' } }, '_{(state of aggregation)}$': { 'd|D|q|qd|qD|dq': { action_: ['output', 'q='], nextState: 'q' } }, '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { '0|1|2|as': { action_: 'p=', nextState: 'p' }, 'b': { action_: 'p=', nextState: 'bp' }, '3|o': { action_: 'q=', nextState: 'q' }, 'd|D': { action_: 'q=', nextState: 'dq' }, 'q|qd|qD|dq': { action_: ['output', 'q='], nextState: 'q' } }, '=<>': { '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [{ type_: 'output', option: 2 }, 'bond'], nextState: '3' } }, '#': { '0|1|2|3|a|as|o': { action_: [{ type_: 'output', option: 2 }, { type_: 'bond', option: "#" }], nextState: '3' } }, '{}^': { '*': { action_: [{ type_: 'output', option: 1 }, { type_: 'insert', option: 'tinySkip' }], nextState: '1' } }, '{}': { '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, '{...}': { '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, 'o|d|D|q|qd|qD|dq': { action_: ['output', 'o='], nextState: 'o' } }, '$...$': { 'a': { action_: 'a=' }, '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, 'as|o': { action_: 'o=' }, 'q|d|D|qd|qD|dq': { action_: ['output', 'o='], nextState: 'o' } }, '\\bond{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'bond'], nextState: "3" } }, '\\frac{(...)}': { '*': { action_: [{ type_: 'output', option: 1 }, 'frac-output'], nextState: '3' } }, '\\overset{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'overset-output'], nextState: '3' } }, '\\underset{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'underset-output'], nextState: '3' } }, '\\underbrace{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'underbrace-output'], nextState: '3' } }, '\\color{(...)}{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'color-output'], nextState: '3' } }, '\\color{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'color0-output'] } }, '\\ce{(...)}': { '*': { action_: [{ type_: 'output', option: 2 }, 'ce'], nextState: '3' } }, '\\,': { '*': { action_: [{ type_: 'output', option: 1 }, 'copy'], nextState: '1' } }, '\\pu{(...)}': { '*': { action_: ['output', { type_: 'write', option: "{" }, 'pu', { type_: 'write', option: "}" }], nextState: '3' } }, '\\x{}{}|\\x{}|\\x': { '0|1|2|3|a|as|b|p|bp|o|c0': { action_: ['o=', 'output'], nextState: '3' }, '*': { action_: ['output', 'o=', 'output'], nextState: '3' } }, 'others': { '*': { action_: [{ type_: 'output', option: 1 }, 'copy'], nextState: '3' } }, 'else2': { 'a': { action_: 'a to o', nextState: 'o', revisit: true }, 'as': { action_: ['output', 'sb=true'], nextState: '1', revisit: true }, 'r|rt|rd|rdt|rdq': { action_: ['output'], nextState: '0', revisit: true }, '*': { action_: ['output', 'copy'], nextState: '3' } } }), actions: { 'o after d': function (buffer, m) { let ret; if ((buffer.d || "").match(/^[1-9][0-9]*$/)) { const tmp = buffer.d; buffer.d = undefined; ret = this['output'](buffer); ret.push({ type_: 'tinySkip' }); buffer.b = tmp; } else { ret = this['output'](buffer); } _mhchemParser.actions['o='](buffer, m); return ret; }, 'd= kv': function (buffer, m) { buffer.d = m; buffer.dType = 'kv'; return undefined; }, 'charge or bond': function (buffer, m) { if (buffer['beginsWithBond']) { let ret = []; _mhchemParser.concatArray(ret, this['output'](buffer)); _mhchemParser.concatArray(ret, _mhchemParser.actions['bond'](buffer, m, "-")); return ret; } else { buffer.d = m; return undefined; } }, '- after o/d': function (buffer, m, isAfterD) { let c1 = _mhchemParser.patterns.match_('orbital', buffer.o || ""); const c2 = _mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); const c3 = _mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); const c4 = _mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); const hyphenFollows = m === "-" && (c1 && c1.remainder === "" || c2 || c3 || c4); if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { buffer.o = '$' + buffer.o + '$'; } let ret = []; if (hyphenFollows) { _mhchemParser.concatArray(ret, this['output'](buffer)); ret.push({ type_: 'hyphen' }); } else { c1 = _mhchemParser.patterns.match_('digits', buffer.d || ""); if (isAfterD && c1 && c1.remainder === '') { _mhchemParser.concatArray(ret, _mhchemParser.actions['d='](buffer, m)); _mhchemParser.concatArray(ret, this['output'](buffer)); } else { _mhchemParser.concatArray(ret, this['output'](buffer)); _mhchemParser.concatArray(ret, _mhchemParser.actions['bond'](buffer, m, "-")); } } return ret; }, 'a to o': function (buffer) { buffer.o = buffer.a; buffer.a = undefined; return undefined; }, 'sb=true': function (buffer) { buffer.sb = true; return undefined; }, 'sb=false': function (buffer) { buffer.sb = false; return undefined; }, 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; return undefined; }, 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; return undefined; }, 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; return undefined; }, 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; return undefined; }, 'state of aggregation': function (_buffer, m) { return { type_: 'state of aggregation', p1: _mhchemParser.go(m, 'o') }; }, 'comma': function (buffer, m) { const a = m.replace(/\s*$/, ''); const withSpace = (a !== m); if (withSpace && buffer['parenthesisLevel'] === 0) { return { type_: 'comma enumeration L', p1: a }; } else { return { type_: 'comma enumeration M', p1: a }; } }, 'output': function (buffer, _m, entityFollows) { let ret; if (!buffer.r) { ret = []; if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { } else { if (buffer.sb) { ret.push({ type_: 'entitySkip' }); } if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows !== 2) { buffer.o = buffer.a; buffer.a = undefined; } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { buffer.o = buffer.a; buffer.d = buffer.b; buffer.q = buffer.p; buffer.a = buffer.b = buffer.p = undefined; } else { if (buffer.o && buffer.dType === 'kv' && _mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { buffer.dType = 'oxidation'; } else if (buffer.o && buffer.dType === 'kv' && !buffer.q) { buffer.dType = undefined; } } ret.push({ type_: 'chemfive', a: _mhchemParser.go(buffer.a, 'a'), b: _mhchemParser.go(buffer.b, 'bd'), p: _mhchemParser.go(buffer.p, 'pq'), o: _mhchemParser.go(buffer.o, 'o'), q: _mhchemParser.go(buffer.q, 'pq'), d: _mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), dType: buffer.dType }); } } else { let rd; if (buffer.rdt === 'M') { rd = _mhchemParser.go(buffer.rd, 'tex-math'); } else if (buffer.rdt === 'T') { rd = [{ type_: 'text', p1: buffer.rd || "" }]; } else { rd = _mhchemParser.go(buffer.rd, 'ce'); } let rq; if (buffer.rqt === 'M') { rq = _mhchemParser.go(buffer.rq, 'tex-math'); } else if (buffer.rqt === 'T') { rq = [{ type_: 'text', p1: buffer.rq || "" }]; } else { rq = _mhchemParser.go(buffer.rq, 'ce'); } ret = { type_: 'arrow', r: buffer.r, rd: rd, rq: rq }; } for (const p in buffer) { if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { delete buffer[p]; } } return ret; }, 'oxidation-output': function (_buffer, m) { let ret = ["{"]; _mhchemParser.concatArray(ret, _mhchemParser.go(m, 'oxidation')); ret.push("}"); return ret; }, 'frac-output': function (_buffer, m) { return { type_: 'frac-ce', p1: _mhchemParser.go(m[0], 'ce'), p2: _mhchemParser.go(m[1], 'ce') }; }, 'overset-output': function (_buffer, m) { return { type_: 'overset', p1: _mhchemParser.go(m[0], 'ce'), p2: _mhchemParser.go(m[1], 'ce') }; }, 'underset-output': function (_buffer, m) { return { type_: 'underset', p1: _mhchemParser.go(m[0], 'ce'), p2: _mhchemParser.go(m[1], 'ce') }; }, 'underbrace-output': function (_buffer, m) { return { type_: 'underbrace', p1: _mhchemParser.go(m[0], 'ce'), p2: _mhchemParser.go(m[1], 'ce') }; }, 'color-output': function (_buffer, m) { return { type_: 'color', color1: m[0], color2: _mhchemParser.go(m[1], 'ce') }; }, 'r=': function (buffer, m) { buffer.r = m; return undefined; }, 'rdt=': function (buffer, m) { buffer.rdt = m; return undefined; }, 'rd=': function (buffer, m) { buffer.rd = m; return undefined; }, 'rqt=': function (buffer, m) { buffer.rqt = m; return undefined; }, 'rq=': function (buffer, m) { buffer.rq = m; return undefined; }, 'operator': function (_buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } } }, 'a': { transitions: _mhchemCreateTransitions({ 'empty': { '*': { action_: [] } }, '1/2$': { '0': { action_: '1/2' } }, 'else': { '0': { action_: [], nextState: '1', revisit: true } }, '${(...)}$__$(...)$': { '*': { action_: 'tex-math tight', nextState: '1' } }, ',': { '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, 'else2': { '*': { action_: 'copy' } } }), actions: {} }, 'o': { transitions: _mhchemCreateTransitions({ 'empty': { '*': { action_: [] } }, '1/2$': { '0': { action_: '1/2' } }, 'else': { '0': { action_: [], nextState: '1', revisit: true } }, 'letters': { '*': { action_: 'rm' } }, '\\ca': { '*': { action_: { type_: 'insert', option: 'circa' } } }, '\\pu{(...)}': { '*': { action_: [{ type_: 'write', option: "{" }, 'pu', { type_: 'write', option: "}" }] } }, '\\x{}{}|\\x{}|\\x': { '*': { action_: 'copy' } }, '${(...)}$__$(...)$': { '*': { action_: 'tex-math' } }, '{(...)}': { '*': { action_: [{ type_: 'write', option: "{" }, 'text', { type_: 'write', option: "}" }] } }, 'else2': { '*': { action_: 'copy' } } }), actions: {} }, 'text': { transitions: _mhchemCreateTransitions({ 'empty': { '*': { action_: 'output' } }, '{...}': { '*': { action_: 'text=' } }, '${(...)}$__$(...)$': { '*': { action_: 'tex-math' } }, '\\greek': { '*': { action_: ['output', 'rm'] } }, '\\pu{(...)}': { '*': { action_: ['output', { type_: 'write', option: "{" }, 'pu', { type_: 'write', option: "}" }] } }, '\\,|\\x{}{}|\\x{}|\\x': { '*': { action_: ['output', 'copy'] } }, 'else': { '*': { action_: 'text=' } } }), actions: { 'output': function (buffer) { if (buffer.text_) { let ret = { type_: 'text', p1: buffer.text_ }; for (const p in buffer) { delete buffer[p]; } return ret; } return undefined; } } }, 'pq': { transitions: _mhchemCreateTransitions({ 'empty': { '*': { action_: [] } }, 'state of aggregation $': { '*': { action_: 'state of aggregation' } }, 'i$': { '0': { action_: [], nextState: '!f', revisit: true } }, '(KV letters),': { '0': { action_: 'rm', nextState: '0' } }, 'formula$': { '0': { action_: [], nextState: 'f', revisit: true } }, '1/2$': { '0': { action_: '1/2' } }, 'else': { '0': { action_: [], nextState: '!f', revisit: true } }, '${(...)}$__$(...)$': { '*': { action_: 'tex-math' } }, '{(...)}': { '*': { action_: 'text' } }, 'a-z': { 'f': { action_: 'tex-math' } }, 'letters': { '*': { action_: 'rm' } }, '-9.,9': { '*': { action_: '9,9' } }, ',': { '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, '\\color{(...)}{(...)}': { '*': { action_: 'color-output' } }, '\\color{(...)}': { '*': { action_: 'color0-output' } }, '\\ce{(...)}': { '*': { action_: 'ce' } }, '\\pu{(...)}': { '*': { action_: [{ type_: 'write', option: "{" }, 'pu', { type_: 'write', option: "}" }] } }, '\\,|\\x{}{}|\\x{}|\\x': { '*': { action_: 'copy' } }, 'else2': { '*': { action_: 'copy' } } }), actions: { 'state of aggregation': function (_buffer, m) { return { type_: 'state of aggregation subscript', p1: _mhchemParser.go(m, 'o') }; }, 'color-output': function (_buffer, m) { return { type_: 'color', color1: m[0], color2: _mhchemParser.go(m[1], 'pq') }; } } }, 'bd': { transitions: _mhchemCreateTransitions({