mirror of
https://codeberg.org/icewind/vdf-reader.git
synced 2026-06-03 18:14:07 +02:00
better errors for unmatched variants
This commit is contained in:
parent
d54e44b51d
commit
23bc240d4f
5 changed files with 84 additions and 8 deletions
63
src/error.rs
63
src/error.rs
|
|
@ -36,6 +36,10 @@ pub enum VdfError {
|
||||||
ParseString(#[from] ParseStringError),
|
ParseString(#[from] ParseStringError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
#[diagnostic(transparent)]
|
#[diagnostic(transparent)]
|
||||||
|
/// Failed to find an enum variant that matches the found tag
|
||||||
|
UnknownVariant(#[from] UnknownVariantError),
|
||||||
|
#[error(transparent)]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
/// Failed to parse serde string
|
/// Failed to parse serde string
|
||||||
SerdeParse(#[from] SerdeParseError),
|
SerdeParse(#[from] SerdeParseError),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
|
@ -73,14 +77,20 @@ impl VdfError {
|
||||||
..e
|
..e
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
VdfError::UnknownVariant(e) => UnknownVariantError {
|
||||||
|
src: source.into(),
|
||||||
|
err_span: span.into(),
|
||||||
|
..e
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExpectedTokens<'a>(&'a [Token]);
|
struct CommaSeperated<'a, T>(&'a [T]);
|
||||||
|
|
||||||
impl Display for ExpectedTokens<'_> {
|
impl<T: Display> Display for CommaSeperated<'_, T> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let mut tokens = self.0.iter();
|
let mut tokens = self.0.iter();
|
||||||
if let Some(token) = tokens.next() {
|
if let Some(token) = tokens.next() {
|
||||||
|
|
@ -101,7 +111,7 @@ impl Display for ExpectedTokens<'_> {
|
||||||
#[derive(Debug, Clone, Diagnostic)]
|
#[derive(Debug, Clone, Diagnostic)]
|
||||||
#[diagnostic(code(vmt_reader::unexpected_token))]
|
#[diagnostic(code(vmt_reader::unexpected_token))]
|
||||||
pub struct UnexpectedTokenError {
|
pub struct UnexpectedTokenError {
|
||||||
#[label("Expected {}", ExpectedTokens(self.expected))]
|
#[label("Expected {}", CommaSeperated(self.expected))]
|
||||||
err_span: SourceSpan,
|
err_span: SourceSpan,
|
||||||
pub expected: &'static [Token],
|
pub expected: &'static [Token],
|
||||||
pub found: Option<Token>,
|
pub found: Option<Token>,
|
||||||
|
|
@ -132,12 +142,12 @@ impl Display for UnexpectedTokenError {
|
||||||
f,
|
f,
|
||||||
"Unexpected token, found {} expected one of {}",
|
"Unexpected token, found {} expected one of {}",
|
||||||
token,
|
token,
|
||||||
ExpectedTokens(self.expected)
|
CommaSeperated(self.expected)
|
||||||
),
|
),
|
||||||
None => write!(
|
None => write!(
|
||||||
f,
|
f,
|
||||||
"Unexpected end of input expected one of {}",
|
"Unexpected end of input expected one of {}",
|
||||||
ExpectedTokens(self.expected)
|
CommaSeperated(self.expected)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,9 +158,9 @@ impl Error for UnexpectedTokenError {}
|
||||||
/// A token that wasn't expected was found while parsing
|
/// A token that wasn't expected was found while parsing
|
||||||
#[derive(Debug, Clone, Diagnostic, Error)]
|
#[derive(Debug, Clone, Diagnostic, Error)]
|
||||||
#[diagnostic(code(vmt_reader::no_valid_token))]
|
#[diagnostic(code(vmt_reader::no_valid_token))]
|
||||||
#[error("No valid token found, expected one of {}", ExpectedTokens(self.expected))]
|
#[error("No valid token found, expected one of {}", CommaSeperated(self.expected))]
|
||||||
pub struct NoValidTokenError {
|
pub struct NoValidTokenError {
|
||||||
#[label("Expected {}", ExpectedTokens(self.expected))]
|
#[label("Expected {}", CommaSeperated(self.expected))]
|
||||||
err_span: SourceSpan,
|
err_span: SourceSpan,
|
||||||
pub expected: &'static [Token],
|
pub expected: &'static [Token],
|
||||||
#[source_code]
|
#[source_code]
|
||||||
|
|
@ -282,6 +292,41 @@ impl SerdeParseError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[error("Unknown variant {variant:?} expected on of {}", ExpectedVariants(self.expected))]
|
||||||
|
#[diagnostic(code(vmt_parser::unknown_variant))]
|
||||||
|
pub struct UnknownVariantError {
|
||||||
|
variant: String,
|
||||||
|
expected: &'static [&'static str],
|
||||||
|
#[label("{}", ExpectedVariants(self.expected))]
|
||||||
|
err_span: SourceSpan,
|
||||||
|
#[source_code]
|
||||||
|
src: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ExpectedVariants(&'static [&'static str]);
|
||||||
|
|
||||||
|
impl Display for ExpectedVariants {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.0.is_empty() {
|
||||||
|
write!(f, "there are no variants")
|
||||||
|
} else {
|
||||||
|
write!(f, "expected on of {}", CommaSeperated(self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnknownVariantError {
|
||||||
|
pub fn new(variant: &str, expected: &'static [&'static str], span: Span, src: &str) -> Self {
|
||||||
|
UnknownVariantError {
|
||||||
|
variant: variant.into(),
|
||||||
|
expected,
|
||||||
|
err_span: span.into(),
|
||||||
|
src: src.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ExpectToken<'source> {
|
pub trait ExpectToken<'source> {
|
||||||
fn expect_token(
|
fn expect_token(
|
||||||
self,
|
self,
|
||||||
|
|
@ -342,4 +387,8 @@ impl serde::de::Error for VdfError {
|
||||||
{
|
{
|
||||||
VdfError::Other(msg.to_string())
|
VdfError::Other(msg.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
|
||||||
|
UnknownVariantError::new(variant, expected, 0..0, "").into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/serde.rs
10
src/serde.rs
|
|
@ -374,7 +374,15 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_enum(Enum::new(self))
|
let variant_token = self.peek().map(|r| r.ok()).flatten();
|
||||||
|
visitor
|
||||||
|
.visit_enum(Enum::new(self))
|
||||||
|
.map_err(|e| match (variant_token, &e) {
|
||||||
|
(Some(variant_token), VdfError::UnknownVariant(_)) => {
|
||||||
|
e.with_source_span(variant_token.span, self.source())
|
||||||
|
}
|
||||||
|
_ => e,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
|
||||||
|
|
|
||||||
4
tests/errors/unmatched.vdf
Normal file
4
tests/errors/unmatched.vdf
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
"Resource"
|
||||||
|
{
|
||||||
|
foo
|
||||||
|
}
|
||||||
|
|
@ -158,6 +158,7 @@ struct GameList {
|
||||||
#[test_case("tests/data/messy.vdf")]
|
#[test_case("tests/data/messy.vdf")]
|
||||||
#[test_case("tests/data/DialogConfigOverlay_1280x720.vdf")]
|
#[test_case("tests/data/DialogConfigOverlay_1280x720.vdf")]
|
||||||
#[test_case("tests/data/serde_array_type.vdf")]
|
#[test_case("tests/data/serde_array_type.vdf")]
|
||||||
|
#[test_case("tests/errors/unmatched.vdf")]
|
||||||
#[test_case("tests/errors/concrete.vmt")]
|
#[test_case("tests/errors/concrete.vmt")]
|
||||||
#[test_case("tests/errors/novalue.vdf")]
|
#[test_case("tests/errors/novalue.vdf")]
|
||||||
#[test_case("tests/errors/serde_array_type.vdf")]
|
#[test_case("tests/errors/serde_array_type.vdf")]
|
||||||
|
|
|
||||||
14
tests/snapshots/serde__tests__errors__unmatched.vdf.snap
Normal file
14
tests/snapshots/serde__tests__errors__unmatched.vdf.snap
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
source: tests/serde.rs
|
||||||
|
expression: out
|
||||||
|
---
|
||||||
|
vmt_parser::unknown_variant
|
||||||
|
|
||||||
|
× Unknown variant "Resource" expected on of expected on of Types, LightmappedGeneric, Resource/specificPanel.res, UserConfigData
|
||||||
|
╭─[1:1]
|
||||||
|
1 │ "Resource"
|
||||||
|
· ─────┬────
|
||||||
|
· ╰── expected on of Types, LightmappedGeneric, Resource/specificPanel.res, UserConfigData
|
||||||
|
2 │ {
|
||||||
|
╰────
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue