packages feed

asil-1.2: src/SymInfo.hs

-- | Extracts symbolic information from a generated Haskell file
module SymInfo(SymInfo(..),extractSymInfo,extractSymInfos) where

import qualified Data.Set as Set
import Data.Set(Set)
import Data.Monoid
import Language.Haskell.Exts
import System.IO
import System.IO.Error


-- | Carries symbolic information around.
data SymInfo = SymInfo { allTypes :: !(Set String), allFields :: !(Set String), allModules :: !(Set String) }
  deriving (Eq,Ord,Show)

-- | Monoid instance allows merging of sym info structures.
instance Monoid SymInfo where
  mempty = SymInfo mempty mempty mempty
  (SymInfo t1 f1 m1) `mappend` (SymInfo t2 f2 m2) = SymInfo (t1 `mappend` t2) (f1 `mappend` f2) (m1 `mappend` m2)


-- | Extracts symbolic info from multiple files
extractSymInfos :: [FilePath] -> IO SymInfo
extractSymInfos paths = do
  infos <- mapM extractSymInfo paths
  return $ foldr mappend mempty infos


-- | Runs the parser.
extractSymInfo :: FilePath -> IO SymInfo
extractSymInfo path = do
  str <- readFile path
  case parseModuleWithMode (defaultParseMode { parseFilename = path, ignoreLanguagePragmas = False, extensions = exts }) str of
    ParseFailed loc msg -> ioError $ userError ("Parse failed at " ++ show loc ++ ": " ++ msg)
    ParseOk m -> return $ toSymInfo m
  where exts = [ OverlappingInstances,MultiParamTypeClasses,FunctionalDependencies
               , FlexibleContexts,FlexibleInstances,EmptyDataDecls,TypeSynonymInstances ]

-- | Takes a Haskell module and returns the symbolic information contained in it.
toSymInfo :: Module -> SymInfo
toSymInfo (Module _ (ModuleName nm) _ _ _ _ decls) = SymInfo tps flds nms where
  nms  = Set.singleton nm
  tps  = strs "TypeObject"
  flds = strs "Key"
  strs nm = foldr mappend mempty (map (allStrs nm) decls)

allStrs :: String -> Decl -> Set String
allStrs nm (PatBind _ _ _ (UnGuardedRhs e) _) = case e of
  App (Con (UnQual (Ident x))) (Lit (String s)) | x == nm -> Set.singleton s
  _        -> mempty
allStrs _ _ = mempty