switch back to source-span for now

This commit is contained in:
Robin Appelman 2021-09-09 15:59:22 +02:00
commit 9310fcde66
4 changed files with 133 additions and 85 deletions

View file

@ -13,9 +13,14 @@ logos = "0.12"
thiserror = "1.0" thiserror = "1.0"
memchr = "2.3.4" memchr = "2.3.4"
serde = "1.0" serde = "1.0"
miette = { version = "1" } source-span = { version = "=2.2.1", default-features = false }
parse-display = "0.5" parse-display = "0.5"
[dev-dependencies] [dev-dependencies]
maplit = "1.0.2" maplit = "1.0.2"
serde_derive = "1.0" serde_derive = "1.0"
main_error = "0.1"
[features]
default = ["colors"]
colors = ["source-span/colors"]

View file

@ -1,4 +1,4 @@
use miette::DiagnosticResult; use main_error::MainError;
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() -> DiagnosticResult<()> { fn main() -> Result<(), MainError> {
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!(

View file

@ -1,7 +1,7 @@
use miette::DiagnosticResult; use main_error::MainError;
use php_literal_parser::{from_str, Value}; use php_literal_parser::{from_str, Value};
fn main() -> DiagnosticResult<()> { fn main() -> Result<(), MainError> {
let source = r###" let source = r###"
array ( array (
"double" => "quote", "double" => "quote",

View file

@ -2,34 +2,32 @@ 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 miette::{Diagnostic, SourceOffset, SourceSpan}; use source_span::{
fmt::{Formatter, Style},
DefaultMetrics, Position, SourceBuffer, Span as SourceSpan,
};
use std::error::Error; use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display};
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, Diagnostic)] #[derive(Error, Debug, Clone)]
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("Array key not valid for this position")] #[error(transparent)]
#[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),
} }
@ -44,25 +42,41 @@ 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, Diagnostic)] #[derive(Debug, Clone)]
#[diagnostic(code(php_literal_parser::unexpected_token))]
pub struct UnexpectedTokenError { pub struct UnexpectedTokenError {
src: String, src: String,
#[snippet(src)] snip: Span,
snip: SourceSpan, err_span: Span,
#[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: SourceSpan, snip: Span,
err_span: SourceSpan, err_span: Span,
) -> Self { ) -> Self {
UnexpectedTokenError { UnexpectedTokenError {
src, src,
@ -79,7 +93,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 Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f) self.0.fmt(f)
} }
} }
@ -91,7 +105,7 @@ impl From<&[Token]> for TokenList {
} }
impl Display for TokenList { impl Display for TokenList {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::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])?,
@ -110,38 +124,14 @@ 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, Error, Diagnostic)] #[derive(Debug, Clone)]
#[diagnostic(code(php_literal_parser::invalid_primitive))]
#[error("{kind}")]
pub struct PrimitiveError { pub struct PrimitiveError {
src: String, src: String,
#[snippet(src)] snip: Span,
snip: SourceSpan, err_span: Span,
#[highlight(snip, label("{}", self.kind.desc()))]
err_span: SourceSpan,
pub kind: PrimitiveErrorKind, pub kind: PrimitiveErrorKind,
} }
@ -157,6 +147,15 @@ 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 {
@ -174,15 +173,11 @@ impl From<UnescapeError> for PrimitiveErrorKind {
} }
} }
#[derive(Debug, Clone, Error, Diagnostic)] #[derive(Debug, Clone)]
#[diagnostic(code(php_literal_parser::invalid_array_key))]
#[error("Invalid array key")]
pub struct ArrayKeyError { pub struct ArrayKeyError {
src: String, src: String,
#[snippet(src)] snip: Span,
snip: SourceSpan, err_span: Span,
#[highlight(snip, label("{}", self.kind))]
err_span: SourceSpan,
kind: ArrayKeyErrorKind, kind: ArrayKeyErrorKind,
} }
@ -193,7 +188,7 @@ pub enum ArrayKeyErrorKind {
} }
impl Display for ArrayKeyErrorKind { impl Display for ArrayKeyErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"{}", "{}",
@ -205,38 +200,56 @@ 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: map_span(&(0..source.len())), snip: (0..source.len()),
err_span: map_span(&err_span), err_span,
kind, kind,
} }
} }
} }
#[derive(Debug, Clone, Error, Diagnostic)] #[derive(Debug, Clone)]
#[diagnostic(code(php_literal_parser::trailing))]
#[error("Trailing characters after parsing")]
pub struct TrailingError { pub struct TrailingError {
src: String, src: String,
#[snippet(src)] snip: Span,
snip: SourceSpan, err_span: Span,
#[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: map_span(&(0..source.len())), snip: (0..source.len()),
err_span: map_span(&err_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,
@ -256,8 +269,8 @@ impl<'source> ExpectToken<'source> for Option<SpannedToken<'source>> {
expected, expected,
None, None,
source.into(), source.into(),
map_span(&(0..source.len())), 0..source.len(),
map_span(&(source.len()..source.len())), source.len()..source.len(),
) )
.into() .into()
}) })
@ -276,8 +289,8 @@ impl<'a, 'source> ExpectToken<'source> for Option<&'a SpannedToken<'source>> {
expected, expected,
None, None,
source.into(), source.into(),
map_span(&(0..source.len())), 0..source.len(),
map_span(&(source.len()..source.len())), source.len()..source.len(),
) )
.into() .into()
}) })
@ -298,21 +311,14 @@ impl<'source> ExpectToken<'source> for SpannedToken<'source> {
expected, expected,
Some(self.token), Some(self.token),
source.into(), source.into(),
map_span(&(0..source.len())), 0..source.len(),
map_span(&self.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>;
} }
@ -322,11 +328,48 @@ 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: map_span(&(0..source.len())), snip: (0..source.len()),
err_span: map_span(&span), err_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)
}