event/entry parsing

This commit is contained in:
Robin Appelman 2023-12-17 22:20:56 +01:00
commit 26c9b82b8e
6 changed files with 172 additions and 51 deletions

View file

@ -1,4 +1,16 @@
mod array;
mod statement;
mod table;
mod value;
use crate::error::{ParseEntryError, ParseItemError};
use crate::Item;
pub use array::Array;
pub use statement::Statement;
use std::any::type_name;
use std::slice; use std::slice;
pub use table::Table;
pub use value::Value;
/// The kinds of entry. /// The kinds of entry.
#[derive(Clone, PartialEq, Eq, Debug, Serialize)] #[derive(Clone, PartialEq, Eq, Debug, Serialize)]
@ -57,12 +69,8 @@ impl Entry {
} }
/// Try to convert the entry to the given type. /// Try to convert the entry to the given type.
pub fn to<T: Parse>(&self) -> Option<T> { pub fn to<T: ParseItem>(self) -> Result<T, ParseEntryError> {
if let Entry::Value(value) = self { T::from_entry(self)
value.to::<T>()
} else {
None
}
} }
/// Try to take the entry as a table. /// Try to take the entry as a table.
@ -114,9 +122,12 @@ impl Entry {
} }
/// Parsable types. /// Parsable types.
pub trait Parse: Sized { pub trait ParseItem: Sized {
/// Try to parse the string. /// Try to cast the entry into a concrete type
fn parse(string: &str) -> Option<Self>; fn from_entry(entry: Entry) -> Result<Self, ParseEntryError>;
/// Try to cast the item into a concrete type
fn from_item(item: Item) -> Result<Self, ParseItemError>;
} }
macro_rules! from_str { macro_rules! from_str {
@ -128,10 +139,20 @@ macro_rules! from_str {
); );
($ty:ident) => ( ($ty:ident) => (
impl Parse for $ty { impl ParseItem for $ty {
fn parse(string: &str) -> Option<Self> { fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
string.parse::<$ty>().ok() let string = match entry.as_str() {
Some(string) => string,
None => {
return Err(ParseEntryError::new(type_name::<Self>(), entry));
}
};
string.parse::<$ty>().map_err(|_| ParseEntryError::new(type_name::<Self>(), entry))
} }
fn from_item(item: Item) -> Result<Self, ParseItemError> {
item.as_str().parse::<$ty>().map_err(|_| ParseItemError::new(type_name::<Self>(), item))
}
} }
); );
} }
@ -141,25 +162,61 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV
from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6); from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6);
from_str!(for i8 i16 i32 i64 isize u8 u16 u32 u64 usize f32 f64); from_str!(for i8 i16 i32 i64 isize u8 u16 u32 u64 usize f32 f64);
impl Parse for bool { impl ParseItem for bool {
fn parse(string: &str) -> Option<Self> { fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
let string = match entry.as_str() {
Some(string) => string,
None => {
return Err(ParseEntryError::new(type_name::<Self>(), entry));
}
};
match string { match string {
"0" => Some(false), "0" => Ok(false),
"1" => Some(true), "1" => Ok(true),
v => v.parse::<bool>().ok(), v => v
.parse::<bool>()
.map_err(|_| ParseEntryError::new(type_name::<Self>(), entry)),
}
}
fn from_item(item: Item) -> Result<Self, ParseItemError> {
match item.as_str() {
"0" => Ok(false),
"1" => Ok(true),
v => v
.parse::<bool>()
.map_err(|_| ParseItemError::new(type_name::<Self>(), item)),
} }
} }
} }
mod table; impl ParseItem for String {
pub use table::Table; fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
match entry {
Entry::Table(entry) => Err(ParseEntryError::new(
type_name::<Self>(),
Entry::Table(entry),
)),
Entry::Array(entry) => Err(ParseEntryError::new(
type_name::<Self>(),
Entry::Array(entry),
)),
Entry::Statement(statement) => Ok(statement.into()),
Entry::Value(value) => Ok(value.into()),
}
}
mod array; fn from_item(item: Item) -> Result<Self, ParseItemError> {
pub use array::Array; Ok(item.into_content().into())
}
}
mod statement; impl<T: ParseItem> ParseItem for Option<T> {
pub use statement::Statement; fn from_entry(entry: Entry) -> Result<Self, ParseEntryError> {
T::from_entry(entry).map(Some)
}
mod value; fn from_item(item: Item) -> Result<Self, ParseItemError> {
use crate::Item; T::from_item(item).map(Some)
pub use value::Value; }
}

View file

@ -19,6 +19,12 @@ impl From<Statement> for Entry {
} }
} }
impl From<Statement> for String {
fn from(value: Statement) -> Self {
value.0
}
}
impl Deref for Statement { impl Deref for Statement {
type Target = str; type Target = str;

View file

@ -1,4 +1,4 @@
use super::{Entry, Parse}; use super::Entry;
use serde::Serialize; use serde::Serialize;
use std::borrow::Cow; use std::borrow::Cow;
use std::ops::Deref; use std::ops::Deref;
@ -18,6 +18,12 @@ impl From<Value> for Entry {
} }
} }
impl From<Value> for String {
fn from(value: Value) -> Self {
value.0
}
}
impl Deref for Value { impl Deref for Value {
type Target = str; type Target = str;
@ -25,10 +31,3 @@ impl Deref for Value {
&self.0 &self.0
} }
} }
impl Value {
/// Try to convert the value to the given type.
pub fn to<T: Parse>(&self) -> Option<T> {
T::parse(&self.0)
}
}

View file

@ -1,4 +1,5 @@
use crate::{Event, Token}; use crate::entry::Entry;
use crate::{Event, Item, Token};
use miette::{Diagnostic, SourceSpan}; use miette::{Diagnostic, SourceSpan};
use std::error::Error; use std::error::Error;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -19,6 +20,14 @@ pub enum VdfError {
#[diagnostic(transparent)] #[diagnostic(transparent)]
/// Wrong event to for conversion /// Wrong event to for conversion
WrongEntryType(#[from] WrongEventTypeError), WrongEntryType(#[from] WrongEventTypeError),
#[error(transparent)]
#[diagnostic(transparent)]
/// Failed to parse entry into type
ParseEntry(#[from] ParseEntryError),
#[error(transparent)]
#[diagnostic(transparent)]
/// Failed to parse item into type
ParseItem(#[from] ParseItemError),
} }
struct ExpectedTokens<'a>(&'a [Token]); struct ExpectedTokens<'a>(&'a [Token]);
@ -134,8 +143,53 @@ impl WrongEventTypeError {
src: String::new(), src: String::new(),
} }
} }
pub fn new_with_source(
event: Event,
expected: &'static str,
got: &'static str,
src: String,
) -> Self {
WrongEventTypeError {
err_span: event.span().into(),
event: event.into_owned(),
expected,
got,
src,
}
}
pub fn with_source(self, src: String) -> Self { pub fn with_source(self, src: String) -> Self {
WrongEventTypeError { src, ..self } WrongEventTypeError { src, ..self }
} }
} }
#[derive(Debug, Clone, Error, Diagnostic)]
#[error("Can't parse entry {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::eof))]
pub struct ParseEntryError {
pub ty: &'static str,
pub value: Entry,
}
impl ParseEntryError {
pub fn new(ty: &'static str, value: Entry) -> Self {
ParseEntryError { ty, value }
}
}
#[derive(Debug, Clone, Error, Diagnostic)]
#[error("Can't parse entry {value:?} as {ty}")]
#[diagnostic(code(vmt_parser::eof))]
pub struct ParseItemError {
pub ty: &'static str,
pub value: Item<'static>,
}
impl ParseItemError {
pub fn new(ty: &'static str, value: Item) -> Self {
ParseItemError {
ty,
value: value.into_owned(),
}
}
}

View file

@ -13,21 +13,6 @@ pub enum Item<'a> {
Item { content: Cow<'a, str>, span: Span }, 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> { impl<'a> Item<'a> {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match self { match self {
@ -42,6 +27,26 @@ impl<'a> Item<'a> {
Item::Item { content, .. } => content, Item::Item { content, .. } => content,
} }
} }
pub fn as_str(&self) -> &str {
match self {
Item::Statement { content, .. } => content.as_ref(),
Item::Item { content, .. } => content.as_ref(),
}
}
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,
},
}
}
} }
/// Reader event. /// Reader event.

View file

@ -1,5 +1,5 @@
pub mod entry; pub mod entry;
mod error; pub mod error;
mod event; mod event;
mod parser; mod parser;
mod reader; mod reader;