@@ -13,39 +13,35 @@
1313--
1414-----------------------------------------------------------------------------
1515
16−{-# LANGUAGE DataKinds #-}
1716{-# LANGUAGE DoAndIfThenElse #-}
18−{-# LANGUAGE FlexibleContexts #-}
1917{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2018{-# LANGUAGE RecordWildCards #-}
2119
2220module PSCi where
2321
2422import Data.Foldable (traverse_)
25−import Data.List (intercalate, nub, sort, isPrefixOf)
23+import Data.List (intercalate, nub, sort)
2624import Data.Traversable (traverse)
25+import Data.Tuple (swap)
2726import Data.Version (showVersion)
2827import qualified Data.Map as M
2928
3029import Control.Applicative
30+import Control.Arrow (first)
3131import 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)
3732import Control.Monad.Trans.Class
33+import Control.Monad.Trans.Except (runExceptT)
3834import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
3935import Control.Monad.Trans.State.Strict
36+import Control.Monad.Writer (runWriter)
4037import qualified Control.Monad.Trans.State.Lazy as L
4138
4239import Options.Applicative as Opts
4340
4441import System.Console.Haskeline
45−import System.Directory (createDirectoryIfMissing, getModificationTime, doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
42+import System.Directory (doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
4643import System.Exit
47−import System.FilePath (pathSeparator, takeDirectory, (</>), isPathSeparator)
48−import System.IO.Error (tryIOError)
44+import System.FilePath (pathSeparator, (</>), isPathSeparator)
4945import System.Process (readProcessWithExitCode)
5046
5147import qualified Language.PureScript as P
@@ -53,8 +49,10 @@ import qualified Language.PureScript.Names as N
5349import qualified Paths_purescript as Paths
5450
5551import qualified Directive as D
56−import Parser (parseCommand)
5752import Completion (completion)
53+import IO (mkdirp)
54+import Make
55+import Parser (parseCommand)
5856import Types
5957
6058-- | The name of the PSCI support module
@@ -88,6 +86,7 @@ supportModule =
8886 ]
8987
9088-- File helpers
89+
9190-- |
9291-- Load the necessary modules.
9392--
@@ -118,7 +117,7 @@ getHistoryFilename = do
118117loadModule :: FilePath -> IO (Either String [P.Module])
119118loadModule filename = do
120119 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)]
122121
123122-- |
124123-- Load all modules, including the Prelude
@@ -147,6 +146,7 @@ loadAllImportedModules = do
147146expandTilde :: FilePath -> IO FilePath
148147expandTilde ('~':p:rest) | isPathSeparator p = (</> rest) <$> getHomeDirectory
149148expandTilde p = return p
149+
150150-- Messages
151151
152152-- |
@@ -160,13 +160,12 @@ helpMessage = "The following commands are available:\n\n " ++
160160 line :: (Directive, String, String) -> String
161161 line (dir, arg, desc) =
162162 let cmd = ':' : D.stringFor dir
163− in intercalate " "
164− [ cmd
165− , replicate (11 - length cmd) ' '
166− , arg
167− , replicate (11 - length arg) ' '
168− , desc
169− ]
163+ in unwords [ cmd
164+ , replicate (11 - length cmd) ' '
165+ , arg
166+ , replicate (11 - length arg) ' '
167+ , desc
168+ ]
170169
171170 extraHelp =
172171 "Further information is available on the PureScript wiki:\n" ++
@@ -194,14 +193,6 @@ prologueMessage = intercalate "\n"
194193quitMessage :: String
195194quitMessage = "See ya!"
196195
197−
198−-- Compilation
199−
200−-- | Compilation options.
201−--
202−options :: P.Options P.Make
203−options = P.Options False False False Nothing False False False P.MakeOptions
204−
205196-- |
206197-- PSCI monad
207198--
@@ -210,30 +201,6 @@ newtype PSCI a = PSCI { runPSCI :: InputT (StateT PSCiState IO) a } deriving (Fu
210201psciIO :: IO a -> PSCI a
211202psciIO io = PSCI . lift $ lift io
212203
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))
215−
216−runMake :: Make a -> IO (Either P.MultipleErrors a)
217−runMake = runExceptT . fmap fst . runWriterT . flip runReaderT options . unMake
218−
219−makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a
220−makeIO f io = do
221− e <- liftIO $ tryIOError io
222− either (throwError . P.singleError . f) return e
223−
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
230− mkdirp path
231− writeFile path text
232− progress s = unless ("Compiling $PSCI" `isPrefixOf` s) $ liftIO . putStrLn $ s
233−
234−mkdirp :: FilePath -> IO ()
235−mkdirp = createDirectoryIfMissing True . takeDirectory
236−
237204-- |
238205-- Makes a volatile module to execute the current expression.
239206--
@@ -274,12 +241,14 @@ createTemporaryModuleForImports PSCiState{psciImportedModules = imports} =
274241importDecl :: ImportedModule -> P.Declaration
275242importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ
276243
277−modulesDir :: FilePath
278−modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"
279−
280244indexFile :: FilePath
281245indexFile = ".psci_modules" ++ pathSeparator : "index.js"
282246
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)
251+
283252-- |
284253-- Takes a value declaration and evaluates it with the current state.
285254--
@@ -288,7 +257,7 @@ handleDeclaration val = do
288257 st <- PSCI $ lift get
289258 let m = createTemporaryModule True st val
290259 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)]
292261 case e of
293262 Left errs -> printErrors errs
294263 Right _ -> do
@@ -309,7 +278,7 @@ handleDecls ds = do
309278 st <- PSCI $ lift get
310279 let st' = updateLets ds st
311280 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)]
313282 case e of
314283 Left err -> printErrors err
315284 Right _ -> PSCI $ lift (put st')
@@ -362,7 +331,7 @@ handleImport :: ImportedModule -> PSCI ()
362331handleImport im = do
363332 st <- updateImportedModules im <$> PSCI (lift get)
364333 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)]
366335 case e of
367336 Left errs -> printErrors errs
368337 Right _ -> do
@@ -376,7 +345,7 @@ handleTypeOf :: P.Expr -> PSCI ()
376345handleTypeOf val = do
377346 st <- PSCI $ lift get
378347 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)]
380349 case e of
381350 Left errs -> printErrors errs
382351 Right env' ->
@@ -409,12 +378,11 @@ printModuleSignatures moduleName env =
409378handleBrowse :: P.ModuleName -> PSCI ()
410379handleBrowse moduleName = do
411380 st <- PSCI $ lift get
412− let loadedModules = psciLoadedModules st
413− env <- psciIO . runMake $ P.make modulesDir loadedModules []
381+ env <- psciIO . runMake $ make st []
414382 case env of
415383 Left errs -> printErrors errs
416384 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)
418386 then PSCI $ outputStrLn $ "Module '" ++ N.runModuleName moduleName ++ "' is not valid."
419387 else printModuleSignatures moduleName env'
420388
@@ -430,7 +398,7 @@ handleKindOf typ = do
430398 st <- PSCI $ lift get
431399 let m = createTemporaryModuleForKind st typ
432400 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)]
434402 case e of
435403 Left errs -> printErrors errs
436404 Right env' ->
@@ -519,7 +487,7 @@ loop PSCiOptions{..} = do
519487 config <- loadUserConfig
520488 modulesOrFirstError <- loadAllModules psciInputFile
521489 case modulesOrFirstError of
522− Left err -> print err >> exitFailure
490+ Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
523491 Right modules -> do
524492 historyFilename <- getHistoryFilename
525493 let settings = defaultSettings { historyFile = Just historyFilename }