I have a possible implementation of in this Gist: https://gist.github.com/danidiaz/4445282a4fcc7ee8c61e It assumes that each token is separated by a newline, like "foo\nbar\nbaz\n"
What I did is to have tree nested layers of parsers: first, one layer for parsing individual command tokens + invalid tokens + escape tokens. Another layer (stopAtEscape) for stopping the parsing after encountering an Escape token. And a final layer (parseCommands) for actually parsing the Commands from the command tokens. The gist uses the "hoist lift" trick described by Gabriel here: https://github.com/Gabriel439/Haskell-Pipes-Parse-Library/issues/31 The idea is to have Parsers whose underlying monad (and not just the state) is a Producer of parsed results, so that after running them you end with a Producer -> Producer function. The type signature for "completerParser" ended up overly complex, with all those nested producers in the return type. Maybe there is a simpler way. On Sunday, October 25, 2015 at 2:41:13 AM UTC+1, Michael Whitehead wrote: > > > Do you mean that if a command is being parsed, and some invalid input > appears, after skipping the invalid inputs we should continue parsing that > same command, instead of starting to parse a new one? > > Yes > > > In other words: should your example return one parsed command, or two? > > So in this example > > example :: Producer B.ByteString IO () > example = do > yield "foobarbaz" > yield "foo" > yield "bar" > yield "invalid" -- skip over invalid input > yield "baz" > yield "foo" > yield "escape" -- exit early from parse based on specific value > yield "foobarbaz" > > I would like there to be 3 parsed commands that get returned. > > On Saturday, October 24, 2015 at 2:54:05 PM UTC-6, Daniel Díaz wrote: >> >> I have another doubt. When you say: >> >> > Basically I want to make it so that when there is an invalid input it >> will just skip it and continue where it left off. >> >> Do you mean that if a command is being parsed, and some invalid input >> appears, after skipping the invalid inputs we should continue parsing that >> same command, instead of starting to parse a new one? >> >> In other words: should your example return one parsed command, or two? >> >> On Saturday, October 24, 2015 at 5:04:36 PM UTC+2, Michael Whitehead >> wrote: >>> >>> If you mean like "foo\nbar\nbaz\n" then yes I can do that. I don't think >>> I could do a delimiter for the command as a whole. Something like >>> "foobarbaz\n" would not work. >>> >>> On Saturday, October 24, 2015 at 3:30:07 AM UTC-6, Daniel Díaz wrote: >>>> >>>> In your use case, do different commads have a clear delimiter >>>> character, like a newline? That would simplify things. >>>> >>>> On Saturday, October 24, 2015 at 7:30:57 AM UTC+2, Michael Whitehead >>>> wrote: >>>>> >>>>> Not sure if I should try to solve my problem with attoparsec itself or >>>>> with pipes. Either way I don't really know where to start so I would >>>>> appreciate it if someone could help me a little. >>>>> >>>>> {-# LANGUAGE OverloadedStrings #-} >>>>> >>>>> module Main where >>>>> >>>>> import qualified Data.ByteString as B >>>>> import Pipes >>>>> import qualified Pipes.Prelude as P >>>>> import qualified Pipes.Attoparsec as P >>>>> import Data.Attoparsec.ByteString.Char8 as A >>>>> >>>>> >>>>> data Foo = Foo deriving Show >>>>> data Bar = Bar deriving Show >>>>> data Baz = Baz deriving Show >>>>> data Command = Command Foo Bar Baz deriving Show >>>>> data Escape = Escape deriving Show >>>>> >>>>> fooParser :: Parser Foo >>>>> fooParser = string "foo" >> return Foo >>>>> >>>>> barParser :: Parser Bar >>>>> barParser = string "bar" >> return Bar >>>>> >>>>> bazParser :: Parser Baz >>>>> bazParser = string "baz" >> return Baz >>>>> >>>>> exitParser :: Parser Escape >>>>> exitParser = string "escape" >> return Escape >>>>> >>>>> commandParser :: Parser Command >>>>> commandParser = >>>>> Command <$> fooParser >>>>> <*> barParser >>>>> <*> bazParser >>>>> >>>>> >>>>> example :: Producer B.ByteString IO () >>>>> example = do >>>>> yield "foobarbaz" >>>>> yield "foo" >>>>> yield "bar" >>>>> yield "invalid" -- skip over invalid input >>>>> yield "baz" >>>>> yield "foo" >>>>> yield "escape" -- exit early from parse based on specific value >>>>> yield "foobarbaz" >>>>> >>>>> main :: IO () >>>>> main = do >>>>> runEffect $ P.parsed commandParser example >-> P.print >>>>> return () >>>>> >>>>> >>>>> Basically I want to make it so that when there is an invalid input it >>>>> will just skip it and continue where it left off. Also I would like to be >>>>> able to handle special values that will allow an exit from the parsing so >>>>> I >>>>> can start fresh. >>>>> >>>> -- You received this message because you are subscribed to the Google Groups "Haskell Pipes" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipes+unsubscr...@googlegroups.com. To post to this group, send email to haskell-pipes@googlegroups.com.