names-th-0.1.0.1: src/Language/Haskell/TH/Name/CamelCase.hs
-- |
-- Module : Language.Haskell.TH.Name.CamelCase
-- Copyright : 2013 Kei Hibino
-- License : BSD3
--
-- Maintainer : ex8k.hibino@gmail.com
-- Stability : experimental
-- Portability : unknown
--
-- This module provides camelcased 'Name' for Template Haskell
module Language.Haskell.TH.Name.CamelCase (
-- * Types to wrap 'Name'
-- $nameTypes
ConName (ConName, conName), toConName,
VarName (VarName, varName), toVarName,
-- * Functions to make camel-cased names
-- $makeNames
conCamelcaseName, varCamelcaseName,
varNameWithPrefix,
-- * Functions to generate haskell template from names
-- $makeTemplates
toTypeCon, toDataCon,
toVarExp, toVarPat
) where
import Data.Char (toUpper, toLower)
import Data.Set (Set, fromList, member)
import Language.Haskell.TH
(Name, mkName, TypeQ, conT, ExpQ, conE, varE, PatQ, varP)
capitalize :: String -> String
capitalize (c:cs) = toUpper c : cs
capitalize "" = ""
unCapitalize :: String -> String
unCapitalize (c:cs) = toLower c : cs
unCapitalize "" = ""
-- | rename the string that equals to reserved identifiers.
rename :: String -> String
rename cs | cs `member` reservedIds = cs ++ "_"
| otherwise = cs
{-# INLINE rename #-}
-- | All reserved identifiers. Taken from section 2.4 of the 2010 Report.
reservedIds :: Set String
reservedIds = fromList [ "case", "class", "data", "default", "deriving"
, "do", "else", "foreign", "if", "import", "in"
, "infix", "infixl", "infixr", "instance", "let"
, "module", "newtype", "of", "then", "type", "where"
, "_" ]
{-# INLINE reservedIds #-}
{- $nameTypes
Wrap 'Name' to distinguish constructor names and variable names.
-}
-- | Type to wrap constructor\'s 'Name'.
newtype ConName = ConName { conName :: Name {- ^ Get wrapped 'Name' -} }
-- | Make constructor name from 'String'.
toConName :: String -> ConName
toConName = ConName . mkName . rename . capitalize
-- | Type to wrap variable\'s 'Name'.
newtype VarName = VarName { varName :: Name {- ^ Get wrapped 'Name' -} }
-- | Make variable name from 'String'.
toVarName :: String -> VarName
toVarName = VarName . mkName . rename . unCapitalize
-- | 'Char' set used from camel-cased names.
nameChars :: String
nameChars = '\'' : ['0' .. '9'] ++ ['A' .. 'Z'] ++ ['a' .. 'z']
-- | Split into chunks to generate camel-cased 'String'.
splitForName :: String -> [String]
splitForName str
| rest /= [] = tk : splitForName (tail rest)
| otherwise = [tk]
where
(tk, rest) = span (`elem` nameChars) str
{- $makeNames
Make camel-cased names.
-}
-- | Convert into camel-cased 'String'.
-- First 'Char' of result is upper case.
camelcaseUpper :: String -> String
camelcaseUpper = concatMap capitalize . splitForName
-- | Make camel-cased constructor name from 'String'.
conCamelcaseName :: String -> ConName
conCamelcaseName = toConName . camelcaseUpper
-- | Make camel-cased variable name from 'String'.
varCamelcaseName :: String -> VarName
varCamelcaseName = toVarName . camelcaseUpper
-- | Make camel-cased variable name with prefix like below.
--
-- > name `varNamePrefix` prefix
--
varNameWithPrefix :: String -> String -> VarName
varNameWithPrefix n p = toVarName $ p ++ camelcaseUpper n
{- $makeTemplates
Make haskell templates from names.
-}
-- | Make type constructor 'TypeQ' monad from constructor name type.
toTypeCon :: ConName -> TypeQ
toTypeCon = conT . conName
-- | Make data constructor 'ExpQ' monad from constructor name type.
toDataCon :: ConName -> ExpQ
toDataCon = conE . conName
-- | Make variable 'ExpQ' monad from variable name type.
toVarExp :: VarName -> ExpQ
toVarExp = varE . varName
-- | Make pattern 'PatQ' monad from variable name type.
toVarPat :: VarName -> PatQ
toVarPat = varP . varName