mirror of
https://codeberg.org/icewind/php-literal-parser.git
synced 2026-06-03 10:34:08 +02:00
Revert "switch back to source-span for now"
This reverts commit 9310fcde66.
This commit is contained in:
parent
ba0538194b
commit
e5d94364cc
4 changed files with 86 additions and 129 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "php-literal-parser"
|
name = "php-literal-parser"
|
||||||
description = "parser for php literals"
|
description = "parser for php literals"
|
||||||
version = "0.3.0"
|
version = "0.2.11"
|
||||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
@ -13,7 +13,7 @@ logos = "0.12"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
memchr = "2.3.4"
|
memchr = "2.3.4"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
source-span = { version = "=2.2.1", default-features = false }
|
miette = { version = "1" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use main_error::MainError;
|
use miette::DiagnosticResult;
|
||||||
use php_literal_parser::from_str;
|
use php_literal_parser::from_str;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ struct Target {
|
||||||
bars: Vec<u8>,
|
bars: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
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,7 +1,7 @@
|
||||||
use main_error::MainError;
|
use miette::DiagnosticResult;
|
||||||
use php_literal_parser::{from_str, Value};
|
use php_literal_parser::{from_str, Value};
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
fn main() -> DiagnosticResult<()> {
|
||||||
let source = r###"
|
let source = r###"
|
||||||
array (
|
array (
|
||||||
"double" => "quote",
|
"double" => "quote",
|
||||||
|
|
|
||||||
203
src/error.rs
203
src/error.rs
|
|
@ -2,32 +2,34 @@ 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;
|
||||||
|
|
||||||
/// Any error that occurred while trying to parse the php literal
|
/// Any error that occurred while trying to parse the php literal
|
||||||
#[derive(Error, Debug, Clone)]
|
#[derive(Error, Debug, Clone, Diagnostic)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
/// A token that wasn't expected was found while parsing
|
/// A token that wasn't expected was found while parsing
|
||||||
UnexpectedToken(#[from] UnexpectedTokenError),
|
UnexpectedToken(#[from] UnexpectedTokenError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
/// A malformed integer, float, boolean or string literal was found
|
/// A malformed integer, float, boolean or string literal was found
|
||||||
InvalidPrimitive(#[from] PrimitiveError),
|
InvalidPrimitive(#[from] PrimitiveError),
|
||||||
#[error(transparent)]
|
#[error("Array key not valid for this position")]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
/// An array key was found that is invalid for this position
|
/// An array key was found that is invalid for this position
|
||||||
UnexpectedArrayKey(ArrayKeyError),
|
UnexpectedArrayKey(ArrayKeyError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
#[diagnostic(transparent)]
|
||||||
/// Trailing characters after parsing
|
/// Trailing characters after parsing
|
||||||
TrailingCharacters(#[from] TrailingError),
|
TrailingCharacters(#[from] TrailingError),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
#[diagnostic(code(php_literal_parser::serde))]
|
||||||
/// Error while populating serde type
|
/// Error while populating serde type
|
||||||
Serde(String),
|
Serde(String),
|
||||||
}
|
}
|
||||||
|
|
@ -42,41 +44,25 @@ impl serde::de::Error for ParseError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A token that wasn't expected was found while parsing
|
/// A token that wasn't expected was found while parsing
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Diagnostic)]
|
||||||
|
#[diagnostic(code(php_literal_parser::unexpected_token))]
|
||||||
pub struct UnexpectedTokenError {
|
pub struct UnexpectedTokenError {
|
||||||
src: String,
|
src: String,
|
||||||
snip: Span,
|
#[snippet(src)]
|
||||||
err_span: Span,
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("Expected {}", self.expected))]
|
||||||
|
err_span: SourceSpan,
|
||||||
pub expected: TokenList,
|
pub expected: TokenList,
|
||||||
pub found: Option<Token>,
|
pub found: Option<Token>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for UnexpectedTokenError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let err = match &self.found {
|
|
||||||
Some(Token::Error) => {
|
|
||||||
format!("No valid token found, expected one of {}", self.expected)
|
|
||||||
}
|
|
||||||
Some(token) => format!(
|
|
||||||
"Unexpected token, found {} expected one of {}",
|
|
||||||
token, self.expected
|
|
||||||
),
|
|
||||||
None => format!(
|
|
||||||
"Unexpected token, found None expected one of {}",
|
|
||||||
self.expected
|
|
||||||
),
|
|
||||||
};
|
|
||||||
fmt_spanned(f, err, self.err_span.clone(), &self.src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnexpectedTokenError {
|
impl UnexpectedTokenError {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
expected: &[Token],
|
expected: &[Token],
|
||||||
found: Option<Token>,
|
found: Option<Token>,
|
||||||
src: String,
|
src: String,
|
||||||
snip: Span,
|
snip: SourceSpan,
|
||||||
err_span: Span,
|
err_span: SourceSpan,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
UnexpectedTokenError {
|
UnexpectedTokenError {
|
||||||
src,
|
src,
|
||||||
|
|
@ -93,7 +79,7 @@ impl UnexpectedTokenError {
|
||||||
pub struct TokenList(Vec<Token>);
|
pub struct TokenList(Vec<Token>);
|
||||||
|
|
||||||
impl Debug for TokenList {
|
impl Debug for TokenList {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +91,7 @@ impl From<&[Token]> for TokenList {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TokenList {
|
impl Display for TokenList {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self.0.len() {
|
match self.0.len() {
|
||||||
0 => {}
|
0 => {}
|
||||||
1 => write!(f, "{}", self.0[0])?,
|
1 => write!(f, "{}", self.0[0])?,
|
||||||
|
|
@ -124,14 +110,38 @@ impl Display for TokenList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for UnexpectedTokenError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match &self.found {
|
||||||
|
Some(Token::Error) => {
|
||||||
|
write!(f, "No valid token found, expected one of {}", self.expected)
|
||||||
|
}
|
||||||
|
Some(token) => write!(
|
||||||
|
f,
|
||||||
|
"Unexpected token, found {} expected one of {}",
|
||||||
|
token, self.expected
|
||||||
|
),
|
||||||
|
None => write!(
|
||||||
|
f,
|
||||||
|
"Unexpected token, found None expected one of {}",
|
||||||
|
self.expected
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Error for UnexpectedTokenError {}
|
impl Error for UnexpectedTokenError {}
|
||||||
|
|
||||||
/// A malformed integer, float, boolean or string literal was found
|
/// A malformed integer, float, boolean or string literal was found
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[diagnostic(code(php_literal_parser::invalid_primitive))]
|
||||||
|
#[error("{kind}")]
|
||||||
pub struct PrimitiveError {
|
pub struct PrimitiveError {
|
||||||
src: String,
|
src: String,
|
||||||
snip: Span,
|
#[snippet(src)]
|
||||||
err_span: Span,
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("{}", self.kind.desc()))]
|
||||||
|
err_span: SourceSpan,
|
||||||
pub kind: PrimitiveErrorKind,
|
pub kind: PrimitiveErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,15 +157,6 @@ pub enum PrimitiveErrorKind {
|
||||||
InvalidStringLiteral,
|
InvalidStringLiteral,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PrimitiveError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let err = format!("{}", self.kind);
|
|
||||||
fmt_spanned(f, err, self.err_span.clone(), &self.src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for PrimitiveError {}
|
|
||||||
|
|
||||||
impl PrimitiveErrorKind {
|
impl PrimitiveErrorKind {
|
||||||
pub fn desc(&self) -> &str {
|
pub fn desc(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -173,11 +174,15 @@ impl From<UnescapeError> for PrimitiveErrorKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[diagnostic(code(php_literal_parser::invalid_array_key))]
|
||||||
|
#[error("Invalid array key")]
|
||||||
pub struct ArrayKeyError {
|
pub struct ArrayKeyError {
|
||||||
src: String,
|
src: String,
|
||||||
snip: Span,
|
#[snippet(src)]
|
||||||
err_span: Span,
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("{}", self.kind))]
|
||||||
|
err_span: SourceSpan,
|
||||||
kind: ArrayKeyErrorKind,
|
kind: ArrayKeyErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,7 +193,7 @@ pub enum ArrayKeyErrorKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ArrayKeyErrorKind {
|
impl Display for ArrayKeyErrorKind {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
|
|
@ -200,56 +205,38 @@ impl Display for ArrayKeyErrorKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ArrayKeyError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let err = format!("{}", self.kind);
|
|
||||||
fmt_spanned(f, err, self.err_span.clone(), &self.src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for ArrayKeyError {}
|
|
||||||
|
|
||||||
impl ArrayKeyError {
|
impl ArrayKeyError {
|
||||||
pub fn new(kind: ArrayKeyErrorKind, source: &str, err_span: Span) -> Self {
|
pub fn new(kind: ArrayKeyErrorKind, source: &str, err_span: Span) -> Self {
|
||||||
ArrayKeyError {
|
ArrayKeyError {
|
||||||
src: source.into(),
|
src: source.into(),
|
||||||
snip: (0..source.len()),
|
snip: map_span(&(0..source.len())),
|
||||||
err_span,
|
err_span: map_span(&err_span),
|
||||||
kind,
|
kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||||
|
#[diagnostic(code(php_literal_parser::trailing))]
|
||||||
|
#[error("Trailing characters after parsing")]
|
||||||
pub struct TrailingError {
|
pub struct TrailingError {
|
||||||
src: String,
|
src: String,
|
||||||
snip: Span,
|
#[snippet(src)]
|
||||||
err_span: Span,
|
snip: SourceSpan,
|
||||||
|
#[highlight(snip, label("end of parsed value"))]
|
||||||
|
err_span: SourceSpan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrailingError {
|
impl TrailingError {
|
||||||
pub fn new(source: &str, err_span: Span) -> Self {
|
pub fn new(source: &str, err_span: Span) -> Self {
|
||||||
TrailingError {
|
TrailingError {
|
||||||
src: source.into(),
|
src: source.into(),
|
||||||
snip: (0..source.len()),
|
snip: map_span(&(0..source.len())),
|
||||||
err_span,
|
err_span: map_span(&err_span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TrailingError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt_spanned(
|
|
||||||
f,
|
|
||||||
format!("end of parsed value"),
|
|
||||||
self.err_span.clone(),
|
|
||||||
&self.src,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for TrailingError {}
|
|
||||||
|
|
||||||
pub trait ExpectToken<'source> {
|
pub trait ExpectToken<'source> {
|
||||||
fn expect_token(
|
fn expect_token(
|
||||||
self,
|
self,
|
||||||
|
|
@ -269,8 +256,8 @@ impl<'source> ExpectToken<'source> for Option<SpannedToken<'source>> {
|
||||||
expected,
|
expected,
|
||||||
None,
|
None,
|
||||||
source.into(),
|
source.into(),
|
||||||
0..source.len(),
|
map_span(&(0..source.len())),
|
||||||
source.len()..source.len(),
|
map_span(&(source.len()..source.len())),
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
|
|
@ -289,8 +276,8 @@ impl<'a, 'source> ExpectToken<'source> for Option<&'a SpannedToken<'source>> {
|
||||||
expected,
|
expected,
|
||||||
None,
|
None,
|
||||||
source.into(),
|
source.into(),
|
||||||
0..source.len(),
|
map_span(&(0..source.len())),
|
||||||
source.len()..source.len(),
|
map_span(&(source.len()..source.len())),
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
|
|
@ -311,14 +298,21 @@ impl<'source> ExpectToken<'source> for SpannedToken<'source> {
|
||||||
expected,
|
expected,
|
||||||
Some(self.token),
|
Some(self.token),
|
||||||
source.into(),
|
source.into(),
|
||||||
0..source.len(),
|
map_span(&(0..source.len())),
|
||||||
self.span,
|
map_span(&self.span),
|
||||||
)
|
)
|
||||||
.into())
|
.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, source: &str) -> Result<T, ParseError>;
|
fn with_span(self, span: Span, source: &str) -> Result<T, ParseError>;
|
||||||
}
|
}
|
||||||
|
|
@ -328,48 +322,11 @@ impl<T, E: Into<PrimitiveErrorKind>> ResultExt<T> for Result<T, E> {
|
||||||
self.map_err(|error| {
|
self.map_err(|error| {
|
||||||
PrimitiveError {
|
PrimitiveError {
|
||||||
src: source.into(),
|
src: source.into(),
|
||||||
snip: (0..source.len()),
|
snip: map_span(&(0..source.len())),
|
||||||
err_span: span,
|
err_span: map_span(&span),
|
||||||
kind: error.into(),
|
kind: error.into(),
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
const METRICS: DefaultMetrics = DefaultMetrics::with_tab_stop(4);
|
|
||||||
|
|
||||||
fn fmt_spanned(f: &mut fmt::Formatter<'_>, err: String, span: Span, source: &str) -> fmt::Result {
|
|
||||||
let start = get_position(source, span.start);
|
|
||||||
let end = get_position(source, span.end);
|
|
||||||
let span = SourceSpan::new(start, end, end.next_line());
|
|
||||||
|
|
||||||
let mut fmt = Formatter::new();
|
|
||||||
let buffer = SourceBuffer::new(
|
|
||||||
source.chars().map(|char| Result::<char, ()>::Ok(char)),
|
|
||||||
Position::default(),
|
|
||||||
METRICS,
|
|
||||||
);
|
|
||||||
fmt.add(span, Some(format!("{}", err)), 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)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue