event casts

This commit is contained in:
Robin Appelman 2023-12-15 20:07:06 +01:00
commit 909cd4a18d
5 changed files with 222 additions and 86 deletions

View file

@ -1,5 +1,6 @@
use super::{Array, Entry};
use crate::entry::{Statement, Value};
use crate::event::{EntryEvent, GroupStartEvent};
use crate::{Event, Item, Reader, Result};
use serde::{Serialize, Serializer};
use std::collections::hash_map;
@ -51,21 +52,23 @@ impl Table {
while let Some(event) = reader.event() {
match event? {
Event::Entry {
Event::Entry(EntryEvent {
key: Item::Item { content: key, .. },
value,
..
} => insert(&mut map, key, Value::from(value.into_content())),
}) => insert(&mut map, key, Value::from(value.into_content())),
Event::Entry {
Event::Entry(EntryEvent {
key: Item::Statement { content: key, .. },
value,
..
} => insert(&mut map, key, Statement::from(value.into_content())),
}) => insert(&mut map, key, Statement::from(value.into_content())),
Event::GroupStart { name, .. } => insert(&mut map, name, Table::load(reader)?),
Event::GroupStart(GroupStartEvent { name, .. }) => {
insert(&mut map, name, Table::load(reader)?)
}
Event::GroupEnd { .. } => break,
Event::GroupEnd(_) => break,
}
}

View file

@ -1,4 +1,4 @@
use crate::Token;
use crate::{Event, Token};
use miette::{Diagnostic, SourceSpan};
use std::error::Error;
use std::fmt::{Display, Formatter};
@ -15,6 +15,10 @@ pub enum VdfError {
#[diagnostic(transparent)]
/// No valid token found
NoValidToken(#[from] NoValidTokenError),
#[error(transparent)]
#[diagnostic(transparent)]
/// Wrong event to for conversion
WrongEntryType(#[from] WrongEventTypeError),
}
struct ExpectedTokens<'a>(&'a [Token]);
@ -85,8 +89,9 @@ impl Display for UnexpectedTokenError {
impl Error for UnexpectedTokenError {}
/// A token that wasn't expected was found while parsing
#[derive(Debug, Clone, Diagnostic)]
#[derive(Debug, Clone, Diagnostic, Error)]
#[diagnostic(code(vmt_reader::no_valid_token))]
#[error("No valid token found, expected one of {}", ExpectedTokens(self.expected))]
pub struct NoValidTokenError {
#[label("Expected {}", ExpectedTokens(self.expected))]
err_span: SourceSpan,
@ -105,14 +110,32 @@ impl NoValidTokenError {
}
}
impl Display for NoValidTokenError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"No valid token found, expected one of {}",
ExpectedTokens(self.expected)
)
}
/// Wrong event to for conversion
#[derive(Debug, Clone, Diagnostic, Error)]
#[diagnostic(code(vmt_reader::wrong_value_type))]
#[error("Wrong event to for conversion, expected a {expected} but found a {got}")]
pub struct WrongEventTypeError {
pub expected: &'static str,
pub got: &'static str,
pub event: Event<'static>,
#[label("Expected a {}", self.expected)]
err_span: SourceSpan,
#[source_code]
src: String,
}
impl Error for NoValidTokenError {}
impl WrongEventTypeError {
pub fn new(event: Event, expected: &'static str, got: &'static str) -> Self {
WrongEventTypeError {
err_span: event.span().into(),
event: event.into_owned(),
expected,
got,
src: String::new(),
}
}
pub fn with_source(self, src: String) -> Self {
WrongEventTypeError { src, ..self }
}
}

155
src/event.rs Normal file
View file

@ -0,0 +1,155 @@
use crate::error::WrongEventTypeError;
use crate::VdfError;
use logos::Span;
use std::borrow::Cow;
/// Kinds of item.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Item<'a> {
/// A statement, the ones starting with #.
Statement { content: Cow<'a, str>, span: Span },
/// A value.
Item { content: Cow<'a, str>, span: Span },
}
impl Item<'_> {
pub fn into_owned(self) -> Item<'static> {
match self {
Item::Statement { content, span } => Item::Statement {
content: content.into_owned().into(),
span,
},
Item::Item { content, span } => Item::Item {
content: content.into_owned().into(),
span,
},
}
}
}
impl<'a> Item<'a> {
pub fn span(&self) -> Span {
match self {
Item::Statement { span, .. } => span.clone(),
Item::Item { span, .. } => span.clone(),
}
}
pub fn into_content(self) -> Cow<'a, str> {
match self {
Item::Statement { content, .. } => content,
Item::Item { content, .. } => content,
}
}
}
/// Reader event.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Event<'a> {
/// A group with the given name is starting.
GroupStart(GroupStartEvent<'a>),
/// A group has ended.
GroupEnd(GroupEndEvent),
/// An entry.
Entry(EntryEvent<'a>),
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GroupStartEvent<'a> {
pub name: Cow<'a, str>,
pub span: Span,
}
impl GroupStartEvent<'_> {
pub fn into_owned(self) -> GroupStartEvent<'static> {
GroupStartEvent {
name: self.name.into_owned().into(),
span: self.span,
}
}
}
impl<'a> TryFrom<Event<'a>> for GroupStartEvent<'a> {
type Error = VdfError;
fn try_from(event: Event<'a>) -> Result<Self, Self::Error> {
match event {
Event::GroupStart(event) => Ok(event),
Event::GroupEnd(_) => {
Err(WrongEventTypeError::new(event, "group start", "group end").into())
}
Event::Entry(_) => Err(WrongEventTypeError::new(event, "group start", "entry").into()),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GroupEndEvent {
pub span: Span,
}
impl<'a> TryFrom<Event<'a>> for GroupEndEvent {
type Error = VdfError;
fn try_from(event: Event<'a>) -> Result<Self, Self::Error> {
match event {
Event::GroupEnd(event) => Ok(event),
Event::GroupStart(_) => {
Err(WrongEventTypeError::new(event, "group end", "group start").into())
}
Event::Entry(_) => Err(WrongEventTypeError::new(event, "group start", "entry").into()),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct EntryEvent<'a> {
pub key: Item<'a>,
pub value: Item<'a>,
pub span: Span,
}
impl EntryEvent<'_> {
pub fn into_owned(self) -> EntryEvent<'static> {
EntryEvent {
key: self.key.into_owned(),
value: self.value.into_owned(),
span: self.span,
}
}
}
impl<'a> TryFrom<Event<'a>> for EntryEvent<'a> {
type Error = VdfError;
fn try_from(event: Event<'a>) -> Result<Self, Self::Error> {
match event {
Event::Entry(event) => Ok(event),
Event::GroupEnd(_) => Err(WrongEventTypeError::new(event, "entry", "group end").into()),
Event::GroupStart(_) => {
Err(WrongEventTypeError::new(event, "entry", "group start").into())
}
}
}
}
impl Event<'_> {
#[allow(dead_code)]
pub fn span(&self) -> Span {
match self {
Event::GroupStart(GroupStartEvent { span, .. }) => span.clone(),
Event::GroupEnd(GroupEndEvent { span, .. }) => span.clone(),
Event::Entry(EntryEvent { span, .. }) => span.clone(),
}
}
pub fn into_owned(self) -> Event<'static> {
match self {
Event::GroupStart(event) => Event::GroupStart(event.into_owned()),
Event::GroupEnd(event) => Event::GroupEnd(event),
Event::Entry(event) => Event::Entry(event.into_owned()),
}
}
}

View file

@ -1,10 +1,12 @@
pub mod entry;
mod error;
mod event;
mod parser;
mod reader;
pub use error::VdfError;
pub type Result<T, E = VdfError> = std::result::Result<T, E>;
pub use event::{EntryEvent, Event, GroupEndEvent, GroupStartEvent, Item};
pub use parser::Token;
pub use reader::{Event, Item, Reader};
pub use reader::Reader;

View file

@ -1,65 +1,12 @@
use super::{Result, Token};
use crate::error::{NoValidTokenError, UnexpectedTokenError};
use crate::event::{EntryEvent, Event, GroupEndEvent, GroupStartEvent, Item};
use logos::{Lexer, Logos, Span, SpannedIter};
use std::borrow::Cow;
/// Kinds of item.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Item<'a> {
/// A statement, the ones starting with #.
Statement { content: Cow<'a, str>, span: Span },
/// A value.
Item { content: Cow<'a, str>, span: Span },
}
impl<'a> Item<'a> {
pub fn span(&self) -> Span {
match self {
Item::Statement { span, .. } => span.clone(),
Item::Item { span, .. } => span.clone(),
}
}
pub fn into_content(self) -> Cow<'a, str> {
match self {
Item::Statement { content, .. } => content,
Item::Item { content, .. } => content,
}
}
}
/// Reader event.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Event<'a> {
/// A group with the given name is starting.
GroupStart { name: Cow<'a, str>, span: Span },
/// A group has ended.
GroupEnd { span: Span },
/// An entry.
Entry {
key: Item<'a>,
value: Item<'a>,
span: Span,
},
}
impl Event<'_> {
#[allow(dead_code)]
pub fn span(&self) -> Span {
match self {
Event::GroupStart { span, .. } => span.clone(),
Event::GroupEnd { span, .. } => span.clone(),
Event::Entry { span, .. } => span.clone(),
}
}
}
/// A VDF token reader.
pub struct Reader<'a> {
pub(crate) content: &'a str,
pub source: &'a str,
lexer: SpannedIter<'a, Token>,
peeked: Option<(Result<Token, <Token as Logos<'a>>::Error>, Span)>,
}
@ -67,7 +14,7 @@ pub struct Reader<'a> {
impl<'a> From<&'a str> for Reader<'a> {
fn from(content: &'a str) -> Self {
Reader {
content,
source: content,
lexer: Lexer::new(content).spanned(),
peeked: None,
}
@ -90,6 +37,10 @@ impl<'a> Reader<'a> {
self.peeked.clone()
}
pub fn span(&self) -> Span {
self.lexer.span()
}
fn token_eat_newlines(&mut self) -> Option<(Result<Token, <Token as Logos>::Error>, Span)> {
loop {
let (token, span) = self.token()?;
@ -122,11 +73,13 @@ impl<'a> Reader<'a> {
return Some(Err(NoValidTokenError::new(
VALID_KEY,
span.into(),
self.content.into(),
self.source.into(),
)
.into()));
}
Some((Ok(Token::GroupEnd), span)) => return Some(Ok(Event::GroupEnd { span })),
Some((Ok(Token::GroupEnd), span)) => {
return Some(Ok(Event::GroupEnd(GroupEndEvent { span })))
}
Some((Ok(Token::Item), span)) => Item::Item {
content: string(self.lexer.slice()),
@ -153,7 +106,7 @@ impl<'a> Reader<'a> {
VALID_KEY,
Some(token),
span.into(),
self.content.into(),
self.source.into(),
)
.into()))
}
@ -175,7 +128,7 @@ impl<'a> Reader<'a> {
&[Token::GroupStart],
Some(token),
span.into(),
self.content.into(),
self.source.into(),
)
.into()))
}
@ -183,7 +136,7 @@ impl<'a> Reader<'a> {
return Some(Err(NoValidTokenError::new(
VALID_VALUE,
span.into(),
self.content.into(),
self.source.into(),
)
.into()));
}
@ -192,7 +145,7 @@ impl<'a> Reader<'a> {
VALID_VALUE,
None,
span.into(),
self.content.into(),
self.source.into(),
)
.into()))
}
@ -206,7 +159,7 @@ impl<'a> Reader<'a> {
VALID_VALUE,
None,
self.lexer.span().into(),
self.content.into(),
self.source.into(),
)
.into()));
}
@ -215,16 +168,16 @@ impl<'a> Reader<'a> {
return Some(Err(NoValidTokenError::new(
VALID_VALUE,
span.into(),
self.content.into(),
self.source.into(),
)
.into()));
}
Some((Ok(Token::GroupStart), span)) => {
return Some(Ok(Event::GroupStart {
return Some(Ok(Event::GroupStart(GroupStartEvent {
name: key.into_content(),
span,
}))
})))
}
Some((Ok(Token::QuotedItem), span)) => Item::Item {
@ -252,14 +205,14 @@ impl<'a> Reader<'a> {
VALID_VALUE,
Some(token),
span.into(),
self.content.into(),
self.source.into(),
)
.into()))
}
};
let span = key.span().start..value.span().end;
Some(Ok(Event::Entry { key, value, span }))
Some(Ok(Event::Entry(EntryEvent { key, value, span })))
}
}