///|
/// String-specific parser combinators and type aliases.
///
/// Provides `StringParser`, `CParser`, `SParser` type aliases and the
/// `many_chars` / `many_chars1` helpers that collect character-level
/// results into `String` values.
///|
/// Convenience alias for `Parser[Input, T]`, used for string-input parsers.
pub type StringParser[T] = Parser[Input, T]
///|
pub type CParser = StringParser[Char]
///|
pub type SParser = StringParser[String]
///|
/// Maps a `char` parser's result to a `String` before applying `f`.
#inline
pub fn[U, E] ParserRaw::string_map(
self : ParserRaw[Input, Char, E],
f : (String) -> U,
) -> ParserRaw[Input, U, E] {
self.map(value => f(value.to_string()))
}
///|
/// Zero or more repetitions of a char parser, collecting results
/// into a `String`.
///
/// Unlike `take_while`, succeeds on zero matches (returns empty string).
#inline
pub fn[E : Commit + ParseFailure] many_chars(
parser : ParserRaw[Input, Char, E],
) -> ParserRaw[Input, String, E] {
ParserRaw::new(input => {
let chars = StringBuilder()
for rest = input {
match parser.run(rest) {
Ok((ch, next)) => {
guard !next.same_cursor(rest) else {
break Err(
ParseFailure::message(rest, "many parser accepted empty input"),
)
}
chars.write_char(ch)
continue next
}
Err(error) =>
break Commit::reject_if_committed(error, chars, rest).map(result => {
let (chars, rest) = result
(chars.to_string(), rest)
})
}
}
})
}
///|
/// One or more repetitions of a char parser, collecting results
/// into a `String`.
///
/// Fails on zero matches.
#inline
pub fn[E : Commit + ParseFailure] many_chars1(
parser : ParserRaw[Input, Char, E],
) -> ParserRaw[Input, String, E] {
ParserRaw::new(input => {
let (head, rest) = match parser.run(input) {
Ok(result) => result
Err(error) => return Err(error)
}
let chars = StringBuilder()
chars.write_char(head)
for rest = rest {
match parser.run(rest) {
Ok((ch, next)) => {
guard !next.same_cursor(rest) else {
break Err(
ParseFailure::message(rest, "many parser accepted empty input"),
)
}
chars.write_char(ch)
continue next
}
Err(error) =>
break Commit::reject_if_committed(error, chars, rest).map(result => {
let (chars, rest) = result
(chars.to_string(), rest)
})
}
}
})
}