git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge pull request #222 from joneshf/psci-fixes

Fix for #216

commit39c89134cc38d8225f24461d6e32fb544b030527 authorPhil Freeman <paf31@cantab.net> dateFri 21 Feb 2014, 16:01 (13 years ago) parent662de7979da0c4
3 files changed+177−59
psci/Commands.hs+13−34 psci/Main.hs+28−25 psci/Parser.hs+136
psci/Commands.hs+13−34
@@ -1,6 +1,6 @@
11-----------------------------------------------------------------------------
22--
3−-- Module : Main
3+-- Module : Commands
44-- Copyright : (c) Phil Freeman 2014
55-- License : MIT
66--
@@ -15,8 +15,9 @@
1515
1616module Commands where
1717
18−import Control.Applicative
19−import System.Console.Haskeline
18+import Language.PureScript
19+
20+import Text.Parsec
2021
2122-- |
2223-- Valid Meta-commands for PSCI
@@ -29,7 +30,7 @@ data Command
2930 -- |
3031 -- A purescript expression
3132 --
32− | Expression [String]
33+ | Expression String
3334 -- |
3435 -- Show the help command
3536 --
@@ -37,7 +38,7 @@ data Command
3738 -- |
3839 -- Import a module from a loaded file
3940 --
40− | Import String
41+ | Import ModuleName
4142 -- |
4243 -- Load a file for use with importing
4344 --
@@ -57,39 +58,17 @@ data Command
5758 -- |
5859 -- An attempt at a meta command that wasn't recognized.
5960 --
60− | Unknown deriving (Show, Eq)
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)
61+ | Unknown ParseError
8462
8563-- |
8664-- The help menu.
8765--
8866help :: [[String]]
8967help =
90− [ [":? ", "Show this help menu"]
91− , [":i <module>", "Import <module> for use in PSCI"]
92− , [":m <file> ", "Load <file> for importing"]
93− , [":q ", "Quit PSCi"]
94− , [":r ", "Reload all modules."]
68+ [ [":? ", "Show this help menu"]
69+ , [":i <module> ", "Import <module> for use in PSCI"]
70+ , [":m <file> ", "Load <file> for importing"]
71+ , [":q ", "Quit PSCi"]
72+ , [":r ", "Reload all modules"]
73+ , [":t <expr> ", "Show the type of <expr>"]
9574 ]
psci/Main.hs+28−25
@@ -29,6 +29,8 @@ import Data.List (intercalate, isPrefixOf, nub, sortBy)
2929import Data.Maybe (mapMaybe)
3030import Data.Traversable (traverse)
3131
32+import Parser
33+
3234import System.Console.Haskeline
3335import System.Directory (doesFileExist, findExecutable, getHomeDirectory)
3436import System.Exit
@@ -36,11 +38,12 @@ import System.Environment.XDG.BaseDir
3638import System.FilePath ((</>), isPathSeparator)
3739import System.Process
3840
41+import Text.Parsec (choice)
42+
3943import qualified Data.Map as M
4044import qualified Language.PureScript as P
4145import qualified Paths_purescript as Paths
4246import qualified System.IO.UTF8 as U (readFile)
43−import qualified Text.Parsec as Parsec (Parsec, eof, try)
4447
4548-- |
4649-- The PSCI state.
@@ -69,8 +72,8 @@ ioToState = lift . lift
6972-- |
7073-- Updates the state to have more imported modules.
7174--
72−updateImports :: String -> PSCI -> PSCI
73−updateImports name (PSCI i m b) = PSCI (P.moduleNameFromString name : i) m b
75+updateImports :: P.ModuleName -> PSCI -> PSCI
76+updateImports name (PSCI i m b) = PSCI (name : i) m b
7477
7578-- |
7679-- Updates the state to have more loaded files.
@@ -115,7 +118,7 @@ getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
115118-- Loads a file for use with imports.
116119--
117120loadModule :: 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
119122
120123-- |
121124-- Expands tilde in path.
@@ -196,7 +199,7 @@ createTemporaryModule exec imports lets value =
196199 let
197200 moduleName = P.ModuleName [P.ProperName "Main"]
198201 importDecl m = P.ImportDeclaration m Nothing
199− traceModule = P.ModuleName [P.ProperName "Trace"]
202+ traceModule = P.ModuleName [P.ProperName "Debug", P.ProperName "Trace"]
200203 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
201204 value' = foldr ($) value lets
202205 itDecl = P.ValueDeclaration (P.Ident "it") [] Nothing value'
@@ -233,24 +236,24 @@ handleTypeOf value (PSCI imports loadedModules lets) = do
233236 Just (ty, _) -> outputStrLn . P.prettyPrintType $ ty
234237 Nothing -> outputStrLn "Could not find type"
235238
236−-- Parser helpers
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)
239+-- Commands
246240
247241-- |
248−-- Parser for any other valid expression.
242+-- Parses the input and returns either a Metacommand or an expression.
249243--
250−parseExpression :: Parsec.Parsec String P.ParseState P.Value
251−parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
252−
253−-- Commands
244+getCommand :: InputT IO Command
245+getCommand = do
246+ firstLine <- getInputLine "> "
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 " "
254257
255258-- |
256259-- Performs an action for each meta-command given, and also for expressions..
@@ -258,9 +261,9 @@ parseExpression = P.whiteSpace *> P.parseValue <* Parsec.eof
258261handleCommand :: Command -> StateT PSCI (InputT IO) ()
259262handleCommand Empty = return ()
260263handleCommand (Expression ls) =
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+ case psciParser (choice [Left <$> psciLet, Right <$> psciExpression]) ls of
265+ Left err -> inputTToState $ outputStrLn (show err)
266+ Right (Left l) -> modify (updateLets l)
264267 Right (Right decl) -> get >>= inputTToState . handleDeclaration decl
265268handleCommand Help = inputTToState $ outputStrLn helpMessage
266269handleCommand (Import moduleName) = modify (updateImports moduleName)
@@ -275,8 +278,8 @@ handleCommand Reload = do
275278 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
276279 put (PSCI defaultImports prelude [])
277280handleCommand (TypeOf expr) =
278− case P.runIndentParser "" parseExpression expr of
279− Left err -> inputTToState $ outputStrLn (show err)
281+ case parseExpression expr of
282+ Left err -> inputTToState $ outputStrLn (show err)
280283 Right expr' -> get >>= inputTToState . handleTypeOf expr'
281284handleCommand _ = outputTStrLn "Unknown command"
282285
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+ ]