{- Copyright (C) 2009 John MacFarlane 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. -} module Text.TeXMath.Parser (parseFormula) where import Control.Monad import Data.Char (isAlphaNum, isDigit, isAscii) import qualified Data.Map as M import Text.ParserCombinators.Parsec import qualified Text.ParserCombinators.Parsec.Token as P import Text.ParserCombinators.Parsec.Language import Text.TeXMath.Types texMathDef :: LanguageDef st texMathDef = LanguageDef { commentStart = "" , commentEnd = "" , commentLine = "%" , nestedComments = False , identStart = letter , identLetter = letter , opStart = opLetter texMathDef , opLetter = oneOf ":_+*/=^-(),;.?'~[]<>!" , reservedOpNames= [] , reservedNames = [] , caseSensitive = True } -- The parser expr1 :: GenParser Char st Exp expr1 = choice [ inbraces , variable , number , texSymbol , text , root , unary , binary , enclosure , array , diacritical , escaped , unicode , ensuremath ] -- | Parse a formula, returning a list of 'Exp'. parseFormula :: String -> Either String [Exp] parseFormula inp = either (Left . show) (Right . id) $ parse formula "formula" inp formula :: GenParser Char st [Exp] formula = do whiteSpace f <- many expr eof return f expr :: GenParser Char st Exp expr = do a <- expr1 limits <- limitsIndicator subSup limits a <|> superOrSubscripted limits a <|> return a limitsIndicator :: GenParser Char st (Maybe Bool) limitsIndicator = try (symbol "\\limits" >> return (Just True)) <|> try (symbol "\\nolimits" >> return (Just False)) <|> return Nothing inbraces :: GenParser Char st Exp inbraces = liftM EGrouped (braces $ many $ notFollowedBy (char '}') >> expr) texToken :: GenParser Char st Exp texToken = inbraces <|> inbrackets <|> do c <- anyChar spaces return $ if isDigit c then (ENumber [c]) else (EIdentifier [c]) inbrackets :: GenParser Char st Exp inbrackets = liftM EGrouped (brackets $ many $ notFollowedBy (char ']') >> expr) number :: GenParser Char st Exp number = lexeme $ liftM ENumber $ many1 digit enclosure :: GenParser Char st Exp enclosure = basicEnclosure <|> left <|> right <|> scaledEnclosure basicEnclosure :: GenParser Char st Exp basicEnclosure = choice $ map (\(s, v) -> try (symbol s) >> return v) enclosures left :: GenParser Char st Exp left = try $ do symbol "\\left" enc <- basicEnclosure <|> (try (symbol ".") >> return (ESymbol Open "\xFEFF")) case enc of (ESymbol Open _) -> tilRight enc <|> return (EStretchy enc) _ -> pzero right :: GenParser Char st Exp right = try $ do symbol "\\right" enc <- basicEnclosure <|> (try (symbol ".") >> return (ESymbol Close "\xFEFF")) case enc of (ESymbol Close x) -> return (EStretchy $ ESymbol Open x) _ -> 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 -> GenParser Char st Exp tilRight start = try $ do contents <- manyTill expr (try $ symbol "\\right" >> lookAhead basicEnclosure) end <- basicEnclosure return $ EGrouped $ EStretchy start : (contents ++ [EStretchy end]) scaledEnclosure :: GenParser Char st Exp scaledEnclosure = try $ do cmd <- command case M.lookup cmd scalers of Just r -> liftM (EScaled r . EStretchy) basicEnclosure Nothing -> pzero endLine :: GenParser Char st Char endLine = try $ do symbol "\\\\" optional inbrackets -- can contain e.g. [1.0in] for a line height, not yet supported return '\n' arrayLine :: GenParser Char st ArrayLine arrayLine = notFollowedBy (try $ char '\\' >> symbol "end" >> return '\n') >> sepBy1 (many (notFollowedBy endLine >> expr)) (symbol "&") array :: GenParser Char st Exp array = stdarray <|> eqnarray <|> align <|> cases <|> matrix matrix :: GenParser Char st Exp matrix = matrixWith "pmatrix" "(" ")" <|> matrixWith "bmatrix" "[" "]" <|> matrixWith "Bmatrix" "{" "}" <|> matrixWith "vmatrix" "\x2223" "\x2223" <|> matrixWith "Vmatrix" "\x2225" "\x2225" matrixWith :: String -> String -> String -> GenParser Char st Exp matrixWith keywd opendelim closedelim = inEnvironment keywd $ do aligns <- option [] arrayAlignments lines' <- sepEndBy1 arrayLine endLine return $ EGrouped [ EStretchy (ESymbol Open opendelim) , EArray aligns lines' , EStretchy (ESymbol Close closedelim)] stdarray :: GenParser Char st Exp stdarray = inEnvironment "array" $ do aligns <- option [] arrayAlignments liftM (EArray aligns) $ sepEndBy1 arrayLine endLine eqnarray :: GenParser Char st Exp eqnarray = inEnvironment "eqnarray" $ liftM (EArray [AlignRight, AlignCenter, AlignLeft]) $ sepEndBy1 arrayLine endLine align :: GenParser Char st Exp align = inEnvironment "align" $ liftM (EArray [AlignRight, AlignLeft]) $ sepEndBy1 arrayLine endLine cases :: GenParser Char st Exp cases = inEnvironment "cases" $ do rs <- sepEndBy1 arrayLine endLine return $ EGrouped [EStretchy (ESymbol Open "{"), EArray [] rs] arrayAlignments :: GenParser Char st [Alignment] arrayAlignments = try $ do as <- braces (many letter) let letterToAlignment 'l' = AlignLeft letterToAlignment 'c' = AlignCenter letterToAlignment 'r' = AlignRight letterToAlignment _ = AlignDefault return $ map letterToAlignment as inEnvironment :: String -> GenParser Char st Exp -> GenParser Char st Exp inEnvironment envType p = do try $ do char '\\' symbol "begin" braces $ symbol envType >> optional (symbol "*") result <- p char '\\' symbol "end" braces $ symbol envType >> optional (symbol "*") return result variable :: GenParser Char st Exp variable = do v <- letter spaces return $ EIdentifier [v] isConvertible :: Exp -> Bool isConvertible (EMathOperator x) = x `elem` convertibleOps where convertibleOps = ["lim","liminf","limsup","inf","sup"] isConvertible (ESymbol Rel _) = True isConvertible (ESymbol Bin _) = True isConvertible (EUnder _ _) = True isConvertible (EOver _ _) = True isConvertible (EUnderover _ _ _) = True isConvertible (ESymbol Op x) = x `elem` convertibleSyms where convertibleSyms = ["\x2211","\x220F","\x22C2", "\x22C3","\x22C0","\x22C1","\x2A05","\x2A06", "\x2210","\x2A01","\x2A02","\x2A00","\x2A04"] isConvertible _ = False subSup :: Maybe Bool -> Exp -> GenParser Char st Exp subSup limits a = try $ do char '_' b <- expr1 char '^' c <- expr return $ case limits of Just True -> EUnderover a b c Nothing | isConvertible a -> EDownup a b c _ -> ESubsup a b c superOrSubscripted :: Maybe Bool -> Exp -> GenParser Char st Exp superOrSubscripted limits a = try $ do c <- oneOf "^_" b <- expr case c of '^' -> return $ case limits of Just True -> EOver a b Nothing | isConvertible a -> EUp a b _ -> ESuper a b '_' -> return $ case limits of Just True -> EUnder a b Nothing | isConvertible a -> EDown a b _ -> ESub a b _ -> pzero escaped :: GenParser Char st Exp escaped = lexeme $ try $ char '\\' >> liftM (ESymbol Ord . (:[])) (satisfy $ not . isAlphaNum) unicode :: GenParser Char st Exp unicode = lexeme $ liftM (ESymbol Ord . (:[])) $ satisfy (not . isAscii) ensuremath :: GenParser Char st Exp ensuremath = lexeme $ try $ string "\\ensuremath" >> inbraces command :: GenParser Char st String command = try $ char '\\' >> liftM ('\\':) (identifier <|> lexeme (count 1 anyChar)) unaryOps :: [String] unaryOps = ["\\sqrt", "\\surd"] textOps :: M.Map String (String -> Exp) textOps = M.fromList [ ("\\textrm", EText "normal" . parseText) , ("\\mathrm", EText "normal") , ("\\text", EText "normal" . parseText) , ("\\mbox", EText "normal") , ("\\mathbf", EText "bold") , ("\\textbf", EText "bold" . parseText) , ("\\mathit", EText "italic") , ("\\textit", EText "italic" . parseText) , ("\\mathtt", EText "monospace") , ("\\texttt", EText "monospace") , ("\\mathsf", EText "sans-serif") , ("\\mathbb", \e -> maybe (EText "double-struck" e) (ESymbol Pun) (M.lookup e mathbb)) , ("\\mathcal", \e -> maybe (EText "script" e) (ESymbol Pun) (M.lookup e mathcal)) , ("\\mathfrak", EText "fraktur") ] parseText :: String -> String parseText ('`':'`':xs) = '\x201C' : parseText xs parseText ('\'':'\'':xs) = '\x201D' : parseText xs parseText ('\'':xs) = '\x2019' : parseText xs parseText ('-':'-':'-':xs) = '\x2014' : parseText xs parseText ('-':'-':xs) = '\x2013' : parseText xs parseText ('\\':'l':'d':'o':'t':'s':xs) = '\x2026' : parseText xs parseText ('~':xs) = '\xA0' : parseText xs parseText (x:xs) = x : parseText xs parseText [] = [] diacritical :: GenParser Char st Exp diacritical = try $ do c <- command case M.lookup c diacriticals of Just r -> liftM r texToken Nothing -> pzero diacriticals :: M.Map String (Exp -> Exp) diacriticals = M.fromList [ ("\\acute", \e -> EOver e (ESymbol Accent "\x00B4")) , ("\\grave", \e -> EOver e (ESymbol Accent "\x0060")) , ("\\breve", \e -> EOver e (ESymbol Accent "\x02D8")) , ("\\check", \e -> EOver e (ESymbol Accent "\x02C7")) , ("\\dot", \e -> EOver e (ESymbol Accent ".")) , ("\\ddot", \e -> EOver e (ESymbol Accent "..")) , ("\\mathring", \e -> EOver e (ESymbol Accent "\x00B0")) , ("\\vec", \e -> EOver e (ESymbol Accent "\x20D7")) , ("\\overrightarrow", \e -> EOver e (ESymbol Accent "\x20D7")) , ("\\overleftarrow", \e -> EOver e (ESymbol Accent "\x20D6")) , ("\\hat", \e -> EOver e (ESymbol Accent "\x005E")) , ("\\widehat", \e -> EOver e (ESymbol Accent "\x0302")) , ("\\tilde", \e -> EOver e (ESymbol Accent "~")) , ("\\widetilde", \e -> EOver e (ESymbol Accent "\x02DC")) , ("\\bar", \e -> EOver e (ESymbol Accent "\x203E")) , ("\\overbrace", \e -> EOver e (ESymbol Accent "\xFE37")) , ("\\overbracket", \e -> EOver e (ESymbol Accent "\x23B4")) , ("\\overline", \e -> EOver e (ESymbol Accent "\x00AF")) , ("\\underbrace", \e -> EUnder e (ESymbol Accent "\xFE38")) , ("\\underbracket", \e -> EUnder e (ESymbol Accent "\x23B5")) , ("\\underline", \e -> EUnder e (ESymbol Accent "\x00AF")) ] unary :: GenParser Char st Exp unary = try $ do c <- command unless (c `elem` unaryOps) pzero a <- texToken return $ EUnary c a text :: GenParser Char st Exp text = try $ do c <- command case M.lookup c textOps of Just f -> liftM f $ braces (many (noneOf "}" <|> (char '\\' >> char '}'))) Nothing -> pzero -- note: sqrt can be unary, \sqrt{2}, or binary, \sqrt[3]{2} root :: GenParser Char st Exp root = try $ do try (symbol "\\sqrt") <|> symbol "\\surd" a <- inbrackets b <- texToken return $ EBinary "\\sqrt" b a binary :: GenParser Char st Exp binary = try $ do c <- command unless (c `elem` binaryOps) pzero a <- texToken b <- texToken return $ EBinary c a b texSymbol :: GenParser Char st Exp texSymbol = try $ do sym <- operator <|> command case M.lookup sym symbols of Just s -> return s Nothing -> pzero -- The lexer lexer :: P.TokenParser st lexer = P.makeTokenParser texMathDef lexeme :: CharParser st a -> CharParser st a lexeme = P.lexeme lexer whiteSpace :: CharParser st () whiteSpace = P.whiteSpace lexer identifier :: CharParser st String identifier = lexeme (P.identifier lexer) operator :: CharParser st String operator = lexeme $ liftM (:[]) (opLetter texMathDef) <|> many1 (char '\'') symbol :: String -> CharParser st String symbol = lexeme . P.symbol lexer braces :: CharParser st a -> CharParser st a braces = lexeme . P.braces lexer brackets :: CharParser st a -> CharParser st a brackets = lexeme . P.brackets lexer binaryOps :: [String] binaryOps = ["\\frac", "\\tfrac", "\\dfrac", "\\stackrel", "\\overset", "\\underset", "\\binom"] scalers :: M.Map String String scalers = 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 = [ ("(", ESymbol Open "(") , (")", ESymbol Close ")") , ("[", ESymbol Open "[") , ("]", ESymbol Close "]") , ("\\{", ESymbol Open "{") , ("\\}", ESymbol Close "}") , ("\\lbrack", ESymbol Open "[") , ("\\lbrace", ESymbol Open "{") , ("\\rbrack", ESymbol Close "]") , ("\\rbrace", ESymbol Close "}") , ("\\llbracket", ESymbol Open "\x27E6") , ("\\rrbracket", ESymbol Close "\x27E7") , ("\\langle", ESymbol Open "\x27E8") , ("\\rangle", ESymbol Close "\x27E9") , ("\\lfloor", ESymbol Open "\x230A") , ("\\rfloor", ESymbol Close "\x230B") , ("\\lceil", ESymbol Open "\x2308") , ("\\rceil", ESymbol Close "\x2309") , ("|", ESymbol Open "\x2223") , ("|", ESymbol Close "\x2223") , ("\\|", ESymbol Open "\x2225") , ("\\|", ESymbol Close "\x2225") , ("\\lvert", ESymbol Open "\x7C") , ("\\rvert", ESymbol Close "\x7C") , ("\\vert", ESymbol Close "\x7C") , ("\\lVert", ESymbol Open "\x2225") , ("\\rVert", ESymbol Close "\x2225") , ("\\Vert", ESymbol Close "\x2016") , ("\\ulcorner", ESymbol Open "\x231C") , ("\\urcorner", ESymbol Close "\x231D") ] symbols :: M.Map String Exp symbols = M.fromList [ ("+", ESymbol Bin "+") , ("-", ESymbol Bin "-") , ("*", ESymbol Bin "*") , (",", ESymbol Pun ",") , (".", ESymbol Pun ".") , (";", ESymbol Pun ";") , (":", ESymbol Pun ":") , ("?", ESymbol Pun "?") , (">", ESymbol Rel ">") , ("<", ESymbol Rel "<") , ("!", ESymbol Ord "!") , ("'", ESymbol Ord "\x02B9") , ("''", ESymbol Ord "\x02BA") , ("'''", ESymbol Ord "\x2034") , ("''''", ESymbol Ord "\x2057") , ("=", ESymbol Rel "=") , (":=", ESymbol Rel ":=") , ("\\mid", ESymbol Bin "\x2223") , ("\\parallel", ESymbol Rel "\x2225") , ("\\backslash", ESymbol Bin "\x2216") , ("/", ESymbol Bin "/") , ("\\setminus", ESymbol Bin "\\") , ("\\times", ESymbol Bin "\x00D7") , ("\\alpha", ESymbol Ord "\x03B1") , ("\\beta", ESymbol Ord "\x03B2") , ("\\chi", ESymbol Ord "\x03C7") , ("\\delta", ESymbol Ord "\x03B4") , ("\\Delta", ESymbol Op "\x0394") , ("\\epsilon", ESymbol Ord "\x03B5") , ("\\varepsilon", ESymbol Ord "\x025B") , ("\\eta", ESymbol Ord "\x03B7") , ("\\gamma", ESymbol Ord "\x03B3") , ("\\Gamma", ESymbol Op "\x0393") , ("\\iota", ESymbol Ord "\x03B9") , ("\\kappa", ESymbol Ord "\x03BA") , ("\\lambda", ESymbol Ord "\x03BB") , ("\\Lambda", ESymbol Op "\x039B") , ("\\mu", ESymbol Ord "\x03BC") , ("\\nu", ESymbol Ord "\x03BD") , ("\\omega", ESymbol Ord "\x03C9") , ("\\Omega", ESymbol Op "\x03A9") , ("\\phi", ESymbol Ord "\x03C6") , ("\\varphi", ESymbol Ord "\x03D5") , ("\\Phi", ESymbol Op "\x03A6") , ("\\pi", ESymbol Ord "\x03C0") , ("\\Pi", ESymbol Op "\x03A0") , ("\\psi", ESymbol Ord "\x03C8") , ("\\Psi", ESymbol Ord "\x03A8") , ("\\rho", ESymbol Ord "\x03C1") , ("\\sigma", ESymbol Ord "\x03C3") , ("\\Sigma", ESymbol Op "\x03A3") , ("\\tau", ESymbol Ord "\x03C4") , ("\\theta", ESymbol Ord "\x03B8") , ("\\vartheta", ESymbol Ord "\x03D1") , ("\\Theta", ESymbol Op "\x0398") , ("\\upsilon", ESymbol Ord "\x03C5") , ("\\xi", ESymbol Ord "\x03BE") , ("\\Xi", ESymbol Op "\x039E") , ("\\zeta", ESymbol Ord "\x03B6") , ("\\frac12", ESymbol Ord "\x00BD") , ("\\frac14", ESymbol Ord "\x00BC") , ("\\frac34", ESymbol Ord "\x00BE") , ("\\frac13", ESymbol Ord "\x2153") , ("\\frac23", ESymbol Ord "\x2154") , ("\\frac15", ESymbol Ord "\x2155") , ("\\frac25", ESymbol Ord "\x2156") , ("\\frac35", ESymbol Ord "\x2157") , ("\\frac45", ESymbol Ord "\x2158") , ("\\frac16", ESymbol Ord "\x2159") , ("\\frac56", ESymbol Ord "\x215A") , ("\\frac18", ESymbol Ord "\x215B") , ("\\frac38", ESymbol Ord "\x215C") , ("\\frac58", ESymbol Ord "\x215D") , ("\\frac78", ESymbol Ord "\x215E") , ("\\pm", ESymbol Bin "\x00B1") , ("\\mp", ESymbol Bin "\x2213") , ("\\triangleleft", ESymbol Bin "\x22B2") , ("\\triangleright", ESymbol Bin "\x22B3") , ("\\cdot", ESymbol Bin "\x22C5") , ("\\star", ESymbol Bin "\x22C6") , ("\\ast", ESymbol Bin "\x002A") , ("\\times", ESymbol Bin "\x00D7") , ("\\div", ESymbol Bin "\x00F7") , ("\\circ", ESymbol Bin "\x2218") , ("\\bullet", ESymbol Bin "\x2022") , ("\\oplus", ESymbol Bin "\x2295") , ("\\ominus", ESymbol Bin "\x2296") , ("\\otimes", ESymbol Bin "\x2297") , ("\\bigcirc", ESymbol Bin "\x25CB") , ("\\oslash", ESymbol Bin "\x2298") , ("\\odot", ESymbol Bin "\x2299") , ("\\land", ESymbol Bin "\x2227") , ("\\wedge", ESymbol Bin "\x2227") , ("\\lor", ESymbol Bin "\x2228") , ("\\vee", ESymbol Bin "\x2228") , ("\\cap", ESymbol Bin "\x2229") , ("\\cup", ESymbol Bin "\x222A") , ("\\sqcap", ESymbol Bin "\x2293") , ("\\sqcup", ESymbol Bin "\x2294") , ("\\uplus", ESymbol Bin "\x228E") , ("\\amalg", ESymbol Bin "\x2210") , ("\\bigtriangleup", ESymbol Bin "\x25B3") , ("\\bigtriangledown", ESymbol Bin "\x25BD") , ("\\dag", ESymbol Bin "\x2020") , ("\\dagger", ESymbol Bin "\x2020") , ("\\ddag", ESymbol Bin "\x2021") , ("\\ddagger", ESymbol Bin "\x2021") , ("\\lhd", ESymbol Bin "\x22B2") , ("\\rhd", ESymbol Bin "\x22B3") , ("\\unlhd", ESymbol Bin "\x22B4") , ("\\unrhd", ESymbol Bin "\x22B5") , ("\\lt", ESymbol Rel "<") , ("\\gt", ESymbol Rel ">") , ("\\ne", ESymbol Rel "\x2260") , ("\\neq", ESymbol Rel "\x2260") , ("\\le", ESymbol Rel "\x2264") , ("\\leq", ESymbol Rel "\x2264") , ("\\leqslant", ESymbol Rel "\x2264") , ("\\ge", ESymbol Rel "\x2265") , ("\\geq", ESymbol Rel "\x2265") , ("\\geqslant", ESymbol Rel "\x2265") , ("\\equiv", ESymbol Rel "\x2261") , ("\\ll", ESymbol Rel "\x226A") , ("\\gg", ESymbol Rel "\x226B") , ("\\doteq", ESymbol Rel "\x2250") , ("\\prec", ESymbol Rel "\x227A") , ("\\succ", ESymbol Rel "\x227B") , ("\\preceq", ESymbol Rel "\x227C") , ("\\succeq", ESymbol Rel "\x227D") , ("\\subset", ESymbol Rel "\x2282") , ("\\supset", ESymbol Rel "\x2283") , ("\\subseteq", ESymbol Rel "\x2286") , ("\\supseteq", ESymbol Rel "\x2287") , ("\\sqsubset", ESymbol Rel "\x228F") , ("\\sqsupset", ESymbol Rel "\x2290") , ("\\sqsubseteq", ESymbol Rel "\x2291") , ("\\sqsupseteq", ESymbol Rel "\x2292") , ("\\sim", ESymbol Rel "\x223C") , ("\\simeq", ESymbol Rel "\x2243") , ("\\approx", ESymbol Rel "\x2248") , ("\\cong", ESymbol Rel "\x2245") , ("\\Join", ESymbol Rel "\x22C8") , ("\\bowtie", ESymbol Rel "\x22C8") , ("\\in", ESymbol Rel "\x2208") , ("\\ni", ESymbol Rel "\x220B") , ("\\owns", ESymbol Rel "\x220B") , ("\\propto", ESymbol Rel "\x221D") , ("\\vdash", ESymbol Rel "\x22A2") , ("\\dashv", ESymbol Rel "\x22A3") , ("\\models", ESymbol Rel "\x22A8") , ("\\perp", ESymbol Rel "\x22A5") , ("\\smile", ESymbol Rel "\x2323") , ("\\frown", ESymbol Rel "\x2322") , ("\\asymp", ESymbol Rel "\x224D") , ("\\notin", ESymbol Rel "\x2209") , ("\\gets", ESymbol Rel "\x2190") , ("\\leftarrow", ESymbol Rel "\x2190") , ("\\to", ESymbol Rel "\x2192") , ("\\rightarrow", ESymbol Rel "\x2192") , ("\\leftrightarrow", ESymbol Rel "\x2194") , ("\\uparrow", ESymbol Rel "\x2191") , ("\\downarrow", ESymbol Rel "\x2193") , ("\\updownarrow", ESymbol Rel "\x2195") , ("\\Leftarrow", ESymbol Rel "\x21D0") , ("\\Rightarrow", ESymbol Rel "\x21D2") , ("\\Leftrightarrow", ESymbol Rel "\x21D4") , ("\\iff", ESymbol Rel "\x21D4") , ("\\Uparrow", ESymbol Rel "\x21D1") , ("\\Downarrow", ESymbol Rel "\x21D3") , ("\\Updownarrow", ESymbol Rel "\x21D5") , ("\\mapsto", ESymbol Rel "\x21A6") , ("\\longleftarrow", ESymbol Rel "\x2190") , ("\\longrightarrow", ESymbol Rel "\x2192") , ("\\longleftrightarrow", ESymbol Rel "\x2194") , ("\\Longleftarrow", ESymbol Rel "\x21D0") , ("\\Longrightarrow", ESymbol Rel "\x21D2") , ("\\Longleftrightarrow", ESymbol Rel "\x21D4") , ("\\longmapsto", ESymbol Rel "\x21A6") , ("\\sum", ESymbol Op "\x2211") , ("\\prod", ESymbol Op "\x220F") , ("\\bigcap", ESymbol Op "\x22C2") , ("\\bigcup", ESymbol Op "\x22C3") , ("\\bigwedge", ESymbol Op "\x22C0") , ("\\bigvee", ESymbol Op "\x22C1") , ("\\bigsqcap", ESymbol Op "\x2A05") , ("\\bigsqcup", ESymbol Op "\x2A06") , ("\\coprod", ESymbol Op "\x2210") , ("\\bigoplus", ESymbol Op "\x2A01") , ("\\bigotimes", ESymbol Op "\x2A02") , ("\\bigodot", ESymbol Op "\x2A00") , ("\\biguplus", ESymbol Op "\x2A04") , ("\\int", ESymbol Op "\x222B") , ("\\iint", ESymbol Op "\x222C") , ("\\iiint", ESymbol Op "\x222D") , ("\\oint", ESymbol Op "\x222E") , ("\\prime", ESymbol Ord "\x2032") , ("\\dots", ESymbol Ord "\x2026") , ("\\ldots", ESymbol Ord "\x2026") , ("\\cdots", ESymbol Ord "\x22EF") , ("\\vdots", ESymbol Ord "\x22EE") , ("\\ddots", ESymbol Ord "\x22F1") , ("\\forall", ESymbol Op "\x2200") , ("\\exists", ESymbol Op "\x2203") , ("\\Re", ESymbol Ord "\x211C") , ("\\Im", ESymbol Ord "\x2111") , ("\\aleph", ESymbol Ord "\x2135") , ("\\hbar", ESymbol Ord "\x210F") , ("\\ell", ESymbol Ord "\x2113") , ("\\wp", ESymbol Ord "\x2118") , ("\\emptyset", ESymbol Ord "\x2205") , ("\\infty", ESymbol Ord "\x221E") , ("\\partial", ESymbol Ord "\x2202") , ("\\nabla", ESymbol Ord "\x2207") , ("\\triangle", ESymbol Ord "\x25B3") , ("\\therefore", ESymbol Pun "\x2234") , ("\\angle", ESymbol Ord "\x2220") , ("\\diamond", ESymbol Op "\x22C4") , ("\\Diamond", ESymbol Op "\x25C7") , ("\\lozenge", ESymbol Op "\x25CA") , ("\\neg", ESymbol Op "\x00AC") , ("\\lnot", ESymbol Ord "\x00AC") , ("\\bot", ESymbol Ord "\x22A5") , ("\\top", ESymbol Ord "\x22A4") , ("\\square", ESymbol Ord "\x25AB") , ("\\Box", ESymbol Op "\x25A1") , ("\\wr", ESymbol Ord "\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") ] -- MathML has a mathvariant attribute which is unimplemented in Firefox -- (see https://bugzilla.mozilla.org/show_bug.cgi?id=114365) -- Therefore, we translate mathcal to unicode symbols directly. -- This list is from http://www.w3.org/TR/MathML2/script.html mathcal :: M.Map String String mathcal = M.fromList [ ("A", "\x1D49C") , ("B", "\x0212C") , ("C", "\x1D49E") , ("D", "\x1D49F") , ("E", "\x02130") , ("F", "\x02131") , ("G", "\x1D4A2") , ("H", "\x0210B") , ("I", "\x02110") , ("J", "\x1D4A5") , ("K", "\x1D4A6") , ("L", "\x02112") , ("M", "\x02133") , ("N", "\x1D4A9") , ("O", "\x1D4AA") , ("P", "\x1D4AB") , ("Q", "\x1D4AC") , ("R", "\x0211B") , ("S", "\x1D4AE") , ("T", "\x1D4AF") , ("U", "\x1D4B0") , ("V", "\x1D4B1") , ("W", "\x1D4B2") , ("X", "\x1D4B3") , ("Y", "\x1D4B4") , ("Z", "\x1D4B5") , ("a", "\x1D4B6") , ("b", "\x1D4B7") , ("c", "\x1D4B8") , ("d", "\x1D4B9") , ("e", "\x0212F") , ("f", "\x1D4BB") , ("g", "\x0210A") , ("h", "\x1D4BD") , ("i", "\x1D4BE") , ("j", "\x1D4BF") , ("k", "\x1D4C0") , ("l", "\x1D4C1") , ("m", "\x1D4C2") , ("n", "\x1D4C3") , ("o", "\x02134") , ("p", "\x1D4C5") , ("q", "\x1D4C6") , ("r", "\x1D4C7") , ("s", "\x1D4C8") , ("t", "\x1D4C9") , ("u", "\x1D4CA") , ("v", "\x1D4CB") , ("w", "\x1D4CC") , ("x", "\x1D4CD") , ("y", "\x1D4CE") , ("z", "\x1D4CF") ] -- Similar to mathcal above, we translate manually. -- This list is from http://www.w3.org/TR/MathML2/double-struck.html mathbb :: M.Map String String mathbb = M.fromList [ ("A", "\x1D538") , ("B", "\x1D539") , ("C", "\x02102") , ("D", "\x1D53B") , ("E", "\x1D53C") , ("F", "\x1D53D") , ("G", "\x1D53E") , ("H", "\x0210D") , ("I", "\x1D540") , ("J", "\x1D541") , ("K", "\x1D542") , ("L", "\x1D543") , ("M", "\x1D544") , ("N", "\x02115") , ("O", "\x1D546") , ("P", "\x02119") , ("Q", "\x0211A") , ("R", "\x0211D") , ("S", "\x1D54A") , ("T", "\x1D54B") , ("U", "\x1D54C") , ("V", "\x1D54D") , ("W", "\x1D54E") , ("X", "\x1D54F") , ("Y", "\x1D550") , ("Z", "\x02124") , ("a", "\x1D552") , ("b", "\x1D553") , ("c", "\x1D554") , ("d", "\x1D555") , ("e", "\x1D556") , ("f", "\x1D557") , ("g", "\x1D558") , ("h", "\x1D559") , ("i", "\x1D55A") , ("j", "\x1D55B") , ("k", "\x1D55C") , ("l", "\x1D55D") , ("m", "\x1D55E") , ("n", "\x1D55F") , ("o", "\x1D560") , ("p", "\x1D561") , ("q", "\x1D562") , ("r", "\x1D563") , ("s", "\x1D564") , ("t", "\x1D565") , ("u", "\x1D566") , ("v", "\x1D567") , ("w", "\x1D568") , ("x", "\x1D569") , ("y", "\x1D56A") , ("z", "\x1D56B") , ("0", "\x1D7D8") , ("1", "\x1D7D9") , ("2", "\x1D7DA") , ("3", "\x1D7DB") , ("4", "\x1D7DC") , ("5", "\x1D7DD") , ("6", "\x1D7DE") , ("7", "\x1D7DF") , ("8", "\x1D7E0") , ("9", "\x1D7E1") ]