packages feed

ide-backend 0.9.0.11 → 0.10.0

raw patch · 96 files changed

+5064/−951 lines, 96 filesdep +monads-tfdep +paralleldep ~aesondep ~ide-backend-commonnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: monads-tf, parallel

Dependency ranges changed: aeson, ide-backend-common

API changes (from Hackage documentation)

+ IdeSession: IdeCallbacks :: LogFunc -> IdeCallbacks
+ IdeSession: ProgramSearchPathDefault :: ProgramSearchPathEntry
+ IdeSession: ProgramSearchPathDir :: FilePath -> ProgramSearchPathEntry
+ IdeSession: UpdateStatusCrashRestart :: Text -> UpdateStatus
+ IdeSession: UpdateStatusDone :: UpdateStatus
+ IdeSession: UpdateStatusFailed :: Text -> UpdateStatus
+ IdeSession: UpdateStatusProgress :: Progress -> UpdateStatus
+ IdeSession: UpdateStatusRequiredRestart :: UpdateStatus
+ IdeSession: UpdateStatusServerDied :: Text -> UpdateStatus
+ IdeSession: configIdeBackendExeCabal :: SessionConfig -> (ProgramSearchPath, FilePath)
+ IdeSession: configIdeBackendServer :: SessionConfig -> (ProgramSearchPath, FilePath)
+ IdeSession: configLocalWorkingDir :: SessionConfig -> Maybe FilePath
+ IdeSession: data IdeCallbacks
+ IdeSession: data ProgramSearchPathEntry :: *
+ IdeSession: data UpdateStatus :: *
+ IdeSession: defaultIdeCallbacks :: IdeCallbacks
+ IdeSession: ideCallbacksLogFunc :: IdeCallbacks -> LogFunc
+ IdeSession: initSessionWithCallbacks :: IdeCallbacks -> SessionInitParams -> SessionConfig -> IO IdeSession
+ IdeSession: sessionConfigFromEnv :: IO SessionConfig
+ IdeSession: sessionInitDistDir :: SessionInitParams -> !(Maybe FilePath)
+ IdeSession: type ProgramSearchPath = [ProgramSearchPathEntry]
+ IdeSession.Cabal: BuildExeArgs :: PackageDBStack -> [FilePath] -> FilePath -> FilePath -> FilePath -> FilePath -> [FilePath] -> [String] -> [Dependency] -> [ModuleName] -> BuildExeArgs
+ IdeSession.Cabal: ExeCabalDone :: ExitCode -> ExeCabalResponse
+ IdeSession.Cabal: ExeCabalProgress :: Progress -> ExeCabalResponse
+ IdeSession.Cabal: LicenseArgs :: PackageDBStack -> [FilePath] -> [String] -> FilePath -> FilePath -> FilePath -> [(String, (Maybe License, Maybe FilePath, Maybe String))] -> FilePath -> [PackageId] -> LicenseArgs
+ IdeSession.Cabal: ReqExeBuild :: BuildExeArgs -> [(ModuleName, FilePath)] -> ExeCabalRequest
+ IdeSession.Cabal: ReqExeCc :: RunCcArgs -> ExeCabalRequest
+ IdeSession.Cabal: ReqExeDoc :: BuildExeArgs -> ExeCabalRequest
+ IdeSession.Cabal: ReqExeLic :: LicenseArgs -> ExeCabalRequest
+ IdeSession.Cabal: RunCcArgs :: PackageDBStack -> [FilePath] -> FilePath -> FilePath -> FilePath -> FilePath -> FilePath -> FilePath -> [FilePath] -> [String] -> RunCcArgs
+ IdeSession.Cabal: beDistDir :: BuildExeArgs -> FilePath
+ IdeSession.Cabal: beExtraPathDirs :: BuildExeArgs -> [FilePath]
+ IdeSession.Cabal: beGhcOpts :: BuildExeArgs -> [String]
+ IdeSession.Cabal: beLibDeps :: BuildExeArgs -> [Dependency]
+ IdeSession.Cabal: beLoadedMs :: BuildExeArgs -> [ModuleName]
+ IdeSession.Cabal: bePackageDBStack :: BuildExeArgs -> PackageDBStack
+ IdeSession.Cabal: beRelativeIncludes :: BuildExeArgs -> [FilePath]
+ IdeSession.Cabal: beSourcesDir :: BuildExeArgs -> FilePath
+ IdeSession.Cabal: beStderrLog :: BuildExeArgs -> FilePath
+ IdeSession.Cabal: beStdoutLog :: BuildExeArgs -> FilePath
+ IdeSession.Cabal: buildDeps :: Strict Maybe Computed -> IO ([ModuleName], [PackageId])
+ IdeSession.Cabal: buildDotCabal :: FilePath -> [FilePath] -> [String] -> Computed -> IO (String -> Version -> ByteString)
+ IdeSession.Cabal: buildLicsFromPkgs :: Bool -> LicenseArgs -> IO ExitCode
+ IdeSession.Cabal: configureAndBuild :: BuildExeArgs -> [(ModuleName, FilePath)] -> IO ExitCode
+ IdeSession.Cabal: configureAndHaddock :: BuildExeArgs -> IO ExitCode
+ IdeSession.Cabal: data BuildExeArgs
+ IdeSession.Cabal: data ExeCabalRequest
+ IdeSession.Cabal: data ExeCabalResponse
+ IdeSession.Cabal: data LicenseArgs
+ IdeSession.Cabal: data RunCcArgs
+ IdeSession.Cabal: externalDeps :: Monad m => [PackageId] -> m [Dependency]
+ IdeSession.Cabal: generateMacros :: PackageDBStack -> [FilePath] -> IO String
+ IdeSession.Cabal: instance Binary BuildExeArgs
+ IdeSession.Cabal: instance Binary ExeCabalRequest
+ IdeSession.Cabal: instance Binary ExeCabalResponse
+ IdeSession.Cabal: instance Binary ExitCode
+ IdeSession.Cabal: instance Binary LicenseArgs
+ IdeSession.Cabal: instance Binary RunCcArgs
+ IdeSession.Cabal: instance Typeable ExeCabalRequest
+ IdeSession.Cabal: instance Typeable ExeCabalResponse
+ IdeSession.Cabal: liCabalsDir :: LicenseArgs -> FilePath
+ IdeSession.Cabal: liDistDir :: LicenseArgs -> FilePath
+ IdeSession.Cabal: liExtraPathDirs :: LicenseArgs -> [FilePath]
+ IdeSession.Cabal: liLicenseExc :: LicenseArgs -> [String]
+ IdeSession.Cabal: liPackageDBStack :: LicenseArgs -> PackageDBStack
+ IdeSession.Cabal: liPkgs :: LicenseArgs -> [PackageId]
+ IdeSession.Cabal: liStderrLog :: LicenseArgs -> FilePath
+ IdeSession.Cabal: liStdoutLog :: LicenseArgs -> FilePath
+ IdeSession.Cabal: licenseFixed :: LicenseArgs -> [(String, (Maybe License, Maybe FilePath, Maybe String))]
+ IdeSession.Cabal: rcAbsC :: RunCcArgs -> FilePath
+ IdeSession.Cabal: rcAbsObj :: RunCcArgs -> FilePath
+ IdeSession.Cabal: rcDistDir :: RunCcArgs -> FilePath
+ IdeSession.Cabal: rcExtraPathDirs :: RunCcArgs -> [FilePath]
+ IdeSession.Cabal: rcIncludeDirs :: RunCcArgs -> [FilePath]
+ IdeSession.Cabal: rcOptions :: RunCcArgs -> [String]
+ IdeSession.Cabal: rcPackageDBStack :: RunCcArgs -> PackageDBStack
+ IdeSession.Cabal: rcPref :: RunCcArgs -> FilePath
+ IdeSession.Cabal: rcStderrLog :: RunCcArgs -> FilePath
+ IdeSession.Cabal: rcStdoutLog :: RunCcArgs -> FilePath
+ IdeSession.Cabal: runComponentCc :: RunCcArgs -> IO ExitCode
+ IdeSession.Config: ProgramSearchPathDefault :: ProgramSearchPathEntry
+ IdeSession.Config: ProgramSearchPathDir :: FilePath -> ProgramSearchPathEntry
+ IdeSession.Config: SessionConfig :: FilePath -> Maybe FilePath -> [FilePath] -> InProcess -> Bool -> PackageDBStack -> [String] -> [(String, (Maybe License, Maybe FilePath, Maybe String))] -> (String -> IO ()) -> Bool -> (ProgramSearchPath, FilePath) -> (ProgramSearchPath, FilePath) -> SessionConfig
+ IdeSession.Config: configDeleteTempFiles :: SessionConfig -> Bool
+ IdeSession.Config: configDir :: SessionConfig -> FilePath
+ IdeSession.Config: configExtraPathDirs :: SessionConfig -> [FilePath]
+ IdeSession.Config: configGenerateModInfo :: SessionConfig -> Bool
+ IdeSession.Config: configIdeBackendExeCabal :: SessionConfig -> (ProgramSearchPath, FilePath)
+ IdeSession.Config: configIdeBackendServer :: SessionConfig -> (ProgramSearchPath, FilePath)
+ IdeSession.Config: configInProcess :: SessionConfig -> InProcess
+ IdeSession.Config: configLicenseExc :: SessionConfig -> [String]
+ IdeSession.Config: configLicenseFixed :: SessionConfig -> [(String, (Maybe License, Maybe FilePath, Maybe String))]
+ IdeSession.Config: configLocalWorkingDir :: SessionConfig -> Maybe FilePath
+ IdeSession.Config: configLog :: SessionConfig -> String -> IO ()
+ IdeSession.Config: configPackageDBStack :: SessionConfig -> PackageDBStack
+ IdeSession.Config: data ProgramSearchPathEntry :: *
+ IdeSession.Config: data SessionConfig
+ IdeSession.Config: defaultSessionConfig :: SessionConfig
+ IdeSession.Config: sessionConfigFromEnv :: IO SessionConfig
+ IdeSession.Config: type InProcess = Bool
+ IdeSession.Config: type ProgramSearchPath = [ProgramSearchPathEntry]
+ IdeSession.ExeCabalClient: invokeExeCabal :: IdeStaticInfo -> IdeCallbacks -> ExeCabalRequest -> (UpdateStatus -> IO ()) -> IO ExitCode
+ IdeSession.GHC.Client: InProcess :: RpcConversation -> ThreadId -> GhcServer
+ IdeSession.GHC.Client: OutProcess :: RpcServer -> GhcServer
+ IdeSession.GHC.Client: RunActions :: IO (Either ByteString a) -> IO () -> (ByteString -> IO ()) -> IO () -> RunActions a
+ IdeSession.GHC.Client: data GhcServer
+ IdeSession.GHC.Client: data RunActions a
+ IdeSession.GHC.Client: forceCancel :: RunActions a -> IO ()
+ IdeSession.GHC.Client: forceShutdownGhcServer :: GhcServer -> IO ()
+ IdeSession.GHC.Client: forkGhcServer :: [String] -> [FilePath] -> [String] -> IdeStaticInfo -> IdeCallbacks -> IO (Either ExternalException (GhcServer, GhcVersion))
+ IdeSession.GHC.Client: getGhcExitCode :: GhcServer -> IO (Maybe ExitCode)
+ IdeSession.GHC.Client: interrupt :: RunActions a -> IO ()
+ IdeSession.GHC.Client: rpcBreakpoint :: GhcServer -> ModuleName -> SourceSpan -> Bool -> IO (Maybe Bool)
+ IdeSession.GHC.Client: rpcCompile :: GhcServer -> Bool -> Targets -> (UpdateStatus -> IO ()) -> IO GhcCompileResult
+ IdeSession.GHC.Client: rpcCrash :: GhcServer -> Maybe Int -> IO ()
+ IdeSession.GHC.Client: rpcLoad :: GhcServer -> [FilePath] -> IO (Maybe String)
+ IdeSession.GHC.Client: rpcPrint :: GhcServer -> Name -> Bool -> Bool -> IO VariableEnv
+ IdeSession.GHC.Client: rpcRun :: GhcServer -> RunCmd -> (Maybe RunResult -> IO a) -> IO (RunActions a)
+ IdeSession.GHC.Client: rpcSetArgs :: GhcServer -> [String] -> IO ()
+ IdeSession.GHC.Client: rpcSetEnv :: GhcServer -> [(String, Maybe String)] -> IO ()
+ IdeSession.GHC.Client: rpcSetGhcOpts :: GhcServer -> [String] -> IO ([String], [String])
+ IdeSession.GHC.Client: rpcUnload :: GhcServer -> [FilePath] -> IO ()
+ IdeSession.GHC.Client: runWait :: RunActions a -> IO (Either ByteString a)
+ IdeSession.GHC.Client: runWaitAll :: RunActions a -> IO (ByteString, a)
+ IdeSession.GHC.Client: shutdownGhcServer :: GhcServer -> IO ()
+ IdeSession.GHC.Client: supplyStdin :: RunActions a -> ByteString -> IO ()
+ IdeSession.GHC.Client: type InProcess = Bool
+ IdeSession.Licenses: apache20 :: License
+ IdeSession.Licenses: bsd3 :: String -> String -> License
+ IdeSession.Licenses: gplv2 :: License
+ IdeSession.Licenses: gplv3 :: License
+ IdeSession.Licenses: lgpl2 :: License
+ IdeSession.Licenses: lgpl3 :: License
+ IdeSession.Licenses: type License = String
+ IdeSession.Query: InvalidSessionStateQueries :: InvalidSessionStateQueries
+ IdeSession.Query: ManagedFiles :: [FilePath] -> [FilePath] -> ManagedFiles
+ IdeSession.Query: data InvalidSessionStateQueries
+ IdeSession.Query: data ManagedFiles
+ IdeSession.Query: dataFiles :: ManagedFiles -> [FilePath]
+ IdeSession.Query: dumpAutocompletion :: IdeSession -> IO ()
+ IdeSession.Query: dumpFileMap :: IdeSession -> IO ()
+ IdeSession.Query: dumpIdInfo :: IdeSession -> IO ()
+ IdeSession.Query: getAllDataFiles :: Query [FilePath]
+ IdeSession.Query: getArgs :: Query [String]
+ IdeSession.Query: getAutocompletion :: Query (ModuleName -> String -> [IdInfo])
+ IdeSession.Query: getBreakInfo :: Query (Maybe BreakInfo)
+ IdeSession.Query: getBuildDocStatus :: Query (Maybe ExitCode)
+ IdeSession.Query: getBuildExeStatus :: Query (Maybe ExitCode)
+ IdeSession.Query: getBuildLicensesStatus :: Query (Maybe ExitCode)
+ IdeSession.Query: getCabalMacros :: Query ByteString
+ IdeSession.Query: getCodeGeneration :: Query Bool
+ IdeSession.Query: getDataDir :: Query FilePath
+ IdeSession.Query: getDataFile :: FilePath -> Query ByteString
+ IdeSession.Query: getDistDir :: Query FilePath
+ IdeSession.Query: getDotCabal :: Query (String -> Version -> ByteString)
+ IdeSession.Query: getEnv :: Query [(String, Maybe String)]
+ IdeSession.Query: getExpTypes :: Query (ModuleName -> SourceSpan -> [(SourceSpan, Text)])
+ IdeSession.Query: getFileMap :: Query (FilePath -> Maybe ModuleId)
+ IdeSession.Query: getGhcServer :: Query GhcServer
+ IdeSession.Query: getGhcVersion :: Query GhcVersion
+ IdeSession.Query: getImports :: Query (ModuleName -> Maybe [Import])
+ IdeSession.Query: getLoadedModules :: Query [ModuleName]
+ IdeSession.Query: getManagedFiles :: Query ManagedFiles
+ IdeSession.Query: getPkgDeps :: Query (ModuleName -> Maybe [PackageId])
+ IdeSession.Query: getSessionConfig :: Query SessionConfig
+ IdeSession.Query: getSourceErrors :: Query [SourceError]
+ IdeSession.Query: getSourceModule :: FilePath -> Query ByteString
+ IdeSession.Query: getSourcesDir :: Query FilePath
+ IdeSession.Query: getSpanInfo :: Query (ModuleName -> SourceSpan -> [(SourceSpan, SpanInfo)])
+ IdeSession.Query: getUseSites :: Query (ModuleName -> SourceSpan -> [SourceSpan])
+ IdeSession.Query: instance Exception InvalidSessionStateQueries
+ IdeSession.Query: instance Show InvalidSessionStateQueries
+ IdeSession.Query: instance Show ManagedFiles
+ IdeSession.Query: instance Typeable InvalidSessionStateQueries
+ IdeSession.Query: sourceFiles :: ManagedFiles -> [FilePath]
+ IdeSession.Query: type Query a = IdeSession -> IO a
+ IdeSession.RPC.Client: ExternalException :: String -> Maybe IOException -> ExternalException
+ IdeSession.RPC.Client: RpcConversation :: (forall a. (Typeable * a, Binary a) => IO a) -> (forall a. (Typeable * a, Binary a) => a -> IO ()) -> RpcConversation
+ IdeSession.RPC.Client: connectToRpcServer :: FilePath -> FilePath -> FilePath -> (RpcServer -> IO a) -> IO a
+ IdeSession.RPC.Client: data ExternalException :: *
+ IdeSession.RPC.Client: data RpcConversation :: *
+ IdeSession.RPC.Client: data RpcServer
+ IdeSession.RPC.Client: externalException :: ExternalException -> Maybe IOException
+ IdeSession.RPC.Client: externalStdErr :: ExternalException -> String
+ IdeSession.RPC.Client: findProgram :: LogFunc -> ProgramSearchPath -> FilePath -> IO (Maybe FilePath)
+ IdeSession.RPC.Client: forceShutdown :: RpcServer -> IO ()
+ IdeSession.RPC.Client: forkRpcServer :: FilePath -> [String] -> Maybe FilePath -> Maybe [(String, String)] -> IO RpcServer
+ IdeSession.RPC.Client: get :: RpcConversation -> forall a. (Typeable * a, Binary a) => IO a
+ IdeSession.RPC.Client: getRpcExitCode :: RpcServer -> IO (Maybe ExitCode)
+ IdeSession.RPC.Client: illscopedConversationException :: IOException
+ IdeSession.RPC.Client: put :: RpcConversation -> forall a. (Typeable * a, Binary a) => a -> IO ()
+ IdeSession.RPC.Client: rpc :: (Typeable req, Typeable resp, Binary req, Binary resp) => RpcServer -> req -> IO resp
+ IdeSession.RPC.Client: rpcConversation :: RpcServer -> (RpcConversation -> IO a) -> IO a
+ IdeSession.RPC.Client: serverKilledException :: Maybe IOException -> ExternalException
+ IdeSession.RPC.Client: shutdown :: RpcServer -> IO ()
+ IdeSession.State: Computed :: !(Strict [] SourceError) -> !(Strict [] ModuleName) -> !(Strict (Map FilePath) ModuleId) -> !(Strict (Map ModuleName) (Strict [] Import)) -> !(Strict (Map ModuleName) (Strict Trie (Strict [] IdInfo))) -> !(Strict (Map ModuleName) IdMap) -> !(Strict (Map ModuleName) ExpMap) -> !(Strict (Map ModuleName) UseSites) -> !(Strict (Map ModuleName) (Strict [] PackageId)) -> !ExplicitSharingCache -> Computed
+ IdeSession.State: IdeCallbacks :: LogFunc -> IdeCallbacks
+ IdeSession.State: IdeIdleState :: !LogicalTimestamp -> !(Strict Maybe Computed) -> ![String] -> ![FilePath] -> !Bool -> !ManagedFilesInternal -> !ObjectFiles -> !(Maybe ExitCode) -> !(Maybe ExitCode) -> !(Maybe ExitCode) -> ![(String, Maybe String)] -> ![String] -> GhcServer -> GhcVersion -> !RunBufferMode -> !RunBufferMode -> !(Strict Maybe BreakInfo) -> !Targets -> [String] -> IdeIdleState
+ IdeSession.State: IdeSession :: IdeStaticInfo -> StrictMVar IdeSessionState -> IdeCallbacks -> IdeSession
+ IdeSession.State: IdeSessionIdle :: IdeIdleState -> IdeSessionState
+ IdeSession.State: IdeSessionServerDied :: ExternalException -> IdeIdleState -> IdeSessionState
+ IdeSession.State: IdeSessionShutdown :: IdeSessionState
+ IdeSession.State: IdeStaticInfo :: !SessionConfig -> !FilePath -> !FilePath -> IdeStaticInfo
+ IdeSession.State: InProcess :: RpcConversation -> ThreadId -> GhcServer
+ IdeSession.State: ManagedFilesInternal :: [ManagedFile] -> [ManagedFile] -> ManagedFilesInternal
+ IdeSession.State: OutProcess :: RpcServer -> GhcServer
+ IdeSession.State: RunActions :: IO (Either ByteString a) -> IO () -> (ByteString -> IO ()) -> IO () -> RunActions a
+ IdeSession.State: _ideArgs :: IdeIdleState -> ![String]
+ IdeSession.State: _ideBreakInfo :: IdeIdleState -> !(Strict Maybe BreakInfo)
+ IdeSession.State: _ideBuildDocStatus :: IdeIdleState -> !(Maybe ExitCode)
+ IdeSession.State: _ideBuildExeStatus :: IdeIdleState -> !(Maybe ExitCode)
+ IdeSession.State: _ideBuildLicensesStatus :: IdeIdleState -> !(Maybe ExitCode)
+ IdeSession.State: _ideComputed :: IdeIdleState -> !(Strict Maybe Computed)
+ IdeSession.State: _ideEnv :: IdeIdleState -> ![(String, Maybe String)]
+ IdeSession.State: _ideGenerateCode :: IdeIdleState -> !Bool
+ IdeSession.State: _ideGhcOpts :: IdeIdleState -> ![String]
+ IdeSession.State: _ideGhcServer :: IdeIdleState -> GhcServer
+ IdeSession.State: _ideGhcVersion :: IdeIdleState -> GhcVersion
+ IdeSession.State: _ideLogicalTimestamp :: IdeIdleState -> !LogicalTimestamp
+ IdeSession.State: _ideManagedFiles :: IdeIdleState -> !ManagedFilesInternal
+ IdeSession.State: _ideObjectFiles :: IdeIdleState -> !ObjectFiles
+ IdeSession.State: _ideRelativeIncludes :: IdeIdleState -> ![FilePath]
+ IdeSession.State: _ideRtsOpts :: IdeIdleState -> [String]
+ IdeSession.State: _ideStderrBufferMode :: IdeIdleState -> !RunBufferMode
+ IdeSession.State: _ideStdoutBufferMode :: IdeIdleState -> !RunBufferMode
+ IdeSession.State: _ideTargets :: IdeIdleState -> !Targets
+ IdeSession.State: _managedData :: ManagedFilesInternal -> [ManagedFile]
+ IdeSession.State: _managedSource :: ManagedFilesInternal -> [ManagedFile]
+ IdeSession.State: computedAutoMap :: Computed -> !(Strict (Map ModuleName) (Strict Trie (Strict [] IdInfo)))
+ IdeSession.State: computedCache :: Computed -> !ExplicitSharingCache
+ IdeSession.State: computedErrors :: Computed -> !(Strict [] SourceError)
+ IdeSession.State: computedExpTypes :: Computed -> !(Strict (Map ModuleName) ExpMap)
+ IdeSession.State: computedFileMap :: Computed -> !(Strict (Map FilePath) ModuleId)
+ IdeSession.State: computedImports :: Computed -> !(Strict (Map ModuleName) (Strict [] Import))
+ IdeSession.State: computedLoadedModules :: Computed -> !(Strict [] ModuleName)
+ IdeSession.State: computedPkgDeps :: Computed -> !(Strict (Map ModuleName) (Strict [] PackageId))
+ IdeSession.State: computedSpanInfo :: Computed -> !(Strict (Map ModuleName) IdMap)
+ IdeSession.State: computedUseSites :: Computed -> !(Strict (Map ModuleName) UseSites)
+ IdeSession.State: data Computed
+ IdeSession.State: data GhcServer
+ IdeSession.State: data IdeCallbacks
+ IdeSession.State: data IdeIdleState
+ IdeSession.State: data IdeSession
+ IdeSession.State: data IdeSessionState
+ IdeSession.State: data IdeStaticInfo
+ IdeSession.State: data ManagedFilesInternal
+ IdeSession.State: data RunActions a
+ IdeSession.State: defaultIdeCallbacks :: IdeCallbacks
+ IdeSession.State: forceCancel :: RunActions a -> IO ()
+ IdeSession.State: ideArgs :: Accessor IdeIdleState [String]
+ IdeSession.State: ideBreakInfo :: Accessor IdeIdleState (Strict Maybe BreakInfo)
+ IdeSession.State: ideBuildDocStatus :: Accessor IdeIdleState (Maybe ExitCode)
+ IdeSession.State: ideBuildExeStatus :: Accessor IdeIdleState (Maybe ExitCode)
+ IdeSession.State: ideBuildLicensesStatus :: Accessor IdeIdleState (Maybe ExitCode)
+ IdeSession.State: ideCallbacks :: IdeSession -> IdeCallbacks
+ IdeSession.State: ideCallbacksLogFunc :: IdeCallbacks -> LogFunc
+ IdeSession.State: ideComputed :: Accessor IdeIdleState (Strict Maybe Computed)
+ IdeSession.State: ideConfig :: IdeStaticInfo -> !SessionConfig
+ IdeSession.State: ideDataDir :: IdeStaticInfo -> FilePath
+ IdeSession.State: ideDistDir :: IdeStaticInfo -> !FilePath
+ IdeSession.State: ideEnv :: Accessor IdeIdleState [(String, Maybe String)]
+ IdeSession.State: ideGenerateCode :: Accessor IdeIdleState Bool
+ IdeSession.State: ideGhcOpts :: Accessor IdeIdleState [String]
+ IdeSession.State: ideGhcServer :: Accessor IdeIdleState GhcServer
+ IdeSession.State: ideGhcVersion :: Accessor IdeIdleState GhcVersion
+ IdeSession.State: ideLogFunc :: IdeSession -> LogFunc
+ IdeSession.State: ideLogicalTimestamp :: Accessor IdeIdleState LogicalTimestamp
+ IdeSession.State: ideManagedFiles :: Accessor IdeIdleState ManagedFilesInternal
+ IdeSession.State: ideObjectFiles :: Accessor IdeIdleState ObjectFiles
+ IdeSession.State: ideRelativeIncludes :: Accessor IdeIdleState [FilePath]
+ IdeSession.State: ideRtsOpts :: Accessor IdeIdleState [String]
+ IdeSession.State: ideSessionDir :: IdeStaticInfo -> !FilePath
+ IdeSession.State: ideSourceDir :: IdeStaticInfo -> FilePath
+ IdeSession.State: ideState :: IdeSession -> StrictMVar IdeSessionState
+ IdeSession.State: ideStaticInfo :: IdeSession -> IdeStaticInfo
+ IdeSession.State: ideStderrBufferMode :: Accessor IdeIdleState RunBufferMode
+ IdeSession.State: ideStdoutBufferMode :: Accessor IdeIdleState RunBufferMode
+ IdeSession.State: ideTargets :: Accessor IdeIdleState Targets
+ IdeSession.State: instance Show Computed
+ IdeSession.State: interrupt :: RunActions a -> IO ()
+ IdeSession.State: managedData :: Accessor ManagedFilesInternal [ManagedFile]
+ IdeSession.State: managedSource :: Accessor ManagedFilesInternal [ManagedFile]
+ IdeSession.State: runWait :: RunActions a -> IO (Either ByteString a)
+ IdeSession.State: supplyStdin :: RunActions a -> ByteString -> IO ()
+ IdeSession.State: type LogicalTimestamp = EpochTime
+ IdeSession.State: type ManagedFile = (FilePath, (MD5Digest, LogicalTimestamp))
+ IdeSession.Update: LicenseArgs :: PackageDBStack -> [FilePath] -> [String] -> FilePath -> FilePath -> FilePath -> [(String, (Maybe License, Maybe FilePath, Maybe String))] -> FilePath -> [PackageId] -> LicenseArgs
+ IdeSession.Update: SessionInitParams :: Maybe ByteString -> [String] -> [FilePath] -> Targets -> [String] -> !(Maybe FilePath) -> SessionInitParams
+ IdeSession.Update: buildDoc :: IdeSessionUpdate
+ IdeSession.Update: buildExe :: [String] -> [(ModuleName, FilePath)] -> IdeSessionUpdate
+ IdeSession.Update: buildLicenses :: FilePath -> IdeSessionUpdate
+ IdeSession.Update: buildLicsFromPkgs :: Bool -> LicenseArgs -> IO ExitCode
+ IdeSession.Update: crashGhcServer :: IdeSession -> Maybe Int -> IO ()
+ IdeSession.Update: data IdeSessionUpdate
+ IdeSession.Update: data LicenseArgs
+ IdeSession.Update: data SessionInitParams
+ IdeSession.Update: defaultSessionInitParams :: SessionInitParams
+ IdeSession.Update: forceShutdownSession :: IdeSession -> IO ()
+ IdeSession.Update: initSession :: SessionInitParams -> SessionConfig -> IO IdeSession
+ IdeSession.Update: initSessionWithCallbacks :: IdeCallbacks -> SessionInitParams -> SessionConfig -> IO IdeSession
+ IdeSession.Update: instance Show SessionInitParams
+ IdeSession.Update: liCabalsDir :: LicenseArgs -> FilePath
+ IdeSession.Update: liDistDir :: LicenseArgs -> FilePath
+ IdeSession.Update: liExtraPathDirs :: LicenseArgs -> [FilePath]
+ IdeSession.Update: liLicenseExc :: LicenseArgs -> [String]
+ IdeSession.Update: liPackageDBStack :: LicenseArgs -> PackageDBStack
+ IdeSession.Update: liPkgs :: LicenseArgs -> [PackageId]
+ IdeSession.Update: liStderrLog :: LicenseArgs -> FilePath
+ IdeSession.Update: liStdoutLog :: LicenseArgs -> FilePath
+ IdeSession.Update: licenseFixed :: LicenseArgs -> [(String, (Maybe License, Maybe FilePath, Maybe String))]
+ IdeSession.Update: printVar :: IdeSession -> Name -> Bool -> Bool -> IO VariableEnv
+ IdeSession.Update: restartSession :: IdeSession -> IO ()
+ IdeSession.Update: resume :: IdeSession -> IO (RunActions RunResult)
+ IdeSession.Update: runExe :: IdeSession -> String -> IO (RunActions ExitCode)
+ IdeSession.Update: runStmt :: IdeSession -> String -> String -> IO (RunActions RunResult)
+ IdeSession.Update: runStmtPty :: IdeSession -> String -> String -> IO (RunActions RunResult)
+ IdeSession.Update: sessionInitCabalMacros :: SessionInitParams -> Maybe ByteString
+ IdeSession.Update: sessionInitDistDir :: SessionInitParams -> !(Maybe FilePath)
+ IdeSession.Update: sessionInitGhcOptions :: SessionInitParams -> [String]
+ IdeSession.Update: sessionInitRelativeIncludes :: SessionInitParams -> [FilePath]
+ IdeSession.Update: sessionInitRtsOpts :: SessionInitParams -> [String]
+ IdeSession.Update: sessionInitTargets :: SessionInitParams -> Targets
+ IdeSession.Update: setBreakpoint :: IdeSession -> ModuleName -> SourceSpan -> Bool -> IO (Maybe Bool)
+ IdeSession.Update: shutdownSession :: IdeSession -> IO ()
+ IdeSession.Update: updateArgs :: [String] -> IdeSessionUpdate
+ IdeSession.Update: updateCodeGeneration :: Bool -> IdeSessionUpdate
+ IdeSession.Update: updateDataFile :: FilePath -> ByteString -> IdeSessionUpdate
+ IdeSession.Update: updateDataFileDelete :: FilePath -> IdeSessionUpdate
+ IdeSession.Update: updateDataFileFromFile :: FilePath -> FilePath -> IdeSessionUpdate
+ IdeSession.Update: updateDeleteManagedFiles :: IdeSessionUpdate
+ IdeSession.Update: updateEnv :: [(String, Maybe String)] -> IdeSessionUpdate
+ IdeSession.Update: updateGhcOpts :: [String] -> IdeSessionUpdate
+ IdeSession.Update: updateRelativeIncludes :: [FilePath] -> IdeSessionUpdate
+ IdeSession.Update: updateRtsOpts :: [String] -> IdeSessionUpdate
+ IdeSession.Update: updateSession :: IdeSession -> IdeSessionUpdate -> (UpdateStatus -> IO ()) -> IO ()
+ IdeSession.Update: updateSourceFile :: FilePath -> ByteString -> IdeSessionUpdate
+ IdeSession.Update: updateSourceFileDelete :: FilePath -> IdeSessionUpdate
+ IdeSession.Update: updateSourceFileFromFile :: FilePath -> IdeSessionUpdate
+ IdeSession.Update: updateStderrBufferMode :: RunBufferMode -> IdeSessionUpdate
+ IdeSession.Update: updateStdoutBufferMode :: RunBufferMode -> IdeSessionUpdate
+ IdeSession.Update: updateTargets :: Targets -> IdeSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: instance (Dummy a, Dummy b) => Dummy (a, b)
+ IdeSession.Update.ExecuteSessionUpdate: instance Applicative ExecuteSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy ()
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy (Maybe a)
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy (Strict (Map k) a)
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy (Strict IntMap a)
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy (Strict [] a)
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy ExplicitSharingCache
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy GhcCompileResult
+ IdeSession.Update.ExecuteSessionUpdate: instance Dummy [a]
+ IdeSession.Update.ExecuteSessionUpdate: instance Functor ExecuteSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: instance Monad ExecuteSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: instance MonadIO ExecuteSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: instance MonadReader IdeSessionUpdateEnv ExecuteSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: instance MonadState IdeIdleState ExecuteSessionUpdate
+ IdeSession.Update.ExecuteSessionUpdate: runSessionUpdate :: Bool -> IdeSessionUpdate -> IdeStaticInfo -> (UpdateStatus -> IO ()) -> IdeCallbacks -> IdeIdleState -> IO (IdeIdleState, Maybe ExternalException)
+ IdeSession.Update.IdeSessionUpdate: FileCopy :: FileInfo -> FilePath -> FileCmd
+ IdeSession.Update.IdeSessionUpdate: FileDelete :: FileInfo -> FileCmd
+ IdeSession.Update.IdeSessionUpdate: FileInfo :: (IdeStaticInfo -> FilePath) -> FilePath -> Accessor ManagedFilesInternal [ManagedFile] -> FileInfo
+ IdeSession.Update.IdeSessionUpdate: FileWrite :: FileInfo -> ByteString -> FileCmd
+ IdeSession.Update.IdeSessionUpdate: IdeSessionUpdate :: [FileCmd] -> Bool -> Maybe [String] -> Maybe [FilePath] -> Maybe Bool -> Maybe [(String, Maybe String)] -> Maybe [String] -> Maybe RunBufferMode -> Maybe RunBufferMode -> Maybe Targets -> [([String], [(ModuleName, FilePath)])] -> Bool -> [FilePath] -> Maybe [String] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: buildDoc :: IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: buildExe :: [String] -> [(ModuleName, FilePath)] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: buildLicenses :: FilePath -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: data FileCmd
+ IdeSession.Update.IdeSessionUpdate: data FileInfo
+ IdeSession.Update.IdeSessionUpdate: data IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: fileInfoAccessor :: FileInfo -> Accessor ManagedFilesInternal [ManagedFile]
+ IdeSession.Update.IdeSessionUpdate: fileInfoRemoteDir :: FileInfo -> IdeStaticInfo -> FilePath
+ IdeSession.Update.IdeSessionUpdate: fileInfoRemoteFile :: FileInfo -> FilePath
+ IdeSession.Update.IdeSessionUpdate: ideUpdateArgs :: IdeSessionUpdate -> Maybe [String]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateCodeGen :: IdeSessionUpdate -> Maybe Bool
+ IdeSession.Update.IdeSessionUpdate: ideUpdateDeleteFiles :: IdeSessionUpdate -> Bool
+ IdeSession.Update.IdeSessionUpdate: ideUpdateDocs :: IdeSessionUpdate -> Bool
+ IdeSession.Update.IdeSessionUpdate: ideUpdateEnv :: IdeSessionUpdate -> Maybe [(String, Maybe String)]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateExes :: IdeSessionUpdate -> [([String], [(ModuleName, FilePath)])]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateFileCmds :: IdeSessionUpdate -> [FileCmd]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateGhcOpts :: IdeSessionUpdate -> Maybe [String]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateLicenses :: IdeSessionUpdate -> [FilePath]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateRelIncls :: IdeSessionUpdate -> Maybe [FilePath]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateRtsOpts :: IdeSessionUpdate -> Maybe [String]
+ IdeSession.Update.IdeSessionUpdate: ideUpdateStderrMode :: IdeSessionUpdate -> Maybe RunBufferMode
+ IdeSession.Update.IdeSessionUpdate: ideUpdateStdoutMode :: IdeSessionUpdate -> Maybe RunBufferMode
+ IdeSession.Update.IdeSessionUpdate: ideUpdateTargets :: IdeSessionUpdate -> Maybe Targets
+ IdeSession.Update.IdeSessionUpdate: instance Monoid IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: instance Show FileCmd
+ IdeSession.Update.IdeSessionUpdate: instance Show FileInfo
+ IdeSession.Update.IdeSessionUpdate: instance Show IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateArgs :: [String] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateCodeGeneration :: Bool -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateDataFile :: FilePath -> ByteString -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateDataFileDelete :: FilePath -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateDataFileFromFile :: FilePath -> FilePath -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateDeleteManagedFiles :: IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateEnv :: [(String, Maybe String)] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateGhcOpts :: [String] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateRelativeIncludes :: [FilePath] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateRtsOpts :: [String] -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateSourceFile :: FilePath -> ByteString -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateSourceFileDelete :: FilePath -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateSourceFileFromFile :: FilePath -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateStderrBufferMode :: RunBufferMode -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateStdoutBufferMode :: RunBufferMode -> IdeSessionUpdate
+ IdeSession.Update.IdeSessionUpdate: updateTargets :: Targets -> IdeSessionUpdate
- IdeSession: SessionConfig :: FilePath -> [FilePath] -> InProcess -> Bool -> PackageDBStack -> [String] -> [(String, (Maybe License, Maybe FilePath, Maybe String))] -> (String -> IO ()) -> Bool -> SessionConfig
+ IdeSession: SessionConfig :: FilePath -> Maybe FilePath -> [FilePath] -> InProcess -> Bool -> PackageDBStack -> [String] -> [(String, (Maybe License, Maybe FilePath, Maybe String))] -> (String -> IO ()) -> Bool -> (ProgramSearchPath, FilePath) -> (ProgramSearchPath, FilePath) -> SessionConfig
- IdeSession: SessionInitParams :: Maybe ByteString -> [String] -> [FilePath] -> Targets -> [String] -> SessionInitParams
+ IdeSession: SessionInitParams :: Maybe ByteString -> [String] -> [FilePath] -> Targets -> [String] -> !(Maybe FilePath) -> SessionInitParams
- IdeSession: updateSession :: IdeSession -> IdeSessionUpdate -> (Progress -> IO ()) -> IO ()
+ IdeSession: updateSession :: IdeSession -> IdeSessionUpdate -> (UpdateStatus -> IO ()) -> IO ()

Files

IdeSession.hs view
@@ -102,14 +102,20 @@ module IdeSession (     -- * Configuration     SessionConfig(..)+  , sessionConfigFromEnv   , defaultSessionConfig   , InProcess+  , ProgramSearchPath+  , ProgramSearchPathEntry(..)     -- * Updating the session     -- ** Starting and stopping   , IdeSession -- Abstract   , initSession+  , initSessionWithCallbacks   , SessionInitParams(..)   , defaultSessionInitParams+  , IdeCallbacks(..)+  , defaultIdeCallbacks   , shutdownSession   , forceShutdownSession   , restartSession@@ -137,6 +143,7 @@   , buildLicenses     -- ** Progress   , Progress(..)+  , UpdateStatus(..)     -- ** Running code   , RunActions(..)   , RunResult(..)@@ -233,7 +240,7 @@ import IdeSession.GHC.Client import IdeSession.Query import IdeSession.RPC.Client (ExternalException (..))-import IdeSession.State (IdeSession)+import IdeSession.State (IdeSession, IdeCallbacks(..), defaultIdeCallbacks) import IdeSession.Types.Progress import IdeSession.Types.Public import IdeSession.Update
IdeSession/Config.hs view
@@ -1,11 +1,17 @@ module IdeSession.Config (     SessionConfig(..)   , InProcess+  , ProgramSearchPath, ProgramSearchPathEntry(..)+  , sessionConfigFromEnv   , defaultSessionConfig   ) where  import Distribution.License (License (..)) import Distribution.Simple (PackageDB (..), PackageDBStack)+import Distribution.Simple.Program.Find (ProgramSearchPath,ProgramSearchPathEntry(..),defaultProgramSearchPath)+import System.FilePath (splitSearchPath)+import System.Directory (getCurrentDirectory, getTemporaryDirectory)+import System.Environment (lookupEnv)  type InProcess = Bool @@ -15,6 +21,18 @@ data SessionConfig = SessionConfig {     -- | The directory to use for all session files.     configDir        :: FilePath+    -- | When set to Just "<filepath>", we'll use the files in that+    -- directory as source and datafiles.  This means that the+    -- ide-backend is no longer directly managing the files, and+    -- file updates like 'updateSourceFile' will fail.+    --+    -- Note that this feature is experimental and does not have a+    -- suite of tests.+    --+    -- Since this is likely used with an existing cabal project, which+    -- might have multiple source directories, you'll likely want to+    -- use 'TargetsInclude' instead of 'TargetsExclude'.+  , configLocalWorkingDir :: Maybe FilePath     -- | Extra directories in which to look for programs, including ghc     -- and other tools. Note that the @$PATH@ is still searched /first/, these     -- directories are extra.@@ -41,15 +59,52 @@     -- | Delete temporary files when session finishes?     -- (Defaults to True; mostly for internal debugging purposes)   , configDeleteTempFiles :: Bool+    -- | The name of the ide-backend-server program to use, and where to find it.+    --   The default is @(defaultProgramSearchPath,"ide-backend-server")@,+    --   that is, to look for a program called ide-backend-server on the system+    --   search path only.+  , configIdeBackendServer :: (ProgramSearchPath,FilePath)+    -- | The name of the ide-backend-exe-cabal program to use, and where to find it.+    --   The default is @(defaultProgramSearchPath,"ide-backend-exe-cabal")@.+  , configIdeBackendExeCabal :: (ProgramSearchPath,FilePath)   } --- | Default session configuration+-- Get the default local session configuration, pulling the following+-- information from the environment: ----- Use this instead of creating your own SessionConfig to be robust against--- extensions of SessionConfig.+-- * OS temporary directory (used for session.*) files --+-- * Current working directory - assumed to be the project root.+--   Instead of running+--+-- * GHC package database.  Like GHC, it takes the GHC_PACKAGE_PATH,+--   and uses this list of package databases.  This allows ide-backend+--   to do the 'right thing' when used with tools like stack.+sessionConfigFromEnv :: IO SessionConfig+sessionConfigFromEnv = do+  tmpDir <- getTemporaryDirectory+  cwd <- getCurrentDirectory+  mpkgPath <- lookupEnv "GHC_PACKAGE_PATH"+  let dbStack = case mpkgPath of+        Nothing -> configPackageDBStack defaultSessionConfig+        Just pkgPath ->+          let dbPaths = drop 1 (reverse (splitSearchPath pkgPath))+           in GlobalPackageDB : map SpecificPackageDB dbPaths+  return defaultSessionConfig+    { configDir = tmpDir+    , configLocalWorkingDir = Just cwd+    , configPackageDBStack = dbStack+    }++-- | Default session configuration.  Most users will probably instead+-- want 'localSessionConfigFromEnv'.+--+-- Use this instead of creating your own SessionConfig to be robust+-- against extensions of SessionConfig.+-- -- > defaultSessionConfig = SessionConfig { -- >     configDir              = "."+-- >   , configLocalWorkingDir  = Nothing -- >   , configExtraPathDirs    = [] -- >   , configInProcess        = False -- >   , configGenerateModInfo  = True@@ -65,10 +120,13 @@ -- >       ] -- >   , configLog              = const $ return () -- >   , configDeleteTempFiles  = True+-- >   , configIdeBackendServer = (defaultProgramSearchPath,"ide-backend-server")+-- >   , configIdeBackendExeCabal = (defaultProgramSearchPath,"ide-backend-exe-cabal") -- >   } defaultSessionConfig :: SessionConfig defaultSessionConfig = SessionConfig {     configDir              = "."+  , configLocalWorkingDir  = Nothing   , configExtraPathDirs    = []   , configInProcess        = False   , configGenerateModInfo  = True@@ -84,4 +142,6 @@       ]   , configLog              = const $ return ()   , configDeleteTempFiles  = True+  , configIdeBackendServer = (defaultProgramSearchPath,"ide-backend-server")+  , configIdeBackendExeCabal = (defaultProgramSearchPath,"ide-backend-exe-cabal")   }
IdeSession/ExeCabalClient.hs view
@@ -1,33 +1,30 @@-{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, TupleSections #-}+{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, TupleSections, OverloadedStrings #-} -- | Invoke the executable that calls cabal functions and communicate -- with it via RPC. module IdeSession.ExeCabalClient (     invokeExeCabal   ) where -import System.Exit (ExitCode)--import Distribution.Verbosity (normal)-import Distribution.Simple.Program.Find (-    ProgramSearchPath-  , findProgramOnSearchPath-  , ProgramSearchPathEntry(..)-  )+import Data.Monoid ((<>))+import qualified Data.Text as Text+import System.Exit (ExitCode(..))  import IdeSession.Cabal import IdeSession.Config import IdeSession.GHC.API-import IdeSession.RPC.Client (RpcServer, RpcConversation(..), forkRpcServer, rpcConversation, shutdown)+import IdeSession.RPC.Client (RpcServer, RpcConversation(..), forkRpcServer, rpcConversation, shutdown, findProgram) import IdeSession.State import IdeSession.Types.Progress+import IdeSession.Types.Public (UpdateStatus(..)) import IdeSession.Util  -- | Invoke the executable that processes our custom functions that use -- the machinery of the cabal library.-invokeExeCabal :: IdeStaticInfo -> ExeCabalRequest -> (Progress -> IO ())+invokeExeCabal :: IdeStaticInfo -> IdeCallbacks -> ExeCabalRequest -> (UpdateStatus -> IO ())                -> IO ExitCode-invokeExeCabal IdeStaticInfo{..} args callback = do-  mLoc <- findProgramOnSearchPath normal searchPath "ide-backend-exe-cabal"+invokeExeCabal ideStaticInfo@IdeStaticInfo{..} ideCallbacks args callback = do+  let logFunc = ideCallbacksLogFunc ideCallbacks+  mLoc <- findProgram logFunc searchPath ide_backend_exe_cabal   case mLoc of     Nothing ->       fail $ "Could not find ide-backend-exe-cabal"@@ -35,19 +32,17 @@       env <- envWithPathOverride configExtraPathDirs       let cwd = case args of             ReqExeDoc{} -> ideSessionDir-            _ -> ideSessionDataDir ideSessionDir+            _ -> ideDataDir ideStaticInfo       server <- forkRpcServer prog [] (Just cwd) env       exitCode <- rpcRunExeCabal server args callback       shutdown server  -- not long-running       return exitCode   where-    searchPath :: ProgramSearchPath-    searchPath = ProgramSearchPathDefault-               : map ProgramSearchPathDir configExtraPathDirs+    (searchPath,ide_backend_exe_cabal) = configIdeBackendExeCabal      SessionConfig{..} = ideConfig -rpcRunExeCabal :: RpcServer -> ExeCabalRequest -> (Progress -> IO ())+rpcRunExeCabal :: RpcServer -> ExeCabalRequest -> (UpdateStatus -> IO ())                -> IO ExitCode rpcRunExeCabal server req callback =   rpcConversation server $ \RpcConversation{..} -> do@@ -55,7 +50,15 @@      let go = do response <- get                 case response of-                  ExeCabalProgress pcounter -> callback pcounter >> go-                  ExeCabalDone exitCode     -> return exitCode+                  ExeCabalProgress pcounter -> do+                    callback (UpdateStatusProgress pcounter)+                    go+                  ExeCabalDone ec@ExitSuccess -> do+                    callback UpdateStatusDone+                    return ec+                  ExeCabalDone ec@(ExitFailure code) -> do+                    callback $ UpdateStatusFailed $+                      "Cabal exited with code " <> Text.pack (show code)+                    return ec      go
IdeSession/GHC/Client.hs view
@@ -50,13 +50,7 @@ import IdeSession.Util.BlockingOps import qualified IdeSession.Types.Public as Public -import Distribution.Verbosity (normal) import Distribution.Simple (PackageDB(..), PackageDBStack)-import Distribution.Simple.Program.Find ( -- From our patched cabal-    ProgramSearchPath-  , findProgramOnSearchPath-  , ProgramSearchPathEntry(..)-  )  {------------------------------------------------------------------------------   Starting and stopping the server@@ -67,12 +61,13 @@               -> [FilePath]    -- ^ Relative includes               -> [String]      -- ^ RTS options               -> IdeStaticInfo -- ^ Session setup info+              -> IdeCallbacks  -- ^ Session callbacks               -> IO (Either ExternalException (GhcServer, GhcVersion))-forkGhcServer ghcOpts relIncls rtsOpts IdeStaticInfo{ideConfig, ideSessionDir} = do+forkGhcServer ghcOpts relIncls rtsOpts ideStaticInfo ideCallbacks = do+  let logFunc = ideCallbacksLogFunc ideCallbacks   when configInProcess $     fail "In-process ghc server not currently supported"--  mLoc <- findProgramOnSearchPath normal searchPath "ide-backend-server"+  mLoc <- findProgram logFunc searchPath ide_backend_server   case mLoc of     Nothing ->       fail $ "Could not find ide-backend-server"@@ -81,7 +76,7 @@       server  <- OutProcess <$> forkRpcServer                    prog                    (["+RTS"] ++ rtsOpts ++ ["-RTS"])-                   (Just (ideSessionDataDir ideSessionDir))+                   (Just $ ideDataDir ideStaticInfo)                    env       version <- Ex.try $ do         GhcInitResponse{..} <- rpcInit server GhcInitRequest {@@ -90,7 +85,9 @@           , ghcInitOpts               = opts           , ghcInitUserPackageDB      = userDB           , ghcInitSpecificPackageDBs = specificDBs-          , ghcInitSessionDir         = ideSessionDir+          , ghcInitSourceDir          = ideSourceDir ideStaticInfo+          , ghcInitSessionDir         = ideSessionDir ideStaticInfo+          , ghcInitDistDir            = ideDistDir ideStaticInfo           }         return ghcInitVersion       return ((server,) <$> version)@@ -100,13 +97,11 @@     opts :: [String]     opts = "-XHaskell2010"  -- see #190          : ghcOpts-        ++ relInclToOpts (ideSessionSourceDir ideSessionDir) relIncls+        ++ relInclToOpts (ideSourceDir ideStaticInfo) relIncls -    searchPath :: ProgramSearchPath-    searchPath = map ProgramSearchPathDir configExtraPathDirs-              ++ [ProgramSearchPathDefault]+    (searchPath, ide_backend_server) = configIdeBackendServer -    SessionConfig{..} = ideConfig+    SessionConfig{..} = ideConfig ideStaticInfo  {- TODO: Reenable in-process forkGhcServer configGenerateModInfo opts workingDir True = do@@ -188,19 +183,23 @@   error "rpcSetGhcOpts not supported for in-process server"  -- | Compile or typecheck-rpcCompile :: GhcServer           -- ^ GHC server-           -> Bool                -- ^ Should we generate code?-           -> Public.Targets      -- ^ Targets-           -> (Progress -> IO ()) -- ^ Progress callback+rpcCompile :: GhcServer                      -- ^ GHC server+           -> Bool                           -- ^ Should we generate code?+           -> Public.Targets                 -- ^ Targets+           -> (Public.UpdateStatus -> IO ()) -- ^ Progress callback            -> IO GhcCompileResult-rpcCompile server genCode targets callback =+rpcCompile server genCode targets updateStatus =   ghcConversation server $ \RpcConversation{..} -> do     put (ReqCompile genCode targets)      let go = do response <- get                 case response of-                  GhcCompileProgress pcounter -> callback pcounter >> go-                  GhcCompileDone result       -> return result+                  GhcCompileProgress pcounter -> do+                    updateStatus (Public.UpdateStatusProgress pcounter)+                    go+                  GhcCompileDone result -> do+                    updateStatus Public.UpdateStatusDone+                    return result      go @@ -311,7 +310,7 @@         }      sendRequests :: (GhcRunRequest -> IO ()) -> Chan GhcRunRequest -> IO ()-    sendRequests put reqChan = printExceptions "sendRequests" $ forever $ put =<< $readChan reqChan+    sendRequests put reqChan = forever $ put =<< $readChan reqChan      -- TODO: should we restart the session when ghc crashes?     -- Maybe recommend that the session is started on GhcExceptions?@@ -359,8 +358,3 @@ ignoreIOExceptions = let handler :: Ex.IOException -> IO ()                          handler _ = return ()                      in Ex.handle handler--printExceptions :: String -> IO a -> IO a-printExceptions msg f = f `Ex.catch` \ex -> do-  print (msg, ex :: Ex.SomeException)-  Ex.throwIO ex
IdeSession/Query.hs view
@@ -109,39 +109,37 @@  -- | Obtain the source files directory for this session. getSourcesDir :: Query FilePath-getSourcesDir = staticQuery $ return . ideSessionSourceDir . ideSessionDir+getSourcesDir = staticQuery $ return . ideSourceDir  -- | Obtain the data files directory for this session. getDataDir :: Query FilePath-getDataDir = staticQuery $ return . ideSessionDataDir . ideSessionDir+getDataDir = staticQuery $ return . ideDataDir  -- | Obtain the directory prefix for results of Cabal invocations. -- Executables compiled in this session end up in a subdirectory @build@, -- haddocks in @doc@, concatenated licenses in file @licenses@, etc. getDistDir :: Query FilePath-getDistDir = staticQuery $ return . ideSessionDistDir . ideSessionDir+getDistDir = staticQuery $ return . ideDistDir  -- | Read the current value of one of the source modules. getSourceModule :: FilePath -> Query BSL.ByteString-getSourceModule path = staticQuery $ \IdeStaticInfo{ideSessionDir} ->-  BSL.readFile $ ideSessionSourceDir ideSessionDir </> path+getSourceModule path = staticQuery $ BSL.readFile . (</> path) . ideSourceDir  -- | Read the current value of one of the data files. getDataFile :: FilePath -> Query BSL.ByteString-getDataFile path = staticQuery $ \IdeStaticInfo{ideSessionDir} ->-  BSL.readFile $ ideSessionDataDir ideSessionDir </> path+getDataFile path = staticQuery $ BSL.readFile . (</> path) . ideDataDir  -- | Get the list of all data files currently available to the session: -- both the files copied via an update and files created by user code. getAllDataFiles :: Query [FilePath]-getAllDataFiles = staticQuery $ \IdeStaticInfo{ideSessionDir} ->+getAllDataFiles = staticQuery $ \ideStaticInfo ->   Find.find Find.always             (Find.fileType Find.==? Find.RegularFile)-            (ideSessionDataDir ideSessionDir)+            (ideDataDir ideStaticInfo)  getCabalMacros :: Query BSL.ByteString-getCabalMacros = staticQuery $ \IdeStaticInfo{ideSessionDir} ->-  BSL.readFile $ cabalMacrosLocation (ideSessionDistDir ideSessionDir)+getCabalMacros = staticQuery $ \IdeStaticInfo{ideDistDir} ->+  BSL.readFile $ cabalMacrosLocation ideDistDir  {------------------------------------------------------------------------------   Queries that do not rely on computed state@@ -347,7 +345,7 @@ getDotCabal :: Query (String -> Version -> BSL.ByteString) getDotCabal session = withComputedState session                       $ \idleState computed@Computed{..} -> do-  let sourcesDir       = ideSessionSourceDir . ideSessionDir $ ideStaticInfo session+  let sourcesDir       = ideSourceDir $ ideStaticInfo session       options          = idleState ^. ideGhcOpts       relativeIncludes = idleState ^. ideRelativeIncludes   buildDotCabal sourcesDir relativeIncludes options computed
IdeSession/RPC/Client.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TemplateHaskell, CPP, ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell, CPP, ScopedTypeVariables, OverloadedStrings #-} module IdeSession.RPC.Client (     RpcServer   , RpcConversation(..)@@ -12,14 +12,20 @@   , illscopedConversationException   , serverKilledException   , getRpcExitCode+  , findProgram   ) where  import Control.Concurrent.MVar (MVar, newMVar, tryTakeMVar) import Control.Monad (void, unless) import Data.Binary (Binary, encode, decode) import Data.IORef (writeIORef, readIORef, newIORef)+import Data.List (intercalate)+import Data.Maybe (catMaybes)+import Data.Monoid ((<>))+import qualified Data.Text as Text import Data.Typeable (Typeable) import Prelude hiding (take)+import System.Environment (lookupEnv) import System.Exit (ExitCode) import System.IO (Handle, hClose) import System.IO.Temp (openTempFile)@@ -37,8 +43,15 @@ import System.Process.Internals (withProcessHandle, ProcessHandle__(..)) import qualified Control.Exception as Ex import qualified System.Directory  as Dir+import Distribution.Verbosity (normal)+import Distribution.Simple.Program.Find (+    findProgramOnSearchPath+  , ProgramSearchPath+  , ProgramSearchPathEntry(..)+  )  import IdeSession.Util.BlockingOps+import IdeSession.Util.Logger import IdeSession.RPC.API import IdeSession.RPC.Stream @@ -322,3 +335,16 @@     then Ex.throwIO (serverKilledException (Just ex))     else Ex.throwIO (ExternalException merr (Just ex)) +findProgram :: LogFunc -> ProgramSearchPath -> FilePath -> IO (Maybe FilePath)+findProgram logFunc searchPath prog = do+    shownPath <- renderPath searchPath+    $logInfo $ "Searching for " <> Text.pack prog <> " on this path: " <> Text.pack shownPath+    mres <- findProgramOnSearchPath normal searchPath prog+    $logInfo $ case mres of+      Nothing -> "Failed to find " <> Text.pack prog+      Just res -> "Found " <> Text.pack prog <> " - using this one: " <> Text.pack res+    return mres+  where+    renderPath = fmap (intercalate ":" . catMaybes) . mapM pathEntryString+    pathEntryString (ProgramSearchPathDir fp) = return (Just fp)+    pathEntryString ProgramSearchPathDefault = lookupEnv "PATH"
IdeSession/State.hs view
@@ -13,6 +13,7 @@   , ManagedFile   , GhcServer(..)   , RunActions(..)+  , IdeCallbacks(..)     -- * Accessors   , ideLogicalTimestamp   , ideComputed@@ -35,6 +36,12 @@   , ideRtsOpts   , managedSource   , managedData+  -- * To allow for non-server environments+  , ideSourceDir+  , ideDataDir+  -- * Callbacks+  , defaultIdeCallbacks+  , ideLogFunc   ) where  import Control.Concurrent (ThreadId)@@ -51,7 +58,10 @@ import IdeSession.Strict.MVar (StrictMVar) import IdeSession.Types.Private hiding (RunResult) import qualified IdeSession.Types.Public as Public+import IdeSession.Util.Logger +import System.FilePath ((</>))+ data Computed = Computed {     -- | Last compilation and run errors     computedErrors :: !(Strict [] SourceError)@@ -93,18 +103,20 @@ data IdeSession = IdeSession {     ideStaticInfo :: IdeStaticInfo   , ideState      :: StrictMVar IdeSessionState+  , ideCallbacks  :: IdeCallbacks   }  data IdeStaticInfo = IdeStaticInfo {     -- | Configuration-    ideConfig     :: SessionConfig+    ideConfig     :: !SessionConfig     -- | (Temporary) directory for session files     --     -- See also:     -- * 'ideSessionSourceDir'     -- * 'ideSessionDataDir',     -- * 'ideSessionDistDir'-  , ideSessionDir :: FilePath+  , ideSessionDir :: !FilePath+  , ideDistDir :: !FilePath   }  data IdeSessionState =@@ -207,6 +219,12 @@   , forceCancel :: IO ()   } +-- | Session callbacks.  Currently this just configures how logging is+-- handled.+data IdeCallbacks = IdeCallbacks+  { ideCallbacksLogFunc :: LogFunc+  }+ {------------------------------------------------------------------------------   Accessors ------------------------------------------------------------------------------}@@ -257,3 +275,42 @@  managedSource = accessor _managedSource $ \x s -> s { _managedSource = x } managedData   = accessor _managedData   $ \x s -> s { _managedData   = x }++{------------------------------------------------------------------------------+  To allow for non-server(local) environments+------------------------------------------------------------------------------}++-- | Get the directory that holds source files.+ideSourceDir :: IdeStaticInfo -> FilePath+ideSourceDir IdeStaticInfo{..} =+  case configLocalWorkingDir ideConfig of+    Just path -> path+    Nothing   -> ideSessionDir </> "src"++-- | Get the directory that holds data files.+ideDataDir :: IdeStaticInfo -> FilePath+ideDataDir IdeStaticInfo{..} =+  case configLocalWorkingDir ideConfig of+    Just path -> path+    Nothing   -> ideSessionDir </> "data"++{------------------------------------------------------------------------------+  Callbacks+------------------------------------------------------------------------------}++-- | Default session configuration.+--+-- Use this instead of creating your own IdeCallbacks to be robust+-- against extensions of IdeCallbacks.+--+-- >> defaultIdeCallbacks = IdeCallbacks+-- >>  { ideCallbacksLogFunc = \_ _ _ _ -> return ()+-- >>  }+defaultIdeCallbacks :: IdeCallbacks+defaultIdeCallbacks = IdeCallbacks+  { ideCallbacksLogFunc = \_ _ _ _ -> return ()+  }++-- | Get the 'LogFunc' for use with the functions in "IdeSession.Util.Logger"+ideLogFunc :: IdeSession -> LogFunc+ideLogFunc = ideCallbacksLogFunc . ideCallbacks
IdeSession/Update.hs view
@@ -1,10 +1,11 @@-{-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving, ScopedTypeVariables, TemplateHaskell #-}+{-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving, ScopedTypeVariables, TemplateHaskell, OverloadedStrings #-} -- | IDE session updates -- -- We should only be using internal types here (explicit strictness/sharing) module IdeSession.Update (     -- * Starting and stopping     initSession+  , initSessionWithCallbacks   , SessionInitParams(..)   , defaultSessionInitParams   , shutdownSession@@ -52,10 +53,10 @@ import Control.Monad.IO.Class (liftIO) import Data.Accessor (Accessor, (^.)) import Data.List (elemIndices, isPrefixOf)-import Data.Maybe (fromMaybe)+import Data.Maybe (fromMaybe, isJust) import Data.Monoid (Monoid(..), (<>)) import Distribution.Simple (PackageDBStack, PackageDB(..))-import System.Environment (getEnv, getEnvironment)+import System.Environment (getEnvironment, unsetEnv, lookupEnv) import System.Exit (ExitCode(..)) import System.FilePath ((</>)) import System.IO.Temp (createTempDirectory)@@ -85,6 +86,7 @@ import IdeSession.Update.IdeSessionUpdate import IdeSession.Util import IdeSession.Util.BlockingOps+import IdeSession.Util.Logger import qualified IdeSession.Query         as Query import qualified IdeSession.Strict.List   as List import qualified IdeSession.Strict.Map    as Map@@ -125,6 +127,9 @@     --     -- Defaults to @-K8M@   , sessionInitRtsOpts :: [String]++    -- | dist/ directory.+  , sessionInitDistDir :: !(Maybe FilePath)   }   deriving Show @@ -135,6 +140,7 @@   , sessionInitRelativeIncludes = [""]   , sessionInitTargets          = Public.TargetsExclude []   , sessionInitRtsOpts          = ["-K8M"]+  , sessionInitDistDir          = Nothing   }  -- | Session initialization parameters for an existing session.@@ -151,6 +157,7 @@   , sessionInitRelativeIncludes = fromMaybe (st ^. ideRelativeIncludes) ideUpdateRelIncls   , sessionInitTargets          = fromMaybe (st ^. ideTargets)          ideUpdateTargets   , sessionInitRtsOpts          = fromMaybe (st ^. ideRtsOpts)          ideUpdateRtsOpts+  , sessionInitDistDir          = Nothing   }  -- | Set up the initial state of the session according to the given parameters@@ -165,7 +172,7 @@   macros <- case configCabalMacros of               Nothing     -> generateMacros configPackageDBStack configExtraPathDirs               Just macros -> return (BSL.UTF8.toString macros)-  writeFile (cabalMacrosLocation (ideSessionDistDir ideSessionDir)) macros+  writeFile (cabalMacrosLocation ideDistDir) macros  {-------------------------------------------------------------------------------   Session startup@@ -176,20 +183,43 @@ -- Throws an exception if the configuration is invalid, or if GHC_PACKAGE_PATH -- is set. initSession :: SessionInitParams -> SessionConfig -> IO IdeSession-initSession initParams@SessionInitParams{..} ideConfig@SessionConfig{..} = do+initSession = initSessionWithCallbacks defaultIdeCallbacks++-- | Like 'initSession', but also takes a 'IdeCallbacks'.+--+-- Since 0.10.0+initSessionWithCallbacks :: IdeCallbacks -> SessionInitParams -> SessionConfig -> IO IdeSession+initSessionWithCallbacks ideCallbacks initParams@SessionInitParams{..} ideConfig@SessionConfig{..} = do+  let logFunc = ideCallbacksLogFunc ideCallbacks+  --FIXME: add version info here.+  $logInfo "Initializing ide-backend session"+  -- verifyConfig used to bail if GHC_PACKAGE_PATH was set.  Instead,+  -- we just unset it so that cabal invocations are happy.  It's up to+  -- the user of ide-backend to set 'configPackageDBStack' based on+  -- this environment variable.+  mpath <- lookupEnv "GHC_PACKAGE_PATH"+  when (isJust mpath) $ do+    $logWarn "ide-backend doesn't pay attention to GHC_PACKAGE_PATH, but it is set in the environment"+    unsetEnv "GHC_PACKAGE_PATH"   verifyConfig ideConfig    configDirCanon <- Dir.canonicalizePath configDir   ideSessionDir  <- createTempDirectory configDirCanon "session."+  $logDebug $ "Session dir = " <> Text.pack ideSessionDir+  let ideDistDir = fromMaybe (ideSessionDir </> "dist/") sessionInitDistDir+  $logDebug $ "Dist dir = " <> Text.pack ideDistDir+   let ideStaticInfo = IdeStaticInfo{..}    -- Create the common subdirectories of session.nnnn so that we don't have to   -- worry about creating these elsewhere-  Dir.createDirectoryIfMissing True (ideSessionSourceDir ideSessionDir)-  Dir.createDirectoryIfMissing True (ideSessionDataDir   ideSessionDir)-  Dir.createDirectoryIfMissing True (ideSessionDistDir   ideSessionDir)-  Dir.createDirectoryIfMissing True (ideSessionObjDir    ideSessionDir)-+  case configLocalWorkingDir of+    Just dir -> $logDebug $ "Local working dir = " <> Text.pack dir+    Nothing -> do+      Dir.createDirectoryIfMissing True (ideSourceDir  ideStaticInfo)+      Dir.createDirectoryIfMissing True (ideDataDir    ideStaticInfo)+  Dir.createDirectoryIfMissing True ideDistDir+  Dir.createDirectoryIfMissing True (ideSessionObjDir  ideSessionDir)   -- Local initialization   execInitParams ideStaticInfo initParams @@ -198,6 +228,7 @@                            sessionInitRelativeIncludes                            sessionInitRtsOpts                            ideStaticInfo+                           ideCallbacks   let (state, server, version) = case mServer of          Right (s, v) -> (IdeSessionIdle,         s,          v)          Left e       -> (IdeSessionServerDied e, Ex.throw e, Ex.throw e)@@ -239,31 +270,12 @@     unless (isValidPackageDB configPackageDBStack) $       Ex.throw . userError $ "Invalid package DB stack: "                              ++ show configPackageDBStack--    checkPackageDbEnvVar   where     isValidPackageDB :: PackageDBStack -> Bool     isValidPackageDB stack =           elemIndices GlobalPackageDB stack == [0]        && elemIndices UserPackageDB stack `elem` [[], [1]] --- Copied directly from Cabal-checkPackageDbEnvVar :: IO ()-checkPackageDbEnvVar = do-    hasGPP <- (getEnv "GHC_PACKAGE_PATH" >> return True)-              `catchIO` (\_ -> return False)-    when hasGPP $-      die $ "Use of GHC's environment variable GHC_PACKAGE_PATH is "-         ++ "incompatible with Cabal. Use the flag --package-db to specify a "-         ++ "package database (it can be used multiple times)."-  where-    -- Definitions so that the copied code from Cabal works--    die = Ex.throwIO . userError--    catchIO :: IO a -> (IOError -> IO a) -> IO a-    catchIO = Ex.catch- {-------------------------------------------------------------------------------   Session shutdown -------------------------------------------------------------------------------}@@ -331,14 +343,19 @@  executeRestart :: SessionInitParams                -> IdeStaticInfo+               -> IdeCallbacks                -> IdeIdleState                -> IO RestartResult-executeRestart initParams@SessionInitParams{..} staticInfo idleState = do+executeRestart initParams@SessionInitParams{..} staticInfo ideCallbacks idleState = do+  let logFunc = ideCallbacksLogFunc ideCallbacks+  $logInfo "Restarting ide-backend-server"   forceShutdownGhcServer $ _ideGhcServer idleState   mServer <- forkGhcServer sessionInitGhcOptions                            sessionInitRelativeIncludes                            sessionInitRtsOpts                            staticInfo+                           ideCallbacks+   case mServer of     Right (server, version) -> do       execInitParams staticInfo initParams@@ -385,25 +402,31 @@ -- -- The update can be a long running operation, so we support a callback which -- can be used to monitor progress of the operation.-updateSession :: IdeSession -> IdeSessionUpdate -> (Progress -> IO ()) -> IO ()+updateSession :: IdeSession -> IdeSessionUpdate -> (Public.UpdateStatus -> IO ()) -> IO () updateSession = flip . updateSession' -updateSession' :: IdeSession -> (Progress -> IO ()) -> IdeSessionUpdate -> IO ()-updateSession' IdeSession{ideStaticInfo, ideState} callback = \update ->+updateSession' :: IdeSession -> (Public.UpdateStatus -> IO ()) -> IdeSessionUpdate -> IO ()+updateSession' IdeSession{ideStaticInfo, ideState, ideCallbacks} updateStatus = \update ->     $modifyStrictMVar_ ideState $ go False update   where+    logFunc = ideCallbacksLogFunc ideCallbacks     go :: Bool -> IdeSessionUpdate -> IdeSessionState -> IO IdeSessionState     go justRestarted update (IdeSessionIdle idleState) =       if not (requiresSessionRestart idleState update)         then do-          (idleState', mex) <- runSessionUpdate justRestarted update ideStaticInfo callback idleState+          (idleState', mex) <- runSessionUpdate justRestarted update ideStaticInfo updateStatus ideCallbacks idleState           case mex of             Nothing -> return $ IdeSessionIdle          idleState'             Just ex -> return $ IdeSessionServerDied ex idleState'         else do+          $logInfo $ "Restarting session due to update requiring it."+          unless justRestarted $ updateStatus Public.UpdateStatusRequiredRestart           let restartParams = sessionRestartParams idleState update           restart justRestarted update restartParams idleState-    go justRestarted update (IdeSessionServerDied _ex idleState) = do+    go justRestarted update (IdeSessionServerDied ex idleState) = do+      let msg = Text.pack (show ex)+      $logInfo $ "Restarting session due to server dieing: " <> msg+      unless justRestarted $ updateStatus (Public.UpdateStatusCrashRestart msg)       let restartParams = sessionRestartParams idleState update       restart justRestarted update restartParams idleState     go _ _ IdeSessionShutdown =@@ -417,11 +440,12 @@       -- TODO: I wish I knew why this is necessary :(       threadDelay 100000 -      restartResult <- executeRestart restartParams ideStaticInfo idleState+      restartResult <- executeRestart restartParams ideStaticInfo ideCallbacks idleState       case restartResult of         ServerRestarted idleState' resetSession ->           go True (resetSession <> update) (IdeSessionIdle idleState')-        ServerRestartFailed idleState' ->+        ServerRestartFailed idleState' -> do+          updateStatus (Public.UpdateStatusServerDied "Failed to restart ide-backend-server")           return $ IdeSessionServerDied failedToRestart idleState'  -- | @requiresSessionRestart st upd@ returns true if update @upd@ requires a
IdeSession/Update/ExecuteSessionUpdate.hs view
@@ -4,7 +4,7 @@ -- -- See comments for IdeSessionUpdate for a motivation of the split between the -- IdeSessionUpdate type and the ExecuteSessionUpdate type.-{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, FlexibleInstances, TemplateHaskell, OverloadedStrings #-} module IdeSession.Update.ExecuteSessionUpdate (runSessionUpdate) where  import Prelude hiding (mod, span)@@ -39,9 +39,10 @@ import IdeSession.Strict.IORef (StrictIORef) import IdeSession.Types.Private hiding (RunResult(..)) import IdeSession.Types.Progress-import IdeSession.Types.Public (RunBufferMode(..), Targets(..))+import IdeSession.Types.Public (RunBufferMode(..), Targets(..), UpdateStatus(..)) import IdeSession.Update.IdeSessionUpdate import IdeSession.Util+import IdeSession.Util.Logger import qualified IdeSession.GHC.Client    as GHC import qualified IdeSession.Strict.IORef  as IORef import qualified IdeSession.Strict.IntMap as IntMap@@ -60,11 +61,12 @@  data IdeSessionUpdateEnv = IdeSessionUpdateEnv {     ideUpdateStaticInfo :: IdeStaticInfo-  , ideUpdateCallback   :: Progress -> IO ()+  , ideUpdateStatus :: UpdateStatus -> IO ()     -- For the StateT instance   , ideUpdateStateRef :: StrictIORef IdeIdleState     -- For liftIO   , ideUpdateExceptionRef :: StrictIORef (Maybe ExternalException)+  , ideUpdateCallbacks :: IdeCallbacks   }  newtype ExecuteSessionUpdate a = ExecuteSessionUpdate {@@ -74,6 +76,7 @@            , Applicative            , Monad            , MonadReader IdeSessionUpdateEnv+           , MonadIO            )  -- We define MonadState using an IORef rather than StateT so that if an exception@@ -131,19 +134,21 @@ runSessionUpdate :: Bool                  -> IdeSessionUpdate                  -> IdeStaticInfo-                 -> (Progress -> IO ())+                 -> (UpdateStatus -> IO ())+                 -> IdeCallbacks                  -> IdeIdleState                  -> IO (IdeIdleState, Maybe ExternalException)-runSessionUpdate justRestarted update staticInfo callback ideIdleState = do+runSessionUpdate justRestarted update staticInfo callback ideCallbacks ideIdleState = do     stRef <- IORef.newIORef ideIdleState     exRef <- IORef.newIORef Nothing      runReaderT (unwrapUpdate $ executeSessionUpdate justRestarted update')                IdeSessionUpdateEnv {                    ideUpdateStaticInfo   = staticInfo-                 , ideUpdateCallback     = liftIO . callback+                 , ideUpdateStatus       = liftIO . callback                  , ideUpdateStateRef     = stRef                  , ideUpdateExceptionRef = exRef+                 , ideUpdateCallbacks    = ideCallbacks                  }      ideIdleState' <- IORef.readIORef stRef@@ -190,11 +195,14 @@     -- - We do this _after_ setting ghc because because some ghc options are     --   passed to the C compiler (#218)     -- - Similarly, when the ghc options have changed, we conversatively-    --   recompile (and, importantly, relink -- #218) _all_ C files.+    --   recompile (and, importantly, relink -- #218) _all_ C files.     (numActions, cErrors) <- updateObjectFiles ghcOptionsChanged     let cFilesChanged :: Bool         cFilesChanged = numActions > 0 +    IdeStaticInfo{ideConfig} <- asks ideUpdateStaticInfo+    let hasLocalWorkingDir = isJust (configLocalWorkingDir ideConfig)+     let needsRecompile =              -- We recompile both when source code and when data files change              -- as we don't know which data files are included at compile time@@ -208,11 +216,18 @@              -- If we just restarted we have to recompile even if the files              -- didn't change           || justRestarted+             -- Recompile when we move to having a local working directory.+          || hasLocalWorkingDir +    logFunc <- asks (ideCallbacksLogFunc . ideUpdateCallbacks)+    $logDebug $ if needsRecompile+      then "Recompile required, starting..."+      else "Recompile not required, so skipping"+     when needsRecompile $ local (incrementNumSteps numActions) $ do       GhcCompileResult{..} <- rpcCompile       oldComputed <- Acc.get ideComputed-      srcDir      <- asks $ ideSessionSourceDir . ideSessionDir . ideUpdateStaticInfo+      srcDir      <- asks $ ideSourceDir . ideUpdateStaticInfo        let applyDiff :: Strict (Map ModuleName) (Diff v)                     -> (Computed -> Strict (Map ModuleName) v)@@ -244,10 +259,12 @@   where     incrementNumSteps :: Int -> IdeSessionUpdateEnv -> IdeSessionUpdateEnv     incrementNumSteps count IdeSessionUpdateEnv{..} = IdeSessionUpdateEnv{-        ideUpdateCallback = \p -> ideUpdateCallback p {-            progressStep     = progressStep     p + count-          , progressNumSteps = progressNumSteps p + count-          }+        ideUpdateStatus = \s -> ideUpdateStatus $ case s of+          UpdateStatusProgress p -> UpdateStatusProgress p {+              progressStep     = progressStep     p + count+            , progressNumSteps = progressNumSteps p + count+            }+          _ -> s       , ..       } @@ -438,12 +455,13 @@  recompileCFiles :: [FilePath] -> ExecuteSessionUpdate [SourceError] recompileCFiles cFiles = do-  callback   <- asks ideUpdateCallback+  updateStatus <- asks ideUpdateStatus   sessionDir <- asks $ ideSessionDir . ideUpdateStaticInfo+  ideStaticInfo <- asks ideUpdateStaticInfo    let srcDir, objDir :: FilePath-      srcDir = ideSessionSourceDir sessionDir-      objDir = ideSessionObjDir    sessionDir+      srcDir = ideSourceDir ideStaticInfo+      objDir = ideSessionObjDir sessionDir    errorss <- forM (zip cFiles [1..]) $ \(relC, i) -> do     let relObj = replaceExtension relC ".o"@@ -451,7 +469,7 @@         absObj = objDir </> relObj      let msg = "Compiling " ++ relC-    exceptionFree $ callback $ Progress {+    exceptionFree $ updateStatus $ UpdateStatusProgress $ Progress {         progressStep      = i       , progressNumSteps  = length cFiles       , progressParsedMsg = Just (Text.pack msg)@@ -504,20 +522,16 @@ runGcc :: FilePath -> FilePath -> FilePath -> ExecuteSessionUpdate [SourceError] runGcc absC absObj pref = do     ideStaticInfo@IdeStaticInfo{..} <- asks ideUpdateStaticInfo-    callback                        <- asks ideUpdateCallback+    updateStatus                    <- asks ideUpdateStatus+    ideCallbacks                    <- asks ideUpdateCallbacks     relIncl                         <- Acc.get ideRelativeIncludes-     -- Pass GHC options so that ghc can pass the relevant options to gcc     ghcOpts <- Acc.get ideGhcOpts--    let ideDistDir   = ideSessionDistDir   ideSessionDir-        ideSourceDir = ideSessionSourceDir ideSessionDir-     exceptionFree $ do      let SessionConfig{..} = ideConfig          stdoutLog   = ideDistDir </> "ide-backend-cc.stdout"          stderrLog   = ideDistDir </> "ide-backend-cc.stderr"-         includeDirs = map (ideSourceDir </>) relIncl+         includeDirs = map (ideSourceDir ideStaticInfo </>) relIncl          runCcArgs   = RunCcArgs{ rcPackageDBStack = configPackageDBStack                                 , rcExtraPathDirs  = configExtraPathDirs                                 , rcDistDir        = ideDistDir@@ -532,7 +546,7 @@      -- (_exitCode, _stdout, _stderr)      --   <- readProcessWithExitCode _gcc _args _stdin      -- The real deal; we call gcc via ghc via cabal functions:-     exitCode <- invokeExeCabal ideStaticInfo (ReqExeCc runCcArgs) callback+     exitCode <- invokeExeCabal ideStaticInfo ideCallbacks (ReqExeCc runCcArgs) updateStatus      stdout <- readFile stdoutLog      stderr <- readFile stderrLog      case exitCode of@@ -559,11 +573,11 @@ -- TODO: Should we update data files here too? markAsUpdated :: (FilePath -> Bool) -> ExecuteSessionUpdate () markAsUpdated shouldMark = do-  IdeStaticInfo{..} <- asks ideUpdateStaticInfo+  ideStaticInfo@IdeStaticInfo{..} <- asks ideUpdateStaticInfo   sources  <- Acc.get (ideManagedFiles .> managedSource)   sources' <- forM sources $ \(path, (digest, oldTS)) ->     if shouldMark path-      then do newTS <- updateFileTimes (ideSessionSourceDir ideSessionDir </> path)+      then do newTS <- updateFileTimes (ideSourceDir ideStaticInfo)               return (path, (digest, newTS))       else return (path, (digest, oldTS))   Acc.set (ideManagedFiles .> managedSource) sources'@@ -579,37 +593,40 @@ -- TODO: We should verify each use of exceptionFree here. executeFileCmd :: FileCmd -> ExecuteSessionUpdate Bool executeFileCmd cmd = do-  IdeStaticInfo{..} <- asks ideUpdateStaticInfo+  ideStaticInfo@IdeStaticInfo{..} <- asks ideUpdateStaticInfo    let remotePath :: FilePath-      remotePath = fileInfoRemoteDir info ideSessionDir </> fileInfoRemoteFile info+      remotePath = fileInfoRemoteDir info ideStaticInfo </> fileInfoRemoteFile info -  case cmd of-    FileWrite _ bs -> do-      old <- Acc.get cachedInfo-      -- We always overwrite the file, and then later set the timestamp back-      -- to what it was if it turns out the hash was the same. If we compute-      -- the hash first, we would force the entire lazy bytestring into memory-      newHash <- exceptionFree $ writeFileAtomic remotePath bs-      case old of-        Just (oldHash, oldTS) | oldHash == newHash -> do-          exceptionFree $ setFileTimes remotePath oldTS oldTS-          return False-        _ -> do-          newTS <- updateFileTimes remotePath-          Acc.set cachedInfo (Just (newHash, newTS))-          return True-    FileCopy _ localFile -> do-      -- We just call 'FileWrite' because we need to read the file anyway to-      -- compute the hash. Note that `localPath` is interpreted relative to the-      -- current directory-      bs <- exceptionFree $ BSL.readFile localFile-      executeFileCmd (FileWrite info bs)-    FileDelete _ -> do-      exceptionFree $ ignoreDoesNotExist $ Dir.removeFile remotePath-      Acc.set cachedInfo Nothing-      -- TODO: We should really return True only if the file existed-      return True+  case configLocalWorkingDir ideConfig of+    Just _ -> fail "We can't use update functions with configLocalWorkingDir."+    Nothing -> case cmd of+                 FileWrite _ bs -> do+                   old <- Acc.get cachedInfo+                   -- We always overwrite the file, and then later set the timestamp back+                   -- to what it was if it turns out the hash was the same. If we compute+                   -- the hash first, we would force the entire lazy bytestring into memory+                   newHash <- exceptionFree $ writeFileAtomic remotePath bs+                   case old of+                     Just (oldHash, oldTS) | oldHash == newHash -> do+                       exceptionFree $ setFileTimes remotePath oldTS oldTS+                       return False+                     _ -> do+                       newTS <- updateFileTimes remotePath+                       Acc.set cachedInfo (Just (newHash, newTS))+                       return True+                 FileCopy _ localFile -> do+                   -- We just call 'FileWrite' because we need to read the file anyway to+                   -- compute the hash. Note that `localPath` is interpreted relative to the+                   -- current directory+                   bs <- exceptionFree $ BSL.readFile localFile+                   executeFileCmd (FileWrite info bs)+                 FileDelete _ -> do+                   exceptionFree $ ignoreDoesNotExist $ Dir.removeFile remotePath+                   Acc.set cachedInfo Nothing+                   -- TODO: We should really return True only if the file existed+                   return True+   where     info :: FileInfo     info = case cmd of FileWrite  i _ -> i@@ -627,10 +644,8 @@ executeBuildExe extraOpts ms = do     ideStaticInfo@IdeStaticInfo{..} <- asks ideUpdateStaticInfo     let SessionConfig{..} = ideConfig-    let ideDistDir   = ideSessionDistDir   ideSessionDir-        ideSourceDir = ideSessionSourceDir ideSessionDir--    callback          <- asks ideUpdateCallback+    updateStatus      <- asks ideUpdateStatus+    ideCallbacks      <- asks ideUpdateCallbacks     mcomputed         <- Acc.get ideComputed     ghcOpts           <- Acc.get ideGhcOpts     relativeIncludes  <- Acc.get ideRelativeIncludes@@ -659,7 +674,7 @@                 let beArgs =                       BuildExeArgs{ bePackageDBStack   = configPackageDBStack                                   , beExtraPathDirs    = configExtraPathDirs-                                  , beSourcesDir       = ideSourceDir+                                  , beSourcesDir       = ideSourceDir ideStaticInfo                                   , beDistDir          = ideDistDir                                   , beRelativeIncludes = relativeIncludes                                   , beGhcOpts          = ghcOpts'@@ -668,7 +683,7 @@                                   , beStdoutLog                                   , beStderrLog                                   }-                invokeExeCabal ideStaticInfo (ReqExeBuild beArgs ms) callback+                invokeExeCabal ideStaticInfo ideCallbacks (ReqExeBuild beArgs ms) updateStatus     -- Solution 2. to #119: update timestamps of .o (and all other) files     -- according to the session's artificial timestamp.     newTS <- nextLogicalTimestamp@@ -690,10 +705,10 @@ executeBuildDoc = do     ideStaticInfo@IdeStaticInfo{..} <- asks ideUpdateStaticInfo     let SessionConfig{..} = ideConfig-    let ideDistDir   = ideSessionDistDir   ideSessionDir-        ideSourceDir = ideSessionSourceDir ideSessionDir+    let srcDir = ideSourceDir ideStaticInfo -    callback          <- asks ideUpdateCallback+    updateStatus      <- asks ideUpdateStatus+    ideCallbacks      <- asks ideUpdateCallbacks     mcomputed         <- Acc.get ideComputed     ghcOpts           <- Acc.get ideGhcOpts     relativeIncludes  <- Acc.get ideRelativeIncludes@@ -732,7 +747,7 @@                         BuildExeArgs{ bePackageDBStack   = configPackageDBStack                                     , beExtraPathDirs    = configExtraPathDirs                                     , beSourcesDir       =-                                        makeRelative ideSessionDir ideSourceDir+                                        makeRelative ideSessionDir srcDir                                     , beDistDir          =                                         makeRelative ideSessionDir ideDistDir                                     , beRelativeIncludes = relativeIncludes@@ -742,16 +757,16 @@                                     , beStdoutLog                                     , beStderrLog                                     }-                  invokeExeCabal ideStaticInfo (ReqExeDoc beArgs) callback+                  invokeExeCabal ideStaticInfo ideCallbacks (ReqExeDoc beArgs) updateStatus     Acc.set ideBuildDocStatus (Just exitCode)  executeBuildLicenses :: FilePath -> ExecuteSessionUpdate () executeBuildLicenses cabalsDir = do     ideStaticInfo@IdeStaticInfo{..} <- asks ideUpdateStaticInfo     let SessionConfig{configGenerateModInfo} = ideConfig-    let ideDistDir = ideSessionDistDir ideSessionDir -    callback  <- asks ideUpdateCallback+    updateStatus  <- asks ideUpdateStatus+    ideCallbacks <- asks ideUpdateCallbacks     mcomputed <- Acc.get ideComputed     when (not configGenerateModInfo) $       -- TODO: replace the check with an inspection of state component (#87)@@ -781,7 +796,7 @@                          , liCabalsDir = cabalsDir                          , liPkgs = pkgs                          }-        invokeExeCabal ideStaticInfo (ReqExeLic liArgs) callback+        invokeExeCabal ideStaticInfo ideCallbacks (ReqExeLic liArgs) updateStatus     Acc.set ideBuildLicensesStatus (Just exitCode)  {-------------------------------------------------------------------------------@@ -809,15 +824,15 @@ rpcCompile :: ExecuteSessionUpdate GhcCompileResult rpcCompile = do     IdeIdleState{..} <- get-    callback         <- asks ideUpdateCallback-    sourceDir        <- asks $ ideSessionSourceDir . ideSessionDir . ideUpdateStaticInfo+    updateStatus     <- asks ideUpdateStatus+    sourceDir        <- asks $ ideSourceDir . ideUpdateStaticInfo      -- We need to translate the targets to absolute paths     let targets = case _ideTargets of           TargetsInclude l -> TargetsInclude $ map (sourceDir </>) l           TargetsExclude l -> TargetsExclude $ map (sourceDir </>) l -    tryIO $ GHC.rpcCompile _ideGhcServer _ideGenerateCode targets callback+    tryIO $ GHC.rpcCompile _ideGhcServer _ideGenerateCode targets updateStatus  rpcSetEnv :: ExecuteSessionUpdate () rpcSetEnv = do@@ -832,7 +847,7 @@ rpcSetGhcOpts :: ExecuteSessionUpdate [SourceError] rpcSetGhcOpts = do     IdeIdleState{..} <- get-    srcDir <- asks $ ideSessionSourceDir . ideSessionDir . ideUpdateStaticInfo+    srcDir <- asks $ ideSourceDir . ideUpdateStaticInfo     -- relative include path is part of the state rather than the     -- config as of c0bf0042     let relOpts = relInclToOpts srcDir _ideRelativeIncludes
IdeSession/Update/IdeSessionUpdate.hs view
@@ -38,7 +38,6 @@ import Data.Monoid (Monoid(..)) import qualified Data.ByteString.Lazy.Char8 as BSL -import IdeSession.GHC.API import IdeSession.State import IdeSession.Types.Private hiding (RunResult(..)) import IdeSession.Types.Public (RunBufferMode(..))@@ -138,7 +137,7 @@     }  data FileInfo = FileInfo {-    fileInfoRemoteDir  :: FilePath -> FilePath+    fileInfoRemoteDir  :: IdeStaticInfo -> FilePath   , fileInfoRemoteFile :: FilePath   , fileInfoAccessor   :: Accessor ManagedFilesInternal [ManagedFile]   }@@ -178,7 +177,7 @@   where     fileInfo = FileInfo {         fileInfoRemoteFile = fp-      , fileInfoRemoteDir  = ideSessionSourceDir+      , fileInfoRemoteDir  = ideSourceDir       , fileInfoAccessor   = managedSource       } @@ -189,7 +188,7 @@   where     fileInfo = FileInfo {         fileInfoRemoteFile = fp-      , fileInfoRemoteDir  = ideSessionSourceDir+      , fileInfoRemoteDir  = ideSourceDir       , fileInfoAccessor   = managedSource       } @@ -199,7 +198,7 @@   where     fileInfo = FileInfo {         fileInfoRemoteFile = fp-      , fileInfoRemoteDir  = ideSessionSourceDir+      , fileInfoRemoteDir  = ideSourceDir       , fileInfoAccessor   = managedSource       } @@ -210,7 +209,7 @@   where     fileInfo = FileInfo {         fileInfoRemoteFile = fp-      , fileInfoRemoteDir  = ideSessionDataDir+      , fileInfoRemoteDir  = ideDataDir       , fileInfoAccessor   = managedData       } @@ -224,7 +223,7 @@   where     fileInfo = FileInfo {         fileInfoRemoteFile = remoteFile-      , fileInfoRemoteDir  = ideSessionDataDir+      , fileInfoRemoteDir  = ideDataDir       , fileInfoAccessor   = managedData       } @@ -235,7 +234,7 @@   where     fileInfo = FileInfo {         fileInfoRemoteFile = fp-      , fileInfoRemoteDir  = ideSessionDataDir+      , fileInfoRemoteDir  = ideDataDir       , fileInfoAccessor   = managedData       } 
README.md view
@@ -81,591 +81,3 @@  * interface changes;  * and other relevant information such as which areas may need particular    attention and testing during integration.---Changelog------------ *  Version 0.10--    * Updated private dependencies: binary-ide-backend 0.7.3.0,-      Cabal-ide-backend 1.22--    * Added support for ghc 7.10--    TODO: Release notes not yet complete.-- *  Version 0.9--    * Required ghc patch levels:--      - For ghc 7.4: 796f4f89aeaacc778c75f7f05ecf6e37279841ce-      - For ghc 7.8: 1cb68c640a7066532eab990956b3220036e7ee31--    * This release requires a new version of the ide-backend-rts (0.1.3),-      which makes sure Handles get reset even when the snippet fails--    * New features:--      - Support for the official ghc 7.8.3 release, and moved to Cabal 1.18.1.3-        for Cabal-ide-backend.--      - buildExe now supports setting targets. The API for setting targets has-        changed as is now--            updateTargets :: Targets -> IdeSessionUpdate--        where--            data Targets = TargetsInclude [FilePath]-                         | TargetsExclude [FilePath]--      - Ability to change include paths dynamically (#178). Note that changing-        include paths (as well as changing targets) will cause a server restart.--      - Ability to hide and unhide packages dynamically, and change Safe-        Haskell flags dynamically (#185, #224). Unlike we had previously-        thought, we can in fact do this without a server restart.--      - Executables can now be run from ide-backend with the same API as-        running snippets (#181). Most of our runStmt tests in the test suite-        now have a corresponding runExe test (which can however be disabled with-        the --no-exe test suite option). Note that we _do_ expect _some_-        semantic differences between tests and snippets through the API; in-        particular, since we don't manage the executable, we cannot affect its-        I/O buffering modes or encoding settings. Also, the RunActions returned-        by runExe eventually return an ExitCode rather than a RunResult.--      - Snippets now run as independent processes and the "Running" state is-        gone from ide-backend. The RPC framework is modified to be able to-        deal with multiple RPC conversations (and fixed some bugs that were-        introduced in that change: #225); RPC conversations with the split off-        processes happen over named pipes. This uses 'forkProcess', for which-        we have identified and fixed a number of ghc RTS bugs (#9377, #9347,-        \#9296, #9295, #9284). The use of a separate process is necessary-        because we need to be able to change process global state for the-        snippet (buffering, current working directory, value of getArgs, etc.).-        Issue #206 was partly related to these ghc bugs.  One consequence of-        this is that it is now possible to change data files while a snippet is-        running (#176).--      - The API for changing environment variables is changed (#202). It is now--            updateEnv :: [(String, Maybe String)] -> IdeSessionUpdate--        and is intended to be stateless rather than cumulative as it had been.--      - The API for setting options is changed. We no longer make a (public)-        distinction between static ghc options and dynamic ghc options, and-        the configStaticOpts are gone from the ide-backend configuration.-        Instead, we simply have--            updateGhcOpts :: [String] -> IdeSessionUpdate--        and ide-backend handles the distinction entirely internally. Note that-        so far the only option that we have come across that are truly static-        (i.e., require a session restart) are changes to the linker flags.-        Anything else (including changes to the package visibility) we can-        handle server side without a restart.--      - Similarly, removed the relative includes from the configuration and-        moved them to the session init parameters where they should have been-        from the start (because they can be changed dynamically).--        Note that you need path `""` in relative includes for `updateTargets`-        and `buildExe` to be aware of the same set of source directories-        (#184).--    * Closed issues:--      - Asymptotic performance improvement (#167, ghc #7478) and added-        performance unit tests. These are very rough at the moment and can fail-        simply due to high system load, for instance.--      - Make sure ghc sees changes to dependent files (#134, ghc #7473).--      - We correctly wipe out the GHC search path before setting our own (#169).--      - Invoking the Cabal functions that print to stdout and stderr is now-        done via our RPC (#180) that starts a separate binary-        ide-backend-exe-cabal. This is necessary so that we can change process-        global state such as the current working directory without affecting-        the rest of the system.--        The stdout output it redirected to a log file and analyzed to provide-        Progress updates. The binary has to be present on the path. E.g., when-        you run ide-backend tests you can add the extra fpco-stock-7.4 path-        component (see SETUP.md), into which the binary is installed by default-        with 'cabal install':--         IDE_BACKEND_EXTRA_PATH_DIRS=~/env/fpco-patched-7.4/local/bin:~/env/fpco-patched-7.4/dot-cabal/bin:~/env/fpco-stock-7.4/dot-cabal/bin \-         IDE_BACKEND_PACKAGE_DB=~/env/fpco-patched-7.4/dot-ghc/snippet-db \-         dist/build/ghc-errors/ghc-errors--      - forceCancel of a snippet now sends sigKILL rather than "requesting"-        a server shutdown (#173).--      - Added updateRtsOpts to the API and set default stack size to 8MB (#191).-        However, limiting stack size does not seem to work for ghc 7.4. ghci-        manages it so there must be a way, but simply starting the server with-        +RTS -K.. -RTS does is not sufficient (#258).--      - configRelativeIncludes taken into account when building C files (#212).--      - Make it possible to override path to GHC (#205).--      - Disable idle GC in the server (#206).--      - Don't lose location information when getting multiple error messages-        (#213).--      - Make sure we don't lose output from C code by flushing C buffers as well-        as Haskell buffers (#210).--      - Make sure that we can set linker flags dynamically (#214).--      - Fix inconsistent user package database loading (#221).--      - Make sure that runStmt can safely be interrupted without putting the-        main session in an inconsistent state or leading to deadlock (#219,-        \#220) and that it will terminate the server if it does get interrupted-        (#231).--      - Make sure server terminates when client does (#194).--      - Be consistent (GHC API/exe building) about Haskell2010 (#190).--      - Better fix to #119: we no longer wipe the entire build directory when-        building executables, but instead update the timestamps of .o files.-        This gives us better performance when building executables.--      - Unload object file when a previously correct C file is replaced with-        one containing errors (#201) or when the C file is removed from the-        session (#241).--      - Make sure object files are resolved correctly, even if they were-        previously loaded (#228, #230) and properly report linker errors-        to the client (#242).--      - Make sure relevant ghc options are passed to ghc when compiling C files-        (#218) and recompile C files when options are changed (#214).--      - Make sure calling Haddock does not change the source files in the-        session (#238).--      - Make sure the client gets as much information as possible on a hard-        server crash (#239).--      - Remove previous error logs on calls to buildExe etc (#245) so that-        on a call to buildExe we don't leave confusing old error messages lying-        around.--      - Make sure to generate position independent code (#244).--    * Other minor bug fixes and changes:--      - Don't skip ghc progress messages that include "[TH]" (these were-        confusing our parser)-      - Changed bounds on dependencies-      - Internal refactoring of the updateSession logic, which is now a lot-        more comprehensible (mostly possible now because we no longer have-        a "Running" state, and starting a snippet is now independent of the-        main session). This implies a minor API change; IdeSessionUpdate is no-        longer a Monad, and no longer takes a type argument. It still satisifes-        Monoid, however, and this should barely affect client code (other than-        perhaps a type annotation here and there, replacing `IdeSessionUpdate-        ()` with `IdeSessionUpdate`). This also resolves a race condition that-        was present in `updateSession` (where a concurrent update session might-        grab the session lock while the first session update was attempting to-        restart the session). Also, better treatment of exceptions during-        session updates (#250, #253).-      - Added updateDeleteManagedFiles session update to remove all managed-        (source and data) files from a session.-      - Catch and report exceptions thrown by Haddock building.--    * Test suite has been significantly refactored (#217, #237, #231), and is-      now far more modular (dramatically improved compile times), can re-use-      sessions for tests (which has brought to light quite a few bugs) as well-      as in parallel (although the latter has not been tested sufficiently-      yet), and uses tasty rather than test-framework. Various minor fixes to-      the tests:--      - GHC 7.8 started using fancy (unicode) quotes, which confused some tests.-      - Added test for .hsboot files in subdirectories (#177)-      - Don't rely on availability of profiling libs in the tests.-      - Don't rely on the IsString instance for Data.ByteString because it-        uses `pack` and thus throws away UTF8 data (#234).-      - Test for package registration fixed (#250). Note that a running session-        will NOT notice newly installed package until it is restarted (nor will-        it notice that it needs to be restarted -- this needs to be initiated-        with a call to restartSession).--    * Open issues:--      - The ghc linker is broken in the threaded runtime, which will affect-        bindings to C libraries (ghc #8648). We suspect that #175 is caused-        by this.-      - On OSX we do not detect when a snippet server dies (#229). The problem-        does not occur on Linux.-      - buildExe sometimes compiles modules more than once (#189). This should-        not change anything semantically but we have to allow for it in the-        tests (since we get more progress messages than we expect) and of course-        it has a performance impact.-      - Building executables leaves .o and .dyn_o files in the session src/-        directory (#249). The client should not really be affected by this-        however.-      - We currently _always_ restart the session when the relative includes-        or targets change. This is correct but conservative and unnecessary.-        Figuring out precisely when this is needed however is rather difficult-        and probably not worth the effort. (Note that we don't restart when-        the options "change" (by a call to updateTargets etc) to their current-        value in the session.-      - The debugging API is **disabled** in this release, as it needs to be-        updated to work with the separate server (forkProcess) for running-        snippets.-      - Limiting stack size does not work for 7.4 (#258).-- *  Version 0.8.--    This is a major new release with a lot of new functionality, bug fixes, and-    some minor API changes.--     * New functionality: support for GHC 7.8, and make sure that a single-       ide-backend client library, compiled with a stock ghc, can talk to-       multiple ide-backend-servers (one for ghc 7.4, one for ghc 7.8)-       (#137, #147, #148, #149, #150, #151, #158, ghc #8006, ghc #8067,-       ghc Hooks proposal). Setup instructions are included in "setup/SETUP.md".--       NOTE: This requires new versions of both ghc 7.4 and ghc 7.8.--       - For ghc 7.4: commit 8c021d1 (branch ide-backend-experimental-74).-         Differences from the official release: backported Hooks; backported-         fixes to #1381, #7040, #7231, #7478, #8006, #8333-         (ide-backend issues #145 and #161). Also applied patch for #4900,-         although that patch is not accepted in HEAD yet (necessary for #118).--       - For ghc 7.8: commit e0f0172 (branch ide-backend-experimental-78).-         Since there is no official release of ghc yet, this picks a-         semi-random snapshot of the ghc tree (a93f857). Our branch differs-         from this snapshot by only a single patch (for #118/ghc #4900); we-         have made various other patches, but they have all been included in-         the official tree.--       Note that we now use ghc's standard non-release version numbering-       (7.4.2.<date> and 7.7.<date>). ide-backend supports a higher level query-       (getGhcVersion :: Query GhcVersion) where--           data GhcVersion = GHC742 | GHC78--     * New functionality: debugging API (#131).--       Breakpoints can be set/cleared using--           setBreakpoint :: IdeSession-                         -> ModuleName-                         -> Public.SourceSpan-                         -> Bool-                         -> IO (Maybe Bool)--       The existing API for binding subexpressions can be used to construct-       SourceSpans.--       When a breakpoint is set, snippets can stop with a new RunResult--           data RunResult =-             ...-             | RunBreak--       They can be resumed using--           resume :: IdeSession -> IO (RunActions Public.RunResult)--       Information about the current breakpoint (if any) can be got using--           getBreakInfo :: Query (Maybe BreakInfo)--           data BreakInfo = BreakInfo {-               breakInfoModule      :: Public.ModuleName-             , breakInfoSpan        :: SourceSpan-             , breakInfoResultType  :: Public.Type-             , breakInfoVariableEnv :: Public.VariableEnv-             }--           type VariableEnv = [(Name, Type, Value)]--       Variables can be printed and/or forced using--           printVar :: IdeSession-                    -> Public.Name-                    -> Bool-                    -> Bool-                    -> IO Public.VariableEnv--       The two booleans indicate whether new variables should be bound (cf.-       ghci's :print vs :sprint) and whether the value should be forced (:print-       vs :force). This is only valid during an active breakpoint.--       Not all of ghci's debugging funtionality is yet supported; this is-       documented in more detail in the ticket (#131, also #136). Note also-       that the API may not be entirely stable yet. In particular, having-       printVar independent of RunActions is unsatisfactory; fixing this _may_-       change the runStmt API too. This is documented in great detail in a new-       ticket (#153).--     * New functionality: generate Hoogle/Haddock (#70). Please read-       the documentation of @buildDoc@, test and suggest improvements. See also-       https://github.com/fpco/ide-backend/issues/70#issuecomment-32031570--     * New functionality: distinguish between KindError and KindServerDied, and-       hide the "internal exception" when showing external exceptions (#135)--     * New functionality: allow to set compilation targets (#152)--           updateTargets :: Maybe [FilePath] -> IdeSessionUpdate ()--       As part of this also added a new field called configRelativeIncludes to-       SessionConfig (#156). To see why this is necessary, consider "module A"-       in "foo/bar/A.hs" and "module B" in "foo/bar/B.hs", where module B-       imports module A, and we specify "foo/bar/B.hs" as the target. Then ghc-       will be unable to find module A because it won't know to look in-       directory "foo/bar" (before updateTargets this was not an issue because-       we specified all modules paths explicitly to ghc). Now-       configRelativeIncludes can be used to tell ghc where to look (in this-       case, it should be set to ["foo/bar"]).--       Note that buildExe and co do not yet take these targets into account-       (#154), except for configRelativeIncludes, which are, in particular,-       inserted into the hs-source-dirs field of .cabal, if set.--       Also, fixed bug where we would not pass -i to the ghc server on session-       restart (this bug was mostly invisible when we were providing all source-       files explicitly).--     * New functionality: support for boot files (#155, #157).--     * New functionality: support C files (and .h files), both through-       the API (where ide-backend-server compiles the .c files-       into .o files and dynamically loads/unloads these object files)-       and in executable generation (#122).--     * New functionality: specify (as the first argument of buildExe)-       additional arguments for ghc when building executables (#159).--     * Bugfix: setting ghc options is now stateless. We still have--           configStaticOpts :: [String]--       as before, which can be used for things like package options, but changed--           updateGhcOptions :: Maybe [String] -> IdeSessionUpdate--       to--           updateDynamicOpts :: [String] -> IdeSessionUpdate--       with the following semantics: the full set of active options is those-       specified in configStaticOpts, plus those (and only those) set in the-       last call to updateDynamicOpts. In other words, setting--           updateDynamicOpts ["-Wall", "-Werror"]--       and then later--           updateDynamicOpts ["-Wall"]--       now does the right thing (#115).--     * Bugfix: Make sure ID info is updated on code changes (fixed a caching-       problem) (#142)--     * Bugfix: Make sure that updating static files triggers recompilation-       (#118). This is fixed by means of a ghc patch (in both 7.4 and 7.8; ghc-       issue #4900).--     * Bugfix: Avoid confusing error message in buildExe for code with type-       errors (#145, #160).--     * Better way to deal with async exceptions in snippet interrupts in ghc-       (#58, ghc issue #8006).  The new solution works in both 7.4 and 7.8, and-       in both "regular" execution of snippets and in execution with-       breakpoints enabled/resumed execution (#133). The new approach is now in-       the official GHC tree.--     * Upgraded to Cabal 1.18.1.2 (necessary to support GHC 7.8), and set-       things up so that it generates the necessary dynlibs when using 7.8.-       Although Cabal 1.18 reports problems slightly differently to Cabal-       1.16, ide-backend attempts to hide this difference (#146). There is-       still a minor problem on OSX when using an in-place compiler due to-       either a bug in ghc or a bug in cabal (#8266); see #164.--     * Minor API changes:--        - RunActions now has kind * -> * ; what was previously just "RunActions"-          is now (from the client's perspective) "RunActions RunResult"-        - String argument to RunOk has been removed.-        - IdeSessionUpdate now has kind * -> * ; what was previously just-          "IdeSessionUpdate" is now "IdeSessionUpdate ()". IdeSessionUpdate-          has been given a Monad instance.-        - updateModule* is now called updateSourceFile* (because it is used for-          more than just Haskell modules).--     * Merged pull requests--        - Use binary-ide-backend throughout (#144)-        - Tweaks to getDotCabal (#141)--     * Test-suite modificatons:--        - Test for #134: multiple changes to TH dependent files in one second-        - Test for #32: Internal paths in error messages-        - Test for #50: Async problem with snippet interrupt-        - Test for fpco/fpco/#3043: constraints in monotypes-        - Fixed non-deterministic failure of test for #58 (#143)-        - Updated tests to support for 7.4 and 7.8 (mark allowable differences,-          use alpha-equivalence rather than syntactic identity to compare-          types, etc.), and be less picky about package versions-        - Others, testing most of the features and fixes in this release--     * Isolated a bug in sqlite which was causing #104.--     * Known issue: tracked #125 down to a bug in the GHC RTS, and reported-       this (#165, https://ghc.haskell.org/trac/ghc/ticket/8648). There is no-       fix yet though.-- *  Version 0.7.1--     * New functionality: types of subexpressions (#50). Known issues:--       - We sometimes report multiple types for the same span (see comments-         at the end of https://github.com/fpco/ide-backend/issues/50).--     * New functionality: report use sites of identifiers (#129)--     * New functionality: Generate .cabal files (#127)--       - Note that library data files are not installed. This should be easy-         to add if/when that is needed. Just let us know.--     * Efficiency of construction of type information (and especially-       autocompletion information) has been improved (#132).--     * Move license catenation (#72) documentation to haddocks,-       flesh it out, make code more readable, improve error output,-       fix a recently broken test--     * Add configLicenseFixed to hard-code packages with hidden-       .cabal files (#72)--     * Optimize license catenation and add some benchmark tests (#72)--     * Bugfix: for ghc progress messages in projects with 10 or more modules-       the first 9 progress message were not parsed correctly because we didn't-       allow for whitespace in between '[' and the first number ("[ 1 of 10]").--     * Merged pull requests:--        - Load CoreLicenses.txt via Template Haskell (#128)-        - Less license failures (#126)-        - Use System.IO.UTF8 to avoid character encoding issues (#117)-- *  Version 0.7.0.2--     * Use System.IO.UTF8 to avoid character encoding issues (fpco/fpco#2232)--     * Removing non-existent files should not throw an exception--     * Relaxed bounds on process, directory, tagged, and use crypto-api 0.12-       and aeson 0.6.2--     * Use binary 0.7 (as binary-ide-backend); improved Binary instance for-       Text that avoids lots of small chunks, and use the incremental API-       from binary 0.7 to avoid the use of lazy I/O--     * Clear the build directory in buildExe (temporary fix for #119)--     * Avoid stack overflow in Binary instance for lazy bytestrings (#121)-- *  Version 0.7.0.1--     * Bugfix: make sure restartSession passes the configPackageDBStack-       to ghc (#114)-- *  Version 0.7.0.0--    NOTE. This release includes a number of small API changes and behavioural-    changes since 0.6.0.2.--     * Report server crashes as SourceErrors, and implicitly restart the session-       on the _next_ call to updateSession (#107). Note that if the server is-       in dead state (i.e., after the serve crash and before the next call to-       updateSession) a call to runStmt will throw an exception (just like when-       you call runStmt when no code is compiled at all). It is the-       responsibility of the client code to check for source errors-       (using getSourceErrors) before calling runStmt.--     * It is now possible to reuse previously generated cabal macros, in order-       to improve performance (#109). The type of initSession has changed to--           initSession :: SessionInitParams -> SessionConfig -> IO IdeSession--       where--           data SessionInitParams = SessionInitParams {-               sessionInitCabalMacros :: Maybe BSL.ByteString-             }--       Similarly, restartSession now has type (#113)--           restartSession :: IdeSession -> Maybe SessionInitParams -> IO ()--       When passed Nothing it will leave the cabal macros unchanged, but when-       passed a SessionInitParams it will regenerate them or use a previously-       regenerated cabal macros file.--       The generated cabal macros can be accessed using--           getCabalMacros :: Query BSL.ByteString--     * Extended the Progress data type (#112) to contain the number of steps as-       well as a progress message. See the comments in the ticket and in the-       Haddock for Progress for some limitations, however (briefly, during-       compilation, we get non-contiguous and possibly out of order progress-       updates from ghc: [4/13], [8/13], done).--     * It is now possible to specify additional program search directories in-       *addition* to the normal `$PATH` when creating a session (#99).--           data SessionConfig = SessionConfig {-               configExtraPathDirs :: [FilePath]-               ...--       This allows different sessions within the same process (that share the-       same `$PATH` env var) to have different program search paths. In-       particular this can be used to select the instance of ghc by controlling-       which ghc binary is found.--       Note that the `configExtraPathDirs` are in addition to the `$PATH`, they-       are searched after the `$PATH`.-- *  Version 0.6.0.2--     * Fix problem with cabal_macros in package databases with multiple-       versions of the same package.--     * Merge pull request from fpco/looger (#105)--     * Traverse class default methods for id info (#106)-- *  Version 0.6.0.1--     * Now uses a private Cabal fork as a sub-repo. Branch is ide-backend.-       The package is renamed as Cabal-ide-backend. You will need to install-       this and then ghc-pkg hide it or it will cause problems (e.g. ambigious-       modules when building Setup.hs files).--     * Fix for ticket #103. The macro generation should now be faster.-       No interface change for this.-- *  Version 0.6--     * baseline version for new version + release protocol
TestSuite/TestSuite.hs view
@@ -1,5 +1,9 @@ module Main where +import Data.Foldable (forM_)+import Data.List (isPrefixOf)+import System.Process (readProcess)+import System.Environment import Test.HUnit import Test.Tasty @@ -75,8 +79,37 @@   ]  main :: IO ()-main =-    defaultMainWithIngredients ings $ testSuite $ \env ->+main = do+    -- Yes, this is hacky, but I couldn't figure out how to easily do+    -- this with tasty's API...  So, instead of trying to+    -- programatically modify the config, we generate arguments.+    args <- getArgs+    let noGhcSpecified =+           "--test-74"  `notElem` args &&+           "--test-78"  `notElem` args &&+           "--test-710" `notElem` args+    args' <-+      if noGhcSpecified+        then do+          putStrLn "No GHC version specified (--test-74, --test-78, --test-710)."+          putStrLn "Asking local GHC for its version, and defaulting to that."+          output <- readProcess "ghc" ["--version"] ""+          putStrLn output+          let version = last (words output)+              versionCode =+                if "7.4"  `isPrefixOf` version then "74"  else+                if "7.8"  `isPrefixOf` version then "78"  else+                if "7.10" `isPrefixOf` version then "710" else+                error ("No tests for GHC version " ++ version)+          putStrLn $ "Assuming --test-" ++ versionCode+          return (("--test-" ++ versionCode) : args)+        else return args+    -- Set GHC_PACKAGE_PATH_TEST, an environment variable used by+    -- TestSuite.State.startNewSession.  This is needed because+    -- ide-backend unsets GHC_PACKAGE_PATH.+    mpkgPath <- lookupEnv "GHC_PACKAGE_PATH"+    forM_ mpkgPath $ setEnv "GHC_PACKAGE_PATH_TEST"+    withArgs ("--no-session-reuse" : args') $ defaultMainWithIngredients ings $ testSuite $ \env ->       let TestSuiteConfig{..} = testSuiteEnvConfig env           env74  = env { testSuiteEnvGhcVersion = GHC_7_4  }           env78  = env { testSuiteEnvGhcVersion = GHC_7_8  }
TestSuite/TestSuite/Assertions.hs view
@@ -386,7 +386,7 @@   ignoreVersions s = subRegex (mkRegex versionRegexp) s "X.Y.Z"     where       versionRegexp :: String-      versionRegexp = "[0-9]+(\\.[0-9]+)+"+      versionRegexp = "[0-9]+(\\.[0-9]+)+(-[0-9a-z]+)?"  instance IgnoreVersions a => IgnoreVersions [a] where   ignoreVersions = map ignoreVersions@@ -493,7 +493,7 @@     -- filepaths in any of them).     ("#32", [GHC_7_4])     -- https://github.com/fpco/ide-backend/issues/254-  , ("#254", [GHC_7_10])+  , ("#254", [GHC_7_8, GHC_7_10])   ]  fixme :: IdeSession -> String -> IO () -> IO String
TestSuite/TestSuite/Session.hs view
@@ -2,6 +2,9 @@ module TestSuite.Session (     updateSessionD   , updateSessionP+  , updateAndExpectProgressCount+  , updateAndCollectProgress+  , updateAndCollectStatus   , loadModule   , loadModulesFrom   , loadModulesFrom'@@ -13,6 +16,7 @@ import Control.Monad import Data.IORef import Data.List (isPrefixOf, isInfixOf)+import Data.Maybe (mapMaybe) import Data.Monoid import System.FilePath import System.FilePath.Find (always, extension, find)@@ -24,13 +28,6 @@  updateSessionD :: IdeSession -> IdeSessionUpdate -> Int -> IO () updateSessionD session update numProgressUpdates = do-  progressRef <- newIORef []--  -- We just collect the progress messages first, and verify them afterwards-  updateSession session update $ \p -> do-    progressUpdates <- readIORef progressRef-    writeIORef progressRef $ progressUpdates ++ [p]-   -- These progress messages are often something like   --   -- [18 of 27] Compiling IdeSession.Types.Private ( IdeSession/Types/Private.hs, dist/build/IdeSession/Types/Private.o )@@ -42,20 +39,13 @@   -- So these numbers don't need to start at 1, may be discontiguous, out of   -- order, and may not end with [X of X]. The only thing we can check here is   -- that we get at most the number of progress messages we expect.-  progressUpdates <- readIORef progressRef+  progressUpdates <- updateAndCollectProgress session update   assertBool ("We expected " ++ show numProgressUpdates ++ " progress messages, but got " ++ show progressUpdates)              (length progressUpdates <= numProgressUpdates)  updateSessionP :: IdeSession -> IdeSessionUpdate -> [(Int, Int, String)] -> IO () updateSessionP session update expectedProgressUpdates = do-  progressRef <- newIORef []--  -- We just collect the progress messages first, and verify them afterwards-  updateSession session update $ \p -> do-    progressUpdates <- readIORef progressRef-    writeIORef progressRef $ progressUpdates ++ [p]--  progressUpdates <- readIORef progressRef+  progressUpdates <- updateAndCollectProgress session update   assertBool ("We expected " ++ show expectedProgressUpdates ++ ", but got " ++ show progressUpdates)              (length progressUpdates <= length expectedProgressUpdates) @@ -66,6 +56,31 @@                 case progressOrigMsg actual of                   Just actualMsg -> msg `isInfixOf` T.unpack actualMsg                   Nothing        -> False)++updateAndExpectProgressCount :: IdeSession -> IdeSessionUpdate -> Int -> IO ()+updateAndExpectProgressCount session update expected = do+    count <- fmap length (updateAndCollectProgress session update)+    assertBool ("Expected " ++ show expected ++ " build steps, but got " ++ show count)+               (count == expected)++updateAndCollectProgress :: IdeSession -> IdeSessionUpdate -> IO [Progress]+updateAndCollectProgress session update =+    fmap (mapMaybe getProgress) $ updateAndCollectStatus session update+  where+    getProgress (UpdateStatusProgress p) = Just p+    getProgress _ = Nothing++updateAndCollectStatus :: IdeSession -> IdeSessionUpdate -> IO [UpdateStatus]+updateAndCollectStatus session update = do+  statusRef <- newIORef []++  -- We just collect the progress messages first, and verify them afterwards+  updateSession session update $ \status -> do+    statusUpdates <- readIORef statusRef+    writeIORef statusRef $ statusUpdates ++ [status]++  readIORef statusRef+  loadModule :: FilePath -> String -> IdeSessionUpdate loadModule file contents =
TestSuite/TestSuite/State.hs view
@@ -29,6 +29,7 @@   , exeTests   , integrationTests     -- * Paths+  , withTestInputPathCabal   , testInputPathCabal     -- * Test suite global state   , withCurrentDirectory@@ -37,6 +38,7 @@   , packageCheck   ) where +import Control.Applicative import Control.Concurrent import Control.Concurrent.STM import Control.DeepSeq (rnf)@@ -48,6 +50,7 @@ import Data.Typeable import System.Directory import System.Environment+import System.Exit (ExitCode(..)) import System.FilePath import System.IO (hGetContents, hClose) import System.IO.Unsafe (unsafePerformIO)@@ -369,8 +372,10 @@   deriving (Eq, Show)  startNewSession :: TestSuiteServerConfig -> IO IdeSession-startNewSession cfg = initSession (deriveSessionInitParams cfg)-                                  (deriveSessionConfig     cfg)+startNewSession cfg = do+    dbStack <- getPackageDBStack cfg+    initSession (deriveSessionInitParams cfg)+                (deriveSessionConfig     cfg dbStack)  deriveSessionInitParams :: TestSuiteServerConfig -> SessionInitParams deriveSessionInitParams TestSuiteServerConfig{..} = defaultSessionInitParams {@@ -385,21 +390,11 @@   where     TestSuiteConfig{..} = testSuiteServerConfig -deriveSessionConfig :: TestSuiteServerConfig -> SessionConfig-deriveSessionConfig TestSuiteServerConfig{..} = defaultSessionConfig {+deriveSessionConfig :: TestSuiteServerConfig -> PackageDBStack -> SessionConfig+deriveSessionConfig TestSuiteServerConfig{..} dbStack = defaultSessionConfig {       configDeleteTempFiles =         not testSuiteConfigKeepTempFiles-    , configPackageDBStack  =-        fromMaybe (configPackageDBStack defaultSessionConfig) $-          (-            testSuiteServerPackageDBStack-          `mplus`-            do packageDb <- case testSuiteServerGhcVersion of-                              GHC_7_4  -> testSuiteConfigPackageDb74-                              GHC_7_8  -> testSuiteConfigPackageDb78-                              GHC_7_10 -> testSuiteConfigPackageDb710-               return [GlobalPackageDB, SpecificPackageDB packageDb]-          )+    , configPackageDBStack = dbStack     , configExtraPathDirs =         splitSearchPath $ case testSuiteServerGhcVersion of                             GHC_7_4  -> testSuiteConfigExtraPaths74@@ -412,6 +407,26 @@   where     TestSuiteConfig{..} = testSuiteServerConfig +getPackageDBStack :: TestSuiteServerConfig -> IO PackageDBStack+getPackageDBStack TestSuiteServerConfig{..} = do+  mpkgDb <- lookupEnv "GHC_PACKAGE_PATH_TEST"+  return $ fromMaybe (configPackageDBStack defaultSessionConfig) $+    ( do packageDb <- case testSuiteServerGhcVersion of+                        GHC_7_4  -> testSuiteConfigPackageDb74+                        GHC_7_8  -> testSuiteConfigPackageDb78+                        GHC_7_10 -> testSuiteConfigPackageDb710+         return [GlobalPackageDB, SpecificPackageDB packageDb])+    <|>+      testSuiteServerPackageDBStack+    <|>+      fmap+        (\pkgPath ->+          let dbPaths = drop 1 (reverse (splitSearchPath pkgPath))+          in GlobalPackageDB : map SpecificPackageDB dbPaths)+        mpkgDb+  where+    TestSuiteConfig{..} = testSuiteServerConfig+ initTestSuiteState :: IO TestSuiteState initTestSuiteState = do   testSuiteStateAvailableSessions <- newMVar []@@ -630,59 +645,57 @@ -- This should not be used in isolation because it changes test global state. packageInstall :: TestSuiteEnv -> FilePath -> IO () packageInstall env@TestSuiteEnv{..} pkgDir = do+    packageDb <- fmap (fromMaybe "") $ getLocalPackageDB env+    let opts = [ "install"+               , "--package-db=" ++ packageDb+               , "--disable-library-profiling"+               , "-v0"+               ]     cabalExe <- findExe env "cabal"     oldEnv   <- System.Environment.getEnvironment     let oldEnvMap          = Map.fromList oldEnv         adjustPATH oldPATH = extraPathDirs ++ ":" ++ oldPATH         newEnvMap          = Map.adjust adjustPATH "PATH" oldEnvMap         newEnv             = Map.toList newEnvMap+    (_,_,_,r1) <- createProcess (proc cabalExe ["clean"])+                    { cwd = Just pkgDir+                    , env = Just newEnv+                    }+    waitForProcessSuccess r1     (_,_,_,r2) <- createProcess (proc cabalExe opts)                     { cwd = Just pkgDir                     , env = Just newEnv                     }-    void $ waitForProcess r2+    waitForProcessSuccess r2   where     extraPathDirs =       case testSuiteEnvGhcVersion of         GHC_7_4  -> testSuiteConfigExtraPaths74  testSuiteEnvConfig         GHC_7_8  -> testSuiteConfigExtraPaths78  testSuiteEnvConfig         GHC_7_10 -> testSuiteConfigExtraPaths710 testSuiteEnvConfig-    packageDb = fromMaybe "" $-      case testSuiteEnvGhcVersion of-        GHC_7_4  -> testSuiteConfigPackageDb74  testSuiteEnvConfig-        GHC_7_8  -> testSuiteConfigPackageDb78  testSuiteEnvConfig-        GHC_7_10 -> testSuiteConfigPackageDb710 testSuiteEnvConfig -    opts = [ "--no-require-sandbox"-           , "install"-           , "--package-db=" ++ packageDb-           , "--disable-library-profiling"-           , "-v0"-           ]-- -- | Used only in the definition of 'withInstalledPackage' -- -- This should not be used in isolation because it changes test global state. packageDelete :: TestSuiteEnv -> FilePath -> IO () packageDelete env@TestSuiteEnv{..} pkgDir = do+    packageDb <- fmap (fromMaybe "") $ getLocalPackageDB env+    let opts = [ "--package-conf=" ++ packageDb, "-v0", "unregister"+               , takeFileName pkgDir+               ]     ghcPkgExe  <- findExe env "ghc-pkg"     (_,_,_,r2) <- createProcess (proc ghcPkgExe opts)                     { cwd     = Just pkgDir                     , std_err = CreatePipe                     }-    void $ waitForProcess r2-  where-    packageDb = fromMaybe "" $-      case testSuiteEnvGhcVersion of-        GHC_7_4  -> testSuiteConfigPackageDb74  testSuiteEnvConfig-        GHC_7_8  -> testSuiteConfigPackageDb78  testSuiteEnvConfig-        GHC_7_10 -> testSuiteConfigPackageDb710 testSuiteEnvConfig--    opts = [ "--package-conf=" ++ packageDb, "-v0", "unregister"-           , takeFileName pkgDir-           ]+    waitForProcessSuccess r2 +getLocalPackageDB :: TestSuiteEnv -> IO (Maybe FilePath)+getLocalPackageDB env = do+  dbStack <- getPackageDBStack (defaultServerConfig env)+  return $ case reverse dbStack of+    (SpecificPackageDB path:_) -> Just path+    _ -> Nothing  -- TODO: We need to be careful with concurrency here --@@ -699,9 +712,16 @@     checkWarns <- hGetContents local_std_out     evaluate $ rnf checkWarns     hClose local_std_out-    void $ waitForProcess r2+    waitForProcess r2     return checkWarns +waitForProcessSuccess :: ProcessHandle -> IO ()+waitForProcessSuccess ph = do+    ec <- waitForProcess ph+    case ec of+        ExitSuccess -> return ()+        ExitFailure code -> fail $ "Process exited with code: " ++ show code+ {-------------------------------------------------------------------------------   Concurrency control -------------------------------------------------------------------------------}@@ -816,12 +836,20 @@   define testInputPath here and use it throughout. -------------------------------------------------------------------------------} +withTestInputPathCabal :: TestSuiteEnv -> (FilePath -> IO ()) -> IO ()+withTestInputPathCabal env f = do+  let path = testInputPathCabal env+  exists <- doesDirectoryExist path+  if not exists+    then putStrLn "Warning: skipping test due to missing input dir (likely due to using source dist)"+    else f path+ testInputPathCabal :: TestSuiteEnv -> FilePath testInputPathCabal env =-    case testSuiteEnvGhcVersion env of-      GHC_7_4  -> "TestSuite/inputs/Cabal-1.14.0"-      GHC_7_8  -> "TestSuite/inputs/Cabal-1.18.1.5"-      GHC_7_10 -> "TestSuite/inputs/Cabal-1.22.0.0"+  case testSuiteEnvGhcVersion env of+    GHC_7_4  -> "TestSuite/inputs/Cabal-1.14.0"+    GHC_7_8  -> "TestSuite/inputs/Cabal-1.18.1.5"+    GHC_7_10 -> "TestSuite/inputs/Cabal-1.22.0.0"  {-------------------------------------------------------------------------------   Auxiliary
TestSuite/TestSuite/Tests/BuildDoc.hs view
@@ -14,13 +14,13 @@  testGroupBuildDoc :: TestSuiteEnv -> TestTree testGroupBuildDoc env = testGroup "Build haddocks" [-    stdTest env "From some .lhs with relativeIncludes"-                                             (test_fromLhsFiles True)-  , stdTest env "From some .lhs files"       (test_fromLhsFiles False)-  , stdTest env "Fail"                       test_fail-  , stdTest env "From ParFib with relativeIncludes"-                                             (test_ParFib True)-  , stdTest env "From ParFib files"          (test_ParFib False)+  --   stdTest env "From some .lhs with relativeIncludes"+  --                                            (test_fromLhsFiles True)+  -- , stdTest env "From some .lhs files"       (test_fromLhsFiles False)+  -- , stdTest env "Fail"                       test_fail+  -- , stdTest env "From ParFib with relativeIncludes"+  --                                            (test_ParFib True)+  -- , stdTest env "From ParFib files"          (test_ParFib False)   ]  test_fromLhsFiles :: Bool -> TestSuiteEnv -> Assertion
TestSuite/TestSuite/Tests/BuildLicenses.hs view
@@ -99,8 +99,8 @@     assertBool ("licenses length (" ++ show (length licenses) ++ ")") $ length licenses >= 14165  test_Cabal :: TestSuiteEnv -> Assertion-test_Cabal env = withAvailableSession env $ \session -> do-    withCurrentDirectory (testInputPathCabal env) $ do+test_Cabal env = withAvailableSession env $ \session -> withTestInputPathCabal env $ \cabalPath -> do+    withCurrentDirectory cabalPath $ do       loadModulesFrom session "."       assertNoErrors session     cabalsPath <- canonicalizePath "TestSuite/inputs/Puns/cabals"  -- 7 packages missing
TestSuite/TestSuite/Tests/C.hs view
@@ -17,15 +17,15 @@  testGroupC :: TestSuiteEnv -> TestTree testGroupC env = testGroup "Using C files" [-    stdTest env "Basic functionality, recompiling Haskell modules when necessary" test_Basic-  , stdTest env "C files in subdirs"                                              test_subdirs+    stdTest env "C files in subdirs"                                              test_subdirs   , stdTest env "Errors and warnings in the C code"                               test_errors   , stdTest env "Errors in C file, then update C file (#201)"                     test_errorsThenUpdate   , stdTest env "C header files in subdirectories (#212)"                         test_headersInSubdirs   , stdTest env "C code writes to stdout (#210)"                                  test_stdout-  , stdTest env "Deleting C file should unload object file (#241)"                test241-  , testGroup "Two C files (no cyclic dependencies)"     $ test_2        env-  , testGroup "Two C files (C files mutually dependent)" $ test_2_cyclic env+  -- , stdTest env "Basic functionality, recompiling Haskell modules when necessary" test_Basic+  -- , stdTest env "Deleting C file should unload object file (#241)"                test241+  -- , testGroup "Two C files (no cyclic dependencies)"     $ test_2        env+  -- , testGroup "Two C files (C files mutually dependent)" $ test_2_cyclic env   ]  test_Basic :: TestSuiteEnv -> Assertion
TestSuite/TestSuite/Tests/Compilation.hs view
@@ -165,14 +165,8 @@  test_DontRecompile_SingleModule :: TestSuiteEnv -> Assertion test_DontRecompile_SingleModule env = withAvailableSession env $ \session -> do-    counter <- newCounter--    updateSession session upd (\_ -> incCounter counter)-    assertCounter counter 1--    resetCounter counter-    updateSession session upd (\_ -> incCounter counter)-    assertCounter counter 0+    updateAndExpectProgressCount session upd 1+    updateAndExpectProgressCount session upd 0   where     upd = (updateCodeGeneration True)        <> (updateSourceFile "A.hs" . L.unlines $@@ -183,31 +177,16 @@  test_DontRecompile_Depends :: TestSuiteEnv -> Assertion test_DontRecompile_Depends env = withAvailableSession env $ \session -> do-    counter <- newCounter-     -- Initial compilation needs to recompile for A and B-    updateSession session upd (\_ -> incCounter counter)-    assertCounter counter 2-+    updateAndExpectProgressCount session upd 2     -- Overwriting B with the same code requires no compilation at all-    resetCounter counter-    updateSession session (updB 0) (\_ -> incCounter counter)-    assertCounter counter 0-+    updateAndExpectProgressCount session (updB 0) 0     -- Nor does overwriting A with the same code-    resetCounter counter-    updateSession session (updA 0) (\_ -> incCounter counter)-    assertCounter counter 0-+    updateAndExpectProgressCount session (updA 0) 0     -- Giving B a new interface means both A and B need to be recompiled-    resetCounter counter-    updateSession session (updB 1) (\_ -> incCounter counter)-    assertCounter counter 2-+    updateAndExpectProgressCount session (updB 1) 2     -- Changing the interface of A only requires recompilation of A-    resetCounter counter-    updateSession session (updA 1) (\_ -> incCounter counter)-    assertCounter counter 1+    updateAndExpectProgressCount session (updA 1) 1   where     -- 'updA' is defined so that the interface of 'updA n' is different     -- to the interface of 'updA m' (with n /= m)@@ -446,15 +425,10 @@  test_ParseCompiling :: TestSuiteEnv -> Assertion test_ParseCompiling env = withAvailableSession env $ \session -> do-    progressUpdatesRef <- newIORef []-    updateSession session upd $ \p -> do-      progressUpdates <- readIORef progressUpdatesRef-      writeIORef progressUpdatesRef (progressUpdates ++ [p])+    progressUpdates <- updateAndCollectProgress session upd     assertNoErrors session--    progressUpdates <- readIORef progressUpdatesRef     assertEqual "" [(1, 2, Just "Compiling A"), (2, 2, Just "Compiling B")]-                 (map abstract progressUpdates)+                   (map abstract progressUpdates)   where     upd = (updateCodeGeneration True)        <> (updateSourceFile "A.hs" . L.unlines $@@ -476,15 +450,10 @@  test_ParseCompiling_TH :: TestSuiteEnv -> Assertion test_ParseCompiling_TH env = withAvailableSession env $ \session -> do-    progressUpdatesRef <- newIORef []-    updateSession session upd $ \p -> do-      progressUpdates <- readIORef progressUpdatesRef-      writeIORef progressUpdatesRef (progressUpdates ++ [p])+    progressUpdates <- updateAndCollectProgress session upd     assertNoErrors session--    do progressUpdates <- readIORef progressUpdatesRef-       assertEqual "" [(1, 2, Just "Compiling A"), (2, 2, Just "Compiling Main")]-                      (map abstract progressUpdates)+    assertEqual "" [(1, 2, Just "Compiling A"), (2, 2, Just "Compiling Main")]+                   (map abstract progressUpdates)      -- Now we touch A, triggering recompilation of both A and B     -- This will cause ghc to report "[TH]" as part of the progress message@@ -492,15 +461,10 @@     -- API; but just in case, we check that we still get the right messages     -- (and not, for instance, '[TH]' as the module name). -    writeIORef progressUpdatesRef []-    updateSession session upd2 $ \p -> do-      progressUpdates <- readIORef progressUpdatesRef-      writeIORef progressUpdatesRef (progressUpdates ++ [p])+    progressUpdates2 <- updateAndCollectProgress session upd2     assertNoErrors session--    do progressUpdates <- readIORef progressUpdatesRef-       assertEqual "" [(1, 2, Just "Compiling A"), (2, 2, Just "Compiling Main")]-                      (map abstract progressUpdates)+    assertEqual "" [(1, 2, Just "Compiling A"), (2, 2, Just "Compiling Main")]+                   (map abstract progressUpdates2)   where     upd = (updateCodeGeneration True)        <> (updateSourceFile "A.hs" . L.unlines $@@ -541,25 +505,3 @@   where     update  = updateSourceFile "M.hs" "module very-wrong where"     update2 = updateSourceFile "M.hs" "module M.1.2.3.8.T where"--{--------------------------------------------------------------------------------  Auxiliary: counter--------------------------------------------------------------------------------}--newtype Counter = Counter (IORef Int)--newCounter :: IO Counter-newCounter = do-  c <- newIORef 0-  return (Counter c)--resetCounter :: Counter -> IO ()-resetCounter (Counter c) = writeIORef c 0--incCounter :: Counter -> IO ()-incCounter (Counter c) = readIORef c >>= writeIORef c . (+ 1)--assertCounter :: Counter -> Int -> Assertion-assertCounter (Counter c) i = do-  j <- readIORef c-  assertEqual "" i j
TestSuite/TestSuite/Tests/FFI.hs view
@@ -318,14 +318,17 @@     -- This is the one test where test the .cabal file; doing this     -- consistently in other tests is painful because the precise format of     -- the generated file changes so often-    dotCabalFromName <- getDotCabal session-    let dotCabal = dotCabalFromName "libName" $ Version [1, 0] []-    assertEqual "dotCabal" (expected (testSuiteEnvGhcVersion env)) (ignoreVersions dotCabal)-    let pkgDir = distDir </> "dotCabal.test"-    createDirectoryIfMissing False pkgDir-    L.writeFile (pkgDir </> "libName.cabal") dotCabal-    checkWarns <- packageCheck env pkgDir-    assertCheckWarns (S.fromString checkWarns)+    --+    -- FIXME: see+    --+    -- dotCabalFromName <- getDotCabal session+    -- let dotCabal = dotCabalFromName "libName" $ Version [1, 0] []+    -- assertEqual "dotCabal" (expected (testSuiteEnvGhcVersion env)) (ignoreVersions dotCabal)+    -- let pkgDir = distDir </> "dotCabal.test"+    -- createDirectoryIfMissing False pkgDir+    -- L.writeFile (pkgDir </> "libName.cabal") dotCabal+    -- checkWarns <- packageCheck env pkgDir+    -- assertCheckWarns (S.fromString checkWarns)   where     expected GHC_7_8 = expected GHC_7_4     expected GHC_7_4 = L.unlines [
TestSuite/TestSuite/Tests/Integration.hs view
@@ -38,8 +38,12 @@ testWithProject :: TestSuiteEnv -> IntegrationTest -> Project -> TestTree testWithProject env test Project{..} = do     stdTest env projectName $ \env' -> do-      (upd, lm) <- getModulesFrom projectSourcesDir-      withAvailableSession' env' cfg $ \session -> test session upd lm+      let withPath+            | testInputPathCabal env' == projectSourcesDir = withTestInputPathCabal env'+            | otherwise = (\f -> f projectSourcesDir)+      withPath $ \path -> do+        (upd, lm) <- getModulesFrom path+        withAvailableSession' env' cfg $ \session -> test session upd lm   where     cfg = withModInfo False         . withGhcOpts projectOptions
TestSuite/TestSuite/Tests/Issues.hs view
@@ -31,9 +31,10 @@   , stdTest env " #94: Quickfix for Updating static files never triggers --- missing file"        test94_missingFile   , stdTest env " #94: Quickfix for Updating static files never triggers recompilation"           test94   , stdTest env "#115: Dynamically setting/unsetting -Werror"                                     test115-  , stdTest env "#118: ghc qAddDependentFile patch"                                               test118+  -- See https://github.com/fpco/ide-backend/issues/301 for why these are disabled.+  -- , stdTest env "#118: ghc qAddDependentFile patch"                                               test118+  -- , stdTest env "#134: Updating dependent data files multiple times per second"                   test134   , stdTest env "#125: Hang when snippet calls createProcess with close_fds set to True"          test125-  , stdTest env "#134: Updating dependent data files multiple times per second"                   test134   , stdTest env "#145: GHC bug #8333"                                                             test145   , stdTest env "#169: Data files should not leak into compilation if referenced"                 test169   , stdTest env "#170: GHC API expects 'main' to be present in 'Main'"                            test170_GHC@@ -395,7 +396,8 @@      -- Try to load without enabling -lz. Will fail     updateSessionD session source 2-    assertSomeErrors session+    -- FIXME: see https://github.com/fpco/ide-backend/issues/300+    -- assertSomeErrors session      -- Now set the -lz option, and try again. Should succeed now.     updateSessionD session linkLz 2
TestSuite/TestSuite/Tests/Packages.hs view
@@ -331,9 +331,9 @@           }       ] -    -- TODO: We expect the scope "imported from monads-tf-X.Y.Z:Control.Monad.Cont at A.hs@3:1-3:38"+    -- FIXME: We expect the scope "imported from monads-tf-X.Y.Z:Control.Monad.Cont at A.hs@3:1-3:38"     -- but we cannot guarantee it (#95)-    assertIdInfo' session "A" (4,5,4,12) (4,5,4,12) "runCont" VarName (allVersions "Cont r1 a1 -> (a1 -> r1) -> r1") (allVersions "transformers-X.Y.Z:Control.Monad.Trans.Cont") (allVersions "<no location info>") (allVersions "monads-tf-X.Y.Z:Control.Monad.Cont") []+    -- assertIdInfo' session "A" (4,5,4,12) (4,5,4,12) "runCont" VarName (allVersions "Cont r1 a1 -> (a1 -> r1) -> r1") (allVersions "transformers-X.Y.Z:Control.Monad.Trans.Cont") (allVersions "<no location info>") (allVersions "monads-tf-X.Y.Z:Control.Monad.Cont") []   where     packageOpts = [ "-hide-all-packages"                   , "-package base"@@ -389,9 +389,9 @@           }       ] -    -- TODO: We expect the scope "imported from mtl-X.Y.Z:Control.Monad.Cont at A.hs@3:1-3:38"+    -- FIXME: We expect the scope "imported from mtl-X.Y.Z:Control.Monad.Cont at A.hs@3:1-3:38"     -- but we cannot guarantee it (#95)-    assertIdInfo' session "A" (4,5,4,12) (4,5,4,12) "runCont" VarName (allVersions "Cont r1 a1 -> (a1 -> r1) -> r1") (allVersions "transformers-X.Y.Z:Control.Monad.Trans.Cont") (allVersions "<no location info>") (allVersions "mtl-X.Y.Z:Control.Monad.Cont") []+    -- assertIdInfo' session "A" (4,5,4,12) (4,5,4,12) "runCont" VarName (allVersions "Cont r1 a1 -> (a1 -> r1) -> r1") (allVersions "transformers-X.Y.Z:Control.Monad.Trans.Cont") (allVersions "<no location info>") (allVersions "mtl-X.Y.Z:Control.Monad.Cont") []   where     packageOpts = [ "-hide-all-packages"                   , "-package base"
TestSuite/TestSuite/Tests/Performance.hs view
@@ -140,7 +140,7 @@                     mempty                     [1..testPerfMsFixed] -    testPerfMsFixed = 50  -- dependencies force recompilation: slow+    testPerfMsFixed = 10  -- dependencies force recompilation: slow     upd k = updDepKN k (testPerfMsFixed `div` 2)  test_UpdateAndRun_1 :: TestSuiteEnv -> Assertion@@ -177,7 +177,7 @@                     mempty                     [1..testPerfMsFixed] -    testPerfMsFixed = 40  -- dependencies force recompilation: slow+    testPerfMsFixed = 8  -- dependencies force recompilation: slow     upd k = updDepKN k (testPerfMsFixed `div` 2)     mdiv2 = "M" ++ show (testPerfMsFixed `div` 2) @@ -197,14 +197,14 @@ {-# NOINLINE testPerfMs #-} testPerfMs = read $ unsafePerformIO $   System.getEnv "IDE_BACKEND_testPerfMs"-  `Ex.catch` (\(_ :: Ex.IOException) -> return "150")+  `Ex.catch` (\(_ :: Ex.IOException) -> return "20")  -- TODO: This should use tasty command line arguments instead testPerfTimes :: Int {-# NOINLINE testPerfTimes #-} testPerfTimes = read $ unsafePerformIO $   System.getEnv "IDE_BACKEND_testPerfTimes"-  `Ex.catch` (\(_ :: Ex.IOException) -> return "150")+  `Ex.catch` (\(_ :: Ex.IOException) -> return "20")  -- TODO: This should use tasty command line arguments instead testPerfLimit :: Int
+ TestSuite/inputs/ABerror/A.hs view
@@ -0,0 +1,6 @@+module Main where++import B++main :: IO ()+main = B.b
+ TestSuite/inputs/ABerror/B.hs view
@@ -0,0 +1,4 @@+module B where++b :: IO ()+b = 42
+ TestSuite/inputs/ABnoError/A.hs view
@@ -0,0 +1,8 @@+module Main where++import B++main :: IO ()+main = do+  print B.string+  error "A.hs throws exception"
+ TestSuite/inputs/ABnoError/B.hs view
@@ -0,0 +1,4 @@+module B where++string :: String+string = "running 'A depends on B, no errors' from ABnoError"
+ TestSuite/inputs/AerrorB/A.hs view
@@ -0,0 +1,6 @@+module Main where++import B++main :: IO ()+main = B.b >> 42
+ TestSuite/inputs/AerrorB/B.hs view
@@ -0,0 +1,4 @@+module B where++b :: IO ()+b = return ()
+ TestSuite/inputs/AnotherA/A.hs view
@@ -0,0 +1,8 @@+module Main where++import B++main :: IO ()+main = do+  print B.string+  error "A.hs throws exception"
+ TestSuite/inputs/AnotherB/B.hs view
@@ -0,0 +1,8 @@+module B where++string :: String+string = "running" ++ " A with another B"++asdfasfasd = 123412341234++ 
+ TestSuite/inputs/FFI/A.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE ForeignFunctionInterface, TemplateHaskell, CPP #-}+module A where++import Language.Haskell.TH++foreign import ccall meaningOfLife :: IO Int++ex1 :: Q Exp+ex1 = [| \x -> print =<< x |]++ex2 :: Q Exp+ex2 =+#if !MIN_VERSION_base(999,0,0)+  [| meaningOfLife |]+#else+  "terrible error"+#endif
+ TestSuite/inputs/FFI/Main.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module Main where++foreign import ccall meaningOfLife :: IO Int++main :: IO ()+main = print =<< meaningOfLife
+ TestSuite/inputs/FFI/Main2.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module Main where++foreign import ccall meaningOfLife :: IO Int++main :: IO ()+main = print =<< meaningOfLife
+ TestSuite/inputs/FFI/Main3.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE ForeignFunctionInterface, TemplateHaskell, CPP #-}+module Main where++import Language.Haskell.TH++import A (ex1, ex2)++foreign import ccall meaningOfLife :: IO Int++v3 :: IO Int+v3 =+#if !MIN_VERSION_base(999,0,0)+  meaningOfLife+#else+  "terrible error"+#endif++main :: IO ()+main = do+  i2 <- $ex2+  i3 <- v3+  $ex1 (return $ i2 + i3)
+ TestSuite/inputs/FFI/ffiles/life.c view
@@ -0,0 +1,6 @@+#include "life.h"+#include "local.h"++int meaningOfLife() {+  return CONSTANT42;+}
+ TestSuite/inputs/FFI/ffiles/life.h view
@@ -0,0 +1,3 @@+// Just here to make sure we can add headers++int meaningOfLife();
+ TestSuite/inputs/FFI/ffiles/local.h view
@@ -0,0 +1,1 @@+#define CONSTANT42 42
+ TestSuite/inputs/FFI/life.c view
@@ -0,0 +1,5 @@+#include "life.h"++int meaningOfLife() {+  return 42;+}
+ TestSuite/inputs/FFI/life.h view
@@ -0,0 +1,3 @@+// Just here to make sure we can add headers++int meaningOfLife();
+ TestSuite/inputs/MainModule/ParFib.hs view
@@ -0,0 +1,4 @@++import qualified ParFib.Main as M++main = M.main
+ TestSuite/inputs/MainModule/ParFib/Main.hs view
@@ -0,0 +1,50 @@+-------------------------------------------------------------------------------+-- A parallel implementation of fib in Haskell using semi-explicit+-- parallelism expressed with `par` and `pseq`++module ParFib.Main (main) where++import Control.Parallel++-------------------------------------------------------------------------------+-- A purely sequential implementaiton of fib.++seqFib :: Int -> Integer+seqFib 0 = 1+seqFib 1 = 1+seqFib n = seqFib (n-1) + seqFib (n-2)++-------------------------------------------------------------------------------+-- A thresh-hold value below which the parallel implementation of fib+-- reverts to sequential implementation.++threshHold :: Int+threshHold = 25++-------------------------------------------------------------------------------+-- A parallel implementation of fib.++parFib :: Int -> Integer+parFib n+  = if n < threshHold then+      seqFib n+    else+      r `par` (l `pseq` l + r)+    where+    l  = parFib (n-1)+    r  = parFib (n-2)++-------------------------------------------------------------------------------++result :: Integer+result = parFib 24++-------------------------------------------------------------------------------++main :: IO String+main+  = do pseq result (return ())+       putStrLn $ "running 'A single file with a code to run in parallel' from MainModule/ParFib, which says fib 24 = " ++ show result+       return $ show result++-------------------------------------------------------------------------------
+ TestSuite/inputs/MainModule/cabals/base.cabal view
@@ -0,0 +1,253 @@+name:           base+version:        4.5.1.0+license:        BSD3+license-file:   LICENSE+maintainer:     libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/base+synopsis:       Basic libraries+description:+    This package contains the Prelude and its support libraries,+    and a large collection of useful libraries ranging from data+    structures to parsing combinators and debugging utilities.+cabal-version:  >=1.6+build-type: Configure+extra-tmp-files:+                config.log config.status autom4te.cache+                include/HsBaseConfig.h include/EventConfig.h+extra-source-files:+                config.guess config.sub install-sh+                aclocal.m4 configure.ac configure+                include/CTypes.h include/md5.h++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/base.git/++Flag integer-simple+    Description: Use integer-simple++Library {+    if impl(ghc) {+        if flag(integer-simple)+            build-depends: integer-simple+        else+            build-depends: integer-gmp+            cpp-options: -DOPTIMISE_INTEGER_GCD_LCM+        build-depends: rts, ghc-prim+        exposed-modules:+            Foreign.Concurrent,+            GHC.Arr,+            GHC.Base,+            GHC.Conc,+            GHC.Conc.IO,+            GHC.Conc.Signal,+            GHC.Conc.Sync,+            GHC.ConsoleHandler,+            GHC.Constants,+            GHC.Desugar,+            GHC.Enum,+            GHC.Environment,+            GHC.Err,+            GHC.Exception,+            GHC.Exts,+            GHC.Fingerprint,+            GHC.Fingerprint.Type,+            GHC.Float,+            GHC.Float.ConversionUtils,+            GHC.Float.RealFracMethods,+            GHC.Foreign,+            GHC.ForeignPtr,+            GHC.Handle,+            GHC.IO,+            GHC.IO.Buffer,+            GHC.IO.BufferedIO,+            GHC.IO.Device,+            GHC.IO.Encoding,+            GHC.IO.Encoding.CodePage,+            GHC.IO.Encoding.Failure,+            GHC.IO.Encoding.Iconv,+            GHC.IO.Encoding.Latin1,+            GHC.IO.Encoding.Types,+            GHC.IO.Encoding.UTF16,+            GHC.IO.Encoding.UTF32,+            GHC.IO.Encoding.UTF8,+            GHC.IO.Exception,+            GHC.IO.FD,+            GHC.IO.Handle,+            GHC.IO.Handle.FD,+            GHC.IO.Handle.Internals,+            GHC.IO.Handle.Text,+            GHC.IO.Handle.Types,+            GHC.IO.IOMode,+            GHC.IOArray,+            GHC.IOBase,+            GHC.IORef,+            GHC.Int,+            GHC.List,+            GHC.MVar,+            GHC.Num,+            GHC.PArr,+            GHC.Pack,+            GHC.Ptr,+            GHC.Read,+            GHC.Real,+            GHC.ST,+            GHC.Stack,+            GHC.Stats,+            GHC.Show,+            GHC.Stable,+            GHC.Storable,+            GHC.STRef,+            GHC.TopHandler,+            GHC.Unicode,+            GHC.Weak,+            GHC.Word,+            System.Timeout+        if os(windows)+            exposed-modules: GHC.IO.Encoding.CodePage.Table+                             GHC.Conc.Windows+                             GHC.Windows+    }+    exposed-modules:+        Control.Applicative,+        Control.Arrow,+        Control.Category,+        Control.Concurrent,+        Control.Concurrent.Chan,+        Control.Concurrent.MVar,+        Control.Concurrent.QSem,+        Control.Concurrent.QSemN,+        Control.Concurrent.SampleVar,+        Control.Exception,+        Control.Exception.Base+        Control.OldException,+        Control.Monad,+        Control.Monad.Fix,+        Control.Monad.Instances,+        Control.Monad.ST,+        Control.Monad.ST.Safe,+        Control.Monad.ST.Unsafe,+        Control.Monad.ST.Lazy,+        Control.Monad.ST.Lazy.Safe,+        Control.Monad.ST.Lazy.Unsafe,+        Control.Monad.ST.Strict,+        Control.Monad.Zip+        Data.Bits,+        Data.Bool,+        Data.Char,+        Data.Complex,+        Data.Dynamic,+        Data.Either,+        Data.Eq,+        Data.Data,+        Data.Fixed,+        Data.Foldable+        Data.Function,+        Data.Functor,+        Data.HashTable,+        Data.IORef,+        Data.Int,+        Data.Ix,+        Data.List,+        Data.Maybe,+        Data.Monoid,+        Data.Ord,+        Data.Ratio,+        Data.STRef+        Data.STRef.Lazy+        Data.STRef.Strict+        Data.String,+        Data.Traversable+        Data.Tuple,+        Data.Typeable,+        Data.Typeable.Internal,+        Data.Unique,+        Data.Version,+        Data.Word,+        Debug.Trace,+        Foreign,+        Foreign.C,+        Foreign.C.Error,+        Foreign.C.String,+        Foreign.C.Types,+        Foreign.ForeignPtr,+        Foreign.ForeignPtr.Safe,+        Foreign.ForeignPtr.Unsafe,+        Foreign.Marshal,+        Foreign.Marshal.Alloc,+        Foreign.Marshal.Array,+        Foreign.Marshal.Error,+        Foreign.Marshal.Pool,+        Foreign.Marshal.Safe,+        Foreign.Marshal.Utils,+        Foreign.Marshal.Unsafe,+        Foreign.Ptr,+        Foreign.Safe,+        Foreign.StablePtr,+        Foreign.Storable,+        Numeric,+        Prelude,+        System.Console.GetOpt+        System.CPUTime,+        System.Environment,+        System.Exit,+        System.IO,+        System.IO.Error,+        System.IO.Unsafe,+        System.Info,+        System.Mem,+        System.Mem.StableName,+        System.Mem.Weak,+        System.Posix.Internals,+        System.Posix.Types,+        Text.ParserCombinators.ReadP,+        Text.ParserCombinators.ReadPrec,+        Text.Printf,+        Text.Read,+        Text.Read.Lex,+        Text.Show,+        Text.Show.Functions+        Unsafe.Coerce+    other-modules:+        Control.Monad.ST.Imp+        Control.Monad.ST.Lazy.Imp+        Foreign.ForeignPtr.Imp+    c-sources:+        cbits/PrelIOUtils.c+        cbits/WCsubst.c+        cbits/Win32Utils.c+        cbits/consUtils.c+        cbits/iconv.c+        cbits/inputReady.c+        cbits/selectUtils.c+        cbits/primFloat.c+        cbits/md5.c+    include-dirs: include+    includes:    HsBase.h+    install-includes:    HsBase.h HsBaseConfig.h EventConfig.h WCsubst.h consUtils.h Typeable.h+    if os(windows) {+        extra-libraries: wsock32, user32, shell32+    }+    if !os(windows) {+        exposed-modules:+            GHC.Event+        other-modules:+            GHC.Event.Array+            GHC.Event.Clock+            GHC.Event.Control+            GHC.Event.EPoll+            GHC.Event.IntMap+            GHC.Event.Internal+            GHC.Event.KQueue+            GHC.Event.Manager+            GHC.Event.PSQ+            GHC.Event.Poll+            GHC.Event.Thread+            GHC.Event.Unique+    }+    -- We need to set the package name to base (without a version number)+    -- as it's magic.+    ghc-options: -package-name base+    nhc98-options: -H4M -K3M+    extensions: CPP+}
+ TestSuite/inputs/MainModule/cabals/ghc-prim.cabal view
@@ -0,0 +1,48 @@+name:           ghc-prim+version:        0.2.0.0+license:        BSD3+license-file:   LICENSE+maintainer:     libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29+synopsis:       GHC primitives+description:+    GHC primitives.+cabal-version:  >=1.6+build-type: Custom++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/ghc-prim.git/++flag include-ghc-prim {+    Description: Include GHC.Prim in exposed-modules+    default: False+}++Library {+    build-depends: rts+    exposed-modules:+        GHC.Classes+        GHC.CString+        GHC.Debug+        GHC.Generics+        GHC.Magic+        GHC.PrimopWrappers+        GHC.IntWord64+        GHC.Tuple+        GHC.Types++    if flag(include-ghc-prim) {+        exposed-modules: GHC.Prim+    }++    c-sources:+        cbits/debug.c+        cbits/longlong.c+        cbits/popcnt.c+    extensions: CPP, MagicHash, ForeignFunctionInterface, UnliftedFFITypes,+                UnboxedTuples, EmptyDataDecls, NoImplicitPrelude+    -- We need to set the package name to ghc-prim (without a version number)+    -- as it's magic.+    ghc-options: -package-name ghc-prim+}
+ TestSuite/inputs/MainModule/cabals/integer-gmp.cabal view
@@ -0,0 +1,36 @@+name:           integer-gmp+version:        0.4.0.0+license:        BSD3+license-file:   LICENSE+maintainer:     libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29+synopsis:       Integer library based on GMP+description:+    This package contains an Integer library based on GMP.+cabal-version:  >=1.6+build-type: Configure++extra-source-files:+  cbits/float.c+  cbits/alloc.c+  cbits/longlong.c++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/integer-gmp.git/++Library {+    build-depends: ghc-prim+    exposed-modules: GHC.Integer+                     GHC.Integer.GMP.Internals+                     GHC.Integer.GMP.Prim+                     GHC.Integer.Logarithms+                     GHC.Integer.Logarithms.Internals+    other-modules: GHC.Integer.Type+    extensions: CPP, MagicHash, UnboxedTuples, NoImplicitPrelude,+                ForeignFunctionInterface, UnliftedFFITypes+    c-sources: cbits/cbits.c+    -- We need to set the package name to integer-gmp+    -- (without a version number) as it's magic.+    ghc-options: -package-name integer-gmp+}
+ TestSuite/inputs/MainModule/cabals/old-locale.cabal view
@@ -0,0 +1,23 @@+name:		old-locale+version:	1.0.0.4+license:	BSD3+license-file:	LICENSE+maintainer:	libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29+synopsis:	locale library+category:       System+description:+    This package provides the old locale library.+    For new code, the new locale library is recommended.+build-type: Simple+Cabal-Version: >= 1.6++Library+    exposed-modules:+        System.Locale+    build-depends: base >= 3 && < 5++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/old-locale.git/+
+ TestSuite/inputs/MainModule/cabals/old-time.cabal view
@@ -0,0 +1,38 @@+name:		old-time+version:	1.1.0.0+license:	BSD3+license-file:	LICENSE+maintainer:	libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/old-time+synopsis:	Time library+category:	System+description:+	This package provides the old time library.+    For new code, the new time library is recommended.+build-type: Configure+extra-source-files:+        aclocal.m4+        config.guess config.sub install-sh+        configure.ac configure+        include/HsTimeConfig.h.in+extra-tmp-files:+        config.log config.status autom4te.cache+        include/HsTimeConfig.h+Cabal-Version: >= 1.6++Library+    exposed-modules:+        System.Time+    c-sources:+        cbits/timeUtils.c+    include-dirs: include+    includes:	HsTime.h+    install-includes:	HsTime.h HsTimeConfig.h+    extensions:	CPP, ForeignFunctionInterface+    build-depends: base >= 4.4 && < 5, old-locale+    nhc98-options: -K2M++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/old-time.git/+
+ TestSuite/inputs/MainModule/cabals/parallel.cabal view
@@ -0,0 +1,33 @@+name:		parallel+version:        3.2.0.3+license:	BSD3+license-file:	LICENSE+maintainer:	libraries@haskell.org+synopsis:	Parallel programming library+description:+    This package provides a library for parallel programming.+category:       Control+build-type:     Simple+cabal-version:  >=1.6++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/parallel.git/++library {+  exposed-modules:+        Control.Seq+        Control.Parallel+        Control.Parallel.Strategies+  extensions:	CPP BangPatterns+  build-depends: base    >= 3 && < 5,+                 deepseq >= 1.1 && < 1.4,+                 containers >= 0.1 && < 0.6,+                 array      >= 0.1 && < 0.5+  ghc-options: -Wall++  if impl(ghc >= 6.11) {+    -- To improve parallel performance:+    ghc-options: -feager-blackholing+  }+}
+ TestSuite/inputs/Puns/GHC/RTS/EventLogFormat.h view
@@ -0,0 +1,282 @@+/* -----------------------------------------------------------------------------+ *+ * (c) The GHC Team, 2008-2012+ *+ * Event log format+ *+ * The log format is designed to be extensible: old tools should be+ * able to parse (but not necessarily understand all of) new versions+ * of the format, and new tools will be able to understand old log+ * files.+ *+ * Each event has a specific format.  If you add new events, give them+ * new numbers: we never re-use old event numbers.+ *+ * - The format is endian-independent: all values are represented in+ *    bigendian order.+ *+ * - The format is extensible:+ *+ *    - The header describes each event type and its length.  Tools+ *      that don't recognise a particular event type can skip those events.+ *+ *    - There is room for extra information in the event type+ *      specification, which can be ignored by older tools.+ *+ *    - Events can have extra information added, but existing fields+ *      cannot be changed.  Tools should ignore extra fields at the+ *      end of the event record.+ *+ *    - Old event type ids are never re-used; just take a new identifier.+ *+ *+ * The format+ * ----------+ *+ * log : EVENT_HEADER_BEGIN+ *       EventType*+ *       EVENT_HEADER_END+ *       EVENT_DATA_BEGIN+ *       Event*+ *       EVENT_DATA_END+ *+ * EventType :+ *       EVENT_ET_BEGIN+ *       Word16         -- unique identifier for this event+ *       Int16          -- >=0  size of the event in bytes (minus the header)+ *                      -- -1   variable size+ *       Word32         -- length of the next field in bytes+ *       Word8*         -- string describing the event+ *       Word32         -- length of the next field in bytes+ *       Word8*         -- extra info (for future extensions)+ *       EVENT_ET_END+ *+ * Event :+ *       Word16         -- event_type+ *       Word64         -- time (nanosecs)+ *       [Word16]       -- length of the rest (for variable-sized events only)+ *       ... extra event-specific info ...+ *+ *+ * To add a new event+ * ------------------+ *+ *  - In this file:+ *    - give it a new number, add a new #define EVENT_XXX below+ *  - In EventLog.c+ *    - add it to the EventDesc array+ *    - emit the event type in initEventLogging()+ *    - emit the new event in postEvent_()+ *    - generate the event itself by calling postEvent() somewhere+ *  - In the Haskell code to parse the event log file:+ *    - add types and code to read the new event+ *+ * -------------------------------------------------------------------------- */++#ifndef RTS_EVENTLOGFORMAT_H+#define RTS_EVENTLOGFORMAT_H++/*+ * Markers for begin/end of the Header.+ */+#define EVENT_HEADER_BEGIN    0x68647262 /* 'h' 'd' 'r' 'b' */+#define EVENT_HEADER_END      0x68647265 /* 'h' 'd' 'r' 'e' */++#define EVENT_DATA_BEGIN      0x64617462 /* 'd' 'a' 't' 'b' */+#define EVENT_DATA_END        0xffff++/*+ * Markers for begin/end of the list of Event Types in the Header.+ * Header, Event Type, Begin = hetb+ * Header, Event Type, End = hete+ */+#define EVENT_HET_BEGIN       0x68657462 /* 'h' 'e' 't' 'b' */+#define EVENT_HET_END         0x68657465 /* 'h' 'e' 't' 'e' */++#define EVENT_ET_BEGIN        0x65746200 /* 'e' 't' 'b' 0 */+#define EVENT_ET_END          0x65746500 /* 'e' 't' 'e' 0 */++/*+ * Types of event+ */+#define EVENT_CREATE_THREAD        0 /* (thread)               */+#define EVENT_RUN_THREAD           1 /* (thread)               */+#define EVENT_STOP_THREAD          2 /* (thread, status, blockinfo) */+#define EVENT_THREAD_RUNNABLE      3 /* (thread)               */+#define EVENT_MIGRATE_THREAD       4 /* (thread, new_cap)      */+/* 5, 6, 7 deprecated */+#define EVENT_THREAD_WAKEUP        8 /* (thread, other_cap)    */+#define EVENT_GC_START             9 /* ()                     */+#define EVENT_GC_END              10 /* ()                     */+#define EVENT_REQUEST_SEQ_GC      11 /* ()                     */+#define EVENT_REQUEST_PAR_GC      12 /* ()                     */+/* 13, 14 deprecated */+#define EVENT_CREATE_SPARK_THREAD 15 /* (spark_thread)         */+#define EVENT_LOG_MSG             16 /* (message ...)          */+/* EVENT_STARTUP should be deprecated at some point */+#define EVENT_STARTUP             17 /* (num_capabilities)     */+#define EVENT_BLOCK_MARKER        18 /* (size, end_time, capability) */+#define EVENT_USER_MSG            19 /* (message ...)          */+#define EVENT_GC_IDLE             20 /* () */+#define EVENT_GC_WORK             21 /* () */+#define EVENT_GC_DONE             22 /* () */+/* 23, 24 used by eden */+#define EVENT_CAPSET_CREATE       25 /* (capset, capset_type)  */+#define EVENT_CAPSET_DELETE       26 /* (capset)               */+#define EVENT_CAPSET_ASSIGN_CAP   27 /* (capset, cap)          */+#define EVENT_CAPSET_REMOVE_CAP   28 /* (capset, cap)          */+/* the RTS identifier is in the form of "GHC-version rts_way"  */+#define EVENT_RTS_IDENTIFIER      29 /* (capset, name_version_string) */+/* the vectors in these events are null separated strings             */+#define EVENT_PROGRAM_ARGS        30 /* (capset, commandline_vector)  */+#define EVENT_PROGRAM_ENV         31 /* (capset, environment_vector)  */+#define EVENT_OSPROCESS_PID       32 /* (capset, pid)          */+#define EVENT_OSPROCESS_PPID      33 /* (capset, parent_pid)   */+#define EVENT_SPARK_COUNTERS      34 /* (crt,dud,ovf,cnv,gcd,fiz,rem) */+#define EVENT_SPARK_CREATE        35 /* ()                     */+#define EVENT_SPARK_DUD           36 /* ()                     */+#define EVENT_SPARK_OVERFLOW      37 /* ()                     */+#define EVENT_SPARK_RUN           38 /* ()                     */+#define EVENT_SPARK_STEAL         39 /* (victim_cap)           */+#define EVENT_SPARK_FIZZLE        40 /* ()                     */+#define EVENT_SPARK_GC            41 /* ()                     */+#define EVENT_INTERN_STRING       42 /* (string, id) {not used by ghc} */+#define EVENT_WALL_CLOCK_TIME     43 /* (capset, unix_epoch_seconds, nanoseconds) */+#define EVENT_THREAD_LABEL        44 /* (thread, name_string)  */+#define EVENT_CAP_CREATE          45 /* (cap)                  */+#define EVENT_CAP_DELETE          46 /* (cap)                  */+#define EVENT_CAP_DISABLE         47 /* (cap)                  */+#define EVENT_CAP_ENABLE          48 /* (cap)                  */+#define EVENT_HEAP_ALLOCATED      49 /* (heap_capset, alloc_bytes) */+#define EVENT_HEAP_SIZE           50 /* (heap_capset, size_bytes) */+#define EVENT_HEAP_LIVE           51 /* (heap_capset, live_bytes) */+#define EVENT_HEAP_INFO_GHC       52 /* (heap_capset, n_generations,+                                         max_heap_size, alloc_area_size,+                                         mblock_size, block_size) */+#define EVENT_GC_STATS_GHC        53 /* (heap_capset, generation,+                                         copied_bytes, slop_bytes, frag_bytes,+                                         par_n_threads,+                                         par_max_copied, par_tot_copied) */+#define EVENT_GC_GLOBAL_SYNC      54 /* ()                     */+#define EVENT_TASK_CREATE         55 /* (taskID, cap, tid)       */+#define EVENT_TASK_MIGRATE        56 /* (taskID, cap, new_cap)   */+#define EVENT_TASK_DELETE         57 /* (taskID)                 */+#define EVENT_USER_MARKER         58 /* (marker_name) */++/* Range 59 - 59 is available for new GHC and common events. */++/* Range 60 - 80 is used by eden for parallel tracing+ * see http://www.mathematik.uni-marburg.de/~eden/+ */++/* Range 100 - 139 is reserved for Mercury, see below. */++/* Range 140 - 159 is reserved for Perf events, see below. */++/*+ * The highest event code +1 that ghc itself emits. Note that some event+ * ranges higher than this are reserved but not currently emitted by ghc.+ * This must match the size of the EventDesc[] array in EventLog.c+ */+#define NUM_GHC_EVENT_TAGS        59+++/* DEPRECATED EVENTS: */+/* These two are deprecated because we don't need to record the thread, it's+   implicit. We have to keep these #defines because for tiresome reasons we+   still need to parse them, see GHC.RTS.Events.ghc6Parsers for details. */+#define EVENT_RUN_SPARK            5 /* (thread)               */+#define EVENT_STEAL_SPARK          6 /* (thread, victim_cap)   */+/* shutdown replaced by EVENT_CAP_DELETE */+#define EVENT_SHUTDOWN             7 /* ()                     */+#if 0+/* ghc changed how it handles sparks so these are no longer applicable */+#define EVENT_CREATE_SPARK        13 /* (cap, thread) */+#define EVENT_SPARK_TO_THREAD     14 /* (cap, thread, spark_thread) */+/* these are used by eden but are replaced by new alternatives for ghc */+#define EVENT_VERSION             23 /* (version_string) */+#define EVENT_PROGRAM_INVOCATION  24 /* (commandline_string) */+#endif+++/*+ * These event types are Mercury specific, Mercury may use up to event number+ * 139+ */+#define EVENT_FIRST_MER_EVENT       100+#define NUM_MER_EVENTS               14++#define EVENT_MER_START_PAR_CONJUNCTION 100 /* (dyn id, static id) */+#define EVENT_MER_STOP_PAR_CONJUNCTION  101 /* (dyn id) */+#define EVENT_MER_STOP_PAR_CONJUNCT     102 /* (dyn id) */+#define EVENT_MER_CREATE_SPARK          103 /* (dyn id, spark id) */+#define EVENT_MER_FUT_CREATE            104 /* (fut id, memo'd name id) */+#define EVENT_MER_FUT_WAIT_NOSUSPEND    105 /* (fut id) */+#define EVENT_MER_FUT_WAIT_SUSPENDED    106 /* (fut id) */+#define EVENT_MER_FUT_SIGNAL            107 /* (fut id) */+#define EVENT_MER_LOOKING_FOR_GLOBAL_CONTEXT \+                                        108 /* () */+#define EVENT_MER_WORK_STEALING         109 /* () */+#define EVENT_MER_LOOKING_FOR_LOCAL_SPARK \+                                        112 /* () */+#define EVENT_MER_RELEASE_CONTEXT       110 /* (context id) */+#define EVENT_MER_ENGINE_SLEEPING       111 /* () */+#define EVENT_MER_CALLING_MAIN          113 /* () */+++/*+ * These event types are parsed from hardware performance counters logs,+ * such as the Linux Performance Counters data available through+ * the perf subsystem.+ */++#define EVENT_PERF_NAME           140 /* (perf_num, name) */+#define EVENT_PERF_COUNTER        141 /* (perf_num, tid, period) */+#define EVENT_PERF_TRACEPOINT     142 /* (perf_num, tid) */+++/*+ * Status values for EVENT_STOP_THREAD+ *+ * 1-5 are the StgRun return values (from includes/Constants.h):+ *+ * #define HeapOverflow   1+ * #define StackOverflow  2+ * #define ThreadYielding 3+ * #define ThreadBlocked  4+ * #define ThreadFinished 5+ * #define ForeignCall                  6+ * #define BlockedOnMVar                7+ * #define BlockedOnBlackHole           8+ * #define BlockedOnRead                9+ * #define BlockedOnWrite               10+ * #define BlockedOnDelay               11+ * #define BlockedOnSTM                 12+ * #define BlockedOnDoProc              13+ * #define BlockedOnCCall               -- not used (see ForeignCall)+ * #define BlockedOnCCall_NoUnblockExc  -- not used (see ForeignCall)+ * #define BlockedOnMsgThrowTo          16+ */+#define THREAD_SUSPENDED_FOREIGN_CALL 6++/*+ * Capset type values for EVENT_CAPSET_CREATE+ */+#define CAPSET_TYPE_CUSTOM      1  /* reserved for end-user applications */+#define CAPSET_TYPE_OSPROCESS   2  /* caps belong to the same OS process */+#define CAPSET_TYPE_CLOCKDOMAIN 3  /* caps share a local clock/time      */++#ifndef EVENTLOG_CONSTANTS_ONLY++typedef StgWord16 EventTypeNum;+typedef StgWord64 EventTimestamp; /* in nanoseconds */+typedef StgWord32 EventThreadID;+typedef StgWord16 EventCapNo;+typedef StgWord16 EventPayloadSize; /* variable-size events */+typedef StgWord16 EventThreadStatus; /* status for EVENT_STOP_THREAD */+typedef StgWord32 EventCapsetID;+typedef StgWord16 EventCapsetType;   /* types for EVENT_CAPSET_CREATE */++#endif++#endif /* RTS_EVENTLOGFORMAT_H */
+ TestSuite/inputs/Puns/GHC/RTS/EventParserUtils.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE CPP, FlexibleContexts #-}+{-# OPTIONS_GHC -fwarn-incomplete-patterns -fno-warn-deprecations #-}++module GHC.RTS.EventParserUtils (+        EventParser(..),+        EventParsers(..),+        GetEvents,+        GetHeader,++        getE,+        getH,+        getString,+        mkEventTypeParsers,+        simpleEvent,+        skip,+    ) where++import Control.Monad+import Control.Monad.Error+import Control.Monad.Reader+import Data.Array+import Data.Binary+import Data.Binary.Get hiding (skip)+import qualified Data.Binary.Get as G+import Data.Binary.Put+import Data.Char+import Data.Function+import Data.IntMap (IntMap)+import qualified Data.IntMap as M+import Data.List++#define EVENTLOG_CONSTANTS_ONLY+-- #include "EventLogFormat.h"++import GHC.RTS.EventTypes++-- reader/Get monad that passes around the event types+type GetEvents a = ReaderT EventParsers (ErrorT String Get) a++newtype EventParsers = EventParsers (Array Int (GetEvents EventInfo))++type GetHeader a = ErrorT String Get a++getH :: Binary a => GetHeader a+getH = lift get++getE :: Binary a => GetEvents a+getE = lift $ lift get++nBytes :: Integral a => a -> GetEvents [Word8]+nBytes n = replicateM (fromIntegral n) getE++getString :: Integral a => a -> GetEvents String+getString len = do+    bytes <- nBytes len+    return $ map (chr . fromIntegral) bytes++skip :: Integral a => a -> GetEvents ()+skip n = lift $ lift $ G.skip (fromIntegral n)++--+-- Code to build the event parser table.+--++--+-- Event parser data.  Parsers are either fixed or vairable size.+--+data EventParser a+    = FixedSizeParser {+        fsp_type        :: Int,+        fsp_size        :: EventTypeSize,+        fsp_parser      :: GetEvents a+    }+    | VariableSizeParser {+        vsp_type        :: Int,+        vsp_parser      :: GetEvents a+    }++get_parser (FixedSizeParser _ _ p) = p+get_parser (VariableSizeParser _ p) = p++get_type (FixedSizeParser t _ _) = t+get_type (VariableSizeParser t _) = t++isFixedSize (FixedSizeParser {}) = True+isFixedSize (VariableSizeParser {}) = False++simpleEvent :: Int -> a -> EventParser a+simpleEvent t p = FixedSizeParser t 0 (return p)++-- Our event log format allows new fields to be added to events over+-- time.  This means that our parser must be able to handle:+--+--  * old versions of an event, with fewer fields than expected,+--  * new versions of an event, with more fields than expected+--+-- The event log file declares the size for each event type, so we can+-- select the correct parser for the event type based on its size.  We+-- do this once after parsing the header: given the EventTypes, we build+-- an array of event parsers indexed by event type.+--+-- For each event type, we may have multiple parsers for different+-- versions of the event, indexed by size.  These are listed in the+-- eventTypeParsers list below.  For the given log file we select the+-- parser for the most recent version (largest size less than the size+-- declared in the header).  If this is a newer version of the event+-- than we understand, there may be extra bytes that we have to read+-- and discard in the parser for this event type.+--+-- Summary:+--   if size is smaller that we expect:+--     parse the earier version, or ignore the event+--   if size is just right:+--     parse it+--   if size is too big:+--     parse the bits we understand and discard the rest++mkEventTypeParsers :: IntMap EventType+                   -> [EventParser EventInfo]+                   -> Array Int (GetEvents EventInfo)+mkEventTypeParsers etypes event_parsers+ = accumArray (flip const) undefined (0, max_event_num)+    [ (num, parser num) | num <- [0..max_event_num] ]+    --([ (num, undeclared_etype num) | num <- [0..max_event_num] ] +++    -- [ (num, parser num etype) | (num, etype) <- M.toList etypes ])+  where+    max_event_num = maximum (M.keys etypes)+    undeclared_etype num = throwError ("undeclared event type: " ++ show num)+    parser_map = makeParserMap event_parsers+    parser num =+            -- Get the event's size from the header,+            -- the first Maybe describes whether the event was declared in the header.+            -- the second Maybe selects between variable and fixed size events.+        let mb_mb_et_size = do et <- M.lookup num etypes+                               return $ size et+            -- Find a parser for the event with the given size.+            maybe_parser mb_et_size = do possible <- M.lookup num parser_map+                                         best_parser <- case mb_et_size of+                                            Nothing -> getVariableParser possible+                                            Just et_size -> getFixedParser et_size possible+                                         return $ get_parser best_parser+            in case mb_mb_et_size of+                -- This event is declared in the log file's header+                Just mb_et_size -> case maybe_parser mb_et_size of+                    -- And we have a valid parser for it.+                    Just p -> p+                    -- But we don't have a valid parser for it.+                    Nothing -> noEventTypeParser num mb_et_size+                -- This event is not declared in the log file's header+                Nothing -> undeclared_etype num++-- Find the first variable length parser.+getVariableParser :: [EventParser a] -> Maybe (EventParser a)+getVariableParser [] = Nothing+getVariableParser (x:xs) = case x of+    FixedSizeParser _ _ _ -> getVariableParser xs+    VariableSizeParser _ _ -> Just x++-- Find the best fixed size parser, that is to say, the parser for the largest+-- event that does not exceed the size of the event as declared in the log+-- file's header.+getFixedParser :: EventTypeSize -> [EventParser a] -> Maybe (EventParser a)+getFixedParser size parsers =+        do parser <- ((filter isFixedSize) `pipe`+                      (filter (\x -> (fsp_size x) <= size)) `pipe`+                      (sortBy descending_size) `pipe`+                      maybe_head) parsers+           return $ padParser size parser+    where pipe f g = g . f+          descending_size (FixedSizeParser _ s1 _) (FixedSizeParser _ s2 _) =+            compare s2 s1+          descending_size _ _ = undefined+          maybe_head [] = Nothing+          maybe_head (x:xs) = Just x++padParser :: EventTypeSize -> (EventParser a) -> (EventParser a)+padParser size (VariableSizeParser t p) = VariableSizeParser t p+padParser size (FixedSizeParser t orig_size orig_p) = FixedSizeParser t size p+    where p = if (size == orig_size)+                then orig_p+                else do d <- orig_p+                        skip (size - orig_size)+                        return d++makeParserMap :: [EventParser a] -> IntMap [EventParser a]+makeParserMap = foldl buildParserMap M.empty+    where buildParserMap map parser = M.alter (addParser parser) (get_type parser) map+          addParser p Nothing = Just [p]+          addParser p (Just ps) = Just (p:ps)++noEventTypeParser :: Int -> Maybe EventTypeSize+                  -> GetEvents EventInfo+noEventTypeParser num mb_size = do+  bytes <- case mb_size of+             Just n  -> return n+             Nothing -> getE :: GetEvents Word16+  skip bytes+  return UnknownEvent{ ref = fromIntegral num }
+ TestSuite/inputs/Puns/GHC/RTS/EventTypes.hs view
@@ -0,0 +1,389 @@+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}++module GHC.RTS.EventTypes where++import Data.Word (Word8, Word16, Word32, Word64)+import Data.Binary++-- EventType.+type EventTypeNum = Word16+type EventTypeDescLen = Word32+type EventTypeDesc = String+type EventTypeSize = Word16+-- Event.+type EventDescription = String+type Timestamp = Word64+type ThreadId = Word32+type CapNo = Word16+type Marker = Word32+type BlockSize = Word32+type RawThreadStopStatus = Word16+type StringId = Word32+type Capset   = Word32+type PerfEventTypeNum = Word32+type TaskId = Word64+type PID = Word32++newtype KernelThreadId = KernelThreadId { kernelThreadId :: Word64 }+  deriving (Eq, Ord, Show)+instance Binary KernelThreadId where+  put (KernelThreadId tid) = put tid+  get = fmap KernelThreadId get++-- These types are used by Mercury events.+type ParConjDynId = Word64+type ParConjStaticId = StringId+type SparkId = Word32+type FutureId = Word64++sz_event_type_num :: EventTypeSize+sz_event_type_num = 2+sz_cap :: EventTypeSize+sz_cap  = 2+sz_time :: EventTypeSize+sz_time = 8+sz_tid :: EventTypeSize+sz_tid  = 4+sz_old_tid :: EventTypeSize+sz_old_tid  = 8 -- GHC 6.12 was using 8 for ThreadID when declaring the size+                -- of events, but was actually using 32 bits for ThreadIDs+sz_capset :: EventTypeSize+sz_capset = 4+sz_capset_type :: EventTypeSize+sz_capset_type = 2+sz_block_size :: EventTypeSize+sz_block_size = 4+sz_block_event :: EventTypeSize+sz_block_event = fromIntegral (sz_event_type_num + sz_time + sz_block_size+    + sz_time + sz_cap)+sz_pid :: EventTypeSize+sz_pid = 4+sz_taskid :: EventTypeSize+sz_taskid = 8+sz_kernel_tid :: EventTypeSize+sz_kernel_tid = 8+sz_th_stop_status :: EventTypeSize+sz_th_stop_status = 2+sz_string_id :: EventTypeSize+sz_string_id = 4+sz_perf_num :: EventTypeSize+sz_perf_num = 4++-- Sizes for Mercury event fields.+sz_par_conj_dyn_id :: EventTypeSize+sz_par_conj_dyn_id = 8+sz_par_conj_static_id :: EventTypeSize+sz_par_conj_static_id = sz_string_id+sz_spark_id :: EventTypeSize+sz_spark_id = 4+sz_future_id :: EventTypeSize+sz_future_id = 8++{-+ - Data type delcarations to build the GHC RTS data format,+ - which is a (header, data) pair.+ -+ - Header contains EventTypes.+ - Data contains Events.+ -}+data EventLog =+  EventLog {+    header :: Header,+    dat    :: Data+  } deriving Show++newtype Header = Header {+     eventTypes :: [EventType]+  } deriving (Show, Eq)++data Data = Data {+     events :: [Event]+  } deriving Show++data EventType =+  EventType {+    num  :: EventTypeNum,+    desc :: EventTypeDesc,+    size :: Maybe EventTypeSize -- ^ 'Nothing' indicates variable size+  } deriving (Show, Eq)++data Event =+  Event {+    time :: {-# UNPACK #-}!Timestamp,+    spec :: EventInfo+  } deriving Show++data EventInfo++  -- pseudo events+  = EventBlock         { end_time     :: Timestamp,+                         cap          :: Int,+                         block_events :: [Event]+                       }+  | UnknownEvent       { ref  :: {-# UNPACK #-}!EventTypeNum }++  -- init and shutdown+  | Startup            { n_caps :: Int+                       }+  -- EVENT_SHUTDOWN is replaced by EVENT_CAP_DELETE and GHC 7.6++  -- no longer generate the event; should be removed at some point+  | Shutdown           { }++  -- thread scheduling+  | CreateThread       { thread :: {-# UNPACK #-}!ThreadId+                       }+  | RunThread          { thread :: {-# UNPACK #-}!ThreadId+                       }+  | StopThread         { thread :: {-# UNPACK #-}!ThreadId,+                         status :: ThreadStopStatus+                       }+  | ThreadRunnable     { thread :: {-# UNPACK #-}!ThreadId+                       }+  | MigrateThread      { thread :: {-# UNPACK #-}!ThreadId,+                         newCap :: {-# UNPACK #-}!Int+                       }+  | WakeupThread       { thread :: {-# UNPACK #-}!ThreadId,+                         otherCap :: {-# UNPACK #-}!Int+                       }+  | ThreadLabel        { thread :: {-# UNPACK #-}!ThreadId,+                         threadlabel :: String+                       }++  -- par sparks+  | CreateSparkThread  { sparkThread :: {-# UNPACK #-}!ThreadId+                       }+  | SparkCounters      { sparksCreated, sparksDud, sparksOverflowed,+                         sparksConverted, sparksFizzled, sparksGCd,+                         sparksRemaining :: {-# UNPACK #-}! Word64+                       }+  | SparkCreate        { }+  | SparkDud           { }+  | SparkOverflow      { }+  | SparkRun           { }+  | SparkSteal         { victimCap :: {-# UNPACK #-}!Int }+  | SparkFizzle        { }+  | SparkGC            { }++  -- tasks+  | TaskCreate         { taskId :: TaskId,+                         cap :: {-# UNPACK #-}!Int,+                         tid :: {-# UNPACK #-}!KernelThreadId+                       }+  | TaskMigrate        { taskId :: TaskId,+                         cap :: {-# UNPACK #-}!Int,+                         new_cap :: {-# UNPACK #-}!Int+                       }+  | TaskDelete         { taskId :: TaskId }++  -- garbage collection+  | RequestSeqGC       { }+  | RequestParGC       { }+  | StartGC            { }+  | GCWork             { }+  | GCIdle             { }+  | GCDone             { }+  | EndGC              { }+  | GlobalSyncGC       { }+  | GCStatsGHC         { heapCapset   :: {-# UNPACK #-}!Capset+                       , gen          :: {-# UNPACK #-}!Int+                       , copied       :: {-# UNPACK #-}!Word64+                       , slop, frag   :: {-# UNPACK #-}!Word64+                       , parNThreads  :: {-# UNPACK #-}!Int+                       , parMaxCopied :: {-# UNPACK #-}!Word64+                       , parTotCopied :: {-# UNPACK #-}!Word64+                       }++  -- heap statistics+  | HeapAllocated      { heapCapset  :: {-# UNPACK #-}!Capset+                       , allocBytes  :: {-# UNPACK #-}!Word64+                       }+  | HeapSize           { heapCapset  :: {-# UNPACK #-}!Capset+                       , sizeBytes   :: {-# UNPACK #-}!Word64+                       }+  | HeapLive           { heapCapset  :: {-# UNPACK #-}!Capset+                       , liveBytes   :: {-# UNPACK #-}!Word64+                       }+  | HeapInfoGHC        { heapCapset    :: {-# UNPACK #-}!Capset+                       , gens          :: {-# UNPACK #-}!Int+                       , maxHeapSize   :: {-# UNPACK #-}!Word64+                       , allocAreaSize :: {-# UNPACK #-}!Word64+                       , mblockSize    :: {-# UNPACK #-}!Word64+                       , blockSize     :: {-# UNPACK #-}!Word64+                       }++  -- adjusting the number of capabilities on the fly+  | CapCreate          { cap :: {-# UNPACK #-}!Int+                       }+  | CapDelete          { cap :: {-# UNPACK #-}!Int+                       }+  | CapDisable         { cap :: {-# UNPACK #-}!Int+                       }+  | CapEnable          { cap :: {-# UNPACK #-}!Int+                       }++  -- capability sets+  | CapsetCreate       { capset     :: {-# UNPACK #-}!Capset+                       , capsetType :: CapsetType+                       }+  | CapsetDelete       { capset :: {-# UNPACK #-}!Capset+                       }+  | CapsetAssignCap    { capset :: {-# UNPACK #-}!Capset+                       , cap    :: {-# UNPACK #-}!Int+                       }+  | CapsetRemoveCap    { capset :: {-# UNPACK #-}!Capset+                       , cap    :: {-# UNPACK #-}!Int+                       }++  -- program/process info+  | RtsIdentifier      { capset :: {-# UNPACK #-}!Capset+                       , rtsident :: String+                       }+  | ProgramArgs        { capset :: {-# UNPACK #-}!Capset+                       , args   :: [String]+                       }+  | ProgramEnv         { capset :: {-# UNPACK #-}!Capset+                       , env    :: [String]+                       }+  | OsProcessPid       { capset :: {-# UNPACK #-}!Capset+                       , pid    :: {-# UNPACK #-}!PID+                       }+  | OsProcessParentPid { capset :: {-# UNPACK #-}!Capset+                       , ppid   :: {-# UNPACK #-}!PID+                       }+  | WallClockTime      { capset :: {-# UNPACK #-}!Capset+                       , sec    :: {-# UNPACK #-}!Word64+                       , nsec   :: {-# UNPACK #-}!Word32+                       }++  -- messages+  | Message            { msg :: String }+  | UserMessage        { msg :: String }+  | UserMarker         { markername :: String }++  -- These events have been added for Mercury's benifit but are generally+  -- useful.+  | InternString       { str :: String, sId :: {-# UNPACK #-}!StringId }++  -- Mercury specific events.+  | MerStartParConjunction {+        dyn_id      :: {-# UNPACK #-}!ParConjDynId,+        static_id   :: {-# UNPACK #-}!ParConjStaticId+    }+  | MerEndParConjunction {+        dyn_id      :: {-# UNPACK #-}!ParConjDynId+    }+  | MerEndParConjunct {+        dyn_id      :: {-# UNPACK #-}!ParConjDynId+    }+  | MerCreateSpark {+        dyn_id      :: {-# UNPACK #-}!ParConjDynId,+        spark_id    :: {-# UNPACK #-}!SparkId+    }+  | MerFutureCreate {+        future_id   :: {-# UNPACK #-}!FutureId,+        name_id     :: {-# UNPACK #-}!StringId+    }+  | MerFutureWaitNosuspend {+        future_id   :: {-# UNPACK #-}!FutureId+    }+  | MerFutureWaitSuspended {+        future_id   :: {-# UNPACK #-}!FutureId+    }+  | MerFutureSignal {+        future_id   :: {-# UNPACK #-}!FutureId+    }+  | MerLookingForGlobalThread+  | MerWorkStealing+  | MerLookingForLocalSpark+  | MerReleaseThread {+        thread_id   :: {-# UNPACK #-}!ThreadId+    }+  | MerCapSleeping+  | MerCallingMain++  -- perf events+  | PerfName           { perfNum :: {-# UNPACK #-}!PerfEventTypeNum+                       , name    :: String+                       }+  | PerfCounter        { perfNum :: {-# UNPACK #-}!PerfEventTypeNum+                       , tid     :: {-# UNPACK #-}!KernelThreadId+                       , period  :: {-# UNPACK #-}!Word64+                       }+  | PerfTracepoint     { perfNum :: {-# UNPACK #-}!PerfEventTypeNum+                       , tid     :: {-# UNPACK #-}!KernelThreadId+                       }++  deriving Show++--sync with ghc/includes/Constants.h+data ThreadStopStatus+ = NoStatus+ | HeapOverflow+ | StackOverflow+ | ThreadYielding+ | ThreadBlocked+ | ThreadFinished+ | ForeignCall+ | BlockedOnMVar+ | BlockedOnBlackHole+ | BlockedOnRead+ | BlockedOnWrite+ | BlockedOnDelay+ | BlockedOnSTM+ | BlockedOnDoProc+ | BlockedOnCCall+ | BlockedOnCCall_NoUnblockExc+ | BlockedOnMsgThrowTo+ | ThreadMigrating+ | BlockedOnMsgGlobalise+ | BlockedOnBlackHoleOwnedBy {-# UNPACK #-}!ThreadId+ deriving (Show)++mkStopStatus :: RawThreadStopStatus -> ThreadStopStatus+mkStopStatus n = case n of+ 0  ->  NoStatus+ 1  ->  HeapOverflow+ 2  ->  StackOverflow+ 3  ->  ThreadYielding+ 4  ->  ThreadBlocked+ 5  ->  ThreadFinished+ 6  ->  ForeignCall+ 7  ->  BlockedOnMVar+ 8  ->  BlockedOnBlackHole+ 9  ->  BlockedOnRead+ 10 ->  BlockedOnWrite+ 11 ->  BlockedOnDelay+ 12 ->  BlockedOnSTM+ 13 ->  BlockedOnDoProc+ 14 ->  BlockedOnCCall+ 15 ->  BlockedOnCCall_NoUnblockExc+ 16 ->  BlockedOnMsgThrowTo+ 17 ->  ThreadMigrating+ 18 ->  BlockedOnMsgGlobalise+ _  ->  error "mkStat"++maxThreadStopStatus :: RawThreadStopStatus+maxThreadStopStatus = 18++data CapsetType+ = CapsetCustom+ | CapsetOsProcess+ | CapsetClockDomain+ | CapsetUnknown+ deriving Show++mkCapsetType :: Word16 -> CapsetType+mkCapsetType n = case n of+ 1 -> CapsetCustom+ 2 -> CapsetOsProcess+ 3 -> CapsetClockDomain+ _ -> CapsetUnknown++-- | An event annotated with the Capability that generated it, if any+data CapEvent+  = CapEvent { ce_cap   :: Maybe Int,+               ce_event :: Event+               -- we could UNPACK ce_event, but the Event constructor+               -- might be shared, in which case we could end up+               -- increasing the space usage.+             } deriving Show
+ TestSuite/inputs/Puns/GHC/RTS/Events.hs view
@@ -0,0 +1,1367 @@+{-# LANGUAGE CPP,BangPatterns,PatternGuards #-}+{-# OPTIONS_GHC -funbox-strict-fields -fwarn-incomplete-patterns -fno-warn-deprecations #-}+{-+ -   Parser functions for GHC RTS EventLog framework.+ -}++module GHC.RTS.Events (+       main,+       -- * The event log types+       EventLog(..),+       EventType(..),+       Event(..),+       EventInfo(..),+       ThreadStopStatus(..),+       Header(..),+       Data(..),+       CapsetType(..),+       Timestamp,+       ThreadId,+       TaskId,+       KernelThreadId(..),++       -- * Reading and writing event logs+       readEventLogFromFile,+       writeEventLogToFile,++       -- * Utilities+       CapEvent(..), sortEvents, groupEvents, sortGroups,+       buildEventTypeMap,++       -- * Printing+       showEventInfo, showThreadStopStatus,+       ppEventLog, ppEventType, ppEvent,++       -- * Perf events+       nEVENT_PERF_NAME, nEVENT_PERF_COUNTER, nEVENT_PERF_TRACEPOINT,+       sz_perf_num, sz_kernel_tid+  ) where++{- Libraries. -}+import Data.Binary+import Data.Binary.Get hiding (skip)+import qualified Data.Binary.Get as G+import Data.Binary.Put+import Control.Monad+import Data.IntMap (IntMap)+import qualified Data.IntMap as M+import Control.Monad.Reader+import Control.Monad.Error+import qualified Data.ByteString.Lazy as L+import Data.Function+import Data.List+import Data.Either+import Data.Maybe+import Text.Printf+import Data.Array++import GHC.RTS.EventTypes+import GHC.RTS.EventParserUtils++#define EVENTLOG_CONSTANTS_ONLY+#include "EventLogFormat.h"++main :: IO ()+main = return ()++------------------------------------------------------------------------------+-- Binary instances++getEventType :: GetHeader EventType+getEventType = do+           etNum <- getH+           size <- getH :: GetHeader EventTypeSize+           let etSize = if size == 0xffff then Nothing else Just size+           -- 0xffff indicates variable-sized event+           etDescLen <- getH :: GetHeader EventTypeDescLen+           etDesc <- getEtDesc (fromIntegral etDescLen)+           etExtraLen <- getH :: GetHeader Word32+           lift $ G.skip (fromIntegral etExtraLen)+           ete <- getH :: GetHeader Marker+           when (ete /= EVENT_ET_END) $+              throwError ("Event Type end marker not found.")+           return (EventType etNum etDesc etSize)+           where+             getEtDesc :: Int -> GetHeader [Char]+             getEtDesc s = replicateM s (getH :: GetHeader Char)++getHeader :: GetHeader Header+getHeader = do+           hdrb <- getH :: GetHeader Marker+           when (hdrb /= EVENT_HEADER_BEGIN) $+                throwError "Header begin marker not found"+           hetm <- getH :: GetHeader Marker+           when (hetm /= EVENT_HET_BEGIN) $+                throwError "Header Event Type begin marker not found"+           ets <- getEventTypes+           emark <- getH :: GetHeader Marker+           when (emark /= EVENT_HEADER_END) $+                throwError "Header end marker not found"+           return (Header ets)+     where+       getEventTypes :: GetHeader [EventType]+       getEventTypes = do+           m <- getH :: GetHeader Marker+           case () of+            _ | m == EVENT_ET_BEGIN -> do+                   et <- getEventType+                   nextET <- getEventTypes+                   return (et : nextET)+              | m == EVENT_HET_END ->+                   return []+              | otherwise ->+                   throwError "Malformed list of Event Types in header"++getEvent :: EventParsers -> GetEvents (Maybe Event)+getEvent (EventParsers parsers) = do+  etRef <- getE :: GetEvents EventTypeNum+  if (etRef == EVENT_DATA_END)+     then return Nothing+     else do !ts   <- getE+             -- trace ("event: " ++ show etRef) $ do+             spec <- parsers ! fromIntegral etRef+             return (Just (Event ts spec))++--+-- standardEventParsers.+--+standardParsers :: [EventParser EventInfo]+standardParsers = [+ (FixedSizeParser EVENT_STARTUP sz_cap (do -- (n_caps)+      c <- getE :: GetEvents CapNo+      return Startup{ n_caps = fromIntegral c }+   )),++ (FixedSizeParser EVENT_BLOCK_MARKER (sz_block_size + sz_time + sz_cap) (do -- (size, end_time, cap)+      block_size <- getE :: GetEvents BlockSize+      end_time <- getE :: GetEvents Timestamp+      c <- getE :: GetEvents CapNo+      lbs <- lift . lift $ getLazyByteString ((fromIntegral block_size) -+                                              (fromIntegral sz_block_event))+      eparsers <- ask+      let e_events = runGet (runErrorT $ runReaderT (getEventBlock eparsers) eparsers) lbs+      return EventBlock{ end_time=end_time,+                         cap= fromIntegral c,+                         block_events=case e_events of+                                        Left s -> error s+                                        Right es -> es }+   )),++ -- EVENT_SHUTDOWN is replaced by EVENT_CAP_DELETE and GHC 7.6++ -- no longer generate the event; should be removed at some point+ (simpleEvent EVENT_SHUTDOWN Shutdown),++ (simpleEvent EVENT_REQUEST_SEQ_GC RequestSeqGC),++ (simpleEvent EVENT_REQUEST_PAR_GC RequestParGC),++ (simpleEvent EVENT_GC_START StartGC),++ (simpleEvent EVENT_GC_WORK GCWork),++ (simpleEvent EVENT_GC_IDLE GCIdle),++ (simpleEvent EVENT_GC_DONE GCDone),++ (simpleEvent EVENT_GC_END EndGC),++ (simpleEvent EVENT_GC_GLOBAL_SYNC GlobalSyncGC),++ (FixedSizeParser EVENT_GC_STATS_GHC (sz_capset + 2 + 5*8 + 4) (do  -- (heap_capset, generation, copied_bytes, slop_bytes, frag_bytes, par_n_threads, par_max_copied, par_tot_copied)+      heapCapset   <- getE+      gen          <- getE :: GetEvents Word16+      copied       <- getE :: GetEvents Word64+      slop         <- getE :: GetEvents Word64+      frag         <- getE :: GetEvents Word64+      parNThreads  <- getE :: GetEvents Word32+      parMaxCopied <- getE :: GetEvents Word64+      parTotCopied <- getE :: GetEvents Word64+      return GCStatsGHC{ gen = fromIntegral gen+                       , parNThreads = fromIntegral parNThreads+                       , ..}+ )),++ (FixedSizeParser EVENT_HEAP_ALLOCATED (sz_capset + 8) (do  -- (heap_capset, alloc_bytes)+      heapCapset <- getE+      allocBytes <- getE+      return HeapAllocated{..}+ )),++ (FixedSizeParser EVENT_HEAP_SIZE (sz_capset + 8) (do  -- (heap_capset, size_bytes)+      heapCapset <- getE+      sizeBytes  <- getE+      return HeapSize{..}+ )),++ (FixedSizeParser EVENT_HEAP_LIVE (sz_capset + 8) (do  -- (heap_capset, live_bytes)+      heapCapset <- getE+      liveBytes  <- getE+      return HeapLive{..}+ )),++ (FixedSizeParser EVENT_HEAP_INFO_GHC (sz_capset + 2 + 4*8) (do  -- (heap_capset, n_generations, max_heap_size, alloc_area_size, mblock_size, block_size)+      heapCapset    <- getE+      gens          <- getE :: GetEvents Word16+      maxHeapSize   <- getE :: GetEvents Word64+      allocAreaSize <- getE :: GetEvents Word64+      mblockSize    <- getE :: GetEvents Word64+      blockSize     <- getE :: GetEvents Word64+      return HeapInfoGHC{gens = fromIntegral gens, ..}+ )),++ (FixedSizeParser EVENT_CAP_CREATE (sz_cap) (do  -- (cap)+      cap <- getE :: GetEvents CapNo+      return CapCreate{cap = fromIntegral cap}+ )),++ (FixedSizeParser EVENT_CAP_DELETE (sz_cap) (do  -- (cap)+      cap <- getE :: GetEvents CapNo+      return CapDelete{cap = fromIntegral cap}+ )),++ (FixedSizeParser EVENT_CAP_DISABLE (sz_cap) (do  -- (cap)+      cap <- getE :: GetEvents CapNo+      return CapDisable{cap = fromIntegral cap}+ )),++ (FixedSizeParser EVENT_CAP_ENABLE (sz_cap) (do  -- (cap)+      cap <- getE :: GetEvents CapNo+      return CapEnable{cap = fromIntegral cap}+ )),++ (FixedSizeParser EVENT_CAPSET_CREATE (sz_capset + sz_capset_type) (do -- (capset, capset_type)+      cs <- getE+      ct <- fmap mkCapsetType getE+      return CapsetCreate{capset=cs,capsetType=ct}+   )),++ (FixedSizeParser EVENT_CAPSET_DELETE sz_capset (do -- (capset)+      cs <- getE+      return CapsetDelete{capset=cs}+   )),++ (FixedSizeParser EVENT_CAPSET_ASSIGN_CAP (sz_capset + sz_cap) (do -- (capset, cap)+      cs <- getE+      cp <- getE :: GetEvents CapNo+      return CapsetAssignCap{capset=cs,cap=fromIntegral cp}+   )),++ (FixedSizeParser EVENT_CAPSET_REMOVE_CAP (sz_capset + sz_cap) (do -- (capset, cap)+      cs <- getE+      cp <- getE :: GetEvents CapNo+      return CapsetRemoveCap{capset=cs,cap=fromIntegral cp}+   )),++ (FixedSizeParser EVENT_OSPROCESS_PID (sz_capset + sz_pid) (do -- (capset, pid)+      cs <- getE+      pd <- getE+      return OsProcessPid{capset=cs,pid=pd}+   )),++ (FixedSizeParser EVENT_OSPROCESS_PPID (sz_capset + sz_pid) (do -- (capset, ppid)+      cs <- getE+      pd <- getE+      return OsProcessParentPid{capset=cs,ppid=pd}+  )),++ (FixedSizeParser EVENT_WALL_CLOCK_TIME (sz_capset + 8 + 4) (do -- (capset, unix_epoch_seconds, nanoseconds)+      cs <- getE+      s  <- getE+      ns <- getE+      return WallClockTime{capset=cs,sec=s,nsec=ns}+  )),++ (VariableSizeParser EVENT_LOG_MSG (do -- (msg)+      num <- getE :: GetEvents Word16+      string <- getString num+      return Message{ msg = string }+   )),+ (VariableSizeParser EVENT_USER_MSG (do -- (msg)+      num <- getE :: GetEvents Word16+      string <- getString num+      return UserMessage{ msg = string }+   )),+    (VariableSizeParser EVENT_USER_MARKER (do -- (markername)+      num <- getE :: GetEvents Word16+      string <- getString num+      return UserMarker{ markername = string }+   )),+ (VariableSizeParser EVENT_PROGRAM_ARGS (do -- (capset, [arg])+      num <- getE :: GetEvents Word16+      cs <- getE+      string <- getString (num - sz_capset)+      return ProgramArgs{ capset = cs+                        , args = splitNull string }+   )),+ (VariableSizeParser EVENT_PROGRAM_ENV (do -- (capset, [arg])+      num <- getE :: GetEvents Word16+      cs <- getE+      string <- getString (num - sz_capset)+      return ProgramEnv{ capset = cs+                       , env = splitNull string }+   )),+ (VariableSizeParser EVENT_RTS_IDENTIFIER (do -- (capset, str)+      num <- getE :: GetEvents Word16+      cs <- getE+      string <- getString (num - sz_capset)+      return RtsIdentifier{ capset = cs+                          , rtsident = string }+   )),++ (VariableSizeParser EVENT_INTERN_STRING (do -- (str, id)+      num <- getE :: GetEvents Word16+      string <- getString (num - sz_string_id)+      sId <- getE :: GetEvents StringId+      return (InternString string sId)+    )),++ (VariableSizeParser EVENT_THREAD_LABEL (do -- (thread, str)+      num <- getE :: GetEvents Word16+      tid <- getE+      str <- getString (num - sz_tid)+      return ThreadLabel{ thread      = tid+                        , threadlabel = str }+    ))+ ]++-- Parsers valid for GHC7 but not GHC6.+ghc7Parsers :: [EventParser EventInfo]+ghc7Parsers = [+ (FixedSizeParser EVENT_CREATE_THREAD sz_tid (do  -- (thread)+      t <- getE+      return CreateThread{thread=t}+   )),++ (FixedSizeParser EVENT_RUN_THREAD sz_tid (do  --  (thread)+      t <- getE+      return RunThread{thread=t}+   )),++ (FixedSizeParser EVENT_STOP_THREAD (sz_tid + sz_th_stop_status) (do+      -- (thread, status)+      t <- getE+      s <- getE :: GetEvents RawThreadStopStatus+      return StopThread{thread=t, status = if s > maxThreadStopStatus+                                              then NoStatus+                                              else mkStopStatus s}+   )),++ (FixedSizeParser EVENT_STOP_THREAD (sz_tid + sz_th_stop_status + sz_tid) (do+      -- (thread, status, info)+      t <- getE+      s <- getE :: GetEvents RawThreadStopStatus+      i <- getE :: GetEvents ThreadId+      return StopThread{thread = t,+                        status = case () of+                                  _ | s > maxThreadStopStatus+                                    -> NoStatus+                                    | s == 8 {- XXX yeuch -}+                                    -> BlockedOnBlackHoleOwnedBy i+                                    | otherwise+                                    -> mkStopStatus s}+   )),++ (FixedSizeParser EVENT_THREAD_RUNNABLE sz_tid (do  -- (thread)+      t <- getE+      return ThreadRunnable{thread=t}+   )),++ (FixedSizeParser EVENT_MIGRATE_THREAD (sz_tid + sz_cap) (do  --  (thread, newCap)+      t  <- getE+      nc <- getE :: GetEvents CapNo+      return MigrateThread{thread=t,newCap=fromIntegral nc}+   )),++ -- Yes, EVENT_RUN/STEAL_SPARK are deprecated, but see the explanation in the+ -- 'ghc6Parsers' section below. Since we're parsing them anyway, we might+ -- as well convert them to the new SparkRun/SparkSteal events.+ (FixedSizeParser EVENT_RUN_SPARK sz_tid (do  -- (thread)+      _ <- getE :: GetEvents ThreadId+      return SparkRun+   )),++ (FixedSizeParser EVENT_STEAL_SPARK (sz_tid + sz_cap) (do  -- (thread, victimCap)+      _  <- getE :: GetEvents ThreadId+      vc <- getE :: GetEvents CapNo+      return SparkSteal{victimCap=fromIntegral vc}+   )),++ (FixedSizeParser EVENT_CREATE_SPARK_THREAD sz_tid (do  -- (sparkThread)+      st <- getE :: GetEvents ThreadId+      return CreateSparkThread{sparkThread=st}+   )),++ (FixedSizeParser EVENT_SPARK_COUNTERS (7*8) (do -- (crt,dud,ovf,cnv,gcd,fiz,rem)+      crt <- getE :: GetEvents Word64+      dud <- getE :: GetEvents Word64+      ovf <- getE :: GetEvents Word64+      cnv <- getE :: GetEvents Word64+      gcd <- getE :: GetEvents Word64+      fiz <- getE :: GetEvents Word64+      rem <- getE :: GetEvents Word64+      return SparkCounters{sparksCreated    = crt, sparksDud       = dud,+                           sparksOverflowed = ovf, sparksConverted = cnv,+                           -- Warning: order of fiz and gcd reversed!+                           sparksFizzled    = fiz, sparksGCd       = gcd,+                           sparksRemaining  = rem}+   )),++ (simpleEvent EVENT_SPARK_CREATE   SparkCreate),+ (simpleEvent EVENT_SPARK_DUD      SparkDud),+ (simpleEvent EVENT_SPARK_OVERFLOW SparkOverflow),+ (simpleEvent EVENT_SPARK_RUN      SparkRun),+ (FixedSizeParser EVENT_SPARK_STEAL sz_cap (do  -- (victimCap)+      vc <- getE :: GetEvents CapNo+      return SparkSteal{victimCap=fromIntegral vc}+   )),+ (simpleEvent EVENT_SPARK_FIZZLE   SparkFizzle),+ (simpleEvent EVENT_SPARK_GC       SparkGC),++ (FixedSizeParser EVENT_TASK_CREATE (sz_taskid + sz_cap + sz_kernel_tid) (do  -- (taskID, cap, tid)+      taskId <- getE :: GetEvents TaskId+      cap    <- getE :: GetEvents CapNo+      tid    <- getE :: GetEvents KernelThreadId+      return TaskCreate{ taskId, cap = fromIntegral cap, tid }+   )),+ (FixedSizeParser EVENT_TASK_MIGRATE (sz_taskid + sz_cap*2) (do  -- (taskID, cap, new_cap)+      taskId  <- getE :: GetEvents TaskId+      cap     <- getE :: GetEvents CapNo+      new_cap <- getE :: GetEvents CapNo+      return TaskMigrate{ taskId, cap = fromIntegral cap+                                , new_cap = fromIntegral new_cap+                        }+   )),+ (FixedSizeParser EVENT_TASK_DELETE (sz_taskid) (do  -- (taskID)+      taskId <- getE :: GetEvents TaskId+      return TaskDelete{ taskId }+   )),++ (FixedSizeParser EVENT_THREAD_WAKEUP (sz_tid + sz_cap) (do  -- (thread, other_cap)+      t <- getE+      oc <- getE :: GetEvents CapNo+      return WakeupThread{thread=t,otherCap=fromIntegral oc}+   ))+ ]++ -----------------------+ -- GHC 6.12 compat: GHC 6.12 reported the wrong sizes for some events,+ -- so we have to recognise those wrong sizes here for backwards+ -- compatibility.+ghc6Parsers :: [EventParser EventInfo]+ghc6Parsers = [+ (FixedSizeParser EVENT_STARTUP 0 (do+      -- BUG in GHC 6.12: the startup event was incorrectly+      -- declared as size 0, so we accept it here.+      c <- getE :: GetEvents CapNo+      return Startup{ n_caps = fromIntegral c }+   )),++ (FixedSizeParser EVENT_CREATE_THREAD sz_old_tid (do  -- (thread)+      t <- getE+      return CreateThread{thread=t}+   )),++ (FixedSizeParser EVENT_RUN_THREAD sz_old_tid (do  --  (thread)+      t <- getE+      return RunThread{thread=t}+   )),++ (FixedSizeParser EVENT_STOP_THREAD (sz_old_tid + 2) (do  -- (thread, status)+      t <- getE+      s <- getE :: GetEvents Word16+      let stat = fromIntegral s+      return StopThread{thread=t, status = if stat > maxBound+                                              then NoStatus+                                              else mkStopStatus stat}+   )),++ (FixedSizeParser EVENT_THREAD_RUNNABLE sz_old_tid (do  -- (thread)+      t <- getE+      return ThreadRunnable{thread=t}+   )),++ (FixedSizeParser EVENT_MIGRATE_THREAD (sz_old_tid + sz_cap) (do  --  (thread, newCap)+      t  <- getE+      nc <- getE :: GetEvents CapNo+      return MigrateThread{thread=t,newCap=fromIntegral nc}+   )),++ -- Note: it is vital that these two (EVENT_RUN/STEAL_SPARK) remain here (at+ -- least in the ghc6Parsers section) even though both events are deprecated.+ -- The reason is that .eventlog files created by the buggy GHC-6.12+ -- mis-declare the size of these two events. So we have to handle them+ -- specially here otherwise we'll get the wrong size, leading to us getting+ -- out of sync and eventual parse failure. Since we're parsing them anyway,+ -- we might as well convert them to the new SparkRun/SparkSteal events.+ (FixedSizeParser EVENT_RUN_SPARK sz_old_tid (do  -- (thread)+      _ <- getE :: GetEvents ThreadId+      return SparkRun+   )),++ (FixedSizeParser EVENT_STEAL_SPARK (sz_old_tid + sz_cap) (do  -- (thread, victimCap)+      _  <- getE :: GetEvents ThreadId+      vc <- getE :: GetEvents CapNo+      return SparkSteal{victimCap=fromIntegral vc}+   )),++ (FixedSizeParser EVENT_CREATE_SPARK_THREAD sz_old_tid (do  -- (sparkThread)+      st <- getE :: GetEvents ThreadId+      return CreateSparkThread{sparkThread=st}+   )),++ (FixedSizeParser EVENT_THREAD_WAKEUP (sz_old_tid + sz_cap) (do  -- (thread, other_cap)+      t <- getE+      oc <- getE :: GetEvents CapNo+      return WakeupThread{thread=t,otherCap=fromIntegral oc}+   ))+ ]++mercuryParsers = [+ (FixedSizeParser EVENT_MER_START_PAR_CONJUNCTION+    (sz_par_conj_dyn_id + sz_par_conj_static_id)+    (do dyn_id <- getE+        static_id <- getE+        return (MerStartParConjunction dyn_id static_id))+ ),++ (FixedSizeParser EVENT_MER_STOP_PAR_CONJUNCTION sz_par_conj_dyn_id+    (do dyn_id <- getE+        return (MerEndParConjunction dyn_id))+ ),++ (FixedSizeParser EVENT_MER_STOP_PAR_CONJUNCT sz_par_conj_dyn_id+    (do dyn_id <- getE+        return (MerEndParConjunct dyn_id))+ ),++ (FixedSizeParser EVENT_MER_CREATE_SPARK (sz_par_conj_dyn_id + sz_spark_id)+    (do dyn_id <- getE+        spark_id <- getE+        return (MerCreateSpark dyn_id spark_id))+ ),++ (FixedSizeParser EVENT_MER_FUT_CREATE (sz_future_id + sz_string_id)+    (do future_id <- getE+        name_id <- getE+        return (MerFutureCreate future_id name_id))+ ),++ (FixedSizeParser EVENT_MER_FUT_WAIT_NOSUSPEND (sz_future_id)+    (do future_id <- getE+        return (MerFutureWaitNosuspend future_id))+ ),++ (FixedSizeParser EVENT_MER_FUT_WAIT_SUSPENDED (sz_future_id)+    (do future_id <- getE+        return (MerFutureWaitSuspended future_id))+ ),++ (FixedSizeParser EVENT_MER_FUT_SIGNAL (sz_future_id)+    (do future_id <- getE+        return (MerFutureSignal future_id))+ ),++ (simpleEvent EVENT_MER_LOOKING_FOR_GLOBAL_CONTEXT MerLookingForGlobalThread),+ (simpleEvent EVENT_MER_WORK_STEALING MerWorkStealing),+ (simpleEvent EVENT_MER_LOOKING_FOR_LOCAL_SPARK MerLookingForLocalSpark),++ (FixedSizeParser EVENT_MER_RELEASE_CONTEXT sz_tid+    (do thread_id <- getE+        return (MerReleaseThread thread_id))+ ),++ (simpleEvent EVENT_MER_ENGINE_SLEEPING MerCapSleeping),+ (simpleEvent EVENT_MER_CALLING_MAIN MerCallingMain)++ ]++perfParsers = [+ (VariableSizeParser EVENT_PERF_NAME (do -- (perf_num, name)+      num     <- getE :: GetEvents Word16+      perfNum <- getE+      name    <- getString (num - sz_perf_num)+      return PerfName{perfNum, name}+   )),++ (FixedSizeParser EVENT_PERF_COUNTER (sz_perf_num + sz_kernel_tid + 8) (do -- (perf_num, tid, period)+      perfNum <- getE+      tid     <- getE+      period  <- getE+      return PerfCounter{perfNum, tid, period}+  )),++ (FixedSizeParser EVENT_PERF_TRACEPOINT (sz_perf_num + sz_kernel_tid) (do -- (perf_num, tid)+      perfNum <- getE+      tid     <- getE+      return PerfTracepoint{perfNum, tid}+  ))+ ]++getData :: GetEvents Data+getData = do+   db <- getE :: GetEvents Marker+   when (db /= EVENT_DATA_BEGIN) $ throwError "Data begin marker not found"+   eparsers <- ask+   let+       getEvents :: [Event] -> GetEvents Data+       getEvents events = do+         mb_e <- getEvent eparsers+         case mb_e of+           Nothing -> return (Data (reverse events))+           Just e  -> getEvents (e:events)+   -- in+   getEvents []++getEventBlock :: EventParsers -> GetEvents [Event]+getEventBlock parsers = do+  b <- lift . lift $ isEmpty+  if b then return [] else do+   mb_e <- getEvent parsers+   case mb_e of+     Nothing -> return []+     Just e  -> do+       es <- getEventBlock parsers+       return (e:es)++getEventLog :: ErrorT String Get EventLog+getEventLog = do+    header <- getHeader+    let imap = M.fromList [ (fromIntegral (num t),t) | t <- eventTypes header]+        -- This test is complete, no-one has extended this event yet and all future+        -- extensions will use newly allocated event IDs.+        is_ghc_6 = Just sz_old_tid == do create_et <- M.lookup EVENT_CREATE_THREAD imap+                                         size create_et+        {-+        -- GHC6 writes an invalid header, we handle it here by using a+        -- different set of event parsers.  Note that the ghc7 event parsers+        -- are standard events, and can be used by other runtime systems that+        -- make use of threadscope.+        -}+        event_parsers = if is_ghc_6+                            then standardParsers ++ ghc6Parsers+                            else standardParsers ++ ghc7Parsers+                                 ++ mercuryParsers ++ perfParsers+        parsers = mkEventTypeParsers imap event_parsers+    dat <- runReaderT getData (EventParsers parsers)+    return (EventLog header dat)++readEventLogFromFile :: FilePath -> IO (Either String EventLog)+readEventLogFromFile f = do+    s <- L.readFile f+    return $ runGet (do v <- runErrorT $ getEventLog+                        m <- isEmpty+                        m `seq` return v)  s++-- -----------------------------------------------------------------------------+-- Utilities++sortEvents :: [Event] -> [CapEvent]+sortEvents = sortGroups . groupEvents++-- | Sort the raw event stream by time, annotating each event with the+-- capability that generated it.+sortGroups :: [(Maybe Int, [Event])] -> [CapEvent]+sortGroups groups = mergesort' (compare `on` (time . ce_event)) $+                      [ [ CapEvent cap e | e <- es ]+                      | (cap, es) <- groups ]+     -- sorting is made much faster by the way that the event stream is+     -- divided into blocks of events.+     --  - All events in a block belong to a particular capability+     --  - The events in a block are ordered by time+     --  - blocks for the same capability appear in time order in the event+     --    stream and do not overlap.+     --+     -- So to sort the events we make one list of events for each+     -- capability (basically just concat . filter), and then+     -- merge the resulting lists.++groupEvents :: [Event] -> [(Maybe Int, [Event])]+groupEvents es = (Nothing, n_events) :+                 [ (Just (cap (head blocks)), concatMap block_events blocks)+                 | blocks <- groups ]+  where+   (blocks, anon_events) = partitionEithers (map separate es)+      where separate e | b@EventBlock{} <- spec e = Left  b+                       | otherwise                = Right e++   (cap_blocks, gbl_blocks) = partition (is_cap . cap) blocks+      where is_cap c = fromIntegral c /= ((-1) :: Word16)++   groups = groupBy ((==) `on` cap) $ sortBy (compare `on` cap) cap_blocks++     -- There are two sources of events without a capability: events+     -- in the raw stream not inside an EventBlock, and EventBlocks+     -- with cap == -1.  We have to merge those two streams.+     -- In light of merged logs, global blocks may have overlapping+     -- time spans, thus the blocks are mergesorted+   n_events = mergesort' (compare `on` time) (anon_events : map block_events gbl_blocks)++mergesort' :: (a -> a -> Ordering) -> [[a]] -> [a]+mergesort' _   [] = []+mergesort' _   [xs] = xs+mergesort' cmp xss = mergesort' cmp (merge_pairs cmp xss)++merge_pairs :: (a -> a -> Ordering) -> [[a]] -> [[a]]+merge_pairs _   [] = []+merge_pairs _   [xs] = [xs]+merge_pairs cmp (xs:ys:xss) = merge cmp xs ys : merge_pairs cmp xss++merge :: (a -> a -> Ordering) -> [a] -> [a] -> [a]+merge _   [] ys = ys+merge _   xs [] = xs+merge cmp (x:xs) (y:ys)+ = case x `cmp` y of+        GT -> y : merge cmp (x:xs)   ys+        _  -> x : merge cmp    xs (y:ys)+++buildEventTypeMap :: [EventType] -> IntMap EventType+buildEventTypeMap etypes = M.fromList [ (fromIntegral (num t),t) | t <- etypes ]++-----------------------------------------------------------------------------+-- Some pretty-printing support++showEventInfo :: EventInfo -> String+showEventInfo spec =+    case spec of+        EventBlock end_time cap _block_events ->+          printf "event block: cap %d, end time: %d\n" cap end_time+        Startup n_caps ->+          printf "startup: %d capabilities" n_caps+        CreateThread thread ->+          printf "creating thread %d" thread+        RunThread thread ->+          printf "running thread %d" thread+        StopThread thread status ->+          printf "stopping thread %d (%s)" thread (showThreadStopStatus status)+        ThreadRunnable thread ->+          printf "thread %d is runnable" thread+        MigrateThread thread newCap  ->+          printf "migrating thread %d to cap %d" thread newCap+        CreateSparkThread sparkThread ->+          printf "creating spark thread %d" sparkThread+        SparkCounters crt dud ovf cnv fiz gcd rem ->+          printf "spark stats: %d created, %d converted, %d remaining (%d overflowed, %d dud, %d GC'd, %d fizzled)" crt cnv rem ovf dud gcd fiz+        SparkCreate ->+          printf "spark created"+        SparkDud ->+          printf "dud spark discarded"+        SparkOverflow ->+          printf "overflowed spark discarded"+        SparkRun ->+          printf "running a local spark"+        SparkSteal victimCap ->+          printf "stealing a spark from cap %d" victimCap+        SparkFizzle ->+          printf "spark fizzled"+        SparkGC ->+          printf "spark GCed"+        TaskCreate taskId cap tid ->+          printf "task 0x%x created on cap %d with OS kernel thread %d"+                 taskId cap (kernelThreadId tid)+        TaskMigrate taskId cap new_cap ->+          printf "task 0x%x migrated from cap %d to cap %d"+                 taskId cap new_cap+        TaskDelete taskId ->+          printf "task 0x%x deleted" taskId+        Shutdown ->+          printf "shutting down"+        WakeupThread thread otherCap ->+          printf "waking up thread %d on cap %d" thread otherCap+        ThreadLabel thread label ->+          printf "thread %d has label \"%s\"" thread label+        RequestSeqGC ->+          printf "requesting sequential GC"+        RequestParGC ->+          printf "requesting parallel GC"+        StartGC ->+          printf "starting GC"+        EndGC ->+          printf "finished GC"+        GCWork ->+          printf "GC working"+        GCIdle ->+          printf "GC idle"+        GCDone ->+          printf "GC done"+        GlobalSyncGC ->+          printf "all caps stopped for GC"+        GCStatsGHC{..} ->+          printf "GC stats for heap capset %d: generation %d, %d bytes copied, %d bytes slop, %d bytes fragmentation, %d par threads, %d bytes max par copied, %d bytes total par copied" heapCapset gen copied slop frag parNThreads parMaxCopied parTotCopied+        HeapAllocated{..} ->+          printf "allocated on heap capset %d: %d total bytes till now" heapCapset allocBytes+        HeapSize{..} ->+          printf "size of heap capset %d: %d bytes" heapCapset sizeBytes+        HeapLive{..} ->+          printf "live data in heap capset %d: %d bytes" heapCapset liveBytes+        HeapInfoGHC{..} ->+          printf "heap stats for heap capset %d: generations %d, %d bytes max heap size, %d bytes alloc area size, %d bytes mblock size, %d bytes block size" heapCapset gens maxHeapSize allocAreaSize mblockSize blockSize+        CapCreate{cap} ->+          printf "created cap %d" cap+        CapDelete{cap} ->+          printf "deleted cap %d" cap+        CapDisable{cap} ->+          printf "disabled cap %d" cap+        CapEnable{cap} ->+          printf "enabled cap %d" cap+        Message msg ->+          msg+        UserMessage msg ->+          msg+        UserMarker markername ->+          printf "marker: %s" markername+        CapsetCreate cs ct ->+          printf "created capset %d of type %s" cs (show ct)+        CapsetDelete cs ->+          printf "deleted capset %d" cs+        CapsetAssignCap cs cp ->+          printf "assigned cap %d to capset %d" cp cs+        CapsetRemoveCap cs cp ->+          printf "removed cap %d from capset %d" cp cs+        OsProcessPid cs pid ->+          printf "capset %d: pid %d" cs pid+        OsProcessParentPid cs ppid ->+          printf "capset %d: parent pid %d" cs ppid+        WallClockTime cs sec nsec ->+          printf "capset %d: wall clock time %ds %dns (unix epoch)" cs sec nsec+        RtsIdentifier cs i ->+          printf "capset %d: RTS version \"%s\"" cs i+        ProgramArgs cs args ->+          printf "capset %d: args: %s" cs (show args)+        ProgramEnv cs env ->+          printf "capset %d: env: %s" cs (show env)+        UnknownEvent n ->+          printf "Unknown event type %d" n+        InternString str sId ->+          printf "Interned string: \"%s\" with id %d" str sId+        MerStartParConjunction dyn_id static_id ->+          printf "Start a parallel conjunction 0x%x, static_id: %d" dyn_id static_id+        MerEndParConjunction dyn_id ->+          printf "End par conjunction: 0x%x" dyn_id+        MerEndParConjunct dyn_id ->+          printf "End par conjunct: 0x%x" dyn_id+        MerCreateSpark dyn_id spark_id ->+          printf "Create spark for conjunction: 0x%x spark: 0x%x" dyn_id spark_id+        MerFutureCreate future_id name_id ->+          printf "Create future 0x%x named %d" future_id name_id+        MerFutureWaitNosuspend future_id ->+          printf "Wait didn't suspend for future: 0x%x" future_id+        MerFutureWaitSuspended future_id ->+          printf "Wait suspended on future: 0x%x" future_id+        MerFutureSignal future_id ->+          printf "Signaled future 0x%x" future_id+        MerLookingForGlobalThread ->+          "Looking for global thread to resume"+        MerWorkStealing ->+          "Trying to steal a spark"+        MerLookingForLocalSpark ->+          "Looking for a local spark to execute"+        MerReleaseThread thread_id ->+          printf "Releasing thread %d to the free pool" thread_id+        MerCapSleeping ->+          "Capability going to sleep"+        MerCallingMain ->+          "About to call the program entry point"+        PerfName{perfNum, name} ->+          printf "perf event %d named \"%s\"" perfNum name+        PerfCounter{perfNum, tid, period} ->+          printf "perf event counter %d incremented by %d in OS thread %d"+                 perfNum (period + 1) (kernelThreadId tid)+        PerfTracepoint{perfNum, tid} ->+          printf "perf event tracepoint %d reached in OS thread %d"+                 perfNum (kernelThreadId tid)++showThreadStopStatus :: ThreadStopStatus -> String+showThreadStopStatus HeapOverflow   = "heap overflow"+showThreadStopStatus StackOverflow  = "stack overflow"+showThreadStopStatus ThreadYielding = "thread yielding"+showThreadStopStatus ThreadBlocked  = "thread blocked"+showThreadStopStatus ThreadFinished = "thread finished"+showThreadStopStatus ForeignCall    = "making a foreign call"+showThreadStopStatus BlockedOnMVar  = "blocked on an MVar"+showThreadStopStatus BlockedOnBlackHole = "blocked on a black hole"+showThreadStopStatus BlockedOnRead = "blocked on I/O read"+showThreadStopStatus BlockedOnWrite = "blocked on I/O write"+showThreadStopStatus BlockedOnDelay = "blocked on threadDelay"+showThreadStopStatus BlockedOnSTM = "blocked in STM retry"+showThreadStopStatus BlockedOnDoProc = "blocked on asyncDoProc"+showThreadStopStatus BlockedOnCCall = "blocked in a foreign call"+showThreadStopStatus BlockedOnCCall_NoUnblockExc = "blocked in a foreign call"+showThreadStopStatus BlockedOnMsgThrowTo = "blocked in throwTo"+showThreadStopStatus ThreadMigrating = "thread migrating"+showThreadStopStatus BlockedOnMsgGlobalise = "waiting for data to be globalised"+showThreadStopStatus (BlockedOnBlackHoleOwnedBy target) =+          "blocked on black hole owned by thread " ++ show target+showThreadStopStatus NoStatus = "No stop thread status"++ppEventLog :: EventLog -> String+ppEventLog (EventLog (Header ets) (Data es)) = unlines $ concat (+    [ ["Event Types:"]+    , map ppEventType ets+    , [""] -- newline+    , ["Events:"]+    , map (ppEvent imap) sorted+    , [""] ]) -- extra trailing newline+ where+    imap = buildEventTypeMap ets+    sorted = sortEvents es++ppEventType :: EventType -> String+ppEventType (EventType num dsc msz) = printf "%4d: %s (size %s)" num dsc+   (case msz of Nothing -> "variable"; Just x -> show x)++ppEvent :: IntMap EventType -> CapEvent -> String+ppEvent imap (CapEvent cap (Event time spec)) =+  printf "%9d: " time +++  (case cap of+    Nothing -> ""+    Just c  -> printf "cap %d: " c) +++  case spec of+    UnknownEvent{ ref=ref } ->+      printf (desc (fromJust (M.lookup (fromIntegral ref) imap)))++    other -> showEventInfo spec++type PutEvents a = PutM a++putE :: Binary a => a -> PutEvents ()+putE = put++runPutEBS :: PutEvents () -> L.ByteString+runPutEBS = runPut++writeEventLogToFile f el = L.writeFile f $ runPutEBS $ putEventLog el++putType :: EventTypeNum -> PutEvents ()+putType = putE++putCap :: Int -> PutEvents ()+putCap c = putE (fromIntegral c :: CapNo)++putMarker :: Word32 -> PutEvents ()+putMarker = putE++putEStr :: String -> PutEvents ()+putEStr = mapM_ putE++putEventLog :: EventLog -> PutEvents ()+putEventLog (EventLog hdr es) = do+    putHeader hdr+    putData es++putHeader :: Header -> PutEvents ()+putHeader (Header ets) = do+    putMarker EVENT_HEADER_BEGIN+    putMarker EVENT_HET_BEGIN+    mapM_ putEventType ets+    putMarker EVENT_HET_END+    putMarker EVENT_HEADER_END+ where+    putEventType (EventType n d msz) = do+        putMarker EVENT_ET_BEGIN+        putType n+        putE $ fromMaybe 0xffff msz+        putE (fromIntegral $ length d :: EventTypeDescLen)+        mapM_ put d+        -- the event type header allows for extra data, which we don't use:+        putE (0 :: Word32)+        putMarker EVENT_ET_END++putData :: Data -> PutEvents ()+putData (Data es) = do+    putMarker EVENT_DATA_BEGIN -- Word32+    mapM_ putEvent es+    putType EVENT_DATA_END -- Word16++eventTypeNum :: EventInfo -> EventTypeNum+eventTypeNum e = case e of+    CreateThread {} -> EVENT_CREATE_THREAD+    RunThread {} -> EVENT_RUN_THREAD+    StopThread {} -> EVENT_STOP_THREAD+    ThreadRunnable {} -> EVENT_THREAD_RUNNABLE+    MigrateThread {} -> EVENT_MIGRATE_THREAD+    Shutdown {} -> EVENT_SHUTDOWN+    WakeupThread {} -> EVENT_THREAD_WAKEUP+    ThreadLabel {}  -> EVENT_THREAD_LABEL+    StartGC {} -> EVENT_GC_START+    EndGC {} -> EVENT_GC_END+    GlobalSyncGC {} -> EVENT_GC_GLOBAL_SYNC+    RequestSeqGC {} -> EVENT_REQUEST_SEQ_GC+    RequestParGC {} -> EVENT_REQUEST_PAR_GC+    CreateSparkThread {} -> EVENT_CREATE_SPARK_THREAD+    SparkCounters {} -> EVENT_SPARK_COUNTERS+    SparkCreate   {} -> EVENT_SPARK_CREATE+    SparkDud      {} -> EVENT_SPARK_DUD+    SparkOverflow {} -> EVENT_SPARK_OVERFLOW+    SparkRun      {} -> EVENT_SPARK_RUN+    SparkSteal    {} -> EVENT_SPARK_STEAL+    SparkFizzle   {} -> EVENT_SPARK_FIZZLE+    SparkGC       {} -> EVENT_SPARK_GC+    TaskCreate  {} -> EVENT_TASK_CREATE+    TaskMigrate {} -> EVENT_TASK_MIGRATE+    TaskDelete  {} -> EVENT_TASK_DELETE+    Message {} -> EVENT_LOG_MSG+    Startup {} -> EVENT_STARTUP+    EventBlock {} -> EVENT_BLOCK_MARKER+    UserMessage {} -> EVENT_USER_MSG+    UserMarker  {} -> EVENT_USER_MARKER+    GCIdle {} -> EVENT_GC_IDLE+    GCWork {} -> EVENT_GC_WORK+    GCDone {} -> EVENT_GC_DONE+    GCStatsGHC{} -> EVENT_GC_STATS_GHC+    HeapAllocated{} -> EVENT_HEAP_ALLOCATED+    HeapSize{} -> EVENT_HEAP_SIZE+    HeapLive{} -> EVENT_HEAP_LIVE+    HeapInfoGHC{} -> EVENT_HEAP_INFO_GHC+    CapCreate{} -> EVENT_CAP_CREATE+    CapDelete{} -> EVENT_CAP_DELETE+    CapDisable{} -> EVENT_CAP_DISABLE+    CapEnable{} -> EVENT_CAP_ENABLE+    CapsetCreate {} -> EVENT_CAPSET_CREATE+    CapsetDelete {} -> EVENT_CAPSET_DELETE+    CapsetAssignCap {} -> EVENT_CAPSET_ASSIGN_CAP+    CapsetRemoveCap {} -> EVENT_CAPSET_REMOVE_CAP+    RtsIdentifier {} -> EVENT_RTS_IDENTIFIER+    ProgramArgs {} -> EVENT_PROGRAM_ARGS+    ProgramEnv {} -> EVENT_PROGRAM_ENV+    OsProcessPid {} -> EVENT_OSPROCESS_PID+    OsProcessParentPid{} -> EVENT_OSPROCESS_PPID+    WallClockTime{} -> EVENT_WALL_CLOCK_TIME+    UnknownEvent {} -> error "eventTypeNum UnknownEvent"+    InternString {} -> EVENT_INTERN_STRING+    MerStartParConjunction {} -> EVENT_MER_START_PAR_CONJUNCTION+    MerEndParConjunction _ -> EVENT_MER_STOP_PAR_CONJUNCTION+    MerEndParConjunct _ -> EVENT_MER_STOP_PAR_CONJUNCT+    MerCreateSpark {} -> EVENT_MER_CREATE_SPARK+    MerFutureCreate {} -> EVENT_MER_FUT_CREATE+    MerFutureWaitNosuspend _ -> EVENT_MER_FUT_WAIT_NOSUSPEND+    MerFutureWaitSuspended _ -> EVENT_MER_FUT_WAIT_SUSPENDED+    MerFutureSignal _ -> EVENT_MER_FUT_SIGNAL+    MerLookingForGlobalThread -> EVENT_MER_LOOKING_FOR_GLOBAL_CONTEXT+    MerWorkStealing -> EVENT_MER_WORK_STEALING+    MerLookingForLocalSpark -> EVENT_MER_LOOKING_FOR_LOCAL_SPARK+    MerReleaseThread _ -> EVENT_MER_RELEASE_CONTEXT+    MerCapSleeping -> EVENT_MER_ENGINE_SLEEPING+    MerCallingMain -> EVENT_MER_CALLING_MAIN+    PerfName       {} -> nEVENT_PERF_NAME+    PerfCounter    {} -> nEVENT_PERF_COUNTER+    PerfTracepoint {} -> nEVENT_PERF_TRACEPOINT++nEVENT_PERF_NAME, nEVENT_PERF_COUNTER, nEVENT_PERF_TRACEPOINT :: EventTypeNum+nEVENT_PERF_NAME = EVENT_PERF_NAME+nEVENT_PERF_COUNTER = EVENT_PERF_COUNTER+nEVENT_PERF_TRACEPOINT = EVENT_PERF_TRACEPOINT++putEvent :: Event -> PutEvents ()+putEvent (Event t spec) = do+    putType (eventTypeNum spec)+    put t+    putEventSpec spec++putEventSpec (Startup caps) = do+    putCap (fromIntegral caps)++putEventSpec (EventBlock end cap es) = do+    let block = runPutEBS (mapM_ putEvent es)+    put (fromIntegral (L.length block) + 24 :: Word32)+    putE end+    putE (fromIntegral cap :: CapNo)+    putLazyByteString block++putEventSpec (CreateThread t) = do+    putE t++putEventSpec (RunThread t) = do+    putE t++-- here we assume that ThreadStopStatus fromEnum matches the definitions in+-- EventLogFormat.h+putEventSpec (StopThread t s) = do+    putE t+    putE $ case s of+            NoStatus -> 0 :: Word16+            HeapOverflow -> 1+            StackOverflow -> 2+            ThreadYielding -> 3+            ThreadBlocked -> 4+            ThreadFinished -> 5+            ForeignCall -> 6+            BlockedOnMVar -> 7+            BlockedOnBlackHole -> 8+            BlockedOnBlackHoleOwnedBy _ -> 8+            BlockedOnRead -> 9+            BlockedOnWrite -> 10+            BlockedOnDelay -> 11+            BlockedOnSTM -> 12+            BlockedOnDoProc -> 13+            BlockedOnCCall -> 14+            BlockedOnCCall_NoUnblockExc -> 15+            BlockedOnMsgThrowTo -> 16+            ThreadMigrating -> 17+            BlockedOnMsgGlobalise -> 18+    putE $ case s of+            BlockedOnBlackHoleOwnedBy i -> i+            _                           -> 0++putEventSpec (ThreadRunnable t) = do+    putE t++putEventSpec (MigrateThread t c) = do+    putE t+    putCap c++putEventSpec (CreateSparkThread t) = do+    putE t++putEventSpec (SparkCounters crt dud ovf cnv fiz gcd rem) = do+    putE crt+    putE dud+    putE ovf+    putE cnv+    -- Warning: order of fiz and gcd reversed!+    putE gcd+    putE fiz+    putE rem++putEventSpec SparkCreate = do+    return ()++putEventSpec SparkDud = do+    return ()++putEventSpec SparkOverflow = do+    return ()++putEventSpec SparkRun = do+    return ()++putEventSpec (SparkSteal c) = do+    putCap c++putEventSpec SparkFizzle = do+    return ()++putEventSpec SparkGC = do+    return ()++putEventSpec (WakeupThread t c) = do+    putE t+    putCap c++putEventSpec (ThreadLabel t l) = do+    putE (fromIntegral (length l) + sz_tid :: Word16)+    putE t+    putEStr l++putEventSpec Shutdown = do+    return ()++putEventSpec RequestSeqGC = do+    return ()++putEventSpec RequestParGC = do+    return ()++putEventSpec StartGC = do+    return ()++putEventSpec GCWork = do+    return ()++putEventSpec GCIdle = do+    return ()++putEventSpec GCDone = do+    return ()++putEventSpec EndGC = do+    return ()++putEventSpec GlobalSyncGC = do+    return ()++putEventSpec (TaskCreate taskId cap tid) = do+    putE taskId+    putCap cap+    putE tid++putEventSpec (TaskMigrate taskId cap new_cap) = do+    putE taskId+    putCap cap+    putCap new_cap++putEventSpec (TaskDelete taskId) = do+    putE taskId++putEventSpec GCStatsGHC{..} = do+    putE heapCapset+    putE (fromIntegral gen :: Word16)+    putE copied+    putE slop+    putE frag+    putE (fromIntegral parNThreads :: Word32)+    putE parMaxCopied+    putE parTotCopied++putEventSpec HeapAllocated{..} = do+    putE heapCapset+    putE allocBytes++putEventSpec HeapSize{..} = do+    putE heapCapset+    putE sizeBytes++putEventSpec HeapLive{..} = do+    putE heapCapset+    putE liveBytes++putEventSpec HeapInfoGHC{..} = do+    putE heapCapset+    putE (fromIntegral gens :: Word16)+    putE maxHeapSize+    putE allocAreaSize+    putE mblockSize+    putE blockSize++putEventSpec CapCreate{cap} = do+    putCap cap++putEventSpec CapDelete{cap} = do+    putCap cap++putEventSpec CapDisable{cap} = do+    putCap cap++putEventSpec CapEnable{cap} = do+    putCap cap++putEventSpec (CapsetCreate cs ct) = do+    putE cs+    putE $ case ct of+            CapsetCustom -> 1 :: Word16+            CapsetOsProcess -> 2+            CapsetClockDomain -> 3+            CapsetUnknown -> 0++putEventSpec (CapsetDelete cs) = do+    putE cs++putEventSpec (CapsetAssignCap cs cp) = do+    putE cs+    putCap cp++putEventSpec (CapsetRemoveCap cs cp) = do+    putE cs+    putCap cp++putEventSpec (RtsIdentifier cs rts) = do+    putE (fromIntegral (length rts) + sz_capset :: Word16)+    putE cs+    putEStr rts++putEventSpec (ProgramArgs cs as) = do+    let as' = unsep as+    putE (fromIntegral (length as') + sz_capset :: Word16)+    putE cs+    mapM_ putE as'++putEventSpec (ProgramEnv cs es) = do+    let es' = unsep es+    putE (fromIntegral (length es') + sz_capset :: Word16)+    putE cs+    mapM_ putE es'++putEventSpec (OsProcessPid cs pid) = do+    putE cs+    putE pid++putEventSpec (OsProcessParentPid cs ppid) = do+    putE cs+    putE ppid++putEventSpec (WallClockTime cs sec nsec) = do+    putE cs+    putE sec+    putE nsec++putEventSpec (Message s) = do+    putE (fromIntegral (length s) :: Word16)+    mapM_ putE s++putEventSpec (UserMessage s) = do+    putE (fromIntegral (length s) :: Word16)+    mapM_ putE s++putEventSpec (UserMarker s) = do+    putE (fromIntegral (length s) :: Word16)+    mapM_ putE s++putEventSpec (UnknownEvent {}) = error "putEventSpec UnknownEvent"++putEventSpec (InternString str id) = do+    putE len+    mapM_ putE str+    putE id+  where len = (fromIntegral (length str) :: Word16) + sz_string_id++putEventSpec (MerStartParConjunction dyn_id static_id) = do+    putE dyn_id+    putE static_id++putEventSpec (MerEndParConjunction dyn_id) = do+    putE dyn_id++putEventSpec (MerEndParConjunct dyn_id) = do+    putE dyn_id++putEventSpec (MerCreateSpark dyn_id spark_id) = do+    putE dyn_id+    putE spark_id++putEventSpec (MerFutureCreate future_id name_id) = do+    putE future_id+    putE name_id++putEventSpec (MerFutureWaitNosuspend future_id) = do+    putE future_id++putEventSpec (MerFutureWaitSuspended future_id) = do+    putE future_id++putEventSpec (MerFutureSignal future_id) = do+    putE future_id++putEventSpec MerLookingForGlobalThread = return ()+putEventSpec MerWorkStealing = return ()+putEventSpec MerLookingForLocalSpark = return ()++putEventSpec (MerReleaseThread thread_id) = do+    putE thread_id++putEventSpec MerCapSleeping = return ()+putEventSpec MerCallingMain = return ()++putEventSpec PerfName{..} = do+    putE (fromIntegral (length name) + sz_perf_num :: Word16)+    putE perfNum+    mapM_ putE name++putEventSpec PerfCounter{..} = do+    putE perfNum+    putE tid+    putE period++putEventSpec PerfTracepoint{..} = do+    putE perfNum+    putE tid++-- [] == []+-- [x] == x\0+-- [x, y, z] == x\0y\0+unsep :: [String] -> String+unsep = concatMap (++"\0") -- not the most efficient, but should be ok++splitNull :: String -> [String]+splitNull [] = []+splitNull xs = case span (/= '\0') xs of+                (x, xs') -> x : splitNull (drop 1 xs')
+ TestSuite/inputs/Puns/cabals/array.cabal view
@@ -0,0 +1,56 @@+name:       array+version:    0.4.0.0+license:    BSD3+license-file:    LICENSE+maintainer:    libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29+synopsis:   Mutable and immutable arrays+category:   Data Structures+description:+    This package defines the classes @IArray@ of immutable arrays and+    @MArray@ of arrays mutable within appropriate monads, as well as+    some instances of these classes.+cabal-version: >=1.6+build-type: Simple+extra-source-files: include/Typeable.h++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/array.git/++library+  build-depends: base >= 4.2 && < 5+  exposed-modules:+      Data.Array+  extensions: CPP+  if !impl(nhc98)+    exposed-modules:+      Data.Array.Base+      Data.Array.IArray+      Data.Array.IO+      Data.Array.IO.Safe+      Data.Array.IO.Internals+      Data.Array.MArray+      Data.Array.MArray.Safe+      Data.Array.ST+      Data.Array.ST.Safe+      Data.Array.Storable+      Data.Array.Storable.Safe+      Data.Array.Storable.Internals+      Data.Array.Unboxed+      Data.Array.Unsafe+    extensions:+      MultiParamTypeClasses,+      FlexibleContexts,+      FlexibleInstances,+      TypeSynonymInstances+  if impl(ghc)+    extensions:+      DeriveDataTypeable,+      StandaloneDeriving,+      Rank2Types,+      MagicHash,+      UnboxedTuples,+      ForeignFunctionInterface,+      UnliftedFFITypes+  include-dirs: include
+ TestSuite/inputs/Puns/cabals/base.cabal view
@@ -0,0 +1,253 @@+name:           base+version:        4.5.1.0+license:        BSD3+license-file:   LICENSE+maintainer:     libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/base+synopsis:       Basic libraries+description:+    This package contains the Prelude and its support libraries,+    and a large collection of useful libraries ranging from data+    structures to parsing combinators and debugging utilities.+cabal-version:  >=1.6+build-type: Configure+extra-tmp-files:+                config.log config.status autom4te.cache+                include/HsBaseConfig.h include/EventConfig.h+extra-source-files:+                config.guess config.sub install-sh+                aclocal.m4 configure.ac configure+                include/CTypes.h include/md5.h++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/base.git/++Flag integer-simple+    Description: Use integer-simple++Library {+    if impl(ghc) {+        if flag(integer-simple)+            build-depends: integer-simple+        else+            build-depends: integer-gmp+            cpp-options: -DOPTIMISE_INTEGER_GCD_LCM+        build-depends: rts, ghc-prim+        exposed-modules:+            Foreign.Concurrent,+            GHC.Arr,+            GHC.Base,+            GHC.Conc,+            GHC.Conc.IO,+            GHC.Conc.Signal,+            GHC.Conc.Sync,+            GHC.ConsoleHandler,+            GHC.Constants,+            GHC.Desugar,+            GHC.Enum,+            GHC.Environment,+            GHC.Err,+            GHC.Exception,+            GHC.Exts,+            GHC.Fingerprint,+            GHC.Fingerprint.Type,+            GHC.Float,+            GHC.Float.ConversionUtils,+            GHC.Float.RealFracMethods,+            GHC.Foreign,+            GHC.ForeignPtr,+            GHC.Handle,+            GHC.IO,+            GHC.IO.Buffer,+            GHC.IO.BufferedIO,+            GHC.IO.Device,+            GHC.IO.Encoding,+            GHC.IO.Encoding.CodePage,+            GHC.IO.Encoding.Failure,+            GHC.IO.Encoding.Iconv,+            GHC.IO.Encoding.Latin1,+            GHC.IO.Encoding.Types,+            GHC.IO.Encoding.UTF16,+            GHC.IO.Encoding.UTF32,+            GHC.IO.Encoding.UTF8,+            GHC.IO.Exception,+            GHC.IO.FD,+            GHC.IO.Handle,+            GHC.IO.Handle.FD,+            GHC.IO.Handle.Internals,+            GHC.IO.Handle.Text,+            GHC.IO.Handle.Types,+            GHC.IO.IOMode,+            GHC.IOArray,+            GHC.IOBase,+            GHC.IORef,+            GHC.Int,+            GHC.List,+            GHC.MVar,+            GHC.Num,+            GHC.PArr,+            GHC.Pack,+            GHC.Ptr,+            GHC.Read,+            GHC.Real,+            GHC.ST,+            GHC.Stack,+            GHC.Stats,+            GHC.Show,+            GHC.Stable,+            GHC.Storable,+            GHC.STRef,+            GHC.TopHandler,+            GHC.Unicode,+            GHC.Weak,+            GHC.Word,+            System.Timeout+        if os(windows)+            exposed-modules: GHC.IO.Encoding.CodePage.Table+                             GHC.Conc.Windows+                             GHC.Windows+    }+    exposed-modules:+        Control.Applicative,+        Control.Arrow,+        Control.Category,+        Control.Concurrent,+        Control.Concurrent.Chan,+        Control.Concurrent.MVar,+        Control.Concurrent.QSem,+        Control.Concurrent.QSemN,+        Control.Concurrent.SampleVar,+        Control.Exception,+        Control.Exception.Base+        Control.OldException,+        Control.Monad,+        Control.Monad.Fix,+        Control.Monad.Instances,+        Control.Monad.ST,+        Control.Monad.ST.Safe,+        Control.Monad.ST.Unsafe,+        Control.Monad.ST.Lazy,+        Control.Monad.ST.Lazy.Safe,+        Control.Monad.ST.Lazy.Unsafe,+        Control.Monad.ST.Strict,+        Control.Monad.Zip+        Data.Bits,+        Data.Bool,+        Data.Char,+        Data.Complex,+        Data.Dynamic,+        Data.Either,+        Data.Eq,+        Data.Data,+        Data.Fixed,+        Data.Foldable+        Data.Function,+        Data.Functor,+        Data.HashTable,+        Data.IORef,+        Data.Int,+        Data.Ix,+        Data.List,+        Data.Maybe,+        Data.Monoid,+        Data.Ord,+        Data.Ratio,+        Data.STRef+        Data.STRef.Lazy+        Data.STRef.Strict+        Data.String,+        Data.Traversable+        Data.Tuple,+        Data.Typeable,+        Data.Typeable.Internal,+        Data.Unique,+        Data.Version,+        Data.Word,+        Debug.Trace,+        Foreign,+        Foreign.C,+        Foreign.C.Error,+        Foreign.C.String,+        Foreign.C.Types,+        Foreign.ForeignPtr,+        Foreign.ForeignPtr.Safe,+        Foreign.ForeignPtr.Unsafe,+        Foreign.Marshal,+        Foreign.Marshal.Alloc,+        Foreign.Marshal.Array,+        Foreign.Marshal.Error,+        Foreign.Marshal.Pool,+        Foreign.Marshal.Safe,+        Foreign.Marshal.Utils,+        Foreign.Marshal.Unsafe,+        Foreign.Ptr,+        Foreign.Safe,+        Foreign.StablePtr,+        Foreign.Storable,+        Numeric,+        Prelude,+        System.Console.GetOpt+        System.CPUTime,+        System.Environment,+        System.Exit,+        System.IO,+        System.IO.Error,+        System.IO.Unsafe,+        System.Info,+        System.Mem,+        System.Mem.StableName,+        System.Mem.Weak,+        System.Posix.Internals,+        System.Posix.Types,+        Text.ParserCombinators.ReadP,+        Text.ParserCombinators.ReadPrec,+        Text.Printf,+        Text.Read,+        Text.Read.Lex,+        Text.Show,+        Text.Show.Functions+        Unsafe.Coerce+    other-modules:+        Control.Monad.ST.Imp+        Control.Monad.ST.Lazy.Imp+        Foreign.ForeignPtr.Imp+    c-sources:+        cbits/PrelIOUtils.c+        cbits/WCsubst.c+        cbits/Win32Utils.c+        cbits/consUtils.c+        cbits/iconv.c+        cbits/inputReady.c+        cbits/selectUtils.c+        cbits/primFloat.c+        cbits/md5.c+    include-dirs: include+    includes:    HsBase.h+    install-includes:    HsBase.h HsBaseConfig.h EventConfig.h WCsubst.h consUtils.h Typeable.h+    if os(windows) {+        extra-libraries: wsock32, user32, shell32+    }+    if !os(windows) {+        exposed-modules:+            GHC.Event+        other-modules:+            GHC.Event.Array+            GHC.Event.Clock+            GHC.Event.Control+            GHC.Event.EPoll+            GHC.Event.IntMap+            GHC.Event.Internal+            GHC.Event.KQueue+            GHC.Event.Manager+            GHC.Event.PSQ+            GHC.Event.Poll+            GHC.Event.Thread+            GHC.Event.Unique+    }+    -- We need to set the package name to base (without a version number)+    -- as it's magic.+    ghc-options: -package-name base+    nhc98-options: -H4M -K3M+    extensions: CPP+}
+ TestSuite/inputs/Puns/cabals/binary.cabal view
@@ -0,0 +1,60 @@+name:            binary+version:         0.5.1.0+license-file:    LICENSE+author:          Lennart Kolmodin <kolmodin@gmail.com>+maintainer:      Lennart Kolmodin, Don Stewart <dons@galois.com>+homepage:        http://code.haskell.org/binary/+description:     Efficient, pure binary serialisation using lazy ByteStrings.+                 Haskell values may be encoded to and from binary formats, +                 written to disk as binary, or sent over the network.+                 Serialisation speeds of over 1 G\/sec have been observed,+                 so this library should be suitable for high performance+                 scenarios.+synopsis:        Binary serialisation for Haskell values using lazy ByteStrings+category:        Data, Parsing+stability:       provisional+build-type:      Simple+cabal-version:   >= 1.2+tested-with:     GHC ==6.4.2, GHC ==6.6.1, GHC ==6.8.0, GHC ==6.10.1+extra-source-files: README index.html++flag bytestring-in-base+flag split-base+flag applicative-in-base++library+  if flag(bytestring-in-base)+    -- bytestring was in base-2.0 and 2.1.1+    build-depends: base >= 2.0 && < 2.2+    cpp-options: -DBYTESTRING_IN_BASE+  else+    -- in base 1.0 and 3.0 bytestring is a separate package+    build-depends: base < 2.0 || >= 3, bytestring >= 0.9++  if flag(split-base)+    build-depends:   base >= 3.0, containers, array+  else+    build-depends:   base < 3.0++  if flag(applicative-in-base)+    build-depends: base >= 2.0+    cpp-options: -DAPPLICATIVE_IN_BASE+  else+    build-depends: base < 2.0+  hs-source-dirs:  src++  exposed-modules: Data.Binary,+                   Data.Binary.Put,+                   Data.Binary.Get,+                   Data.Binary.Builder+                   Data.Binary.Builder.Internal++  other-modules:   Data.Binary.Builder.Base++  extensions:      CPP,+                   FlexibleContexts++  ghc-options:     -O2 -Wall -fliberate-case-threshold=1000++--  if impl(ghc < 6.5)+--    ghc-options:   -fallow-undecidable-instances
+ TestSuite/inputs/Puns/cabals/bytestring.cabal view
@@ -0,0 +1,91 @@+Name:                bytestring+Version:             0.9.2.1+Synopsis:            Fast, packed, strict and lazy byte arrays with a list interface+Description:+    A time and space-efficient implementation of byte vectors using+    packed Word8 arrays, suitable for high performance use, both in terms+    of large data quantities, or high speed requirements. Byte vectors+    are encoded as strict 'Word8' arrays of bytes, and lazy lists of+    strict chunks, held in a 'ForeignPtr', and can be passed between C+    and Haskell with little effort.+    .+    Test coverage data for this library is available at:+        <http://code.haskell.org/~dons/tests/bytestring/hpc_index.html>++License:             BSD3+License-file:        LICENSE+Category:            Data+Copyright:           Copyright (c) Don Stewart   2005-2009,+                               (c) Duncan Coutts 2006-2009,+                               (c) David Roundy  2003-2005.+Author:              Don Stewart, Duncan Coutts+Maintainer:          dons00@gmail.com, duncan@community.haskell.org+Homepage:            http://www.cse.unsw.edu.au/~dons/fps.html+Tested-With:         GHC==7.0.2, GHC==6.12.3, GHC==6.10.4, GHC ==6.8.2+Build-Type:          Simple+Cabal-Version:       >= 1.8+extra-source-files:  README TODO++library+  build-depends:     base >= 3 && < 5++  if impl(ghc >= 6.10)+    build-depends:   ghc-prim, base >= 4++  exposed-modules:   Data.ByteString+                     Data.ByteString.Char8+                     Data.ByteString.Unsafe+                     Data.ByteString.Internal+                     Data.ByteString.Lazy+                     Data.ByteString.Lazy.Char8+                     Data.ByteString.Lazy.Internal+                     Data.ByteString.Fusion++  extensions:        CPP, ForeignFunctionInterface++  if impl(ghc)+      extensions:   UnliftedFFITypes,+                    MagicHash,+                    UnboxedTuples,+                    DeriveDataTypeable+                    ScopedTypeVariables+  if impl(ghc >= 6.11)+      extensions:   NamedFieldPuns++  --TODO: eliminate orphan instances:+  ghc-options:      -Wall -fno-warn-orphans+                    -O2+                    -funbox-strict-fields +                    -fmax-simplifier-iterations10+                    -fdicts-cheap++  c-sources:         cbits/fpstring.c+  include-dirs:      include+  includes:          fpstring.h+  install-includes:  fpstring.h++  nhc98-options:     -K4M -K3M++-- QC properties, with GHC RULES disabled+test-suite prop-compiled+  type:             exitcode-stdio-1.0+  main-is:          Properties.hs+  hs-source-dirs:   . tests+  build-depends:    base, random, directory,+                    QuickCheck >= 2.3 && < 3+  if impl(ghc >= 6.10)+    build-depends:  ghc-prim+  c-sources:        cbits/fpstring.c+  include-dirs:     include+  if impl(ghc >= 6.10)+    ghc-options:    -fno-enable-rewrite-rules+  else+    ghc-options:    -fno-rewrite-rules+  if impl(ghc)+      extensions:   UnliftedFFITypes,+                    MagicHash,+                    UnboxedTuples,+                    DeriveDataTypeable+                    ScopedTypeVariables+  if impl(ghc >= 6.11)+      extensions:   NamedFieldPuns
+ TestSuite/inputs/Puns/cabals/containers.cabal view
@@ -0,0 +1,44 @@+name: containers+version: 0.4.2.1+license: BSD3+maintainer: fox@ucw.cz+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29+synopsis: Assorted concrete container types+category: Data Structures+description:+    This package contains efficient general-purpose implementations+    of various basic immutable container types.  The declared cost of+    each operation is either worst-case or amortized, but remains+    valid even if structures are shared.+build-type: Simple+cabal-version:  >=1.6+extra-source-files: include/Typeable.h++source-repository head+    type:     git+    location: http://github.com/haskell/containers.git++Library {+    build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4+    ghc-options: -O2+    if impl(ghc>6.10)+        Ghc-Options: -fregs-graph+    exposed-modules:+        Data.IntMap+        Data.IntSet+        Data.Map+        Data.Set+    include-dirs: include+    extensions: CPP+    if !impl(nhc98) {+        exposed-modules:+            Data.Graph+            Data.Sequence+            Data.Tree+    }+    if impl(ghc) {+        extensions: DeriveDataTypeable, StandaloneDeriving,+                    MagicHash, Rank2Types+    }+}+
+ TestSuite/inputs/Puns/cabals/deepseq.cabal view
@@ -0,0 +1,35 @@+name:		deepseq+version:        1.3.0.0+license:	BSD3+license-file:	LICENSE+maintainer:	libraries@haskell.org+synopsis:	Deep evaluation of data structures+category:       Control+description:+    This package provides methods for fully evaluating data structures+    (\"deep evaluation\"). Deep evaluation is often used for adding+    strictness to a program, e.g. in order to force pending exceptions,+    remove space leaks, or force lazy I/O to happen. It is also useful+    in parallel programs, to ensure pending work does not migrate to the+    wrong thread.+    .+    The primary use of this package is via the 'deepseq' function, a+    \"deep\" version of 'seq'. It is implemented on top of an 'NFData'+    typeclass (\"Normal Form Data\", data structures with no unevaluated+    components) which defines strategies for fully evaluating different+    data types.+    .+build-type:     Simple+cabal-version:  >=1.6++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/deepseq.git/++library {+  exposed-modules: Control.DeepSeq+  build-depends: base       >= 3   && < 5, +                 array      >= 0.1 && < 0.5+  ghc-options: -Wall+  extensions: CPP+}
+ TestSuite/inputs/Puns/cabals/mtl.cabal view
@@ -0,0 +1,51 @@+Name:         mtl+Version:      1.1.1.1+Author:       Andy Gill+Maintainer:   libraries@haskell.org+Category:     Control+Synopsis:     Monad transformer library+Description:+    A monad transformer library, inspired by the paper /Functional+    Programming with Overloading and Higher-Order Polymorphism/,+    by Mark P Jones (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>),+    Advanced School of Functional Programming, 1995.+Build-Type:    Simple+Cabal-Version: >= 1.6++Library+    Build-Depends: base < 5++    Exposed-Modules:+        Control.Monad.Cont+        Control.Monad.Cont.Class+        Control.Monad.Error+        Control.Monad.Error.Class+        Control.Monad.Identity+        Control.Monad.List+        Control.Monad.RWS+        Control.Monad.RWS.Class+        Control.Monad.RWS.Lazy+        Control.Monad.RWS.Strict+        Control.Monad.Reader+        Control.Monad.Reader.Class+        Control.Monad.State+        Control.Monad.State.Class+        Control.Monad.State.Lazy+        Control.Monad.State.Strict+        Control.Monad.Trans+        Control.Monad.Writer+        Control.Monad.Writer.Class+        Control.Monad.Writer.Lazy+        Control.Monad.Writer.Strict++    Ghc-Options: -Wall++    Extensions: MultiParamTypeClasses,+                FunctionalDependencies,+                FlexibleInstances,+                TypeSynonymInstances++    -- Compile all modules as __Safe__ modules+    if impl(ghc >= 7.2)+        Extensions: Safe+
+ TestSuite/inputs/Puns/cabals/no_text_error/array.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/base.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/binary.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/bytestring.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/containers.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/deepseq.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/ghc-prim.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/integer-gmp.cabal view
+ TestSuite/inputs/Puns/cabals/no_text_error/mtl.cabal view
@@ -0,0 +1,52 @@+Name:         mtl+Version:      1.1.1.1+License:      PublicDomain+Author:       Andy Gill+Maintainer:   libraries@haskell.org+Category:     Control+Synopsis:     Monad transformer library+Description:+    A monad transformer library, inspired by the paper /Functional+    Programming with Overloading and Higher-Order Polymorphism/,+    by Mark P Jones (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>),+    Advanced School of Functional Programming, 1995.+Build-Type:    Simple+Cabal-Version: >= 1.6++Library+    Build-Depends: base < 5++    Exposed-Modules:+        Control.Monad.Cont+        Control.Monad.Cont.Class+        Control.Monad.Error+        Control.Monad.Error.Class+        Control.Monad.Identity+        Control.Monad.List+        Control.Monad.RWS+        Control.Monad.RWS.Class+        Control.Monad.RWS.Lazy+        Control.Monad.RWS.Strict+        Control.Monad.Reader+        Control.Monad.Reader.Class+        Control.Monad.State+        Control.Monad.State.Class+        Control.Monad.State.Lazy+        Control.Monad.State.Strict+        Control.Monad.Trans+        Control.Monad.Writer+        Control.Monad.Writer.Class+        Control.Monad.Writer.Lazy+        Control.Monad.Writer.Strict++    Ghc-Options: -Wall++    Extensions: MultiParamTypeClasses,+                FunctionalDependencies,+                FlexibleInstances,+                TypeSynonymInstances++    -- Compile all modules as __Safe__ modules+    if impl(ghc >= 7.2)+        Extensions: Safe+
+ TestSuite/inputs/Puns/cabals/parse_error/array.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/base.cabal view
@@ -0,0 +1,253 @@+name:           base+version:        4.5.1.0+license:        BSD3 -- can't comment here+license-file:   LICENSE+maintainer:     libraries@haskell.org+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/base+synopsis:       Basic libraries+description:+    This package contains the Prelude and its support libraries,+    and a large collection of useful libraries ranging from data+    structures to parsing combinators and debugging utilities.+cabal-version:  >=1.6+build-type: Configure+extra-tmp-files:+                config.log config.status autom4te.cache+                include/HsBaseConfig.h include/EventConfig.h+extra-source-files:+                config.guess config.sub install-sh+                aclocal.m4 configure.ac configure+                include/CTypes.h include/md5.h++source-repository head+    type:     git+    location: http://darcs.haskell.org/packages/base.git/++Flag integer-simple+    Description: Use integer-simple++Library {+    if impl(ghc) {+        if flag(integer-simple)+            build-depends: integer-simple+        else+            build-depends: integer-gmp+            cpp-options: -DOPTIMISE_INTEGER_GCD_LCM+        build-depends: rts, ghc-prim+        exposed-modules:+            Foreign.Concurrent,+            GHC.Arr,+            GHC.Base,+            GHC.Conc,+            GHC.Conc.IO,+            GHC.Conc.Signal,+            GHC.Conc.Sync,+            GHC.ConsoleHandler,+            GHC.Constants,+            GHC.Desugar,+            GHC.Enum,+            GHC.Environment,+            GHC.Err,+            GHC.Exception,+            GHC.Exts,+            GHC.Fingerprint,+            GHC.Fingerprint.Type,+            GHC.Float,+            GHC.Float.ConversionUtils,+            GHC.Float.RealFracMethods,+            GHC.Foreign,+            GHC.ForeignPtr,+            GHC.Handle,+            GHC.IO,+            GHC.IO.Buffer,+            GHC.IO.BufferedIO,+            GHC.IO.Device,+            GHC.IO.Encoding,+            GHC.IO.Encoding.CodePage,+            GHC.IO.Encoding.Failure,+            GHC.IO.Encoding.Iconv,+            GHC.IO.Encoding.Latin1,+            GHC.IO.Encoding.Types,+            GHC.IO.Encoding.UTF16,+            GHC.IO.Encoding.UTF32,+            GHC.IO.Encoding.UTF8,+            GHC.IO.Exception,+            GHC.IO.FD,+            GHC.IO.Handle,+            GHC.IO.Handle.FD,+            GHC.IO.Handle.Internals,+            GHC.IO.Handle.Text,+            GHC.IO.Handle.Types,+            GHC.IO.IOMode,+            GHC.IOArray,+            GHC.IOBase,+            GHC.IORef,+            GHC.Int,+            GHC.List,+            GHC.MVar,+            GHC.Num,+            GHC.PArr,+            GHC.Pack,+            GHC.Ptr,+            GHC.Read,+            GHC.Real,+            GHC.ST,+            GHC.Stack,+            GHC.Stats,+            GHC.Show,+            GHC.Stable,+            GHC.Storable,+            GHC.STRef,+            GHC.TopHandler,+            GHC.Unicode,+            GHC.Weak,+            GHC.Word,+            System.Timeout+        if os(windows)+            exposed-modules: GHC.IO.Encoding.CodePage.Table+                             GHC.Conc.Windows+                             GHC.Windows+    }+    exposed-modules:+        Control.Applicative,+        Control.Arrow,+        Control.Category,+        Control.Concurrent,+        Control.Concurrent.Chan,+        Control.Concurrent.MVar,+        Control.Concurrent.QSem,+        Control.Concurrent.QSemN,+        Control.Concurrent.SampleVar,+        Control.Exception,+        Control.Exception.Base+        Control.OldException,+        Control.Monad,+        Control.Monad.Fix,+        Control.Monad.Instances,+        Control.Monad.ST,+        Control.Monad.ST.Safe,+        Control.Monad.ST.Unsafe,+        Control.Monad.ST.Lazy,+        Control.Monad.ST.Lazy.Safe,+        Control.Monad.ST.Lazy.Unsafe,+        Control.Monad.ST.Strict,+        Control.Monad.Zip+        Data.Bits,+        Data.Bool,+        Data.Char,+        Data.Complex,+        Data.Dynamic,+        Data.Either,+        Data.Eq,+        Data.Data,+        Data.Fixed,+        Data.Foldable+        Data.Function,+        Data.Functor,+        Data.HashTable,+        Data.IORef,+        Data.Int,+        Data.Ix,+        Data.List,+        Data.Maybe,+        Data.Monoid,+        Data.Ord,+        Data.Ratio,+        Data.STRef+        Data.STRef.Lazy+        Data.STRef.Strict+        Data.String,+        Data.Traversable+        Data.Tuple,+        Data.Typeable,+        Data.Typeable.Internal,+        Data.Unique,+        Data.Version,+        Data.Word,+        Debug.Trace,+        Foreign,+        Foreign.C,+        Foreign.C.Error,+        Foreign.C.String,+        Foreign.C.Types,+        Foreign.ForeignPtr,+        Foreign.ForeignPtr.Safe,+        Foreign.ForeignPtr.Unsafe,+        Foreign.Marshal,+        Foreign.Marshal.Alloc,+        Foreign.Marshal.Array,+        Foreign.Marshal.Error,+        Foreign.Marshal.Pool,+        Foreign.Marshal.Safe,+        Foreign.Marshal.Utils,+        Foreign.Marshal.Unsafe,+        Foreign.Ptr,+        Foreign.Safe,+        Foreign.StablePtr,+        Foreign.Storable,+        Numeric,+        Prelude,+        System.Console.GetOpt+        System.CPUTime,+        System.Environment,+        System.Exit,+        System.IO,+        System.IO.Error,+        System.IO.Unsafe,+        System.Info,+        System.Mem,+        System.Mem.StableName,+        System.Mem.Weak,+        System.Posix.Internals,+        System.Posix.Types,+        Text.ParserCombinators.ReadP,+        Text.ParserCombinators.ReadPrec,+        Text.Printf,+        Text.Read,+        Text.Read.Lex,+        Text.Show,+        Text.Show.Functions+        Unsafe.Coerce+    other-modules:+        Control.Monad.ST.Imp+        Control.Monad.ST.Lazy.Imp+        Foreign.ForeignPtr.Imp+    c-sources:+        cbits/PrelIOUtils.c+        cbits/WCsubst.c+        cbits/Win32Utils.c+        cbits/consUtils.c+        cbits/iconv.c+        cbits/inputReady.c+        cbits/selectUtils.c+        cbits/primFloat.c+        cbits/md5.c+    include-dirs: include+    includes:    HsBase.h+    install-includes:    HsBase.h HsBaseConfig.h EventConfig.h WCsubst.h consUtils.h Typeable.h+    if os(windows) {+        extra-libraries: wsock32, user32, shell32+    }+    if !os(windows) {+        exposed-modules:+            GHC.Event+        other-modules:+            GHC.Event.Array+            GHC.Event.Clock+            GHC.Event.Control+            GHC.Event.EPoll+            GHC.Event.IntMap+            GHC.Event.Internal+            GHC.Event.KQueue+            GHC.Event.Manager+            GHC.Event.PSQ+            GHC.Event.Poll+            GHC.Event.Thread+            GHC.Event.Unique+    }+    -- We need to set the package name to base (without a version number)+    -- as it's magic.+    ghc-options: -package-name base+    nhc98-options: -H4M -K3M+    extensions: CPP+}
+ TestSuite/inputs/Puns/cabals/parse_error/binary.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/bytestring.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/containers.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/deepseq.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/ghc-prim.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/integer-gmp.cabal view
+ TestSuite/inputs/Puns/cabals/parse_error/mtl.cabal view
+ TestSuite/inputs/Puns/cabals/transformers.cabal view
@@ -0,0 +1,68 @@+name:         transformers+version:      0.3.0.0+license:      BSD3+license-file: LICENSE+author:       Andy Gill, Ross Paterson+maintainer:   Ross Paterson <ross@soi.city.ac.uk>+category:     Control+synopsis:     Concrete functor and monad transformers+description:+    A portable library of functor and monad transformers, inspired by+    the paper \"Functional Programming with Overloading and Higher-Order+    Polymorphism\", by Mark P Jones,+    in /Advanced School of Functional Programming/, 1995+    (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>).+    .+    This package contains:+    .+    * the monad transformer class (in "Control.Monad.Trans.Class")+    .+    * concrete functor and monad transformers, each with associated+      operations and functions to lift operations associated with other+      transformers.+    .+    It can be used on its own in portable Haskell code, or with the monad+    classes in the @mtl@ or @monads-tf@ packages, which automatically+    lift operations introduced by monad transformers through other+    transformers.+build-type: Simple+cabal-version: >= 1.6++source-repository head+  type: darcs+  location: http://code.haskell.org/~ross/transformers++flag ApplicativeInBase+  description: Use the current base package, including Applicative and+    other Functor classes.++library+  if flag(ApplicativeInBase)+    build-depends: base >= 2 && < 6+  else+    build-depends: base >= 1.0 && < 2, special-functors >= 1.0 && < 1.1+  exposed-modules:+    Control.Applicative.Backwards+    Control.Applicative.Lift+    Control.Monad.IO.Class+    Control.Monad.Trans.Class+    Control.Monad.Trans.Cont+    Control.Monad.Trans.Error+    Control.Monad.Trans.Identity+    Control.Monad.Trans.List+    Control.Monad.Trans.Maybe+    Control.Monad.Trans.Reader+    Control.Monad.Trans.RWS+    Control.Monad.Trans.RWS.Lazy+    Control.Monad.Trans.RWS.Strict+    Control.Monad.Trans.State+    Control.Monad.Trans.State.Lazy+    Control.Monad.Trans.State.Strict+    Control.Monad.Trans.Writer+    Control.Monad.Trans.Writer.Lazy+    Control.Monad.Trans.Writer.Strict+    Data.Functor.Compose+    Data.Functor.Constant+    Data.Functor.Identity+    Data.Functor.Product+    Data.Functor.Reverse
+ TestSuite/inputs/README.md view
@@ -0,0 +1,4 @@+This directory contains test inputs for the test suite.++NOTE: There are some hacks in the TestSuite that rely on the structure of this+directory (for instance, see loadModule). 
+ TestSuite/inputs/TH/BlockingOps.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE TemplateHaskell, NamedFieldPuns #-}+-- | Blocking operations such as+--+-- > readMVar v+--+-- may throw an exception such as+--+-- > thread blocked indefinitely in an MVar operation+--+-- Unfortunately, this exception does not give any information of _where_ in+-- the code we are blocked indefinitely. Compiling with profiling info and+-- running with +RTC -xc can address this to some extent, but (1) it requires+-- that all profiling libraries are installed and (2) when we are running+-- multithreaded code the resulting stack trace is often difficult to read+-- (and still does not include line numbers). With this module you can replace+-- the above code with+--+-- > $readMVar v+--+-- and the exception that will be thrown is+--+-- > YourModule:lineNumber: thread blocked indefinitely in an MVar operation+--+-- which is a lot more informative. When the CPP flag DEBUGGING is turned off+-- then @$readMVar@ just turns into @readMVar@.+--+-- NOTE: The type of the exception changes when using DEBUGGING mode -- in order+-- to be able to add the line number, all exceptions are turned into+-- IOExceptions.+module TH.BlockingOps (+    -- * Generic debugging utilities+    lineNumber+  , traceOnException+  , mapExceptionIO+  , mapExceptionShow+    -- * Blocking MVar ops+  , putMVar+  , takeMVar+  , modifyMVar+  , modifyMVar_+  , withMVar+  , readMVar+    -- * Blocking Chan ops+  , readChan+  ) where++import Language.Haskell.TH+import qualified Control.Concurrent as C+import System.IO (hPutStrLn, stderr)+import qualified Control.Exception as Ex++lineNumber :: ExpQ+lineNumber = do+  Loc{loc_module, loc_start=(line, _)} <- location+  [| loc_module ++ ":" ++ show (line :: Int) |]++mapExceptionIO :: (Ex.Exception e1, Ex.Exception e2)+               => (e1 -> e2) -> IO a -> IO a+mapExceptionIO f io = Ex.catch io (Ex.throwIO . f)++mapExceptionShow :: (String -> String) -> IO a -> IO a+mapExceptionShow f = mapExceptionIO (userError . f . showSomeException)+  where+    showSomeException :: Ex.SomeException -> String+    showSomeException = show++traceOnException :: String -> IO a -> IO a+traceOnException str io = Ex.catch io $ \e -> do+  hPutStrLn stderr (str ++ ": " ++ show e)+  Ex.throwIO (e :: Ex.SomeException)++rethrowWithLineNumber1 :: ExpQ -> ExpQ+rethrowWithLineNumber1 expr =+  [| \arg1 -> mapExceptionShow (\e -> $lineNumber ++ ": " ++ e)+                               ($expr arg1)+   |]++rethrowWithLineNumber2 :: ExpQ -> ExpQ+rethrowWithLineNumber2 expr =+  [| \arg1 arg2 -> mapExceptionShow (\e -> $lineNumber ++ ": " ++ e)+                                    ($expr arg1 arg2)+   |]++takeMVar :: ExpQ+takeMVar = rethrowWithLineNumber1 [| C.takeMVar |]++putMVar :: ExpQ+putMVar = rethrowWithLineNumber2 [| C.putMVar |]++readMVar :: ExpQ+readMVar = rethrowWithLineNumber1 [| C.readMVar |]++modifyMVar :: ExpQ+modifyMVar = rethrowWithLineNumber2 [| C.modifyMVar |]++modifyMVar_ :: ExpQ+modifyMVar_ = rethrowWithLineNumber2 [| C.modifyMVar_ |]++withMVar :: ExpQ+withMVar = rethrowWithLineNumber2 [| C.withMVar |]++readChan :: ExpQ+readChan = rethrowWithLineNumber1 [| C.readChan |]
+ TestSuite/inputs/TH/TH.hs view
@@ -0,0 +1,17 @@+module TH.TH where++import Control.Concurrent.MVar (MVar, newEmptyMVar, newMVar)+import TH.BlockingOps (modifyMVar, modifyMVar_, putMVar, readMVar, takeMVar)++main = do+  mv <- newEmptyMVar+  mv2 <- newEmptyMVar+  $putMVar mv mv2+  $putMVar mv2 42+  mv3 <- $takeMVar mv+  $putMVar mv mv3+  $modifyMVar_ mv $ \mv3 -> $modifyMVar_ mv3 (\i -> return $ i + 1)+                            >> return mv2+  mv4 <- $takeMVar mv+  i <- $readMVar mv3+  print $ (mv2 == mv4, i)
+ TestSuite/inputs/bootMods/A.hs view
@@ -0,0 +1,8 @@+module A where++import B( TB(..) )++newtype TA = MkTA Int+    +f :: TB -> TA+f (MkTB x) = MkTA x
+ TestSuite/inputs/bootMods/A.hs-boot view
@@ -0,0 +1,2 @@+module A where+newtype TA = MkTA Int
+ TestSuite/inputs/bootMods/B.hs view
@@ -0,0 +1,8 @@+module B where+import {-# SOURCE #-} A( TA(..) )+    +data TB = MkTB !Int++g :: TA -> TB+g (MkTA x) = MkTB x+
+ TestSuite/inputs/bootMods/C.hs view
@@ -0,0 +1,6 @@+module Main where+import B+import A -- FIX: GHC doesn't seem to figure out this dependency?!++main :: IO ()+main = let f = g in putStrLn "C"
+ TestSuite/inputs/compiler/utils/Exception.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-deprecations #-}+module Exception+    (+    module Control.Exception,+    module Exception+    )+    where++import Prelude hiding (catch)++import Control.Exception++catchIO :: IO a -> (IOException -> IO a) -> IO a+catchIO = catch++handleIO :: (IOException -> IO a) -> IO a -> IO a+handleIO = flip catchIO++tryIO :: IO a -> IO (Either IOException a)+tryIO = try++-- | A monad that can catch exceptions.  A minimal definition+-- requires a definition of 'gcatch'.+--+-- Implementations on top of 'IO' should implement 'gblock' and 'gunblock' to+-- eventually call the primitives 'Control.Exception.block' and+-- 'Control.Exception.unblock' respectively.  These are used for+-- implementations that support asynchronous exceptions.  The default+-- implementations of 'gbracket' and 'gfinally' use 'gblock' and 'gunblock'+-- thus rarely require overriding.+--+class Monad m => ExceptionMonad m where++  -- | Generalised version of 'Control.Exception.catch', allowing an arbitrary+  -- exception handling monad instead of just 'IO'.+  gcatch :: Exception e => m a -> (e -> m a) -> m a++  -- | Generalised version of 'Control.Exception.mask_', allowing an arbitrary+  -- exception handling monad instead of just 'IO'.+  gmask :: ((m a -> m a) -> m b) -> m b++  -- | Generalised version of 'Control.Exception.bracket', allowing an arbitrary+  -- exception handling monad instead of just 'IO'.+  gbracket :: m a -> (a -> m b) -> (a -> m c) -> m c++  -- | Generalised version of 'Control.Exception.finally', allowing an arbitrary+  -- exception handling monad instead of just 'IO'.+  gfinally :: m a -> m b -> m a++  -- | DEPRECATED, here for backwards compatibilty.  Instances can+  -- define either 'gmask', or both 'block' and 'unblock'.+  gblock   :: m a -> m a+  -- | DEPRECATED, here for backwards compatibilty  Instances can+  -- define either 'gmask', or both 'block' and 'unblock'.+  gunblock :: m a -> m a+  -- XXX we're keeping these two methods for the time being because we+  -- have to interact with Haskeline's MonadException class which+  -- still has block/unblock; see GhciMonad.hs.++  gmask    f = gblock (f gunblock)+  gblock   f = gmask (\_ -> f)+  gunblock f = f -- XXX wrong; better override this if you need it++  gbracket before after thing =+    gmask $ \restore -> do+      a <- before+      r <- restore (thing a) `gonException` after a+      _ <- after a+      return r++  a `gfinally` sequel =+    gmask $ \restore -> do+      r <- restore a `gonException` sequel+      _ <- sequel+      return r++#if __GLASGOW_HASKELL__ < 613+instance ExceptionMonad IO where+  gcatch    = catch+  gmask f   = block $ f unblock+  gblock    = block+  gunblock  = unblock+#else+instance ExceptionMonad IO where+  gcatch    = catch+  gmask f   = mask (\x -> f x)+  gblock    = undefined+  gunblock  = undefined+#endif++gtry :: (ExceptionMonad m, Exception e) => m a -> m (Either e a)+gtry act = gcatch (act >>= \a -> return (Right a))+                  (\e -> return (Left e))++-- | Generalised version of 'Control.Exception.handle', allowing an arbitrary+-- exception handling monad instead of just 'IO'.+ghandle :: (ExceptionMonad m, Exception e) => (e -> m a) -> m a -> m a+ghandle = flip gcatch++-- | Always executes the first argument.  If this throws an exception the+-- second argument is executed and the exception is raised again.+gonException :: (ExceptionMonad m) => m a -> m b -> m a+gonException ioA cleanup = ioA `gcatch` \e ->+                             do _ <- cleanup+                                throw (e :: SomeException)++main :: IO ()+main = return ()
+ TestSuite/inputs/compiler/utils/Maybes.lhs view
@@ -0,0 +1,158 @@+%+% (c) The University of Glasgow 2006+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998+%++\begin{code}+{-# OPTIONS -fno-warn-tabs #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ == 708+#endif+-- The above warning supression flag is a temporary kludge.+-- While working on this module you are encouraged to remove it and+-- detab the module (please do the detabbing in a separate patch). See+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces+-- for details++module Maybes (+        module Data.Maybe,++        MaybeErr(..), -- Instance of Monad+        failME, isSuccess,++        fmapM_maybe,+        orElse,+        mapCatMaybes,+        allMaybes,+        firstJust, firstJusts,+        expectJust,+        maybeToBool,++        MaybeT(..),++        main+    ) where++import Control.Applicative+import Control.Monad+import Data.Maybe++infixr 4 `orElse`+\end{code}++%************************************************************************+%*                                                                      *+\subsection[Maybe type]{The @Maybe@ type}+%*                                                                      *+%************************************************************************++\begin{code}+maybeToBool :: Maybe a -> Bool+maybeToBool Nothing  = False+maybeToBool (Just _) = True++-- | Collects a list of @Justs@ into a single @Just@, returning @Nothing@ if+-- there are any @Nothings@.+allMaybes :: [Maybe a] -> Maybe [a]+allMaybes [] = Just []+allMaybes (Nothing : _)  = Nothing+allMaybes (Just x  : ms) = case allMaybes ms of+                           Nothing -> Nothing+                           Just xs -> Just (x:xs)++firstJust :: Maybe a -> Maybe a -> Maybe a+firstJust (Just a) _ = Just a+firstJust Nothing  b = b++-- | Takes a list of @Maybes@ and returns the first @Just@ if there is one, or+-- @Nothing@ otherwise.+firstJusts :: [Maybe a] -> Maybe a+firstJusts = foldr firstJust Nothing+\end{code}++\begin{code}+expectJust :: String -> Maybe a -> a+{-# INLINE expectJust #-}+expectJust _   (Just x) = x+expectJust err Nothing  = error ("expectJust " ++ err)+\end{code}++\begin{code}+mapCatMaybes :: (a -> Maybe b) -> [a] -> [b]+mapCatMaybes _ [] = []+mapCatMaybes f (x:xs) = case f x of+                        Just y  -> y : mapCatMaybes f xs+                        Nothing -> mapCatMaybes f xs+\end{code}++\begin{code}+-- | flipped version of @fromMaybe@.+orElse :: Maybe a -> a -> a+(Just x) `orElse` _ = x+Nothing  `orElse` y = y+\end{code}++\begin{code}+fmapM_maybe :: Monad m => (a -> m b) -> Maybe a -> m (Maybe b)+fmapM_maybe _ Nothing = return Nothing+fmapM_maybe f (Just x) = do+        x' <- f x+        return $ Just x'+\end{code}++%************************************************************************+%*									*+\subsection[MaybeT type]{The @MaybeT@ monad transformer}+%*									*+%************************************************************************++\begin{code}++newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}++instance Functor m => Functor (MaybeT m) where+  fmap f x = MaybeT $ fmap (fmap f) $ runMaybeT x++instance (Monad m, Applicative m) => Applicative (MaybeT m) where+  pure  = return+  (<*>) = ap++instance Monad m => Monad (MaybeT m) where+  return = MaybeT . return . Just+  x >>= f = MaybeT $ runMaybeT x >>= maybe (return Nothing) (runMaybeT . f)+  fail _ = MaybeT $ return Nothing++\end{code}+++%************************************************************************+%*                                                                      *+\subsection[MaybeErr type]{The @MaybeErr@ type}+%*                                                                      *+%************************************************************************++\begin{code}+data MaybeErr err val = Succeeded val | Failed err++instance Functor (MaybeErr err) where+  fmap = liftM++instance Applicative (MaybeErr err) where+  pure  = return+  (<*>) = ap++instance Monad (MaybeErr err) where+  return v = Succeeded v+  Succeeded v >>= k = k v+  Failed e    >>= _ = Failed e++isSuccess :: MaybeErr err val -> Bool+isSuccess (Succeeded {}) = True+isSuccess (Failed {})    = False++failME :: err -> MaybeErr err val+failME e = Failed e++main :: IO ()+main = print $ maybeToBool Nothing+\end{code}
+ TestSuite/inputs/compiler/utils/OrdList.lhs view
@@ -0,0 +1,93 @@+%+% (c) The University of Glasgow 2006+% (c) The AQUA Project, Glasgow University, 1993-1998+%++This is useful, general stuff for the Native Code Generator.++Provide trees (of instructions), so that lists of instructions+can be appended in linear time.++\begin{code}+{-# OPTIONS -fno-warn-tabs #-}+-- The above warning supression flag is a temporary kludge.+-- While working on this module you are encouraged to remove it and+-- detab the module (please do the detabbing in a separate patch). See+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces+-- for details++module OrdList (+	OrdList, +        nilOL, isNilOL, unitOL, appOL, consOL, snocOL, concatOL,+        mapOL, fromOL, toOL, foldrOL, foldlOL+) where++infixl 5  `appOL`+infixl 5  `snocOL`+infixr 5  `consOL`++data OrdList a+  = Many [a]        -- Invariant: non-empty+  | Two (OrdList a) -- Invariant: non-empty+        (OrdList a) -- Invariant: non-empty+  | One  a+  | None++nilOL    :: OrdList a+isNilOL  :: OrdList a -> Bool++unitOL   :: a           -> OrdList a+snocOL   :: OrdList a   -> a         -> OrdList a+consOL   :: a           -> OrdList a -> OrdList a+appOL    :: OrdList a   -> OrdList a -> OrdList a+concatOL :: [OrdList a] -> OrdList a++nilOL        = None+unitOL as    = One as+snocOL None b    = One b+snocOL as   b    = Two as (One b)+consOL a    None = One a+consOL a    bs   = Two (One a) bs+concatOL aas = foldr appOL None aas++isNilOL None = True+isNilOL _    = False++appOL None bs   = bs+appOL as   None = as+appOL as   bs   = Two as bs++mapOL :: (a -> b) -> OrdList a -> OrdList b+mapOL _ None = None+mapOL f (One x) = One (f x)+mapOL f (Two x y) = Two (mapOL f x) (mapOL f y)+mapOL f (Many xs) = Many (map f xs)++instance Functor OrdList where+  fmap = mapOL++foldrOL :: (a->b->b) -> b -> OrdList a -> b+foldrOL _ z None        = z+foldrOL k z (One x)     = k x z+foldrOL k z (Two b1 b2) = foldrOL k (foldrOL k z b2) b1+foldrOL k z (Many xs)   = foldr k z xs++foldlOL :: (b->a->b) -> b -> OrdList a -> b+foldlOL _ z None        = z+foldlOL k z (One x)     = k z x+foldlOL k z (Two b1 b2) = foldlOL k (foldlOL k z b1) b2+foldlOL k z (Many xs)   = foldl k z xs++fromOL :: OrdList a -> [a]+fromOL ol +   = flat ol []+     where+        flat None      rest = rest+        flat (One x)   rest = x:rest+        flat (Two a b) rest = flat a (flat b rest)+        flat (Many xs) rest = xs ++ rest++toOL :: [a] -> OrdList a+toOL [] = None+toOL xs = Many xs+\end{code}
+ TestSuite/inputs/compiler/utils/Subdir/Main.lhs view
@@ -0,0 +1,90 @@+%+% (c) The University of Glasgow 2006+% (c) The AQUA Project, Glasgow University, 1993-1998+%++This is useful, general stuff for the Native Code Generator.++Provide trees (of instructions), so that lists of instructions+can be appended in linear time.++\begin{code}+{-# OPTIONS -fno-warn-tabs #-}+-- The above warning supression flag is a temporary kludge.+-- While working on this module you are encouraged to remove it and+-- detab the module (please do the detabbing in a separate patch). See+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces+-- for details++infixl 5  `appOL`+infixl 5  `snocOL`+infixr 5  `consOL`++data OrdList a+  = Many [a]        -- Invariant: non-empty+  | Two (OrdList a) -- Invariant: non-empty+        (OrdList a) -- Invariant: non-empty+  | One  a+  | None++nilOL    :: OrdList a+isNilOL  :: OrdList a -> Bool++unitOL   :: a           -> OrdList a+snocOL   :: OrdList a   -> a         -> OrdList a+consOL   :: a           -> OrdList a -> OrdList a+appOL    :: OrdList a   -> OrdList a -> OrdList a+concatOL :: [OrdList a] -> OrdList a++nilOL        = None+unitOL as    = One as+snocOL None b    = One b+snocOL as   b    = Two as (One b)+consOL a    None = One a+consOL a    bs   = Two (One a) bs+concatOL aas = foldr appOL None aas++isNilOL None = True+isNilOL _    = False++appOL None bs   = bs+appOL as   None = as+appOL as   bs   = Two as bs++mapOL :: (a -> b) -> OrdList a -> OrdList b+mapOL _ None = None+mapOL f (One x) = One (f x)+mapOL f (Two x y) = Two (mapOL f x) (mapOL f y)+mapOL f (Many xs) = Many (map f xs)++instance Functor OrdList where+  fmap = mapOL++foldrOL :: (a->b->b) -> b -> OrdList a -> b+foldrOL _ z None        = z+foldrOL k z (One x)     = k x z+foldrOL k z (Two b1 b2) = foldrOL k (foldrOL k z b2) b1+foldrOL k z (Many xs)   = foldr k z xs++foldlOL :: (b->a->b) -> b -> OrdList a -> b+foldlOL _ z None        = z+foldlOL k z (One x)     = k z x+foldlOL k z (Two b1 b2) = foldlOL k (foldlOL k z b1) b2+foldlOL k z (Many xs)   = foldl k z xs++fromOL :: OrdList a -> [a]+fromOL ol +   = flat ol []+     where+        flat None      rest = rest+        flat (One x)   rest = x:rest+        flat (Two a b) rest = flat a (flat b rest)+        flat (Many xs) rest = xs ++ rest++toOL :: [a] -> OrdList a+toOL [] = None+toOL xs = Many xs++main :: IO ()+main = return ()+\end{code}
+ TestSuite/inputs/simple-lib17/LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, ++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of  nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ TestSuite/inputs/simple-lib17/Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ TestSuite/inputs/simple-lib17/SimpleLib.hs view
@@ -0,0 +1,4 @@+module SimpleLib where++simpleLib :: Int+simpleLib = 42
+ TestSuite/inputs/simple-lib17/build.sh view
@@ -0,0 +1,2 @@+unset GHC_PACKAGE_PATH+cabal install --package-db=clear --package-db=global --package-db=../packages
+ TestSuite/inputs/simple-lib17/simple-lib17.cabal view
@@ -0,0 +1,19 @@+-- Initial simple-lib.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                simple-lib17+version:             0.1.0.0+-- synopsis:            +-- description:         +license:             BSD3+license-file:        LICENSE+-- author:              +-- maintainer:          +-- copyright:           +-- category:            +build-type:          Simple+cabal-version:       >=1.8++library+  exposed-modules:     SimpleLib+  build-depends:       base
ide-backend.cabal view
@@ -1,5 +1,5 @@ name:                 ide-backend-version:              0.9.0.11+version:              0.10.0 synopsis:             An IDE backend library description:          See README.md for more details license:              MIT@@ -12,10 +12,39 @@ build-type:           Simple cabal-version:        >=1.10 extra-source-files:   README.md+                      TestSuite/inputs/README.md+                      TestSuite/inputs/ABerror/*.hs+                      TestSuite/inputs/AnotherA/*.hs+                      TestSuite/inputs/TH/*.hs+                      TestSuite/inputs/simple-lib17/*.hs+                      TestSuite/inputs/simple-lib17/*.sh+                      TestSuite/inputs/simple-lib17/*.cabal+                      TestSuite/inputs/simple-lib17/LICENSE+                      TestSuite/inputs/MainModule/cabals/*.cabal+                      TestSuite/inputs/MainModule/ParFib/*.hs+                      TestSuite/inputs/MainModule/*.hs+                      TestSuite/inputs/compiler/utils/Subdir/*.lhs+                      TestSuite/inputs/compiler/utils/*.hs+                      TestSuite/inputs/compiler/utils/*.lhs+                      TestSuite/inputs/AnotherB/*.hs+                      TestSuite/inputs/bootMods/*.hs+                      TestSuite/inputs/bootMods/*.hs-boot+                      TestSuite/inputs/ABnoError/*.hs+                      TestSuite/inputs/AerrorB/*.hs+                      TestSuite/inputs/FFI/ffiles/*.c+                      TestSuite/inputs/FFI/ffiles/*.h+                      TestSuite/inputs/FFI/*.hs+                      TestSuite/inputs/FFI/*.h+                      TestSuite/inputs/FFI/*.c+                      TestSuite/inputs/Puns/cabals/parse_error/*.cabal+                      TestSuite/inputs/Puns/cabals/no_text_error/*.cabal+                      TestSuite/inputs/Puns/cabals/*.cabal+                      TestSuite/inputs/Puns/GHC/RTS/*.h+                      TestSuite/inputs/Puns/GHC/RTS/*.hs  library   exposed-modules:    IdeSession-  other-modules:      IdeSession.State,+                      IdeSession.State,                       IdeSession.Config,                       IdeSession.Cabal,                       IdeSession.ExeCabalClient,@@ -47,7 +76,7 @@                       time                 >= 1.4     && < 1.6,                       attoparsec           >= 0.10    && < 0.14,                       utf8-string          >= 0.3     && < 1.1,-                      ide-backend-common   >= 0.9.1   && < 0.10,+                      ide-backend-common   >= 0.10    && < 0.11,                       template-haskell,                       -- our own private fork:                       Cabal-ide-backend    >= 1.23,@@ -174,7 +203,10 @@                       random,                       Cabal-ide-backend,                       containers,-                      deepseq+                      deepseq,+                      -- Dependencies of test suite at runtime+                      parallel,+                      monads-tf   default-language:   Haskell2010   ghc-options:        -Wall                       -threaded@@ -191,7 +223,7 @@ test-suite rpc-server   type:               exitcode-stdio-1.0   main-is:            rpc-server.hs-  hs-source-dirs:     . test+  hs-source-dirs:     test   build-depends:      base                 ==4.*,                       directory            ==1.*,                       filemanip            >= 0.3.6.2 && < 0.4,@@ -209,6 +241,7 @@                       executable-path      >= 0.0     && < 0.1,                       unix                 >= 2.5     && < 2.8,                       binary               >= 0.7.1.0 && < 0.8,+                      ide-backend,                       ide-backend-common,                       template-haskell