Advertisement
Yurry

Template Haskore

Jun 4th, 2012
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE TemplateHaskell #-}
  2. module Morpho where
  3.  
  4. import Data.Char
  5. import Language.Haskell.TH
  6. import Language.Haskell.TH.Syntax
  7. import Control.Monad
  8. import qualified Data.Map as M
  9.  
  10. decapitalize [] = []
  11. decapitalize (x:xs) = (toLower x):xs
  12.  
  13. capitalize [] = []
  14. capitalize (x:xs) = (toUpper x):xs
  15.  
  16. type GCat = (String, [String])
  17.  
  18. toDerive = [''Eq, ''Ord, ''Show, ''Read]
  19.  
  20. makeCategories :: [GCat] -> [Dec]
  21. makeCategories categories =
  22.     [DataD [] (mkName name) [] (undefValue:[NormalC (mkName value) [] | value <- values]) toDerive
  23.         | (name, values) <- categories,
  24.         let undefValue = NormalC (mkName $ "Undef" ++ name) []]
  25.  
  26. makeStruct :: Name -> [Name] -> Dec
  27. makeStruct name categories = DataD [] name [] [makeCon categories] []
  28.     where makeCon = RecC name . map
  29.               (\fname -> (mkName (decapitalize $ show fname), NotStrict, ConT fname))
  30.  
  31. showField :: Exp -> Exp -> Q Exp
  32. showField fname empty = [|\struct -> let value = $(return fname) struct in if value == $(return empty) then "" else show value|]
  33.  
  34. genPE :: Int -> Q ([Pat], [Exp])
  35. genPE n = do
  36.     ids <- replicateM n (newName "x")
  37.     return (map VarP ids, map VarE ids)
  38.  
  39. showClause :: Name -> [String] -> Q Clause
  40. showClause sname categories = do
  41.     (pats, vars) <- genPE (length categories)
  42.     -- Рекурсивно строим выражение (" "++show x1++...++"") из списка переменных [x1, ...]
  43.     let varsWithUndef = zip vars (map (\c -> ConE . mkName $ ("Undef" ++ c)) categories)
  44.     let f []       = [| "" |]
  45.         f ((v, undef):[]) = [|(if $(return v) == $(return undef) then "" else (show $(return v)))|]
  46.         f ((v, undef):vars) = [|(if $(return v) == $(return undef) then "" else (show $(return v)) ++ " ") ++ $(f vars)|]
  47.     -- Собираем один клоз функции
  48.     body <- f varsWithUndef
  49.     return $ Clause [ConP sname pats]       -- (A x1 x2)
  50.            (NormalB body) []  -- "A"++" "++show x1++" "++show x2
  51.  
  52. deriveShow :: Name -> [String] -> Q [Dec]
  53. deriveShow sname categories = do
  54.     showbody <- showClause sname categories
  55.     return [InstanceD [] (AppT (ConT ''Show) (ConT sname)) [FunD 'show [showbody]]]
  56.  
  57. makeEmptyStruct name fields =
  58.    foldl (\exp field -> AppE exp (ConE . mkName . ("Undef" ++) . show $ field)) (ConE name) fields
  59.  
  60. concatExps :: [Q Exp] -> Q Exp
  61. concatExps [] = [|[]|]
  62. concatExps (x:xs) = [|$x ++ $(concatExps xs)|]
  63.  
  64. makeSetter :: Name -> Name -> String -> Exp
  65. makeSetter var field value = TupE [LitE (StringL value), LamE ([VarP var]) (RecUpdE (VarE var) [(field, ConE (mkName value))])]
  66.    
  67. makeLoaders :: [GCat] -> Q Exp
  68. makeLoaders categories = do
  69.    var <- newName "gv"
  70.    return (ListE $ concat [[makeSetter var field value | value <- values] | (name, values) <- categories, let field = mkName (decapitalize name)])
  71.  
  72. defGrammarValue :: String -> [GCat] -> Q [Dec]
  73. defGrammarValue structName fields = do
  74.    let categories = makeCategories fields
  75.    let catNames = map (\(DataD _ fname _ _ _) -> fname) categories
  76.    let sname = mkName structName
  77.    let struct = makeStruct sname catNames
  78.    let emptyGV = FunD (mkName "emptyGV") [Clause [] (NormalB $ makeEmptyStruct sname catNames) []]
  79.    shower <- deriveShow sname (fst . unzip $ fields)
  80.    loader <- [d|gvLoader = M.fromList $ $(makeLoaders fields)|]
  81.    return $ categories ++ [struct, emptyGV] ++ shower ++ loader
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement