Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
adds a simple error type to allow producing nicer errors
Browse files Browse the repository at this point in the history
  • Loading branch information
kritzcreek committed Jul 1, 2024
1 parent 1e1bc02 commit 1a1ee75
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::borrow::Cow;

mod context_error;
mod format;
mod parse;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use std::fmt;

use nom::error::{ContextError, ErrorKind, FromExternalError, ParseError};

/// default error type, only contains the error's location and code
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CtxError<I> {
/// position of the error in the input data
pub input: I,
/// contextual error message
pub context: &'static str,
}

impl<I> ParseError<I> for CtxError<I> {
fn from_error_kind(input: I, _kind: ErrorKind) -> Self {
CtxError {
input,
context: "no context set yet",
}
}

fn append(_: I, _: ErrorKind, other: Self) -> Self {
other
}
}

impl<I> ContextError<I> for CtxError<I> {
fn add_context(_input: I, context: &'static str, mut other: Self) -> Self {
other.context = context;
other
}
}

impl<I, E> FromExternalError<I, E> for CtxError<I> {
/// Create a new error from an input position and an external error
fn from_external_error(input: I, _kind: ErrorKind, _e: E) -> Self {
CtxError {
input,
context: "no context set yet",
}
}
}

/// The Display implementation allows the std::error::Error implementation
impl<I: fmt::Display> fmt::Display for CtxError<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "error '{}' at: {}", self.context, self.input)
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
use std::borrow::Cow;
use std::{borrow::Cow, str};

use nom::{
branch::alt,
bytes::complete::{tag, take_while1},
character::complete::char,
combinator::{cut, eof, fail, opt},
error::{context, convert_error, VerboseError},
combinator::{cut, eof, fail, opt, verify},
error::context,
multi::many1,
sequence::{delimited, preceded, tuple},
Finish, IResult, Parser,
};

use super::{Descriptor, NonLocalSymbol, Package, Scheme, Symbol};
use super::{context_error::CtxError, Descriptor, NonLocalSymbol, Package, Scheme, Symbol};

pub(super) fn parse_symbol(input: &str) -> Result<Symbol<'_>, String> {
match parse_symbol_inner(input).finish() {
Ok((_, symbol)) => Ok(symbol),
Err(err) => Err(format!(
"Invalid symbol: '{input}'\n{}",
convert_error(input, err)
)),
Err(err) => Err(format!("Invalid symbol: '{input}'\n{err}",)),
}
}

type PResult<'a, A> = IResult<&'a str, A, VerboseError<&'a str>>;
type PResult<'a, A> = IResult<&'a str, A, CtxError<&'a str>>;

fn parse_symbol_inner(input: &str) -> PResult<'_, Symbol<'_>> {
let (input, symbol) = alt((parse_local_symbol, parse_nonlocal_symbol))(input)?;
Expand All @@ -38,26 +35,33 @@ fn parse_local_symbol(input: &str) -> PResult<'_, Symbol<'_>> {
}

fn parse_nonlocal_symbol(input: &str) -> PResult<'_, Symbol<'_>> {
tuple((
parse_space_terminated,
parse_package,
many1(parse_descriptor),
))
.map(|(scheme, package, descriptors)| {
Symbol::NonLocal(NonLocalSymbol {
scheme: Scheme(scheme),
package,
descriptors,
tuple((parse_scheme, parse_package, many1(parse_descriptor)))
.map(|(scheme, package, descriptors)| {
Symbol::NonLocal(NonLocalSymbol {
scheme,
package,
descriptors,
})
})
})
.parse(input)
}

fn parse_scheme(input: &str) -> PResult<'_, Scheme> {
context(
"Invalid scheme",
verify(parse_space_terminated, |s: &Cow<'_, str>| {
!s.starts_with("local")
}),
)
.map(Scheme)
.parse(input)
}

fn parse_package(input: &str) -> PResult<'_, Package> {
tuple((
parse_space_terminated,
parse_space_terminated,
parse_space_terminated,
context("Invalid package manager", parse_space_terminated),
context("Invalid package name", parse_space_terminated),
context("Invalid package version", parse_space_terminated),
))
.map(|(manager, package_name, version)| Package {
manager,
Expand Down

0 comments on commit 1a1ee75

Please sign in to comment.