conjure_cp_essence_parser/parser/
parse_model.rs

1use std::fs;
2use std::sync::{Arc, RwLock};
3
4use conjure_cp_core::Model;
5use conjure_cp_core::ast::Expression;
6use conjure_cp_core::ast::{DeclarationPtr, Moo};
7use conjure_cp_core::context::Context;
8use conjure_cp_core::error::Error;
9use conjure_cp_core::metadata::Metadata;
10#[allow(unused)]
11use uniplate::Uniplate;
12
13use crate::errors::EssenceParseError;
14
15use super::expression::parse_expression;
16use super::find::parse_find_statement;
17use super::letting::parse_letting_statement;
18use super::util::{get_tree, named_children};
19
20/// Parse an Essence file into a Model using the tree-sitter parser.
21pub fn parse_essence_file_native(
22    path: &str,
23    context: Arc<RwLock<Context<'static>>>,
24) -> Result<Model, EssenceParseError> {
25    let source_code = fs::read_to_string(path)
26        .unwrap_or_else(|_| panic!("Failed to read the source code file {path}"));
27    parse_essence_with_context(&source_code, context)
28}
29
30pub fn parse_essence_with_context(
31    src: &str,
32    context: Arc<RwLock<Context<'static>>>,
33) -> Result<Model, EssenceParseError> {
34    let (tree, source_code) = match get_tree(src) {
35        Some(tree) => tree,
36        None => {
37            return Err(EssenceParseError::TreeSitterError(
38                "Failed to parse source code".to_string(),
39            ));
40        }
41    };
42
43    let mut model = Model::new(context);
44    // let symbols = model.as_submodel().symbols().clone();
45    let root_node = tree.root_node();
46    for statement in named_children(&root_node) {
47        match statement.kind() {
48            "single_line_comment" => {}
49            "find_statement_list" => {
50                let var_hashmap = parse_find_statement(statement, &source_code);
51                for (name, domain) in var_hashmap {
52                    model
53                        .as_submodel_mut()
54                        .symbols_mut()
55                        .insert(DeclarationPtr::new_var(name, domain));
56                }
57            }
58            "constraint_list" => {
59                let mut constraint_vec: Vec<Expression> = Vec::new();
60                for constraint in named_children(&statement) {
61                    let current_symbols = model.as_submodel().symbols().clone();
62
63                    if constraint.kind() != "single_line_comment" {
64                        constraint_vec.push(parse_expression(
65                            constraint,
66                            &source_code,
67                            &statement,
68                            &current_symbols,
69                        )?);
70                    }
71                }
72                model.as_submodel_mut().add_constraints(constraint_vec);
73            }
74            "language_label" => {}
75            "letting_statement_list" => {
76                let letting_vars = parse_letting_statement(statement, &source_code)?;
77                model.as_submodel_mut().symbols_mut().extend(letting_vars);
78            }
79            "dominance_relation" => {
80                let inner = statement
81                    .child(1)
82                    .expect("Expected a sub-expression inside `dominanceRelation`");
83                let current_symbols = model.as_submodel().symbols().clone();
84                let expr = parse_expression(inner, &source_code, &statement, &current_symbols)?;
85                let dominance = Expression::DominanceRelation(Metadata::new(), Moo::new(expr));
86                if model.dominance.is_some() {
87                    return Err(EssenceParseError::ParseError(Error::Parse(
88                        "Duplicate dominance relation".to_owned(),
89                    )));
90                }
91                model.dominance = Some(dominance);
92            }
93            _ => {
94                let kind = statement.kind();
95                return Err(EssenceParseError::ParseError(Error::Parse(format!(
96                    "Unrecognized top level statement kind: {kind}"
97                ))));
98            }
99        }
100    }
101    Ok(model)
102}