htmls/parser/
element.rs

1use crate::lexer::Token;
2use crate::parser::ast::{ElementNode, SelectorNode};
3use crate::parser::error::ParseError;
4use super::Parser;
5
6/// Parse element selector
7pub fn parse_element(it: &mut Parser) -> Result<SelectorNode, ParseError> {
8    match &it.current_token {
9        Some((Token::Class, _, _)) => {
10            let element_node = parse_class_selector(it)?;
11            Ok(SelectorNode::ElementSelector(element_node))
12        }
13        Some((Token::Id, _, _)) => {
14            let element_node = parse_id_selector(it)?;
15            Ok(SelectorNode::ElementSelector(element_node))
16        }
17        Some((Token::Tag, _, _)) => {
18            let element_node = parse_tag_selector(it)?;
19            Ok(SelectorNode::ElementSelector(element_node))
20        }
21        Some((Token::Attr, _, _)) => {
22            let element_node = parse_attr_selector(it)?;
23            Ok(SelectorNode::ElementSelector(element_node))
24        }
25        _ => {
26            let (line, column) = it.get_current_position();
27            let current = it.get_current_token_str();
28            Err(ParseError::unexpected_token(
29                "class, id, tag, or attr",
30                &current,
31                line,
32                column,
33            ))
34        }
35    }
36}
37
38/// Parse class selector (class)
39fn parse_class_selector(it: &mut Parser) -> Result<ElementNode, ParseError> {
40    it.consume_token(&Token::Class)?;
41    
42    let (is_regex, value) = parse_selector_value(it)?;
43
44    if value.is_empty() {
45        let (line, column) = it.get_current_position();
46        return Err(ParseError::invalid_selector_value("empty value", line, column));
47    }
48
49    Ok(ElementNode::Class(value, is_regex))
50}
51
52/// Parse ID selector (id)
53fn parse_id_selector(it: &mut Parser) -> Result<ElementNode, ParseError> {
54
55    it.consume_token(&Token::Id)?;
56
57    let (is_regex, value) = parse_selector_value(it)?;
58
59    if value.is_empty() {
60        let (line, column) = it.get_current_position();
61        return Err(ParseError::invalid_selector_value("empty value", line, column));
62    }
63
64    Ok(ElementNode::Id(value, is_regex))
65}
66
67/// Parse tag selector (tag)
68fn parse_tag_selector(it: &mut Parser) -> Result<ElementNode, ParseError> {
69
70    it.consume_token(&Token::Tag)?;
71
72    let (is_regex, value) = parse_selector_value(it)?;
73
74    if value.is_empty() {
75        let (line, column) = it.get_current_position();
76        return Err(ParseError::invalid_selector_value("empty value", line, column));
77    }
78
79    Ok(ElementNode::Tag(value, is_regex))
80}
81
82/// Parse attribute selector (attr)
83fn parse_attr_selector(it: &mut Parser) -> Result<ElementNode, ParseError> {
84
85    it.consume_token(&Token::Attr)?;
86   
87    let (_, attr_name) = parse_selector_value(it)?;
88
89    if attr_name.is_empty() {
90        let (line, column) = it.get_current_position();
91        return Err(ParseError::invalid_selector_value("empty attribute name", line, column));
92    }
93
94    let (is_regex, attr_value) = match parse_selector_value(it) {
95        Ok((is_regex, attr_value)) => (is_regex, Some(attr_value)),
96        Err(_) => (false, None)
97    };
98
99    Ok(ElementNode::Attr(attr_name, attr_value, is_regex))
100}
101
102/// Parse selector value
103fn parse_selector_value(it: &mut Parser) -> Result<(bool, String), ParseError> {
104    let is_regex = if it.check_token(&Token::Tilde) {
105        it.consume_token(&Token::Tilde)?; // Consume regex token
106        true
107    } else {
108        false
109    };
110
111    // Parse selector value (common argument or quoted argument)
112    match &it.current_token {
113        Some((Token::String(value), _, _)) => {
114            let value = value.clone();
115            it.read_token(); // Consume argument
116            Ok((is_regex, value))
117        }
118        _ => {
119            let (line, column) = it.get_current_position();
120            let current = it.get_current_token_str();
121            Err(ParseError::unexpected_token(
122                "selector argument",
123                &current,
124                line,
125                column,
126            ))
127        }
128    }
129}