Skip to content

Commit

Permalink
Move diagnostic functions into the miette module.
Browse files Browse the repository at this point in the history
This change moves `Glob` functions enabled by the `miette` feature into
the `miette` module (much like functions enabled by the `walk` feature).
  • Loading branch information
olson-sean-k committed Nov 25, 2023
1 parent 95d9bb3 commit a7a02f6
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 75 deletions.
72 changes: 69 additions & 3 deletions src/diagnostics/miette.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,67 @@
#![cfg(feature = "miette")]
#![cfg_attr(docsrs, doc(cfg(feature = "miette")))]

use miette::{Diagnostic, SourceSpan};
use std::borrow::Cow;
use tardar::BoxedDiagnostic;
use tardar::{
BoxedDiagnostic, DiagnosticResult, DiagnosticResultExt as _, IteratorExt as _, ResultExt as _,
};
use thiserror::Error;

use crate::diagnostics::SpanExt as _;
use crate::rule::{self, Checked};
use crate::token::{self, TokenKind, TokenTree, Tokenized};
use crate::Glob;

/// APIs for diagnosing globs.
impl<'t> Glob<'t> {
/// Constructs a [`Glob`] from a glob expression with diagnostics.
///
/// This function is the same as [`Glob::new`], but additionally returns detailed diagnostics
/// on both success and failure.
///
/// See [`Glob::diagnose`].
///
/// # Examples
///
/// ```rust
/// use tardar::DiagnosticResultExt as _;
/// use wax::Glob;
///
/// let result = Glob::diagnosed("(?i)readme.{md,mkd,markdown}");
/// for diagnostic in result.diagnostics() {
/// eprintln!("{}", diagnostic);
/// }
/// if let Some(glob) = result.ok_output() { /* ... */ }
/// ```
///
/// [`Glob`]: crate::Glob
/// [`Glob::diagnose`]: crate::Glob::diagnose
/// [`Glob::new`]: crate::Glob::new
pub fn diagnosed(expression: &'t str) -> DiagnosticResult<'t, Self> {
parse_and_diagnose(expression).and_then_diagnose(|tree| {
Glob::compile(tree.as_ref().tokens())
.into_error_diagnostic()
.map_output(|program| Glob { tree, program })
})
}

/// Gets **non-error** [`Diagnostic`]s.
///
/// This function requires a receiving [`Glob`] and so does not report error-level
/// [`Diagnostic`]s. It can be used to get non-error diagnostics after constructing or
/// [partitioning][`Glob::partition`] a [`Glob`].
///
/// See [`Glob::diagnosed`].
///
/// [`Diagnostic`]: miette::Diagnostic
/// [`Glob`]: crate::Glob
/// [`Glob::diagnosed`]: crate::Glob::diagnosed
/// [`Glob::partition`]: crate::Glob::partition
pub fn diagnose(&self) -> impl Iterator<Item = Box<dyn Diagnostic + '_>> {
diagnose(self.tree.as_ref())
}
}

#[derive(Clone, Debug, Diagnostic, Error)]
#[diagnostic(code(wax::glob::semantic_literal), severity(warning))]
Expand All @@ -29,7 +84,19 @@ pub struct TerminatingSeparatorWarning<'t> {
span: SourceSpan,
}

pub fn diagnose<'i, 't>(
fn parse_and_diagnose(expression: &str) -> DiagnosticResult<Checked<Tokenized>> {
token::parse(expression)
.into_error_diagnostic()
.and_then_diagnose(|tokenized| rule::check(tokenized).into_error_diagnostic())
.and_then_diagnose(|checked| {
// TODO: This should accept `&Checked`.
diagnose(checked.as_ref())
.into_non_error_diagnostic()
.map_output(|_| checked)
})
}

fn diagnose<'i, 't>(
tokenized: &'i Tokenized<'t>,
) -> impl 'i + Iterator<Item = BoxedDiagnostic<'t>> {
None.into_iter()
Expand Down Expand Up @@ -65,7 +132,6 @@ pub fn diagnose<'i, 't>(
)
}

// These tests exercise `Glob` APIs, which wrap functions in this module.
#[cfg(test)]
mod tests {
use crate::Glob;
Expand Down
3 changes: 0 additions & 3 deletions src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ use ::miette::LabeledSpan;
use std::cmp;
use std::fmt::{self, Display, Formatter};

#[cfg(feature = "miette")]
pub use crate::diagnostics::miette::diagnose;

/// Location and length of a token within a glob expression.
///
/// Spans are encoded as a tuple of `usize`s, where the first element is the location or position
Expand Down
69 changes: 0 additions & 69 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ use std::ffi::OsStr;
use std::fmt::{self, Debug, Display, Formatter};
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
#[cfg(feature = "miette")]
use tardar::{DiagnosticResult, DiagnosticResultExt as _, IteratorExt as _, ResultExt as _};
use thiserror::Error;

use crate::encode::CompileError;
Expand Down Expand Up @@ -743,60 +741,6 @@ impl<'t> Glob<'t> {
}
}

/// APIs for diagnosing globs.
#[cfg(feature = "miette")]
#[cfg_attr(docsrs, doc(cfg(feature = "miette")))]
impl<'t> Glob<'t> {
/// Constructs a [`Glob`] from a glob expression with diagnostics.
///
/// This function is the same as [`Glob::new`], but additionally returns detailed diagnostics
/// on both success and failure.
///
/// See [`Glob::diagnose`].
///
/// # Examples
///
/// ```rust
/// use tardar::DiagnosticResultExt as _;
/// use wax::Glob;
///
/// let result = Glob::diagnosed("(?i)readme.{md,mkd,markdown}");
/// for diagnostic in result.diagnostics() {
/// eprintln!("{}", diagnostic);
/// }
/// if let Some(glob) = result.ok_output() { /* ... */ }
/// ```
///
/// [`Glob`]: crate::Glob
/// [`Glob::diagnose`]: crate::Glob::diagnose
/// [`Glob::new`]: crate::Glob::new
#[cfg(feature = "miette")]
#[cfg_attr(docsrs, doc(cfg(feature = "miette")))]
pub fn diagnosed(expression: &'t str) -> DiagnosticResult<'t, Self> {
parse_and_diagnose(expression).and_then_diagnose(|tree| {
Glob::compile(tree.as_ref().tokens())
.into_error_diagnostic()
.map_output(|program| Glob { tree, program })
})
}

/// Gets **non-error** [`Diagnostic`]s.
///
/// This function requires a receiving [`Glob`] and so does not report error-level
/// [`Diagnostic`]s. It can be used to get non-error diagnostics after constructing or
/// [partitioning][`Glob::partition`] a [`Glob`].
///
/// See [`Glob::diagnosed`].
///
/// [`Diagnostic`]: miette::Diagnostic
/// [`Glob`]: crate::Glob
/// [`Glob::diagnosed`]: crate::Glob::diagnosed
/// [`Glob::partition`]: crate::Glob::partition
pub fn diagnose(&self) -> impl Iterator<Item = Box<dyn Diagnostic + '_>> {
diagnostics::diagnose(self.tree.as_ref())
}
}

impl Display for Glob<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.tree.as_ref().expression())
Expand Down Expand Up @@ -1063,19 +1007,6 @@ fn parse_and_check(expression: &str) -> Result<Checked<Tokenized>, BuildError> {
Ok(checked)
}

#[cfg(feature = "miette")]
fn parse_and_diagnose(expression: &str) -> DiagnosticResult<Checked<Tokenized>> {
token::parse(expression)
.into_error_diagnostic()
.and_then_diagnose(|tokenized| rule::check(tokenized).into_error_diagnostic())
.and_then_diagnose(|checked| {
// TODO: This should accept `&Checked`.
diagnostics::diagnose(checked.as_ref())
.into_non_error_diagnostic()
.map_output(|_| checked)
})
}

// TODO: Construct paths from components in tests. In practice, using string literals works, but is
// technically specific to platforms that support `/` as a separator.
#[cfg(test)]
Expand Down

0 comments on commit a7a02f6

Please sign in to comment.