1 use std::{error::Error, fmt}; 2 3 /// An error related to parsing of a cfg expression 4 #[derive(Debug, PartialEq)] 5 pub struct ParseError { 6 /// The string that was parsed 7 pub original: String, 8 /// The range of characters in the original string that result 9 /// in this error 10 pub span: std::ops::Range<usize>, 11 /// The specific reason for the error 12 pub reason: Reason, 13 } 14 15 /// The particular reason for a `ParseError` 16 #[derive(Debug, PartialEq)] 17 pub enum Reason { 18 /// not() takes exactly 1 predicate, unlike all() and any() 19 InvalidNot(usize), 20 /// The characters are not valid in an cfg expression 21 InvalidCharacters, 22 /// An opening parens was unmatched with a closing parens 23 UnclosedParens, 24 /// A closing parens was unmatched with an opening parens 25 UnopenedParens, 26 /// An opening quotes was unmatched with a closing quotes 27 UnclosedQuotes, 28 /// A closing quotes was unmatched with an opening quotes 29 UnopenedQuotes, 30 /// The expression does not contain any valid terms 31 Empty, 32 /// Found an unexpected term, which wasn't one of the expected terms that 33 /// is listed 34 Unexpected(&'static [&'static str]), 35 /// Failed to parse an integer value 36 InvalidInteger, 37 /// The root cfg() may only contain a single predicate 38 MultipleRootPredicates, 39 /// An element was not part of the builtin information in rustc 40 UnknownBuiltin, 41 } 42 43 impl fmt::Display for ParseError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 45 f.write_str(&self.original)?; 46 f.write_str("\n")?; 47 48 for _ in 0..self.span.start { 49 f.write_str(" ")?; 50 } 51 52 // Mismatched parens/quotes have a slightly different output 53 // than the other errors 54 match &self.reason { 55 r @ Reason::UnclosedParens | r @ Reason::UnclosedQuotes => { 56 f.write_fmt(format_args!("- {}", r)) 57 } 58 r @ Reason::UnopenedParens | r @ Reason::UnopenedQuotes => { 59 f.write_fmt(format_args!("^ {}", r)) 60 } 61 other => { 62 for _ in self.span.start..self.span.end { 63 f.write_str("^")?; 64 } 65 66 f.write_fmt(format_args!(" {}", other)) 67 } 68 } 69 } 70 } 71 72 impl fmt::Display for Reason { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 74 use Reason::{ 75 Empty, InvalidCharacters, InvalidInteger, InvalidNot, MultipleRootPredicates, 76 UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin, UnopenedParens, 77 UnopenedQuotes, 78 }; 79 80 match self { 81 InvalidCharacters => f.write_str("invalid character(s)"), 82 UnclosedParens => f.write_str("unclosed parens"), 83 UnopenedParens => f.write_str("unopened parens"), 84 UnclosedQuotes => f.write_str("unclosed quotes"), 85 UnopenedQuotes => f.write_str("unopened quotes"), 86 Empty => f.write_str("empty expression"), 87 Unexpected(expected) => { 88 if expected.len() > 1 { 89 f.write_str("expected one of ")?; 90 91 for (i, exp) in expected.iter().enumerate() { 92 f.write_fmt(format_args!("{}`{}`", if i > 0 { ", " } else { "" }, exp))?; 93 } 94 f.write_str(" here") 95 } else if !expected.is_empty() { 96 f.write_fmt(format_args!("expected a `{}` here", expected[0])) 97 } else { 98 f.write_str("the term was not expected here") 99 } 100 } 101 InvalidNot(np) => f.write_fmt(format_args!("not() takes 1 predicate, found {}", np)), 102 InvalidInteger => f.write_str("invalid integer"), 103 MultipleRootPredicates => f.write_str("multiple root predicates"), 104 UnknownBuiltin => f.write_str("unknown built-in"), 105 } 106 } 107 } 108 109 impl Error for ParseError { description(&self) -> &str110 fn description(&self) -> &str { 111 use Reason::{ 112 Empty, InvalidCharacters, InvalidInteger, InvalidNot, MultipleRootPredicates, 113 UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin, UnopenedParens, 114 UnopenedQuotes, 115 }; 116 117 match self.reason { 118 InvalidCharacters => "invalid character(s)", 119 UnclosedParens => "unclosed parens", 120 UnopenedParens => "unopened parens", 121 UnclosedQuotes => "unclosed quotes", 122 UnopenedQuotes => "unopened quotes", 123 Empty => "empty expression", 124 Unexpected(_) => "unexpected term", 125 InvalidNot(_) => "not() takes 1 predicate", 126 InvalidInteger => "invalid integer", 127 MultipleRootPredicates => "multiple root predicates", 128 UnknownBuiltin => "unknown built-in", 129 } 130 } 131 } 132