{-
Copyright (C) 2009 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}{- | Functions for parsing a LaTeX formula to a Haskell representation.
-}moduleText.TeXMath.Parser(parseFormula)whereimportControl.MonadimportData.Char(isDigit,isAscii)importqualifiedData.MapasMimportText.ParserCombinators.ParsecimportqualifiedText.ParserCombinators.Parsec.TokenasPimportText.ParserCombinators.Parsec.LanguageimportText.TeXMath.TypesimportControl.Applicative((<*),(*>),(<$>))typeTP=GenParserChar()texMathDef::LanguageDefsttexMathDef=LanguageDef{commentStart="\\label{",commentEnd="}",commentLine="%",nestedComments=False,identStart=letter,identLetter=letter,opStart=opLettertexMathDef,opLetter=oneOf":_+*/=^-(),;.?'~[]<>!",reservedOpNames=[],reservedNames=[],caseSensitive=True}-- The parserexpr1::TPExpexpr1=choice[inbraces,variable,number,texSymbol,text,root,unary,binary,enclosure,environment,diacritical,escaped,unicode,ensuremath]-- | Parse a formula, returning a list of 'Exp'.parseFormula::String->EitherString[Exp]parseFormulainp=either(Left.show)(Right.id)$parseformula"formula"inpformula::TP[Exp]formula=dowhiteSpacef<-manyexprwhiteSpaceeofreturnfexpr::TPExpexpr=dooptional(try$symbol"\\displaystyle")a<-expr1limits<-limitsIndicatorsubSuplimitsa<|>superOrSubscriptedlimitsa<|>returnalimitsIndicator::TP(MaybeBool)limitsIndicator=try(symbol"\\limits">>return(JustTrue))<|>try(symbol"\\nolimits">>return(JustFalse))<|>returnNothinginbraces::TPExpinbraces=liftMEGrouped(braces$many$notFollowedBy(char'}')>>expr)texToken::TPExptexToken=texSymbol<|>inbraces<|>inbrackets<|>doc<-anyCharspacesreturn$ifisDigitcthen(ENumber[c])else(EIdentifier[c])inbrackets::TPExpinbrackets=liftMEGrouped(brackets$many$notFollowedBy(char']')>>expr)number::TPExpnumber=lexeme$liftMENumber$many1digitenclosure::TPExpenclosure=basicEnclosure<|>left<|>right<|>scaledEnclosurebasicEnclosure::TPExpbasicEnclosure=choice$map(\(s,v)->try(symbols)>>returnv)enclosuresleft::TPExpleft=try$dosymbol"\\left"enc<-basicEnclosure<|>(try(symbol".")>>return(ESymbolOpen"\xFEFF"))caseencof(ESymbolOpen_)->tilRightenc<|>return(EStretchyenc)_->pzeroright::TPExpright=try$dosymbol"\\right"enc<-basicEnclosure<|>(try(symbol".")>>return(ESymbolClose"\xFEFF"))caseencof(ESymbolClosex)->return(EStretchy$ESymbolOpenx)_->pzero-- We want stuff between \left( and \right) to be in an mrow,-- so that the scaling is based just on this unit, and not the-- whole containing formula.tilRight::Exp->TPExptilRightstart=try$docontents<-manyTillexpr(try$symbol"\\right">>lookAheadbasicEnclosure)end<-basicEnclosureletstartChar=casestartofESymbol_c->c_->""letendChar=caseendofESymbol_c->c_->""return$EDelimitedstartCharendCharcontentsscaledEnclosure::TPExpscaledEnclosure=try$docmd<-commandcaseM.lookupcmdscalersofJustr->liftM(EScaledr.EStretchy)basicEnclosureNothing->pzeroendLine::TPCharendLine=try$dosymbol"\\\\"optionalinbrackets-- can contain e.g. [1.0in] for a line height, not yet supportedreturn'\n'arrayLine::TPArrayLinearrayLine=notFollowedBy(try$symbol"\\end">>return'\n')>>sepBy1(many(notFollowedByendLine>>expr))(symbol"&")arrayAlignments::TP[Alignment]arrayAlignments=try$doas<-braces(manyletter)letletterToAlignment'l'=AlignLeftletterToAlignment'c'=AlignCenterletterToAlignment'r'=AlignRightletterToAlignment_=AlignDefaultreturn$mapletterToAlignmentasenvironment::TPExpenvironment=try$dosymbol"\\begin"name<-char'{'*>manyTillanyChar(char'}')spacesletname'=filter(/='*')namecaseM.lookupname'environmentsofJustenv->env<*spaces<*symbol"\\end"<*braces(stringname)<*spacesNothing->mzeroenvironments::M.MapString(TPExp)environments=M.fromList[("array",stdarray),("eqnarray",eqnarray),("align",align),("aligned",align),("alignat",inbraces*>spaces*>align),("alignedat",inbraces*>spaces*>align),("flalign",flalign),("flaligned",flalign),("cases",cases),("pmatrix",matrixWith"("")"),("bmatrix",matrixWith"[""]"),("Bmatrix",matrixWith"{""}"),("vmatrix",matrixWith"\x2223""\x2223"),("Vmatrix",matrixWith"\x2225""\x2225"),("split",align),("multiline",gather),("gather",gather),("gathered",gather)]matrixWith::String->String->TPExpmatrixWithopendelimclosedelim=doaligns<-option[]arrayAlignmentslines'<-sepEndBy1arrayLineendLinereturn$EDelimitedopendelimclosedelim[EArrayalignslines']stdarray::TPExpstdarray=doaligns<-option[]arrayAlignments(EArrayaligns)<$>sepEndBy1arrayLineendLinegather::TPExpgather=(EArray[])<$>sepEndByarrayLineendLineeqnarray::TPExpeqnarray=(EArray[AlignRight,AlignCenter,AlignLeft])<$>sepEndBy1arrayLineendLinealign::TPExpalign=(EArray[AlignRight,AlignLeft])<$>sepEndBy1arrayLineendLineflalign::TPExpflalign=(EArray[AlignLeft,AlignRight])<$>sepEndBy1arrayLineendLinecases::TPExpcases=dors<-sepEndBy1arrayLineendLinereturn$EDelimited"{"""[EArray[]rs]variable::TPExpvariable=dov<-letterspacesreturn$EIdentifier[v]isConvertible::Exp->BoolisConvertible(EMathOperatorx)=x`elem`convertibleOpswhereconvertibleOps=["lim","liminf","limsup","inf","sup","min","max","Pr","det","gcd"]isConvertible(ESymbolRel_)=TrueisConvertible(ESymbolBin_)=TrueisConvertible(ESymbolOpx)=x`elem`convertibleSymswhereconvertibleSyms=["\x2211","\x220F","\x22C2","\x22C3","\x22C0","\x22C1","\x2A05","\x2A06","\x2210","\x2A01","\x2A02","\x2A00","\x2A04"]isConvertible_=False-- check if sub/superscripts should always be under and over the expressionisUnderover::Exp->BoolisUnderover(EOver_(ESymbolAccent"\xFE37"))=True-- \overbraceisUnderover(EOver_(ESymbolAccent"\x23B4"))=True-- \overbracketisUnderover(EUnder_(ESymbolAccent"\xFE38"))=True-- \underbraceisUnderover(EUnder_(ESymbolAccent"\x23B5"))=True-- \underbracketisUnderover_=FalsesubSup::MaybeBool->Exp->TPExpsubSuplimitsa=try$doletsub1=symbol"_">>expr1letsup1=symbol"^">>expr1(b,c)<-try(do{m<-sub1;n<-sup1;return(m,n)})<|>(do{n<-sup1;m<-sub1;return(m,n)})return$caselimitsofJustTrue->EUnderoverabcNothing|isConvertiblea->EDownupabc|isUnderovera->EUnderoverabc_->ESubsupabcsuperOrSubscripted::MaybeBool->Exp->TPExpsuperOrSubscriptedlimitsa=try$doc<-oneOf"^_"spacesb<-exprcasecof'^'->return$caselimitsofJustTrue->EOverabNothing|isConvertiblea->EUpab|isUnderovera->EOverab_->ESuperab'_'->return$caselimitsofJustTrue->EUnderabNothing|isConvertiblea->EDownab|isUnderovera->EUnderab_->ESubab_->pzeroescaped::TPExpescaped=lexeme$try$char'\\'>>liftM(ESymbolOrd.(:[]))(satisfyisEscapable)whereisEscapable'{'=TrueisEscapable'}'=TrueisEscapable'$'=TrueisEscapable'%'=TrueisEscapable'&'=TrueisEscapable'_'=TrueisEscapable'#'=TrueisEscapable'^'=True-- actually only if followed by {}isEscapable' '=TrueisEscapable_=Falseunicode::TPExpunicode=lexeme$liftM(ESymbolOrd.(:[]))$satisfy(not.isAscii)ensuremath::TPExpensuremath=try$lexeme(string"\\ensuremath")>>inbracescommand::TPStringcommand=try$char'\\'>>liftM('\\':)(identifier<|>lexeme(count1anyChar))unaryOps::[String]unaryOps=["\\sqrt","\\surd"]-- Note: cal and scr are treated the same way, as unicode is lacking such two different sets for those.textOps::M.MapString(String->Exp)textOps=M.fromList[("\\textrm",ETextTextNormal.parseText),("\\mathrm",ETextTextNormal),("\\mathup",ETextTextNormal),("\\text",ETextTextNormal.parseText),("\\mbox",ETextTextNormal),("\\mathbf",ETextTextBold),("\\mathbfup",ETextTextBold),("\\textbf",ETextTextBold.parseText),("\\mathit",ETextTextItalic),("\\textit",ETextTextItalic.parseText),("\\mathtt",ETextTextMonospace),("\\texttt",ETextTextMonospace),("\\mathsf",ETextTextSansSerif),("\\mathsfup",ETextTextSansSerif),("\\mathbb",ETextTextDoubleStruck),("\\mathcal",ETextTextScript),("\\mathscr",ETextTextScript),("\\mathfrak",ETextTextFraktur),("\\mathbfit",ETextTextBoldItalic),("\\mathbfsfup",ETextTextBoldSansSerif),("\\mathbfsfit",ETextTextBoldSansSerifItalic),("\\mathbfscr",ETextTextBoldScript),("\\mathbffrak",ETextTextBoldFraktur),("\\mathbfcal",ETextTextBoldScript),("\\mathsfit",ETextTextSansSerifItalic)]parseText::String->StringparseText('`':'`':xs)='\x201C':parseTextxsparseText('\'':'\'':xs)='\x201D':parseTextxsparseText('\'':xs)='\x2019':parseTextxsparseText('-':'-':'-':xs)='\x2014':parseTextxsparseText('-':'-':xs)='\x2013':parseTextxsparseText('\\':'l':'d':'o':'t':'s':xs)='\x2026':parseTextxsparseText('~':xs)='\xA0':parseTextxsparseText(x:xs)=x:parseTextxsparseText[]=[]diacritical::TPExpdiacritical=try$doc<-commandcaseM.lookupcdiacriticalsofJustr->liftMrtexTokenNothing->pzerodiacriticals::M.MapString(Exp->Exp)diacriticals=M.fromList[("\\acute",\e->EOvere(ESymbolAccent"\x00B4")),("\\grave",\e->EOvere(ESymbolAccent"\x0060")),("\\breve",\e->EOvere(ESymbolAccent"\x02D8")),("\\check",\e->EOvere(ESymbolAccent"\x02C7")),("\\dot",\e->EOvere(ESymbolAccent".")),("\\ddot",\e->EOvere(ESymbolAccent"..")),("\\mathring",\e->EOvere(ESymbolAccent"\x00B0")),("\\vec",\e->EOvere(ESymbolAccent"\x20D7")),("\\overrightarrow",\e->EOvere(ESymbolAccent"\x20D7")),("\\overleftarrow",\e->EOvere(ESymbolAccent"\x20D6")),("\\hat",\e->EOvere(ESymbolAccent"\x005E")),("\\widehat",\e->EOvere(ESymbolAccent"\x0302")),("\\tilde",\e->EOvere(ESymbolAccent"~")),("\\widetilde",\e->EOvere(ESymbolAccent"\x02DC")),("\\bar",\e->EOvere(ESymbolAccent"\x203E")),("\\overbrace",\e->EOvere(ESymbolAccent"\xFE37")),("\\overbracket",\e->EOvere(ESymbolAccent"\x23B4")),("\\overline",\e->EOvere(ESymbolAccent"\x00AF")),("\\underbrace",\e->EUndere(ESymbolAccent"\xFE38")),("\\underbracket",\e->EUndere(ESymbolAccent"\x23B5")),("\\underline",\e->EUndere(ESymbolAccent"\x00AF"))]unary::TPExpunary=try$doc<-commandunless(c`elem`unaryOps)pzeroa<-texTokenreturn$EUnarycatext::TPExptext=try$doc<-commandcaseM.lookupctextOpsofJustf->liftMf$braces(many(noneOf"}"<|>(char'\\'>>char'}')))Nothing->pzero-- note: sqrt can be unary, \sqrt{2}, or binary, \sqrt[3]{2}root::TPExproot=try$dotry(symbol"\\sqrt")<|>symbol"\\surd"a<-inbracketsb<-texTokenreturn$EBinary"\\sqrt"babinary::TPExpbinary=try$doc<-commandunless(c`elem`binaryOps)pzeroa<-texTokenb<-texTokenreturn$EBinarycabtexSymbol::TPExptexSymbol=try$dosym<-operator<|>commandcaseM.lookupsymsymbolsofJusts->returnsNothing->pzero-- The lexerlexer::P.TokenParserstlexer=P.makeTokenParsertexMathDeflexeme::CharParsersta->CharParserstalexeme=P.lexemelexerwhiteSpace::CharParserst()whiteSpace=P.whiteSpacelexeridentifier::CharParserstStringidentifier=lexeme(P.identifierlexer)operator::CharParserstStringoperator=lexeme$many1(char'\'')<|>liftM(:[])(opLettertexMathDef)symbol::String->CharParserstStringsymbol=lexeme.P.symbollexerbraces::CharParsersta->CharParserstabraces=lexeme.P.braceslexerbrackets::CharParsersta->CharParserstabrackets=lexeme.P.bracketslexerbinaryOps::[String]binaryOps=["\\frac","\\tfrac","\\dfrac","\\stackrel","\\overset","\\underset","\\binom"]scalers::M.MapStringStringscalers=M.fromList[("\\bigg","2.2"),("\\Bigg","2.9"),("\\big","1.2"),("\\Big","1.6"),("\\biggr","2.2"),("\\Biggr","2.9"),("\\bigr","1.2"),("\\Bigr","1.6"),("\\biggl","2.2"),("\\Biggl","2.9"),("\\bigl","1.2"),("\\Bigl","1.6")]enclosures::[(String,Exp)]enclosures=[("(",ESymbolOpen"("),(")",ESymbolClose")"),("[",ESymbolOpen"["),("]",ESymbolClose"]"),("\\{",ESymbolOpen"{"),("\\}",ESymbolClose"}"),("\\lbrack",ESymbolOpen"["),("\\lbrace",ESymbolOpen"{"),("\\rbrack",ESymbolClose"]"),("\\rbrace",ESymbolClose"}"),("\\llbracket",ESymbolOpen"\x27E6"),("\\rrbracket",ESymbolClose"\x27E7"),("\\langle",ESymbolOpen"\x27E8"),("\\rangle",ESymbolClose"\x27E9"),("\\lfloor",ESymbolOpen"\x230A"),("\\rfloor",ESymbolClose"\x230B"),("\\lceil",ESymbolOpen"\x2308"),("\\rceil",ESymbolClose"\x2309"),("|",ESymbolOpen"\x2223"),("|",ESymbolClose"\x2223"),("\\|",ESymbolOpen"\x2225"),("\\|",ESymbolClose"\x2225"),("\\lvert",ESymbolOpen"\x7C"),("\\rvert",ESymbolClose"\x7C"),("\\vert",ESymbolClose"\x7C"),("\\lVert",ESymbolOpen"\x2225"),("\\rVert",ESymbolClose"\x2225"),("\\Vert",ESymbolClose"\x2016"),("\\ulcorner",ESymbolOpen"\x231C"),("\\urcorner",ESymbolClose"\x231D")]symbols::M.MapStringExpsymbols=M.fromList[("+",ESymbolBin"+"),("-",ESymbolBin"\x2212"),("*",ESymbolBin"*"),(",",ESymbolPun","),(".",ESymbolPun"."),(";",ESymbolPun";"),(":",ESymbolPun":"),("?",ESymbolPun"?"),(">",ESymbolRel">"),("<",ESymbolRel"<"),("!",ESymbolOrd"!"),("'",ESymbolOrd"\x02B9"),("''",ESymbolOrd"\x02BA"),("'''",ESymbolOrd"\x2034"),("''''",ESymbolOrd"\x2057"),("=",ESymbolRel"="),(":=",ESymbolRel":="),("\\mid",ESymbolBin"\x2223"),("\\parallel",ESymbolRel"\x2225"),("\\backslash",ESymbolBin"\x2216"),("/",ESymbolBin"/"),("\\setminus",ESymbolBin"\\"),("\\times",ESymbolBin"\x00D7"),("\\alpha",EIdentifier"\x03B1"),("\\beta",EIdentifier"\x03B2"),("\\chi",EIdentifier"\x03C7"),("\\delta",EIdentifier"\x03B4"),("\\Delta",ESymbolOp"\x0394"),("\\epsilon",EIdentifier"\x03B5"),("\\varepsilon",EIdentifier"\x025B"),("\\eta",EIdentifier"\x03B7"),("\\gamma",EIdentifier"\x03B3"),("\\Gamma",ESymbolOp"\x0393"),("\\iota",EIdentifier"\x03B9"),("\\kappa",EIdentifier"\x03BA"),("\\lambda",EIdentifier"\x03BB"),("\\Lambda",ESymbolOp"\x039B"),("\\mu",EIdentifier"\x03BC"),("\\nu",EIdentifier"\x03BD"),("\\omega",EIdentifier"\x03C9"),("\\Omega",ESymbolOp"\x03A9"),("\\phi",EIdentifier"\x03D5"),("\\varphi",EIdentifier"\x03C6"),("\\Phi",ESymbolOp"\x03A6"),("\\pi",EIdentifier"\x03C0"),("\\Pi",ESymbolOp"\x03A0"),("\\psi",EIdentifier"\x03C8"),("\\Psi",ESymbolOrd"\x03A8"),("\\rho",EIdentifier"\x03C1"),("\\sigma",EIdentifier"\x03C3"),("\\Sigma",ESymbolOp"\x03A3"),("\\tau",EIdentifier"\x03C4"),("\\theta",EIdentifier"\x03B8"),("\\vartheta",EIdentifier"\x03D1"),("\\Theta",ESymbolOp"\x0398"),("\\upsilon",EIdentifier"\x03C5"),("\\xi",EIdentifier"\x03BE"),("\\Xi",ESymbolOp"\x039E"),("\\zeta",EIdentifier"\x03B6"),("\\pm",ESymbolBin"\x00B1"),("\\mp",ESymbolBin"\x2213"),("\\triangleleft",ESymbolBin"\x22B2"),("\\triangleright",ESymbolBin"\x22B3"),("\\cdot",ESymbolBin"\x22C5"),("\\star",ESymbolBin"\x22C6"),("\\ast",ESymbolBin"\x002A"),("\\times",ESymbolBin"\x00D7"),("\\div",ESymbolBin"\x00F7"),("\\circ",ESymbolBin"\x2218"),("\\bullet",ESymbolBin"\x2022"),("\\oplus",ESymbolBin"\x2295"),("\\ominus",ESymbolBin"\x2296"),("\\otimes",ESymbolBin"\x2297"),("\\bigcirc",ESymbolBin"\x25CB"),("\\oslash",ESymbolBin"\x2298"),("\\odot",ESymbolBin"\x2299"),("\\land",ESymbolBin"\x2227"),("\\wedge",ESymbolBin"\x2227"),("\\lor",ESymbolBin"\x2228"),("\\vee",ESymbolBin"\x2228"),("\\cap",ESymbolBin"\x2229"),("\\cup",ESymbolBin"\x222A"),("\\sqcap",ESymbolBin"\x2293"),("\\sqcup",ESymbolBin"\x2294"),("\\uplus",ESymbolBin"\x228E"),("\\amalg",ESymbolBin"\x2210"),("\\bigtriangleup",ESymbolBin"\x25B3"),("\\bigtriangledown",ESymbolBin"\x25BD"),("\\dag",ESymbolBin"\x2020"),("\\dagger",ESymbolBin"\x2020"),("\\ddag",ESymbolBin"\x2021"),("\\ddagger",ESymbolBin"\x2021"),("\\lhd",ESymbolBin"\x22B2"),("\\rhd",ESymbolBin"\x22B3"),("\\unlhd",ESymbolBin"\x22B4"),("\\unrhd",ESymbolBin"\x22B5"),("\\lt",ESymbolRel"<"),("\\gt",ESymbolRel">"),("\\ne",ESymbolRel"\x2260"),("\\neq",ESymbolRel"\x2260"),("\\le",ESymbolRel"\x2264"),("\\leq",ESymbolRel"\x2264"),("\\leqslant",ESymbolRel"\x2264"),("\\ge",ESymbolRel"\x2265"),("\\geq",ESymbolRel"\x2265"),("\\geqslant",ESymbolRel"\x2265"),("\\equiv",ESymbolRel"\x2261"),("\\ll",ESymbolRel"\x226A"),("\\gg",ESymbolRel"\x226B"),("\\doteq",ESymbolRel"\x2250"),("\\prec",ESymbolRel"\x227A"),("\\succ",ESymbolRel"\x227B"),("\\preceq",ESymbolRel"\x227C"),("\\succeq",ESymbolRel"\x227D"),("\\subset",ESymbolRel"\x2282"),("\\supset",ESymbolRel"\x2283"),("\\subseteq",ESymbolRel"\x2286"),("\\supseteq",ESymbolRel"\x2287"),("\\sqsubset",ESymbolRel"\x228F"),("\\sqsupset",ESymbolRel"\x2290"),("\\sqsubseteq",ESymbolRel"\x2291"),("\\sqsupseteq",ESymbolRel"\x2292"),("\\sim",ESymbolRel"\x223C"),("\\simeq",ESymbolRel"\x2243"),("\\approx",ESymbolRel"\x2248"),("\\cong",ESymbolRel"\x2245"),("\\Join",ESymbolRel"\x22C8"),("\\bowtie",ESymbolRel"\x22C8"),("\\in",ESymbolRel"\x2208"),("\\ni",ESymbolRel"\x220B"),("\\owns",ESymbolRel"\x220B"),("\\propto",ESymbolRel"\x221D"),("\\vdash",ESymbolRel"\x22A2"),("\\dashv",ESymbolRel"\x22A3"),("\\models",ESymbolRel"\x22A8"),("\\perp",ESymbolRel"\x22A5"),("\\smile",ESymbolRel"\x2323"),("\\frown",ESymbolRel"\x2322"),("\\asymp",ESymbolRel"\x224D"),("\\notin",ESymbolRel"\x2209"),("\\gets",ESymbolRel"\x2190"),("\\leftarrow",ESymbolRel"\x2190"),("\\to",ESymbolRel"\x2192"),("\\rightarrow",ESymbolRel"\x2192"),("\\leftrightarrow",ESymbolRel"\x2194"),("\\uparrow",ESymbolRel"\x2191"),("\\downarrow",ESymbolRel"\x2193"),("\\updownarrow",ESymbolRel"\x2195"),("\\Leftarrow",ESymbolRel"\x21D0"),("\\Rightarrow",ESymbolRel"\x21D2"),("\\Leftrightarrow",ESymbolRel"\x21D4"),("\\iff",ESymbolRel"\x21D4"),("\\Uparrow",ESymbolRel"\x21D1"),("\\Downarrow",ESymbolRel"\x21D3"),("\\Updownarrow",ESymbolRel"\x21D5"),("\\mapsto",ESymbolRel"\x21A6"),("\\longleftarrow",ESymbolRel"\x2190"),("\\longrightarrow",ESymbolRel"\x2192"),("\\longleftrightarrow",ESymbolRel"\x2194"),("\\Longleftarrow",ESymbolRel"\x21D0"),("\\Longrightarrow",ESymbolRel"\x21D2"),("\\Longleftrightarrow",ESymbolRel"\x21D4"),("\\longmapsto",ESymbolRel"\x21A6"),("\\sum",ESymbolOp"\x2211"),("\\prod",ESymbolOp"\x220F"),("\\bigcap",ESymbolOp"\x22C2"),("\\bigcup",ESymbolOp"\x22C3"),("\\bigwedge",ESymbolOp"\x22C0"),("\\bigvee",ESymbolOp"\x22C1"),("\\bigsqcap",ESymbolOp"\x2A05"),("\\bigsqcup",ESymbolOp"\x2A06"),("\\coprod",ESymbolOp"\x2210"),("\\bigoplus",ESymbolOp"\x2A01"),("\\bigotimes",ESymbolOp"\x2A02"),("\\bigodot",ESymbolOp"\x2A00"),("\\biguplus",ESymbolOp"\x2A04"),("\\int",ESymbolOp"\x222B"),("\\iint",ESymbolOp"\x222C"),("\\iiint",ESymbolOp"\x222D"),("\\oint",ESymbolOp"\x222E"),("\\prime",ESymbolOrd"\x2032"),("\\dots",ESymbolOrd"\x2026"),("\\ldots",ESymbolOrd"\x2026"),("\\cdots",ESymbolOrd"\x22EF"),("\\vdots",ESymbolOrd"\x22EE"),("\\ddots",ESymbolOrd"\x22F1"),("\\forall",ESymbolOp"\x2200"),("\\exists",ESymbolOp"\x2203"),("\\Re",ESymbolOrd"\x211C"),("\\Im",ESymbolOrd"\x2111"),("\\aleph",ESymbolOrd"\x2135"),("\\hbar",ESymbolOrd"\x210F"),("\\ell",ESymbolOrd"\x2113"),("\\wp",ESymbolOrd"\x2118"),("\\emptyset",ESymbolOrd"\x2205"),("\\infty",ESymbolOrd"\x221E"),("\\partial",ESymbolOrd"\x2202"),("\\nabla",ESymbolOrd"\x2207"),("\\triangle",ESymbolOrd"\x25B3"),("\\therefore",ESymbolPun"\x2234"),("\\angle",ESymbolOrd"\x2220"),("\\diamond",ESymbolOp"\x22C4"),("\\Diamond",ESymbolOp"\x25C7"),("\\lozenge",ESymbolOp"\x25CA"),("\\neg",ESymbolOp"\x00AC"),("\\lnot",ESymbolOrd"\x00AC"),("\\bot",ESymbolOrd"\x22A5"),("\\top",ESymbolOrd"\x22A4"),("\\square",ESymbolOrd"\x25AB"),("\\Box",ESymbolOp"\x25A1"),("\\wr",ESymbolOrd"\x2240"),("\\!",ESpace"-0.167em"),("\\,",ESpace"0.167em"),("\\>",ESpace"0.222em"),("\\:",ESpace"0.222em"),("\\;",ESpace"0.278em"),("~",ESpace"0.333em"),("\\quad",ESpace"1em"),("\\qquad",ESpace"2em"),("\\arccos",EMathOperator"arccos"),("\\arcsin",EMathOperator"arcsin"),("\\arctan",EMathOperator"arctan"),("\\arg",EMathOperator"arg"),("\\cos",EMathOperator"cos"),("\\cosh",EMathOperator"cosh"),("\\cot",EMathOperator"cot"),("\\coth",EMathOperator"coth"),("\\csc",EMathOperator"csc"),("\\deg",EMathOperator"deg"),("\\det",EMathOperator"det"),("\\dim",EMathOperator"dim"),("\\exp",EMathOperator"exp"),("\\gcd",EMathOperator"gcd"),("\\hom",EMathOperator"hom"),("\\inf",EMathOperator"inf"),("\\ker",EMathOperator"ker"),("\\lg",EMathOperator"lg"),("\\lim",EMathOperator"lim"),("\\liminf",EMathOperator"liminf"),("\\limsup",EMathOperator"limsup"),("\\ln",EMathOperator"ln"),("\\log",EMathOperator"log"),("\\max",EMathOperator"max"),("\\min",EMathOperator"min"),("\\Pr",EMathOperator"Pr"),("\\sec",EMathOperator"sec"),("\\sin",EMathOperator"sin"),("\\sinh",EMathOperator"sinh"),("\\sup",EMathOperator"sup"),("\\tan",EMathOperator"tan"),("\\tanh",EMathOperator"tanh")]