module Language.Haskell.Names.Interfaces
(
NamesDB(..)
, runNamesModuleT
, evalNamesModuleT
, readInterface
, writeInterface
, IfaceException(..)
) where
import Language.Haskell.Names.Types
import Language.Haskell.Exts (ModuleName(ModuleName),prettyPrint,Name)
import Language.Haskell.Names.SyntaxUtils (stringToName,nameToString,annName)
import Language.Haskell.Exts.Annotated.Simplify (sName)
import qualified Data.ByteString.Lazy as BS
import Data.Aeson
import Data.Monoid
import Data.Char
import Data.Typeable
import qualified Data.Map as Map
import Control.Exception
import Control.Applicative
import Control.Monad
import Distribution.HaskellSuite
import qualified Distribution.ModuleName as Cabal
import System.FilePath
import Paths_haskell_names
data IfaceException =
BadInterface FilePath String
deriving (Typeable, Show)
instance Exception IfaceException
readInterface :: FilePath -> IO [Symbol]
readInterface path =
either (throwIO . BadInterface path) return =<<
eitherDecode <$> BS.readFile path
writeInterface :: FilePath -> [Symbol] -> IO ()
writeInterface path iface =
BS.writeFile path $
encode iface `mappend` BS.pack [fromIntegral $ ord '\n']
prettyName :: Name -> String
prettyName = nameToString . annName
instance ToJSON Symbol where
toJSON symbol =
object ([
"entity" .= symbolEntity symbol,
"module" .= prettyPrint (symbolModule symbol),
"name" .= prettyName (symbolName symbol)] ++ additionalInfo symbol)
where
additionalInfo symbol = case symbol of
Method { className = cls } ->
["class" .= prettyName cls]
Selector { typeName = ty, constructors = cons } ->
["type" .= prettyName ty
,"constructors".= map prettyName cons]
Constructor { typeName = ty } ->
["type".= prettyName ty]
_ -> []
symbolEntity :: Symbol -> String
symbolEntity i = case i of
Value {} -> "value"
Method {} -> "method"
Selector {} -> "selector"
Constructor {} -> "constructor"
Type {} -> "type"
Data {} -> "data"
NewType {} -> "newtype"
TypeFam {} -> "typeFamily"
DataFam {} -> "dataFamily"
Class {} -> "class"
parseName :: String -> Name
parseName = sName . stringToName
instance FromJSON Symbol where
parseJSON (Object v) = do
entity <- v .: "entity"
symbolmodule <- ModuleName <$> v .: "module"
symbolname <- parseName <$> v .: "name"
case entity :: String of
"value" -> return $ Value symbolmodule symbolname
"method" -> do
cls <- v .: "class"
return (Method symbolmodule symbolname (parseName cls))
"selector" -> do
typ <- v .: "type"
cons <- v .: "constructors"
return (Selector symbolmodule symbolname (parseName typ) (map parseName cons))
"constructor" -> do
typ <- v .: "type"
return (Constructor symbolmodule symbolname (parseName typ))
"type" -> return $ Type symbolmodule symbolname
"data" -> return $ Data symbolmodule symbolname
"newtype" -> return $ NewType symbolmodule symbolname
"typeFamily" -> return $ TypeFam symbolmodule symbolname
"dataFamily" -> return $ DataFam symbolmodule symbolname
"class" -> return $ Class symbolmodule symbolname
_ -> mzero
parseJSON _ = mzero
newtype NamesDB = NamesDB FilePath
instance IsPackageDB NamesDB where
dbName = return "haskell-names"
readPackageDB init (NamesDB db) =
map (makePkgInfoAbsolute (dropFileName db)) <$> readDB init db
writePackageDB (NamesDB db) = writeDB db
globalDB = Just . NamesDB . (</> "libraries" </> "packages.db") <$> getDataDir
dbFromPath path = return $ NamesDB path
nameFilesExtension :: FilePath
nameFilesExtension = "names"
runNamesModuleT
:: ModuleT [Symbol] IO a
-> Packages
-> Map.Map Cabal.ModuleName [Symbol]
-> IO (a, Map.Map Cabal.ModuleName [Symbol])
runNamesModuleT ma pkgs = runModuleT ma pkgs nameFilesExtension readInterface
evalNamesModuleT
:: ModuleT [Symbol] IO a
-> Packages
-> IO a
evalNamesModuleT ma pkgs = evalModuleT ma pkgs nameFilesExtension readInterface