Skip to main content

conjure_cp_core/rule_engine/
rewrite_morph.rs

1use itertools::Itertools;
2use tree_morph::{helpers::select_panic, prelude::*};
3
4use crate::{Model, bug};
5
6use super::{RuleSet, get_rules_grouped};
7
8/// Rewrites a `Model` by applying rule sets using an optimized, tree-morphing rewriter.
9///
10/// This function traverses the expression tree of the model and applies the given rules
11/// to transform it. It operates on the model's internal structure, replacing the root
12/// expression and updating the symbol table based on the transformations performed by the
13/// `morph` function.
14///
15/// # Parameters
16///
17/// - `model`: The `Model` to be rewritten. It is consumed and a new, transformed version is returned.
18/// - `rule_sets`: A vector of `RuleSet` references containing the rules for transformation. These rules are grouped by priority before being applied.
19/// - `prop_multiple_equally_applicable`: A boolean flag to control behavior when multiple rules of the same priority can be applied to the same expression.
20///   - If `true`, the rewriter will use a selection strategy (`select_panic`) that panics.
21///   - If `false`, the rewriter will use a selection strategy (`select_first`) that simply picks the first applicable rule it encounters.
22///
23/// # Returns
24///
25/// The rewritten `Model` after all applicable rules have been applied.
26///
27/// # Panics
28///
29/// This function will panic under two conditions:
30/// - If the internal grouping of rules by priority fails (from `get_rules_grouped`).
31/// - If `prop_multiple_equally_applicable` is set to `true` and more than one rule of the same priority can be applied to the same expression.
32pub fn rewrite_morph<'a>(
33    mut model: Model,
34    rule_sets: &Vec<&'a RuleSet<'a>>,
35    prop_multiple_equally_applicable: bool,
36) -> Model {
37    let submodel = model.as_submodel_mut();
38    let rules_grouped = get_rules_grouped(rule_sets)
39        .unwrap_or_else(|_| bug!("get_rule_priorities() failed!"))
40        .into_iter()
41        .map(|(_, rule)| rule.into_iter().map(|f| f.rule).collect_vec())
42        .collect_vec();
43    let selector = if prop_multiple_equally_applicable {
44        select_panic
45    } else {
46        select_first
47    };
48
49    let engine = EngineBuilder::new()
50        .set_selector(selector)
51        .append_rule_groups(rules_grouped)
52        .build();
53    let (expr, symbol_table) = engine.morph(submodel.root().clone(), submodel.symbols().clone());
54
55    *submodel.symbols_mut() = symbol_table;
56    submodel.replace_root(expr);
57    model
58}