packages feed

LslPlus-0.2.0: src/Language/Lsl/Internal/AccessGenerator.hs

{-# OPTIONS_GHC -XTemplateHaskell #-}
module Language.Lsl.Internal.AccessGenerator(genAccessorsForType,genMAccessorsForType) where

import Language.Haskell.TH
import Control.Monad.State

genAccessors (ConT nm) = genAccessorsForType nm
genAccessors _ = fail "can't generate accessors for specified type"

genAccessorsForType nm = do
    info <- reify nm
    case info of
        TyConI d -> generateAccessorsForDec d
        _ -> fail $ "can't generate accessors for specified name: " ++ show nm

generateAccessorsForDec (DataD _ _ _ [con] _) = generateAccessorsForCon con
generateAccessorsForDec (DataD _ _ _ _ _) = fail "can't generate accessors for data type with multiple constructors"
generateAccessorsForDec _ = fail "can only generate accessors for 'data' types (not even newtypes)"

generateAccessorsForCon (RecC _ vs) = generateAccessorsForSelectors vs
generateAccessorsForCon _ = fail "can only generate accessors for constructors with record selectors (and not quantified constructors)"

generateAccessorsForSelectors vs = mapM generateAccessorForSelector vs
generateAccessorForSelector (nm,_,_) = 
    let nm' = mkName ("set'" ++ nameBase nm) in do
        nm0 <- newName "x"
        nm1 <- newName "y"
        return (FunD nm' [Clause [VarP nm0, VarP nm1] (NormalB (RecUpdE (VarE nm0) [(nm,VarE nm1)])) []])

genMAccessors (ConT nm) = genAccessorsForType nm
genMAccessors _ = fail "can't generate accessors for specified type"

genMAccessorsForType nm = do
    info <- reify nm
    case info of
        TyConI d -> generateMAccessorsForDec d
        _ -> fail $ "can't generate accessors for specified name: " ++ show nm

generateMAccessorsForDec (DataD _ _ _ [con] _) = generateMAccessorsForCon con
generateMAccessorsForDec (DataD _ _ _ _ _) = fail "can't generate accessors for data type with multiple constructors"
generateMAccessorsForDec _ = fail "can only generate accessors for 'data' types (not even newtypes)"

generateMAccessorsForCon (RecC _ vs) = generateMAccessorsForSelectors vs
generateMAccessorsForCon _ = fail "can only generate accessors for constructors with record selectors (and not quantified constructors)"

generateMAccessorsForSelectors vs = 
    mapM generateMAccessorForSelector vs >>= return . concat
    
generateMAccessorForSelector (nm,_,_) = 
    let nmPut' = mkName ("put'" ++ nameBase nm) 
        nmGet' = mkName ("get'" ++ nameBase nm)
        nmCompose = '(.)
        nmBind = '(>>= )
        nmGet = 'get
        nmPut = 'put
        nmReturn = 'return
    in do
        nm0 <- newName "x"
        nm1 <- newName "s"
        return [(FunD nmGet' [Clause [] (NormalB (AppE (AppE (VarE nmBind) (VarE nmGet)) (AppE (AppE (VarE nmCompose) (VarE nmReturn)) (VarE nm)))) []]),
                (FunD nmPut' [Clause [VarP nm0] 
                    (NormalB 
                        -- get >>= \ s -> put (s { nm = nm0 })
                        (AppE (AppE (VarE nmBind) (VarE nmGet)) (LamE [VarP nm1] (AppE (VarE nmPut) (RecUpdE (VarE nm1) [(nm,VarE nm0)]))))
                    ) []])]