1
//! Perform gradual rule-based transformations on trees.
2
//!
3
//! See the [`morph`](Engine::morph) for more information.
4

            
5
use crate::cache::{CacheResult, RewriteCache};
6
use crate::engine_zipper::{EngineZipper, NaiveZipper};
7
use crate::events::EventHandlers;
8
use crate::helpers::{SelectorFn, one_or_select};
9
use crate::prelude::Rule;
10
use crate::rule::{RuleGroups, RuleSet, apply_into_update};
11
use crate::update::Update;
12

            
13
use rayon::prelude::*;
14
use tracing::{debug, error, info, instrument, trace};
15
use uniplate::Uniplate;
16

            
17
/// An engine for exhaustively transforming trees with user-defined rules.
18
///
19
/// See the [`morph`](Engine::morph) method for more information.
20
pub struct Engine<T, M, R, C>
21
where
22
    T: Uniplate + Send + Sync,
23
    R: Rule<T, M> + Clone,
24
    C: RewriteCache<T>,
25
{
26
    pub(crate) event_handlers: EventHandlers<T, M, R>,
27

            
28
    /// A collection of groups of equally-prioritised rules.
29
    pub(crate) rule_groups: RuleGroups<T, M, R>,
30

            
31
    pub(crate) selector: SelectorFn<T, M, R>,
32

            
33
    pub(crate) cache: C,
34

            
35
    /// Whether to use parallel (Rayon) iteration when checking rules.
36
    pub(crate) parallel: bool,
37

            
38
    pub(crate) fixedpoint: bool,
39

            
40
    pub(crate) down_predicate: fn(&T) -> bool,
41
}
42

            
43
impl<T, M, R, C> Engine<T, M, R, C>
44
where
45
    T: Uniplate + Send + Sync,
46
    R: Rule<T, M> + Clone + Sync,
47
    M: Sync,
48
    C: RewriteCache<T>,
49
{
50
    #[instrument(skip(selector, parallel, subtree, meta, rules, event_handlers))]
51
95512927
    fn select_rule<'a>(
52
95512927
        selector: SelectorFn<T, M, R>,
53
95512927
        parallel: bool,
54
95512927
        subtree: &T,
55
95512927
        meta: &mut M,
56
95512927
        rules: RuleSet<'a, R>,
57
95512927
        event_handlers: &EventHandlers<T, M, R>,
58
95512927
    ) -> Option<(&'a R, Update<T, M>)> {
59
95512927
        trace!("Beginning Rule Checks");
60
95512927
        if parallel {
61
            let applicable: Vec<(&'a R, Update<T, M>)> = rules
62
                .par_iter()
63
                .filter_map(|rule| {
64
                    let update = apply_into_update(rule, subtree, meta)?;
65
                    Some((rule, update))
66
                })
67
                .collect();
68
            trace!("Finished Rule Checks");
69
            one_or_select(selector, subtree, &mut applicable.into_iter())
70
        } else {
71
403229918
            let applicable = &mut rules.into_iter().filter_map(|rule| {
72
403229918
                event_handlers.trigger_before_rule(subtree, meta, rule);
73
403229918
                let result = apply_into_update(rule, subtree, meta);
74
403229918
                let is_applicable = result.is_some();
75
403229918
                event_handlers.trigger_after_rule(subtree, meta, rule, is_applicable);
76
403229918
                let update = result?;
77
290977
                Some((rule, update))
78
403229918
            });
79
95512927
            trace!("Finished Rule Checks");
80
95512927
            one_or_select(selector, subtree, applicable)
81
        }
82
95512927
    }
83

            
84
43
    fn apply_rule(
85
43
        zipper: &mut EngineZipper<T, M, R, C>,
86
43
        event_handlers: &EventHandlers<T, M, R>,
87
43
        application: (&R, Update<T, M>),
88
43
        level: usize,
89
43
    ) {
90
43
        let (rule, mut update) = application;
91
        debug!("Applying Rule '{}'", rule.name());
92

            
93
43
        let cache_active = zipper.cache.is_active();
94
43
        let original = cache_active.then(|| zipper.focus().clone());
95

            
96
        // Clear any stale cached hashes in the replacement subtree
97
43
        zipper.cache.invalidate_subtree(&update.new_subtree);
98

            
99
43
        let replacement = cache_active.then(|| update.new_subtree.clone());
100

            
101
        // Replace the current subtree, invalidating subtree node states
102
43
        zipper.replace_focus(update.new_subtree);
103

            
104
        // Mark all ancestors as dirty, insert ancestor mappings, and move back to the root
105
43
        zipper.mark_dirty_to_root(level);
106

            
107
43
        let (focus, meta) = zipper.focus_and_meta();
108
43
        let (new_tree, root_transformed) = update.commands.apply(focus.clone(), meta);
109

            
110
43
        if root_transformed {
111
            debug!("Root transformed, clearing state.");
112
            // This must unfortunately throw all node states away,
113
            // since the `transform` command may redefine the whole tree
114
            zipper.replace_focus(new_tree);
115
43
        } else if let (Some(orig), Some(repl)) = (original, replacement) {
116
7
            if orig != repl {
117
7
                zipper.cache.insert(&orig, Some(repl), level);
118
7
            } else {
119
                error!("Original Subtree is the same as Replacement Tree");
120
            }
121
36
        }
122

            
123
43
        let (focus, meta) = zipper.focus_and_meta();
124
43
        event_handlers.trigger_on_apply(focus, meta, rule);
125
43
    }
126

            
127
1334
    fn apply_rule_fixedpoint(
128
1334
        zipper: &mut EngineZipper<T, M, R, C>,
129
1334
        event_handlers: &EventHandlers<T, M, R>,
130
1334
        rule_groups: &RuleGroups<T, M, R>,
131
1334
        selector: SelectorFn<T, M, R>,
132
1334
        parallel: bool,
133
1334
        application: (&R, Update<T, M>),
134
1334
        level: usize,
135
1334
    ) {
136
        // Apply the initial rule
137
1334
        let (rule, mut update) = application;
138
        debug!("Applying Rules in Fixed Point Mode");
139

            
140
1334
        if update.has_transform() {
141
            trace!("Rule has Transform. Stopping Fixed Point");
142
            Self::apply_rule(zipper, event_handlers, (rule, update), level);
143
            return;
144
1334
        }
145

            
146
        // No transform — apply locally
147
1334
        let cache_active = zipper.cache.is_active();
148
1334
        let original = cache_active.then(|| zipper.focus().clone());
149
1334
        zipper.cache.invalidate_subtree(&update.new_subtree);
150
1334
        let replacement = cache_active.then(|| update.new_subtree.clone());
151
1334
        zipper.replace_focus(update.new_subtree);
152

            
153
1334
        {
154
1334
            let (focus, meta) = zipper.focus_and_meta();
155
1334
            update.commands.apply(focus.clone(), meta);
156
1334
        }
157

            
158
1334
        if let (Some(orig), Some(repl)) = (original, replacement) {
159
            if orig != repl {
160
                zipper.cache.insert(&orig, Some(repl), level);
161
            } else {
162
                error!("Original Subtree is the same as Replacement Tree");
163
            }
164
1334
        }
165

            
166
1334
        let (focus, meta) = zipper.focus_and_meta();
167
1334
        event_handlers.trigger_on_apply(focus, meta, rule);
168

            
169
1334
        let mut try_level = 0;
170
12944
        while try_level <= level {
171
11610
            let subtree = zipper.focus();
172
11610
            let id = rule_groups.discriminant_fn.map(|f| f(subtree));
173
11610
            let rules = rule_groups.get_rules(try_level, id);
174

            
175
11610
            let (subtree, meta) = zipper.focus_and_meta();
176
11610
            match Self::select_rule(selector, parallel, subtree, meta, rules, event_handlers) {
177
98
                Some((rule, mut update)) => {
178
98
                    if update.has_transform() {
179
                        trace!("Rule has Transform. Stopping Fixed Point");
180
                        Self::apply_rule(zipper, event_handlers, (rule, update), level);
181
                        return;
182
98
                    }
183

            
184
                    debug!("Applying Rule '{}' till Fixed Point (local)", rule.name());
185
98
                    let cache_active = zipper.cache.is_active();
186
98
                    let original = cache_active.then(|| zipper.focus().clone());
187
98
                    zipper.cache.invalidate_subtree(&update.new_subtree);
188
98
                    let replacement = cache_active.then(|| update.new_subtree.clone());
189
98
                    zipper.replace_focus(update.new_subtree);
190

            
191
98
                    {
192
98
                        let (focus, meta) = zipper.focus_and_meta();
193
98
                        update.commands.apply(focus.clone(), meta);
194
98
                    }
195

            
196
98
                    if let (Some(orig), Some(repl)) = (original, replacement) {
197
                        if orig != repl {
198
                            zipper.cache.insert(&orig, Some(repl), level);
199
                        } else {
200
                            error!("Original Subtree is the same as Replacement Tree");
201
                        }
202
98
                    }
203

            
204
98
                    let (focus, meta) = zipper.focus_and_meta();
205
98
                    event_handlers.trigger_on_apply(focus, meta, rule);
206

            
207
98
                    try_level = 0;
208
                }
209
11512
                None => {
210
11512
                    try_level += 1;
211
11512
                }
212
            }
213
        }
214

            
215
        // Node stabilized — mark pass-through and go to root
216
1334
        zipper.set_pass_through(level);
217
1334
        zipper.mark_dirty_to_root(level);
218
1334
    }
219

            
220
    fn apply_rule_naive_fixedpoint(
221
        zipper: &mut NaiveZipper<T, M, R, C>,
222
        event_handlers: &EventHandlers<T, M, R>,
223
        rule_groups: &RuleGroups<T, M, R>,
224
        selector: SelectorFn<T, M, R>,
225
        parallel: bool,
226
        application: (&R, Update<T, M>),
227
        level: usize,
228
    ) -> bool {
229
        let (rule, mut update) = application;
230
        debug!("Applying Rule '{}' in Fast Mode (naive)", rule.name());
231

            
232
        if update.has_transform() {
233
            trace!("Rule has Transform. Stopping Fixed Point");
234
            Self::apply_rule_naive(zipper, event_handlers, (rule, update), level);
235
            return false;
236
        }
237

            
238
        // No transform — apply locally (no root traversal)
239
        let cache_active = zipper.cache.is_active();
240
        let original = cache_active.then(|| zipper.focus().clone());
241
        zipper.cache.invalidate_subtree(&update.new_subtree);
242
        let replacement = cache_active.then(|| update.new_subtree.clone());
243
        zipper.replace_focus(update.new_subtree);
244

            
245
        {
246
            let (focus, meta) = zipper.focus_and_meta();
247
            update.commands.apply(focus.clone(), meta);
248
        }
249

            
250
        if let (Some(orig), Some(repl)) = (original, replacement) {
251
            if orig != repl {
252
                zipper.cache.insert(&orig, Some(repl), level);
253
            } else {
254
                error!("Original Subtree is the same as Replacement Tree");
255
            }
256
        }
257

            
258
        let (focus, meta) = zipper.focus_and_meta();
259
        event_handlers.trigger_on_apply(focus, meta, rule);
260

            
261
        // Try rules from level 0 up to current level
262
        let mut try_level = 0;
263
        while try_level <= level {
264
            let subtree = zipper.focus();
265
            let id = rule_groups.discriminant_fn.map(|f| f(subtree));
266
            let rules = rule_groups.get_rules(try_level, id);
267

            
268
            let (subtree, meta) = zipper.focus_and_meta();
269
            match Self::select_rule(selector, parallel, subtree, meta, rules, event_handlers) {
270
                Some((rule, mut update)) => {
271
                    if update.has_transform() {
272
                        trace!("Rule has Transform. Stopping Fixed Point");
273
                        Self::apply_rule_naive(zipper, event_handlers, (rule, update), level);
274
                        return false;
275
                    }
276

            
277
                    debug!(
278
                        "Applying Rule '{}' in Fast Mode (naive, local)",
279
                        rule.name()
280
                    );
281
                    let cache_active = zipper.cache.is_active();
282
                    let original = cache_active.then(|| zipper.focus().clone());
283
                    zipper.cache.invalidate_subtree(&update.new_subtree);
284
                    let replacement = cache_active.then(|| update.new_subtree.clone());
285
                    zipper.replace_focus(update.new_subtree);
286

            
287
                    {
288
                        let (focus, meta) = zipper.focus_and_meta();
289
                        update.commands.apply(focus.clone(), meta);
290
                    }
291

            
292
                    if let (Some(orig), Some(repl)) = (original, replacement) {
293
                        if orig != repl {
294
                            zipper.cache.insert(&orig, Some(repl), level);
295
                        } else {
296
                            error!("Original Subtree is the same as Replacement Tree");
297
                        }
298
                    }
299

            
300
                    let (focus, meta) = zipper.focus_and_meta();
301
                    event_handlers.trigger_on_apply(focus, meta, rule);
302

            
303
                    try_level = 0;
304
                }
305
                None => {
306
                    try_level += 1;
307
                }
308
            }
309
        }
310

            
311
        // Node stabilized — need to go to root and rebuild ancestors
312
        zipper.map_ancestors_to_root(level);
313
        true
314
    }
315

            
316
289420
    fn apply_rule_naive(
317
289420
        zipper: &mut NaiveZipper<T, M, R, C>,
318
289420
        event_handlers: &EventHandlers<T, M, R>,
319
289420
        application: (&R, Update<T, M>),
320
289420
        level: usize,
321
289420
    ) {
322
289420
        let (rule, mut update) = application;
323
        debug!("Applying Rule '{}'", rule.name());
324

            
325
289420
        let cache_active = zipper.cache.is_active();
326
289420
        let original = cache_active.then(|| zipper.focus().clone());
327
289420
        zipper.cache.invalidate_subtree(&update.new_subtree);
328
289420
        let replacement = cache_active.then(|| update.new_subtree.clone());
329

            
330
289420
        zipper.replace_focus(update.new_subtree);
331
289420
        zipper.map_ancestors_to_root(level);
332

            
333
289420
        let (focus, meta) = zipper.focus_and_meta();
334
289420
        let (new_tree, root_transformed) = update.commands.apply(focus.clone(), meta);
335

            
336
289420
        if root_transformed {
337
26420
            trace!("Root transformed.");
338
26420
            zipper.replace_focus(new_tree);
339
263000
        } else if let (Some(orig), Some(repl)) = (original, replacement) {
340
            if orig != repl {
341
                zipper.cache.insert(&orig, Some(repl), level);
342
            } else {
343
                error!("Original Subtree is the same as Replacement Tree");
344
            }
345
263000
        }
346

            
347
289420
        let (focus, meta) = zipper.focus_and_meta();
348
289420
        event_handlers.trigger_on_apply(focus, meta, rule);
349
289420
    }
350

            
351
    /// Exhaustively rewrites a tree using user-defined rule groups.
352
    ///
353
    /// Rewriting is complete when all rules have been attempted with no change. Rules may be organised
354
    /// into groups to control the order in which they are attempted.
355
    ///
356
    /// # Rule Groups
357
    /// If all rules are treated equally, those which apply higher in the tree will take precedence
358
    /// because of the left-most outer-most traversal order of the engine.
359
    ///
360
    /// This can cause problems if a rule which should ideally be applied early (e.g. evaluating
361
    /// constant expressions) is left until later.
362
    ///
363
    /// To solve this, rules are organised into different collections or "groups".
364
    /// The engine will apply rules in an earlier group to the entire tree before trying later groups.
365
    /// That is, no rule is attempted if a rule in an earlier group is applicable to any part of the
366
    /// tree.
367
    ///
368
    /// # Selector Functions
369
    ///
370
    /// If multiple rules in the same group are applicable to an expression, the user-defined
371
    /// selector function is used to choose one. This function is given an iterator over pairs of
372
    /// rules and the engine-created [`Update`] values which contain their modifications to the tree.
373
    ///
374
    /// Some useful selector functions are available in the [`helpers`](crate::helpers) module. One
375
    /// common function is [`select_first`](crate::helpers::select_first), which simply returns the
376
    /// first applicable rule.
377
    ///
378
    /// # Event Handlers
379
    ///
380
    /// The engine provides events for more fine-tuned control over rewriting behaviour. Events have mutable
381
    /// access to the current metadata.
382
    ///
383
    /// The engine will call the provided handlers for the "enter" and
384
    /// "exits" events as it enters and exits subtrees while traversing, respectively.
385
    ///
386
    /// The "enter" event is triggered first on the root, and then whenever the engine moves down
387
    /// into a subtree. As a result, when a node is passed to rules, all nodes above it will have
388
    /// been passed to handlers for this event, in ascending order of their proximity to the root.
389
    ///
390
    /// The "exit" event is triggered when the engine leaves a subtree.
391
    /// All nodes passed to "enter" event handlers (except the root) will also be passed to "exit"
392
    /// event handlers in reverse order.
393
    ///
394
    /// In effect, before a node is passed to rules, all nodes in the path from the root (including the
395
    /// current node) will have been passed to the "enter" event in order. No nodes are skipped.
396
    ///
397
    /// Event handling is useful when, for example, using a symbol table to keep track of variable definitions.
398
    /// When entering a scope where a variable is defined, one can place the variable and its value into the table.
399
    /// That stack can then be used for quick value lookup while inside the scope. When leaving the scope the
400
    /// variable can be removed from the table.
401
    ///
402
    /// # Optimizations
403
    ///
404
    /// To optimize the morph function, we use a dirty/clean approach. Since whether a rule applies
405
    /// is purely a function of a node and its children, rules should only be checked once unless a node
406
    /// or one of its children has been changed.
407
    ///
408
    /// # Example
409
    /// ```rust
410
    /// use tree_morph::{prelude::*, helpers::select_panic};
411
    /// use uniplate::Uniplate;
412
    ///
413
    ///
414
    /// // A simple language of multiplied and squared constant expressions
415
    /// #[derive(Debug, Clone, PartialEq, Eq, Uniplate)]
416
    /// #[uniplate()]
417
    /// enum Expr {
418
    ///     Val(i32),
419
    ///     Mul(Box<Expr>, Box<Expr>),
420
    ///     Sqr(Box<Expr>),
421
    /// }
422
    ///
423
    /// // a * b ~> (value of) a * b, where 'a' and 'b' are literal values
424
    /// fn rule_eval_mul(cmds: &mut Commands<Expr, i32>, subtree: &Expr, meta: &i32) -> Option<Expr> {
425
    ///     cmds.mut_meta(Box::new(|m: &mut i32| *m += 1));
426
    ///
427
    ///     if let Expr::Mul(a, b) = subtree {
428
    ///         if let (Expr::Val(a_v), Expr::Val(b_v)) = (a.as_ref(), b.as_ref()) {
429
    ///             return Some(Expr::Val(a_v * b_v));
430
    ///         }
431
    ///     }
432
    ///     None
433
    /// }
434
    ///
435
    /// // e ^ 2 ~> e * e, where e is an expression
436
    /// // If this rule is applied before the sub-expression is fully evaluated, duplicate work
437
    /// // will be done on the resulting two identical sub-expressions.
438
    /// fn rule_expand_sqr(cmds: &mut Commands<Expr, i32>, subtree: &Expr, meta: &i32) -> Option<Expr> {
439
    ///     cmds.mut_meta(Box::new(|m: &mut i32| *m += 1));
440
    ///
441
    ///     if let Expr::Sqr(expr) = subtree {
442
    ///         return Some(Expr::Mul(
443
    ///             Box::new(*expr.clone()),
444
    ///             Box::new(*expr.clone())
445
    ///         ));
446
    ///     }
447
    ///     None
448
    /// }
449
    ///
450
    /// // (1 * 2) ^ 2
451
    /// let expr = Expr::Sqr(
452
    ///     Box::new(Expr::Mul(
453
    ///         Box::new(Expr::Val(1)),
454
    ///         Box::new(Expr::Val(2))
455
    ///     ))
456
    /// );
457
    ///
458
    /// // Try with both rules in the same group, keeping track of the number of rule applications
459
    /// let mut engine = EngineBuilder::new()
460
    ///     .set_selector(select_panic)
461
    ///     .add_rule_group(rule_fns![rule_eval_mul, rule_expand_sqr])
462
    ///     .build();
463
    /// let (result, num_applications) = engine.morph(expr.clone(), 0);
464
    /// assert_eq!(result, Expr::Val(4));
465
    /// assert_eq!(num_applications, 4); // The `Sqr` is expanded first, causing duplicate work
466
    ///
467
    /// // Move the evaluation rule to an earlier group
468
    /// let mut engine = EngineBuilder::new()
469
    ///     .set_selector(select_panic)
470
    ///     .add_rule_group(rule_fns![rule_eval_mul])
471
    ///     .add_rule_group(rule_fns![rule_expand_sqr])
472
    ///     .build();
473
    /// let (result, num_applications) = engine.morph(expr.clone(), 0);
474
    /// assert_eq!(result, Expr::Val(4));
475
    /// assert_eq!(num_applications, 3); // Now the sub-expression (1 * 2) is evaluated first
476
    /// ```
477
    // #[instrument(skip(self, tree, meta))]
478
35
    pub fn morph(&mut self, tree: T, meta: M) -> (T, M)
479
35
    where
480
35
        T: Uniplate + Send + Sync,
481
35
        R: Rule<T, M>,
482
    {
483
        // Owns the tree/meta and is consumed to get them back at the end
484
35
        let mut zipper = EngineZipper::new(
485
35
            tree,
486
35
            meta,
487
35
            self.down_predicate,
488
35
            &self.event_handlers,
489
35
            &mut self.cache,
490
        );
491
35
        info!("Beginning Morph");
492

            
493
        'main: loop {
494
            // Return here after every successful rule application
495
11547
            for level in 0..self.rule_groups.levels() {
496
1226276
                while zipper.go_next_dirty(level).is_some() {
497
1216114
                    trace!("Got Dirty, Level {}", level);
498

            
499
                    {
500
1216114
                        let subtree = zipper.focus();
501
1216114
                        let id = self.rule_groups.discriminant_fn.map(|f| f(subtree));
502
1216114
                        let rules = self.rule_groups.get_rules(level, id);
503

            
504
                        debug!("Checking Level {} with {} Rules", level, rules.len());
505
1216114
                        match zipper.cache.get(subtree, level) {
506
9
                            CacheResult::Terminal(clean_level) => {
507
                                debug!(
508
                                    "Cache Hit - Nothing Applicable (clean through level {})",
509
                                    clean_level
510
                                );
511
9
                                zipper.trigger_cache_hit();
512
9
                                zipper.set_dirty_from(clean_level + 1);
513
9
                                continue;
514
                            }
515
8
                            CacheResult::Rewrite(cached) => {
516
                                debug!("Cache Hit");
517
8
                                zipper.trigger_cache_hit();
518
8
                                zipper.replace_focus(cached);
519
8
                                zipper.mark_dirty_to_root(level);
520
8
                                continue 'main;
521
                            }
522
1216097
                            _ => {
523
1216097
                                zipper.trigger_cache_miss();
524
1216097
                            }
525
                        };
526
                    }
527

            
528
                    // Choose one transformation from all applicable rules at this level
529
1216097
                    let (subtree, meta) = zipper.focus_and_meta();
530
1216097
                    let id = self.rule_groups.discriminant_fn.map(|f| f(subtree));
531

            
532
1216097
                    let rules = self.rule_groups.get_rules(level, id);
533
1216097
                    match Self::select_rule(
534
1216097
                        self.selector,
535
1216097
                        self.parallel,
536
1216097
                        subtree,
537
1216097
                        meta,
538
1216097
                        rules,
539
1216097
                        &self.event_handlers,
540
1216097
                    ) {
541
1377
                        Some(selected) => {
542
1377
                            if self.fixedpoint {
543
1334
                                Self::apply_rule_fixedpoint(
544
1334
                                    &mut zipper,
545
1334
                                    &self.event_handlers,
546
1334
                                    &self.rule_groups,
547
1334
                                    self.selector,
548
1334
                                    self.parallel,
549
1334
                                    selected,
550
1334
                                    level,
551
1334
                                );
552
1377
                            } else {
553
43
                                Self::apply_rule(
554
43
                                    &mut zipper,
555
43
                                    &self.event_handlers,
556
43
                                    selected,
557
43
                                    level,
558
43
                                );
559
43
                            }
560
1377
                            continue 'main;
561
                        }
562
                        None => {
563
1214720
                            trace!("Nothing Applicable");
564
1214720
                            if zipper.cache.is_active() {
565
24
                                let subtree = zipper.focus().clone();
566
24
                                zipper.cache.insert(&subtree, None, level);
567
1214701
                            }
568
1214720
                            zipper.set_dirty_from(level + 1);
569
                        }
570
                    }
571
                }
572
            }
573

            
574
            // All rules have been tried with no more changes
575
35
            break;
576
        }
577

            
578
35
        info!("Finished Morph");
579
35
        zipper.into()
580
35
    }
581

            
582
    /// Exhaustively rewrites a tree using user-defined rule groups.
583
    ///
584
    /// It is not recommended to use this function besides testing and for correctness.
585
39220
    pub fn morph_naive(&mut self, tree: T, meta: M) -> (T, M)
586
39220
    where
587
39220
        T: Uniplate,
588
39220
        R: Rule<T, M>,
589
    {
590
39220
        let mut zipper = NaiveZipper::new(
591
39220
            tree,
592
39220
            meta,
593
39220
            self.down_predicate,
594
39220
            &self.event_handlers,
595
39220
            &mut self.cache,
596
        );
597
39220
        info!("Beginning Naive Morph");
598

            
599
        'main: loop {
600
2667440
            for level in 0..self.rule_groups.levels() {
601
                loop {
602
                    {
603
94285220
                        let subtree = zipper.focus();
604
94285220
                        match zipper.cache.get(subtree, level) {
605
                            CacheResult::Terminal(_clean_level) => {
606
                                debug!("Cache Hit - Nothing Applicable");
607
                                zipper.trigger_cache_hit();
608
                                if zipper.get_next().is_none() {
609
                                    break;
610
                                }
611
                                continue;
612
                            }
613
                            CacheResult::Rewrite(cached) => {
614
                                debug!("Cache Hit");
615
                                zipper.trigger_cache_hit();
616
                                zipper.replace_focus(cached);
617
                                zipper.map_ancestors_to_root(level);
618
                                continue 'main;
619
                            }
620
94285220
                            _ => {
621
94285220
                                zipper.trigger_cache_miss();
622
94285220
                            }
623
                        };
624
                    }
625

            
626
94285220
                    let (subtree, meta) = zipper.focus_and_meta();
627
94285220
                    let id = self.rule_groups.discriminant_fn.map(|f| f(subtree));
628
94285220
                    let rules = self.rule_groups.get_rules(level, id);
629
                    debug!("Checking Level {} with {} Rules", level, rules.len());
630
                    // Choose one transformation from all applicable rules at this level
631
94285220
                    let selected = Self::select_rule(
632
94285220
                        self.selector,
633
94285220
                        self.parallel,
634
94285220
                        subtree,
635
94285220
                        meta,
636
94285220
                        rules,
637
94285220
                        &self.event_handlers,
638
                    );
639

            
640
94285220
                    if let Some(selected) = selected {
641
289420
                        if self.fixedpoint {
642
                            let stabilized = Self::apply_rule_naive_fixedpoint(
643
                                &mut zipper,
644
                                &self.event_handlers,
645
                                &self.rule_groups,
646
                                self.selector,
647
                                self.parallel,
648
                                selected,
649
                                level,
650
                            );
651
                            if !stabilized {
652
                                continue 'main;
653
                            }
654
                            // Stabilized — continue 'main to restart from root
655
                            continue 'main;
656
289420
                        } else {
657
289420
                            Self::apply_rule_naive(
658
289420
                                &mut zipper,
659
289420
                                &self.event_handlers,
660
289420
                                selected,
661
289420
                                level,
662
289420
                            );
663
289420
                        }
664
289420
                        continue 'main;
665
                    } else {
666
                        debug!("Nothing Applicable");
667
93995800
                        if zipper.cache.is_active() {
668
                            let subtree = zipper.focus().clone();
669
                            zipper.cache.insert(&subtree, None, level);
670
93995800
                        }
671
                    }
672

            
673
93995800
                    if zipper.get_next().is_none() {
674
2378020
                        break;
675
91617780
                    }
676
                }
677
            }
678

            
679
39220
            break;
680
        }
681

            
682
39220
        info!("Finished Naive Morph");
683
39220
        zipper.into_parts()
684
39220
    }
685
}