@@ -36,10 +36,11 @@ import System.Environment.XDG.BaseDir
3636import System.FilePath ((</>), isPathSeparator)
3737import System.Process
3838
39+import qualified Data.Map as M
3940import qualified Language.PureScript as P
4041import qualified Paths_purescript as Paths
4142import 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)
4344
4445-- |
4546-- The PSCI state.
@@ -114,7 +115,7 @@ getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
114115-- Loads a file for use with imports.
115116--
116117loadModule :: 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
118119
119120-- |
120121-- Expands tilde in path.
@@ -190,24 +191,25 @@ options = P.Options True False True (Just "Main") True "PS" []
190191-- |
191192-- Makes a volatile module to execute the current expression.
192193--
193−createTemporaryModule :: [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
194−createTemporaryModule imports lets value =
194+createTemporaryModule :: Bool -> [P.ProperName] -> [P.Value -> P.Value] -> P.Value -> P.Module
195+createTemporaryModule exec imports lets value =
195196 let
196197 moduleName = P.ModuleName [P.ProperName "Main"]
197198 importDecl m = P.ImportDeclaration m Nothing
198199 traceModule = P.ModuleName [P.ProperName "Trace"]
199200 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
200201 value' = foldr ($) value lets
201− mainDecl = P.ValueDeclaration (P.Ident "main") [] Nothing (P.App trace value')
202+ itDecl = P.ValueDeclaration (P.Ident "it") [] Nothing value'
203+ mainDecl = P.ValueDeclaration (P.Ident "main") [] Nothing (P.App trace (P.Var (P.Qualified Nothing (P.Ident "it"))))
202204 in
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]
204206
205207-- |
206208-- Takes a value declaration and evaluates it with the current state.
207209--
208210handleDeclaration :: P.Value -> PSCI -> InputT IO ()
209211handleDeclaration value (PSCI imports loadedModules lets) = do
210− let m = createTemporaryModule imports lets value
212+ let m = createTemporaryModule True imports lets value
211213 case P.compile options (loadedModules ++ [m]) of
212214 Left err -> outputStrLn err
213215 Right (js, _, _) -> do
@@ -218,52 +220,49 @@ handleDeclaration value (PSCI imports loadedModules lets) = do
218220 Just (ExitFailure _, _, err) -> outputStrLn err
219221 Nothing -> outputStrLn "Couldn't find node.js"
220222
221−-- Parser helpers
222−
223223-- |
224−-- PSCI version of the indent parser.
225−-- This really does nothing except provide a shorter alias.
224+-- Takes a value and prints its type
226225--
227−parser :: Parsec.Parsec String P.ParseState a -> String -> Either Parsec.ParseError a
228−parser = P.runIndentParser ""
226+handleTypeOf :: P.Value -> PSCI -> InputT IO ()
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"
229235
230−-- |
231−-- Parser for any other valid expression.
232−--
233−parseExpression :: String -> Either Parsec.ParseError P.Value
234−parseExpression = parser (P.whiteSpace *> P.parseValue <* Parsec.eof)
236+-- Parser helpers
235237
236238-- |
237239-- Parser for our PSCI version of @let@.
238240-- This is essentially let from do-notation.
239241-- However, since we don't support the @Eff@ monad, we actually want the normal @let@.
240242--
241−parseLet :: String -> Either Parsec.ParseError (P.Value -> P.Value)
242−parseLet = parser $
243− P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
244− <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
243+parseLet :: Parsec.Parsec String P.ParseState (P.Value -> P.Value)
244+parseLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
245+ <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
245246
246247-- |
247−-- Parser for PSCI modules.
248+-- Parser for any other valid expression.
248249--
249−parseModules :: String -> Either Parsec.ParseError [P.Module]
250−parseModules = parser P.parseModules
250+parseExpression :: Parsec.Parsec String P.ParseState P.Value
251+parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
251252
252253-- Commands
253254
254255-- |
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..
256257--
257258handleCommand :: Command -> StateT PSCI (InputT IO) ()
258259handleCommand Empty = return ()
259260handleCommand (Expression ls) =
260− let expr = unlines ls
261− in case parseLet expr of
262− Left _ ->
263− either outprintT (\decl -> get >>= inputTToState . handleDeclaration decl)
264− (parseExpression expr)
265− Right l -> modify (updateLets l)
266−handleCommand Help = outputTStrLn helpMessage
261+ case P.runIndentParser "" (Left <$> Parsec.try parseLet <|> Right <$> parseExpression) (unlines ls) of
262+ Left err -> inputTToState $ outputStrLn (show err)
263+ Right (Left l) -> modify (updateLets l)
264+ Right (Right decl) -> get >>= inputTToState . handleDeclaration decl
265+handleCommand Help = inputTToState $ outputStrLn helpMessage
267266handleCommand (Import moduleName) = modify (updateImports moduleName)
268267handleCommand (LoadFile filePath) = do
269268 absPath <- ioToState $ expandTilde filePath
@@ -275,7 +274,11 @@ handleCommand (LoadFile filePath) = do
275274handleCommand Reload = do
276275 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
277276 put (PSCI defaultImports prelude [])
278−handleCommand Unknown = outputTStrLn "Unknown command"
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'
281+handleCommand _ = outputTStrLn "Unknown command"
279282
280283-- Command helpers
281284