1
//! Common utilities and types for rewriters.
2
use super::{
3
    resolve_rules::{ResolveRulesError, RuleData},
4
    Reduction,
5
};
6
use crate::{
7
    ast::{
8
        pretty::{pretty_variable_declaration, pretty_vec},
9
        Expression,
10
    },
11
    Model,
12
};
13

            
14
use itertools::Itertools;
15
use serde_json::json;
16
use std::fmt::Debug;
17
use thiserror::Error;
18
use tracing::{info, trace};
19

            
20
#[derive(Debug, Clone)]
21
pub struct RuleResult<'a> {
22
    pub rule_data: RuleData<'a>,
23
    pub reduction: Reduction,
24
}
25

            
26
/// Logs, to the main log, and the human readable traces used by the integration tester, that the
27
/// rule has been applied to the expression
28
12308
pub fn log_rule_application(
29
12308
    result: &RuleResult,
30
12308
    initial_expression: &Expression,
31
12308
    initial_model: &Model,
32
12308
) {
33
12308
    let red = &result.reduction;
34
12308
    let rule = result.rule_data.rule;
35
12308
    let new_top_string = pretty_vec(&red.new_top);
36
12308

            
37
12308
    info!(
38
        %new_top_string,
39
        "Applying rule: {} ({:?}), to expression: {}, resulting in: {}",
40
        rule.name,
41
        rule.rule_sets,
42
        initial_expression,
43
        red.new_expression
44
    );
45

            
46
    // empty if no top level constraints
47
12308
    let top_level_str = if red.new_top.is_empty() {
48
11135
        String::new()
49
    } else {
50
1173
        let mut exprs: Vec<String> = vec![];
51

            
52
2771
        for expr in &red.new_top {
53
1598
            exprs.push(format!("  {}", expr));
54
1598
        }
55

            
56
1173
        let exprs = exprs.iter().join("\n");
57
1173

            
58
1173
        format!("new constraints:\n{}\n", exprs)
59
    };
60

            
61
    // empty if no new variables
62
    // TODO: consider printing modified and removed declarations too, though removing a declaration in a rule is less likely.
63
12308
    let new_variables_str = {
64
12308
        let mut vars: Vec<String> = vec![];
65

            
66
12308
        for var_name in red.added_symbols(&initial_model.symbols()) {
67
1292
            #[allow(clippy::unwrap_used)]
68
1292
            vars.push(format!(
69
1292
                "  {}",
70
1292
                pretty_variable_declaration(&red.symbols, &var_name).unwrap()
71
1292
            ));
72
1292
        }
73
12308
        if vars.is_empty() {
74
11135
            String::new()
75
        } else {
76
1173
            format!("new variables:\n{}", vars.join("\n"))
77
        }
78
    };
79

            
80
12308
    trace!(
81
        target: "rule_engine_human",
82
12240
        "{}, \n   ~~> {} ({:?}) \n{} \n{}\n{}--\n",
83
        initial_expression,
84
        rule.name,
85
        rule.rule_sets,
86
        red.new_expression,
87
        new_variables_str,
88
        top_level_str
89
    );
90

            
91
12308
    trace!(
92
        target: "rule_engine",
93
12240
        "{}",
94
12240
    json!({
95
12240
        "rule_name": result.rule_data.rule.name,
96
12240
        "rule_priority": result.rule_data.priority,
97
12240
        "rule_set": {
98
12240
            "name": result.rule_data.rule_set.name,
99
12240
        },
100
12240
        "initial_expression": serde_json::to_value(initial_expression).unwrap(),
101
12240
        "transformed_expression": serde_json::to_value(&red.new_expression).unwrap()
102
12240
    })
103

            
104
    )
105
12308
}
106

            
107
/// Represents errors that can occur during the model rewriting process.
108
#[derive(Debug, Error)]
109
pub enum RewriteError {
110
    #[error("Error resolving rules {0}")]
111
    ResolveRulesError(ResolveRulesError),
112
}
113

            
114
impl From<ResolveRulesError> for RewriteError {
115
    fn from(error: ResolveRulesError) -> Self {
116
        RewriteError::ResolveRulesError(error)
117
    }
118
}