statements

This commit is contained in:
Robin Appelman 2023-12-15 16:22:51 +01:00
commit 12d3e35496
8 changed files with 69 additions and 53 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ target
*.obj *.obj
result result
.direnv .direnv
*.snap.new

View file

@ -1,5 +1,4 @@
use super::{Array, Entry, Statement, Value}; use super::{Array, Entry, Statement, Value};
use crate::error::StatementInTableError;
use crate::{Event, Item, Reader, Result}; use crate::{Event, Item, Reader, Result};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use std::collections::HashMap; use std::collections::HashMap;
@ -46,25 +45,16 @@ impl Table {
while let Some(event) = reader.event() { while let Some(event) = reader.event() {
match event? { match event? {
Event::Entry { Event::Entry {
key: Item::Statement { .. }, key: Item::Statement { content: key, .. },
span, value,
.. ..
} => { } => insert(&mut map, key.into(), Statement::from(value.content).into()),
return Err(
StatementInTableError::new(span.into(), reader.content.into()).into(),
)
}
Event::Entry {
key: Item::Value { content: key, .. },
value: Item::Statement { content: value, .. },
..
} => insert(&mut map, key.into(), Statement::from(value).into()),
Event::Entry { Event::Entry {
key: Item::Value { content: key, .. }, key: Item::Key { content: key, .. },
value: Item::Value { content: value, .. }, value,
.. ..
} => insert(&mut map, key.into(), Value::from(value).into()), } => insert(&mut map, key.into(), Value::from(value.content).into()),
Event::GroupStart { name, .. } => { Event::GroupStart { name, .. } => {
insert(&mut map, name.into(), Table::load(reader)?.into()) insert(&mut map, name.into(), Table::load(reader)?.into())

View file

@ -15,10 +15,6 @@ pub enum VdfError {
#[diagnostic(transparent)] #[diagnostic(transparent)]
/// No valid token found /// No valid token found
NoValidToken(#[from] NoValidTokenError), NoValidToken(#[from] NoValidTokenError),
#[error(transparent)]
#[diagnostic(transparent)]
/// An unexpected statement was found inside a table
StatementInTable(#[from] StatementInTableError),
} }
struct ExpectedTokens<'a>(&'a [Token]); struct ExpectedTokens<'a>(&'a [Token]);
@ -53,12 +49,17 @@ pub struct UnexpectedTokenError {
} }
impl UnexpectedTokenError { impl UnexpectedTokenError {
pub fn new(expected: &'static [Token], found: Option<Token>, err_span: SourceSpan, src: String) -> Self { pub fn new(
expected: &'static [Token],
found: Option<Token>,
err_span: SourceSpan,
src: String,
) -> Self {
UnexpectedTokenError { UnexpectedTokenError {
err_span, err_span,
expected, expected,
found, found,
src src,
} }
} }
} }
@ -96,7 +97,11 @@ pub struct NoValidTokenError {
impl NoValidTokenError { impl NoValidTokenError {
pub fn new(expected: &'static [Token], err_span: SourceSpan, src: String) -> Self { pub fn new(expected: &'static [Token], err_span: SourceSpan, src: String) -> Self {
NoValidTokenError { err_span, expected ,src } NoValidTokenError {
err_span,
expected,
src,
}
} }
} }
@ -111,19 +116,3 @@ impl Display for NoValidTokenError {
} }
impl Error for NoValidTokenError {} impl Error for NoValidTokenError {}
/// An unexpected statement was found inside a table
#[derive(Debug, Clone, Diagnostic, Error)]
#[diagnostic(code(php_literal_parser::unexpected_token))]
#[error("An unexpected statement was found inside a table")]
pub struct StatementInTableError {
#[label("Unexpected statement")]
err_span: SourceSpan,
#[source_code]
src: String,
}
impl StatementInTableError {
pub fn new(err_span: SourceSpan, src: String) -> Self {
StatementInTableError { err_span, src }
}
}

View file

@ -21,16 +21,16 @@ pub enum Token {
Item, Item,
/// An enclosed or bare item. /// An enclosed or bare item.
#[regex("\"([^\"\\\\]|\\\\.)*\"")] #[regex("\"([^\"\\\\]|\\\\.)*\"")]
#[display("item")] #[display("quoted item")]
QuotedItem, QuotedItem,
/// An enclosed or bare statement. /// An enclosed or bare statement.
#[regex("\"#([^\"\\\\]|\\\\.)*\"")]
#[display("statement")]
QuotedStatement,
/// An enclosed or bare statement.
#[regex("#[^ \"\t\n]+")] #[regex("#[^ \"\t\n]+")]
#[display("statement")] #[display("statement")]
Statement, Statement,
/// An enclosed or bare statement.
#[regex("\"#([^\"\\\\]|\\\\.)*\"")]
#[display("quoted statement")]
QuotedStatement,
} }
#[cfg(test)] #[cfg(test)]

View file

@ -10,25 +10,31 @@ pub enum Item<'a> {
Statement { content: Cow<'a, str>, span: Span }, Statement { content: Cow<'a, str>, span: Span },
/// A value. /// A value.
Value { content: Cow<'a, str>, span: Span }, Key { content: Cow<'a, str>, span: Span },
} }
impl<'a> Item<'a> { impl<'a> Item<'a> {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match self { match self {
Item::Statement { span, .. } => span.clone(), Item::Statement { span, .. } => span.clone(),
Item::Value { span, .. } => span.clone(), Item::Key { span, .. } => span.clone(),
} }
} }
pub fn into_content(self) -> Cow<'a, str> { pub fn into_content(self) -> Cow<'a, str> {
match self { match self {
Item::Statement { content, .. } => content, Item::Statement { content, .. } => content,
Item::Value { content, .. } => content, Item::Key { content, .. } => content,
} }
} }
} }
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Value<'a> {
pub content: Cow<'a, str>,
pub span: Span,
}
/// Reader event. /// Reader event.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub enum Event<'a> { pub enum Event<'a> {
@ -41,7 +47,7 @@ pub enum Event<'a> {
/// An entry. /// An entry.
Entry { Entry {
key: Item<'a>, key: Item<'a>,
value: Item<'a>, value: Value<'a>,
span: Span, span: Span,
}, },
} }
@ -98,12 +104,12 @@ impl<'a> Reader<'a> {
} }
Some((Ok(Token::GroupEnd), span)) => return Some(Ok(Event::GroupEnd { span })), Some((Ok(Token::GroupEnd), span)) => return Some(Ok(Event::GroupEnd { span })),
Some((Ok(Token::Item), span)) => Item::Value { Some((Ok(Token::Item), span)) => Item::Key {
content: string(self.lexer.slice()), content: string(self.lexer.slice()),
span, span,
}, },
Some((Ok(Token::QuotedItem), span)) => Item::Value { Some((Ok(Token::QuotedItem), span)) => Item::Key {
content: quoted_string(self.lexer.slice()), content: quoted_string(self.lexer.slice()),
span, span,
}, },
@ -158,12 +164,12 @@ impl<'a> Reader<'a> {
})) }))
} }
Some((Ok(Token::QuotedItem), span)) => Item::Value { Some((Ok(Token::QuotedItem), span)) => Value {
content: quoted_string(self.lexer.slice()), content: quoted_string(self.lexer.slice()),
span, span,
}, },
Some((Ok(Token::Item), span)) => Item::Value { Some((Ok(Token::Item), span)) => Value {
content: string(self.lexer.slice()), content: string(self.lexer.slice()),
span, span,
}, },
@ -179,7 +185,7 @@ impl<'a> Reader<'a> {
} }
}; };
let span = key.span().start..value.span().end; let span = key.span().start..value.span.end;
Some(Ok(Event::Entry { key, value, span })) Some(Ok(Event::Entry { key, value, span }))
} }
} }

12
tests/data/messy.vdf Normal file
View file

@ -0,0 +1,12 @@
"#base" "panelBase.res"
"Resource/specificPanel.res"
{
// Specify panel-specific controls here
empty ""
"empty quoted" "\"\""
array 1
array 2
array "3"
windows_path "C:\test\no newline"
}

View file

@ -4,6 +4,7 @@ use vdf_reader::entry::Table;
use vdf_reader::Reader; use vdf_reader::Reader;
#[test_case("tests/data/concrete.vmt")] #[test_case("tests/data/concrete.vmt")]
#[test_case("tests/data/messy.vdf")]
fn test_parse(path: &str) { fn test_parse(path: &str) {
let raw = read_to_string(path).unwrap(); let raw = read_to_string(path).unwrap();
let mut reader = Reader::from(raw.as_str()); let mut reader = Reader::from(raw.as_str());

View file

@ -0,0 +1,17 @@
---
source: tests/parse.rs
expression: parsed
---
Table({
"#base": Statement(Statement("panelBase.res")),
"Resource/specificPanel.res": Table(Table({
"array": Array(Array([
Value(Value("1")),
Value(Value("2")),
Value(Value("3")),
])),
"empty": Value(Value("")),
"empty quoted": Value(Value("\"\"")),
"windows_path": Value(Value("C:\\test\\no newline")),
})),
})