@@ -13,39 +13,35 @@
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
16−{-# LANGUAGE DataKinds #-}
17{-# LANGUAGE DoAndIfThenElse #-}
16{-# LANGUAGE DoAndIfThenElse #-}
18−{-# LANGUAGE FlexibleContexts #-}
19{-# LANGUAGE GeneralizedNewtypeDeriving #-}
17{-# LANGUAGE GeneralizedNewtypeDeriving #-}
20{-# LANGUAGE RecordWildCards #-}
18{-# LANGUAGE RecordWildCards #-}
22module PSCi where
20module PSCi where
24import Data.Foldable (traverse_)
22import Data.Foldable (traverse_)
25−import Data.List (intercalate, nub, sort, isPrefixOf)
23+import Data.List (intercalate, nub, sort)
26import Data.Traversable (traverse)
24import Data.Traversable (traverse)
25+import Data.Tuple (swap)
27import Data.Version (showVersion)
26import Data.Version (showVersion)
28import qualified Data.Map as M
27import qualified Data.Map as M
30import Control.Applicative
29import Control.Applicative
30+import Control.Arrow (first)
31import Control.Monad
31import Control.Monad
32−import Control.Monad.IO.Class (MonadIO, liftIO)
33−import Control.Monad.Error.Class (MonadError(..))
34−import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
35−import Control.Monad.Reader (MonadReader, ReaderT, runReaderT)
36−import Control.Monad.Writer (MonadWriter, WriterT, runWriterT, runWriter)
37import Control.Monad.Trans.Class
32import Control.Monad.Trans.Class
33+import Control.Monad.Trans.Except (runExceptT)
38import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
34import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
39import Control.Monad.Trans.State.Strict
35import Control.Monad.Trans.State.Strict
36+import Control.Monad.Writer (runWriter)
40import qualified Control.Monad.Trans.State.Lazy as L
37import qualified Control.Monad.Trans.State.Lazy as L
42import Options.Applicative as Opts
39import Options.Applicative as Opts
44import System.Console.Haskeline
41import System.Console.Haskeline
45−import System.Directory (createDirectoryIfMissing, getModificationTime, doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
42+import System.Directory (doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
46import System.Exit
43import System.Exit
47−import System.FilePath (pathSeparator, takeDirectory, (</>), isPathSeparator)
44+import System.FilePath (pathSeparator, (</>), isPathSeparator)
48−import System.IO.Error (tryIOError)
49import System.Process (readProcessWithExitCode)
45import System.Process (readProcessWithExitCode)
51import qualified Language.PureScript as P
47import qualified Language.PureScript as P
@@ -53,8 +49,10 @@ import qualified Language.PureScript.Names as N
53import qualified Paths_purescript as Paths
49import qualified Paths_purescript as Paths
55import qualified Directive as D
51import qualified Directive as D
56−import Parser (parseCommand)
57import Completion (completion)
52import Completion (completion)
55+import Parser (parseCommand)
58import Types
56import Types
60-- | The name of the PSCI support module
58-- | The name of the PSCI support module
@@ -88,6 +86,7 @@ supportModule =
90-- File helpers
88-- File helpers
92-- Load the necessary modules.
91-- Load the necessary modules.
@@ -118,7 +117,7 @@ getHistoryFilename = do
118loadModule :: FilePath -> IO (Either String [P.Module])
117loadModule :: FilePath -> IO (Either String [P.Module])
119loadModule filename = do
118loadModule filename = do
120 content <- readFile filename
119 content <- readFile filename
121− return $ either (Left . show) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]
120+ return $ either (Left . P.prettyPrintMultipleErrors False) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]
124-- Load all modules, including the Prelude
123-- Load all modules, including the Prelude
@@ -147,6 +146,7 @@ loadAllImportedModules = do
147expandTilde :: FilePath -> IO FilePath
146expandTilde :: FilePath -> IO FilePath
148expandTilde ('~':p:rest) | isPathSeparator p = (</> rest) <$> getHomeDirectory
147expandTilde ('~':p:rest) | isPathSeparator p = (</> rest) <$> getHomeDirectory
149expandTilde p = return p
148expandTilde p = return p
150-- Messages
150-- Messages
@@ -160,13 +160,12 @@ helpMessage = "The following commands are available:\n\n " ++
160 line :: (Directive, String, String) -> String
160 line :: (Directive, String, String) -> String
161 line (dir, arg, desc) =
161 line (dir, arg, desc) =
162 let cmd = ':' : D.stringFor dir
162 let cmd = ':' : D.stringFor dir
164− [ cmd
163+ in unwords [ cmd
165− , replicate (11 - length cmd) ' '
164+ , replicate (11 - length cmd) ' '
167− , replicate (11 - length arg) ' '
166+ , replicate (11 - length arg) ' '
171 extraHelp =
170 extraHelp =
172 "Further information is available on the PureScript wiki:\n" ++
171 "Further information is available on the PureScript wiki:\n" ++
@@ -194,14 +193,6 @@ prologueMessage = intercalate "\n"
194quitMessage :: String
193quitMessage :: String
195quitMessage = "See ya!"
194quitMessage = "See ya!"
200−-- | Compilation options.
202−options :: P.Options P.Make
203−options = P.Options False False False Nothing False False False P.MakeOptions
206-- PSCI monad
197-- PSCI monad
@@ -210,30 +201,6 @@ newtype PSCI a = PSCI { runPSCI :: InputT (StateT PSCiState IO) a } deriving (Fu
210psciIO :: IO a -> PSCI a
201psciIO :: IO a -> PSCI a
211psciIO io = PSCI . lift $ lift io
202psciIO io = PSCI . lift $ lift io
213−newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (WriterT P.MultipleErrors (ExceptT P.MultipleErrors IO)) a }
214− deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadWriter P.MultipleErrors, MonadReader (P.Options P.Make))
216−runMake :: Make a -> IO (Either P.MultipleErrors a)
217−runMake = runExceptT . fmap fst . runWriterT . flip runReaderT options . unMake
219−makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a
221− e <- liftIO $ tryIOError io
222− either (throwError . P.singleError . f) return e
224−instance P.MonadMake Make where
225− getTimestamp path = makeIO (const (P.SimpleErrorWrapper $ P.CannotGetFileInfo path)) $ do
226− exists <- doesFileExist path
227− traverse (const $ getModificationTime path) $ guard exists
228− readTextFile path = makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile path)) $ readFile path
229− writeTextFile path text = makeIO (const (P.SimpleErrorWrapper $ P.CannotWriteFile path)) $ do
232− progress s = unless ("Compiling $PSCI" `isPrefixOf` s) $ liftIO . putStrLn $ s
234−mkdirp :: FilePath -> IO ()
235−mkdirp = createDirectoryIfMissing True . takeDirectory
238-- Makes a volatile module to execute the current expression.
205-- Makes a volatile module to execute the current expression.
@@ -274,12 +241,14 @@ createTemporaryModuleForImports PSCiState{psciImportedModules = imports} =
274importDecl :: ImportedModule -> P.Declaration
241importDecl :: ImportedModule -> P.Declaration
275importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ
242importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ
277−modulesDir :: FilePath
278−modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"
280indexFile :: FilePath
244indexFile :: FilePath
281indexFile = ".psci_modules" ++ pathSeparator : "index.js"
245indexFile = ".psci_modules" ++ pathSeparator : "index.js"
247+make :: PSCiState -> [(Either P.RebuildPolicy FilePath, P.Module)] -> Make P.Environment
248+make PSCiState{..} ms =
249+ let filePathMap = M.fromList $ (first P.getModuleName . swap) `map` (psciLoadedModules ++ ms)
250+ in P.make (buildMakeActions filePathMap M.empty) (psciLoadedModules ++ ms)
284-- Takes a value declaration and evaluates it with the current state.
253-- Takes a value declaration and evaluates it with the current state.
@@ -288,7 +257,7 @@ handleDeclaration val = do
288 st <- PSCI $ lift get
257 st <- PSCI $ lift get
289 let m = createTemporaryModule True st val
258 let m = createTemporaryModule True st val
290 let nodeArgs = psciNodeFlags st ++ [indexFile]
259 let nodeArgs = psciNodeFlags st ++ [indexFile]
291− e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, supportModule), (Left P.RebuildAlways, m)]) []
260+ e <- psciIO . runMake $ make st [(Left P.RebuildAlways, supportModule), (Left P.RebuildAlways, m)]
292 case e of
261 case e of
293 Left errs -> printErrors errs
262 Left errs -> printErrors errs
294 Right _ -> do
263 Right _ -> do
@@ -309,7 +278,7 @@ handleDecls ds = do
309 st <- PSCI $ lift get
278 st <- PSCI $ lift get
310 let st' = updateLets ds st
279 let st' = updateLets ds st
311 let m = createTemporaryModule False st' (P.ObjectLiteral [])
280 let m = createTemporaryModule False st' (P.ObjectLiteral [])
312− e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st' ++ [(Left P.RebuildAlways, m)]) []
281+ e <- psciIO . runMake $ make st' [(Left P.RebuildAlways, m)]
313 case e of
282 case e of
314 Left err -> printErrors err
283 Left err -> printErrors err
315 Right _ -> PSCI $ lift (put st')
284 Right _ -> PSCI $ lift (put st')
@@ -362,7 +331,7 @@ handleImport :: ImportedModule -> PSCI ()
362handleImport im = do
331handleImport im = do
363 st <- updateImportedModules im <$> PSCI (lift get)
332 st <- updateImportedModules im <$> PSCI (lift get)
364 let m = createTemporaryModuleForImports st
333 let m = createTemporaryModuleForImports st
365− e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []
334+ e <- psciIO . runMake $ make st [(Left P.RebuildAlways, m)]
366 case e of
335 case e of
367 Left errs -> printErrors errs
336 Left errs -> printErrors errs
368 Right _ -> do
337 Right _ -> do
@@ -376,7 +345,7 @@ handleTypeOf :: P.Expr -> PSCI ()
376handleTypeOf val = do
345handleTypeOf val = do
377 st <- PSCI $ lift get
346 st <- PSCI $ lift get
378 let m = createTemporaryModule False st val
347 let m = createTemporaryModule False st val
379− e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []
348+ e <- psciIO . runMake $ make st [(Left P.RebuildAlways, m)]
380 case e of
349 case e of
381 Left errs -> printErrors errs
350 Left errs -> printErrors errs
382 Right env' ->
351 Right env' ->
@@ -409,12 +378,11 @@ printModuleSignatures moduleName env =
409handleBrowse :: P.ModuleName -> PSCI ()
378handleBrowse :: P.ModuleName -> PSCI ()
410handleBrowse moduleName = do
379handleBrowse moduleName = do
411 st <- PSCI $ lift get
380 st <- PSCI $ lift get
412− let loadedModules = psciLoadedModules st
413− env <- psciIO . runMake $ P.make modulesDir loadedModules []
381+ env <- psciIO . runMake $ make st []
414 case env of
382 case env of
415 Left errs -> printErrors errs
383 Left errs -> printErrors errs
416 Right env' ->
384 Right env' ->
417− if moduleName `notElem` (nub . map ((\ (P.Module _ modName _ _ ) -> modName) . snd)) loadedModules
385+ if moduleName `notElem` (nub . map ((\ (P.Module _ modName _ _ ) -> modName) . snd)) (psciLoadedModules st)
418 then PSCI $ outputStrLn $ "Module '" ++ N.runModuleName moduleName ++ "' is not valid."
386 then PSCI $ outputStrLn $ "Module '" ++ N.runModuleName moduleName ++ "' is not valid."
419 else printModuleSignatures moduleName env'
387 else printModuleSignatures moduleName env'
@@ -430,7 +398,7 @@ handleKindOf typ = do
430 st <- PSCI $ lift get
398 st <- PSCI $ lift get
431 let m = createTemporaryModuleForKind st typ
399 let m = createTemporaryModuleForKind st typ
432 mName = P.ModuleName [P.ProperName "$PSCI"]
400 mName = P.ModuleName [P.ProperName "$PSCI"]
433− e <- psciIO . runMake $ P.make modulesDir (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []
401+ e <- psciIO . runMake $ make st [(Left P.RebuildAlways, m)]
434 case e of
402 case e of
435 Left errs -> printErrors errs
403 Left errs -> printErrors errs
436 Right env' ->
404 Right env' ->
@@ -519,7 +487,7 @@ loop PSCiOptions{..} = do
519 config <- loadUserConfig
487 config <- loadUserConfig
520 modulesOrFirstError <- loadAllModules psciInputFile
488 modulesOrFirstError <- loadAllModules psciInputFile
521 case modulesOrFirstError of
489 case modulesOrFirstError of
522− Left err -> print err >> exitFailure
490+ Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
523 Right modules -> do
491 Right modules -> do
524 historyFilename <- getHistoryFilename
492 historyFilename <- getHistoryFilename
525 let settings = defaultSettings { historyFile = Just historyFilename }
493 let settings = defaultSettings { historyFile = Just historyFilename }