use crate::reader::Reader;
pub trait ParseError {
fn is_recoverable(&self) -> bool;
fn to_recoverable(self) -> Self;
fn to_non_recoverable(self) -> Self;
}
pub type ParseFunc<T, E> = fn(&mut Reader) -> Result<T, E>;
pub fn optional<T, E>(f: ParseFunc<T, E>, reader: &mut Reader) -> Result<Option<T>, E>
where
E: ParseError,
{
let start = reader.cursor();
match f(reader) {
Ok(r) => Ok(Some(r)),
Err(e) => {
if e.is_recoverable() {
reader.seek(start);
Ok(None)
} else {
Err(e)
}
}
}
}
pub fn recover<T, E>(f: ParseFunc<T, E>, reader: &mut Reader) -> Result<T, E>
where
E: ParseError,
{
match f(reader) {
Ok(r) => Ok(r),
Err(e) => Err(e.to_recoverable()),
}
}
pub fn non_recover<T, E>(f: ParseFunc<T, E>, reader: &mut Reader) -> Result<T, E>
where
E: ParseError,
{
match f(reader) {
Ok(r) => Ok(r),
Err(e) => Err(e.to_non_recoverable()),
}
}
pub fn zero_or_more<T, E>(f: ParseFunc<T, E>, reader: &mut Reader) -> Result<Vec<T>, E>
where
E: ParseError,
{
let mut v = Vec::new();
loop {
let initial_state = reader.cursor();
if reader.is_eof() {
return Ok(v);
}
match f(reader) {
Ok(r) => {
v.push(r);
}
Err(e) => {
return if e.is_recoverable() {
reader.seek(initial_state);
Ok(v)
} else {
Err(e)
};
}
}
}
}
pub fn one_or_more<T, E>(f: ParseFunc<T, E>, reader: &mut Reader) -> Result<Vec<T>, E>
where
E: ParseError,
{
match f(reader) {
Ok(first) => {
let mut v = vec![first];
loop {
let initial_state = reader.cursor();
match f(reader) {
Ok(r) => {
v.push(r);
}
Err(e) => {
return if e.is_recoverable() {
reader.seek(initial_state);
Ok(v)
} else {
Err(e)
};
}
}
}
}
Err(e) => Err(e.to_non_recoverable()),
}
}
pub fn choice<T, E>(fs: &[ParseFunc<T, E>], reader: &mut Reader) -> Result<T, E>
where
E: ParseError,
{
for (pos, f) in fs.iter().enumerate() {
let start = reader.cursor();
if pos == fs.len() - 1 {
return f(reader);
}
match f(reader) {
Err(err) if err.is_recoverable() => {
reader.seek(start);
continue;
}
x => return x,
}
}
unreachable!("You can't call choice with an empty vector of choice")
}