@@ -7,6 +7,7 @@ module Main (main) where
77
88import Control.Monad (unless , foldM )
99import Control.Monad.Error.Class (throwError )
10+ import Control.Monad.IO.Class (liftIO )
1011import Control.Monad.Logger (runLogger' )
1112import qualified Control.Monad.State as State
1213import Control.Monad.Trans (lift )
@@ -15,25 +16,30 @@ import Control.Monad.Trans.Reader (runReaderT)
1516import Control.Monad.Writer.Strict (runWriterT )
1617import qualified Data.Aeson as A
1718import Data.Aeson ((.=) )
18- import Data.Bifunctor (first , second )
19+ import Data.Bifunctor (first , second , bimap )
1920import qualified Data.ByteString.Lazy as BL
2021import Data.Default (def )
2122import Data.Function (on )
23+ import qualified Data.IORef as IORef
2224import Data.List (nubBy )
2325import qualified Data.List.NonEmpty as NE
2426import qualified Data.Map as M
2527import Data.Text (Text )
2628import qualified Data.Text as T
2729import qualified Data.Text.Encoding as T
30+ import Data.Time.Clock (UTCTime )
2831import GHC.Generics (Generic )
2932import qualified Language.PureScript as P
3033import qualified Language.PureScript.CST as CST
3134import qualified Language.PureScript.CST.Monad as CSTM
3235import qualified Language.PureScript.CodeGen.JS as J
3336import qualified Language.PureScript.CodeGen.JS.Printer as P
3437import qualified Language.PureScript.CoreFn as CF
38+ import qualified Language.PureScript.Docs.Types as Docs
3539import qualified Language.PureScript.Errors.JSON as P
3640import qualified Language.PureScript.Interactive as I
41+ import qualified Language.PureScript.Make as Make
42+ import qualified Language.PureScript.Make.Cache as Cache
3743import qualified Language.PureScript.TypeChecker.TypeSearch as TS
3844import qualified Network.Wai.Handler.Warp as Warp
3945import System.Environment (getArgs )
@@ -51,33 +57,90 @@ data Error
5157
5258instance A. ToJSON Error
5359
60+ toCompilerErrors :: NE. NonEmpty CST. ParserError -> Error
61+ toCompilerErrors = CompilerErrors . toJsonErrors . CST. toMultipleErrors " <file>"
62+
63+ toJsonErrors :: P. MultipleErrors -> [P. JSONError ]
64+ toJsonErrors = P. toJSONErrors False P. Error
65+
66+ -- As of PureScript 0.14 we only need the `codegen` part of `MakeActions` to run
67+ -- Try PureScript, because we already know all dependencies are compiled, we're
68+ -- only building one module, we don't allow FFI declarations, and we want to
69+ -- avoid writing to the file system as much as possible.
70+ buildMakeActions :: IORef. IORef (Maybe JS ) -> Make. MakeActions Make. Make
71+ buildMakeActions codegenRef =
72+ Make. MakeActions
73+ getInputTimestampsAndHashes
74+ getOutputTimestamp
75+ readExterns
76+ codegen
77+ ffiCodegen
78+ progress
79+ readCacheDb
80+ writeCacheDb
81+ outputPrimDocs
82+ where
83+ getInputTimestampsAndHashes :: P. ModuleName -> Make. Make (Either Make. RebuildPolicy (M. Map FilePath (UTCTime , Make. Make Cache. ContentHash )))
84+ getInputTimestampsAndHashes _ = pure $ Right M. empty
85+
86+ getOutputTimestamp :: P. ModuleName -> Make. Make (Maybe UTCTime )
87+ getOutputTimestamp _ = pure Nothing
88+
89+ readExterns :: P. ModuleName -> Make. Make (FilePath , Maybe P. ExternsFile )
90+ readExterns _ = pure (" <file>" , Nothing )
91+
92+ codegen :: CF. Module CF. Ann -> Docs. Module -> P. ExternsFile -> P. SupplyT Make. Make ()
93+ codegen m _ _ = do
94+ rawJs <- J. moduleToJs m Nothing
95+ lift $ liftIO $ IORef. writeIORef codegenRef $ Just $ P. prettyPrintJS rawJs
96+
97+ -- If we ever support FFI implementations in Try PureScript then we will need
98+ -- to implement this function. However, we do not plan to support this feature.
99+ ffiCodegen :: CF. Module CF. Ann -> Make. Make ()
100+ ffiCodegen _ = pure ()
101+
102+ progress :: Make. ProgressMessage -> Make. Make ()
103+ progress _ = pure ()
104+
105+ readCacheDb :: Make. Make Cache. CacheDb
106+ readCacheDb = pure M. empty
107+
108+ writeCacheDb :: Cache. CacheDb -> Make. Make ()
109+ writeCacheDb _ = pure ()
110+
111+ outputPrimDocs :: Make. Make ()
112+ outputPrimDocs = pure ()
113+
54114server :: [P. ExternsFile ] -> P. Env -> P. Environment -> Int -> IO ()
55115server externs initNamesEnv initEnv port = do
116+ codegenRef <- IORef. newIORef Nothing
117+ let makeActions = buildMakeActions codegenRef
56118 let compile :: Text -> IO (Either Error ([P. JSONError ], JS ))
57119 compile input
58- | T. length input > 20000 = return ( Left ( OtherError " Please limit your input to 20000 characters" ))
120+ | T. length input > 20000 = return $ Left $ OtherError " Please limit your input to 20000 characters"
59121 | otherwise = do
60- case CST. parseModuleFromFile " <file>" input >>= CST. resFull of
61- Left parseError ->
62- return . Left . CompilerErrors . P. toJSONErrors False P. Error $ CST. toMultipleErrors " <file>" parseError
63- Right m | P. getModuleName m == P. ModuleName " Main" -> do
64- (resultMay, ws) <- runLogger' . runExceptT . flip runReaderT P. defaultOptions $ do
65- ((P. Module ss coms moduleName elaborated exps, env), nextVar) <- P. runSupplyT 0 $ do
66- desugared <- P. desugar initNamesEnv externs [P. importPrim m] >>= \ case
67- [d] -> pure d
68- _ -> error " desugaring did not produce one module"
69- P. runCheck' (P. emptyCheckState initEnv) $ P. typeCheckModule desugared
70- regrouped <- P. createBindingGroups moduleName . P. collapseBindingGroups $ elaborated
71- let mod' = P. Module ss coms moduleName regrouped exps
72- corefn = CF. moduleToCoreFn env mod'
73- [renamed] = P. renameInModules [corefn]
74- unless (null . CF. moduleForeign $ renamed) . throwError . P. errorMessage $ P. MissingFFIModule moduleName
75- P. evalSupplyT nextVar $ P. prettyPrintJS <$> J. moduleToJs renamed Nothing
76- case resultMay of
77- Left errs -> (return . Left . CompilerErrors . P. toJSONErrors False P. Error ) errs
78- Right js -> (return . Right ) (P. toJSONErrors False P. Error ws, js)
79- Right _ ->
80- (return . Left . OtherError ) " The name of the main module should be Main."
122+ case CST. parseModuleFromFile " <file>" input of
123+ Left parserErrors ->
124+ return $ Left $ toCompilerErrors parserErrors
125+
126+ Right partialResult -> case CST. resFull partialResult of
127+ (_, Left parserErrors) ->
128+ return $ Left $ toCompilerErrors parserErrors
129+
130+ (parserWarnings, Right m) | P. getModuleName m == P. ModuleName " Main" -> do
131+ (makeResult, warnings) <- Make. runMake P. defaultOptions $ Make. rebuildModule makeActions [] m
132+ codegenResult <- IORef. readIORef codegenRef
133+ return $ case makeResult of
134+ Left errors ->
135+ Left $ CompilerErrors $ toJsonErrors errors
136+ Right _ | Just js <- codegenResult -> do
137+ let ws = warnings <> CST. toMultipleWarnings " <file>" parserWarnings
138+ Right (toJsonErrors ws, js)
139+ Right _ ->
140+ Left $ OtherError " Failed to read the results of codegen."
141+
142+ (_, Right _) ->
143+ return $ Left $ OtherError " The name of the main module should be Main."
81144
82145 scottyOpts (getOpts port) $ do
83146 get " /" $
@@ -102,7 +165,8 @@ server externs initNamesEnv initEnv port = do
102165 search = fst . TS. typeSearch (Just [] ) initEnv (P. emptyCheckState initEnv)
103166 results = nubBy ((==) `on` fst ) $ do
104167 elab <- elabs
105- let strictMatches = search (replaceTypeVariablesAndDesugar (\ nm s -> P. Skolem P. NullSourceAnn nm s (P. SkolemScope 0 )) elab)
168+ let mkSkolemType nm s = P. Skolem P. NullSourceAnn nm Nothing s (P. SkolemScope 0 )
169+ strictMatches = search (replaceTypeVariablesAndDesugar mkSkolemType elab)
106170 flexMatches = search (replaceTypeVariablesAndDesugar (const (P. TUnknown P. NullSourceAnn )) elab)
107171 take 50 (strictMatches ++ flexMatches)
108172 Scotty. json $ A. object [ " results" .= [ P. showQualified id k
@@ -154,7 +218,7 @@ tryParseType = hush . fmap (CST.convertType "<file>") . runParser CST.parseTypeP
154218
155219 runParser :: CST. Parser a -> Text -> Either String a
156220 runParser p =
157- first (CST. prettyPrintError . NE. head )
221+ bimap (CST. prettyPrintError . NE. head ) snd
158222 . CST. runTokenParser (p <* CSTM. token CST. TokEof )
159223 . CST. lexTopLevel
160224
0 commit comments