Skip to content

Commit faaab11

Browse files
author
Martijn Groeneveldt
committed
improve the error implementation
1 parent 51f24ba commit faaab11

File tree

7 files changed

+133
-53
lines changed

7 files changed

+133
-53
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
target
22
/Cargo.lock
33
/.cargo/config
4+
.idea

procedural-masquerade/lib.rs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -244,33 +244,33 @@ macro_rules! define_invoke_proc_macro {
244244
#[doc(hidden)]
245245
#[macro_export]
246246
macro_rules! $macro_name {
247-
($proc_macro_name: ident ! $paren: tt) => {
248-
#[derive($proc_macro_name)]
249-
#[allow(unused)]
250-
enum ProceduralMasqueradeDummyType {
251-
// The magic happens here.
252-
//
253-
// We use an `enum` with an explicit discriminant
254-
// because that is the only case where a type definition
255-
// can contain a (const) expression.
256-
//
257-
// `(0, "foo").0` evalutes to 0, with the `"foo"` part ignored.
258-
//
259-
// By the time the `#[proc_macro_derive]` function
260-
// implementing `#[derive($proc_macro_name)]` is called,
261-
// `$paren` has already been replaced with the input of this inner macro,
262-
// but `stringify!` has not been expanded yet.
263-
//
264-
// This how arbitrary tokens can be inserted
265-
// in the input to the `#[proc_macro_derive]` function.
266-
//
267-
// Later, `stringify!(...)` is expanded into a string literal
268-
// which is then ignored.
269-
// Using `stringify!` enables passing arbitrary tokens
270-
// rather than only what can be parsed as a const expression.
271-
Input = (0, stringify! $paren ).0
272-
}
273-
}
274-
}
247+
($proc_macro_name: ident ! $paren: tt) => {
248+
#[derive($proc_macro_name)]
249+
#[allow(unused)]
250+
enum ProceduralMasqueradeDummyType {
251+
// The magic happens here.
252+
//
253+
// We use an `enum` with an explicit discriminant
254+
// because that is the only case where a type definition
255+
// can contain a (const) expression.
256+
//
257+
// `(0, "foo").0` evalutes to 0, with the `"foo"` part ignored.
258+
//
259+
// By the time the `#[proc_macro_derive]` function
260+
// implementing `#[derive($proc_macro_name)]` is called,
261+
// `$paren` has already been replaced with the input of this inner macro,
262+
// but `stringify!` has not been expanded yet.
263+
//
264+
// This how arbitrary tokens can be inserted
265+
// in the input to the `#[proc_macro_derive]` function.
266+
//
267+
// Later, `stringify!(...)` is expanded into a string literal
268+
// which is then ignored.
269+
// Using `stringify!` enables passing arbitrary tokens
270+
// rather than only what can be parsed as a const expression.
271+
Input = (0, stringify! $paren ).0
272+
}
273+
}
274+
}
275275
};
276276
}

src/parser.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,15 @@ pub enum BasicParseErrorKind<'i> {
5656
}
5757

5858
impl<'i> BasicParseErrorKind<'i> {
59-
fn description(&self) -> &'static str {
59+
fn description(&self) -> String {
6060
match self {
61-
BasicParseErrorKind::UnexpectedToken(_) => "Unexpected token",
62-
BasicParseErrorKind::EndOfInput => "End of input",
63-
BasicParseErrorKind::AtRuleInvalid(_) => "Invalid @ rule",
64-
BasicParseErrorKind::AtRuleBodyInvalid => "Invalid @ rule body",
65-
BasicParseErrorKind::QualifiedRuleInvalid => "Invalid qualified rule",
61+
BasicParseErrorKind::UnexpectedToken(token) => {
62+
format!("Unexpected token: '{}'", token.description())
63+
}
64+
BasicParseErrorKind::EndOfInput => "End of input".to_owned(),
65+
BasicParseErrorKind::AtRuleInvalid(message) => format!("Invalid @ rule: {}", message),
66+
BasicParseErrorKind::AtRuleBodyInvalid => "Invalid @ rule body".to_owned(),
67+
BasicParseErrorKind::QualifiedRuleInvalid => "Invalid qualified rule".to_owned(),
6668
}
6769
}
6870
}
@@ -78,7 +80,7 @@ pub struct BasicParseError<'i> {
7880

7981
impl<'i> fmt::Display for BasicParseError<'i> {
8082
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
81-
write!(formatter, "{}", self.kind.description())
83+
formatter.write_str(self.kind.description().as_str())
8284
}
8385
}
8486

@@ -178,16 +180,19 @@ impl<'i, T> ParseError<'i, T> {
178180
}
179181
}
180182

181-
impl<'i, T> fmt::Display for ParseError<'i, T> {
183+
impl<'i, T> fmt::Display for ParseError<'i, T>
184+
where
185+
T: fmt::Display,
186+
{
182187
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
183-
write!(formatter, "{}", match &self.kind {
184-
ParseErrorKind::Basic(basic_kind) => basic_kind.description(),
185-
ParseErrorKind::Custom(_) => "Custom error",
186-
})
188+
match &self.kind {
189+
ParseErrorKind::Basic(basic_kind) => formatter.write_str(&basic_kind.description()),
190+
ParseErrorKind::Custom(custom_type) => custom_type.fmt(formatter),
191+
}
187192
}
188193
}
189194

190-
impl<'i, T> Error for ParseError<'i, T> where T: fmt::Debug {}
195+
impl<'i, T> Error for ParseError<'i, T> where T: Error {}
191196

192197
/// The owned input for a parser.
193198
pub struct ParserInput<'i> {

src/rules_and_declarations.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,7 @@ where
268268
let start = self.input.state();
269269
// FIXME: remove intermediate variable when lifetimes are non-lexical
270270
let ident = match self.input.next_including_whitespace_and_comments() {
271-
Ok(&Token::WhiteSpace(_)) | Ok(&Token::Comment(_)) | Ok(&Token::Semicolon) => {
272-
continue
273-
}
271+
Ok(&Token::WhiteSpace(_)) | Ok(&Token::Comment(_)) | Ok(&Token::Semicolon) => continue,
274272
Ok(&Token::Ident(ref name)) => Ok(Ok(name.clone())),
275273
Ok(&Token::AtKeyword(ref name)) => Ok(Err(name.clone())),
276274
Ok(token) => Err(token.clone()),

src/serializer.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,15 +451,24 @@ impl TokenSerializationType {
451451
),
452452
Number => matches!(
453453
other.0,
454-
Ident | Function | UrlOrBadUrl | DelimMinus | Number | Percentage | DelimPercent | Dimension
454+
Ident
455+
| Function
456+
| UrlOrBadUrl
457+
| DelimMinus
458+
| Number
459+
| Percentage
460+
| DelimPercent
461+
| Dimension
455462
),
456463
DelimAt => matches!(other.0, Ident | Function | UrlOrBadUrl | DelimMinus),
457464
DelimDotOrPlus => matches!(other.0, Number | Percentage | Dimension),
458465
DelimAssorted | DelimAsterisk => matches!(other.0, DelimEquals),
459466
DelimBar => matches!(other.0, DelimEquals | DelimBar | DashMatch),
460467
DelimSlash => matches!(other.0, DelimAsterisk | SubstringMatch),
461468
Nothing | WhiteSpace | Percentage | UrlOrBadUrl | Function | CDC | OpenParen
462-
| DashMatch | SubstringMatch | DelimQuestion | DelimEquals | DelimPercent | Other => false,
469+
| DashMatch | SubstringMatch | DelimQuestion | DelimEquals | DelimPercent | Other => {
470+
false
471+
}
463472
}
464473
}
465474
}

src/tests.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
extern crate test;
77

88
use encoding_rs;
9-
use serde_json::{self, Value, json, Map};
9+
use serde_json::{self, json, Map, Value};
1010

1111
#[cfg(feature = "bench")]
1212
use self::test::Bencher;
@@ -30,7 +30,7 @@ fn almost_equals(a: &Value, b: &Value) -> bool {
3030
let a = a.as_f64().unwrap();
3131
let b = b.as_f64().unwrap();
3232
(a - b).abs() <= a.abs() * 1e-6
33-
},
33+
}
3434

3535
(&Value::Bool(a), &Value::Bool(b)) => a == b,
3636
(&Value::String(ref a), &Value::String(ref b)) => a == b,
@@ -410,15 +410,16 @@ fn unicode_range() {
410410
Ok(None)
411411
}
412412
});
413-
result.unwrap()
413+
result
414+
.unwrap()
414415
.iter()
415-
.map(|v|
416-
if let Some((v0, v1)) = v{
416+
.map(|v| {
417+
if let Some((v0, v1)) = v {
417418
json!([v0, v1])
418419
} else {
419420
Value::Null
420421
}
421-
)
422+
})
422423
.collect::<Vec<_>>()
423424
.to_json()
424425
});
@@ -809,7 +810,11 @@ trait ToJson {
809810
fn to_json(&self) -> Value;
810811
}
811812

812-
impl<T> ToJson for T where T: Clone, Value: From<T> {
813+
impl<T> ToJson for T
814+
where
815+
T: Clone,
816+
Value: From<T>,
817+
{
813818
fn to_json(&self) -> Value {
814819
Value::from(self.clone())
815820
}

src/tokenizer.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,68 @@ impl<'a> Token<'a> {
191191
BadUrl(_) | BadString(_) | CloseParenthesis | CloseSquareBracket | CloseCurlyBracket
192192
)
193193
}
194+
195+
pub(crate) fn description(&self) -> String {
196+
match self {
197+
Ident(name) => format!("A ident token '{}'", name),
198+
AtKeyword(value) => format!("The value '{}' does not include the `@` marker", value),
199+
Hash(value) => format!("The value '{}' does not include the `#` marker", value),
200+
IDHash(value) => format!(
201+
"The value '{}' does not include the `#` marker, but has a valid ID selector",
202+
value
203+
),
204+
QuotedString(value) => format!("The value '{}' does not include the quotes", value),
205+
UnquotedUrl(value) => format!(
206+
"The value '{}' does not include the `url(` `)` markers.",
207+
value
208+
),
209+
Delim(character) => format!("'{}'", character),
210+
Number {
211+
has_sign, value, ..
212+
} => {
213+
let sign = if has_sign.clone() { '-' } else { '+' };
214+
format!("{}{}", sign, value.to_string())
215+
}
216+
Percentage {
217+
has_sign,
218+
unit_value,
219+
..
220+
} => {
221+
let sign = if has_sign.clone() { '-' } else { '+' };
222+
format!("{}{}%", sign, unit_value.to_string())
223+
}
224+
Dimension {
225+
has_sign,
226+
value,
227+
unit,
228+
..
229+
} => {
230+
let sign = if has_sign.clone() { '-' } else { '+' };
231+
format!("{}{} {}", sign, value.to_string(), unit)
232+
}
233+
WhiteSpace(whitespace) => format!("whitespace: '{}'", whitespace),
234+
Comment(comment) => format!("The comment: '{}'", comment),
235+
Colon => String::from(":"),
236+
Semicolon => String::from(";"),
237+
Comma => String::from(","),
238+
IncludeMatch => String::from("~="),
239+
DashMatch => String::from("|="),
240+
PrefixMatch => String::from("^="),
241+
SuffixMatch => String::from("$="),
242+
SubstringMatch => String::from("*="),
243+
CDO => String::from("<!--"),
244+
CDC => String::from("-->"),
245+
Function(name) => format!("The value ({}) does not include the `(` marker", name),
246+
ParenthesisBlock => String::from("("),
247+
SquareBracketBlock => String::from("["),
248+
CurlyBracketBlock => String::from("{"),
249+
BadUrl(url) => format!("Bad url: '{}'", url),
250+
BadString(string) => format!("Bad string: '{}'", string),
251+
CloseParenthesis => "Unclosed parenthesis".to_owned(),
252+
CloseSquareBracket => "Unclosed square bracket".to_owned(),
253+
CloseCurlyBracket => "Unclosed curly bracket".to_owned(),
254+
}
255+
}
194256
}
195257

196258
#[derive(Clone)]

0 commit comments

Comments
 (0)