packages feed

lhc-0.6.20081127: src/DerivingDrift/Drift.hs

module DerivingDrift.Drift(driftDerive) where

import Char
import List
import Control.Monad.Identity
import qualified Data.Traversable as T

import CharIO
import DerivingDrift.DataP
import DerivingDrift.StandardRules
import FrontEnd.HsParser
import FrontEnd.ParseMonad
import FrontEnd.HsSyn
import Name.Name
import Name.Names
import Name.VConsts
import Options
import Text.PrettyPrint.HughesPJ(render)
import qualified Data.Map as Map
import qualified FlagDump as FD

driftDerive :: HsModule -> IO HsModule
driftDerive hsModule = ans where
    ans | null ss = return hsModule
        | otherwise = do
            wdump FD.Derived $ do
                CharIO.print $ hsModuleName hsModule
                mapM_ CharIO.putErrLn ss
            return hsMod'
    hsMod' = hsModule { hsModuleDecls = hsModuleDecls hsModule ++ ndcls }
    --hsMod = case parse (unlines ss) (SrcLoc (show $ hsModuleName hsModule) 1 1) 0 [] of
    hsMod = case runParser parse (unlines ss)  of
        ParseOk _ e -> e
        ParseFailed sl err -> error $ "driftDerive: " ++ show sl ++ err
    ndcls = hsModuleDecls hsMod
    ss = [ n | Just n <- map driftDerive' $ hsModuleDecls hsModule, any (not . isSpace) n ]

enumDontDerive :: [(HsName,[HsName])]
enumDontDerive = [
    (f class_Eq, [func_equals fns]),
    (f class_Ord, [func_geq fns, func_leq fns, func_lt fns, func_gt fns]),
    (f class_Enum, [func_toEnum fns,func_fromEnum fns] ++ map (nameName . toUnqualified) [v_enumFrom, v_succ, v_pred, v_enumFromThen, v_enumFromThenTo, v_enumFromTo])
    ]  where
        Identity fns = T.mapM (return . f) sFuncNames
        f n = nameName (toUnqualified n)



driftDerive' :: Monad m => HsDecl -> m String
driftDerive' HsDataDecl { hsDeclName = name, hsDeclArgs = args, hsDeclCons = condecls, hsDeclDerives = derives } = do
        let d =  toData  name args condecls derives
            isEnum = length condecls > 1 && null (concatMap hsConDeclArgs condecls)
        xs <- return $  map (derive isEnum d) derives -- (if isEnum then derives List.\\ enumDontDerive else derives )
        return $ unlines xs
driftDerive' (HsNewTypeDecl sloc cntxt name args condecl derives) = do
        let d =  toData  name args [condecl] derives
        xs <- return $ map (derive False d) derives
        return $ unlines xs

driftDerive' _ = fail "Nothing to derive"

toData :: HsName -> [HsName] -> [HsConDecl] -> [HsName] -> Data
toData name args cons derives = ans where
    f c = Body { constructor = pp (show $ hsConDeclName c), types = hsConDeclArgs c, labels = lb c }
    pp xs@(x:_) | isAlpha x = xs
    pp xs = '(':xs++")"
    lb HsConDecl {} = []
    lb r = concat [map show xs | (xs,_) <- hsConDeclRecArg r ]
    ans = D { statement = DataStmt, vars = map show args, constraints = [], name = show name,  derives = map show derives, body = map f cons }


derive True d wh | Just fns <- lookup wh enumDontDerive = inst fns where
    dummy = "{- This is a dummy instance, it will be rewritten internally -}\n"
    inst fns = dummy ++ "instance " ++ show wh ++ " " ++ name d ++ " where\n" ++ concat (intersperse "\n" (map f fns))
    f n = "    " ++ g (show n) ++ " = " ++ g (show n)
    g (c:cs) | c == '_' || c == '\'' || isAlpha c = c:cs
    g x = "(" ++ x ++ ")"

derive _ d wh | Just fn <- Map.lookup wh (Map.mapKeys (nameName . toUnqualified) standardRules) = render $ fn d
              | otherwise  = error ("derive: Tried to use non-existing rule "++show wh++" for "++name d)