@@ -36,10 +36,11 @@ import System.Environment.XDG.BaseDir
36import System.FilePath ((</>), isPathSeparator)
36import System.FilePath ((</>), isPathSeparator)
37import System.Process
37import System.Process
39+import qualified Data.Map as M
39import qualified Language.PureScript as P
40import qualified Language.PureScript as P
40import qualified Paths_purescript as Paths
41import qualified Paths_purescript as Paths
41import qualified System.IO.UTF8 as U (readFile)
42import qualified System.IO.UTF8 as U (readFile)
42−import qualified Text.Parsec as Parsec (Parsec, ParseError, eof)
43+import qualified Text.Parsec as Parsec (Parsec, eof, try)
45-- The PSCI state.
46-- The PSCI state.
@@ -114,7 +115,7 @@ getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
114-- Loads a file for use with imports.
115-- Loads a file for use with imports.
116loadModule :: FilePath -> IO (Either String [P.Module])
117loadModule :: FilePath -> IO (Either String [P.Module])
117−loadModule = fmap (either (Left . show) Right . parseModules) . U.readFile
118+loadModule = fmap (either (Left . show) Right . P.runIndentParser "" P.parseModules) . U.readFile
120-- Expands tilde in path.
121-- Expands tilde in path.
@@ -190,24 +191,25 @@ options = P.Options True False True (Just "Main") True "PS" []
191-- Makes a volatile module to execute the current expression.
192-- Makes a volatile module to execute the current expression.
193−createTemporaryModule :: [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
194+createTemporaryModule :: Bool -> [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
194−createTemporaryModule imports lets value =
195+createTemporaryModule exec imports lets value =
196 moduleName = P.ModuleName [P.ProperName "Main"]
197 moduleName = P.ModuleName [P.ProperName "Main"]
197 importDecl m = P.ImportDeclaration m Nothing
198 importDecl m = P.ImportDeclaration m Nothing
198 traceModule = P.ModuleName [P.ProperName "Trace"]
199 traceModule = P.ModuleName [P.ProperName "Trace"]
199 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
200 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
200 value' = foldr ($) value lets
201 value' = foldr ($) value lets
202+ itDecl = P.ValueDeclaration (P.Ident "it") [] Nothing value'
201− mainDecl = P.ValueDeclaration (P.Ident "main") [] Nothing (P.App trace value')
203+ mainDecl = P.ValueDeclaration (P.Ident "main") [] Nothing (P.App trace (P.Var (P.Qualified Nothing (P.Ident "it"))))
203− P.Module moduleName $ map (importDecl . P.ModuleName . return) imports ++ [mainDecl]
205+ P.Module moduleName $ map (importDecl . P.ModuleName . return) imports ++ if exec then [itDecl, mainDecl] else [itDecl]
206-- Takes a value declaration and evaluates it with the current state.
208-- Takes a value declaration and evaluates it with the current state.
208handleDeclaration :: P.Value -> PSCI -> InputT IO ()
210handleDeclaration :: P.Value -> PSCI -> InputT IO ()
209handleDeclaration value (PSCI imports loadedModules lets) = do
211handleDeclaration value (PSCI imports loadedModules lets) = do
210− let m = createTemporaryModule imports lets value
212+ let m = createTemporaryModule True imports lets value
211 case P.compile options (loadedModules ++ [m]) of
213 case P.compile options (loadedModules ++ [m]) of
212 Left err -> outputStrLn err
214 Left err -> outputStrLn err
213 Right (js, _, _) -> do
215 Right (js, _, _) -> do
@@ -218,52 +220,49 @@ handleDeclaration value (PSCI imports loadedModules lets) = do
218 Just (ExitFailure _, _, err) -> outputStrLn err
220 Just (ExitFailure _, _, err) -> outputStrLn err
219 Nothing -> outputStrLn "Couldn't find node.js"
221 Nothing -> outputStrLn "Couldn't find node.js"
224−-- PSCI version of the indent parser.
224+-- Takes a value and prints its type
225−-- This really does nothing except provide a shorter alias.
227−parser :: Parsec.Parsec String P.ParseState a -> String -> Either Parsec.ParseError a
226+handleTypeOf :: P.Value -> PSCI -> InputT IO ()
228−parser = P.runIndentParser ""
227+handleTypeOf value (PSCI imports loadedModules lets) = do
228+ let m = createTemporaryModule False imports lets value
229+ case P.compile options { P.optionsMain = Nothing } (loadedModules ++ [m]) of
230+ Left err -> outputStrLn err
231+ Right (_, _, env') ->
232+ case M.lookup (P.ModuleName [P.ProperName "Main"], P.Ident "it") (P.names env') of
233+ Just (ty, _) -> outputStrLn . P.prettyPrintType $ ty
234+ Nothing -> outputStrLn "Could not find type"
230−-- |
236+-- Parser helpers
231−-- Parser for any other valid expression.
233−parseExpression :: String -> Either Parsec.ParseError P.Value
234−parseExpression = parser (P.whiteSpace *> P.parseValue <* Parsec.eof)
237-- Parser for our PSCI version of @let@.
239-- Parser for our PSCI version of @let@.
238-- This is essentially let from do-notation.
240-- This is essentially let from do-notation.
239-- However, since we don't support the @Eff@ monad, we actually want the normal @let@.
241-- However, since we don't support the @Eff@ monad, we actually want the normal @let@.
241−parseLet :: String -> Either Parsec.ParseError (P.Value -> P.Value)
243+parseLet :: Parsec.Parsec String P.ParseState (P.Value -> P.Value)
243− P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
244+parseLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
244− <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
245+ <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
247−-- Parser for PSCI modules.
248+-- Parser for any other valid expression.
249−parseModules :: String -> Either Parsec.ParseError [P.Module]
250+parseExpression :: Parsec.Parsec String P.ParseState P.Value
250−parseModules = parser P.parseModules
251+parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
252-- Commands
253-- Commands
255−-- Performs an action for each meta-command given, and also for expressions.
256+-- Performs an action for each meta-command given, and also for expressions..
257handleCommand :: Command -> StateT PSCI (InputT IO) ()
258handleCommand :: Command -> StateT PSCI (InputT IO) ()
258handleCommand Empty = return ()
259handleCommand Empty = return ()
259handleCommand (Expression ls) =
260handleCommand (Expression ls) =
260− let expr = unlines ls
261+ case P.runIndentParser "" (Left <$> Parsec.try parseLet <|> Right <$> parseExpression) (unlines ls) of
261− in case parseLet expr of
262+ Left err -> inputTToState $ outputStrLn (show err)
262− Left _ ->
263+ Right (Left l) -> modify (updateLets l)
263− either outprintT (\decl -> get >>= inputTToState . handleDeclaration decl)
264+ Right (Right decl) -> get >>= inputTToState . handleDeclaration decl
264− (parseExpression expr)
265− Right l -> modify (updateLets l)
266−handleCommand Help = outputTStrLn helpMessage
265+handleCommand Help = inputTToState $ outputStrLn helpMessage
267handleCommand (Import moduleName) = modify (updateImports moduleName)
266handleCommand (Import moduleName) = modify (updateImports moduleName)
268handleCommand (LoadFile filePath) = do
267handleCommand (LoadFile filePath) = do
269 absPath <- ioToState $ expandTilde filePath
268 absPath <- ioToState $ expandTilde filePath
@@ -275,7 +274,11 @@ handleCommand (LoadFile filePath) = do
275handleCommand Reload = do
274handleCommand Reload = do
276 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
275 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
277 put (PSCI defaultImports prelude [])
276 put (PSCI defaultImports prelude [])
277+handleCommand (TypeOf expr) =
278+ case P.runIndentParser "" parseExpression expr of
279+ Left err -> inputTToState $ outputStrLn (show err)
280+ Right expr' -> get >>= inputTToState . handleTypeOf expr'
278−handleCommand Unknown = outputTStrLn "Unknown command"
281+handleCommand _ = outputTStrLn "Unknown command"
280-- Command helpers
283-- Command helpers