conjure_cp_essence_parser/parser/
find.rs1#![allow(clippy::legacy_numeric_constants)]
2
3use std::collections::BTreeMap;
4use tree_sitter::Node;
5
6use super::ParseContext;
7use super::domain::parse_domain;
8use super::util::named_children;
9use crate::diagnostics::diagnostics_api::SymbolKind;
10use crate::diagnostics::source_map::{HoverInfo, span_with_hover};
11use crate::errors::{FatalParseError, RecoverableParseError};
12use crate::field;
13use conjure_cp_core::ast::{DomainPtr, Name};
14
15pub fn parse_find_statement(
17 ctx: &mut ParseContext,
18 find_statement: Node,
19) -> Result<BTreeMap<Name, DomainPtr>, FatalParseError> {
20 let mut vars = BTreeMap::new();
21
22 let domain = field!(find_statement, "domain");
23 let Some(domain) = parse_domain(ctx, domain)? else {
24 return Ok(vars);
25 };
26
27 let variable_list = field!(find_statement, "variables");
28 for variable in named_children(&variable_list) {
29 let variable_name = &ctx.source_code[variable.start_byte()..variable.end_byte()];
30 let name = Name::user(variable_name);
31
32 if vars.contains_key(&name) {
34 ctx.errors.push(RecoverableParseError::new(
35 format!(
36 "Variable '{}' is already declared in this find statement",
37 variable_name
38 ),
39 Some(variable.range()),
40 ));
41 continue;
43 }
44
45 if let Some(symbols) = &ctx.symbols
47 && symbols.read().lookup(&name).is_some()
48 {
49 ctx.errors.push(RecoverableParseError::new(
50 format!(
51 "Variable '{}' is already declared in a previous statement",
52 variable_name
53 ),
54 Some(variable.range()),
55 ));
56 continue;
58 }
59
60 vars.insert(name, domain.clone());
61 let hover = HoverInfo {
62 description: format!("Find variable: {variable_name}"),
63 kind: Some(SymbolKind::Find),
64 ty: Some(domain.to_string()),
65 decl_span: None,
66 };
67 span_with_hover(&variable, ctx.source_code, ctx.source_map, hover);
68 }
69
70 Ok(vars)
71}