1-----------------------------------------------------------------------------
4-- Copyright : (c) 2013-15 Phil Freeman, (c) 2014-15 Gary Burgess
5-- License : MIT (http://opensource.org/licenses/MIT)
7-- Maintainer : Phil Freeman <paf31@cantab.net>
8-- Stability : experimental
13-----------------------------------------------------------------------------
15{-# LANGUAGE DataKinds #-}
16{-# LANGUAGE FlexibleContexts #-}
17{-# LANGUAGE RecordWildCards #-}
18{-# LANGUAGE TupleSections #-}
22import Control.Applicative
24import Control.Monad.Error.Class (MonadError(..))
25import Control.Monad.Writer.Strict
27import Data.List (isSuffixOf, partition)
28import Data.Version (showVersion)
29import qualified Data.Map as M
30import qualified Data.Aeson as A
31import qualified Data.ByteString.Lazy as B
32import qualified Data.ByteString.UTF8 as BU8
34import Options.Applicative as Opts
36import System.Exit (exitSuccess, exitFailure)
37import System.IO (hPutStrLn, stderr)
39import System.FilePath.Glob (glob)
41import qualified Language.PureScript as P
42import qualified Paths_purescript as Paths
44import Language.PureScript.Make
48data PSCMakeOptions = PSCMakeOptions
49 { pscmInput :: [FilePath]
50 , pscmForeignInput :: [FilePath]
51 , pscmOutputDir :: FilePath
52 , pscmOpts :: P.Options
53 , pscmUsePrefix :: Bool
54 , pscmJSONErrors :: Bool
57data InputOptions = InputOptions
58 { ioInputFiles :: [FilePath]
61-- | Argumnets: verbose, use JSON, warnings, errors
62printWarningsAndErrors :: Bool -> Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO ()
63printWarningsAndErrors verbose False warnings errors = do
64 when (P.nonEmpty warnings) $
65 hPutStrLn stderr (P.prettyPrintMultipleWarnings verbose warnings)
68 hPutStrLn stderr (P.prettyPrintMultipleErrors verbose errs)
71printWarningsAndErrors verbose True warnings errors = do
72 hPutStrLn stderr . BU8.toString . B.toStrict . A.encode $
73 JSONResult (toJSONErrors verbose P.Warning warnings)
74 (either (toJSONErrors verbose P.Error) (const []) errors)
75 either (const exitFailure) (const (return ())) errors
77compile :: PSCMakeOptions -> IO ()
78compile PSCMakeOptions{..} = do
79 input <- globWarningOnMisses (unless pscmJSONErrors . warnFileTypeNotFound) pscmInput
80 when (null input && not pscmJSONErrors) $ do
81 hPutStrLn stderr "psc: No input files."
83 let (jsFiles, pursFiles) = partition (isSuffixOf ".js") input
84 moduleFiles <- readInput (InputOptions pursFiles)
85 inputForeign <- globWarningOnMisses (unless pscmJSONErrors . warnFileTypeNotFound) pscmForeignInput
86 foreignFiles <- forM (inputForeign ++ jsFiles) (\inFile -> (inFile,) <$> readUTF8File inFile)
87 (makeErrors, makeWarnings) <- runMake pscmOpts $ do
88 (ms, foreigns) <- parseInputs moduleFiles foreignFiles
89 let filePathMap = M.fromList $ map (\(fp, P.Module _ _ mn _ _) -> (mn, fp)) ms
90 makeActions = buildMakeActions pscmOutputDir filePathMap foreigns pscmUsePrefix
91 P.make makeActions (map snd ms)
92 printWarningsAndErrors (P.optionsVerboseErrors pscmOpts) pscmJSONErrors makeWarnings makeErrors
95warnFileTypeNotFound :: String -> IO ()
96warnFileTypeNotFound = hPutStrLn stderr . ("psc: No files found using pattern: " ++)
98globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath]
99globWarningOnMisses warn = concatMapM globWithWarning
101 globWithWarning pattern = do
102 paths <- glob pattern
103 when (null paths) $ warn pattern
105 concatMapM f = liftM concat . mapM f
107readInput :: InputOptions -> IO [(Either P.RebuildPolicy FilePath, String)]
108readInput InputOptions{..} = forM ioInputFiles $ \inFile -> (Right inFile, ) <$> readUTF8File inFile
110parseInputs :: (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m)
111 => [(Either P.RebuildPolicy FilePath, String)]
112 -> [(FilePath, P.ForeignJS)]
113 -> m ([(Either P.RebuildPolicy FilePath, P.Module)], M.Map P.ModuleName FilePath)
114parseInputs modules foreigns =
115 (,) <$> P.parseModulesFromFiles (either (const "") id) modules
116 <*> P.parseForeignModulesFromFiles foreigns
118inputFile :: Parser FilePath
119inputFile = strArgument $
121 <> help "The input .purs file(s)"
123inputForeignFile :: Parser FilePath
124inputForeignFile = strOption $
127 <> help "The input .js file(s) providing foreign import implementations"
129outputDirectory :: Parser FilePath
130outputDirectory = strOption $
133 <> Opts.value "output"
135 <> help "The output directory"
137requirePath :: Parser (Maybe FilePath)
138requirePath = optional $ strOption $
140 <> long "require-path"
141 <> help "The path prefix to use for require() calls in the generated JavaScript"
146 <> help "Disable tail call optimizations"
148noMagicDo :: Parser Bool
151 <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad"
156 <> help "Skip the optimization phase"
158comments :: Parser Bool
162 <> help "Include comments in the generated code"
164verboseErrors :: Parser Bool
165verboseErrors = switch $
167 <> long "verbose-errors"
168 <> help "Display verbose error messages"
170noPrefix :: Parser Bool
174 <> help "Do not include comment header"
176jsonErrors :: Parser Bool
179 <> help "Print errors to stderr as JSON"
181options :: Parser P.Options
182options = P.Options <$> noTco
187 <*> (not <$> comments)
190pscMakeOptions :: Parser PSCMakeOptions
191pscMakeOptions = PSCMakeOptions <$> many inputFile
192 <*> many inputForeignFile
195 <*> (not <$> noPrefix)
199main = execParser opts >>= compile
201 opts = info (version <*> helper <*> pscMakeOptions) infoModList
202 infoModList = fullDesc <> headerInfo <> footerInfo
203 headerInfo = header "psc - Compiles PureScript to Javascript"
204 footerInfo = footer $ "psc " ++ showVersion Paths.version
206 version :: Parser (a -> a)
207 version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list