### Complete Lexer Setup Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/03-char-lexer.md Sets up a complete lexer with whitespace and comment handling, including parsers for numbers, identifiers, and keywords. This example defines a simple expression grammar. ```haskell {-# LANGUAGE OverloadedStrings #} import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L import Data.Void type Parser = Parsec Void String -- Space consumer: handles whitespace and comments sc :: Parser () sc = L.space space1 lineComment blockComment where lineComment = L.skipLineComment "--" blockComment = L.skipBlockComment "{- "- }" -- Lexeme: parse and consume trailing space lexeme :: Parser a -> Parser a lexeme = L.lexeme sc -- Symbols with automatic spacing symbol :: String -> Parser String symbol = L.symbol sc -- Numbers integer :: Parser Integer integer = lexeme L.decimal float' :: Parser Double float' = lexeme L.float -- Identifiers identifier :: Parser String identifier = lexeme $ (:) <$> letterChar <*> many alphaNumChar -- Keywords keyword :: String -> Parser () keyword w = lexeme (string w >> notFollowedBy alphaNumChar) >> return () -- Example grammar data Expr = Var String | Num Integer | Add Expr Expr variable :: Parser Expr variable = Var <$> identifier number :: Parser Expr number = Num <$> integer expr :: Parser Expr expr = term `chainl1` addOp term :: Parser Expr term = variable <|> number <|> symbol "(" *> expr <* symbol ")" addOp :: Parser (Expr -> Expr -> Expr) addOp = Add <$ symbol "+" main :: IO () main = do parseTest expr "x + 42 + y" -- Success: Add (Add (Var "x") (Num 42)) (Var "y") ``` -------------------------------- ### Complete Example: Simple Configuration Parser Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md A full example demonstrating how to parse a simple configuration file with Megaparsec. It includes defining the configuration structure, space consumption, lexical elements, and the main parsing logic. ```haskell {-# LANGUAGE OverloadedStrings #-} import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L import Data.Void import Data.Map (Map) import qualified Data.Map as M type Parser = Parsec Void String -- Config structure data Config = Config { cfgPort :: Int , cfgHost :: String , cfgOptions :: Map String String } deriving (Show) -- Space consumer sc :: Parser () sc = L.space space1 lineComment blockComment where lineComment = L.skipLineComment "#" blockComment = empty lexeme :: Parser a -> Parser a lexeme = L.lexeme sc symbol :: String -> Parser String symbol = L.symbol sc -- Lexical elements identifier :: Parser String identifier = lexeme $ (:) <$> letterChar <*> many alphaNumChar integer :: Parser Int integer = lexeme L.decimal stringLit :: Parser String stringLit = char '"' *> manyTill anySingle (char '"') -- Config parser config :: Parser Config config = do sc port <- portEntry host <- hostEntry opts <- many optEntry eof return $ Config port host (M.fromList opts) portEntry :: Parser Int portEntry = keyword "port" *> symbol "=" *> integer hostEntry :: Parser String hostEntry = keyword "host" *> symbol "=" *> stringLit optEntry :: Parser (String, String) optEntry = do key <- keyword "option" *> symbol "[" *> identifier <* symbol "]" symbol "=" val <- stringLit return (key, val) keyword :: String -> Parser () keyword kw = lexeme $ string kw >> notFollowedBy alphaNumChar -- Main main :: IO () main = do let input = "port = 8080\nhost = \"localhost\"\noption [debug] = \"true\"" case parse config "config.cfg" input of Left err -> putStrLn $ errorBundlePretty err Right cfg -> print cfg ``` -------------------------------- ### Complete Binary Parser Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md A full example demonstrating parsing a simple binary format consisting of a type byte, length byte, and data bytes. Includes parsing multiple records and running the parser. ```haskell {-# LANGUAGE OverloadedStrings #} import Text.Megaparsec import Text.Megaparsec.Byte import qualified Text.Megaparsec.Byte.Lexer as L import Data.ByteString (ByteString) import qualified Data.ByteString as B import Data.Word (Word8) import Data.Void type Parser = Parsec Void ByteString -- Simple binary format parser: -- Format: [TYPE:1 byte] [LENGTH:1 byte] [DATA:length bytes] data BinaryRecord = BinaryRecord { recType :: Word8 , recData :: ByteString } deriving (Show) parseRecord :: Parser BinaryRecord parseRecord = do typ <- anySingle len <- anySingle dat <- takeP Nothing (fromIntegral len) return $ BinaryRecord typ dat parseMultipleRecords :: Parser [BinaryRecord] parseMultipleRecords = many parseRecord -- Example parsing example :: IO () example = do let input = B.pack [0x01, 0x03, 0x48, 0x69, 0x21] -- Type 1, len 3, "Hi!" case parse parseRecord "binary.dat" input of Left err -> putStrLn $ errorBundlePretty err Right rec -> print rec ``` -------------------------------- ### Predefined Start Position Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Represents the standard initial position (1) for lines or columns. Use as a default starting point. ```haskell pos1 :: Pos ``` ```haskell pos1 = mkPos 1 ``` -------------------------------- ### Full Debugging Example with Expression Parser Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/07-debugging-and-error-builders.md A comprehensive example demonstrating the use of `dbg` on multiple parts of an expression parser, including numbers, operators, and parentheses. Requires `OverloadedStrings`. ```haskell {-# LANGUAGE OverloadedStrings #-} import Text.Megaparsec import Text.Megaparsec.Char import Text.Megaparsec.Debug type Parser = ParsecT Void String IO -- Simple expression parser data Expr = Num Int | Add Expr Expr expr :: Parser Expr expr = dbg "expr" $ term `chainl1` addOp term :: Parser Expr term = dbg "term" $ number <|> parens expr number :: Parser Expr number = dbg "number" $ Num . read <$> some digitChar addOp :: Parser (Expr -> Expr -> Expr) addOp = dbg "addOp" $ Add <$ symbol "+" parens :: Parser a -> Parser a parens p = symbol "(" *> p <* symbol ")" symbol :: String -> Parser String symbol s = dbg ("symbol:" ++ s) $ string s main :: IO () main = parseTest expr "1+2" ``` -------------------------------- ### Manual Error Creation Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/07-debugging-and-error-builders.md Demonstrates how to manually construct a `ParseError` using a combination of unexpected and expected item builders, and then pretty-print it. ```haskell {-# LANGUAGE OverloadedStrings #-} import Text.Megaparsec import Text.Megaparsec.Error import Text.Megaparsec.Error.Builder import Text.Megaparsec.Pos import qualified Data.Set as Set -- Create test error manually testError :: ParseError String Void testError = err 5 (utok 'a' <> etok 'b' <> elabel ('d' :| "igit")) -- Display it main :: IO () main = putStrLn $ parseErrorTextPretty testError ``` -------------------------------- ### Example: Parse Byte Sequence (HTTP Version) Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Demonstrates using `string` to parse the exact byte sequence "HTTP/1.1". ```haskell import qualified Data.ByteString as B httpVersion :: Parser B.ByteString httpVersion = string "HTTP/1.1" ``` -------------------------------- ### Custom Stream Instance Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/05-monadparsec-class.md Provides an example implementation of the `Stream` type class for a custom `MyStream` data type. This demonstrates how to adapt user-defined stream types for use with Megaparsec. ```haskell {-# LANGUAGE TypeFamilies #} import Text.Megaparsec.Stream import Data.Proxy data MyStream = MyStream { tokens :: [Char] } instance Stream MyStream where type Token MyStream = Char type Tokens MyStream = String tokenToChunk _ = pure tokensToChunk _ = id chunkToTokens _ = id chunkLength _ = length chunkEmpty _ = null take1_ (MyStream []) = Nothing take1_ (MyStream (t:ts)) = Just (t, MyStream ts) takeN_ n (MyStream s) | n <= 0 = Just ([], MyStream s) | null s = Nothing | otherwise = Just (splitAt n s) takeWhile_ f (MyStream s) = let (a, b) = span f s in (a, MyStream b) ``` -------------------------------- ### Example: Parse Byte Sequence (Case-Insensitive POST) Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Demonstrates using `string'` to parse the byte sequence "POST" case-insensitively. ```haskell -- Case-insensitive HTTP method method :: Parser B.ByteString method = string' "POST" ``` -------------------------------- ### ErrorItem Examples Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Demonstrates the construction of different `ErrorItem` variants: `Tokens`, `Label`, and `EndOfInput`. ```haskell import Text.Megaparsec.Error unexpected1 = Tokens ('a' :| "bc") expectedLabel = Label ('d' :| "igit") atEnd = EndOfInput ``` -------------------------------- ### Custom Error Types Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Example demonstrating how to define and use custom error types with `ShowErrorComponent`. ```APIDOC ## Custom Error Types ### Description Example demonstrating how to define and use custom error types with `ShowErrorComponent`. ### Usage ```haskell {-# LANGUAGE DeriveGeneric #-} import Text.Megaparsec import Text.Megaparsec.Error import Data.Void import GHC.Generics data CompileError = InvalidSyntax String | TypeMismatch String String | NameNotDefined String deriving (Show, Eq, Ord, Generic) instance ShowErrorComponent CompileError where showErrorComponent (InvalidSyntax msg) = "invalid syntax: " ++ msg showErrorComponent (TypeMismatch exp got) = "type mismatch: expected " ++ exp ++ " but got " ++ got showErrorComponent (NameNotDefined name) = "name not defined: " ++ name type Parser = Parsec CompileError String parseWithCustomErrors :: Parser () parseWithCustomErrors = do symbol "let" name <- identifier when (name == "reserved") $ customFailure (NameNotDefined name) ``` ``` -------------------------------- ### ErrorFancy Examples Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Shows examples of creating `ErrorFancy` types: `ErrorFail` for monadic failures, `ErrorIndentation` for indentation issues, and `ErrorCustom` for user-defined errors. ```haskell import Text.Megaparsec.Error monadFail = ErrorFail "Something went wrong" badIndent = ErrorIndentation GT (mkPos 2) (mkPos 1) customErr = ErrorCustom MyCustomError ``` -------------------------------- ### Stateful Parser Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/05-monadparsec-class.md Demonstrates creating a parser that interacts with state using `StateT` and `lift`. This parser increments a state counter for each character parsed. ```haskell import Control.Monad.State type StatefulParser st = ParsecT Void String (State st) -- Parser that maintains state countingParser :: StatefulParser Int String countingParser = do c <- anySingle lift $ modify (+1) return [c] ``` -------------------------------- ### Whitespace and Comment Handling Setup Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Provides functions for consuming whitespace, including options for line and block comments. Includes wrappers for lexing and parsing symbols and keywords. ```haskell -- Minimal whitespace consumer sc :: Parser () sc = L.space space1 empty empty -- With line comments scWithComments :: Parser () scWithComments = L.space space1 lineComment blockComment where lineComment = L.skipLineComment "--" blockComment = L.skipBlockComment "{- "-} " -- Lexeme wrapper lexeme :: Parser a -> Parser a lexeme = L.lexeme sc -- Symbols symbol :: String -> Parser String symbol = L.symbol sc -- Keywords (with lookahead to prevent matching prefixes) keyword :: String -> Parser () keyword kw = lexeme (string kw >> notFollowedBy alphaNumChar) >> return () ``` -------------------------------- ### Example: Parse Specific Bytes (Comma and Semicolon) Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Demonstrates using `char` to parse ASCII comma and semicolon bytes. ```haskell import Data.ByteString (ByteString) import Data.Word (Word8) import Text.Megaparsec.Byte type Parser = Parsec Void ByteString comma :: Parser Word8 comma = char 44 -- ASCII comma semicolon :: Parser Word8 semicolon = char 59 -- ASCII semicolon ``` -------------------------------- ### Example: Parse Specific Byte (Case-Insensitive 'A') Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Demonstrates using `char'` to parse the ASCII byte for 'A' case-insensitively. ```haskell -- Match 'A' or 'a' (bytes 65 or 97) letterA :: Parser Word8 letterA = char' 65 -- matches both uppercase and lowercase A ``` -------------------------------- ### Build Specific Dependent Package Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build and test a particular dependent package, for example, 'mmark'. ```console $ nix build .#deps/mmark --no-link ``` -------------------------------- ### Example: Signed Integer Parser Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/03-char-lexer.md Demonstrates parsing signed integers using `signed` and `decimal`. This parser handles optional '+' or '-' signs. ```haskell integer :: Parser Int integer = L.signed (return ()) L.decimal ``` -------------------------------- ### mapParseError Usage Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Example demonstrating how to use `mapParseError` to convert a custom error type (`MyError`) into its string representation by applying a transformation function `showFancy`. ```haskell -- Convert custom error to string representation errorToString :: ParseError String MyError -> ParseError String String errorToString = mapParseError showFancy where showFancy (ErrorCustom err) = ErrorFail (show err) showFancy e = e ``` -------------------------------- ### Apply Patch in Nix Configuration Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Example of how to apply a local patch file to a dependent package within the 'deps' attribute set in a Nix 'default.nix' file. ```nix deps = { # ... idris = patch haskellPackages.idris ./nix/patches/idris.patch; }; ``` -------------------------------- ### Run ghcid for Interactive Development Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Start ghcid for interactive development. Use the appropriate command based on whether you are editing the 'megaparsec' or 'megaparsec-tests' package. ```console ghcid --command="cabal repl megaparsec" ``` ```console ghcid --command="cabal repl megaparsec-tests --enable-tests" ``` -------------------------------- ### errorBundlePrettyWith Custom Filter Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md An example demonstrating how to use errorBundlePrettyWith to display only errors occurring at the latest position in the parsed input. ```haskell -- Display only errors at the last position importantErrors bundle = let lastPos = maximum $ map errorOffset (bundleErrors bundle) in errorBundlePrettyWith (\e -> errorOffset e == lastPos) bundle ``` -------------------------------- ### Create Initial Source Position Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Generates the starting SourcePos for a given file, setting line and column to 1. Use to initialize parsing context. ```haskell initialPos :: FilePath -> SourcePos ``` ```haskell let startPos = initialPos "input.txt" -- SourcePos "input.txt" (pos1) (pos1) ``` -------------------------------- ### handleParseError Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Example function demonstrating how to handle parse errors using `errorBundlePretty`. ```APIDOC ## Handling Parse Errors ### Description Example function demonstrating how to handle parse errors using `errorBundlePretty`. ### Usage ```haskell import Text.Megaparsec import Text.Megaparsec.Error myParser :: Parsec Void String Int myParser = read <$> some digitChar handleParseError :: FilePath -> String -> IO () handleParseError filename content = do case parse myParser filename content of Left err -> do putStrLn "Parse error:" putStr (errorBundlePretty err) Right value -> do putStrLn "Success:" print value -- Usage: main = handleParseError "input.txt" "not a number" ``` ``` -------------------------------- ### errorBundlePretty Example Usage Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Shows how to use errorBundlePretty within a case statement to print a formatted error message when parsing fails. ```haskell case parse myParser "file.txt" input of Left bundle -> putStrLn (errorBundlePretty bundle) Right result -> print result ``` -------------------------------- ### Example Usage of dbg' for Complex Parsers Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/07-debugging-and-error-builders.md Illustrates using `dbg'` to debug a complex parser that might not have a `Show` instance for its return type. ```haskell import Text.Megaparsec.Debug -- Parse something complex without Show instance complexParser :: (MonadParsecDbg e String m) => m ComplexType complexParser = dbg' "complex" innerParser ``` -------------------------------- ### Usage Example for ParsecT with IO Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Demonstrates defining a parser type using `ParsecT` over the `IO` monad, enabling parsers to perform I/O actions during parsing. ```haskell type Parser = ParsecT Void Text IO -- Parser that also performs I/O parseWithIO :: Parser String parseWithIO = do result <- anySingle _ <- liftIO $ putStrLn $ "Parsed: " ++ [result] return [result] ``` -------------------------------- ### Example Usage of dbg for Number Parsing Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/07-debugging-and-error-builders.md Demonstrates how to use the `dbg` function to trace the execution of a parser that reads a number. Requires importing Text.Megaparsec.Debug. ```haskell import Text.Megaparsec import Text.Megaparsec.Char import Text.Megaparsec.Debug type Parser = ParsecT Void String IO parseNumber :: Parser Int parseNumber = dbg "number" $ read <$> some digitChar main :: IO () main = do parseTest parseNumber "42" ``` -------------------------------- ### Example: Parsing Lines from ByteString Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Demonstrates parsing multiple lines from a ByteString, where each line is terminated by a newline character. Requires importing Text.Megaparsec.Byte and using a Parsec parser over ByteString. ```haskell import Data.ByteString (ByteString) import Text.Megaparsec.Byte type Parser = Parsec Void ByteString lines :: Parser [ByteString] lines = many (many (anySingleBut 10) <* newline) ``` -------------------------------- ### ParseError Examples Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Illustrates the creation of `TrivialError` and `FancyError` instances. `TrivialError` includes offset, unexpected token, and expected items, while `FancyError` contains an offset and custom error components. ```haskell import qualified Data.Set as Set trivialErr = TrivialError 5 (Just (Tokens ('x' :| ""))) (Set.singleton (Label ('y' :| ""))) fancyErr = FancyError 10 (Set.singleton (ErrorFail "parsing failed")) ``` -------------------------------- ### Example Usage of err for Error Creation Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/07-debugging-and-error-builders.md Demonstrates creating a trivial parse error at a specific offset with defined unexpected and expected tokens. ```haskell import Text.Megaparsec.Error.Builder import Text.Megaparsec.Pos -- Create an error at offset 5 myError = err 5 (utok 'x' <> etok 'y') ``` -------------------------------- ### Custom ShowErrorComponent Instance Example Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Demonstrates how to create a custom instance of ShowErrorComponent for a user-defined error type, enabling pretty-printing of specific error variants. ```haskell data MyError = InvalidToken String | UnexpectedEOF deriving (Show, Eq, Ord) instance ShowErrorComponent MyError where showErrorComponent (InvalidToken t) = "invalid token: " ++ t showErrorComponent UnexpectedEOF = "unexpected end of file" ``` -------------------------------- ### Run Parser with parse Function Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Provides an example of using the `parse` function to run a `Parsec` parser on a string input, handling success with the parsed value or failure with a pretty-printed error bundle. ```haskell import Text.Megaparsec import Text.Megaparsec.Char import Data.Text (Text) import qualified Data.Text as T type Parser = Parsec Void Text numbers :: Parser [Int] numbers = (read <$> some digitChar) `sepBy` char ',' main = do let input = "1,2,3,4,5" case parse numbers "numbers.txt" input of Left err -> putStrLn $ errorBundlePretty err Right ns -> print ns ``` -------------------------------- ### Indented Block Parsing Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Demonstrates parsing indented blocks using `L.indentBlock`. This example shows how to parse a block keyword followed by indented items. ```haskell -- Parse indented items indentedBlock :: Parser [Item] indentedBlock = L.indentBlock sc $ do keyword "block" return $ L.IndentMany Nothing return item item :: Parser Item item = Item <$> lexeme identifier ``` -------------------------------- ### Example: Skipping Whitespace Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Assigns the 'space' parser to a variable 'skipWhitespace'. This is a common pattern for defining a parser that ignores any whitespace characters. ```haskell skipWhitespace :: Parser () skipWhitespace = space ``` -------------------------------- ### Example: Parsing Windows-Style Lines Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Parses a ByteString that uses CRLF as its line ending. This is useful for compatibility with Windows text files when parsing binary data. ```haskell windowsLine :: Parser ByteString windowsLine = manyTill anySingle crlf ``` -------------------------------- ### Complete Megaparsec Lexer Setup Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Defines a comprehensive lexer with support for whitespace, line comments, block comments, symbols, literals (integers, floats), identifiers, keywords, and various separators. ```haskell {-# LANGUAGE OverloadedStrings #-} import qualified Text.Megaparsec.Char.Lexer as L import Text.Megaparsec type Parser = Parsec Void String -- Whitespace space :: Parser () space = L.space space1 lineComment blockComment where lineComment = L.skipLineComment "--" blockComment = L.skipBlockComment "{- "- }" -- Lexeme wrapper lexeme :: Parser a -> Parser a lexeme = L.lexeme space -- Symbols symbol :: String -> Parser String symbol = L.symbol space -- Literals integer :: Parser Integer integer = lexeme L.decimal float' :: Parser Double float' = lexeme L.float -- Identifiers (no reserved words check for this example) identifier :: Parser String identifier = lexeme $ (:) <$> letterChar <*> many alphaNumChar -- Keywords keyword :: String -> Parser () keyword w = lexeme $ string w >> notFollowedBy alphaNumChar -- Separators comma :: Parser () comma = void (symbol ",") semicolon :: Parser () semicolon = void (symbol ";") lparen :: Parser () lparen = void (symbol "(") rparen :: Parser () rparen = void (symbol ")") lbrace :: Parser () lbrace = void (symbol "{") rbrace :: Parser () rbrace = void (symbol "}") ``` -------------------------------- ### Example Usage of errFancy for Custom Errors Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/07-debugging-and-error-builders.md Shows how to create a custom fancy parse error with a specific message at a given offset. ```haskell -- Create a custom error customErr = errFancy 10 (fancy (ErrorFail "parsing failed")) ``` -------------------------------- ### Usage Example for Parsec Type Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Illustrates how to define a parser type using the `Parsec` alias for parsing `Text` input and returning `Int` values, using `Void` for errors. ```haskell type Parser = Parsec Void Text parseNumber :: Parser Int parseNumber = read <$> some digitChar ``` -------------------------------- ### Implement satisfy using token Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/05-monadparsec-class.md The `token` parser is a fundamental primitive that parses a single token based on a matching function and a set of expected items for error reporting. This example shows how to implement `satisfy` using `token`. ```haskell token :: (Token s -> Maybe a) -> Set (ErrorItem (Token s)) -> m a -- Implement satisfy using token satisfy :: (MonadParsec e s m) => (Token s -> Bool) -> m (Token s) satisfy f = token testToken Set.empty where testToken x = if f x then Just x else Nothing ``` -------------------------------- ### getOffset Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Gets the current offset, which represents the number of tokens consumed so far. This is useful for tracking progress or for advanced state manipulation. ```APIDOC ## getOffset ### Description Get the current offset in tokens consumed so far. ### Method N/A (Haskell function) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Response #### Success Response - `m Int` — offset ### Example ```haskell -- Get position in input for error reporting currentOffset :: (MonadParsec e s m) => m Int currentOffset = getOffset ``` ``` -------------------------------- ### Example: Platform-Independent Line Parsing Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/06-byte-parsing.md Parses a ByteString using 'eol' which handles both CRLF and LF line endings. This ensures consistent line parsing across different operating systems. ```haskell portableLine :: Parser ByteString portableLine = manyTill anySingle eol ``` -------------------------------- ### Conditional Parsing with `ifStmt` Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Shows how to implement conditional parsing logic using `ifStmt`, `whileStmt`, and `assignStmt`. The `statement` parser uses `ifStmt` as an example of a conditional structure. ```haskell -- Parse based on first token statement :: Parser Stmt statement = ifStmt <|> whileStmt <|> assignStmt ifStmt :: Parser Stmt ifStmt = do keyword "if" cond <- expr keyword "then" thenPart <- statement keyword "else" elsePart <- statement return $ If cond thenPart elsePart assignStmt :: Parser Stmt assignStmt = do name <- identifier symbol "=" val <- expr return $ Assign name val ``` -------------------------------- ### Comma-Separated List Parsing Utilities Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Provides utility parsers for handling comma-separated lists, including zero or more items, one or more items, and lists enclosed in brackets. Includes an example for parsing a list of decimals. ```haskell -- Zero or more items list :: Parser a -> Parser [a] list p = sepBy p (symbol ",") -- One or more items list1 :: Parser a -> Parser [a] list1 p = sepBy1 p (symbol ",") -- Between brackets bracketed :: Parser a -> Parser [a] bracketed p = symbol "[" *> sepBy p (symbol ",") <* symbol "]" -- Example usage numbers :: Parser [Int] numbers = bracketed L.decimal ``` -------------------------------- ### Build All Benchmarks Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build all benchmark suites for Megaparsec. The results will be symlinked in the 'result' directory. ```console $ nix build .#all_benches ``` -------------------------------- ### Megaparsec Common Type Aliases and Patterns Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/09-quick-reference.md Commonly used type aliases and lexer setup patterns for defining parsers, handling whitespace, and parsing basic language constructs like symbols, keywords, numbers, and identifiers. ```haskell -- Type alias type Parser = Parsec Void String -- Lexer setup sc :: Parser () sc = L.space space1 lineComment blockComment where lineComment = L.skipLineComment "--" blockComment = L.skipBlockComment "{- "- }" -- Wrapped lexeme lexeme :: Parser a -> Parser a lexeme = L.lexeme sc -- Symbol symbol :: String -> Parser String symbol = L.symbol sc -- Keyword keyword :: String -> Parser () keyword kw = lexeme (string kw >> notFollowedBy alphaNumChar) >> return () -- Number integer :: Parser Integer integer = lexeme L.decimal -- Identifier identifier :: Parser String identifier = lexeme ((:) <$> letterChar <*> many alphaNumChar) -- Expression with operators expr :: Parser Expr expr = makeExprParser term operators -- List parsing list :: Parser [a] list = symbol "[" *> sepBy expr (symbol ",") <* symbol "]" ``` -------------------------------- ### Build and Test All Base Packages Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build and test the 'base' group of packages, which includes Megaparsec, hspec-megaparsec, megaparsec-tests, and parser-combinators-tests. ```console $ nix build .#all_base --no-link ``` -------------------------------- ### Build Megaparsec and Test Packages Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build the main 'megaparsec' library and the 'megaparsec-tests' package within the Nix shell. ```console cabal build all ``` -------------------------------- ### Run Megaparsec Benchmarks Source: https://github.com/mrkkrp/megaparsec/blob/master/README.md Execute these commands in the terminal to build and run the Megaparsec benchmarks for memory and speed. ```bash $ nix-build -A benches.parsers-bench $ cd result/bench $ ./bench-memory $ ./bench-speed ``` -------------------------------- ### Build All Dependent Packages Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build and test a selected set of high-quality dependent packages to check compatibility with your changes. ```console $ nix build .#all_deps --no-link ``` -------------------------------- ### Enter Nix Development Shell Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Use this command to enter the Nix shell for development. All subsequent development commands should be run from within this shell. ```console $ nix develop ``` -------------------------------- ### Skip Non-Nested Block Comment Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/03-char-lexer.md Skips a non-nested block comment between specified start and end delimiters. Always succeeds. ```haskell skipBlockComment :: (MonadParsec e s m) => Tokens s -> Tokens s -> m () blockComment :: Parser () blockComment = L.skipBlockComment "/*" "*/" ``` -------------------------------- ### Get Remaining Input Stream Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Retrieves the entire remaining input stream. This is useful for peeking at the input without consuming it. ```haskell getInput :: (MonadParsec e s m) => m s ``` ```haskell peek :: (MonadParsec e String m) => m String peek = getInput ``` -------------------------------- ### Get Current Indentation Level Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/03-char-lexer.md Returns the current column position as the indentation level. Useful for enforcing indentation rules. ```haskell indentLevel :: (TraversableStream s, MonadParsec e s m) => m Pos checkIndent :: Parser Pos checkIndent = L.indentLevel ``` -------------------------------- ### Build Specific Package Benchmarks Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build the microbenchmarks for a specific package, such as 'megaparsec'. ```console $ nix build .#benches/megaparsec # builds megaparsec's microbenchmarks ``` -------------------------------- ### Line Comment Parser Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/02-character-parsing.md Parses a line comment that starts with '--' and continues until the end of the line. This is used to ignore comments in the input. ```haskell -- Line comment (until end of line) lineComment :: (MonadParsec e String m) => m () lineComment = string "--" *> skipMany (anySingleBut '\n') ``` -------------------------------- ### Build Specific Base Package Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Build and test an individual package from the 'base' group, such as 'parser-combinators-tests'. ```console $ nix build .#base/parser-combinators-tests --no-link ``` -------------------------------- ### Skip line comments Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/03-char-lexer.md Parses and consumes a line comment, starting with a specified prefix and continuing to the end of the line. Does not consume the newline character itself. ```haskell lineComment :: Parser () lineComment = L.skipLineComment "--" -- Usage in space consumer: sc = L.space space1 lineComment blockComment -- parseTest sc "hello -- comment\nworld" ``` -------------------------------- ### Identifier Parser Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/02-character-parsing.md Parses a string that starts with a letter followed by zero or more alphanumeric characters. This is a common pattern for parsing identifiers in programming languages. ```haskell identifier :: (MonadParsec e String m) => m String identifier = (:) <$> letterChar <*> many alphaNumChar "identifier" ``` -------------------------------- ### Initial PosState Constructor Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Constructs the initial position state for parsing. Requires the source file name and the input stream. ```haskell initialPosState :: FilePath -> s -> PosState s ``` -------------------------------- ### Get Current Offset Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Retrieves the current offset, indicating the number of tokens consumed so far. Useful for tracking progress or for error reporting. ```haskell getOffset :: (MonadParsec e s m) => m Int ``` ```haskell -- Get position in input for error reporting currentOffset :: (MonadParsec e s m) => m Int currentOffset = getOffset ``` -------------------------------- ### Run Tests in Megaparsec-Tests Package Source: https://github.com/mrkkrp/megaparsec/blob/master/HACKING.md Execute all tests defined in the 'megaparsec-tests' package. ```console cabal test all ``` -------------------------------- ### try Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/05-monadparsec-class.md Enables backtracking for a parser. If the parser fails after consuming input, the input position is reset, allowing alternative parsers to be attempted. ```APIDOC ## try ### Description Backtrack on failure. When the parser fails after consuming input, pretend no input was consumed, allowing alternatives to be tried. ### Method `try :: m a -> m a` ### Parameters - **parser** (`m a`): Parser to try with backtracking ### Returns `m a` ### Usage Needed for choice operators when alternatives overlap in their initial input. ### Performance Note `tokens`, `takeWhileP`, `takeWhile1P`, and `string`-based parsers backtrack automatically. ### Example ```haskell -- Without try, "lexical" fails because "let" matches first 2 chars parseTest (string "let" <|> string "lexical") "lexical" -- Error: unexpected "lex", expecting "let" -- With try, backtracking allows second alternative parseTest (try (string "let") <|> string "lexical") "lexical" -- Success: "lexical" ``` ``` -------------------------------- ### Fast Primitive vs. Slow Alternative Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/05-monadparsec-class.md Demonstrates using the fast primitive `takeWhileP` for consuming matching tokens instead of a character-by-character approach with `many` and `satisfy`. ```haskell -- Instead of character-by-character: slow :: (MonadParsec e String m) => m String slow = many (satisfy isAlpha) -- Use fast primitive: fast :: (MonadParsec e String m) => m String fast = takeWhileP (Just "letter") isAlpha ``` -------------------------------- ### initialPosState Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Constructs the initial position state required for parsing. It takes the source file name and the input stream as parameters. ```APIDOC ## initialPosState ### Description Construct the initial position state. ### Parameters - **filename** (FilePath) - Source file name - **input** (s) - Input stream ### Returns `PosState s` ``` -------------------------------- ### Run Parser with parseMaybe Function Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Shows how to use `parseMaybe` for lightweight parsing that returns `Just` the parsed value on success or `Nothing` on failure, requiring complete input consumption. ```haskell type Parser = Parsec Void Text maybeInt :: Maybe Int maybeInt = parseMaybe (read <$> some digitChar) "42" -- Result: Just 42 noInt :: Maybe Int noInt = parseMaybe (read <$> some digitChar) "abc" -- Result: Nothing ``` -------------------------------- ### Get Current Source Position Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Retrieves the current source position, including file name, line, and column. Useful for error reporting and context tracking. ```haskell getSourcePos :: (TraversableStream s, MonadParsec e s m) => m SourcePos ``` ```haskell withPosition :: (TraversableStream s, MonadParsec e s m) => m a -> m (SourcePos, a) withPosition p = do pos <- getSourcePos val <- p return (pos, val) ``` -------------------------------- ### Run Parser with runParser Function Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Illustrates the use of `runParser`, which is equivalent to `parse`, for running a `Parsec` parser over `Identity` with an explicit filename. ```haskell runParser :: Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a ``` -------------------------------- ### Parse without consuming input using lookAhead Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/05-monadparsec-class.md Use `lookAhead` to run a parser without advancing the input position. This is useful for peeking at input, for example, to check for keywords. ```haskell -- Check for keyword without consuming peekKeyword :: (MonadParsec e String m) => m (Maybe String) peekKeyword = optional (lookAhead identifier) -- Example: parse "if" only if it's actually there ifStatement :: (MonadParsec e String m) => m Expr ifStatement = do keyword <- lookAhead (string "if") -- Now parse normally string "if" condition <- expr return (If condition) ``` -------------------------------- ### Get and Check Indentation Level Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Retrieve the current indentation level using `L.indentLevel`. The `indentedExpr` parser demonstrates how to enforce indentation by comparing the current level against a reference level. ```haskell checkIndent :: Parser Pos checkIndent = L.indentLevel indentedExpr :: Parser Expr indentedExpr = do ref <- L.indentLevel expr' <- expression actual <- L.indentLevel if actual >= ref then return expr' else fail "insufficient indentation" ``` -------------------------------- ### Create Initial Parser State Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/04-types-and-errors.md Constructs the initial State for a parser given the input stream and a filename for error reporting. Initializes offset to 0 and error list to empty. ```haskell initialState :: FilePath -> s -> State s e ``` ```haskell initialState "input.txt" "some input" ``` -------------------------------- ### Run Parser with parseTest Function Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Demonstrates using `parseTest` to run a parser and print the result or error message to `IO`, useful for interactive testing and development. ```haskell type Parser = Parsec Void String main = do parseTest (some digitChar) "12345" -- Output: "12345" parseTest (some digitChar) "hello" -- Output: (error message showing unexpected input) ``` -------------------------------- ### Line-Based Parsing Utilities Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Offers parsers for handling lines of text, including parsing multiple lines, a single line, and non-empty lines while skipping empty ones. ```haskell -- Parse multiple lines lines :: Parser [String] lines = endBy line newline -- Parse a single line (everything until newline) line :: Parser String line = manyTill anySingle newline -- Parse lines with content (skip empty lines) nonEmptyLines :: Parser [String] nonEmptyLines = many $ lexeme (manyTill anySingle eol) <* optional eol ``` -------------------------------- ### runParser Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Equivalent to `parse`. Runs a parser over the Identity monad with an explicit filename for error reporting. ```APIDOC ## runParser ### Description Equivalent to `parse`. Runs a parser over `Identity` with explicit filename. ### Method `runParser` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **parser** (`Parsec e s a`) - Required - The parser to run - **filename** (`String`) - Required - Name used in error messages - **input** (`s`) - Required - Input stream to parse ### Response #### Success Response (200) - **a** (`a`) - The successfully parsed value #### Error Response - **ParseErrorBundle s e** (`Either (ParseErrorBundle s e) a`) - Parse error bundle on failure ### Example ```haskell -- Example usage is identical to the 'parse' function. -- runParser :: Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a ``` ``` -------------------------------- ### parse Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Runs a parser over the Identity monad. This is a common entry point for parsing, returning either a parse error bundle or the successfully parsed value. ```APIDOC ## parse ### Description Runs a parser over `Identity`. This is the most common entry point for parsing. ### Method `parse` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **parser** (`Parsec e s a`) - Required - The parser to run - **filename** (`String`) - Required - Name used in error messages (can be empty string) - **input** (`s`) - Required - Input stream to parse ### Response #### Success Response (200) - **a** (`a`) - The successfully parsed value #### Error Response - **ParseErrorBundle s e** (`Either (ParseErrorBundle s e) a`) - Parse error bundle on failure ### Example ```haskell import Text.Megaparsec import Text.Megaparsec.Char import Data.Text (Text) import qualified Data.Text as T type Parser = Parsec Void Text numbers :: Parser [Int] numbers = (read <$> some digitChar) `sepBy` char ',' main = do let input = "1,2,3,4,5" case parse numbers "numbers.txt" input of Left err -> putStrLn $ errorBundlePretty err Right ns -> print ns ``` ``` -------------------------------- ### anySingle Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Parses and returns any single token from the stream. Always succeeds unless at the end of the input. ```APIDOC ## anySingle ### Description Parse and return any single token from the stream. Always succeeds unless at end of input. ### Returns - **m (Token s)** — the next token ### Definition `anySingle = satisfy (const True)` ### Usage Parse and return any single token from the stream. ### Request Example ```haskell -- Copy one character from input copyChar :: (MonadParsec e String m) => m Char copyChar = do c <- anySingle liftIO $ putChar c return c ``` ``` -------------------------------- ### unexpected Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md Fails with an error message about an unexpected item without consuming input. ```APIDOC ## unexpected ### Description Fail with an error message about an unexpected item without consuming input. ### Parameters #### Path Parameters - item (ErrorItem (Token s)) - Required - What was unexpected ### Returns m a ### Example ```haskell -- Fail if we see a semicolon where it's unexpected notSemicolon :: (MonadParsec e String m) => m Char notSemicolon = do c <- anySingle when (c == ';') $ unexpected (Tokens (';' :| [])) return c ``` ``` -------------------------------- ### Recommended Megaparsec Imports Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/09-quick-reference.md A standard set of imports for common Megaparsec usage, including core modules, character parsers, lexer utilities, and common Haskell libraries. ```haskell import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L import Data.Void import Data.Text (Text) import Data.Scientific import Control.Applicative import Control.Monad.Combinators.Expr ``` -------------------------------- ### Fast Input Consumption in Haskell Source: https://github.com/mrkkrp/megaparsec/blob/master/README.md Combinators like `takeWhile`, `takeWhile1`, and `takeP` provide high-performance ways to consume input streams. `takeP` specifically grabs a specified number of tokens as a chunk, similar to `tokens`. ```haskell takeWhile :: (Stream s m t) => (t -> Bool) -> ParsecT s u m s takeWhile1 :: (Stream s m t) => (t -> Bool) -> ParsecT s u m s takeP :: (Stream s m t) => Int -> ParsecT s u m s ``` -------------------------------- ### runParser' Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/01-core-types-and-runners.md An advanced variant of `runParser` that accepts and returns the parser state, allowing for parsing to begin at an arbitrary position. ```APIDOC ## runParser' ### Description Advanced variant that accepts and returns parser state. Allows specifying arbitrary textual position at the beginning of parsing. ### Parameters #### Path Parameters - parser (Parsec e s a) - Required - The parser to run - state (State s e) - Required - Initial parser state ### Returns Tuple of final state and either parse error or result ### Usage For resuming parsing from a specific position or state ### Example ```haskell type Parser = Parsec Void Text -- Parse with custom initial position let state = State { stateInput = "hello world" , stateOffset = 0 , statePosState = initialPosState "custom.txt" "hello world" , stateParseErrors = [] } (finalState, result) = runParser' (some letterChar) state ``` ``` -------------------------------- ### Permutation Parsing for Arguments Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/08-common-patterns.md Parses a set of arguments in any order using `Control.Applicative.Permutations`. This is useful for parsing function calls or configuration options where argument order is not fixed. ```haskell import Control.Applicative.Permutations -- Parse arguments in any order arguments :: Parser (String, String, Int) arguments = runPermutation $ (,,) <$> toPermutation (keyword "name" *> identifier) <*> toPermutation (keyword "type" *> identifier) <*> toPermutation (keyword "count" *> L.decimal) ``` -------------------------------- ### string Source: https://github.com/mrkkrp/megaparsec/blob/master/_autodocs/02-character-parsing.md Parses an exact sequence of characters. ```APIDOC ## string ### Description Parse an exact sequence of characters. ### Parameters: #### Path Parameters - s (Tokens s) - String to match ### Returns m (Tokens s) — the matched string ### Note Auto-backtracking; on failure, no input is consumed ### Performance Optimized using `tokens` primitive; fast even for long strings ### Example: ```haskell keyword :: (MonadParsec e String m) => String -> m String keyword kw = string kw ("keyword " ++ show kw) let_ :: (MonadParsec e String m) => m String let_ = keyword "let" if_ :: (MonadParsec e String m) => m String if_ = keyword "if" ``` ```