-- | A parser-combinator library. -- -- The primary goal in writing Parcom was to facilitate parsing Unicode string -- data from various source streams, including raw -- 'Data.ByteString.ByteString's - while Attoparsec can parse -- 'Data.ByteString.ByteString's, it sacrifices some convenience for -- performance, and using it to parse textual data is not as comfortable as I -- would like; Parsec can handle textual data much better, but it needs the -- input to be converetd to Unicode for this to work nicely. Nonetheless, -- Parcom\'s interface is quite obviously heavily inspired by both Parsec and -- Attoparsec. -- -- Parcom supports 'String', 'Data.ByteString.ByteString' (lazy and strict) and -- 'Data.Text.Text' (lazy and strict) as its input format out-of-the-box. By -- implementing one or more of the typeclasses in 'Text.Parcom.Stream', you can -- extend Parcom to work on other input types as well. module Text.Parcom ( module Text.Parcom.Prim , module Text.Parcom.Combinators , module Text.Parcom.Core -- * Getting Started -- | Parcom being a parser combinator library, the usual approach is to use -- predefined atomic parsers (defined in "Text.Parcom.Prim" and re-exported -- here for convenience) and combine them using predefined combinators (defined -- in "Text.Parcom.Combinators"). Anyone with prior exposure to Parsec or -- Attoparsec should be familiar with the concept. Here's an example that -- parses a value, which can be a positive integer literal or NULL: -- -- > myParser :: Parcom String Char (Maybe Int) -- > myParser = intLiteral <|> nullLiteral "value (integer or NULL)" -- > -- > intLiteral :: Parcom String Char (Maybe Int) -- > intLiteral = do -- > x <- oneOf ['1'..'9'] -- > xs <- many (oneOf ['0'..'9']) -- > return $ Just $ read (x:xs) -- > -- > nullLiteral :: Parcom String Char (Maybe Int) -- > nullLiteral = do -- > tokens "NULL" -- > notFollowedBy (satisfy (not . isSpace)) -- > return Nothing -- -- Such a parser can then be run against some input using 'parse' or 'parseT', -- the monadic equivalent. -- -- > main = do -- > src <- getContents -- > let parseResult = parse myParser "" src -- > case parseResult of -- > Left err -> do -- > putStrLn "Sorry, there has been an error, namely:" -- > print err -- > Right (Just i) -> putStrLn $ "Found an integer value: " ++ show i -- > Right Nothing -> putStrLn "Found NULL" -- * Backtracking -- | As you build more complex parsers, you may encounter situations where a -- parser fails after having consumed some input already. Combining such a -- parser with other alternatives will yield undesired results: the parser -- fails, but it will not push the input it has already consumed back onto the -- input stream. To fix this, use the 'try' primitive, which modifies a parser -- such that when it fails, it undoes any input consumption it may have caused. -- * Input types other than 'String' -- | To support input from @Text@ or @ByteString@s, import one of the following -- modules: -- -- * "Text.Parcom.Text" or "Text.Parcom.Text.Strict" for strict @Text@ -- -- * "Text.Parcom.Text.Lazy" for lazy @Text@ -- -- * "Text.Parcom.ByteString" or "ByteString.Parcom.ByteString.Strict" for strict @ByteString@ -- -- * "Text.Parcom.ByteString.Lazy" for lazy @ByteString@ -- * Parsing textual data -- | Parcom provides two primitives for textual data: 'Text.Parcom.Textual.char' -- and 'Text.Parcom.Textual.string'. While textual data can be extracted from -- input streams that are textual already (e.g. 'String' or 'Data.Text.Text') -- using the normal token-based primities ('token', 'tokens', and 'prefix'), -- doing so for bytestrings isn't trivial. The textual-data ) where import Text.Parcom.Prim import Text.Parcom.Core import Text.Parcom.Combinators