content: {-|
  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 Control.Monad ((<=<))
  import Data.Char (chr)
  import Language.Haskell.TH (Q, ExpQ, stringE)
  import Language.Haskell.TH.Quote (QuasiQuoter(..))
  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
  