Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #95 from Kiwifuit/master
An Error Type for `Selector::parse`
- Loading branch information
Showing
4 changed files
with
220 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
//! Custom error types for diagnostics | ||
//! Includes re-exported error types from dependencies | ||
|
||
mod utils; | ||
|
||
use std::{error::Error, fmt::Display}; | ||
|
||
use cssparser::{BasicParseErrorKind, ParseErrorKind, Token}; | ||
use selectors::parser::SelectorParseErrorKind; | ||
|
||
/// Error type that is returned when calling `Selector::parse` | ||
#[derive(Debug, Clone)] | ||
pub enum SelectorErrorKind<'a> { | ||
/// A `Token` was not expected | ||
UnexpectedToken(Token<'a>), | ||
|
||
/// End-Of-Line was unexpected | ||
EndOfLine, | ||
|
||
/// `@` rule is invalid | ||
InvalidAtRule(String), | ||
|
||
/// The body of an `@` rule is invalid | ||
InvalidAtRuleBody, | ||
|
||
/// The qualified rule is invalid | ||
QualRuleInvalid, | ||
|
||
/// Expected a `::` for a pseudoelement | ||
ExpectedColonOnPseudoElement(Token<'a>), | ||
|
||
/// Expected an identity for a pseudoelement | ||
ExpectedIdentityOnPseudoElement(Token<'a>), | ||
|
||
/// A `SelectorParseErrorKind` error that isn't really supposed to happen did | ||
UnexpectedSelectorParseError(SelectorParseErrorKind<'a>), | ||
} | ||
|
||
impl<'a> From<cssparser::ParseError<'a, SelectorParseErrorKind<'a>>> for SelectorErrorKind<'a> { | ||
fn from(original: cssparser::ParseError<'a, SelectorParseErrorKind<'a>>) -> Self { | ||
// NOTE: This could be improved, but I dont | ||
// exactly know how | ||
match original.kind { | ||
ParseErrorKind::Basic(err) => SelectorErrorKind::from(err), | ||
ParseErrorKind::Custom(err) => SelectorErrorKind::from(err), | ||
} | ||
} | ||
} | ||
|
||
impl<'a> From<BasicParseErrorKind<'a>> for SelectorErrorKind<'a> { | ||
fn from(err: BasicParseErrorKind<'a>) -> Self { | ||
match err { | ||
BasicParseErrorKind::UnexpectedToken(token) => Self::UnexpectedToken(token), | ||
BasicParseErrorKind::EndOfInput => Self::EndOfLine, | ||
BasicParseErrorKind::AtRuleInvalid(rule) => { | ||
Self::InvalidAtRule(rule.clone().to_string()) | ||
} | ||
BasicParseErrorKind::AtRuleBodyInvalid => Self::InvalidAtRuleBody, | ||
BasicParseErrorKind::QualifiedRuleInvalid => Self::QualRuleInvalid, | ||
} | ||
} | ||
} | ||
|
||
impl<'a> From<SelectorParseErrorKind<'a>> for SelectorErrorKind<'a> { | ||
fn from(err: SelectorParseErrorKind<'a>) -> Self { | ||
match err { | ||
SelectorParseErrorKind::PseudoElementExpectedColon(token) => { | ||
Self::ExpectedColonOnPseudoElement(token) | ||
} | ||
SelectorParseErrorKind::PseudoElementExpectedIdent(token) => { | ||
Self::ExpectedIdentityOnPseudoElement(token) | ||
} | ||
other => Self::UnexpectedSelectorParseError(other), | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Display for SelectorErrorKind<'a> { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!( | ||
f, | ||
"{}", | ||
match self { | ||
Self::UnexpectedToken(token) => { | ||
format!("Token {:?} was not expected", utils::render_token(token)) | ||
} | ||
Self::EndOfLine => "Unexpected EOL".to_string(), | ||
Self::InvalidAtRule(rule) => format!("Invalid @-rule {:?}", rule), | ||
Self::InvalidAtRuleBody => "The body of an @-rule was invalid".to_string(), | ||
Self::QualRuleInvalid => "The qualified name was invalid".to_string(), | ||
Self::ExpectedColonOnPseudoElement(token) => format!( | ||
"Expected a ':' token for pseudoelement, got {:?} instead", | ||
utils::render_token(token) | ||
), | ||
Self::ExpectedIdentityOnPseudoElement(token) => format!( | ||
"Expected identity for pseudoelement, got {:?} instead", | ||
utils::render_token(token) | ||
), | ||
Self::UnexpectedSelectorParseError(err) => format!( | ||
"Unexpected error occurred. Please report this to the developer\n{:#?}", | ||
err | ||
), | ||
} | ||
) | ||
} | ||
} | ||
|
||
impl<'a> Error for SelectorErrorKind<'a> { | ||
fn description(&self) -> &str { | ||
match self { | ||
Self::UnexpectedToken(_) => "Token was not expected", | ||
Self::EndOfLine => "Unexpected EOL", | ||
Self::InvalidAtRule(_) => "Invalid @-rule", | ||
Self::InvalidAtRuleBody => "The body of an @-rule was invalid", | ||
Self::QualRuleInvalid => "The qualified name was invalid", | ||
Self::ExpectedColonOnPseudoElement(_) => "Missing colon character on pseudoelement", | ||
Self::ExpectedIdentityOnPseudoElement(_) => "Missing pseudoelement identity", | ||
Self::UnexpectedSelectorParseError(_) => "Unexpected error", | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
use cssparser::Token; | ||
|
||
pub(crate) fn render_token(token: &Token<'_>) -> String { | ||
// THIS TOOK FOREVER TO IMPLEMENT | ||
|
||
match token { | ||
// TODO: Give these guys some better names | ||
Token::Ident(ident) => format!("{}", ident.clone()), | ||
Token::AtKeyword(value) => format!("@{}", value.clone()), | ||
Token::Hash(name) | Token::IDHash(name) => format!("#{}", name.clone()), | ||
Token::QuotedString(value) => format!("\"{}\"", value.clone()), | ||
Token::Number { | ||
has_sign: signed, | ||
value: num, | ||
int_value: _, | ||
} | ||
| Token::Percentage { | ||
has_sign: signed, | ||
unit_value: num, | ||
int_value: _, | ||
} => render_number(*signed, *num, token), | ||
Token::Dimension { | ||
has_sign: signed, | ||
value: num, | ||
int_value: _, | ||
unit, | ||
} => format!("{}{}", render_int(*signed, *num), unit), | ||
Token::WhiteSpace(_) => String::from(" "), | ||
Token::Comment(comment) => format!("/* {} */", comment), | ||
Token::Function(name) => format!("{}()", name.clone()), | ||
Token::BadString(string) => format!("<Bad String {:?}>", string.clone()), | ||
Token::BadUrl(url) => format!("<Bad URL {:?}>", url.clone()), | ||
// Single-character token | ||
sc_token => render_single_char_token(sc_token), | ||
} | ||
} | ||
|
||
fn render_single_char_token(token: &Token) -> String { | ||
String::from(match token { | ||
Token::Colon => ":", | ||
Token::Semicolon => ";", | ||
Token::Comma => ",", | ||
Token::IncludeMatch => "~=", | ||
Token::DashMatch => "|=", | ||
Token::PrefixMatch => "^=", | ||
Token::SuffixMatch => "$=", | ||
Token::SubstringMatch => "*=", | ||
Token::CDO => "<!--", | ||
Token::CDC => "-->", | ||
Token::ParenthesisBlock => "<(", | ||
Token::SquareBracketBlock => "<[", | ||
Token::CurlyBracketBlock => "<{", | ||
Token::CloseParenthesis => "<)", | ||
Token::CloseSquareBracket => "<]", | ||
Token::CloseCurlyBracket => "<}", | ||
other => panic!( | ||
"Token {:?} is not supposed to match as a single-character token!", | ||
other | ||
), | ||
}) | ||
} | ||
|
||
fn render_number(signed: bool, num: f32, token: &Token) -> String { | ||
let num = render_int(signed, num); | ||
|
||
match token { | ||
Token::Number { .. } => num, | ||
Token::Percentage { .. } => format!("{}%", num), | ||
_ => panic!("render_number is not supposed to be called on a non-numerical token"), | ||
} | ||
} | ||
|
||
fn render_int(signed: bool, num: f32) -> String { | ||
if signed { | ||
render_int_signed(num) | ||
} else { | ||
render_int_unsigned(num) | ||
} | ||
} | ||
|
||
fn render_int_signed(num: f32) -> String { | ||
if num > 0.0 { | ||
format!("+{}", num) | ||
} else { | ||
format!("-{}", num) | ||
} | ||
} | ||
|
||
fn render_int_unsigned(num: f32) -> String { | ||
format!("{}", num) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters