parser > function: conversion parser
Conversion parsers don't change how the text is parsed—they change the value returned. Every parser returns a value when it succeeds. The function supplied must take a single argument (the successful value) and returns a new value. This is how text is converted to other objects and simpler objects built into larger ones. In accordance with Python's operator precedence,
> is the operator in Parsita with the loosest binding.
from parsita import * class IntegerParsers(TextParsers): integer = reg(r'[-+]?[0-9]+') > int assert IntegerParsers.integer.parse('-128') == Success(-128)
parser >= function: transformation parser
Transformation parsers pass the parsed output to a function which returns a new parser. This new parser is then immediately applied to the remaining input. There are two main uses for this parser.
The first use is as a fallible conversion parser. The conversion parser cannot tolerate failure. From the conversion parser's perspective, by the time the parsed output gets to the conversion function, parsing has already succeeded, just the output value is being changed. If the parsing needs to fail, then the transformation parser can be used. The transformer function can return a
success or a
failure to declare success or failure based on its calculation.
TransformationParser is basically equivalent to a
PredicateParser followed by a
ConversionParser. Where you would otherwise write
pred(parser, is_valid_object) > create_object, you can write
parser >= maybe_create_object, instead.
from dataclasses import dataclass from parsita import * @dataclass class Percent: number: int def to_percent(number: int) -> Parser[str, Percent]: if not 0 <= number <= 100: return failure("a number between 0 and 100") else: return success(Percent(number)) class PercentParsers(TextParsers): percent = (reg(r"[0-9]+") > int) >= to_percent assert PercentParsers.percent.parse('50') == Success(Percent(50)) assert isinstance(PercentParsers.percent.parse('150'), Failure)
In the current version of Parsita, the error messages that come from this leave something to be desired. Right now in the core of Parsita, there is no way to separately specify where in the input parsing failed or what the actual token was. The location of the failure is always the farther point that input was consumed and the actual token is always the next token from that point. That means that the error message will always mark the token after what was successfully consumed and passed to
>= before it was converted into a failure. Future versions of Parsita will address this issue.
Parsers parameterized by previous input
The second use is to parse later text based on previous text. This is incredibly powerful, but in my experience, not that useful. When viewing parser combinators as a monad, this is the
bind operation, so functional programming enthusiasts are really into it. It is only included in Parsita because it came free with the fallible conversion parser use case above.
from parsita import * def select_parser(type: str): if type == 'int': return reg(r"[0-9]+") > int elif type == 'decimal': return reg(r"[0-9]+\.[0-9]+") > float class NumberParsers(TextParsers): type = lit('int', 'decimal') number = type >= select_parser assert NumberParsers.number.parse('int 5') == Success(5) assert isinstance(NumberParsers.number.parse('int 2.0'), Failure)