public static string Interpret(Atom.MathList mathList, System.Func <string, string>?errorLaTeX = null) { errorLaTeX ??= error => $@"\color{{red}}\text{{{Atom.LaTeXParser.EscapeAsLaTeX(error)}}}"; (Atom.MathList left, Atom.MathList right)? equation = null; for (var i = 0; i < mathList.Count; i++) { if (mathList[i] is Atom.Atoms.Relation { Nucleus: "=" })
private MathList?BuildInternal(bool oneCharOnly, char stopChar = '\0') { if (oneCharOnly && stopChar > '\0') { throw new InvalidCodePathException("Cannot set both oneCharOnly and stopChar"); } var r = new MathList(); MathAtom?prevAtom = null; while (HasCharacters) { if (Error != null) { return(null); } MathAtom atom; switch (GetNextCharacter()) { case '^' when oneCharOnly: case '}' when oneCharOnly: case '_' when oneCharOnly: case '&' when oneCharOnly: // this is not the character we are looking for. They are for the caller to look at. UnlookCharacter(); return(r); case var ch when stopChar > '\0' && ch == stopChar: return(r); case '^': if (prevAtom == null || prevAtom.Superscript != null || !prevAtom.ScriptsAllowed) { prevAtom = new Ordinary(string.Empty); r.Add(prevAtom); } // this is a superscript for the previous atom. // note, if the next char is StopChar, it will be consumed and doesn't count as stop. prevAtom.Superscript = this.BuildInternal(true); continue; case '_': if (prevAtom == null || prevAtom.Subscript != null || !prevAtom.ScriptsAllowed) { prevAtom = new Ordinary(string.Empty); r.Add(prevAtom); } // this is a subscript for the previous atom. // note, if the next char is StopChar, it will be consumed and doesn't count as stop. prevAtom.Subscript = this.BuildInternal(true); continue; case '{': MathList?sublist; if (_currentEnvironment != null && _currentEnvironment.Name == null) { // \\ or \cr which do not have a corrosponding \end var oldEnv = _currentEnvironment; _currentEnvironment = null; sublist = BuildInternal(false, '}'); _currentEnvironment = oldEnv; } else { sublist = BuildInternal(false, '}'); } if (sublist == null) { return(null); } prevAtom = sublist.Atoms.LastOrDefault(); r.Append(sublist); if (oneCharOnly) { return(r); } continue; #warning TODO Example //https://phabricator.wikimedia.org/T99369 //https://phab.wmfusercontent.org/file/data/xsimlcnvo42siudvwuzk/PHID-FILE-bdcqexocj5b57tj2oezn/math_rendering.png //dt, \text{d}t, \partial t, \nabla\psi \\ \underline\overline{dy/dx, \text{d}y/\text{d}x, \frac{dy}{dx}, \frac{\text{d}y}{\text{d}x}, \frac{\partial^2}{\partial x_1\partial x_2}y} \\ \prime, case '}' when oneCharOnly || stopChar != 0: throw new InvalidCodePathException("This should have been handled before."); case '}': SetError("Missing opening brace"); return(null); case '\\': var command = ReadCommand(); var done = StopCommand(command, r, stopChar); if (done != null) { return(done); } if (Error != null) { return(null); } if (ApplyModifier(command, prevAtom)) { continue; } if (LaTeXDefaults.FontStyles.TryGetValue(command, out var fontStyle)) { var oldSpacesAllowed = _textMode; var oldFontStyle = _currentFontStyle; _textMode = (command == "text"); _currentFontStyle = fontStyle; var childList = BuildInternal(true); if (childList == null) { return(null); } _currentFontStyle = oldFontStyle; _textMode = oldSpacesAllowed; prevAtom = childList.Atoms.LastOrDefault(); r.Append(childList); if (oneCharOnly) { return(r); } continue; } switch (AtomForCommand(command, stopChar)) { case null: SetError(Error ?? "Internal error"); return(null); case var a: atom = a; break; } break; case '&': // column separation in tables if (_currentEnvironment != null) { return(r); } var table = BuildTable(null, r, false, stopChar); if (table == null) { return(null); } return(new MathList(table)); case '\'': // this case is NOT in iosMath int i = 1; while (ExpectCharacter('\'')) { i++; } atom = new Prime(i); break; case ' ' when _textMode: atom = new Ordinary(" "); break; case var ch when ch <= sbyte.MaxValue: if (LaTeXDefaults.ForAscii((sbyte)ch) is MathAtom asciiAtom) { atom = asciiAtom; } else { continue; // Ignore ASCII spaces and control characters } break; case var ch: // not a recognized character, display it directly atom = new Ordinary(ch.ToStringInvariant()); break; } atom.FontStyle = _currentFontStyle; r.Add(atom); prevAtom = atom; if (oneCharOnly) { return(r); // we consumed our character. } } if (stopChar > 0) { if (stopChar == '}') { SetError("Missing closing brace"); } else { // we never found our stop character. SetError("Expected character not found: " + stopChar.ToStringInvariant()); } } return(r); }