@@ -12,40 +12,52 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
15−{-# LANGUAGE DataKinds, GeneralizedNewtypeDeriving, TupleSections, RecordWildCards #-}
15+{-# LANGUAGE DataKinds #-}
16+{-# LANGUAGE FlexibleContexts #-}
17+{-# LANGUAGE RecordWildCards #-}
18+{-# LANGUAGE ScopedTypeVariables #-}
19+{-# LANGUAGE TupleSections #-}
17module Main where
21module Main where
19import Control.Applicative
23import Control.Applicative
20import Control.Monad
24import Control.Monad
25+import Control.Monad.Error.Class (MonadError(..))
21import Control.Monad.Reader
26import Control.Monad.Reader
27+import Control.Monad.Supply (evalSupplyT)
22import Control.Monad.Writer
28import Control.Monad.Writer
24import Data.Maybe (fromMaybe)
30import Data.Maybe (fromMaybe)
31+import Data.Traversable (traverse)
25import Data.Version (showVersion)
32import Data.Version (showVersion)
27import Options.Applicative as Opts
34import Options.Applicative as Opts
28import System.Directory (createDirectoryIfMissing)
36import System.Directory (createDirectoryIfMissing)
29−import System.FilePath (takeDirectory)
30import System.Exit (exitSuccess, exitFailure)
37import System.Exit (exitSuccess, exitFailure)
38+import System.FilePath (takeDirectory)
31−import System.IO (hPutStrLn, stderr)
39+import System.IO (hPrint, hPutStrLn, stderr)
41+import qualified Data.Map as M
33import qualified Language.PureScript as P
42import qualified Language.PureScript as P
43+import qualified Language.PureScript.Constants as C
44+import qualified Language.PureScript.CodeGen.JS as J
34import qualified Paths_purescript as Paths
45import qualified Paths_purescript as Paths
36data PSCOptions = PSCOptions
47data PSCOptions = PSCOptions
37− { pscInput :: [FilePath]
48+ { pscInput :: [FilePath]
49+ , pscForeignInput :: [FilePath]
38− , pscOpts :: P.Options P.Compile
50+ , pscOpts :: P.Options P.Compile
39− , pscStdIn :: Bool
51+ , pscStdIn :: Bool
40− , pscOutput :: Maybe FilePath
52+ , pscOutput :: Maybe FilePath
41− , pscExterns :: Maybe FilePath
53+ , pscExterns :: Maybe FilePath
42− , pscUsePrefix :: Bool
54+ , pscUsePrefix :: Bool
45data InputOptions = InputOptions
57data InputOptions = InputOptions
46− { ioNoPrelude :: Bool
58+ { ioNoPrelude :: Bool
47− , ioUseStdIn :: Bool
59+ , ioUseStdIn :: Bool
48− , ioInputFiles :: [FilePath]
60+ , ioInputFiles :: [FilePath]
51readInput :: InputOptions -> IO [(Maybe FilePath, String)]
63readInput :: InputOptions -> IO [(Maybe FilePath, String)]
@@ -59,19 +71,19 @@ runPSC :: P.Options P.Compile -> PSC a -> Either P.MultipleErrors (a, P.Multiple
59runPSC opts rwe = runWriterT (runReaderT rwe opts)
71runPSC opts rwe = runWriterT (runReaderT rwe opts)
61compile :: PSCOptions -> IO ()
73compile :: PSCOptions -> IO ()
62−compile (PSCOptions input opts stdin output externs usePrefix) = do
74+compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
63 modules <- P.parseModulesFromFiles (fromMaybe "") <$> readInput (InputOptions (P.optionsNoPrelude opts) stdin input)
75 modules <- P.parseModulesFromFiles (fromMaybe "") <$> readInput (InputOptions (P.optionsNoPrelude opts) stdin input)
64 case modules of
76 case modules of
65 Left err -> do
77 Left err -> do
66− hPutStrLn stderr $ show err
78+ hPrint stderr err
67 exitFailure
79 exitFailure
68− Right ms -> do
80+ Right ms ->
69− case runPSC opts (P.compile (map snd ms) prefix) of
81+ case runPSC opts (compileJS (map snd ms) M.empty) of
70 Left errs -> do
82 Left errs -> do
71 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
83 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
72 exitFailure
84 exitFailure
73− Right ((js, exts, _), warnings) -> do
85+ Right ((js, exts), warnings) -> do
74− when (P.nonEmpty warnings) $
86+ when (P.nonEmpty warnings) $
75 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
87 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
76 case output of
88 case output of
77 Just path -> mkdirp path >> writeFile path js
89 Just path -> mkdirp path >> writeFile path js
@@ -85,6 +97,28 @@ compile (PSCOptions input opts stdin output externs usePrefix) = do
85 then ["Generated by psc version " ++ showVersion Paths.version]
97 then ["Generated by psc version " ++ showVersion Paths.version]
100+ compileJS :: forall m. (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m, MonadReader (P.Options P.Compile) m)
101+ => [P.Module] -> M.Map P.ModuleName String -> m (String, String)
102+ compileJS ms foreigns = do
103+ (modulesToCodeGen, exts, env, nextVar) <- P.compile ms
104+ js <- concat <$> evalSupplyT nextVar (traverse J.moduleToJs modulesToCodeGen)
105+ js' <- generateMain env js
106+ let pjs = unlines $ map ("// " ++) prefix ++ [P.prettyPrintJS js']
111+ generateMain :: P.Environment -> [J.JS] -> m [J.JS]
112+ generateMain env js = do
113+ mainName <- asks P.optionsMain
114+ additional <- asks P.optionsAdditional
115+ case P.moduleNameFromString <$> mainName of
117+ when ((mmi, P.Ident C.main) `M.notMember` P.names env) $
118+ throwError . P.errorMessage $ P.NameIsUndefined (P.Ident C.main)
119+ return $ js ++ [J.mainCall mmi (P.browserNamespace additional)]
88mkdirp :: FilePath -> IO ()
122mkdirp :: FilePath -> IO ()
89mkdirp = createDirectoryIfMissing True . takeDirectory
123mkdirp = createDirectoryIfMissing True . takeDirectory
@@ -161,6 +195,12 @@ inputFile = strArgument $
161 metavar "FILE"
195 metavar "FILE"
162 <> help "The input .purs file(s)"
196 <> help "The input .purs file(s)"
198+inputForeignFile :: Parser FilePath
199+inputForeignFile = strOption $
202+ <> help "The input .purs file(s)"
164outputFile :: Parser (Maybe FilePath)
204outputFile :: Parser (Maybe FilePath)
165outputFile = optional . strOption $
205outputFile = optional . strOption $
166 short 'o'
206 short 'o'
@@ -196,6 +236,7 @@ options = P.Options <$> noPrelude
197pscOptions :: Parser PSCOptions
237pscOptions :: Parser PSCOptions
198pscOptions = PSCOptions <$> many inputFile
238pscOptions = PSCOptions <$> many inputFile
239+ <*> many inputForeignFile
199 <*> options
240 <*> options
200 <*> useStdIn
241 <*> useStdIn
201 <*> outputFile
242 <*> outputFile
@@ -212,4 +253,3 @@ main = execParser opts >>= compile
213 version :: Parser (a -> a)
254 version :: Parser (a -> a)
214 version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
255 version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden