mirror of
https://codeberg.org/icewind/php-literal-parser.git
synced 2026-06-03 18:44:07 +02:00
handle empty arrays and trailing commas
This commit is contained in:
parent
4c4cbefcf5
commit
36b75790f0
4 changed files with 51 additions and 21 deletions
23
examples/parse.rs
Normal file
23
examples/parse.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use php_object_parser::parse;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let source = r###"
|
||||||
|
array (
|
||||||
|
"double" => "quote",
|
||||||
|
'single' => 'quote',
|
||||||
|
"escaped" => "\"quote\"",
|
||||||
|
1 => 2,
|
||||||
|
"nested" => [
|
||||||
|
"sub" => "key",
|
||||||
|
],
|
||||||
|
"array" => [1,2,3,4],
|
||||||
|
"bool" => false,
|
||||||
|
"negative" => -1,
|
||||||
|
)
|
||||||
|
"###;
|
||||||
|
|
||||||
|
match parse(source) {
|
||||||
|
Ok(result) => print!("{:#?}", result),
|
||||||
|
Err(err) => eprint!("{}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/ast.rs
25
src/ast.rs
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::error::UnexpectedTokenError;
|
||||||
use crate::error::{ExpectToken, InvalidArrayKeyError, ParseError, ResultExt, SpannedError};
|
use crate::error::{ExpectToken, InvalidArrayKeyError, ParseError, ResultExt, SpannedError};
|
||||||
use crate::lexer::Token;
|
use crate::lexer::Token;
|
||||||
use crate::string::{unescape_double, unescape_single, UnescapeError};
|
use crate::string::{unescape_double, unescape_single, UnescapeError};
|
||||||
|
|
@ -124,7 +125,20 @@ fn parse_array<'source>(
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let key_or_value = parse_lexer(source, lexer)?;
|
let key_or_value = match parse_lexer(source, lexer) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(err) => {
|
||||||
|
// trailing comma or empty array
|
||||||
|
if matches!(
|
||||||
|
err.error(),
|
||||||
|
ParseError::UnexpectedToken(UnexpectedTokenError { found: None, .. })
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
let key_or_value_span = lexer.span();
|
let key_or_value_span = lexer.span();
|
||||||
let next = lexer
|
let next = lexer
|
||||||
.next()
|
.next()
|
||||||
|
|
@ -202,6 +216,7 @@ fn test_parse() {
|
||||||
Value::String("test".to_string()),
|
Value::String("test".to_string()),
|
||||||
parse(r#""test""#).unwrap()
|
parse(r#""test""#).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Value::Array(hashmap! {}), parse(r#"array()"#).unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Value::Array(hashmap! {
|
Value::Array(hashmap! {
|
||||||
Key::Int(0) => Value::Int(3),
|
Key::Int(0) => Value::Int(3),
|
||||||
|
|
@ -210,6 +225,14 @@ fn test_parse() {
|
||||||
}),
|
}),
|
||||||
parse(r#"array(3,4,5)"#).unwrap()
|
parse(r#"array(3,4,5)"#).unwrap()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Value::Array(hashmap! {
|
||||||
|
Key::Int(0) => Value::Int(3),
|
||||||
|
Key::Int(1) => Value::Int(4),
|
||||||
|
Key::Int(2) => Value::Int(5),
|
||||||
|
}),
|
||||||
|
parse(r#"array(3,4,5,)"#).unwrap()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Value::Array(hashmap! {
|
Value::Array(hashmap! {
|
||||||
Key::Int(1) => Value::Int(3),
|
Key::Int(1) => Value::Int(3),
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ impl<'a, T: Error + Debug> SpannedError<'a, T> {
|
||||||
error,
|
error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn error(&self) -> &T {
|
||||||
|
&self.error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const METRICS: DefaultMetrics = DefaultMetrics::with_tab_stop(4);
|
const METRICS: DefaultMetrics = DefaultMetrics::with_tab_stop(4);
|
||||||
|
|
|
||||||
20
src/lexer.rs
20
src/lexer.rs
|
|
@ -1,5 +1,4 @@
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
|
|
||||||
#[derive(Logos, Debug, PartialEq, Clone)]
|
#[derive(Logos, Debug, PartialEq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
|
|
@ -30,25 +29,6 @@ pub enum Token {
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Token {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Token::Array => write!(f, "array"),
|
|
||||||
Token::Bool => write!(f, "bool"),
|
|
||||||
Token::Arrow => write!(f, "arrow"),
|
|
||||||
Token::BracketOpen => write!(f, "bracket open"),
|
|
||||||
Token::BracketClose => write!(f, "bracket close"),
|
|
||||||
Token::SquareOpen => write!(f, "square bracket open"),
|
|
||||||
Token::SquareClose => write!(f, "square bracket close"),
|
|
||||||
Token::Comma => write!(f, "comma"),
|
|
||||||
Token::LiteralString => write!(f, "string literal"),
|
|
||||||
Token::Float => write!(f, "float literal"),
|
|
||||||
Token::Integer => write!(f, "integer literal"),
|
|
||||||
Token::Error => write!(f, "invalid token"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lex() {
|
fn test_lex() {
|
||||||
let source = r###"
|
let source = r###"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue