party
A simple parser combinator library. Party is stable, though breaking changes might come in a far-future 2.0 or 3.0 release.
Types
The custom error type for the parser,
which can itself be parameterized by a user-defined error type.
The user-defined error type is useful for, for example,
adding a int.parse
call into your parser pipeline.
See try
for using this feature.
pub type ParseError(e) {
Unexpected(pos: Position, error: String)
UserError(pos: Position, error: e)
}
Constructors
-
Unexpected(pos: Position, error: String)
-
UserError(pos: Position, error: e)
The parser type, parameterized by the type it parses and the user-defined error type it can return.
pub opaque type Parser(a, e)
Functions
pub fn all(ps: List(Parser(a, b))) -> Parser(a, b)
Do each parser in the list, returning the result of the last parser.
pub fn between(
open: Parser(a, b),
p: Parser(c, b),
close: Parser(d, b),
) -> Parser(c, b)
Parse open
, followed by p
and close
. Returns the value returned by p
.
The values returned by open
and close
are discarded.
pub fn choice(ps: List(Parser(a, b))) -> Parser(a, b)
Parse with the first parser in the list that doesn’t fail.
pub fn do(
p: Parser(a, b),
f: fn(a) -> Parser(c, b),
) -> Parser(c, b)
A monadic bind for pleasant interplay with gleam’s use
syntax.
example:
fn identifier() -> Parser(String, e) {
use pos <- do(pos())
use first <- do(lowercase_letter())
use rest <- do(many(either(alphanum(), char("_"))))
return(Ident(pos, first <> string.concat(rest)))
}
pub fn drop(
p: Parser(a, b),
f: fn() -> Parser(c, b),
) -> Parser(c, b)
A version of seq
for pleasant interplay with gleam’s use
syntax.
example:
fn pair() -> Parser(#(String, String), e) {
use a <- do(alphanum())
use <- drop(char(","))
use b <- do(alphanum())
return(#(a, b))
}
pub fn either(p: Parser(a, b), q: Parser(a, b)) -> Parser(a, b)
Parse the first parser, or the second if the first fails.
pub fn end() -> Parser(Nil, a)
Parses successfully only when at the end of the input string.
pub fn error_map(p: Parser(a, b), f: fn(b) -> c) -> Parser(a, c)
Transform the user-defined error type with a user-provided conversion function.
pub fn go(
p: Parser(a, b),
src: String,
) -> Result(a, ParseError(b))
Apply a parser to a string.
pub fn lazy(p: fn() -> Parser(a, b)) -> Parser(a, b)
Run a parser as normal, but the parser itself isn’t evaluated until it is used.
This is needed for recursive grammars, such as E := n | E + E
where n
is a number.
Example: lazy(digit)
instead of digit()
.
pub fn line() -> Parser(List(String), a)
Parse the rest of a line and return the array of parsed characters. The newline character at the end is discarded.
pub fn line_concat() -> Parser(String, a)
Parse the rest of a line and return the parsed characters as a String. The newline character at the end is discarded.
pub fn many(p: Parser(a, b)) -> Parser(List(a), b)
Keep trying the parser until it fails, and return the array of parsed results. This cannot fail because it parses zero or more times!
pub fn many1(p: Parser(a, b)) -> Parser(List(a), b)
Keep trying the parser until it fails, and return the array of parsed results. This can fail, because it must parse successfully at least once!
pub fn many1_concat(p: Parser(String, a)) -> Parser(String, a)
Parse a certain string as many times as possible, returning everything that was parsed. This can fail, because it must parse successfully at least once!
pub fn many_concat(p: Parser(String, a)) -> Parser(String, a)
Parse a certain string as many times as possible, returning everything that was parsed. This cannot fail because it parses zero or more times!
pub fn map(p: Parser(a, b), f: fn(a) -> c) -> Parser(c, b)
Do p
, then apply f
to the result if it succeeded.
pub fn not(p: Parser(a, b)) -> Parser(Nil, b)
Negate a parser: if it succeeds, this fails, and vice versa.
Example: seq(string("if"), not(either(alphanum(), char("_"))))
pub fn perhaps(p: Parser(a, b)) -> Parser(Result(a, Nil), b)
Try running a parser, but still succeed (with Error(Nil)
) if it failed.
pub fn return(x: a) -> Parser(a, b)
A monadic return for pleasant interplay with gleam’s use
syntax.
see do
for more details and an example.
This is redundant if the last do
is a map
instead.
But I prefer using it, stylistically.
pub fn run(
p: Parser(a, b),
src: List(String),
pos: Position,
) -> Result(#(a, List(String), Position), ParseError(b))
ADVANCED (exposes the internals of party
)
Apply a parser to a list of graphemes (holding on to extra result info that party
typically threads for you).
pub fn satisfy(
when pred: fn(String) -> Bool,
) -> Parser(String, a)
Parse a character if it matches the predicate.
pub fn sep(
parser: Parser(a, b),
by s: Parser(c, b),
) -> Parser(List(a), b)
Parse a sequence separated by the given separator parser.
pub fn sep1(
parser: Parser(a, b),
by s: Parser(c, b),
) -> Parser(List(a), b)
Parse a sequence separated by the given separator parser. This only succeeds if at least one element of the sequence was parsed.
pub fn seq(p: Parser(a, b), q: Parser(c, b)) -> Parser(c, b)
Do the first parser, ignore its result, then do the second parser.
pub fn stateful_many(
state: a,
p: Parser(fn(a) -> #(b, a), c),
) -> Parser(#(List(b), a), c)
A many
parser that also gets to update some state with each success
pub fn stateful_many1(
state: a,
p: Parser(fn(a) -> #(b, a), c),
) -> Parser(#(List(b), a), c)
A many1
parser that also gets to update some state with each success
pub fn try(
p: Parser(a, b),
f: fn(a) -> Result(c, b),
) -> Parser(c, b)
Do p
, the apply f
to the result if it succeeded.
f
itself can fail with the user-defined error type,
and if it does the result is a UserError
with the error.
pub fn until(
do p: Parser(a, b),
until terminator: Parser(c, b),
) -> Parser(List(a), b)
Parse zero or more repetitions of a parser, collecting the results into a list.
Stop when the terminator parser succeeds, even if the looping parser would also succeed.
The terminator parser’s results are consumed and discarded.
The main motivator for until
is multiline comments ending in */
, -->
, -}
, *)
, etc.