1
#![allow(clippy::legacy_numeric_constants)]
2

            
3
use std::collections::BTreeMap;
4
use tree_sitter::Node;
5

            
6
use super::ParseContext;
7
use super::domain::parse_domain;
8
use super::util::named_children;
9
use crate::diagnostics::diagnostics_api::SymbolKind;
10
use crate::diagnostics::source_map::{HoverInfo, span_with_hover};
11
use crate::errors::{FatalParseError, RecoverableParseError};
12
use crate::field;
13
use conjure_cp_core::ast::{DomainPtr, Name};
14

            
15
/// Parse a find statement into a map of decision variable names to their domains.
16
2746
pub fn parse_find_statement(
17
2746
    ctx: &mut ParseContext,
18
2746
    find_statement: Node,
19
2746
) -> Result<BTreeMap<Name, DomainPtr>, FatalParseError> {
20
2746
    let mut vars = BTreeMap::new();
21

            
22
2746
    let domain = field!(find_statement, "domain");
23
2746
    let Some(domain) = parse_domain(ctx, domain)? else {
24
124
        return Ok(vars);
25
    };
26

            
27
2622
    let variable_list = field!(find_statement, "variables");
28
3104
    for variable in named_children(&variable_list) {
29
3104
        let variable_name = &ctx.source_code[variable.start_byte()..variable.end_byte()];
30
3104
        let name = Name::user(variable_name);
31

            
32
        // Check for duplicate within the same statement
33
3104
        if vars.contains_key(&name) {
34
34
            ctx.errors.push(RecoverableParseError::new(
35
34
                format!(
36
                    "Variable '{}' is already declared in this find statement",
37
                    variable_name
38
                ),
39
34
                Some(variable.range()),
40
            ));
41
            // don't return here, as we can still add the other variables to the symbol table
42
34
            continue;
43
3070
        }
44

            
45
        // Check for duplicate declaration across statements
46
3070
        if let Some(symbols) = &ctx.symbols
47
3070
            && symbols.read().lookup(&name).is_some()
48
        {
49
34
            ctx.errors.push(RecoverableParseError::new(
50
34
                format!(
51
                    "Variable '{}' is already declared in a previous statement",
52
                    variable_name
53
                ),
54
34
                Some(variable.range()),
55
            ));
56
            // don't return here, as we can still add the other variables to the symbol table
57
34
            continue;
58
3036
        }
59

            
60
3036
        vars.insert(name, domain.clone());
61
3036
        let hover = HoverInfo {
62
3036
            description: format!("Find variable: {variable_name}"),
63
3036
            kind: Some(SymbolKind::Find),
64
3036
            ty: Some(domain.to_string()),
65
3036
            decl_span: None,
66
3036
        };
67
3036
        span_with_hover(&variable, ctx.source_code, ctx.source_map, hover);
68
    }
69

            
70
2622
    Ok(vars)
71
2746
}