{-| Module : DigraphQuote Description : Template Haskell quasi-quoter for digraph table Copyright : (c) Eric Mertens, 2017 License : ISC Maintainer : emertens@gmail.com -} module DigraphQuote (digraphTable) where import Data.Char import Control.Monad import Language.Haskell.TH import Language.Haskell.TH.Quote import Numeric (readHex) digraphTable :: QuasiQuoter digraphTable = QuasiQuoter { quoteExp = digraphTableExp , quotePat = const (fail "Digraph table must be an expression") , quoteType = const (fail "Digraph table must be an expression") , quoteDec = const (fail "Digraph table must be an expression") } digraphTableExp :: String -> ExpQ digraphTableExp = stringE . concat <=< traverse parseEntry . lines -- Parse entries, empty lines are ignored, -- comments are allowed -- Entries are a two-character digraph followed by a hexadecimal -- representation of the replacement character's unicode value. -- -- Examples -- -- > "' 14 -- > AB 0123 -- > CD 0FDE -- with a comment -- > -- > -- with a comment parseEntry :: String -> Q String parseEntry line = case words line of [x,y] : ('U':'+':hex) : rest | [(n,"")] <- readHex hex , isAllowedTerminator rest -> pure [x,y,chr n] rest | isAllowedTerminator rest -> pure "" -- skip empty lines | otherwise -> fail ("Bad digraph entry: " ++ line) -- Optionally tolerate a comment isAllowedTerminator :: [String] -> Bool isAllowedTerminator (('-':'-':_):_) = True isAllowedTerminator [] = True isAllowedTerminator _ = False