///|
pub(all) enum ParseError {
UnexpectedEnd(offset~ : Int)
Expected(label~ : String, offset~ : Int)
ExpectedAny(labels~ : Array[String], offset~ : Int)
EmptyMatchInMany(offset~ : Int)
EmptyChoice(offset~ : Int)
UnboundReference(offset~ : Int)
NotFollowedBy(label~ : String, offset~ : Int)
Context(label~ : String, cause~ : ParseError)
}
///|
pub fn ParseError::offset(self : ParseError) -> Int {
match self {
UnexpectedEnd(offset~) => offset
Expected(offset~, ..) => offset
ExpectedAny(offset~, ..) => offset
EmptyMatchInMany(offset~) => offset
EmptyChoice(offset~) => offset
UnboundReference(offset~) => offset
NotFollowedBy(offset~, ..) => offset
Context(cause~, ..) => cause.offset()
}
}
///|
fn append_unique_label(labels : Array[String], label : String) -> Array[String] {
let merged = labels.copy()
if !merged.contains(label) {
merged.push(label)
}
merged
}
///|
fn ParseError::merge_at_same_offset(
self : ParseError,
other : ParseError,
) -> ParseError {
match (self, other) {
(Expected(label=left, offset~), Expected(label=right, ..)) =>
if left == right {
self
} else {
ExpectedAny(labels=[left, right], offset~)
}
(ExpectedAny(labels=left, offset~), Expected(label=right, ..)) =>
ExpectedAny(labels=append_unique_label(left, right), offset~)
(Expected(label=left, offset~), ExpectedAny(labels=right, ..)) =>
ExpectedAny(labels=append_unique_label(right, left), offset~)
(ExpectedAny(labels=left, offset~), ExpectedAny(labels=right, ..)) => {
let merged = left.copy()
for label in right {
if !merged.contains(label) {
merged.push(label)
}
}
ExpectedAny(labels=merged, offset~)
}
_ => other
}
}
///|
fn ParseError::furthest(self : ParseError, other : ParseError) -> ParseError {
if self.offset() > other.offset() {
self
} else if self.offset() < other.offset() {
other
} else {
self.merge_at_same_offset(other)
}
}
///|
pub struct State[T] {
priv input : Array[T]
priv offset : Int
}
///|
pub fn[T] State::new(input : Array[T]) -> State[T] {
{ input, offset: 0 }
}
///|
pub fn[T] State::offset(self : State[T]) -> Int {
self.offset
}
///|
pub fn[T] State::is_at_end(self : State[T]) -> Bool {
self.offset == self.input.length()
}
///|
fn[T] State::next(self : State[T]) -> (T, State[T])? {
match self.input.get(self.offset) {
Some(token) => Some((token, { input: self.input, offset: self.offset + 1 }))
None => None
}
}
///|
pub struct Parser[T, A] {
priv execute : (State[T]) -> Reply[T, A]
}
///|
enum Reply[T, A] {
Success(A, State[T], Bool, Bool)
Failure(ParseError, Bool, Bool)
}
///|
fn[T, A] Reply::to_result(
self : Reply[T, A],
) -> Result[(A, State[T]), ParseError] {
match self {
Success(value, state, _, _) => Ok((value, state))
Failure(error, _, _) => Err(error)
}
}
///|
fn[T, A] Reply::with_prefix(
self : Reply[T, A],
consumed : Bool,
committed : Bool,
) -> Reply[T, A] {
match self {
Success(value, state, next_consumed, next_committed) =>
Success(
value,
state,
consumed || next_consumed,
committed || next_committed,
)
Failure(error, next_consumed, next_committed) =>
Failure(error, consumed || next_consumed, committed || next_committed)
}
}