Skip to main content

conjure_cp_essence_parser/parser/
keyword_checks.rs

1use crate::errors::RecoverableParseError;
2use crate::parser::syntax_errors::is_malformed_line_error;
3
4const KEYWORDS: [&str; 24] = [
5    "forall",
6    "exists",
7    "such",
8    "that",
9    "letting",
10    "find",
11    "minimise",
12    "maximise",
13    "subject",
14    "to",
15    "where",
16    "and",
17    "or",
18    "not",
19    "if",
20    "then",
21    "else",
22    "in",
23    "sum",
24    "product",
25    "bool",
26    "pareto",
27    "minimising",
28    "maximising",
29];
30
31pub fn keyword_as_identifier(
32    root: tree_sitter::Node,
33    source: &str,
34    errors: &mut Vec<RecoverableParseError>,
35) {
36    let mut stack = vec![root];
37    while let Some(node) = stack.pop() {
38        if node.is_error() && is_malformed_line_error(&node, source) {
39            return;
40        }
41        if (node.kind() == "variable" || node.kind() == "identifier" || node.kind() == "parameter")
42            && let Ok(text) = node.utf8_text(source.as_bytes())
43        {
44            let ident = text.trim();
45            if KEYWORDS.contains(&ident) {
46                let start_point = node.start_position();
47                let end_point = node.end_position();
48                errors.push(RecoverableParseError::new(
49                    format!("Keyword '{ident}' used as identifier"),
50                    Some(tree_sitter::Range {
51                        start_byte: node.start_byte(),
52                        end_byte: node.end_byte(),
53                        start_point,
54                        end_point,
55                    }),
56                ));
57            }
58        }
59
60        for i in 0..node.child_count() {
61            if let Some(child) = u32::try_from(i).ok().and_then(|i| node.child(i)) {
62                stack.push(child);
63            }
64        }
65    }
66}