floem_css_parser/
analyzer.rs

1use crate::lexer::Token;
2
3pub struct SyntaxError<'a> {
4    pub line: usize,
5    pub column: usize,
6    pub error: &'static str,
7    pub value: &'a str,
8}
9
10impl std::fmt::Display for SyntaxError<'_> {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        write!(
13            f,
14            "error: {}\n {}:{} | {}",
15            self.error, self.line, self.column, self.value
16        )
17    }
18}
19
20fn find_line_with_value<'a>(lines: &[&'a str], line: usize, m: &str) -> (usize, &'a str) {
21    let line = lines[line - 1];
22    let col = line
23        .find(m)
24        .unwrap_or_else(|| panic!("Analyzer error: cant find column for {m}"));
25    (col, line)
26}
27
28/// Work in progress
29#[must_use]
30pub fn analyze_tokens<'a>(tokens: &[Token<'a>], input: &'a str) -> Vec<SyntaxError<'a>> {
31    let mut errors: Vec<SyntaxError> = Vec::with_capacity(tokens.len());
32    let mut tokens = tokens.iter().peekable();
33    let lines = input.lines().collect::<Vec<_>>();
34    loop {
35        let Some(token) = tokens.next() else {
36            break;
37        };
38
39        match token {
40            Token::Selector { line, value } => {
41                let line = *line;
42                let (column, value) = find_line_with_value(&lines, line, value);
43                if let Some(peek) = tokens.peek() {
44                    if !matches!(peek, Token::BlockOpen { .. } | Token::Selector { .. }) {
45                        let error = SyntaxError {
46                            line,
47                            column,
48                            error: "Expecting { after selector",
49                            value,
50                        };
51                        errors.push(error);
52                    }
53                } else {
54                    let error = SyntaxError {
55                        line,
56                        column,
57                        error: "Unexpected EOF",
58                        value,
59                    };
60                    errors.push(error);
61                }
62            }
63            Token::Property { line, value } => {
64                if let Some(peek) = tokens.peek() {
65                    if !matches!(peek, Token::Colon { .. }) {
66                        let line = *line;
67                        let (column, value) = find_line_with_value(&lines, line, value);
68                        let error = SyntaxError {
69                            line,
70                            column,
71                            error: "Unexpected token after property",
72                            value,
73                        };
74                        errors.push(error);
75                    }
76                } else {
77                    todo!()
78                }
79            }
80            Token::Value { value, line } => {
81                if let Some(peek) = tokens.peek() {
82                    if !matches!(peek, Token::Semicolon { .. }) {
83                        let line = *line;
84                        let (column, value) = find_line_with_value(&lines, line, value);
85                        let error = SyntaxError {
86                            line,
87                            column,
88                            error: "Expecting ; after value",
89                            value,
90                        };
91                        errors.push(error);
92                    }
93                } else {
94                    todo!()
95                }
96            }
97            Token::Semicolon { line } => {
98                if let Some(peek) = tokens.peek() {
99                    if !matches!(peek, Token::BlockClose { .. } | Token::Property { .. }) {
100                        let line = *line;
101                        let (column, value) = find_line_with_value(&lines, line, ";");
102                        let error = SyntaxError {
103                            line,
104                            column,
105                            error: "Expecting property or } after ;",
106                            value,
107                        };
108                        errors.push(error);
109                    }
110                } else {
111                    todo!()
112                }
113            }
114            Token::Colon { line } => {
115                if let Some(peek) = tokens.peek() {
116                    if !matches!(peek, Token::Value { .. }) {
117                        let line = *line;
118                        let (column, value) = find_line_with_value(&lines, line, ":");
119                        let error = SyntaxError {
120                            line,
121                            column,
122                            error: "Expecting value after :",
123                            value,
124                        };
125                        errors.push(error);
126                    }
127                } else {
128                    todo!()
129                }
130            }
131            _ => (),
132        }
133    }
134
135    errors
136}