git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge pull request #222 from joneshf/psci-fixes
39c8913Phil Freeman
psci/Commands.hs+13−34
@@ -1,6 +1,6 @@
1-----------------------------------------------------------------------------
1-----------------------------------------------------------------------------
2--
2--
3−-- Module : Main
3+-- Module : Commands
4-- Copyright : (c) Phil Freeman 2014
4-- Copyright : (c) Phil Freeman 2014
5-- License : MIT
5-- License : MIT
6--
6--
@@ -15,8 +15,9 @@
15
15
16module Commands where
16module Commands where
17
17
18−import Control.Applicative
18+import Language.PureScript
19−import System.Console.Haskeline
19+
20+import Text.Parsec
20
21
21-- |
22-- |
22-- Valid Meta-commands for PSCI
23-- Valid Meta-commands for PSCI
@@ -29,7 +30,7 @@ data Command
29 -- |
30 -- |
30 -- A purescript expression
31 -- A purescript expression
31 --
32 --
32− | Expression [String]
33+ | Expression String
33 -- |
34 -- |
34 -- Show the help command
35 -- Show the help command
35 --
36 --
@@ -37,7 +38,7 @@ data Command
37 -- |
38 -- |
38 -- Import a module from a loaded file
39 -- Import a module from a loaded file
39 --
40 --
40− | Import String
41+ | Import ModuleName
41 -- |
42 -- |
42 -- Load a file for use with importing
43 -- Load a file for use with importing
43 --
44 --
@@ -57,39 +58,17 @@ data Command
57 -- |
58 -- |
58 -- An attempt at a meta command that wasn't recognized.
59 -- An attempt at a meta command that wasn't recognized.
59 --
60 --
60− | Unknown deriving (Show, Eq)
61+ | Unknown ParseError
61−
62−-- |
63−-- Parses the input and returns either a Metacommand or an expression.
64−--
65−getCommand :: InputT IO Command
66−getCommand = do
67− firstLine <- getInputLine "> "
68− case firstLine of
69− Nothing -> return Empty
70− Just ":?" -> return Help
71− Just (':':'i':' ':moduleName) -> return $ Import moduleName
72− Just (':':'m':' ':filePath) -> return $ LoadFile filePath
73− Just ":q" -> return Quit
74− Just ":r" -> return Reload
75− Just (':':'t':' ':expr) -> return $ TypeOf expr
76− Just (':':_) -> return Unknown
77− Just other -> Expression <$> go [other]
78− where
79− go ls = do
80− l <- getInputLine " "
81− case l of
82− Nothing -> return $ reverse ls
83− Just l' -> go (l' : ls)
84
62
85-- |
63-- |
86-- The help menu.
64-- The help menu.
87--
65--
88help :: [[String]]
66help :: [[String]]
89help =
67help =
90− [ [":? ", "Show this help menu"]
68+ [ [":? ", "Show this help menu"]
91− , [":i <module>", "Import <module> for use in PSCI"]
69+ , [":i <module> ", "Import <module> for use in PSCI"]
92− , [":m <file> ", "Load <file> for importing"]
70+ , [":m <file> ", "Load <file> for importing"]
93− , [":q ", "Quit PSCi"]
71+ , [":q ", "Quit PSCi"]
94− , [":r ", "Reload all modules."]
72+ , [":r ", "Reload all modules"]
73+ , [":t <expr> ", "Show the type of <expr>"]
95 ]
74 ]
psci/Main.hs+28−25
@@ -29,6 +29,8 @@ import Data.List (intercalate, isPrefixOf, nub, sortBy)
29import Data.Maybe (mapMaybe)
29import Data.Maybe (mapMaybe)
30import Data.Traversable (traverse)
30import Data.Traversable (traverse)
31
31
32+import Parser
33+
32import System.Console.Haskeline
34import System.Console.Haskeline
33import System.Directory (doesFileExist, findExecutable, getHomeDirectory)
35import System.Directory (doesFileExist, findExecutable, getHomeDirectory)
34import System.Exit
36import System.Exit
@@ -36,11 +38,12 @@ import System.Environment.XDG.BaseDir
36import System.FilePath ((</>), isPathSeparator)
38import System.FilePath ((</>), isPathSeparator)
37import System.Process
39import System.Process
38
40
41+import Text.Parsec (choice)
42+
39import qualified Data.Map as M
43import qualified Data.Map as M
40import qualified Language.PureScript as P
44import qualified Language.PureScript as P
41import qualified Paths_purescript as Paths
45import qualified Paths_purescript as Paths
42import qualified System.IO.UTF8 as U (readFile)
46import qualified System.IO.UTF8 as U (readFile)
43−import qualified Text.Parsec as Parsec (Parsec, eof, try)
44
47
45-- |
48-- |
46-- The PSCI state.
49-- The PSCI state.
@@ -69,8 +72,8 @@ ioToState = lift . lift
69-- |
72-- |
70-- Updates the state to have more imported modules.
73-- Updates the state to have more imported modules.
71--
74--
72−updateImports :: String -> PSCI -> PSCI
75+updateImports :: P.ModuleName -> PSCI -> PSCI
73−updateImports name (PSCI i m b) = PSCI (P.moduleNameFromString name : i) m b
76+updateImports name (PSCI i m b) = PSCI (name : i) m b
74
77
75-- |
78-- |
76-- Updates the state to have more loaded files.
79-- Updates the state to have more loaded files.
@@ -115,7 +118,7 @@ getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
115-- Loads a file for use with imports.
118-- Loads a file for use with imports.
116--
119--
117loadModule :: FilePath -> IO (Either String [P.Module])
120loadModule :: FilePath -> IO (Either String [P.Module])
118−loadModule = fmap (either (Left . show) Right . P.runIndentParser "" P.parseModules) . U.readFile
121+loadModule = fmap (either (Left . show) Right . parseModules) . U.readFile
119
122
120-- |
123-- |
121-- Expands tilde in path.
124-- Expands tilde in path.
@@ -196,7 +199,7 @@ createTemporaryModule exec imports lets value =
196 let
199 let
197 moduleName = P.ModuleName [P.ProperName "Main"]
200 moduleName = P.ModuleName [P.ProperName "Main"]
198 importDecl m = P.ImportDeclaration m Nothing
201 importDecl m = P.ImportDeclaration m Nothing
199− traceModule = P.ModuleName [P.ProperName "Trace"]
202+ traceModule = P.ModuleName [P.ProperName "Debug", P.ProperName "Trace"]
200 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
203 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
201 value' = foldr ($) value lets
204 value' = foldr ($) value lets
202 itDecl = P.ValueDeclaration (P.Ident "it") [] Nothing value'
205 itDecl = P.ValueDeclaration (P.Ident "it") [] Nothing value'
@@ -233,24 +236,24 @@ handleTypeOf value (PSCI imports loadedModules lets) = do
233 Just (ty, _) -> outputStrLn . P.prettyPrintType $ ty
236 Just (ty, _) -> outputStrLn . P.prettyPrintType $ ty
234 Nothing -> outputStrLn "Could not find type"
237 Nothing -> outputStrLn "Could not find type"
235
238
236−-- Parser helpers
239+-- Commands
237−
238−-- |
239−-- Parser for our PSCI version of @let@.
240−-- This is essentially let from do-notation.
241−-- However, since we don't support the @Eff@ monad, we actually want the normal @let@.
242−--
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)
246
240
247-- |
241-- |
248−-- Parser for any other valid expression.
242+-- Parses the input and returns either a Metacommand or an expression.
249--
243--
250−parseExpression :: Parsec.Parsec String P.ParseState P.Value
244+getCommand :: InputT IO Command
251−parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
245+getCommand = do
252−
246+ firstLine <- getInputLine "> "
253−-- Commands
247+ case firstLine of
248+ Nothing -> return Empty
249+ Just line -> case parseCommands line of
250+ Left err -> return $ Unknown err
251+ Right c -> case c of
252+ Expression expr -> Expression <$> go [expr]
253+ _ -> lift $ return c
254+ where
255+ go :: [String] -> InputT IO String
256+ go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
254
257
255-- |
258-- |
256-- Performs an action for each meta-command given, and also for expressions..
259-- Performs an action for each meta-command given, and also for expressions..
@@ -258,9 +261,9 @@ parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
258handleCommand :: Command -> StateT PSCI (InputT IO) ()
261handleCommand :: Command -> StateT PSCI (InputT IO) ()
259handleCommand Empty = return ()
262handleCommand Empty = return ()
260handleCommand (Expression ls) =
263handleCommand (Expression ls) =
261− case P.runIndentParser "" (Left <$> Parsec.try parseLet <|> Right <$> parseExpression) (unlines ls) of
264+ case psciParser (choice [Left <$> psciLet, Right <$> psciExpression]) ls of
262− Left err -> inputTToState $ outputStrLn (show err)
265+ Left err -> inputTToState $ outputStrLn (show err)
263− Right (Left l) -> modify (updateLets l)
266+ Right (Left l) -> modify (updateLets l)
264 Right (Right decl) -> get >>= inputTToState . handleDeclaration decl
267 Right (Right decl) -> get >>= inputTToState . handleDeclaration decl
265handleCommand Help = inputTToState $ outputStrLn helpMessage
268handleCommand Help = inputTToState $ outputStrLn helpMessage
266handleCommand (Import moduleName) = modify (updateImports moduleName)
269handleCommand (Import moduleName) = modify (updateImports moduleName)
@@ -275,8 +278,8 @@ handleCommand Reload = do
275 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
278 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
276 put (PSCI defaultImports prelude [])
279 put (PSCI defaultImports prelude [])
277handleCommand (TypeOf expr) =
280handleCommand (TypeOf expr) =
278− case P.runIndentParser "" parseExpression expr of
281+ case parseExpression expr of
279− Left err -> inputTToState $ outputStrLn (show err)
282+ Left err -> inputTToState $ outputStrLn (show err)
280 Right expr' -> get >>= inputTToState . handleTypeOf expr'
283 Right expr' -> get >>= inputTToState . handleTypeOf expr'
281handleCommand _ = outputTStrLn "Unknown command"
284handleCommand _ = outputTStrLn "Unknown command"
282
285
psci/Parser.hsnew file+136
@@ -0,0 +1,136 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Parser
4+-- Copyright : (c) Phil Freeman 2014
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- Parser for PSCI.
13+--
14+-----------------------------------------------------------------------------
15+
16+module Parser where
17+
18+import Commands
19+
20+import Control.Applicative hiding (many)
21+
22+import Text.Parsec hiding ((<|>))
23+
24+import qualified Language.PureScript as P
25+
26+-- |
27+-- PSCI version of modules
28+--
29+psciModules :: Parsec String P.ParseState [P.Module]
30+psciModules = P.parseModules
31+
32+-- |
33+-- PSCI version of @let@.
34+-- This is essentially let from do-notation.
35+-- However, since we don't support the @Eff@ monad,
36+-- we actually want the normal @let@.
37+--
38+psciLet :: Parsec String P.ParseState (P.Value -> P.Value)
39+psciLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
40+ <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
41+
42+-- |
43+-- PSCI version of any other valid expression.
44+--
45+psciExpression :: Parsec String P.ParseState P.Value
46+psciExpression = P.whiteSpace *> P.parseValue <* eof
47+
48+-- |
49+-- Parser for PSCI.
50+-- This is really just a wrapper around 'Language.PureScript.runIndentParser'
51+--
52+psciParser :: Parsec String P.ParseState a -> String -> Either ParseError a
53+psciParser = P.runIndentParser ""
54+
55+-- |
56+-- Parses PSCI modules.
57+--
58+parseModules :: String -> Either ParseError [P.Module]
59+parseModules = psciParser psciModules
60+
61+-- |
62+-- Parses PSCI @let@ bindings.
63+--
64+parseLet :: String -> Either ParseError (P.Value -> P.Value)
65+parseLet = psciParser psciLet
66+
67+-- |
68+-- Parses PSCI @expressions@.
69+--
70+parseExpression :: String -> Either ParseError P.Value
71+parseExpression = psciParser psciExpression
72+
73+-- |
74+-- Parses PSCI metacommands or expressions input from the user.
75+--
76+parseCommands :: String -> Either ParseError Command
77+parseCommands = psciParser $ choice (map try availableCommands)
78+
79+-- |
80+-- Parses expressions entered at the PSCI repl.
81+--
82+psciExpr :: Parsec String P.ParseState Command
83+psciExpr = Expression <$> (lookAhead (try (noneOf ":")) *> many1 anyChar)
84+
85+-- |
86+-- Parses 'Commands.Help' command.
87+--
88+psciHelp :: Parsec String P.ParseState Command
89+psciHelp = Help <$ (spaces *> string ":?" *> spaces)
90+
91+-- |
92+-- Parses 'Commands.Import' command.
93+--
94+psciImport :: Parsec String P.ParseState Command
95+psciImport = Import <$> (spaces *> string ":i" *> spaces *> P.moduleName)
96+
97+-- |
98+-- Parses 'Commands.LoadFile' command.
99+--
100+psciLoadFile :: Parsec String P.ParseState Command
101+psciLoadFile = LoadFile <$> do
102+ spaces
103+ string ":m"
104+ spaces
105+ try (manyTill anyChar space) <|> many1 anyChar
106+
107+-- |
108+-- Parses 'Commands.Quit' command.
109+--
110+psciQuit :: Parsec String P.ParseState Command
111+psciQuit = Quit <$ (spaces *> string ":q" *> spaces)
112+
113+-- |
114+-- Parses 'Commands.Reload' command.
115+--
116+psciReload :: Parsec String P.ParseState Command
117+psciReload = Reload <$ (spaces *> string ":r" *> spaces)
118+
119+-- |
120+-- Parses 'Commands.TypeOf' command.
121+--
122+psciTypeOf :: Parsec String P.ParseState Command
123+psciTypeOf = TypeOf <$> (spaces *> string ":t" *> spaces *> many anyChar)
124+
125+-- |
126+-- List of commands that are available from PSCI.
127+--
128+availableCommands :: [Parsec String P.ParseState Command]
129+availableCommands = [ psciExpr
130+ , psciHelp
131+ , psciImport
132+ , psciLoadFile
133+ , psciQuit
134+ , psciReload
135+ , psciTypeOf
136+ ]