git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Consolidate all parsing in psci into one parsec parser
aea20d4Phil Freeman
psci/Commands.hs+5−7
@@ -17,8 +17,6 @@ module Commands where
17
17
18import Language.PureScript
18import Language.PureScript
19
19
20−import Text.Parsec
21−
22-- |
20-- |
23-- Valid Meta-commands for PSCI
21-- Valid Meta-commands for PSCI
24--
22--
@@ -30,7 +28,7 @@ data Command
30 -- |
28 -- |
31 -- A purescript expression
29 -- A purescript expression
32 --
30 --
33− | Expression String
31+ | Expression Value
34 -- |
32 -- |
35 -- Show the help command
33 -- Show the help command
36 --
34 --
@@ -52,13 +50,13 @@ data Command
52 --
50 --
53 | Reload
51 | Reload
54 -- |
52 -- |
55− -- Find the type of an expression
53+ -- Binds a value to a name
56 --
54 --
57− | TypeOf String
55+ | Let (Value -> Value)
58 -- |
56 -- |
59− -- An attempt at a meta command that wasn't recognized.
57+ -- Find the type of an expression
60 --
58 --
61− | Unknown ParseError
59+ | TypeOf Value
62
60
63-- |
61-- |
64-- The help menu.
62-- The help menu.
psci/Main.hs+13−20
@@ -38,7 +38,7 @@ import System.Environment.XDG.BaseDir
38import System.FilePath ((</>), isPathSeparator)
38import System.FilePath ((</>), isPathSeparator)
39import System.Process
39import System.Process
40
40
41−import Text.Parsec (choice)
41+import Text.Parsec (ParseError)
42
42
43import qualified Data.Map as M
43import qualified Data.Map as M
44import qualified Language.PureScript as P
44import qualified Language.PureScript as P
@@ -118,7 +118,7 @@ getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
118-- Loads a file for use with imports.
118-- Loads a file for use with imports.
119--
119--
120loadModule :: FilePath -> IO (Either String [P.Module])
120loadModule :: FilePath -> IO (Either String [P.Module])
121−loadModule = fmap (either (Left . show) Right . parseModules) . U.readFile
121+loadModule filename = either (Left . show) Right . P.runIndentParser filename P.parseModules <$> U.readFile filename
122
122
123-- |
123-- |
124-- Expands tilde in path.
124-- Expands tilde in path.
@@ -241,16 +241,13 @@ handleTypeOf value (PSCI imports loadedModules lets) = do
241-- |
241-- |
242-- Parses the input and returns either a Metacommand or an expression.
242-- Parses the input and returns either a Metacommand or an expression.
243--
243--
244−getCommand :: InputT IO Command
244+getCommand :: InputT IO (Either ParseError (Maybe Command))
245getCommand = do
245getCommand = do
246 firstLine <- getInputLine "> "
246 firstLine <- getInputLine "> "
247 case firstLine of
247 case firstLine of
248− Nothing -> return Empty
248+ Nothing -> return (Right Nothing)
249− Just line -> case parseCommands line of
249+ Just s@ (':' : _) -> return . either Left (Right . Just) $ parseCommand s -- The start of a command
250− Left err -> return $ Unknown err
250+ Just s -> either Left (Right . Just) . parseCommand <$> go [s]
251− Right c -> case c of
252− Expression expr -> Expression <$> go [expr]
253− _ -> lift $ return c
254 where
251 where
255 go :: [String] -> InputT IO String
252 go :: [String] -> InputT IO String
256 go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
253 go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
@@ -260,11 +257,8 @@ getCommand = do
260--
257--
261handleCommand :: Command -> StateT PSCI (InputT IO) ()
258handleCommand :: Command -> StateT PSCI (InputT IO) ()
262handleCommand Empty = return ()
259handleCommand Empty = return ()
263−handleCommand (Expression ls) =
264− case psciParser (choice [Left <$> psciLet, Right <$> psciExpression]) ls of
265− Left err -> inputTToState $ outputStrLn (show err)
266− Right (Left l) -> modify (updateLets l)
267− Right (Right decl) -> get >>= inputTToState . handleDeclaration decl
260+handleCommand (Expression val) = get >>= inputTToState . handleDeclaration val
261+handleCommand (Let l) = modify (updateLets l)
268handleCommand Help = inputTToState $ outputStrLn helpMessage
262handleCommand Help = inputTToState $ outputStrLn helpMessage
269handleCommand (Import moduleName) = modify (updateImports moduleName)
263handleCommand (Import moduleName) = modify (updateImports moduleName)
270handleCommand (LoadFile filePath) = do
264handleCommand (LoadFile filePath) = do
@@ -277,10 +271,7 @@ handleCommand (LoadFile filePath) = do
277handleCommand Reload = do
271handleCommand Reload = do
278 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
272 (Right prelude) <- ioToState $ loadModule =<< getPreludeFilename
279 put (PSCI defaultImports prelude [])
273 put (PSCI defaultImports prelude [])
280−handleCommand (TypeOf expr) =
281− case parseExpression expr of
282− Left err -> inputTToState $ outputStrLn (show err)
283− Right expr' -> get >>= inputTToState . handleTypeOf expr'
274+handleCommand (TypeOf val) = get >>= inputTToState . handleTypeOf val
284handleCommand _ = outputTStrLn "Unknown command"
275handleCommand _ = outputTStrLn "Unknown command"
285
276
286-- Command helpers
277-- Command helpers
@@ -314,5 +305,7 @@ main = do
314 go = do
305 go = do
315 c <- inputTToState getCommand
306 c <- inputTToState getCommand
316 case c of
307 case c of
308+ Left err -> outputTStrLn (show err) >> go
309+ Right Nothing -> go
317− Quit -> outputTStrLn quitMessage
310+ Right (Just Quit) -> outputTStrLn quitMessage
318− _ -> handleCommand c >> go
311+ Right (Just c') -> handleCommand c' >> go
psci/Parser.hs+24−68
@@ -13,124 +13,80 @@
13--
13--
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16−module Parser where
16+module Parser (
17+ parseCommand
18+ ) where
17
19
18import Commands
20import Commands
19
21
22+import Data.Char (isSpace)
23+
20import Control.Applicative hiding (many)
24import Control.Applicative hiding (many)
21
25
22import Text.Parsec hiding ((<|>))
26import Text.Parsec hiding ((<|>))
23
27
24import qualified Language.PureScript as P
28import qualified Language.PureScript as P
25
29
26−-- |
27−-- PSCI version of modules
28−--
29−psciModules :: Parsec String P.ParseState [P.Module]
30−psciModules = P.parseModules
31−
32-- |
30-- |
33-- PSCI version of @let@.
31-- PSCI version of @let@.
34-- This is essentially let from do-notation.
32-- This is essentially let from do-notation.
35-- However, since we don't support the @Eff@ monad,
33-- However, since we don't support the @Eff@ monad,
36-- we actually want the normal @let@.
34-- we actually want the normal @let@.
37--
35--
38−psciLet :: Parsec String P.ParseState (P.Value -> P.Value)
36+psciLet :: Parsec String P.ParseState Command
39−psciLet = P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
37+psciLet = Let <$> (P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
40− <*> (P.indented *> P.reservedOp "=" *> P.parseValue)
38+ <*> (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
39
73-- |
40-- |
74-- Parses PSCI metacommands or expressions input from the user.
41-- Parses PSCI metacommands or expressions input from the user.
75--
42--
76−parseCommands :: String -> Either ParseError Command
43+parseCommand :: String -> Either ParseError Command
77−parseCommands = psciParser $ choice (map try availableCommands)
44+parseCommand = P.runIndentParser "" $ choice
45+ [ P.whiteSpace *> char ':' *> (psciHelp <|> psciImport <|> psciLoadFile <|> psciQuit <|> psciReload <|> psciTypeOf)
46+ , try psciLet
47+ , psciExpression
48+ ] <* eof
78
49
79-- |
50-- |
80-- Parses expressions entered at the PSCI repl.
51-- Parses expressions entered at the PSCI repl.
81--
52--
82−psciExpr :: Parsec String P.ParseState Command
53+psciExpression :: Parsec String P.ParseState Command
83−psciExpr = Expression <$> (lookAhead (try (noneOf ":")) *> many1 anyChar)
54+psciExpression = Expression <$> P.parseValue
84
55
85-- |
56-- |
86-- Parses 'Commands.Help' command.
57-- Parses 'Commands.Help' command.
87--
58--
88psciHelp :: Parsec String P.ParseState Command
59psciHelp :: Parsec String P.ParseState Command
89−psciHelp = Help <$ (spaces *> string ":?" *> spaces)
60+psciHelp = Help <$ char '?'
90
61
91-- |
62-- |
92-- Parses 'Commands.Import' command.
63-- Parses 'Commands.Import' command.
93--
64--
94psciImport :: Parsec String P.ParseState Command
65psciImport :: Parsec String P.ParseState Command
95−psciImport = Import <$> (spaces *> string ":i" *> spaces *> P.moduleName)
66+psciImport = Import <$> (char 'i' *> P.whiteSpace *> P.moduleName)
96
67
97-- |
68-- |
98-- Parses 'Commands.LoadFile' command.
69-- Parses 'Commands.LoadFile' command.
99--
70--
100psciLoadFile :: Parsec String P.ParseState Command
71psciLoadFile :: Parsec String P.ParseState Command
101−psciLoadFile = LoadFile <$> do
72+psciLoadFile = LoadFile . trimEnd <$> (char 'm' *> P.whiteSpace *> manyTill anyChar eof)
102− spaces
73+ where
103− string ":m"
74+ trimEnd = reverse . dropWhile isSpace . reverse
104− spaces
105− try (manyTill anyChar space) <|> many1 anyChar
106
75
107-- |
76-- |
108-- Parses 'Commands.Quit' command.
77-- Parses 'Commands.Quit' command.
109--
78--
110psciQuit :: Parsec String P.ParseState Command
79psciQuit :: Parsec String P.ParseState Command
111−psciQuit = Quit <$ (spaces *> string ":q" *> spaces)
80+psciQuit = Quit <$ char 'q'
112
81
113-- |
82-- |
114-- Parses 'Commands.Reload' command.
83-- Parses 'Commands.Reload' command.
115--
84--
116psciReload :: Parsec String P.ParseState Command
85psciReload :: Parsec String P.ParseState Command
117−psciReload = Reload <$ (spaces *> string ":r" *> spaces)
86+psciReload = Reload <$ char 'r'
118
87
119-- |
88-- |
120-- Parses 'Commands.TypeOf' command.
89-- Parses 'Commands.TypeOf' command.
121--
90--
122psciTypeOf :: Parsec String P.ParseState Command
91psciTypeOf :: Parsec String P.ParseState Command
123−psciTypeOf = TypeOf <$> (spaces *> string ":t" *> spaces *> many anyChar)
92+psciTypeOf = TypeOf <$> (char 't' *> P.whiteSpace *> P.parseValue)
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− ]