htmls/parser/
validate.rs

1use crate::parser::ast::{
2    ElementNode, FunctionNode, IndexNode, Node, SelectorNode, SetOperationNode,
3    TextNode, Visitor, Visitable,
4};
5use crate::parser::error::ParseError;
6
7/// Syntax validator state
8#[derive(Debug, Clone)]
9struct ValidationState {
10    /// Whether a text query directive has already appeared in the current path
11    has_text_selector: bool,
12    
13    /// Position where the text query directive appeared (line, column)
14    text_selector_pos: Option<(usize, usize)>,
15    
16    /// Current position (line, column)
17    current_pos: (usize, usize),
18}
19
20impl ValidationState {
21    /// Create new validation state
22    fn new() -> Self {
23        ValidationState {
24            has_text_selector: false,
25            text_selector_pos: None,
26            current_pos: (0, 0),
27        }
28    }
29    
30    /// Update current position
31    fn set_position(&mut self, line: usize, column: usize) {
32        self.current_pos = (line, column);
33    }
34    
35    /// Record text selector appearance
36    fn mark_text_selector(&mut self) {
37        self.has_text_selector = true;
38        self.text_selector_pos = Some(self.current_pos);
39    }
40    
41    /// Check if element selector can be added
42    fn can_add_element_selector(&self) -> bool {
43        !self.has_text_selector
44    }
45    
46}
47
48/// HTML selector syntax validator
49pub struct SyntaxValidator {
50    /// Current validation state
51    state: ValidationState,
52}
53
54impl SyntaxValidator {
55
56    pub fn new() -> Self {
57        SyntaxValidator {
58            state: ValidationState::new(),
59        }
60    }
61    
62    /// Validate if AST conforms to syntax rules
63    pub fn validate(&mut self, node: &Node) -> Result<(), ParseError> {
64        // Use Visitable's accept method instead of directly calling visit_node
65        node.accept(self)
66    }
67    
68    /// Set current position information
69    #[allow(dead_code)]
70    pub fn set_position(&mut self, line: usize, column: usize) {
71        self.state.set_position(line, column);
72    }
73}
74
75impl Visitor<Result<(), ParseError>> for SyntaxValidator {
76    fn visit_node(&mut self, node: &Node) -> Result<(), ParseError> {
77        match node {
78            Node::Selector(selector) => self.visit_selector(selector),
79            Node::Pipeline(left, right) => self.visit_pipeline(left, right),
80            Node::SetOperation(op) => self.visit_set_operation(op),
81            Node::IndexSelection(inner, idx) => {
82                self.visit_node(inner)?;
83                self.visit_index(idx)
84            }
85            Node::FunctionCall(inner, func) => {
86                self.visit_node(inner)?;
87                self.visit_function(func)
88            }
89        }
90    }
91    
92    fn visit_selector(&mut self, node: &SelectorNode) -> Result<(), ParseError> {
93        match node {
94            SelectorNode::ElementSelector(elem) => self.visit_element(elem),
95            SelectorNode::TextSelector(text) => self.visit_text(text),
96        }
97    }
98    
99    fn visit_element(&mut self, _node: &ElementNode) -> Result<(), ParseError> {
100        // Check if element selector can be added
101        if !self.state.can_add_element_selector() {
102            let (line, column) = self.state.current_pos;
103            return Err(ParseError::element_after_text_selector(line, column));
104        }
105        
106        Ok(())
107    }
108    
109    fn visit_text(&mut self, _node: &TextNode) -> Result<(), ParseError> {
110        // Check if text selector already exists
111        if self.state.has_text_selector {
112            let (line, column) = self.state.current_pos;
113            return Err(ParseError::multiple_text_selectors(line, column));
114        }
115        
116        // Mark text selector appearance
117        self.state.mark_text_selector();
118        
119        Ok(())
120    }
121    
122    fn visit_pipeline(&mut self, left: &Node, right: &Node) -> Result<(), ParseError> {
123        // Pipeline operation does not reset text selector state
124        // Left operand's state is passed to right operand
125        self.visit_node(left)?;
126        self.visit_node(right)
127    }
128    
129    
130    fn visit_set_operation(&mut self, node: &SetOperationNode) -> Result<(), ParseError> {
131        match node {
132            SetOperationNode::Union(left, right) 
133            | SetOperationNode::Intersection(left, right) 
134            | SetOperationNode::Difference(left, right) => {
135
136                let original_state = self.state.clone();
137                
138                self.visit_node(left)?;
139                
140                self.state = original_state;
141                self.visit_node(right)?;
142                
143                // State is not merged after set operation, equivalent to reset
144                // Because each branch produces independent result sets
145                self.state = ValidationState::new();
146                
147                Ok(())
148            }
149        }
150    }
151    
152    fn visit_index(&mut self, _node: &IndexNode) -> Result<(), ParseError> {
153        // Index selection does not change text selector state
154        Ok(())
155    }
156    
157    fn visit_function(&mut self, _node: &FunctionNode) -> Result<(), ParseError> {
158        // Function call does not change text selector state
159        Ok(())
160    }
161}