htmls/parser/
error.rs

1use std::error::Error;
2use std::fmt;
3
4/// Parser error types
5#[derive(Debug, Clone, PartialEq)]
6pub enum ParseErrorKind {
7    /// Unexpected token encountered
8    UnexpectedToken,
9
10    /// Invalid selector value
11    InvalidSelectorValue,
12
13    /// Nesting level too deep
14    NestingTooDeep,
15
16    /// Other syntax errors
17    SyntaxError,
18    
19    /// Multiple text query directives
20    MultipleTextSelectors,
21    
22    /// Element query directive after text query directive
23    ElementAfterTextSelector,
24}
25
26impl fmt::Display for ParseErrorKind {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            ParseErrorKind::UnexpectedToken => write!(f, "Unexpected token"),
30            ParseErrorKind::InvalidSelectorValue => write!(f, "Invalid selector value"),
31            ParseErrorKind::NestingTooDeep => write!(f, "Nesting level too deep"),
32            ParseErrorKind::SyntaxError => write!(f, "Syntax error"),
33            ParseErrorKind::MultipleTextSelectors => write!(f, "Multiple text query directives"),
34            ParseErrorKind::ElementAfterTextSelector => write!(f, "Element query after text query"),
35        }
36    }
37}
38
39/// Parse error
40#[derive(Debug, Clone)]
41pub struct ParseError {
42    /// Error type
43    pub kind: ParseErrorKind,
44
45    /// Error message
46    pub message: String,
47
48    /// Line number where the error occurred
49    pub line: usize,
50
51    /// Column number where the error occurred
52    pub column: usize,
53
54    /// Error recovery hint
55    pub recovery_hint: Option<String>,
56}
57
58impl ParseError {
59    /// Create a new parse error
60    #[allow(dead_code)]
61    pub fn new(
62        kind: ParseErrorKind,
63        message: String,
64        line: usize,
65        column: usize,
66        recovery_hint: Option<String>,
67    ) -> Self {
68        ParseError {
69            kind,
70            message,
71            line,
72            column,
73            recovery_hint,
74        }
75    }
76
77    /// Create an unexpected token error
78    pub fn unexpected_token(expected: &str, found: &str, line: usize, column: usize) -> Self {
79        ParseError {
80            kind: ParseErrorKind::UnexpectedToken,
81            message: format!("Expected {} but found {}", expected, found),
82            line,
83            column,
84            recovery_hint: Some(format!("Please check if {} is missing here", expected)),
85        }
86    }
87
88    pub fn syntax_error(msg: &str, line: usize, column: usize) -> Self {
89        ParseError {
90            kind: ParseErrorKind::SyntaxError,
91            message: msg.to_string(),
92            line,
93            column,
94            recovery_hint: None,
95        }
96    }
97
98
99    /// Create an invalid selector value error
100    pub fn invalid_selector_value(value: &str, line: usize, column: usize) -> Self {
101        ParseError {
102            kind: ParseErrorKind::InvalidSelectorValue,
103            message: format!("Invalid selector value: {}", value),
104            line,
105            column,
106            recovery_hint: Some("Please check if the selector value format is correct".to_string()),
107        }
108    }
109
110    /// Create a nesting too deep error
111    pub fn nesting_too_deep(max_depth: usize, line: usize, column: usize) -> Self {
112        ParseError {
113            kind: ParseErrorKind::NestingTooDeep,
114            message: format!("Expression nesting exceeds maximum depth ({})", max_depth),
115            line,
116            column,
117            recovery_hint: Some("Please simplify the expression, reduce nesting levels".to_string()),
118        }
119    }
120    
121    /// Create a multiple text selectors error
122    pub fn multiple_text_selectors(line: usize, column: usize) -> Self {
123        ParseError {
124            kind: ParseErrorKind::MultipleTextSelectors,
125            message: "Query operation can only contain one text query directive".to_string(),
126            line,
127            column,
128            recovery_hint: Some("Please remove extra text query directives or separate them with set operations (+, *, -)".to_string()),
129        }
130    }
131    
132    /// Create an element after text selector error
133    pub fn element_after_text_selector(line: usize, column: usize) -> Self {
134        ParseError {
135            kind: ParseErrorKind::ElementAfterTextSelector,
136            message: "Element query directives cannot appear after text query directives".to_string(),
137            line,
138            column,
139            recovery_hint: Some("Please place element query directives before text query directives".to_string()),
140        }
141    }
142}
143
144impl fmt::Display for ParseError {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        write!(
147            f,
148            "Parse error (line {}, column {}): {} - {}",
149            self.line, self.column, self.kind, self.message
150        )?;
151
152        if let Some(hint) = &self.recovery_hint {
153            write!(f, "\nHint: {}", hint)?;
154        }
155
156        Ok(())
157    }
158}
159
160impl Error for ParseError {}
161