freetype2-0.2.0: test/Fields/Lens.hsc
module Fields.Lens where
import Data.Char
#if __GLASGOW_HASKELL__ < 804
import Data.Monoid
#endif
import Language.Haskell.TH
testFieldsFT :: Name -> ExpQ
testFieldsFT dt = do
dec <- reify dt
case dec of
TyConI (DataD _ dtName _ _ cons _) ->
stringE . mappend (nameBase dt <> "\n") . mconcat . flip fmap cons $ \con ->
case con of
RecC _ vars ->
mconcat . flip fmap vars $ \(varName, _, _) ->
"✓ " <> synthesize id (nameBase dt) (nameBase varName) <> "\n"
_ -> error $ "Not all constructors of " <> nameBase dt <> " have record fields"
_ -> error $ nameBase dt <> " is not a plain type constructor"
synthesize :: (String -> String) -> String -> String -> String
synthesize modify dt this =
let prefixSize = length $ strip dt
reference = "(" <> dt <> ", " <> this <> ")"
in if take prefixSize this /= strip dt
then error $ "Prefix does not match function name " <> reference
else if isLower . head $ drop prefixSize this
then error $ "Field prefix is larger than the datatype name " <> reference
else let name = modify . first toLower $ drop prefixSize this
in if null name
then error $ "Nothing left after stripping prefix " <> reference
else name
strip :: String -> String
strip str =
let caps = filter (\a -> isUpper a || a == '\'') . drop 1 $ dropWhile (/= '_') str
in if last caps == '\''
then init (fmap toLower caps) <> "t"
else fmap toLower caps
first :: (a -> a) -> [a] -> [a]
first _ [] = []
first f (a:as) = f a : as