git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Parse foreign files for `// module X.Y.Z` comment
330bab9Gary Burgess
psc/Foreign.hsnew file+36
@@ -0,0 +1,36 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Foreign
4+-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>, Gary Burgess <gary.burgess@gmail.com>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module Foreign (parseForeignModulesFromFiles) where
16+
17+import Control.Applicative ((*>), (<*))
18+import Control.Monad (forM, msum)
19+import qualified Data.Map as M
20+import qualified Language.PureScript as P
21+import qualified Text.Parsec as PS
22+
23+parseForeignModulesFromFiles :: [(FilePath, String)] -> Either String (M.Map P.ModuleName String)
24+parseForeignModulesFromFiles files = do
25+ foreigns <- forM files $ \(path, file) -> do
26+ case findModuleName (lines file) of
27+ Just name -> Right (name, file)
28+ Nothing -> Left $ "Could not find a module definition comment in " ++ path
29+ return $ M.fromList foreigns
30+
31+findModuleName :: [String] -> Maybe P.ModuleName
32+findModuleName = msum . map parseComment
33+ where
34+ parseComment :: String -> Maybe P.ModuleName
35+ parseComment s = either (const Nothing) Just $
36+ P.lex "" s >>= P.runTokenParser "" (P.symbol' "//" *> P.reserved "module" *> P.moduleName <* PS.eof)
psc/Main.hs+38−33
@@ -36,14 +36,16 @@ import Options.Applicative as Opts
36import System.Directory (createDirectoryIfMissing)
36import System.Directory (createDirectoryIfMissing)
37import System.Exit (exitSuccess, exitFailure)
37import System.Exit (exitSuccess, exitFailure)
38import System.FilePath (takeDirectory)
38import System.FilePath (takeDirectory)
39−import System.IO (hPrint, hPutStrLn, stderr)
39+import System.IO (hPutStrLn, stderr)
40
40
41import qualified Data.Map as M
41import qualified Data.Map as M
42import qualified Language.PureScript as P
42import qualified Language.PureScript as P
43−import qualified Language.PureScript.Constants as C
44import qualified Language.PureScript.CodeGen.JS as J
43import qualified Language.PureScript.CodeGen.JS as J
44+import qualified Language.PureScript.Constants as C
45import qualified Paths_purescript as Paths
45import qualified Paths_purescript as Paths
46
46
47+import Foreign
48+
47data PSCOptions = PSCOptions
49data PSCOptions = PSCOptions
48 { pscInput :: [FilePath]
50 { pscInput :: [FilePath]
49 , pscForeignInput :: [FilePath]
51 , pscForeignInput :: [FilePath]
@@ -72,13 +74,15 @@ runPSC opts rwe = runWriterT (runReaderT rwe opts)
72
74
73compile :: PSCOptions -> IO ()
75compile :: PSCOptions -> IO ()
74compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
76compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
77+ let prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
75− modules <- P.parseModulesFromFiles (fromMaybe "") <$> readInput (InputOptions (P.optionsNoPrelude opts) stdin input)
78+ moduleFiles <- readInput (InputOptions (P.optionsNoPrelude opts) stdin input)
76− case modules of
79+ foreignFiles <- forM inputForeign (\inFile -> (inFile,) <$> readFile inFile)
80+ case parseInputs moduleFiles foreignFiles of
77 Left err -> do
81 Left err -> do
78− hPrint stderr err
82+ hPutStrLn stderr err
79 exitFailure
83 exitFailure
80− Right ms ->
84+ Right (ms, foreigns) ->
81− case runPSC opts (compileJS (map snd ms) M.empty) of
85+ case runPSC opts (compileJS (map snd ms) M.empty prefix) of
82 Left errs -> do
86 Left errs -> do
83 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
87 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
84 exitFailure
88 exitFailure
@@ -92,32 +96,33 @@ compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
92 Just path -> mkdirp path >> writeFile path exts
96 Just path -> mkdirp path >> writeFile path exts
93 Nothing -> return ()
97 Nothing -> return ()
94 exitSuccess
98 exitSuccess
99+
100+parseInputs :: [(Maybe FilePath, String)] -> [(FilePath, String)] -> Either String ([(Maybe FilePath, P.Module)], M.Map P.ModuleName String)
101+parseInputs modules foreigns =
102+ (,) <$> either (Left . show) Right (P.parseModulesFromFiles (fromMaybe "") modules)
103+ <*> parseForeignModulesFromFiles foreigns
104+
105+compileJS :: forall m. (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m, MonadReader (P.Options P.Compile) m)
106+ => [P.Module] -> M.Map P.ModuleName String -> [String] -> m (String, String)
107+compileJS ms foreigns prefix = do
108+ (modulesToCodeGen, exts, env, nextVar) <- P.compile ms
109+ js <- concat <$> evalSupplyT nextVar (traverse J.moduleToJs modulesToCodeGen)
110+ js' <- generateMain env js
111+ let pjs = unlines $ map ("// " ++) prefix ++ [P.prettyPrintJS js']
112+ return (pjs, exts)
113+
95 where
114 where
96− prefix = if usePrefix
115+
97− then ["Generated by psc version " ++ showVersion Paths.version]
98− else []
99−
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']
107− return (pjs, exts)
108−
109− where
110−
111− generateMain :: P.Environment -> [J.JS] -> m [J.JS]
116+ generateMain :: P.Environment -> [J.JS] -> m [J.JS]
112− generateMain env js = do
117+ generateMain env js = do
113− mainName <- asks P.optionsMain
118+ mainName <- asks P.optionsMain
114− additional <- asks P.optionsAdditional
119+ additional <- asks P.optionsAdditional
115− case P.moduleNameFromString <$> mainName of
120+ case P.moduleNameFromString <$> mainName of
116− Just mmi -> do
121+ Just mmi -> do
117− when ((mmi, P.Ident C.main) `M.notMember` P.names env) $
122+ when ((mmi, P.Ident C.main) `M.notMember` P.names env) $
118− throwError . P.errorMessage $ P.NameIsUndefined (P.Ident C.main)
123+ throwError . P.errorMessage $ P.NameIsUndefined (P.Ident C.main)
119− return $ js ++ [J.mainCall mmi (P.browserNamespace additional)]
124+ return $ js ++ [J.mainCall mmi (P.browserNamespace additional)]
120− _ -> return js
125+ _ -> return js
121
126
122mkdirp :: FilePath -> IO ()
127mkdirp :: FilePath -> IO ()
123mkdirp = createDirectoryIfMissing True . takeDirectory
128mkdirp = createDirectoryIfMissing True . takeDirectory
@@ -199,7 +204,7 @@ inputForeignFile :: Parser FilePath
199inputForeignFile = strOption $
204inputForeignFile = strOption $
200 short 'f'
205 short 'f'
201 <> long "ffi"
206 <> long "ffi"
202− <> help "The input .purs file(s)"
207+ <> help "The input .js file(s) providing foreign import implementations"
203
208
204outputFile :: Parser (Maybe FilePath)
209outputFile :: Parser (Maybe FilePath)
205outputFile = optional . strOption $
210outputFile = optional . strOption $
purescript.cabal+2−1
@@ -44,6 +44,7 @@ library
44 bytestring -any,
44 bytestring -any,
45 text -any,
45 text -any,
46 split -any
46 split -any
47+
47 exposed-modules: Language.PureScript
48 exposed-modules: Language.PureScript
48 Language.PureScript.AST
49 Language.PureScript.AST
49 Language.PureScript.AST.Binders
50 Language.PureScript.AST.Binders
@@ -147,7 +148,7 @@ executable psc
147 main-is: Main.hs
148 main-is: Main.hs
148 buildable: True
149 buildable: True
149 hs-source-dirs: psc
150 hs-source-dirs: psc
150− other-modules:
151+ other-modules: Foreign
151 ghc-options: -Wall -O2 -fno-warn-unused-do-bind
152 ghc-options: -Wall -O2 -fno-warn-unused-do-bind
152
153
153executable psc-make
154executable psc-make