///|
pub fn Parser::satisfy(f : (Char) -> Bool, label~ : String) -> Parser[Char] {
fn(input) {
let { chars, row, col } = input
match chars {
[x, .. chars] if f(x) =>
if x == '\n' {
(x, Input::{ chars, row: row + 1, col: 0 })
} else {
(x, Input::{ ..input, chars, col: col + 1 })
}
_ => raise expect(row~, col~, label)
}
}
}
///|
pub fn Parser::char(ch : Char) -> Parser[Char] {
satisfy(c => c == ch, label=ch.to_string())
}
///|
pub fn Parser::one_of(xs : String) -> Parser[Char] {
satisfy(String::contains_char(xs, _), label="one of \{xs.iter()}}")
}
///|
pub fn Parser::none_of(xs : String) -> Parser[Char] {
satisfy(
ch => not(String::contains_char(xs, ch)),
label="none of \{xs.iter()}}",
)
}
///|
pub fn Parser::string(str : String) -> Parser[String] {
fn(input) {
guard not(str.contains_char('\n')) else { panic() }
let { chars, row, col } = input
let len = str.length()
guard chars.length() >= len && chars.view(end_offset=len) == str else {
raise expect(row~, col~, str)
}
(
str,
Input::{ ..input, chars: chars.view(start_offset=len), col: col + len },
)
}
}
///|
pub fn[A] Parser::eof(x : A) -> Parser[A] {
fn(input) {
let { chars, row, col } = input
match chars {
[] => (x, input)
_ => raise expect(row~, col~, "eof")
}
}
}