flatparse-0.3.5.1: High-performance parsing from strict bytestrings

FlatParse.Basic

Description

This module implements a Parser supporting custom error types. If you need efficient indentation parsing, use FlatParse.Stateful instead.

Many internals are exposed for hacking on and extending. These are generally denoted by a # hash suffix.

Synopsis

# Parser types and constructors

newtype Parser e a Source #

Parser e a has an error type e and a return type a.

Constructors

 Parser FieldsrunParser# :: ForeignPtrContents -> Addr# -> Addr# -> Res# e a

#### Instances

Instances details

# Running parsers

runParser :: Parser e a -> ByteString -> Result e a Source #

Run a parser.

runParserS :: Parser e a -> String -> Result e a Source #

Run a parser on a String input. Reminder: OverloadedStrings for ByteString does not yield a valid UTF-8 encoding! For non-ASCII ByteString literal input, use runParserS or packUTF8 for testing.

# Errors and failures

empty :: Parser e a Source #

The failing parser. By default, parser choice (<|>) arbitrarily backtracks on parser failure.

err :: e -> Parser e a Source #

Throw a parsing error. By default, parser choice (<|>) can't backtrack on parser error. Use try to convert an error to a recoverable failure.

lookahead :: Parser e a -> Parser e a Source #

Save the parsing state, then run a parser, then restore the state.

fails :: Parser e a -> Parser e () Source #

Convert a parsing failure to a success.

try :: Parser e a -> Parser e a Source #

Convert a parsing error into failure.

optional :: Parser e a -> Parser e (Maybe a) Source #

Convert a parsing failure to a Maybe. If possible, use withOption instead.

optional_ :: Parser e a -> Parser e () Source #

Convert a parsing failure to a ().

withOption :: Parser e a -> (a -> Parser e b) -> Parser e b -> Parser e b Source #

CPS'd version of optional. This is usually more efficient, since it gets rid of the extra Maybe allocation.

cut :: Parser e a -> e -> Parser e a Source #

Convert a parsing failure to an error.

cutting :: Parser e a -> e -> (e -> e -> e) -> Parser e a Source #

Run the parser, if we get a failure, throw the given error, but if we get an error, merge the inner and the newly given errors using the e -> e -> e function. This can be useful for implementing parsing errors which may propagate hints or accummulate contextual information.

# Basic lexing and parsing

eof :: Parser e () Source #

Succeed if the input is empty.

Read the given number of bytes as a ByteString.

Throws a runtime error if given a negative integer.

Consume the rest of the input. May return the empty bytestring.

skip :: Int -> Parser e () Source #

Skip forward n bytes. Fails if fewer than n bytes are available.

Throws a runtime error if given a negative integer.

Parse a UTF-8 character literal. This is a template function, you can use it as $(char 'x'), for example, and the splice in this case has type Parser e (). byte :: Word8 -> Parser e () Source # Read a Word8. bytes :: [Word] -> Q Exp Source # Read a sequence of bytes. This is a template function, you can use it as $(bytes [3, 4, 5]), for example, and the splice has type Parser e ().

Parse a UTF-8 string literal. This is a template function, you can use it as $(string "foo"), for example, and the splice has type Parser e (). This is a template function which makes it possible to branch on a collection of string literals in an efficient way. By using switch, such branching is compiled to a trie of primitive parsing operations, which has optimized control flow, vectorized reads and grouped checking for needed input bytes. The syntax is slightly magical, it overloads the usual case expression. An example: $(switch [| case _ of
"foo" -> pure True
"bar" -> pure False |])


The underscore is mandatory in case _ of. Each branch must be a string literal, but optionally we may have a default case, like in

    \$(switch [| case _ of
"foo" -> pure 10
"bar" -> pure 20
_     -> pure 30 |])


All case right hand sides must be parsers with the same type. That type is also the type of the whole switch expression.

A switch has longest match semantics, and the order of cases does not matter, except for the default case, which may only appear as the last case.

If a switch does not have a default case, and no case matches the input, then it returns with failure, without having consumed any input. A fallthrough to the default case also does not consume any input.

Switch expression with an optional first argument for performing a post-processing action after every successful branch matching, not including the default branch. For example, if we have ws :: Parser e () for a whitespace parser, we might want to consume whitespace after matching on any of the switch cases. For that case, we can define a "lexeme" version of switch as follows.

  switch' :: Q Exp -> Q Exp
switch' = switchWithPost (Just [| ws |])


Note that this switch' function cannot be used in the same module it's defined in, because of the stage restriction of Template Haskell.

rawSwitchWithPost :: Maybe (Q Exp) -> [(String, Q Exp)] -> Maybe (Q Exp) -> Q Exp Source #

Version of switchWithPost without syntactic sugar. The second argument is the list of cases, the third is the default case.

satisfy :: (Char -> Bool) -> Parser e Char Source #

Parse a UTF-8 Char for which a predicate holds.

satisfy_ :: (Char -> Bool) -> Parser e () Source #

Skip a UTF-8 Char for which a predicate holds.

satisfyASCII :: (Char -> Bool) -> Parser e Char Source #

Parse an ASCII Char for which a predicate holds. Assumption: the predicate must only return True for ASCII-range characters. Otherwise this function might read a 128-255 range byte, thereby breaking UTF-8 decoding.

satisfyASCII_ :: (Char -> Bool) -> Parser e () Source #

Skip an ASCII Char for which a predicate holds. Assumption: the predicate must only return True for ASCII-range characters.

fusedSatisfy :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser e Char Source #

This is a variant of satisfy which allows more optimization. We can pick four testing functions for the four cases for the possible number of bytes in the UTF-8 character. So in fusedSatisfy f1 f2 f3 f4, if we read a one-byte character, the result is scrutinized with f1, for two-bytes, with f2, and so on. This can result in dramatic lexing speedups.

For example, if we want to accept any letter, the naive solution would be to use isLetter, but this accesses a large lookup table of Unicode character classes. We can do better with fusedSatisfy isLatinLetter isLetter isLetter isLetter, since here the isLatinLetter is inlined into the UTF-8 decoding, and it probably handles a great majority of all cases without accessing the character table.

fusedSatisfy_ :: (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> (Char -> Bool) -> Parser e () Source #

Skipping variant of fusedSatisfy.

Parse any Word8 (byte).

anyWord8_ :: Parser e () Source #

Skip any Word8 (byte).

Parse any Word16.

anyWord16_ :: Parser e () Source #

Skip any Word16.

Parse any Word32.

anyWord32_ :: Parser e () Source #

Skip any Word32.

Parse any Word64.

anyWord64_ :: Parser e () Source #

Skip any Word64.

Parse any Word.

anyWord_ :: Parser e () Source #

Skip any Word.

Parse any Int8.

Parse any Int16.

Parse any Int32.

Parse any Int64.

Parse any Int.

Parse any UTF-8-encoded Char.

anyChar_ :: Parser e () Source #

Skip any UTF-8-encoded Char.

Parse any Char in the ASCII range, fail if the next input character is not in the range. This is more efficient than anyChar if we are only working with ASCII.

Skip any Char in the ASCII range. More efficient than anyChar_ if we're working only with ASCII.

isDigit c = '0' <= c && c <= '9'
isGreekLetter c = ('Α' <= c && c <= 'Ω') || ('α' <= c && c <= 'ω')
isLatinLetter c = ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')

Read a non-negative Int from the input, as a non-empty digit sequence. The Int may overflow in the result.

Read a non-negative Integer from the input, as a non-empty digit sequence.

Read a null-terminated bytestring (a C-style string).

Consumes the null terminator.

## Explicit-endianness machine integers

Parse any Word16 (little-endian).

Parse any Word16 (big-endian).

Parse any Word32 (little-endian).

Parse any Word32 (big-endian).

Parse any Word64 (little-endian).

Parse any Word64 (big-endian).

Parse any Int16 (little-endian).

Parse any Int16 (big-endian).

Parse any Int32 (little-endian).

Parse any Int32 (big-endian).

Parse any Int64 (little-endian).

Parse any Int64 (big-endian).

# Combinators

(<|>) :: Parser e a -> Parser e a -> Parser e a infixr 6 Source #

Choose between two parsers. If the first parser fails, try the second one, but if the first one throws an error, propagate the error.

branch :: Parser e a -> Parser e b -> Parser e b -> Parser e b Source #

Branch on a parser: if the first argument succeeds, continue with the second, else with the third. This can produce slightly more efficient code than (<|>). Moreover, ḃranch does not backtrack from the true/false cases.

chainl :: (b -> a -> b) -> Parser e b -> Parser e a -> Parser e b Source #

An analogue of the list foldl function: first parse a b, then parse zero or more a-s, and combine the results in a left-nested way by the b -> a -> b function. Note: this is not the usual chainl function from the parsec libraries!

chainr :: (a -> b -> b) -> Parser e a -> Parser e b -> Parser e b Source #

An analogue of the list foldr function: parse zero or more a-s, terminated by a b, and combine the results in a right-nested way using the a -> b -> b function. Note: this is not the usual chainr function from the parsec libraries!

many :: Parser e a -> Parser e [a] Source #

Run a parser zero or more times, collect the results in a list. Note: for optimal performance, try to avoid this. Often it is possible to get rid of the intermediate list by using a combinator or a custom parser.

many_ :: Parser e a -> Parser e () Source #

Skip a parser zero or more times.

some :: Parser e a -> Parser e [a] Source #

Run a parser one or more times, collect the results in a list. Note: for optimal performance, try to avoid this. Often it is possible to get rid of the intermediate list by using a combinator or a custom parser.

some_ :: Parser e a -> Parser e () Source #

Skip a parser one or more times.

notFollowedBy :: Parser e a -> Parser e b -> Parser e a Source #

Succeed if the first parser succeeds and the second one fails.

isolate :: Int -> Parser e a -> Parser e a Source #

isolate n p runs the parser p isolated to the next n bytes. All isolated bytes must be consumed.

Throws a runtime error if given a negative integer.

# Positions and spans

newtype Pos Source #

Byte offset counted backwards from the end of the buffer.

Constructors

 Pos Int

#### Instances

Instances details
 Source # Instance detailsDefined in FlatParse.Internal Methods(==) :: Pos -> Pos -> Bool #(/=) :: Pos -> Pos -> Bool # Source # Instance detailsDefined in FlatParse.Internal Methodscompare :: Pos -> Pos -> Ordering #(<) :: Pos -> Pos -> Bool #(<=) :: Pos -> Pos -> Bool #(>) :: Pos -> Pos -> Bool #(>=) :: Pos -> Pos -> Bool #max :: Pos -> Pos -> Pos #min :: Pos -> Pos -> Pos # Source # Instance detailsDefined in FlatParse.Internal MethodsshowsPrec :: Int -> Pos -> ShowS #show :: Pos -> String #showList :: [Pos] -> ShowS #

data Span Source #

A pair of positions.

Constructors

 Span !Pos !Pos

#### Instances

Instances details
 Source # Instance detailsDefined in FlatParse.Internal Methods(==) :: Span -> Span -> Bool #(/=) :: Span -> Span -> Bool # Source # Instance detailsDefined in FlatParse.Internal MethodsshowsPrec :: Int -> Span -> ShowS #show :: Span -> String #showList :: [Span] -> ShowS #

Get the current position in the input.

setPos :: Pos -> Parser e () Source #

Set the input position. Warning: this can result in crashes if the position points outside the current buffer. It is always safe to setPos values which came from getPos with the current input.

The end of the input.

spanOf :: Parser e a -> Parser e Span Source #

Return the consumed span of a parser.

withSpan :: Parser e a -> (a -> Span -> Parser e b) -> Parser e b Source #

Bind the result together with the span of the result. CPS'd version of spanOf for better unboxing.

Return the ByteString consumed by a parser. Note: it's more efficient to use spanOf and withSpan instead.

withByteString :: Parser e a -> (a -> ByteString -> Parser e b) -> Parser e b Source #

CPS'd version of byteStringOf. Can be more efficient, because the result is more eagerly unboxed by GHC. It's more efficient to use spanOf or withSpan instead.

inSpan :: Span -> Parser e a -> Parser e a Source #

Run a parser in a given input span. The input position and the Int state is restored after the parser is finished, so inSpan does not consume input and has no side effect. Warning: this operation may crash if the given span points outside the current parsing buffer. It's always safe to use inSpan if the span comes from a previous withSpan or spanOf call on the current input.

## Position and span conversions

Check whether a Pos points into a ByteString.

posLineCols :: ByteString -> [Pos] -> [(Int, Int)] Source #

Compute corresponding line and column numbers for each Pos in a list. Throw an error on invalid positions. Note: computing lines and columns may traverse the ByteString, but it traverses it only once regardless of the length of the position list.

Create a ByteString from a Span. The result is invalid if the Span points outside the current buffer, or if the Span start is greater than the end position.

Slice into a ByteString using a Span. The result is invalid if the Span is not a valid slice of the first argument.

mkPos :: ByteString -> (Int, Int) -> Pos Source #

Create a Pos from a line and column number. Throws an error on out-of-bounds line and column numbers.

lines :: ByteString -> [String] Source #

Break an UTF-8-coded ByteString to lines. Throws an error on invalid input. This is mostly useful for grabbing specific source lines for displaying error messages.

# Getting the rest of the input as a String

Parse the rest of the current line as a String. Assumes UTF-8 encoding, throws an error if the encoding is invalid.

Parse the rest of the current line as a String, but restore the parsing state. Assumes UTF-8 encoding. This can be used for debugging.

Take the rest of the input as a String. Assumes UTF-8 encoding.

Get the rest of the input as a String, but restore the parsing state. Assumes UTF-8 encoding. This can be used for debugging.

# String conversions

Convert a String to an UTF-8-coded ByteString.

Convert an UTF-8-coded ByteString to a String.

# Internal functions

ensureBytes# :: Int -> Parser e () Source #

Check that the input has at least the given number of bytes.

## Unboxed arguments

Read the given number of bytes as a ByteString.

Throws a runtime error if given a negative integer.

atSkip# :: Int# -> Parser e a -> Parser e a Source #

Skip forward n bytes and run the given parser. Fails if fewer than n bytes are available.

Throws a runtime error if given a negative integer.

setBack# :: Int -> Parser e () Source #

Decrease the current input position by the given number of bytes.

withAddr# :: (Addr# -> Parser e a) -> Parser e a Source #

Run a parser, passing it the current address the parser is at.

Useful for parsing offset-based data tables. For example, you may use this to save the base address to use together with various 0-indexed offsets.

takeBsOffAddr offset moves to addr#, skips offset# bytes, reads len# bytes into a ByteString, and restores the original address.

The Addr# should be from withAddr#.

Useful for parsing offset-based data tables. For example, you may use this together with withAddr# to jump to an offset in your input and read some data.

lookahead, but specify the address to lookahead from.

The Addr# should be from withAddr#.

atAddr# :: Addr# -> Parser e a -> Parser e a Source #

Run a parser at the given address.

The Addr# should be from withAddr#.

This is a highly internal function -- you likely want lookaheadFromAddr#, which will reset the address after running the parser.

## Machine integer continuation parsers

withAnyInt64# :: (Int# -> Parser e a) -> Parser e a Source #

## Unsafe

Read a null-terminated bytestring (a C-style string), where the bytestring is known to be null-terminated somewhere in the input.

Highly unsafe. Unless you have a guarantee that the string will be null terminated before the input ends, use anyCString instead. Honestly, I'm not sure if this is a good function to define. But here it is.

Fails on GHC versions older than 9.0, since we make use of the cstringLength# primop introduced in GHC 9.0, and we aren't very useful without it.

Consumes the null terminator.

scan8# :: Word8 -> Parser e () Source #

Unsafely read a concrete byte from the input. It's not checked that the input has enough bytes.

scan16# :: Word16 -> Parser e () Source #

Unsafely read two concrete bytes from the input. It's not checked that the input has enough bytes.

scan32# :: Word32 -> Parser e () Source #

Unsafely read four concrete bytes from the input. It's not checked that the input has enough bytes.

scan64# :: Word -> Parser e () Source #

Unsafely read eight concrete bytes from the input. It's not checked that the input has enough bytes.

Unsafely read and return a byte from the input. It's not checked that the input is non-empty.

scanBytes# :: [Word] -> Q Exp Source #

Template function, creates a Parser e () which unsafely scans a given sequence of bytes.