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
98496541
    fn select_rule<'a>(
52
98496541
        selector: SelectorFn<T, M, R>,
53
98496541
        parallel: bool,
54
98496541
        subtree: &T,
55
98496541
        meta: &mut M,
56
98496541
        rules: RuleSet<'a, R>,
57
98496541
        event_handlers: &EventHandlers<T, M, R>,
58
98496541
    ) -> Option<(&'a R, Update<T, M>)> {
59
98496541
        trace!("Beginning Rule Checks");
60
98496541
        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
413428280
            let applicable = &mut rules.into_iter().filter_map(|rule| {
72
413428280
                event_handlers.trigger_before_rule(subtree, meta, rule);
73
413428280
                let result = apply_into_update(rule, subtree, meta);
74
413428280
                let is_applicable = result.is_some();
75
413428280
                event_handlers.trigger_after_rule(subtree, meta, rule, is_applicable);
76
413428280
                let update = result?;
77
300485
                Some((rule, update))
78
413428280
            });
79
98496541
            trace!("Finished Rule Checks");
80
98496541
            one_or_select(selector, subtree, applicable)
81
        }
82
98496541
    }
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
2624
    fn apply_rule_fixedpoint(
128
2624
        zipper: &mut EngineZipper<T, M, R, C>,
129
2624
        event_handlers: &EventHandlers<T, M, R>,
130
2624
        rule_groups: &RuleGroups<T, M, R>,
131
2624
        selector: SelectorFn<T, M, R>,
132
2624
        parallel: bool,
133
2624
        application: (&R, Update<T, M>),
134
2624
        level: usize,
135
2624
    ) {
136
        // Apply the initial rule
137
2624
        let (rule, mut update) = application;
138
        debug!("Applying Rules in Fixed Point Mode");
139

            
140
2624
        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
2624
        }
145

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

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

            
158
2624
        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
2624
        }
165

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

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

            
175
23156
            let (subtree, meta) = zipper.focus_and_meta();
176
23156
            match Self::select_rule(selector, parallel, subtree, meta, rules, event_handlers) {
177
196
                Some((rule, mut update)) => {
178
196
                    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
196
                    }
183

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

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

            
196
196
                    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
196
                    }
203

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

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

            
215
        // Node stabilized — mark pass-through and go to root
216
2624
        zipper.set_pass_through(level);
217
2624
        zipper.mark_dirty_to_root(level);
218
2624
    }
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
297540
    fn apply_rule_naive(
317
297540
        zipper: &mut NaiveZipper<T, M, R, C>,
318
297540
        event_handlers: &EventHandlers<T, M, R>,
319
297540
        application: (&R, Update<T, M>),
320
297540
        level: usize,
321
297540
    ) {
322
297540
        let (rule, mut update) = application;
323
        debug!("Applying Rule '{}'", rule.name());
324

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

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

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

            
336
297540
        if root_transformed {
337
27940
            trace!("Root transformed.");
338
27940
            zipper.replace_focus(new_tree);
339
269600
        } 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
269600
        }
346

            
347
297540
        let (focus, meta) = zipper.focus_and_meta();
348
297540
        event_handlers.trigger_on_apply(focus, meta, rule);
349
297540
    }
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
45
    pub fn morph(&mut self, tree: T, meta: M) -> (T, M)
479
45
    where
480
45
        T: Uniplate + Send + Sync,
481
45
        R: Rule<T, M>,
482
    {
483
        // Owns the tree/meta and is consumed to get them back at the end
484
45
        let mut zipper = EngineZipper::new(
485
45
            tree,
486
45
            meta,
487
45
            self.down_predicate,
488
45
            &self.event_handlers,
489
45
            &mut self.cache,
490
        );
491
45
        info!("Beginning Morph");
492

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

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

            
504
                        debug!("Checking Level {} with {} Rules", level, rules.len());
505
2375202
                        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
2375185
                            _ => {
523
2375185
                                zipper.trigger_cache_miss();
524
2375185
                            }
525
                        };
526
                    }
527

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

            
532
2375185
                    let rules = self.rule_groups.get_rules(level, id);
533
2375185
                    match Self::select_rule(
534
2375185
                        self.selector,
535
2375185
                        self.parallel,
536
2375185
                        subtree,
537
2375185
                        meta,
538
2375185
                        rules,
539
2375185
                        &self.event_handlers,
540
2375185
                    ) {
541
2667
                        Some(selected) => {
542
2667
                            if self.fixedpoint {
543
2624
                                Self::apply_rule_fixedpoint(
544
2624
                                    &mut zipper,
545
2624
                                    &self.event_handlers,
546
2624
                                    &self.rule_groups,
547
2624
                                    self.selector,
548
2624
                                    self.parallel,
549
2624
                                    selected,
550
2624
                                    level,
551
2624
                                );
552
2667
                            } 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
2667
                            continue 'main;
561
                        }
562
                        None => {
563
2372518
                            trace!("Nothing Applicable");
564
2372518
                            if zipper.cache.is_active() {
565
24
                                let subtree = zipper.focus().clone();
566
24
                                zipper.cache.insert(&subtree, None, level);
567
2372499
                            }
568
2372518
                            zipper.set_dirty_from(level + 1);
569
                        }
570
                    }
571
                }
572
            }
573

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

            
578
45
        info!("Finished Morph");
579
45
        zipper.into()
580
45
    }
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
40200
    pub fn morph_naive(&mut self, tree: T, meta: M) -> (T, M)
586
40200
    where
587
40200
        T: Uniplate,
588
40200
        R: Rule<T, M>,
589
    {
590
40200
        let mut zipper = NaiveZipper::new(
591
40200
            tree,
592
40200
            meta,
593
40200
            self.down_predicate,
594
40200
            &self.event_handlers,
595
40200
            &mut self.cache,
596
        );
597
40200
        info!("Beginning Naive Morph");
598

            
599
        'main: loop {
600
2736380
            for level in 0..self.rule_groups.levels() {
601
                loop {
602
                    {
603
96098200
                        let subtree = zipper.focus();
604
96098200
                        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
96098200
                            _ => {
621
96098200
                                zipper.trigger_cache_miss();
622
96098200
                            }
623
                        };
624
                    }
625

            
626
96098200
                    let (subtree, meta) = zipper.focus_and_meta();
627
96098200
                    let id = self.rule_groups.discriminant_fn.map(|f| f(subtree));
628
96098200
                    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
96098200
                    let selected = Self::select_rule(
632
96098200
                        self.selector,
633
96098200
                        self.parallel,
634
96098200
                        subtree,
635
96098200
                        meta,
636
96098200
                        rules,
637
96098200
                        &self.event_handlers,
638
                    );
639

            
640
96098200
                    if let Some(selected) = selected {
641
297540
                        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
297540
                        } else {
657
297540
                            Self::apply_rule_naive(
658
297540
                                &mut zipper,
659
297540
                                &self.event_handlers,
660
297540
                                selected,
661
297540
                                level,
662
297540
                            );
663
297540
                        }
664
297540
                        continue 'main;
665
                    } else {
666
                        debug!("Nothing Applicable");
667
95800660
                        if zipper.cache.is_active() {
668
                            let subtree = zipper.focus().clone();
669
                            zipper.cache.insert(&subtree, None, level);
670
95800660
                        }
671
                    }
672

            
673
95800660
                    if zipper.get_next().is_none() {
674
2438840
                        break;
675
93361820
                    }
676
                }
677
            }
678

            
679
40200
            break;
680
        }
681

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