parse string error

This commit is contained in:
Robin Appelman 2023-12-18 01:58:41 +01:00
commit f75a64204c
4 changed files with 55 additions and 34 deletions

View file

@ -34,6 +34,10 @@ pub enum VdfError {
#[diagnostic(transparent)]
/// Failed to parse string into type
ParseString(#[from] ParseStringError),
#[error(transparent)]
#[diagnostic(transparent)]
/// Failed to parse serde string
SerdeParse(#[from] SerdeParseError),
#[error("{0}")]
Other(String),
}
@ -173,7 +177,7 @@ impl WrongEventTypeError {
#[derive(Debug, Clone, Error, Diagnostic)]
#[error("Can't parse entry {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::eof))]
#[diagnostic(code(vmt_parser::parse_value))]
pub struct ParseEntryError {
pub ty: &'static str,
pub value: Entry,
@ -187,7 +191,7 @@ impl ParseEntryError {
#[derive(Debug, Clone, Error, Diagnostic)]
#[error("Can't parse entry {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::eof))]
#[diagnostic(code(vmt_parser::parse_item))]
pub struct ParseItemError {
pub ty: &'static str,
pub value: Item<'static>,
@ -203,8 +207,8 @@ impl ParseItemError {
}
#[derive(Debug, Clone, Error, Diagnostic)]
#[error("Can't parse entry {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::eof))]
#[error("Can't parse string {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::parse_string))]
pub struct ParseStringError {
pub ty: &'static str,
pub value: String,
@ -219,6 +223,29 @@ impl ParseStringError {
}
}
#[derive(Debug, Clone, Error, Diagnostic)]
#[error("Can't parse {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::parse_serde))]
pub struct SerdeParseError {
pub ty: &'static str,
pub value: String,
#[label("Expected a {ty}")]
err_span: SourceSpan,
#[source_code]
src: String,
}
impl SerdeParseError {
pub fn new(ty: &'static str, value: &str, span: Span, src: &str) -> Self {
SerdeParseError {
ty,
value: value.into(),
err_span: span.into(),
src: src.into(),
}
}
}
pub trait ExpectToken<'source> {
fn expect_token(
self,

View file

@ -8,7 +8,6 @@ use std::borrow::Cow;
pub struct Reader<'a> {
pub source: &'a str,
lexer: SpannedIter<'a, Token>,
peeked: Option<(Result<Token, <Token as Logos<'a>>::Error>, Span)>,
}
impl<'a> From<&'a str> for Reader<'a> {
@ -16,26 +15,14 @@ impl<'a> From<&'a str> for Reader<'a> {
Reader {
source: content,
lexer: Lexer::new(content).spanned(),
peeked: None,
}
}
}
impl<'a> Reader<'a> {
fn token(&mut self) -> Option<(Result<Token, <Token as Logos>::Error>, Span)> {
if let Some((token, span)) = self.peeked.take() {
Some((token, span))
} else {
self.lexer.next()
}
}
fn peek(&mut self) -> Option<(Result<Token, <Token as Logos>::Error>, Span)> {
if self.peeked.is_none() {
self.peeked = self.lexer.next();
}
self.peeked.clone()
}
pub fn span(&self) -> Span {
self.lexer.span()

View file

@ -1,5 +1,5 @@
use crate::entry::ParseItem;
use crate::error::{ExpectToken, NoValidTokenError, ParseStringError};
use crate::error::{ExpectToken, NoValidTokenError, SerdeParseError};
use crate::tokenizer::{SpannedToken, Tokenizer};
use crate::{Token, VdfError};
use logos::Span;
@ -50,13 +50,15 @@ impl<'de> Deserializer<'de> {
self.peeked = Some(Ok(token))
}
fn read_str(&mut self) -> Result<Cow<'de, str>> {
fn read_str(&mut self) -> Result<(Cow<'de, str>, Span)> {
let token = self.next().expect_token(STRING_ITEMS, self.source())?;
Ok(token.string(self.source()))
Ok((token.string(self.source()), token.span))
}
fn parse<T: ParseItem>(&mut self) -> Result<T> {
T::from_str(self.read_str()?.as_ref()).map_err(VdfError::from)
let (str, span) = self.read_str()?;
T::from_str(str.as_ref())
.map_err(|e| SerdeParseError::new(e.ty, &e.value, span, self.source()).into())
}
fn set_last_key(&mut self, key: Cow<'de, str>) {
@ -183,11 +185,16 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
let str = self.read_str()?;
let (str, span) = self.read_str()?;
let mut chars = str.chars();
match (chars.next(), chars.next()) {
(Some(_), None) => Ok(()),
_ => Err(ParseStringError::new("char", str.as_ref())),
_ => Err(SerdeParseError::new(
"char",
str.as_ref(),
span,
self.source(),
)),
}?;
visitor.visit_str(str.as_ref())
@ -199,14 +206,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
visitor.visit_str(self.read_str()?.as_ref())
visitor.visit_str(self.read_str()?.0.as_ref())
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_string(self.read_str()?.into())
visitor.visit_string(self.read_str()?.0.into())
}
// The `Serializer` implementation on the previous page serialized byte
@ -222,7 +229,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.read_str()?.as_bytes().into())
visitor.visit_byte_buf(self.read_str()?.0.as_bytes().into())
}
// An absent optional is represented as the JSON `null` and a present
@ -257,9 +264,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
let str = self.read_str()?;
let (str, span) = self.read_str()?;
if !str.is_empty() {
return Err(ParseStringError::new("unit", str.as_ref()).into());
return Err(SerdeParseError::new("unit", str.as_ref(), span, self.source()).into());
}
visitor.visit_unit()
}
@ -268,9 +275,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where
V: Visitor<'de>,
{
let str = self.read_str()?;
let (str, span) = self.read_str()?;
if !str.is_empty() {
return Err(ParseStringError::new("unit", str.as_ref()).into());
return Err(SerdeParseError::new("unit", str.as_ref(), span, self.source()).into());
}
visitor.visit_unit()
}
@ -517,10 +524,10 @@ impl<'de, 'a> VariantAccess<'de> for Enum<'a, 'de> {
type Error = VdfError;
fn unit_variant(self) -> Result<()> {
let str = self.de.read_str()?;
let (str, span) = self.de.read_str()?;
if !str.is_empty() {
return Err(ParseStringError::new("unit", str.as_ref()).into());
return Err(SerdeParseError::new("unit", str.as_ref(), span, self.source()).into());
}
Ok(())

View file

@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::collections::BTreeMap;
use std::fs::read_to_string;
use test_case::test_case;
use vdf_reader::from_str;