mirror of
https://codeberg.org/icewind/php-literal-parser.git
synced 2026-06-03 10:34:08 +02:00
switch to miette for error reporting
This commit is contained in:
parent
f24e69d99f
commit
097ed69b9e
9 changed files with 387 additions and 316 deletions
|
|
@ -11,14 +11,11 @@ documentation = "https://docs.rs/php-literal-parser"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
logos = "0.12"
|
logos = "0.12"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
source-span = { version = "=2.2.1", default-features = false }
|
|
||||||
memchr = "2.3.4"
|
memchr = "2.3.4"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
miette = { version = "1", git = "https://github.com/cormacrelf/miette", branch = "transparent" }
|
||||||
|
parse-display = "0.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["colors"]
|
|
||||||
colors = ["source-span/colors"]
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use miette::DiagnosticResult;
|
||||||
use php_literal_parser::{from_str, ParseError};
|
use php_literal_parser::{from_str, ParseError};
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
|
@ -7,7 +8,7 @@ struct Target {
|
||||||
bars: Vec<u8>,
|
bars: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), ParseError> {
|
fn main() -> DiagnosticResult<()> {
|
||||||
let target = from_str(r#"["foo" => true, "bars" => [1, 2, 3, 4,]]"#)?;
|
let target = from_str(r#"["foo" => true, "bars" => [1, 2, 3, 4,]]"#)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
use miette::DiagnosticResult;
|
||||||
use php_literal_parser::{from_str, Value};
|
use php_literal_parser::{from_str, Value};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> DiagnosticResult<()> {
|
||||||
let source = r###"
|
let source = r###"
|
||||||
array (
|
array (
|
||||||
"double" => "quote",
|
"double" => "quote",
|
||||||
|
|
@ -17,8 +18,6 @@ fn main() {
|
||||||
)
|
)
|
||||||
"###;
|
"###;
|
||||||
|
|
||||||
match from_str::<Value>(source) {
|
println!("{:#?}", from_str::<Value>(source)?);
|
||||||
Ok(result) => print!("{:#?}", result),
|
Ok(())
|
||||||
Err(err) => eprint!("{}", err.with_source(source)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
405
src/error.rs
405
src/error.rs
|
|
@ -2,36 +2,30 @@ use crate::lexer::{SpannedToken, Token};
|
||||||
use crate::num::ParseIntError;
|
use crate::num::ParseIntError;
|
||||||
use crate::string::UnescapeError;
|
use crate::string::UnescapeError;
|
||||||
use logos::Span;
|
use logos::Span;
|
||||||
use source_span::{
|
use miette::{Diagnostic, SourceOffset, SourceSpan};
|
||||||
fmt::{Formatter, Style},
|
|
||||||
DefaultMetrics, Position, SourceBuffer, Span as SourceSpan,
|
|
||||||
};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{self, Debug, Display};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::num::ParseFloatError;
|
use std::num::ParseFloatError;
|
||||||
use std::str::ParseBoolError;
|
use std::str::ParseBoolError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// An error and related source span
|
#[derive(Error, Debug, Clone, Diagnostic)]
|
||||||
///
|
pub enum ParseError {
|
||||||
/// You can pretty-print the error with the offending source by using `with_source`
|
#[error(transparent)]
|
||||||
///
|
#[diagnostic(transparent)]
|
||||||
/// ## Example
|
UnexpectedToken(#[from] UnexpectedTokenError),
|
||||||
///
|
#[error(transparent)]
|
||||||
/// ```text
|
#[diagnostic(transparent)]
|
||||||
/// . |
|
InvalidPrimitive(#[from] PrimitiveError),
|
||||||
/// 2 | [
|
#[error("Array key not valid for this position")]
|
||||||
/// 3 | "broken"
|
#[diagnostic(code(php_object_parser::invalid_array_key))]
|
||||||
/// 4 | "array"
|
UnexpectedArrayKey(ArrayKeyError),
|
||||||
/// | ^^^^^^^^ Unexpected token, found LiteralString expected one of [SquareClose, Comma, Arrow]
|
#[error("Trailing characters after parsing")]
|
||||||
/// 5 | ]
|
#[diagnostic(code(php_object_parser::trailing))]
|
||||||
/// 6 |
|
TrailingCharacters,
|
||||||
/// ```
|
#[error("{0}")]
|
||||||
///
|
#[diagnostic(code(php_object_parser::other))]
|
||||||
#[derive(Debug, Clone)]
|
Custom(String),
|
||||||
pub struct ParseError {
|
|
||||||
span: Option<Span>,
|
|
||||||
error: RawParseError,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl serde::de::Error for ParseError {
|
impl serde::de::Error for ParseError {
|
||||||
|
|
@ -39,181 +33,85 @@ impl serde::de::Error for ParseError {
|
||||||
where
|
where
|
||||||
T: Display,
|
T: Display,
|
||||||
{
|
{
|
||||||
ParseError {
|
ParseError::Custom(msg.to_string())
|
||||||
span: None,
|
|
||||||
error: RawParseError::custom(msg),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseError {
|
#[derive(Debug, Clone, Diagnostic)]
|
||||||
pub fn new(error: RawParseError, span: Span) -> Self {
|
#[diagnostic(code(php_object_parser::unexpected_token))]
|
||||||
ParseError {
|
|
||||||
span: Some(span),
|
|
||||||
error,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(&self) -> &RawParseError {
|
|
||||||
&self.error
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_source(self, source: &str) -> SourceSpannedError {
|
|
||||||
SourceSpannedError {
|
|
||||||
span: self.span,
|
|
||||||
error: self.error,
|
|
||||||
source,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for ParseError {
|
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
||||||
Some(&self.error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ParseError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
<RawParseError as Display>::fmt(&self.error, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RawParseError> for ParseError {
|
|
||||||
fn from(err: RawParseError) -> Self {
|
|
||||||
ParseError {
|
|
||||||
span: None,
|
|
||||||
error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SourceSpannedError<'source> {
|
|
||||||
span: Option<Span>,
|
|
||||||
error: RawParseError,
|
|
||||||
source: &'source str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'source> SourceSpannedError<'source> {
|
|
||||||
pub fn into_inner(self) -> ParseError {
|
|
||||||
ParseError {
|
|
||||||
span: self.span,
|
|
||||||
error: self.error,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const METRICS: DefaultMetrics = DefaultMetrics::with_tab_stop(4);
|
|
||||||
|
|
||||||
impl<'source> Display for SourceSpannedError<'source> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.span.as_ref() {
|
|
||||||
Some(span) => {
|
|
||||||
let start = get_position(self.source, span.start);
|
|
||||||
let end = get_position(self.source, span.end);
|
|
||||||
let span = SourceSpan::new(start, end, end.next_line());
|
|
||||||
|
|
||||||
let mut fmt = Formatter::new();
|
|
||||||
let buffer = SourceBuffer::new(
|
|
||||||
self.source.chars().map(|char| Result::<char, ()>::Ok(char)),
|
|
||||||
Position::default(),
|
|
||||||
METRICS,
|
|
||||||
);
|
|
||||||
fmt.add(span, Some(format!("{}", self.error)), Style::Error);
|
|
||||||
let formatted = fmt
|
|
||||||
.render(
|
|
||||||
buffer.iter(),
|
|
||||||
SourceSpan::new(
|
|
||||||
Position::default(),
|
|
||||||
Position::new(usize::max_value() - 1, usize::max_value()),
|
|
||||||
Position::end(),
|
|
||||||
),
|
|
||||||
&METRICS,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
write!(f, "{}", formatted)?;
|
|
||||||
}
|
|
||||||
None => write!(f, "{}", self.error)?,
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_position(text: &str, index: usize) -> Position {
|
|
||||||
let mut pos = Position::default();
|
|
||||||
for char in text.chars().take(index) {
|
|
||||||
pos = pos.next(char, &METRICS);
|
|
||||||
}
|
|
||||||
|
|
||||||
pos
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug, Clone)]
|
|
||||||
pub enum RawParseError {
|
|
||||||
#[error("{0}")]
|
|
||||||
UnexpectedToken(#[from] UnexpectedTokenError),
|
|
||||||
#[error("Invalid boolean literal: {0}")]
|
|
||||||
InvalidBoolLiteral(#[from] ParseBoolError),
|
|
||||||
#[error("Invalid integer literal: {0}")]
|
|
||||||
InvalidIntLiteral(#[from] ParseIntError),
|
|
||||||
#[error("Invalid float literal: {0}")]
|
|
||||||
InvalidFloatLiteral(#[from] ParseFloatError),
|
|
||||||
#[error("Invalid string literal")]
|
|
||||||
InvalidStringLiteral,
|
|
||||||
#[error("Array key not valid for this position")]
|
|
||||||
UnexpectedArrayKey,
|
|
||||||
#[error("Trailing characters after parsing")]
|
|
||||||
TrailingCharacters,
|
|
||||||
#[error("{0}")]
|
|
||||||
Custom(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl serde::de::Error for RawParseError {
|
|
||||||
fn custom<T>(msg: T) -> Self
|
|
||||||
where
|
|
||||||
T: Display,
|
|
||||||
{
|
|
||||||
RawParseError::Custom(msg.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UnescapeError> for RawParseError {
|
|
||||||
fn from(_: UnescapeError) -> Self {
|
|
||||||
RawParseError::InvalidStringLiteral
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct UnexpectedTokenError {
|
pub struct UnexpectedTokenError {
|
||||||
pub expected: Vec<Token>,
|
src: String,
|
||||||
|
#[snippet(src)]
|
||||||
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("Expected {}", self.expected))]
|
||||||
|
err_span: SourceSpan,
|
||||||
|
pub expected: TokenList,
|
||||||
pub found: Option<Token>,
|
pub found: Option<Token>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnexpectedTokenError {
|
impl UnexpectedTokenError {
|
||||||
pub fn new(expected: &[Token], found: Option<Token>) -> Self {
|
pub fn new(
|
||||||
|
expected: &[Token],
|
||||||
|
found: Option<Token>,
|
||||||
|
src: String,
|
||||||
|
snip: SourceSpan,
|
||||||
|
err_span: SourceSpan,
|
||||||
|
) -> Self {
|
||||||
UnexpectedTokenError {
|
UnexpectedTokenError {
|
||||||
expected: expected.to_vec(),
|
src,
|
||||||
|
snip,
|
||||||
|
err_span,
|
||||||
|
expected: expected.into(),
|
||||||
found,
|
found,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TokenList(Vec<Token>);
|
||||||
|
|
||||||
|
impl Debug for TokenList {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[Token]> for TokenList {
|
||||||
|
fn from(list: &[Token]) -> Self {
|
||||||
|
TokenList(list.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for TokenList {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
if !self.0.is_empty() {
|
||||||
|
let mut tokens = self.0[0..self.0.len() - 1].iter();
|
||||||
|
write!(f, "{}", tokens.next().unwrap())?;
|
||||||
|
for token in tokens {
|
||||||
|
write!(f, ", {}", token)?;
|
||||||
|
}
|
||||||
|
if self.0.len() > 1 {
|
||||||
|
write!(f, " or {}", self.0.last().unwrap())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for UnexpectedTokenError {
|
impl Display for UnexpectedTokenError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.found {
|
match &self.found {
|
||||||
Some(Token::Error) => write!(
|
Some(Token::Error) => {
|
||||||
f,
|
write!(f, "No valid token found, expected one of {}", self.expected)
|
||||||
"No valid token found, expected one of {:?}",
|
}
|
||||||
self.expected
|
|
||||||
),
|
|
||||||
Some(token) => write!(
|
Some(token) => write!(
|
||||||
f,
|
f,
|
||||||
"Unexpected token, found {:?} expected one of {:?}",
|
"Unexpected token, found {} expected one of {}",
|
||||||
token, self.expected
|
token, self.expected
|
||||||
),
|
),
|
||||||
None => write!(
|
None => write!(
|
||||||
f,
|
f,
|
||||||
"Unexpected token, found None expected one of {:?}",
|
"Unexpected token, found None expected one of {}",
|
||||||
self.expected
|
self.expected
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
@ -222,55 +120,158 @@ impl Display for UnexpectedTokenError {
|
||||||
|
|
||||||
impl Error for UnexpectedTokenError {}
|
impl Error for UnexpectedTokenError {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[diagnostic(code(php_object_parser::invalid_primitive))]
|
||||||
|
#[error("{kind}")]
|
||||||
|
pub struct PrimitiveError {
|
||||||
|
src: String,
|
||||||
|
#[snippet(src)]
|
||||||
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("{}", self.kind.desc()))]
|
||||||
|
err_span: SourceSpan,
|
||||||
|
pub kind: PrimitiveErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug, Clone)]
|
||||||
|
pub enum PrimitiveErrorKind {
|
||||||
|
#[error("Invalid boolean literal: {0}")]
|
||||||
|
InvalidBoolLiteral(#[from] ParseBoolError),
|
||||||
|
#[error("Invalid integer literal: {0}")]
|
||||||
|
InvalidIntLiteral(#[from] ParseIntError),
|
||||||
|
#[error("Invalid float literal: {0}")]
|
||||||
|
InvalidFloatLiteral(#[from] ParseFloatError),
|
||||||
|
#[error("Invalid string literal")]
|
||||||
|
InvalidStringLiteral,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimitiveErrorKind {
|
||||||
|
pub fn desc(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
PrimitiveErrorKind::InvalidBoolLiteral(_) => "Not a boolean",
|
||||||
|
PrimitiveErrorKind::InvalidIntLiteral(err) => err.desc(),
|
||||||
|
PrimitiveErrorKind::InvalidFloatLiteral(_) => "Not a valid float",
|
||||||
|
PrimitiveErrorKind::InvalidStringLiteral => "Not a string literal",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UnescapeError> for PrimitiveErrorKind {
|
||||||
|
fn from(_: UnescapeError) -> Self {
|
||||||
|
PrimitiveErrorKind::InvalidStringLiteral
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[diagnostic(code(php_object_parser::invalid_array_key))]
|
||||||
|
#[error("Invalid array key")]
|
||||||
|
pub struct ArrayKeyError {
|
||||||
|
src: String,
|
||||||
|
#[snippet(src)]
|
||||||
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("This is the highlight"))]
|
||||||
|
err_span: SourceSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArrayKeyError {
|
||||||
|
pub fn new(source: &str, snip: Span, err_span: Span) -> Self {
|
||||||
|
ArrayKeyError {
|
||||||
|
src: source.into(),
|
||||||
|
snip: map_span(&snip),
|
||||||
|
err_span: map_span(&err_span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ExpectToken<'source> {
|
pub trait ExpectToken<'source> {
|
||||||
fn expect_token(self, expected: &[Token]) -> Result<SpannedToken<'source>, ParseError>;
|
fn expect_token(
|
||||||
|
self,
|
||||||
|
expected: &[Token],
|
||||||
|
source: &str,
|
||||||
|
) -> Result<SpannedToken<'source>, ParseError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'source> ExpectToken<'source> for Option<SpannedToken<'source>> {
|
impl<'source> ExpectToken<'source> for Option<SpannedToken<'source>> {
|
||||||
fn expect_token(self, expected: &[Token]) -> Result<SpannedToken<'source>, ParseError> {
|
fn expect_token(
|
||||||
self.ok_or_else(|| UnexpectedTokenError {
|
self,
|
||||||
expected: expected.to_vec(),
|
expected: &[Token],
|
||||||
found: None,
|
source: &str,
|
||||||
|
) -> Result<SpannedToken<'source>, ParseError> {
|
||||||
|
self.ok_or_else(|| {
|
||||||
|
UnexpectedTokenError::new(
|
||||||
|
expected,
|
||||||
|
None,
|
||||||
|
source.into(),
|
||||||
|
map_span(&(0..source.len())),
|
||||||
|
map_span(&(source.len()..source.len())),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
.with_span(usize::max_value()..usize::max_value())
|
.and_then(|token| token.expect_token(expected, source))
|
||||||
.and_then(|token| token.expect_token(expected))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'source> ExpectToken<'source> for Option<&'a SpannedToken<'source>> {
|
impl<'a, 'source> ExpectToken<'source> for Option<&'a SpannedToken<'source>> {
|
||||||
fn expect_token(self, expected: &[Token]) -> Result<SpannedToken<'source>, ParseError> {
|
fn expect_token(
|
||||||
self.ok_or_else(|| UnexpectedTokenError {
|
self,
|
||||||
expected: expected.to_vec(),
|
expected: &[Token],
|
||||||
found: None,
|
source: &str,
|
||||||
|
) -> Result<SpannedToken<'source>, ParseError> {
|
||||||
|
self.ok_or_else(|| {
|
||||||
|
UnexpectedTokenError::new(
|
||||||
|
expected,
|
||||||
|
None,
|
||||||
|
source.into(),
|
||||||
|
map_span(&(0..source.len())),
|
||||||
|
map_span(&(source.len()..source.len())),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
.with_span(usize::max_value()..usize::max_value())
|
.and_then(|token| token.clone().expect_token(expected, source))
|
||||||
.and_then(|token| token.clone().expect_token(expected))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'source> ExpectToken<'source> for SpannedToken<'source> {
|
impl<'source> ExpectToken<'source> for SpannedToken<'source> {
|
||||||
fn expect_token(self, expected: &[Token]) -> Result<SpannedToken<'source>, ParseError> {
|
fn expect_token(
|
||||||
|
self,
|
||||||
|
expected: &[Token],
|
||||||
|
source: &str,
|
||||||
|
) -> Result<SpannedToken<'source>, ParseError> {
|
||||||
if expected.iter().any(|expect| self.token.eq(expect)) {
|
if expected.iter().any(|expect| self.token.eq(expect)) {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
Err(UnexpectedTokenError {
|
Err(UnexpectedTokenError::new(
|
||||||
expected: expected.to_vec(),
|
expected,
|
||||||
found: Some(self.token),
|
Some(self.token),
|
||||||
})
|
source.into(),
|
||||||
.with_span(self.span)
|
map_span(&(0..source.len())),
|
||||||
|
map_span(&self.span),
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn map_span(span: &Span) -> SourceSpan {
|
||||||
|
SourceSpan::new(
|
||||||
|
SourceOffset::from(span.start),
|
||||||
|
SourceOffset::from(span.end - span.start),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ResultExt<T> {
|
pub trait ResultExt<T> {
|
||||||
fn with_span(self, span: Span) -> Result<T, ParseError>;
|
fn with_span(self, span: Span, source: &str) -> Result<T, ParseError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E: Into<RawParseError>> ResultExt<T> for Result<T, E> {
|
impl<T, E: Into<PrimitiveErrorKind>> ResultExt<T> for Result<T, E> {
|
||||||
fn with_span(self, span: Span) -> Result<T, ParseError> {
|
fn with_span(self, span: Span, source: &str) -> Result<T, ParseError> {
|
||||||
self.map_err(|error| ParseError {
|
self.map_err(|error| {
|
||||||
span: Some(span),
|
PrimitiveError {
|
||||||
error: error.into(),
|
src: source.into(),
|
||||||
|
snip: map_span(&(0..source.len())),
|
||||||
|
err_span: map_span(&span),
|
||||||
|
kind: error.into(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/lexer.rs
19
src/lexer.rs
|
|
@ -1,38 +1,53 @@
|
||||||
use logos::{Lexer, Logos, Span};
|
use logos::{Lexer, Logos, Span};
|
||||||
|
use parse_display::Display;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
#[derive(Logos, Debug, PartialEq, Clone, Copy)]
|
#[derive(Logos, Debug, PartialEq, Clone, Copy, Display)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
#[token("array")]
|
#[token("array")]
|
||||||
|
#[display("'array'")]
|
||||||
Array,
|
Array,
|
||||||
#[regex("(?i:true|false)")]
|
#[regex("(?i:true|false)")]
|
||||||
|
#[display("boolean literal")]
|
||||||
Bool,
|
Bool,
|
||||||
#[regex("null")]
|
#[token("null")]
|
||||||
|
#[display("'null'")]
|
||||||
Null,
|
Null,
|
||||||
#[token("=>")]
|
#[token("=>")]
|
||||||
|
#[display("'=>'")]
|
||||||
Arrow,
|
Arrow,
|
||||||
#[token("(")]
|
#[token("(")]
|
||||||
|
#[display("'('")]
|
||||||
BracketOpen,
|
BracketOpen,
|
||||||
#[token(")")]
|
#[token(")")]
|
||||||
|
#[display("')'")]
|
||||||
BracketClose,
|
BracketClose,
|
||||||
#[token("[")]
|
#[token("[")]
|
||||||
|
#[display("'['")]
|
||||||
SquareOpen,
|
SquareOpen,
|
||||||
#[token("]")]
|
#[token("]")]
|
||||||
|
#[display("']'")]
|
||||||
SquareClose,
|
SquareClose,
|
||||||
#[token(",")]
|
#[token(",")]
|
||||||
|
#[display("','")]
|
||||||
Comma,
|
Comma,
|
||||||
|
#[display("string literal")]
|
||||||
#[regex("(\"([^\"\\\\]|\\\\.)*\")|(\'([^\'\\\\]|\\\\.)*\')")]
|
#[regex("(\"([^\"\\\\]|\\\\.)*\")|(\'([^\'\\\\]|\\\\.)*\')")]
|
||||||
LiteralString,
|
LiteralString,
|
||||||
|
#[display("float literal")]
|
||||||
#[regex("-?((([0-9]+(_[0-9]+)*|([0-9]*(_[0-9]+)*[\\.][0-9]+(_[0-9]+)*)|([0-9]+(_[0-9]+)*[\\.][0-9]*(_[0-9]+)*)))[eE][+-]?[0-9]+(_[0-9]+)*|([0-9]*(_[0-9]+)*[\\.][0-9]+(_[0-9]+)*)|([0-9]+(_[0-9]+)*[\\.][0-9]*(_[0-9]+)*))")]
|
#[regex("-?((([0-9]+(_[0-9]+)*|([0-9]*(_[0-9]+)*[\\.][0-9]+(_[0-9]+)*)|([0-9]+(_[0-9]+)*[\\.][0-9]*(_[0-9]+)*)))[eE][+-]?[0-9]+(_[0-9]+)*|([0-9]*(_[0-9]+)*[\\.][0-9]+(_[0-9]+)*)|([0-9]+(_[0-9]+)*[\\.][0-9]*(_[0-9]+)*))")]
|
||||||
Float,
|
Float,
|
||||||
|
#[display("integer literal")]
|
||||||
#[regex("-?(0|[1-9][0-9]*(_[0-9]+)*|0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*|0[0-7]+(_[0-7]+)*|0[bB][01]+(_[01]+)*)")]
|
#[regex("-?(0|[1-9][0-9]*(_[0-9]+)*|0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*|0[0-7]+(_[0-7]+)*|0[bB][01]+(_[01]+)*)")]
|
||||||
Integer,
|
Integer,
|
||||||
#[token(";")]
|
#[token(";")]
|
||||||
|
#[display("';'")]
|
||||||
SemiColon,
|
SemiColon,
|
||||||
#[error]
|
#[error]
|
||||||
#[regex(r"(#|//)[^\n]*", logos::skip)]
|
#[regex(r"(#|//)[^\n]*", logos::skip)]
|
||||||
#[regex(r"/\*([^*]|\*[^/])+\*/", logos::skip)]
|
#[regex(r"/\*([^*]|\*[^/])+\*/", logos::skip)]
|
||||||
#[regex(r"[ \t\n\f]+", logos::skip)]
|
#[regex(r"[ \t\n\f]+", logos::skip)]
|
||||||
|
#[display("error")]
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ mod serde_impl;
|
||||||
mod string;
|
mod string;
|
||||||
|
|
||||||
use crate::string::is_array_key_numeric;
|
use crate::string::is_array_key_numeric;
|
||||||
pub use error::{ParseError, RawParseError};
|
pub use error::ParseError;
|
||||||
use serde::de::{self, MapAccess, SeqAccess, Visitor};
|
use serde::de::{self, MapAccess, SeqAccess, Visitor};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
pub use serde_impl::from_str;
|
pub use serde_impl::from_str;
|
||||||
|
|
|
||||||
12
src/num.rs
12
src/num.rs
|
|
@ -11,8 +11,18 @@ pub enum ParseIntError {
|
||||||
#[error("unexpected negative number")]
|
#[error("unexpected negative number")]
|
||||||
UnexpectedNegative,
|
UnexpectedNegative,
|
||||||
}
|
}
|
||||||
|
impl ParseIntError {
|
||||||
|
pub fn desc(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
ParseIntError::Empty => "Number expected",
|
||||||
|
ParseIntError::InvalidDigit => "Not a valid digit",
|
||||||
|
ParseIntError::Overflow => "Number to large",
|
||||||
|
ParseIntError::UnexpectedNegative => "Expected a positive number",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Mostly copied from std
|
/// Mostly copied from std, adjusted for php specifics
|
||||||
pub fn parse_int(src: &str) -> Result<i64, ParseIntError> {
|
pub fn parse_int(src: &str) -> Result<i64, ParseIntError> {
|
||||||
if src.is_empty() {
|
if src.is_empty() {
|
||||||
return Err(ParseIntError::Empty);
|
return Err(ParseIntError::Empty);
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,14 @@ use std::iter::Peekable;
|
||||||
use std::num::ParseFloatError;
|
use std::num::ParseFloatError;
|
||||||
|
|
||||||
pub struct Parser<'source> {
|
pub struct Parser<'source> {
|
||||||
|
source: &'source str,
|
||||||
tokens: Peekable<TokenStream<'source>>,
|
tokens: Peekable<TokenStream<'source>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'source> Parser<'source> {
|
impl<'source> Parser<'source> {
|
||||||
pub fn new(source: &'source str) -> Self {
|
pub fn new(source: &'source str) -> Self {
|
||||||
Parser {
|
Parser {
|
||||||
|
source,
|
||||||
tokens: TokenStream::new(Token::lexer(source)).peekable(),
|
tokens: TokenStream::new(Token::lexer(source)).peekable(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,29 +42,32 @@ impl<'source> Parser<'source> {
|
||||||
.slice()
|
.slice()
|
||||||
.to_ascii_lowercase()
|
.to_ascii_lowercase()
|
||||||
.parse()
|
.parse()
|
||||||
.with_span(token.span)
|
.with_span(token.span, token.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_int_token(&self, token: SpannedToken) -> Result<i64, ParseError> {
|
pub fn parse_int_token(&self, token: SpannedToken) -> Result<i64, ParseError> {
|
||||||
parse_int(token.slice()).with_span(token.span)
|
parse_int(token.slice()).with_span(token.span, token.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_float_token(&self, token: SpannedToken) -> Result<f64, ParseError> {
|
pub fn parse_float_token(&self, token: SpannedToken) -> Result<f64, ParseError> {
|
||||||
parse_float(token.slice()).with_span(token.span)
|
parse_float(token.slice()).with_span(token.span, token.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_string_token(&self, token: SpannedToken) -> Result<String, ParseError> {
|
pub fn parse_string_token(&self, token: SpannedToken) -> Result<String, ParseError> {
|
||||||
parse_string(token.slice()).with_span(token.span)
|
parse_string(token.slice()).with_span(token.span, token.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_array_key(&self, token: SpannedToken) -> Result<Key, ParseError> {
|
pub fn parse_array_key(&self, token: SpannedToken) -> Result<Key, ParseError> {
|
||||||
let token = token.expect_token(&[
|
let token = token.expect_token(
|
||||||
|
&[
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::Integer,
|
Token::Integer,
|
||||||
Token::Float,
|
Token::Float,
|
||||||
Token::LiteralString,
|
Token::LiteralString,
|
||||||
Token::Null,
|
Token::Null,
|
||||||
])?;
|
],
|
||||||
|
self.source,
|
||||||
|
)?;
|
||||||
Ok(match self.parse_literal(token)? {
|
Ok(match self.parse_literal(token)? {
|
||||||
Value::Int(int) => Key::Int(int),
|
Value::Int(int) => Key::Int(int),
|
||||||
Value::Float(float) => Key::Int(float as i64),
|
Value::Float(float) => Key::Int(float as i64),
|
||||||
|
|
@ -73,6 +78,10 @@ impl<'source> Parser<'source> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn source(&self) -> &'source str {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_float(literal: &str) -> Result<f64, ParseFloatError> {
|
fn parse_float(literal: &str) -> Result<f64, ParseFloatError> {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ use serde::de::{
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::error::{ExpectToken, ResultExt};
|
use crate::error::{ArrayKeyError, ExpectToken, ResultExt};
|
||||||
use crate::lexer::{SpannedToken, Token};
|
use crate::lexer::{SpannedToken, Token};
|
||||||
use crate::num::ParseIntError;
|
use crate::num::ParseIntError;
|
||||||
use crate::parser::{ArraySyntax, Parser};
|
use crate::parser::{ArraySyntax, Parser};
|
||||||
use crate::{Key, ParseError, RawParseError};
|
use crate::{Key, ParseError};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
|
@ -26,6 +26,10 @@ impl<'de> Deserializer<'de> {
|
||||||
peeked: Default::default(),
|
peeked: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn source(&self) -> &'de str {
|
||||||
|
self.parser.source()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a php literal
|
/// Parse a php literal
|
||||||
|
|
@ -58,7 +62,7 @@ where
|
||||||
token: Token::SemiColon,
|
token: Token::SemiColon,
|
||||||
..
|
..
|
||||||
}) => Ok(t),
|
}) => Ok(t),
|
||||||
Some(_) => Err(RawParseError::TrailingCharacters.into()),
|
Some(_) => Err(ParseError::TrailingCharacters.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +84,9 @@ impl<'de> Deserializer<'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bool(&mut self) -> Result<bool> {
|
fn parse_bool(&mut self) -> Result<bool> {
|
||||||
let token = self.next_token().expect_token(&[Token::Bool])?;
|
let token = self
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::Bool], self.source())?;
|
||||||
Ok(self.parser.parse_bool_token(token)?)
|
Ok(self.parser.parse_bool_token(token)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,22 +98,16 @@ impl<'de> Deserializer<'de> {
|
||||||
where
|
where
|
||||||
T: TryFrom<i64>,
|
T: TryFrom<i64>,
|
||||||
{
|
{
|
||||||
let token = self.next_token().expect_token(&[Token::Integer])?;
|
let token = self
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::Integer], self.source())?;
|
||||||
let span = token.span.clone();
|
let span = token.span.clone();
|
||||||
let int = self.parser.parse_int_token(token)?;
|
let int = self.parser.parse_int_token(token)?;
|
||||||
if int < 0 {
|
if int < 0 {
|
||||||
Err(ParseError::new(
|
Err(ParseIntError::UnexpectedNegative).with_span(span, self.source())
|
||||||
RawParseError::InvalidIntLiteral(ParseIntError::UnexpectedNegative),
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
} else {
|
} else {
|
||||||
Ok(T::try_from(int).map_err(|_| {
|
Ok(T::try_from(int)
|
||||||
ParseError::new(
|
.or_else(|_| Err(ParseIntError::Overflow).with_span(span, self.source()))?)
|
||||||
RawParseError::InvalidIntLiteral(ParseIntError::Overflow),
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,25 +115,25 @@ impl<'de> Deserializer<'de> {
|
||||||
where
|
where
|
||||||
T: TryFrom<i64>,
|
T: TryFrom<i64>,
|
||||||
{
|
{
|
||||||
let token = self.next_token().expect_token(&[Token::Integer])?;
|
let token = self
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::Integer], self.source())?;
|
||||||
let span = token.span.clone();
|
let span = token.span.clone();
|
||||||
Ok(
|
Ok(T::try_from(self.parser.parse_int_token(token)?)
|
||||||
T::try_from(self.parser.parse_int_token(token)?).map_err(|_| {
|
.or_else(|_| Err(ParseIntError::Overflow).with_span(span, self.source()))?)
|
||||||
ParseError::new(
|
|
||||||
RawParseError::InvalidIntLiteral(ParseIntError::Overflow),
|
|
||||||
span,
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_float(&mut self) -> Result<f64> {
|
fn parse_float(&mut self) -> Result<f64> {
|
||||||
let token = self.next_token().expect_token(&[Token::Float])?;
|
let token = self
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::Float], self.source())?;
|
||||||
Ok(self.parser.parse_float_token(token)?)
|
Ok(self.parser.parse_float_token(token)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_string(&mut self) -> Result<String> {
|
fn parse_string(&mut self) -> Result<String> {
|
||||||
let token = self.next_token().expect_token(&[Token::LiteralString])?;
|
let token = self
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::LiteralString], self.source())?;
|
||||||
Ok(self.parser.parse_string_token(token)?)
|
Ok(self.parser.parse_string_token(token)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +145,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let peek = self.peek_token().expect_token(&[
|
let source = self.source();
|
||||||
|
let peek = self.peek_token().expect_token(
|
||||||
|
&[
|
||||||
Token::Null,
|
Token::Null,
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::LiteralString,
|
Token::LiteralString,
|
||||||
|
|
@ -153,7 +155,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
Token::Float,
|
Token::Float,
|
||||||
Token::Array,
|
Token::Array,
|
||||||
Token::SquareOpen,
|
Token::SquareOpen,
|
||||||
])?;
|
],
|
||||||
|
source,
|
||||||
|
)?;
|
||||||
match peek.token {
|
match peek.token {
|
||||||
Token::Null => self.deserialize_unit(visitor),
|
Token::Null => self.deserialize_unit(visitor),
|
||||||
Token::Bool => self.deserialize_bool(visitor),
|
Token::Bool => self.deserialize_bool(visitor),
|
||||||
|
|
@ -300,7 +304,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let token = self.peek_token().expect_token(&[
|
let source = self.source();
|
||||||
|
let token = self.peek_token().expect_token(
|
||||||
|
&[
|
||||||
Token::Null,
|
Token::Null,
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::LiteralString,
|
Token::LiteralString,
|
||||||
|
|
@ -308,7 +314,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
Token::Float,
|
Token::Float,
|
||||||
Token::Array,
|
Token::Array,
|
||||||
Token::SquareOpen,
|
Token::SquareOpen,
|
||||||
])?;
|
],
|
||||||
|
source,
|
||||||
|
)?;
|
||||||
if token.token == Token::Null {
|
if token.token == Token::Null {
|
||||||
let _ = self.next_token();
|
let _ = self.next_token();
|
||||||
visitor.visit_none()
|
visitor.visit_none()
|
||||||
|
|
@ -321,7 +329,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.next_token().expect_token(&[Token::Null])?;
|
self.next_token()
|
||||||
|
.expect_token(&[Token::Null], self.source())?;
|
||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,10 +354,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
{
|
{
|
||||||
let token = self
|
let token = self
|
||||||
.next_token()
|
.next_token()
|
||||||
.expect_token(&[Token::Array, Token::SquareOpen])?;
|
.expect_token(&[Token::Array, Token::SquareOpen], self.source())?;
|
||||||
let syntax = match token.token {
|
let syntax = match token.token {
|
||||||
Token::Array => {
|
Token::Array => {
|
||||||
self.next_token().expect_token(&[Token::BracketOpen])?;
|
self.next_token()
|
||||||
|
.expect_token(&[Token::BracketOpen], self.source())?;
|
||||||
ArraySyntax::Long
|
ArraySyntax::Long
|
||||||
}
|
}
|
||||||
Token::SquareOpen => ArraySyntax::Short,
|
Token::SquareOpen => ArraySyntax::Short,
|
||||||
|
|
@ -384,10 +394,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
{
|
{
|
||||||
let token = self
|
let token = self
|
||||||
.next_token()
|
.next_token()
|
||||||
.expect_token(&[Token::Array, Token::SquareOpen])?;
|
.expect_token(&[Token::Array, Token::SquareOpen], self.source())?;
|
||||||
let syntax = match token.token {
|
let syntax = match token.token {
|
||||||
Token::Array => {
|
Token::Array => {
|
||||||
self.next_token().expect_token(&[Token::BracketOpen])?;
|
self.next_token()
|
||||||
|
.expect_token(&[Token::BracketOpen], self.source())?;
|
||||||
ArraySyntax::Long
|
ArraySyntax::Long
|
||||||
}
|
}
|
||||||
Token::SquareOpen => ArraySyntax::Short,
|
Token::SquareOpen => ArraySyntax::Short,
|
||||||
|
|
@ -419,25 +430,26 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
// panic!("a");
|
let source = self.source();
|
||||||
let token = self.peek_token().expect_token(&[
|
let token = self.peek_token().expect_token(
|
||||||
Token::LiteralString,
|
&[Token::LiteralString, Token::Array, Token::SquareOpen],
|
||||||
Token::Array,
|
source,
|
||||||
Token::SquareOpen,
|
)?;
|
||||||
])?;
|
|
||||||
match token.token {
|
match token.token {
|
||||||
Token::LiteralString => visitor.visit_enum(self.parse_string()?.into_deserializer()),
|
Token::LiteralString => visitor.visit_enum(self.parse_string()?.into_deserializer()),
|
||||||
Token::Array | Token::SquareOpen => {
|
Token::Array | Token::SquareOpen => {
|
||||||
self.eat_token();
|
self.eat_token();
|
||||||
let syntax = if token.token == Token::Array {
|
let syntax = if token.token == Token::Array {
|
||||||
self.next_token().expect_token(&[Token::BracketOpen])?;
|
self.next_token()
|
||||||
|
.expect_token(&[Token::BracketOpen], self.source())?;
|
||||||
ArraySyntax::Long
|
ArraySyntax::Long
|
||||||
} else {
|
} else {
|
||||||
ArraySyntax::Short
|
ArraySyntax::Short
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = visitor.visit_enum(Enum::new(self))?;
|
let value = visitor.visit_enum(Enum::new(self))?;
|
||||||
self.next_token().expect_token(&[syntax.close_bracket()])?;
|
self.next_token()
|
||||||
|
.expect_token(&[syntax.close_bracket()], self.source())?;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
@ -475,6 +487,10 @@ impl<'source, 'a> ArrayWalker<'source, 'a> {
|
||||||
done: false,
|
done: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> &'source str {
|
||||||
|
self.de.source()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, 'a> SeqAccess<'de> for ArrayWalker<'de, 'a> {
|
impl<'de, 'a> SeqAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
|
|
@ -488,7 +504,8 @@ impl<'de, 'a> SeqAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = self.de.next_token().expect_token(&[
|
let token = self.de.next_token().expect_token(
|
||||||
|
&[
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::Integer,
|
Token::Integer,
|
||||||
Token::Float,
|
Token::Float,
|
||||||
|
|
@ -497,18 +514,19 @@ impl<'de, 'a> SeqAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
Token::Array,
|
Token::Array,
|
||||||
Token::SquareOpen,
|
Token::SquareOpen,
|
||||||
self.syntax.close_bracket(),
|
self.syntax.close_bracket(),
|
||||||
])?;
|
],
|
||||||
|
self.source(),
|
||||||
|
)?;
|
||||||
|
|
||||||
if token.token == self.syntax.close_bracket() {
|
if token.token == self.syntax.close_bracket() {
|
||||||
self.done = true;
|
self.done = true;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = self.de.next_token().expect_token(&[
|
let next = self.de.next_token().expect_token(
|
||||||
self.syntax.close_bracket(),
|
&[self.syntax.close_bracket(), Token::Comma, Token::Arrow],
|
||||||
Token::Comma,
|
self.source(),
|
||||||
Token::Arrow,
|
)?;
|
||||||
])?;
|
|
||||||
|
|
||||||
let value_token = match next.token.clone() {
|
let value_token = match next.token.clone() {
|
||||||
Token::Comma => token,
|
Token::Comma => token,
|
||||||
|
|
@ -517,10 +535,15 @@ impl<'de, 'a> SeqAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
let key = self.de.parser.parse_array_key(token)?;
|
let key = self.de.parser.parse_array_key(token)?;
|
||||||
match key {
|
match key {
|
||||||
Key::Int(key) if key == self.next_int_key => Ok(()),
|
Key::Int(key) if key == self.next_int_key => Ok(()),
|
||||||
_ => Err(RawParseError::UnexpectedArrayKey).with_span(span),
|
_ => Err(ParseError::UnexpectedArrayKey(ArrayKeyError::new(
|
||||||
|
self.source(),
|
||||||
|
span.clone(),
|
||||||
|
span,
|
||||||
|
))),
|
||||||
}?;
|
}?;
|
||||||
self.next_int_key += 1;
|
self.next_int_key += 1;
|
||||||
let value = self.de.next_token().expect_token(&[
|
let value = self.de.next_token().expect_token(
|
||||||
|
&[
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::Integer,
|
Token::Integer,
|
||||||
Token::Float,
|
Token::Float,
|
||||||
|
|
@ -528,11 +551,13 @@ impl<'de, 'a> SeqAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
Token::Null,
|
Token::Null,
|
||||||
Token::Array,
|
Token::Array,
|
||||||
Token::SquareOpen,
|
Token::SquareOpen,
|
||||||
])?;
|
],
|
||||||
|
self.source(),
|
||||||
|
)?;
|
||||||
let next = self
|
let next = self
|
||||||
.de
|
.de
|
||||||
.next_token()
|
.next_token()
|
||||||
.expect_token(&[Token::Comma, self.syntax.close_bracket()])?;
|
.expect_token(&[Token::Comma, self.syntax.close_bracket()], self.source())?;
|
||||||
if next.token == self.syntax.close_bracket() {
|
if next.token == self.syntax.close_bracket() {
|
||||||
self.done = true;
|
self.done = true;
|
||||||
}
|
}
|
||||||
|
|
@ -562,25 +587,27 @@ impl<'de, 'a> MapAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = self.de.next_token().expect_token(&[
|
let token = self.de.next_token().expect_token(
|
||||||
|
&[
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::Integer,
|
Token::Integer,
|
||||||
Token::Float,
|
Token::Float,
|
||||||
Token::LiteralString,
|
Token::LiteralString,
|
||||||
Token::Null,
|
Token::Null,
|
||||||
self.syntax.close_bracket(),
|
self.syntax.close_bracket(),
|
||||||
])?;
|
],
|
||||||
|
self.source(),
|
||||||
|
)?;
|
||||||
|
|
||||||
if token.token == self.syntax.close_bracket() {
|
if token.token == self.syntax.close_bracket() {
|
||||||
self.done = true;
|
self.done = true;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = self.de.next_token().expect_token(&[
|
let next = self.de.next_token().expect_token(
|
||||||
Token::Arrow,
|
&[Token::Arrow, Token::Comma, self.syntax.close_bracket()],
|
||||||
Token::Comma,
|
self.source(),
|
||||||
self.syntax.close_bracket(),
|
)?;
|
||||||
])?;
|
|
||||||
|
|
||||||
match next.token {
|
match next.token {
|
||||||
Token::Arrow => {
|
Token::Arrow => {
|
||||||
|
|
@ -607,7 +634,9 @@ impl<'de, 'a> MapAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
where
|
where
|
||||||
V: DeserializeSeed<'de>,
|
V: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
self.de.peek_token().expect_token(&[
|
let source = self.source();
|
||||||
|
self.de.peek_token().expect_token(
|
||||||
|
&[
|
||||||
Token::Bool,
|
Token::Bool,
|
||||||
Token::Integer,
|
Token::Integer,
|
||||||
Token::Float,
|
Token::Float,
|
||||||
|
|
@ -615,7 +644,9 @@ impl<'de, 'a> MapAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
Token::Null,
|
Token::Null,
|
||||||
Token::Array,
|
Token::Array,
|
||||||
Token::SquareOpen,
|
Token::SquareOpen,
|
||||||
])?;
|
],
|
||||||
|
source,
|
||||||
|
)?;
|
||||||
|
|
||||||
// Deserialize a map key.
|
// Deserialize a map key.
|
||||||
let value = seed.deserialize(&mut *self.de)?;
|
let value = seed.deserialize(&mut *self.de)?;
|
||||||
|
|
@ -623,7 +654,7 @@ impl<'de, 'a> MapAccess<'de> for ArrayWalker<'de, 'a> {
|
||||||
let next = self
|
let next = self
|
||||||
.de
|
.de
|
||||||
.next_token()
|
.next_token()
|
||||||
.expect_token(&[Token::Comma, self.syntax.close_bracket()])?;
|
.expect_token(&[Token::Comma, self.syntax.close_bracket()], self.source())?;
|
||||||
|
|
||||||
if next.token == self.syntax.close_bracket() {
|
if next.token == self.syntax.close_bracket() {
|
||||||
self.done = true;
|
self.done = true;
|
||||||
|
|
@ -640,6 +671,10 @@ impl<'a, 'de> Enum<'a, 'de> {
|
||||||
fn new(de: &'a mut Deserializer<'de>) -> Self {
|
fn new(de: &'a mut Deserializer<'de>) -> Self {
|
||||||
Enum { de }
|
Enum { de }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> &'de str {
|
||||||
|
self.de.source()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `EnumAccess` is provided to the `Visitor` to give it the ability to determine
|
// `EnumAccess` is provided to the `Visitor` to give it the ability to determine
|
||||||
|
|
@ -656,7 +691,9 @@ impl<'de, 'a> EnumAccess<'de> for Enum<'a, 'de> {
|
||||||
V: DeserializeSeed<'de>,
|
V: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
let val = seed.deserialize(&mut *self.de)?;
|
let val = seed.deserialize(&mut *self.de)?;
|
||||||
self.de.next_token().expect_token(&[Token::Arrow])?;
|
self.de
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::Arrow], self.source())?;
|
||||||
Ok((val, self))
|
Ok((val, self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -667,7 +704,9 @@ impl<'de, 'a> VariantAccess<'de> for Enum<'a, 'de> {
|
||||||
type Error = ParseError;
|
type Error = ParseError;
|
||||||
|
|
||||||
fn unit_variant(self) -> Result<()> {
|
fn unit_variant(self) -> Result<()> {
|
||||||
self.de.next_token().expect_token(&[Token::LiteralString])?;
|
self.de
|
||||||
|
.next_token()
|
||||||
|
.expect_token(&[Token::LiteralString], self.source())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue