// Error types and formatting for parse failures
///|
pub(all) struct ParseError {
message : String
input : ParseInput
}
///|
pub fn ParseError::new(msg : String, input : ParseInput) -> ParseError {
ParseError::{ message: msg, input }
}
///|
pub fn ParseError::format(self : ParseError) -> String {
"Parse error at " + self.input.position() + ": " + self.message
}
// Error context — accumulate multiple expectations
///|
pub(all) struct ErrorContext {
expected : Array[String]
errors : Array[ParseError]
}
///|
pub fn ErrorContext::new() -> ErrorContext {
ErrorContext::{ expected: [], errors: [] }
}
///|
pub fn ErrorContext::add_expected(
self : ErrorContext,
label : String,
) -> ErrorContext {
let new_exp = self.expected
new_exp.push(label)
ErrorContext::{ ..self, expected: new_exp }
}
///|
pub fn ErrorContext::add_error(
self : ErrorContext,
err : ParseError,
) -> ErrorContext {
let new_errs = self.errors
new_errs.push(err)
ErrorContext::{ ..self, errors: new_errs }
}
///|
pub fn ErrorContext::format(self : ErrorContext) -> String {
let result = "expected: " + format_expected(self.expected, 0, "")
if self.errors.length() > 0 {
result + " | " + format_errors(self.errors, 0, "")
} else {
result
}
}
///|
fn format_expected(
expected : Array[String],
idx : Int,
result : String,
) -> String {
if idx >= expected.length() {
result
} else {
let sep = if idx > 0 { ", " } else { "" }
format_expected(expected, idx + 1, result + sep + expected[idx])
}
}
///|
fn format_errors(
errors : Array[ParseError],
idx : Int,
result : String,
) -> String {
if idx >= errors.length() {
result
} else {
let sep = if idx > 0 { "; " } else { "" }
format_errors(errors, idx + 1, result + sep + errors[idx].message)
}
}