Parsec, updateState, and failure

Hi, If a parser which updated user state fails, will such update be reverted? Suppose we have two parsers combined with <|> p = p1 <|> p2 p1 has the following: p1 = try $ do ... -- getting something from the input stream updateState (\st -> ...) -- updated state based on what gotten from the input x <- p3 -- p3 should see updated state and return something updateState (\st -> ...) -- updated state again (if p3 succeeded) return x If p3 fails, p1 fails too (second updateState will not be reached). But what will p2 (tried next) see in the user state? Will it be state after the first updateState, or will failure of p1 roll the update back? Is there any bracket- or try-catch-finally-like mechanism for Parsec? Thanks. -- Dimitry Golubovsky Anywhere on the Web

Dimitry Golubovsky wrote:
Hi,
If a parser which updated user state fails, will such update be reverted?
Without actually checking, I would strongly suspect that yes, if a parser fails, all its state modifications are thrown away. (This is usually what you would want...)
Is there any bracket- or try-catch-finally-like mechanism for Parsec?
I don't think so. If you find yourself wanting to parse data differently depending on stuff you've already seen, you might find it easier to run a 2-pass parser of some kind.

On 31 May 2008, at 7:12 AM, Dimitry Golubovsky wrote:
Hi,
If a parser which updated user state fails, will such update be reverted?
Suppose we have two parsers combined with <|>
p = p1 <|> p2
p1 has the following:
p1 = try $ do ... -- getting something from the input stream updateState (\st -> ...) -- updated state based on what gotten from the input x <- p3 -- p3 should see updated state and return something updateState (\st -> ...) -- updated state again (if p3 succeeded) return x
If p3 fails, p1 fails too (second updateState will not be reached). But what will p2 (tried next) see in the user state?
The same thing p1 saw. You can see the implementation in http:// darcs.haskell.org/ghc-6.8/libraries/parsec/Text/ParserCombinators/ Parsec/Prim.hs; you want the parsecPlus function. Furthermore, you might note that the GenParser type is defined as newtype GenParser tok st a = Parser (State tok st -> Consumed (Reply tok st a)) runP (Parser p) = p data Consumed a = Consumed a --input is consumed | Empty !a --no input is consumed data Reply tok st a = Ok !a !(State tok st) ParseError -- parsing succeeded with "a" | Error ParseError -- parsing failed data State tok st = State { stateInput :: [tok] , statePos :: !SourcePos , stateUser :: !st } A parser that fails doesn't deliver a new state for parsecPlus to consider using going forward. jcc

"Dimitry Golubovsky"
If a parser which updated user state fails, will such update be reverted?
I have no idea, I gave up before investigating that far. You want to avoid state at any cost, even more so if the state would influence parsing: spaghetti and headaches lay ahead. In the end I did three passes: two times parsec and one time something similar to accumMap. Now that I'm thinking of it, it would be nice if parsec supported spans in source positions, so that you can report errors like XYZ at foo.bar line 3 column 2 in ZYX spanning line 2-4 column 34-20. -- (c) this sig last receiving data processing entity. Inspect headers for past copyright information. All rights reserved. Unauthorised copying, hiring, renting, public performance and/or broadcasting of this signature prohibited.

On Sat, May 31, 2008 at 12:12 PM, Achim Schneider
"Dimitry Golubovsky"
wrote: If a parser which updated user state fails, will such update be reverted?
I have no idea, I gave up before investigating that far.
You want to avoid state at any cost, even more so if the state would influence parsing: spaghetti and headaches lay ahead. In the end I did three passes: two times parsec and one time something similar to accumMap.
If you really really wanted state that doesn't un-roll when parsing fails, this should work (but is untested):
type MyParser = ParsecT String () (State MyState)
runMyParser :: MyParser a -> String -> SourceName -> MyState -> (Either ParseError a, MyState)
runMyParser m in name state = flip runState state $ runPT m in name
You can then use 'get' and 'set'. But as you suggest, that way may be madness. -Antoine
participants (5)
-
Achim Schneider
-
Andrew Coppin
-
Antoine Latter
-
Dimitry Golubovsky
-
Jonathan Cast