use shuck_ast::{File, Span};
use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseStatus {
Clean,
Recovered,
Fatal,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ZshCaseGroupPart {
pub pattern_part_index: usize,
pub span: Span,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SyntaxFacts {
pub zsh_brace_if_spans: Vec<Span>,
pub zsh_always_spans: Vec<Span>,
pub zsh_case_group_parts: Vec<ZshCaseGroupPart>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseDiagnostic {
pub message: String,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct ParseResult {
pub file: File,
pub diagnostics: Vec<ParseDiagnostic>,
pub status: ParseStatus,
pub terminal_error: Option<Error>,
pub syntax_facts: SyntaxFacts,
}
impl ParseResult {
pub fn is_ok(&self) -> bool {
self.status == ParseStatus::Clean
}
pub fn is_err(&self) -> bool {
!self.is_ok()
}
pub fn strict_error(&self) -> Error {
self.terminal_error.clone().unwrap_or_else(|| {
let Some(diagnostic) = self.diagnostics.first() else {
panic!("non-clean parse result should include a diagnostic or terminal error");
};
Error::parse_at(
diagnostic.message.clone(),
diagnostic.span.start.line,
diagnostic.span.start.column,
)
})
}
pub fn unwrap(self) -> Self {
if self.is_ok() {
self
} else {
panic!(
"called `ParseResult::unwrap()` on a non-clean parse: {}",
self.strict_error()
)
}
}
pub fn expect(self, message: &str) -> Self {
if self.is_ok() {
self
} else {
panic!("{message}: {}", self.strict_error())
}
}
pub fn unwrap_err(self) -> Error {
if self.is_err() {
self.strict_error()
} else {
panic!("called `ParseResult::unwrap_err()` on a clean parse")
}
}
pub fn expect_err(self, message: &str) -> Error {
if self.is_err() {
self.strict_error()
} else {
panic!("{message}")
}
}
}