use core::convert::From;
use std::fmt::Display;
use std::iter::IntoIterator;
use crate::errors::{ErrorDetails, Severity};
use crate::lexer::TokenStream;
#[derive(Debug, Clone, Default)]
pub struct Diagnostics<'a> {
pub errors: Vec<ErrorDetails<'a>>,
pub warnings: Vec<ErrorDetails<'a>>,
}
impl<'a> Diagnostics<'a> {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn from_details(details: Vec<ErrorDetails<'a>>) -> Self {
let mut diagnostics = Self::new();
for detail in details {
match detail.severity {
Severity::Error => diagnostics.errors.push(detail),
Severity::Warning | Severity::Note => diagnostics.warnings.push(detail),
}
}
diagnostics
}
#[must_use]
pub fn has_errors(&self) -> bool {
!self.errors.is_empty()
}
#[must_use]
pub fn has_warnings(&self) -> bool {
!self.warnings.is_empty()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.errors.is_empty() && self.warnings.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.errors.len() + self.warnings.len()
}
pub fn iter(&self) -> impl Iterator<Item = &ErrorDetails<'a>> {
self.errors.iter().chain(self.warnings.iter())
}
pub fn errors_iter(&self) -> impl Iterator<Item = &ErrorDetails<'a>> {
self.errors.iter()
}
pub fn warnings_iter(&self) -> impl Iterator<Item = &ErrorDetails<'a>> {
self.warnings.iter()
}
pub fn push_error(&mut self, error: ErrorDetails<'a>) {
self.errors.push(error);
}
pub fn push_warning(&mut self, warning: ErrorDetails<'a>) {
self.warnings.push(warning);
}
pub fn push(&mut self, detail: ErrorDetails<'a>) {
match detail.severity {
Severity::Error => self.errors.push(detail),
Severity::Warning | Severity::Note => self.warnings.push(detail),
}
}
pub fn merge(&mut self, other: Diagnostics<'a>) {
self.errors.extend(other.errors);
self.warnings.extend(other.warnings);
}
}
#[derive(Debug, Clone)]
pub struct ParseResult<'a, T> {
result: Option<T>,
failures: Vec<ErrorDetails<'a>>,
}
impl<'a, T> From<ParseResult<'a, T>> for (Option<T>, Vec<ErrorDetails<'a>>) {
fn from(pr: ParseResult<'a, T>) -> Self {
(pr.result, pr.failures)
}
}
impl<T> Display for ParseResult<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.result {
Some(_) => write!(
f,
"ParseResult: Has result, Failures = {}",
self.failures.len()
),
None => write!(
f,
"ParseResult: No Result, Failures = {}",
self.failures.len()
),
}
}
}
impl<'a, T> ParseResult<'a, T> {
#[inline]
pub const fn has_result(&self) -> bool {
self.result.is_some()
}
pub fn new(result: Option<T>, failures: Vec<ErrorDetails<'a>>) -> Self {
Self { result, failures }
}
#[inline]
pub fn failures(&self) -> impl Iterator<Item = &ErrorDetails<'a>> {
self.failures.iter()
}
#[inline]
pub fn into_failures(self) -> impl Iterator<Item = ErrorDetails<'a>> {
self.failures.into_iter()
}
#[inline]
pub const fn has_failures(&self) -> bool {
!matches!(self.failures.len(), 0)
}
#[inline]
pub fn push_failure(&mut self, failure: ErrorDetails<'a>) {
self.failures.push(failure);
}
#[inline]
pub fn append_failures(&mut self, failures: &mut Vec<ErrorDetails<'a>>) {
self.failures.append(failures);
}
#[inline]
pub fn unwrap(self) -> T {
self.result
.expect("Attempted to unwrap a ParseResult that did not have a result.")
}
pub fn unpack(self) -> (Option<T>, Vec<ErrorDetails<'a>>) {
(self.result, self.failures)
}
pub fn unpack_with_severity(self) -> (Option<T>, Vec<ErrorDetails<'a>>, Vec<ErrorDetails<'a>>) {
let diagnostics = Diagnostics::from_details(self.failures);
(self.result, diagnostics.errors, diagnostics.warnings)
}
pub fn diagnostics(&self) -> Diagnostics<'a> {
Diagnostics::from_details(self.failures.clone())
}
pub fn errors(&self) -> Vec<&ErrorDetails<'a>> {
self.failures
.iter()
.filter(|f| f.severity == Severity::Error)
.collect()
}
pub fn warnings(&self) -> Vec<&ErrorDetails<'a>> {
self.failures
.iter()
.filter(|f| matches!(f.severity, Severity::Warning | Severity::Note))
.collect()
}
pub fn all_diagnostics(&self) -> impl Iterator<Item = &ErrorDetails<'a>> {
self.errors().into_iter().chain(self.warnings())
}
#[inline]
pub fn unwrap_or_fail(self) -> T {
if self.has_failures() {
for failure in &self.failures {
failure.eprint();
}
panic!(
"Parsing had {} failure(s). See errors above.",
self.failures.len()
);
}
self.result
.expect("Attempted to unwrap a ParseResult that did not have a result.")
}
pub fn ok_or_errors(self) -> Result<T, Vec<ErrorDetails<'a>>> {
if self.has_failures() {
Err(self.failures)
} else {
self.result.ok_or(self.failures)
}
}
pub fn map<U, F>(self, f: F) -> ParseResult<'a, U>
where
F: FnOnce(T) -> U,
{
ParseResult {
result: self.result.map(f),
failures: self.failures,
}
}
pub fn and_then<U, F>(self, f: F) -> ParseResult<'a, U>
where
F: FnOnce(T) -> ParseResult<'a, U>,
{
match self.result {
Some(value) => {
let mut next_result = f(value);
next_result.failures.extend(self.failures);
next_result
}
None => ParseResult {
result: None,
failures: self.failures,
},
}
}
pub fn into_result(self) -> Result<T, Diagnostics<'a>> {
match self.result {
None => Err(Diagnostics::from_details(self.failures)),
Some(t) => Ok(t),
}
}
}
impl<'a, T> From<(T, ErrorDetails<'a>)> for ParseResult<'a, T> {
fn from(parse_pair: (T, ErrorDetails<'a>)) -> ParseResult<'a, T> {
ParseResult {
result: Some(parse_pair.0),
failures: vec![parse_pair.1],
}
}
}
impl<'a, I, T> From<(I, Vec<ErrorDetails<'a>>)> for ParseResult<'a, Vec<T>>
where
I: IntoIterator<Item = T>,
{
fn from(parse_pair: (I, Vec<ErrorDetails<'a>>)) -> ParseResult<'a, Vec<T>> {
let collection: Vec<T> = parse_pair.0.into_iter().collect();
if collection.is_empty() {
return ParseResult {
result: None,
failures: parse_pair.1,
};
}
ParseResult {
result: Some(collection),
failures: parse_pair.1,
}
}
}
impl<'a> From<(TokenStream<'a>, Vec<ErrorDetails<'a>>)> for ParseResult<'a, TokenStream<'a>> {
fn from(
parse_pair: (TokenStream<'a>, Vec<ErrorDetails<'a>>),
) -> ParseResult<'a, TokenStream<'a>> {
ParseResult {
result: Some(parse_pair.0),
failures: parse_pair.1,
}
}
}