Skip to content

Sequential parser

parser1 & parser2: sequential parser

All the previous parsers will match at most one thing. This is the syntax for matching one parser and then another after it. If working in a ParserContext, the two may be separated by whitespace. The value returned is a list of all the values returned by each parser. If there are multiple parsers separated by &, a list of the same length as the number of parsers is returned. Like |, either side may be a bare string, but not both. In accordance with Python's operator precedence, & binds more tightly than |.

from parsita import *

class UrlParsers(ParserContext):
    url = lit('http', 'ftp') & '://' & reg(r'[^/]+') & reg(r'.*')

assert UrlParsers.url.parse('http://drhagen.com/blog/sane-equality/') == \
    Success(['http', '://', 'drhagen.com', '/blog/sane-equality/'])

seq(*parsers): sequential parser

seq is the explicit function form of &. It takes any number of parsers and matches them in order, returning a list of all their values.

Unlike &, seq never flattens nested SequentialParsers. With &, an unprotected SequentialParser on the left side is extended, so (a & b) & c produces a 3-element list [a, b, c], while a & (b & c) produces a 2-element list [a, [b, c]]. With seq, each argument is always one element of the result, so seq(a & b, c) always produces a 2-element list [[a, b], c].

from parsita import *

class CidrParsers(ParserContext):
    octet = reg(r'\d{1,3}') > int
    ip = seq(octet << '.', octet << '.', octet << '.', octet)
    prefix = reg(r'\d{1,2}') > int
    cidr = seq(ip << '/', prefix)

assert CidrParsers.cidr.parse('192.168.1.0/24') == Success([[192, 168, 1, 0], 24])

parser1 >> parser2 and parser1 << parser2: discard left and right parsers

The discard left and discard right parser match the exact same text as parser1 & parser2, but rather than return a list of values from both, the left value in >> and the right value in << is discarded so that only the remaining value is returned. A mnemonic to help remember which is which is to imagine the symbols as open mouths eating the parser to be discarded.

from parsita import *

class PointParsers(ParserContext, whitespace=r'[ ]*'):
    integer = reg(r'[-+]?[0-9]+') > int
    point = '(' >> integer << ',' & integer << ')'

assert PointParsers.point.parse('(4, 3)') == Success([4, 3])