hssqlppp-0.2.0: Database/HsSqlPpp/Dbms/MakeLabels.hs
{-# LANGUAGE TemplateHaskell, FlexibleInstances, EmptyDataDecls, DeriveDataTypeable #-}
-- robbed from the darcs version of hlist
-- Making labels
{-
The following TH splice
$(makeLabels ["getX","getY","draw"])
should expand into the following declarations
data GetX; getX = proxy::Proxy GetX
data GetY; getY = proxy::Proxy GetY
data Draw; draw = proxy::Proxy Draw
-}
module Database.HsSqlPpp.Dbms.MakeLabels (makeLabels,label) where
import Data.HList.FakePrelude
import Language.Haskell.TH.Ppr () --pprint,Ppr)
import Language.Haskell.TH.Syntax
import Data.Char (toUpper, toLower)
import Control.Monad (liftM)
import Data.Typeable
capitalize, uncapitalize :: String -> String
capitalize (c:rest) = toUpper c : rest
capitalize [] = []
uncapitalize (c:rest) = toLower c : rest
uncapitalize [] = []
-- Make the name of the type constructor whose string representation
-- is capitalized str
make_tname :: String -> Name
make_tname str = mkName $ capitalize str
-- Make the name of the value identifier whose string representation
-- is uncapitalized str
make_dname :: String -> Name
make_dname str = mkName $ uncapitalize str
-- The template of our declaration. We will then replace all occurences
-- of Foo with the desired name
dcl_template :: Q [Dec]
dcl_template = [d| data Foo deriving Typeable; foo :: Proxy Foo; foo = proxy::Proxy Foo |]
-- A very dirty traversal/replacement...
class ReplaceSyntax a where
replace_name :: (Name,Name) -> (Name,Name) -> a -> a
instance ReplaceSyntax [Dec] where
replace_name frm to dcls = map (replace_name frm to) dcls
instance ReplaceSyntax Dec where
replace_name (tfrom,_) (tto,_)
dcl@(DataD ctx n parms con othern) =
if tfrom == n then
DataD ctx tto parms con othern
else dcl
replace_name (tfrom,dfrom) (tto,dto)
(ValD (VarP n) (NormalB body) []) =
let n' = if n == dfrom then dto else n
in ValD (VarP n')
(NormalB (replace_name (tfrom,dfrom) (tto,dto) body)) []
replace_name (tfrom,dfrom) (tto,dto) (SigD n t) =
let n' = if n == dfrom then dto else n
in SigD n' (replace_name (tfrom,dfrom) (tto,dto) t)
replace_name _ _ dcl =
error $ "Can't handle: " ++ show dcl
instance ReplaceSyntax Exp where
replace_name from to (SigE exp' tp) =
SigE (replace_name from to exp')
(replace_name from to tp)
replace_name _ _ exp' = exp'
instance ReplaceSyntax Type where
replace_name (tfrom,_) (tto,_) tp@(ConT n) =
if n == tfrom then (ConT tto) else tp
replace_name from to (AppT t1 t2) =
(AppT (replace_name from to t1) (replace_name from to t2))
replace_name _ _ t = error $ "Can't handle: " ++ show t
-- Our main function
makeLabels :: [String] -> Q [Dec]
makeLabels = liftM concat . sequence . map repl
where
repl n = liftM (replace_name from (to n)) dcl_template
from = (make_tname "foo",make_dname "foo")
to n = (make_tname n,make_dname n)
label :: String -> Q [Dec]
label s = makeLabels [s]
{-
-- Show the code expression
show_code :: Ppr a => Q a -> IO ()
show_code cde = runQ cde >>= putStrLn . pprint
t1 :: IO ()
t1 = show_code [d| data Foo |]
t2 :: String
t2 = showName $ mkName "Foo"
t3 :: IO ()
t3 = show_code $
liftM (replace_name
(make_tname "foo",make_dname "foo")
(make_tname "bar",make_dname "bar")) dcl_template
t4 :: IO ()
t4 = show_code $ makeLabels ["getX","getY","draw"]
-}