comparse
comparse
is a parser combinator library supporting arbitrary input types.
Combinators do not care about the exact type of the input stream, allowing you
to use them on your own data source, as long as it supports a specific set of
operations. The ParserT
monad transformer can wrap around another monad,
allowing you to easily implement features such as tracing, context-sensitive
parsing, state machines, and so on. comparse
does its best to provide
meaningful error messages without sacrificing performances or the developer
experience when writing parsers.
Example
The following example shows how to use the comparse
library to parse a subset
of the JSON data format:
import Control.Monad (void)
import Control.Monad.Parser
import Data.Char (isAlpha, isDigit)
import Data.Stream.StringLines
data JValue
= JString String
| JNumber Int
| JBool Bool
| JNull
| JObject [(String, JValue)]
| JArray [JValue]
deriving (Show)
main :: IO ()
main = interact $ show . parseJValue
parseJValue :: String -> Maybe JValue
parseJValue s =
case runStringParser (json <* eof) s of
Parsed v (StringLines "" _) _ -> Just v
_ -> Nothing
lexeme :: StringParser a -> StringParser a
lexeme p = spaces *> p <* spaces
where
spaces = void $ many $ oneOf " \n\r\t"
symbol :: String -> StringParser String
symbol = lexeme . string
json :: StringParser JValue
json =
JString <$> stringLiteral
<|> JNumber <$> number
<|> JBool <$> bool
<|> JNull <$ symbol "null"
<|> JObject <$> object
<|> JArray <$> array
stringLiteral :: StringParser String
stringLiteral = lexeme $ like '"' *> many (unlike '\"') <* like '"'
number :: StringParser Int
number =
lexeme
( read <$> ((:) <$> like '-' <*> many1 digit)
<|> read <$> (optional (like '+') *> many1 digit)
)
<* notFollowedBy (match isAlpha)
where
digit = match isDigit
bool :: StringParser Bool
bool = True <$ symbol "true" <|> False <$ symbol "false"
object :: StringParser [(String, JValue)]
object =
symbol "{"
*> sepBy ((,) <$> (stringLiteral <* symbol ":") <*> json) (symbol ",")
<* symbol "}"
array :: StringParser [JValue]
array = symbol "[" *> sepBy json (symbol ",") <* symbol "]"
For more examples, please refer to the tests.