packages feed

texmath-0.12.7.1: src/Text/TeXMath/Writers/Typst.hs

{-# LANGUAGE GeneralizedNewtypeDeriving, ViewPatterns, GADTs, OverloadedStrings #-}
{-
Copyright (C) 2023 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

-}

module Text.TeXMath.Writers.Typst (writeTypst) where

import Data.List (transpose)
import qualified Data.Map as M
import qualified Data.Text as T
import Text.TeXMath.Types
import qualified Text.TeXMath.Shared as S
import Data.Generics (everywhere, mkT)
import Data.Text (Text)
import Data.Char (isDigit, isAlpha)

-- import Debug.Trace
-- tr' x = trace (show x) x

-- | Transforms an expression tree to equivalent Typst
writeTypst :: DisplayType -> [Exp] -> Text
writeTypst dt exprs =
  T.unwords $ map writeExp $ everywhere (mkT $ S.handleDownup dt) exprs

writeExps :: [Exp] -> Text
writeExps = T.intercalate " " . map writeExp

inParens :: Text -> Text
inParens s = "(" <> s <> ")"

inQuotes :: Text -> Text
inQuotes s = "\"" <> s <> "\""

esc :: Text -> Text
esc t =
  if T.any needsEscape t
     then T.concatMap escapeChar t
     else t
  where
    escapeChar c
      | needsEscape c = "\\" <> T.singleton c
      | otherwise = T.singleton c
    needsEscape '[' = True
    needsEscape ']' = True
    needsEscape '|' = True
    needsEscape '#' = True
    needsEscape '$' = True
    needsEscape '(' = True
    needsEscape ')' = True
    needsEscape '_' = True
    needsEscape _ = False

writeExpS :: Exp -> Text
writeExpS (EGrouped es) = "(" <> writeExps es <> ")"
writeExpS e =
  case writeExp e of
    t | T.all (\c -> isDigit c || c == '.') t -> t
      | T.all (\c -> isAlpha c || c == '.') t -> t
      | otherwise -> "(" <> t <> ")"

writeExpB :: Exp -> Text
writeExpB e =
  case writeExp e of
    "" -> "zws"
    t -> t

writeExp :: Exp -> Text
writeExp (ENumber s) = s
writeExp (ESymbol _t s) =
  maybe (esc s) id $ M.lookup s typstSymbols
writeExp (EIdentifier s) =
  if T.length s == 1
     then writeExp (ESymbol Ord s)
     else inQuotes s
writeExp (EMathOperator s)
  | s `elem` ["arccos", "arcsin", "arctan", "arg", "cos", "cosh",
              "cot", "ctg", "coth", "csc", "deg", "det", "dim", "exp",
              "gcd", "hom", "mod", "inf", "ker", "lg", "lim", "ln",
              "log", "max", "min", "Pr", "sec", "sin", "sinh", "sup",
              "tan", "tg", "tanh", "liminf", "and", "limsup"]
    = s
  | otherwise = "\"" <> s <> "\""
writeExp (EGrouped es) = writeExps es
writeExp (EFraction _fractype e1 e2) =
  case (e1, e2) of
    (EGrouped _, _) -> "frac(" <> writeExp e1 <> ", " <> writeExp e2 <> ")"
    (_, EGrouped _) -> "frac(" <> writeExp e1 <> ", " <> writeExp e2 <> ")"
    _ -> writeExp e1 <> " / " <> writeExp e2
writeExp (ESub b e1) = writeExpB b <> "_" <> writeExpS e1
writeExp (ESuper b e1) = writeExpB b <> "^" <> writeExpS e1
writeExp (ESubsup b e1 e2) = writeExpB b <> "_" <> writeExpS e1 <>
                                           "^" <> writeExpS e2
writeExp (EOver _ (EOver _ b (ESymbol TOver "\9182")) e1) =
  "overbrace(" <> writeExp b <> ", " <> writeExp e1 <> ")"
writeExp (EOver _ (EOver _ b (ESymbol TOver "\9140")) e1) =
  "overbracket(" <> writeExp b <> ", " <> writeExp e1 <> ")"
writeExp (EOver _ (EOver _ b (ESymbol TOver "_")) e1) =
  "overline(" <> writeExp b <> ", " <> writeExp e1 <> ")"
writeExp (EOver _convertible b e1) =
  case e1 of
    ESymbol Accent "`" -> "grave" <> inParens (writeExp b)
    ESymbol Accent "\xb4" -> "acute" <> inParens (writeExp b)
    ESymbol Accent "^" -> "hat" <> inParens (writeExp b)
    ESymbol Accent "~" -> "tilde" <> inParens (writeExp b)
    ESymbol Accent "\xaf" -> "macron" <> inParens (writeExp b)
    ESymbol Accent "\x2d8" -> "breve" <> inParens (writeExp b)
    ESymbol Accent "." -> "dot" <> inParens (writeExp b)
    ESymbol Accent "\xa8" -> "diaer" <> inParens (writeExp b)
    ESymbol Accent "\x2218" -> "circle" <> inParens (writeExp b)
    ESymbol Accent "\x2dd" -> "acute.double" <> inParens (writeExp b)
    ESymbol Accent "\x2c7" -> "caron" <> inParens (writeExp b)
    ESymbol Accent "\x2192" -> "->" <> inParens (writeExp b)
    ESymbol Accent "\x2190" -> "<-" <> inParens (writeExp b)
    ESymbol TOver "\9182" -> "overbrace(" <> writeExp b <> ")"
    ESymbol TOver "\9140" -> "overbracket(" <> writeExp b <> ")"
    ESymbol TOver "_" -> "overline(" <> writeExp b <> ")"
    _ -> writeExpB b <> "^" <> writeExpS e1
writeExp (EUnder _ (EUnder _ b (ESymbol TUnder "_")) e1) =
  "underline(" <> writeExp b <> ", " <> writeExp e1 <> ")"
writeExp (EUnder _ (EUnder _ b (ESymbol TUnder "\9182")) e1) =
  "underbrace(" <> writeExp b <> ", " <> writeExp e1 <> ")"
writeExp (EUnder _ (EUnder _ b (ESymbol TUnder "\9140")) e1) =
  "underbrace(" <> writeExp b <> ", " <> writeExp e1 <> ")"
writeExp (EUnder _convertible b e1) =
  case e1 of
    ESymbol TUnder "_" -> "underline(" <> writeExp b <> ")"
    ESymbol TUnder "\9182" -> "underbrace(" <> writeExp b <> ")"
    ESymbol TUnder "\9140" -> "underbracket(" <> writeExp b <> ")"
    _ -> writeExpB b <> "_" <> writeExpS e1
writeExp (EUnderover convertible b e1 e2) =
  case (e1, e2) of
    (_, ESymbol Accent _) -> writeExp (EUnder convertible (EOver False b e2) e1)
    (_, ESymbol TOver _) -> writeExp (EUnder convertible (EOver False b e2) e1)
    (ESymbol TUnder _, _) -> writeExp (EOver convertible (EUnder False b e1) e2)
    _ -> writeExpB b <> "_" <> writeExpS e1 <> "^" <> writeExpS e2
writeExp (ESqrt e) = "sqrt(" <> writeExp e <> ")"
writeExp (ERoot i e) = "root(" <> writeExp i <> ", " <> writeExp e <> ")"
writeExp (ESpace width) =
  case (floor (width * 18) :: Int) of
    0 -> "zws"
    3 -> "thin"
    4 -> "med"
    6 -> "thick"
    18 -> "quad"
    n -> "#h(" <> tshow (n `div` 18) <> "em)"
writeExp (EText ttype s) =
  case ttype of
       TextNormal -> "upright" <> inParens (inQuotes s)
       TextItalic -> "italic" <> inParens (inQuotes s)
       TextBold   -> "bold" <> inParens (inQuotes s)
       TextBoldItalic -> "bold" <> inParens ("italic" <> inParens (inQuotes s))
       TextMonospace -> "mono" <> inParens (inQuotes s)
       TextSansSerif -> "sans" <> inParens (inQuotes s)
       TextDoubleStruck -> "bb" <> inParens (inQuotes s)
       TextScript -> "cal" <> inParens (inQuotes s)
       TextFraktur -> "frak" <> inParens (inQuotes s)
       TextSansSerifBold -> "bold" <> inParens ("sans" <> inParens (inQuotes s))
       TextSansSerifBoldItalic -> "bold" <>
         inParens ("italic" <> inParens ("sans" <> inParens (inQuotes s)))
       TextBoldScript -> "bold" <> inParens ("cal" <> inParens (inQuotes s))
       TextBoldFraktur -> "bold" <> inParens ("frak" <> inParens (inQuotes s))
       TextSansSerifItalic -> "italic" <>
          inParens ("sans" <> inParens (inQuotes s))
writeExp (EStyled ttype es) =
  let contents = writeExps es
  in case ttype of
       TextNormal -> "upright" <> inParens contents
       TextItalic -> "italic" <> inParens contents
       TextBold   -> "bold" <> inParens contents
       TextBoldItalic -> "bold" <> inParens ("italic" <> inParens contents)
       TextMonospace -> "mono" <> inParens contents
       TextSansSerif -> "sans" <> inParens contents
       TextDoubleStruck -> "bb" <> inParens contents
       TextScript -> "cal" <> inParens contents
       TextFraktur -> "frak" <> inParens contents
       TextSansSerifBold -> "bold" <> inParens ("sans" <> inParens contents)
       TextSansSerifBoldItalic -> "bold" <>
         inParens ("italic" <> inParens ("sans" <> inParens contents))
       TextBoldScript -> "bold" <> inParens ("cal" <> inParens contents)
       TextBoldFraktur -> "bold" <> inParens ("frak" <> inParens contents)
       TextSansSerifItalic -> "italic" <> inParens ("sans" <> inParens contents)
writeExp (EBoxed e) = "#box([" <> writeExp e <> "])"
writeExp (EPhantom e) = "#hide[" <> writeExp e <> "]"
writeExp (EScaled size e) =
  "#scale(x: " <> tshow (floor (100 * size) :: Int) <>
          "%, y: " <> tshow (floor (100 * size) :: Int) <>
          "%)[" <> writeExp e <> "]"
writeExp (EDelimited "(" ")" [Right (EArray _aligns rows)])
  | all (\row -> length row == 1) rows = -- vector
  "vec(" <> mkArray (transpose rows) <> ")"
writeExp (EDelimited "(" ")" [Right (EArray _aligns [[xs],[ys]])]) =
  "binom(" <> writeExps xs <> ", " <> writeExps ys <> ")"
writeExp (EDelimited "(" ")" [Right (EArray _aligns rows)]) =
  "mat(delim: \"(\", " <> mkArray rows <> ")"
writeExp (EDelimited "[" "]" [Right (EArray _aligns rows)]) =
  "mat(delim: \"[\", " <> mkArray rows <> ")"
writeExp (EDelimited "{" "}" [Right (EArray _aligns rows)]) =
  "mat(delim: \"{\", " <> mkArray rows <> ")"
writeExp (EDelimited "|" "|" [Right (EArray _aligns rows)]) =
  "mat(delim: \"|\", " <> mkArray rows <> ")"
writeExp (EDelimited "||" "||" [Right (EArray _aligns rows)]) =
  "mat(delim: \"||\", " <> mkArray rows <> ")"
writeExp (EDelimited "\x2223" "\x2223" [Right (EArray _aligns rows)]) =
  "mat(delim: \"||\", " <> mkArray rows <> ")"
writeExp (EDelimited "\x2225" "\x2225" [Right (EArray _aligns rows)]) =
  "mat(delim: \"||\", " <> mkArray rows <> ")"
writeExp (EDelimited op "" [Right (EArray [AlignLeft, AlignLeft] rows)]) =
  "cases" <> inParens("delim: " <> inQuotes op <> mconcat (map toCase rows))
   where toCase = (", " <>) . T.intercalate " & " . map writeExps
writeExp (EDelimited open close es) =
  if isDelim open && isDelim close
     then "lr" <> inParens (open <> body <> close)
     else esc open <> body <> esc close
  where fromDelimited (Left e)  = e
        fromDelimited (Right e) = writeExp e
        isDelim c = c `elem` ["(",")","[","]","{","}","|","||"]
        body = T.unwords (map fromDelimited es)
writeExp (EArray _aligns rows)
  = T.intercalate "\\\n" $ map mkRow rows
     where mkRow = T.intercalate " & " . map writeExps

mkArray :: [[[Exp]]] -> Text
mkArray rows =
  T.intercalate "; " $ map mkRow rows
 where
   mkRow = T.intercalate ", " . map mkCell
   mkCell = writeExps

tshow :: Show a => a -> Text
tshow = T.pack . show

typstSymbols :: M.Map Text Text
typstSymbols = M.fromList
  [ ("\x1d538","AA")
  , ("\x391","Alpha")
  , ("\x1d539","BB")
  , ("\x392","Beta")
  , ("\x2102","CC")
  , ("\x3A7","Chi")
  , ("\x1d53b","DD")
  , ("\x394","Delta")
  , ("\x1d53c","EE")
  , ("\x395","Epsilon")
  , ("\x397","Eta")
  , ("\x1d53d","FF")
  , ("\x1d53e","GG")
  , ("\x393","Gamma")
  , ("\x210d","HH")
  , ("\x1d540","II")
  , ("\x2111","Im")
  , ("\x399","Iota")
  , ("\x1d541","JJ")
  , ("\x1d542","KK")
  , ("\x3CF","Kai")
  , ("\x39A","Kappa")
  , ("\x1d543","LL")
  , ("\x39B","Lambda")
  , ("\x1d544","MM")
  , ("\x39C","Mu")
  , ("\x2115","NN")
  , ("\x39D","Nu")
  , ("\x1d546","OO")
  , ("\x3A9","Omega")
  , ("\x39F","Omicron")
  , ("\x2119","PP")
  , ("\x3A6","Phi")
  , ("\x3A0","Pi")
  , ("\x3A8","Psi")
  , ("\x211a","QQ")
  , ("\x211d","RR")
  , ("\x211c","Re")
  , ("\x3A1","Rho")
  , ("\x1d54a","SS")
  , ("\x3A3","Sigma")
  , ("\x1d54b","TT")
  , ("\x3A4","Tau")
  , ("\x398","Theta")
  , ("\x1d54c","UU")
  , ("\x3A5","Upsilon")
  , ("\x1d54d","VV")
  , ("\x1d54e","WW")
  , ("\x1d54f","XX")
  , ("\x39E","Xi")
  , ("\x1d550","YY")
  , ("\x2124","ZZ")
  , ("\x396","Zeta")
  , ("\xb4","acute")
  , ("\x2dd","acute.double")
  , ("\x5d0","alef")
  , ("\x3b1","alpha")
  , ("&","amp")
  , ("\x214b","amp.inv")
  , ("\x2227","and")
  , ("\x22c0","and.big")
  , ("\x22cf","and.curly")
  , ("\x27d1","and.dot")
  , ("\x2a53","and.double")
  , ("\x2220","angle")
  , ("\x2329","angle.l")
  , ("\x232a","angle.r")
  , ("\x300a","angle.l.double")
  , ("\x300b","angle.r.double")
  , ("\x299f","angle.acute")
  , ("\x2221","angle.arc")
  , ("\x299b","angle.arc.rev")
  , ("\x29a3","angle.rev")
  , ("\x221f","angle.right")
  , ("\11262","angle.right.rev")
  , ("\x22be","angle.right.arc")
  , ("\x299d","angle.right.dot")
  , ("\x299c","angle.right.sq")
  , ("\x27c0","angle.spatial")
  , ("\x2222","angle.spheric")
  , ("\x29a0","angle.spheric.rev")
  , ("\x29a1","angle.spheric.top")
  , ("\x212B","angstrom")
  , ("\x2248","approx")
  , ("\x224a","approx.eq")
  , ("\x2249","approx.not")
  , ("\x2192","arrow.r")
  , ("\x27fc","arrow.r.long.bar")
  , ("\x21a6","arrow.r.bar")
  , ("\x2937","arrow.r.curve")
  , ("\x21e2","arrow.r.dashed")
  , ("\x2911","arrow.r.dotted")
  , ("\x21d2","arrow.r.double")
  , ("\x2907","arrow.r.double.bar")
  , ("\x27f9","arrow.r.double.long")
  , ("\x27fe","arrow.r.double.long.bar")
  , ("\x21cf","arrow.r.double.not")
  , ("\x27a1","arrow.r.filled")
  , ("\x21aa","arrow.r.hook")
  , ("\x27f6","arrow.r.long")
  , ("\x27ff","arrow.r.long.squiggly")
  , ("\x21ac","arrow.r.loop")
  , ("\x219b","arrow.r.not")
  , ("\x2b46","arrow.r.quad")
  , ("\x21dd","arrow.r.squiggly")
  , ("\x21e5","arrow.r.stop")
  , ("\x21e8","arrow.r.stroked")
  , ("\x21a3","arrow.r.tail")
  , ("\x21db","arrow.r.triple")
  , ("\x2905","arrow.r.twohead.bar")
  , ("\x21a0","arrow.r.twohead")
  , ("\x219d","arrow.r.wave")
  , ("\x2190","arrow.l")
  , ("\x21a4","arrow.l.bar")
  , ("\x2936","arrow.l.curve")
  , ("\x21e0","arrow.l.dashed")
  , ("\x2b38","arrow.l.dotted")
  , ("\x21d0","arrow.l.double")
  , ("\x2906","arrow.l.double.bar")
  , ("\x27f8","arrow.l.double.long")
  , ("\x27fd","arrow.l.double.long.bar")
  , ("\x21cd","arrow.l.double.not")
  , ("\x2b05","arrow.l.filled")
  , ("\x21a9","arrow.l.hook")
  , ("\x27f5","arrow.l.long")
  , ("\x27fb","arrow.l.long.bar")
  , ("\x2b33","arrow.l.long.squiggly")
  , ("\x21ab","arrow.l.loop")
  , ("\x219a","arrow.l.not")
  , ("\x2b45","arrow.l.quad")
  , ("\x21dc","arrow.l.squiggly")
  , ("\x21e4","arrow.l.stop")
  , ("\x21e6","arrow.l.stroked")
  , ("\x21a2","arrow.l.tail")
  , ("\x21da","arrow.l.triple")
  , ("\x2b36","arrow.l.twohead.bar")
  , ("\x219e","arrow.l.twohead")
  , ("\x219c","arrow.l.wave")
  , ("\x2191","arrow.t")
  , ("\x21a5","arrow.t.bar")
  , ("\x2934","arrow.t.curve")
  , ("\x21e1","arrow.t.dashed")
  , ("\x21d1","arrow.t.double")
  , ("\x2b06","arrow.t.filled")
  , ("\x27f0","arrow.t.quad")
  , ("\x2912","arrow.t.stop")
  , ("\x21e7","arrow.t.stroked")
  , ("\x290a","arrow.t.triple")
  , ("\x219f","arrow.t.twohead")
  , ("\x2193","arrow.b")
  , ("\x21a7","arrow.b.bar")
  , ("\x2935","arrow.b.curve")
  , ("\x21e3","arrow.b.dashed")
  , ("\x21d3","arrow.b.double")
  , ("\x2b07","arrow.b.filled")
  , ("\x27f1","arrow.b.quad")
  , ("\x2913","arrow.b.stop")
  , ("\x21e9","arrow.b.stroked")
  , ("\x290b","arrow.b.triple")
  , ("\x21a1","arrow.b.twohead")
  , ("\x2194","arrow.l.r")
  , ("\x21d4","arrow.l.r.double")
  , ("\x27fa","arrow.l.r.double.long")
  , ("\x21ce","arrow.l.r.double.not")
  , ("\x2b0c","arrow.l.r.filled")
  , ("\x27f7","arrow.l.r.long")
  , ("\x21ae","arrow.l.r.not")
  , ("\x2b04","arrow.l.r.stroked")
  , ("\x21ad","arrow.l.r.wave")
  , ("\x2195","arrow.t.b")
  , ("\x21d5","arrow.t.b.double")
  , ("\x2b0d","arrow.t.b.filled")
  , ("\x21f3","arrow.t.b.stroked")
  , ("\x2197","arrow.tr")
  , ("\x21d7","arrow.tr.double")
  , ("\x2b08","arrow.tr.filled")
  , ("\x2924","arrow.tr.hook")
  , ("\x2b00","arrow.tr.stroked")
  , ("\x2198","arrow.br")
  , ("\x21d8","arrow.br.double")
  , ("\x2b0a","arrow.br.filled")
  , ("\x2925","arrow.br.hook")
  , ("\x2b02","arrow.br.stroked")
  , ("\x2196","arrow.tl")
  , ("\x21d6","arrow.tl.double")
  , ("\x2b09","arrow.tl.filled")
  , ("\x2923","arrow.tl.hook")
  , ("\x2b01","arrow.tl.stroked")
  , ("\x2199","arrow.bl")
  , ("\x21d9","arrow.bl.double")
  , ("\x2b0b","arrow.bl.filled")
  , ("\x2926","arrow.bl.hook")
  , ("\x2b03","arrow.bl.stroked")
  , ("\x2921","arrow.tl.br")
  , ("\x2922","arrow.tr.bl")
  , ("\x21ba","arrow.ccw")
  , ("\x21b6","arrow.ccw.half")
  , ("\x21bb","arrow.cw")
  , ("\x21b7","arrow.cw.half")
  , ("\x21af","arrow.zigzag")
  , ("\x2303","arrowhead.t")
  , ("\x2304","arrowhead.b")
  , ("\x21c9","arrows.rr")
  , ("\x21c7","arrows.ll")
  , ("\x21c8","arrows.tt")
  , ("\x21ca","arrows.bb")
  , ("\x21c6","arrows.lr")
  , ("\x21b9","arrows.lr.stop")
  , ("\x21c4","arrows.rl")
  , ("\x21c5","arrows.tb")
  , ("\x21f5","arrows.bt")
  , ("\x21f6","arrows.rrr")
  , ("\x2b31","arrows.lll")
  , ("*","ast")
  , ("\x204e","ast.low")
  , ("\x2051","ast.double")
  , ("\x2042","ast.triple")
  , ("\xfe61","ast.small")
  , ("\x2217","ast.op")
  , ("\x229b","ast.circle")
  , ("\x29c6","ast.sq")
  , ("@","at")
  , ("\\","backslash")
  , ("\x29b8","backslash.circle")
  , ("\x29f7","backslash.not")
  , ("\x2610","ballot")
  , ("\x2612","ballot.x")
  , ("|","bar.v")
  , ("\x2016","bar.v.double")
  , ("\x2980","bar.v.triple")
  , ("\xa6","bar.v.broken")
  , ("\x29b6","bar.v.circle")
  , ("\x2015","bar.h")
  , ("\x2235","because")
  , ("\x5d1","bet")
  , ("\x3b2","beta")
  , ("\x3d0","beta.alt")
  , ("\x20bf","bitcoin")
  , ("\x22a5","bot")
  , ("{","brace.l")
  , ("}","brace.r")
  , ("\x23de","brace.t")
  , ("\x23df","brace.b")
  , ("[","bracket.l")
  , ("]","bracket.r")
  , ("\x23b4","bracket.t")
  , ("\x23b5","bracket.b")
  , ("\x2d8","breve")
  , ("\x2038","caret")
  , ("\x2c7","caron")
  , ("\x2713","checkmark")
  , ("\x1f5f8","checkmark.light")
  , ("\x3c7","chi")
  , ("\x25cb","circle.stroked")
  , ("\x2218","circle.stroked.tiny")
  , ("\x26ac","circle.stroked.small")
  , ("\x25ef","circle.stroked.big")
  , ("\x25cf","circle.filled")
  , ("\x2981","circle.filled.tiny")
  , ("\x2219","circle.filled.small")
  , ("\x2b24","circle.filled.big")
  , ("\x25cc","circle.dotted")
  , ("\x229a","circle.nested")
  , ("\x2105","co")
  , (":","colon")
  , ("\x2254","colon.eq")
  , ("\x2a74","colon.double.eq")
  , (",","comma")
  , ("\x2201","complement")
  , ("\x2218","compose")
  , ("\x2217","convolve")
  , ("\xa9","copyright")
  , ("\x2117","copyright.sound")
  , ("\x2020","dagger")
  , ("\x2021","dagger.double")
  , ("\x2013","dash.en")
  , ("\x2014","dash.em")
  , ("\x2012","dash.fig")
  , ("\x301c","dash.wave")
  , ("\x2239","dash.colon")
  , ("\x229d","dash.circle")
  , ("\x3030","dash.wave.double")
  , ("\xb0","degree")
  , ("\x2103","degree.c")
  , ("\x2109","degree.f")
  , ("\x3b4","delta")
  , ("\xa8","diaer")
  , ("\x2300","diameter")
  , ("\x25c7","diamond.stroked")
  , ("\x22c4","diamond.stroked.small")
  , ("\x2b26","diamond.stroked.medium")
  , ("\x27d0","diamond.stroked.dot")
  , ("\x25c6","diamond.filled")
  , ("\x2b25","diamond.filled.medium")
  , ("\x2b29","diamond.filled.small")
  , ("\x2202","diff")
  , ("\xf7","div")
  , ("\x2a38","div.circle")
  , ("\x2223","divides")
  , ("\x2224","divides.not")
  , ("$","dollar")
  , (".","dot")
  , ("\x22c5","dot.op")
  , ("\xb7","dot.c")
  , ("\x2299","dot.circle")
  , ("\x2a00","dot.circle.big")
  , ("\x22a1","dot.square")
  , ("\x2026","dots.h")
  , ("\x22ef","dots.h.c")
  , ("\x22ee","dots.v")
  , ("\x22f1","dots.down")
  , ("\x22f0","dots.up")
  , ("\x2113","ell")
  , ("\x2b2d","ellipse.stroked.h")
  , ("\x2b2f","ellipse.stroked.v")
  , ("\x2b2c","ellipse.filled.h")
  , ("\x2b2e","ellipse.filled.v")
  , ("\x3b5","epsilon")
  , ("\x3f5","epsilon.alt")
  , ("=","eq")
  , ("\x225b","eq.star")
  , ("\x229c","eq.circle")
  , ("\x2255","eq.colon")
  , ("\x225d","eq.def")
  , ("\x225c","eq.delta")
  , ("\x225a","eq.equi")
  , ("\x2259","eq.est")
  , ("\x22dd","eq.gt")
  , ("\x22dc","eq.lt")
  , ("\x225e","eq.m")
  , ("\x2260","eq.not")
  , ("\x22de","eq.prec")
  , ("\x225f","eq.quest")
  , ("\xfe66","eq.small")
  , ("\x22df","eq.succ")
  , ("\x3b7","eta")
  , ("\x20ac","euro")
  , ("!","excl")
  , ("\x203c","excl.double")
  , ("\xa1","excl.inv")
  , ("\x2049","excl.quest")
  , ("\x2203","exists")
  , ("\x2204","exists.not")
  , ("\x29d8","fence.l")
  , ("\x29da","fence.l.double")
  , ("\x29d9","fence.r")
  , ("\x29db","fence.r.double")
  , ("\x2999","fence.dotted")
  , ("\x2766","floral")
  , ("\x2619","floral.l")
  , ("\x2767","floral.r")
  , ("\x2200","forall")
  , ("\x20a3","franc")
  , ("\x3b3","gamma")
  , ("\x5d2","gimel")
  , ("`","grave")
  , (">","gt")
  , ("\x29c1","gt.circle")
  , ("\x22d7","gt.dot")
  , ("\x226b","gt.double")
  , ("\x2265","gt.eq")
  , ("\x22db","gt.eq.lt")
  , ("\x2271","gt.eq.not")
  , ("\x2267","gt.eqq")
  , ("\x2277","gt.lt")
  , ("\x2279","gt.lt.not")
  , ("\x2269","gt.neqq")
  , ("\x226f","gt.not")
  , ("\x22e7","gt.ntilde")
  , ("\xfe65","gt.small")
  , ("\x2273","gt.tilde")
  , ("\x2275","gt.tilde.not")
  , ("\x22d9","gt.triple")
  , ("\x2af8","gt.triple.nested")
  , ("\x21c0","harpoon.rt")
  , ("\x295b","harpoon.rt.bar")
  , ("\x2953","harpoon.rt.stop")
  , ("\x21c1","harpoon.rb")
  , ("\x295f","harpoon.rb.bar")
  , ("\x2957","harpoon.rb.stop")
  , ("\x21bc","harpoon.lt")
  , ("\x295a","harpoon.lt.bar")
  , ("\x2952","harpoon.lt.stop")
  , ("\x21bd","harpoon.lb")
  , ("\x295e","harpoon.lb.bar")
  , ("\x2956","harpoon.lb.stop")
  , ("\x21bf","harpoon.tl")
  , ("\x2960","harpoon.tl.bar")
  , ("\x2958","harpoon.tl.stop")
  , ("\x21be","harpoon.tr")
  , ("\x295c","harpoon.tr.bar")
  , ("\x2954","harpoon.tr.stop")
  , ("\x21c3","harpoon.bl")
  , ("\x2961","harpoon.bl.bar")
  , ("\x2959","harpoon.bl.stop")
  , ("\x21c2","harpoon.br")
  , ("\x295d","harpoon.br.bar")
  , ("\x2955","harpoon.br.stop")
  , ("\x294e","harpoon.lt.rt")
  , ("\x2950","harpoon.lb.rb")
  , ("\x294b","harpoon.lb.rt")
  , ("\x294a","harpoon.lt.rb")
  , ("\x2951","harpoon.tl.bl")
  , ("\x294f","harpoon.tr.br")
  , ("\x294d","harpoon.tl.br")
  , ("\x294c","harpoon.tr.bl")
  , ("\x2964","harpoons.rtrb")
  , ("\x2965","harpoons.blbr")
  , ("\x296f","harpoons.bltr")
  , ("\x2967","harpoons.lbrb")
  , ("\x2962","harpoons.ltlb")
  , ("\x21cb","harpoons.ltrb")
  , ("\x2966","harpoons.ltrt")
  , ("\x2969","harpoons.rblb")
  , ("\x21cc","harpoons.rtlb")
  , ("\x2968","harpoons.rtlt")
  , ("\x296e","harpoons.tlbr")
  , ("\x2963","harpoons.tltr")
  , ("#","hash")
  , ("^","hat")
  , ("\x2b21","hexa.stroked")
  , ("\x2b22","hexa.filled")
  , ("\x2010","hyph")
  , ("-","hyph.minus")
  , ("\x2011","hyph.nobreak")
  , ("\x2027","hyph.point")
  , ("\173","hyph.soft")
  , ("\x2261","ident")
  , ("\x2262","ident.not")
  , ("\x2263","ident.strict")
  , ("\x2208","in")
  , ("\x2209","in.not")
  , ("\x220b","in.rev")
  , ("\x220c","in.rev.not")
  , ("\x220d","in.rev.small")
  , ("\x220a","in.small")
  , ("\x221e","infinity")
  , ("\x222b","integral")
  , ("\x2a17","integral.arrow.hook")
  , ("\x2a11","integral.ccw")
  , ("\x222e","integral.cont")
  , ("\x2233","integral.cont.ccw")
  , ("\x2232","integral.cont.cw")
  , ("\x2231","integral.cw")
  , ("\x222c","integral.double")
  , ("\x2a0c","integral.quad")
  , ("\x2a19","integral.sect")
  , ("\x2a16","integral.sq")
  , ("\x222f","integral.surf")
  , ("\x2a18","integral.times")
  , ("\x222d","integral.triple")
  , ("\x2a1a","integral.union")
  , ("\x2230","integral.vol")
  , ("\x203d","interrobang")
  , ("\x3b9","iota")
  , ("\x2a1d","join")
  , ("\x27d6","join.r")
  , ("\x27d5","join.l")
  , ("\x27d7","join.l.r")
  , ("\x3d7","kai")
  , ("\x3ba","kappa")
  , ("\x3f0","kappa.alt")
  , ("\x212a","kelvin")
  , ("\x3bb","lambda")
  , ("\x20ba","lira")
  , ("\x25ca","lozenge.stroked")
  , ("\x2b2b","lozenge.stroked.small")
  , ("\x2b28","lozenge.stroked.medium")
  , ("\x29eb","lozenge.filled")
  , ("\x2b2a","lozenge.filled.small")
  , ("\x2b27","lozenge.filled.medium")
  , ("<","lt")
  , ("\x29c0","lt.circle")
  , ("\x22d6","lt.dot")
  , ("\x226a","lt.double")
  , ("\x2264","lt.eq")
  , ("\x22da","lt.eq.gt")
  , ("\x2270","lt.eq.not")
  , ("\x2266","lt.eqq")
  , ("\x2276","lt.gt")
  , ("\x2278","lt.gt.not")
  , ("\x2268","lt.neqq")
  , ("\x226e","lt.not")
  , ("\x22e6","lt.ntilde")
  , ("\xfe64","lt.small")
  , ("\x2272","lt.tilde")
  , ("\x2274","lt.tilde.not")
  , ("\x22d8","lt.triple")
  , ("\x2af7","lt.triple.nested")
  , ("\xaf","macron")
  , ("\x2720","maltese")
  , ("\x2212","minus")
  , ("\x2296","minus.circle")
  , ("\x2238","minus.dot")
  , ("\x2213","minus.plus")
  , ("\x229f","minus.square")
  , ("\x2242","minus.tilde")
  , ("\x2a3a","minus.triangle")
  , ("\x22a7","models")
  , ("\x3bc","mu")
  , ("\x22b8","multimap")
  , ("\x2207","nabla")
  , ("\xac","not")
  , ("\x1f39c","notes.up")
  , ("\x1f39d","notes.down")
  , ("\x2205","nothing")
  , ("\x29b0","nothing.rev")
  , ("\x3bd","nu")
  , ("\x2126","ohm")
  , ("\x2127","ohm.inv")
  , ("\x3c9","omega")
  , ("\x3bf","omicron")
  , ("\x221e","oo")
  , ("\x2228","or")
  , ("\x22c1","or.big")
  , ("\x22ce","or.curly")
  , ("\x27c7","or.dot")
  , ("\x2a54","or.double")
  , ("\x2225","parallel")
  , ("\x29b7","parallel.circle")
  , ("\x2226","parallel.not")
  , ("(","paren.l")
  , (")","paren.r")
  , ("\x23dc","paren.t")
  , ("\x23dd","paren.b")
  , ("\x2b20","penta.stroked")
  , ("\x2b1f","penta.filled")
  , ("%","percent")
  , ("\x2030","permille")
  , ("\x27c2","perp")
  , ("\x29b9","perp.circle")
  , ("\x20b1","peso")
  , ("\x3c6","phi")
  , ("\x3d5","phi.alt")
  , ("\x3c0","pi")
  , ("\x3d6","pi.alt")
  , ("\xb6","pilcrow")
  , ("\x204b","pilcrow.rev")
  , ("\x210e","planck")
  , ("\x210f","planck.reduce")
  , ("+","plus")
  , ("\x2295","plus.circle")
  , ("\x27f4","plus.circle.arrow")
  , ("\x2a01","plus.circle.big")
  , ("\x2214","plus.dot")
  , ("\xb1","plus.minus")
  , ("\xfe62","plus.small")
  , ("\x229e","plus.square")
  , ("\x2a39","plus.triangle")
  , ("\xa3","pound")
  , ("\x227a","prec")
  , ("\x2ab7","prec.approx")
  , ("\x2abb","prec.double")
  , ("\x227c","prec.eq")
  , ("\x22e0","prec.eq.not")
  , ("\x2ab3","prec.eqq")
  , ("\x2ab9","prec.napprox")
  , ("\x2ab5","prec.neqq")
  , ("\x2280","prec.not")
  , ("\x22e8","prec.ntilde")
  , ("\x227e","prec.tilde")
  , ("\x2032","prime")
  , ("\x2035","prime.rev")
  , ("\x2033","prime.double")
  , ("\x2036","prime.double.rev")
  , ("\x2034","prime.triple")
  , ("\x2037","prime.triple.rev")
  , ("\x2057","prime.quad")
  , ("\x220f","product")
  , ("\x2210","product.co")
  , ("\x221d","prop")
  , ("\x3c8","psi")
  , ("\x220e","qed")
  , ("?","quest")
  , ("\x2047","quest.double")
  , ("\x2048","quest.excl")
  , ("\xbf","quest.inv")
  , ("\"","quote.double")
  , ("'","quote.single")
  , ("\x201c","quote.l.double")
  , ("\x2018","quote.l.single")
  , ("\x201d","quote.r.double")
  , ("\x2019","quote.r.single")
  , ("\xab","quote.angle.l.double")
  , ("\x2039","quote.angle.l.single")
  , ("\xbb","quote.angle.r.double")
  , ("\x203a","quote.angle.r.single")
  , ("\x201f","quote.high.double")
  , ("\x201b","quote.high.single")
  , ("\x201e","quote.low.double")
  , ("\x201a","quote.low.single")
  , ("\x2236","ratio")
  , ("\x25ad","rect.stroked.h")
  , ("\x25af","rect.stroked.v")
  , ("\x25ac","rect.filled.h")
  , ("\x25ae","rect.filled.v")
  , ("\x203b","refmark")
  , ("\x3c1","rho")
  , ("\x3f1","rho.alt")
  , ("\x20bd","ruble")
  , ("\x20b9","rupee")
  , ("\x2229","sect")
  , ("\x2a44","sect.and")
  , ("\x22c2","sect.big")
  , ("\x2a40","sect.dot")
  , ("\x22d2","sect.double")
  , ("\x2293","sect.sq")
  , ("\x2a05","sect.sq.big")
  , ("\x2a4e","sect.sq.double")
  , ("\xa7","section")
  , (";","semi")
  , ("\x204f","semi.rev")
  , ("\x2120","servicemark")
  , ("\x5e9","shin")
  , ("\x3c3","sigma")
  , ("/","slash")
  , ("\x2afd","slash.double")
  , ("\x2afb","slash.triple")
  , ("\x2a33","smash")
  , ("s","space")
  , ("\xa0","space.nobreak")
  , ("\x2002","space.en")
  , ("\x2003","space.quad")
  , ("\x2004","space.third")
  , ("\x2005","space.quarter")
  , ("\x2006","space.sixth")
  , ("\x205f","space.med")
  , ("\x2007","space.fig")
  , ("\x2008","space.punct")
  , ("\x2009","space.thin")
  , ("\x200a","space.hair")
  , ("\x25a1","square.stroked")
  , ("\x25ab","square.stroked.tiny")
  , ("\x25fd","square.stroked.small")
  , ("\x25fb","square.stroked.medium")
  , ("\x2b1c","square.stroked.big")
  , ("\x2b1a","square.stroked.dotted")
  , ("\x25a2","square.stroked.rounded")
  , ("\x25a0","square.filled")
  , ("\x25aa","square.filled.tiny")
  , ("\x25fe","square.filled.small")
  , ("\x25fc","square.filled.medium")
  , ("\x2b1b","square.filled.big")
  , ("\x22c6","star.op")
  , ("\x2605","star.stroked")
  , ("\x2605","star.filled")
  , ("\x2282","subset")
  , ("\x2abd","subset.dot")
  , ("\x22d0","subset.double")
  , ("\x2286","subset.eq")
  , ("\x2288","subset.eq.not")
  , ("\x2291","subset.eq.sq")
  , ("\x22e2","subset.eq.sq.not")
  , ("\x228a","subset.neq")
  , ("\x2284","subset.not")
  , ("\x228f","subset.sq")
  , ("\x22e4","subset.sq.neq")
  , ("\x227b","succ")
  , ("\x2ab8","succ.approx")
  , ("\x2abc","succ.double")
  , ("\x227d","succ.eq")
  , ("\x22e1","succ.eq.not")
  , ("\x2ab4","succ.eqq")
  , ("\x2aba","succ.napprox")
  , ("\x2ab6","succ.neqq")
  , ("\x2281","succ.not")
  , ("\x22e9","succ.ntilde")
  , ("\x227f","succ.tilde")
  , ("\x2663","suit.club")
  , ("\x2666","suit.diamond")
  , ("\x2665","suit.heart")
  , ("\x2660","suit.spade")
  , ("\x2211","sum")
  , ("\x2a0b","sum.integral")
  , ("\x2283","supset")
  , ("\x2abe","supset.dot")
  , ("\x22d1","supset.double")
  , ("\x2287","supset.eq")
  , ("\x2289","supset.eq.not")
  , ("\x2292","supset.eq.sq")
  , ("\x22e3","supset.eq.sq.not")
  , ("\x228b","supset.neq")
  , ("\x2285","supset.not")
  , ("\x2290","supset.sq")
  , ("\x22e5","supset.sq.neq")
  , ("\x22a2","tack.r")
  , ("\x27dd","tack.r.long")
  , ("\x22a3","tack.l")
  , ("\x27de","tack.l.long")
  , ("\x2ade","tack.l.short")
  , ("\x22a5","tack.t")
  , ("\x27d8","tack.t.big")
  , ("\x2aeb","tack.t.double")
  , ("\x2ae0","tack.t.short")
  , ("\x22a4","tack.b")
  , ("\x27d9","tack.b.big")
  , ("\x2aea","tack.b.double")
  , ("\x2adf","tack.b.short")
  , ("\x27db","tack.l.r")
  , ("\x3c4","tau")
  , ("\x2234","therefore")
  , ("\x3b8","theta")
  , ("\x3d1","theta.alt")
  , ("~","tilde")
  , ("\x223c","tilde.op")
  , ("\x2243","tilde.eq")
  , ("\x2244","tilde.eq.not")
  , ("\x22cd","tilde.eq.rev")
  , ("\x2245","tilde.eqq")
  , ("\x2247","tilde.eqq.not")
  , ("\x2246","tilde.neqq")
  , ("\x2241","tilde.not")
  , ("\x223d","tilde.rev")
  , ("\x224c","tilde.rev.eqq")
  , ("\x224b","tilde.triple")
  , ("\xd7","times")
  , ("\x2a09","times.big")
  , ("\x2297","times.circle")
  , ("\x2a02","times.circle.big")
  , ("\x22c7","times.div")
  , ("\x22cb","times.l")
  , ("\x22cc","times.r")
  , ("\x22a0","times.square")
  , ("\x2a3b","times.triangle")
  , ("\x22a4","top")
  , ("\x25b7","triangle.stroked.r")
  , ("\x25c1","triangle.stroked.l")
  , ("\x25b3","triangle.stroked.t")
  , ("\x25bd","triangle.stroked.b")
  , ("\x25fa","triangle.stroked.bl")
  , ("\x25ff","triangle.stroked.br")
  , ("\x25f8","triangle.stroked.tl")
  , ("\x25f9","triangle.stroked.tr")
  , ("\x25b9","triangle.stroked.small.r")
  , ("\x25bf","triangle.stroked.small.b")
  , ("\x25c3","triangle.stroked.small.l")
  , ("\x25b5","triangle.stroked.small.t")
  , ("\x1f6c6","triangle.stroked.rounded")
  , ("\x27c1","triangle.stroked.nested")
  , ("\x25ec","triangle.stroked.dot")
  , ("\x25b6","triangle.filled.r")
  , ("\x25c0","triangle.filled.l")
  , ("\x25b2","triangle.filled.t")
  , ("\x25bc","triangle.filled.b")
  , ("\x25e3","triangle.filled.bl")
  , ("\x25e2","triangle.filled.br")
  , ("\x25e4","triangle.filled.tl")
  , ("\x25e5","triangle.filled.tr")
  , ("\x25b8","triangle.filled.small.r")
  , ("\x25be","triangle.filled.small.b")
  , ("\x25c2","triangle.filled.small.l")
  , ("\x25b4","triangle.filled.small.t")
  , ("\x3014","turtle.l")
  , ("\x3015","turtle.r")
  , ("\x23e0","turtle.t")
  , ("\x23e1","turtle.b")
  , ("\x222a","union")
  , ("\x228c","union.arrow")
  , ("\x22c3","union.big")
  , ("\x228d","union.dot")
  , ("\x2a03","union.dot.big")
  , ("\x22d3","union.double")
  , ("\x2a41","union.minus")
  , ("\x2a45","union.or")
  , ("\x228e","union.plus")
  , ("\x2a04","union.plus.big")
  , ("\x2294","union.sq")
  , ("\x2a06","union.sq.big")
  , ("\x2a4f","union.sq.double")
  , ("\x3c5","upsilon")
  , ("\x2216","without")
  , ("\8288","wj")
  , ("\x20a9","won")
  , ("\x2240","wreath")
  , ("\x3be","xi")
  , ("\xa5","yen")
  , ("\x3b6","zeta")
  , ("\x200d","zwj")
  , ("\x200c","zwnj")
  , ("\x200b","zws") ]