{-# LANGUAGE NoImplicitPrelude #-}

module DSV.DelimiterSplice
  ( charDelimiter
  ) where

import DSV.DelimiterType
import DSV.Prelude

import Data.Word (Word8)

import qualified Data.Char

import Language.Haskell.TH.Syntax (Q, Exp, lift)

-- | A Template Haskell expression of type 'Delimiter'. Rejects code points above @0xff@.
--
-- === Example
--
-- 'comma' is defined as:
--
-- @$('charDelimiter' ',')@
--
-- This could be written equivalently as:
--
-- @'Delimiter' ('fromIntegral' ('Data.Char.ord' ','))@
--
-- but the former includes a compile-time check to ensure that the character @','@ is representable by a single byte (and thus that 'fromIntegral' does not overflow).

charDelimiter :: Char -> Q Exp
charDelimiter :: Char -> Q Exp
charDelimiter Char
c =
  do
    let n :: Int
n = Char -> Int
Data.Char.ord Char
c :: Int
    if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
forall a. Bounded a => a
maxBound :: Word8) :: Int)
        then String -> Q Exp
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"Character " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
c] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is outside the range of Word8.")
        else Delimiter -> Q Exp
forall t. Lift t => t -> Q Exp
lift (Word8 -> Delimiter
Delimiter (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n :: Word8))