@@ -20,53 +20,51 @@ module Language.PureScript.Make
2020 , inferForeignModules
2121 ) where
2222
23−import Prelude.Compat
24−
25−import Control.Concurrent.Lifted as C
26−import Control.Monad hiding (sequence)
27−import Control.Monad.Base (MonadBase(..))
28−import Control.Monad.Error.Class (MonadError(..))
29−import Control.Monad.IO.Class
30−import Control.Monad.Logger
31−import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
32−import Control.Monad.Supply
33−import Control.Monad.Trans.Class (MonadTrans(..))
34−import Control.Monad.Trans.Control (MonadBaseControl(..))
35−import Control.Monad.Trans.Except
36−import Control.Monad.Writer.Class (MonadWriter(..))
37−
38−import Data.Aeson (encode, decode)
23+import Prelude.Compat
24+
25+import Control.Concurrent.Lifted as C
26+import Control.Monad hiding (sequence)
27+import Control.Monad.Base (MonadBase(..))
28+import Control.Monad.Error.Class (MonadError(..))
29+import Control.Monad.IO.Class
30+import Control.Monad.Logger
31+import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
32+import Control.Monad.Supply
33+import Control.Monad.Trans.Class (MonadTrans(..))
34+import Control.Monad.Trans.Control (MonadBaseControl(..))
35+import Control.Monad.Trans.Except
36+import Control.Monad.Writer.Class (MonadWriter(..))
37+import Data.Aeson (encode, decode)
3938import qualified Data.Aeson as Aeson
40−import Data.Either (partitionEithers)
41−import Data.Function (on)
42−import Data.Foldable (for_)
43−import Data.List (foldl', sortBy, groupBy)
44−import Data.Maybe (fromMaybe, catMaybes)
45−import Data.Monoid ((<>))
46−import Data.Time.Clock
47−import Data.Traversable (for)
48−import Data.Version (showVersion)
39+import Data.Either (partitionEithers)
40+import Data.Function (on)
41+import Data.Foldable (for_)
42+import Data.List (foldl', sortBy, groupBy)
43+import Data.Maybe (fromMaybe, catMaybes)
44+import Data.Monoid ((<>))
45+import Data.Time.Clock
46+import Data.Traversable (for)
47+import Data.Version (showVersion)
4948import qualified Data.ByteString.Lazy as B
5049import qualified Data.ByteString.UTF8 as BU8
5150import qualified Data.Map as M
5251import qualified Data.Set as S
5352import qualified Data.Text as T
5453import qualified Data.Text.Encoding as TE
55−
56−import Language.PureScript.AST
57−import Language.PureScript.Crash
58−import Language.PureScript.Environment
59−import Language.PureScript.Errors
60−import Language.PureScript.Externs
61−import Language.PureScript.Linter
62−import Language.PureScript.ModuleDependencies
63−import Language.PureScript.Names
64−import Language.PureScript.Options
65−import Language.PureScript.Pretty
66−import Language.PureScript.Pretty.Common(SMap(..))
67−import Language.PureScript.Renamer
68−import Language.PureScript.Sugar
69−import Language.PureScript.TypeChecker
54+import Language.PureScript.AST
55+import Language.PureScript.Crash
56+import Language.PureScript.Environment
57+import Language.PureScript.Errors
58+import Language.PureScript.Externs
59+import Language.PureScript.Linter
60+import Language.PureScript.ModuleDependencies
61+import Language.PureScript.Names
62+import Language.PureScript.Options
63+import Language.PureScript.Pretty
64+import Language.PureScript.Pretty.Common(SMap(..))
65+import Language.PureScript.Renamer
66+import Language.PureScript.Sugar
67+import Language.PureScript.TypeChecker
7068import qualified Language.JavaScript.Parser as JS
7169import qualified Language.PureScript.Bundle as Bundle
7270import qualified Language.PureScript.CodeGen.JS as J
@@ -74,21 +72,18 @@ import qualified Language.PureScript.Constants as C
7472import qualified Language.PureScript.CoreFn as CF
7573import qualified Language.PureScript.CoreFn.ToJSON as CFJ
7674import qualified Language.PureScript.Parser as PSParser
77−
7875import qualified Paths_purescript as Paths
79−
80−import SourceMap
81−import SourceMap.Types
82−
83−import System.Directory (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
84−import System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise, replaceExtension)
85−import System.IO.Error (tryIOError)
86−
76+import SourceMap
77+import SourceMap.Types
78+import System.Directory (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
79+import System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise, replaceExtension)
80+import System.IO.Error (tryIOError)
8781import qualified Text.Parsec as Parsec
8882
8983-- | Progress messages from the make process
9084data ProgressMessage
9185 = CompilingModule ModuleName
86+ -- ^ Compilation started for the specified module
9287 deriving (Show, Eq, Ord)
9388
9489-- | Render a progress message
@@ -102,7 +97,6 @@ renderProgressMessage (CompilingModule mn) = "Compiling " ++ T.unpack (runModule
10297-- * The particular backend being used (Javascript, C++11, etc.)
10398--
10499-- * The details of how files are read/written etc.
105−--
106100data MakeActions m = MakeActions
107101 { getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
108102 -- ^ Get the timestamp for the input file(s) for a module. If there are multiple
@@ -121,26 +115,26 @@ data MakeActions m = MakeActions
121115 -- ^ Respond to a progress update.
122116 }
123117
124−-- |
125−-- Generated code for an externs file.
126−--
118+-- | Generated code for an externs file.
127119type Externs = B.ByteString
128120
129−-- |
130−-- Determines when to rebuild a module
131−--
121+-- | Determines when to rebuild a module
132122data RebuildPolicy
133123 -- | Never rebuild this module
134124 = RebuildNever
135125 -- | Always rebuild this module
136126 | RebuildAlways deriving (Show, Eq, Ord)
137127
138−-- | Rebuild a single module
139−rebuildModule :: forall m. (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
140− => MakeActions m
141− -> [ExternsFile]
142− -> Module
143− -> m ExternsFile
128+-- | Rebuild a single module.
129+--
130+-- This function is used for fast-rebuild workflows (PSCi and psc-ide are examples).
131+rebuildModule
132+ :: forall m
133+ . (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
134+ => MakeActions m
135+ -> [ExternsFile]
136+ -> Module
137+ -> m ExternsFile
144138rebuildModule MakeActions{..} externs m@(Module _ _ moduleName _ _) = do
145139 progress $ CompilingModule moduleName
146140 let env = foldl' (flip applyExternsFileToEnvironment) initEnvironment externs
@@ -157,12 +151,10 @@ rebuildModule MakeActions{..} externs m@(Module _ _ moduleName _ _) = do
157151 evalSupplyT nextVar . codegen renamed env' . encode $ exts
158152 return exts
159153
160−-- |
161−-- Compiles in "make" mode, compiling each module separately to a js files and an externs file
154+-- | Compiles in "make" mode, compiling each module separately to a @.js@ file and an @externs.json@ file.
162155--
163156-- If timestamps have not changed, the externs file can be used to provide the module's types without
164157-- having to typecheck the module again.
165−--
166158make :: forall m. (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
167159 => MakeActions m
168160 -> [Module]
@@ -244,7 +236,7 @@ make ma@MakeActions{..} ms = do
244236 putMVar (fst $ fromMaybe (internalError "make: no barrier") $ lookup moduleName barriers) externs
245237 putMVar (snd $ fromMaybe (internalError "make: no barrier") $ lookup moduleName barriers) errors
246238
247− maximumMaybe :: (Ord a) => [a] -> Maybe a
239+ maximumMaybe :: Ord a => [a] -> Maybe a
248240 maximumMaybe [] = Nothing
249241 maximumMaybe xs = Just $ maximum xs
250242
@@ -262,11 +254,10 @@ make ma@MakeActions{..} ms = do
262254importPrim :: Module -> Module
263255importPrim = addDefaultImport (ModuleName [ProperName C.prim])
264256
265−-- |
266−-- A monad for running make actions
267−--
268−newtype Make a = Make { unMake :: ReaderT Options (ExceptT MultipleErrors (Logger MultipleErrors)) a }
269− deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
257+-- | A monad for running make actions
258+newtype Make a = Make
259+ { unMake :: ReaderT Options (ExceptT MultipleErrors (Logger MultipleErrors)) a
260+ } deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
270261
271262instance MonadBase IO Make where
272263 liftBase = liftIO
@@ -276,12 +267,12 @@ instance MonadBaseControl IO Make where
276267 liftBaseWith f = Make $ liftBaseWith $ \q -> f (q . unMake)
277268 restoreM = Make . restoreM
278269
279−-- |
280−-- Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
281−--
270+-- | Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
282271runMake :: Options -> Make a -> IO (Either MultipleErrors a, MultipleErrors)
283272runMake opts = runLogger' . runExceptT . flip runReaderT opts . unMake
284273
274+-- | Run an 'IO' action in the 'Make' monad, by specifying how IO errors should
275+-- be rendered as 'ErrorMessage' values.
285276makeIO :: (IOError -> ErrorMessage) -> IO a -> Make a
286277makeIO f io = do
287278 e <- liftIO $ tryIOError io
@@ -299,7 +290,8 @@ inferForeignModules
299290 . MonadIO m
300291 => M.Map ModuleName (Either RebuildPolicy FilePath)
301292 -> m (M.Map ModuleName FilePath)
302−inferForeignModules = fmap (M.mapMaybe id) . traverse inferForeignModule
293+inferForeignModules =
294+ fmap (M.mapMaybe id) . traverse inferForeignModule
303295 where
304296 inferForeignModule :: Either RebuildPolicy FilePath -> m (Maybe FilePath)
305297 inferForeignModule (Left _) = return Nothing
@@ -310,16 +302,19 @@ inferForeignModules = fmap (M.mapMaybe id) . traverse inferForeignModule
310302 then return (Just jsFile)
311303 else return Nothing
312304
313−-- |
314−-- A set of make actions that read and write modules from the given directory.
315−--
316−buildMakeActions :: FilePath -- ^ the output directory
317− -> M.Map ModuleName (Either RebuildPolicy FilePath) -- ^ a map between module names and paths to the file containing the PureScript module
318− -> M.Map ModuleName FilePath -- ^ a map between module name and the file containing the foreign javascript for the module
319− -> Bool -- ^ Generate a prefix comment?
320− -> MakeActions Make
305+-- | A set of make actions that read and write modules from the given directory.
306+buildMakeActions
307+ :: FilePath
308+ -- ^ the output directory
309+ -> M.Map ModuleName (Either RebuildPolicy FilePath)
310+ -- ^ a map between module names and paths to the file containing the PureScript module
311+ -> M.Map ModuleName FilePath
312+ -- ^ a map between module name and the file containing the foreign javascript for the module
313+ -> Bool
314+ -- ^ Generate a prefix comment?
315+ -> MakeActions Make
321316buildMakeActions outputDir filePathMap foreigns usePrefix =
322− MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
317+ MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
323318 where
324319
325320 getInputTimestamp :: ModuleName -> Make (Either RebuildPolicy (Maybe UTCTime))
@@ -421,10 +416,8 @@ buildMakeActions outputDir filePathMap foreigns usePrefix =
421416 progress :: ProgressMessage -> Make ()
422417 progress = liftIO . putStrLn . renderProgressMessage
423418
424−-- |
425−-- Check that the declarations in a given PureScript module match with those
419+-- | Check that the declarations in a given PureScript module match with those
426420-- in its corresponding foreign module.
427−--
428421checkForeignDecls :: CF.Module ann -> FilePath -> SupplyT Make ()
429422checkForeignDecls m path = do
430423 jsStr <- lift $ readTextFile path