calyx_opt/traversal/
action.rs

1//! Actions control the traversal of control programs.
2use calyx_ir::Control;
3use calyx_ir::StaticControl;
4use calyx_utils::CalyxResult;
5
6/// Result of performing a visit.
7pub type VisResult = CalyxResult<Action>;
8
9/// Action performed at the end of visiting a control statement.
10pub enum Action {
11    /// Continue traversal of control program.
12    Continue,
13    /// Globally abort traversal of control program.
14    Stop,
15    /// Skips the traversal of this node's children but continues traversing\
16    /// the sibling nodes.
17    SkipChildren,
18    /// Replace the current ast node with a new node.
19    /// If performed using a start_* method, none of the newly created children
20    /// will be visited.
21    Change(Box<Control>),
22    /// Replace the current StaticControl node with a new node
23    /// If performed using a start_* method, none of the newly created children
24    /// will be visited.
25    StaticChange(Box<StaticControl>),
26}
27
28impl Action {
29    /// Run the traversal specified by `next` if this traversal succeeds.
30    /// If the result of this traversal is not `Action::Continue`, do not
31    /// run `next()`.
32    pub(super) fn and_then<F>(self, mut next: F) -> VisResult
33    where
34        F: FnMut() -> VisResult,
35    {
36        match self {
37            Action::Continue => next(),
38            Action::Change(_)
39            | Action::Stop
40            | Action::SkipChildren
41            | Action::StaticChange(_) => Ok(self),
42        }
43    }
44
45    pub fn change(control: Control) -> Self {
46        Action::Change(Box::new(control))
47    }
48
49    pub fn static_change(control: StaticControl) -> Self {
50        Action::StaticChange(Box::new(control))
51    }
52
53    /// Applies the Change action if `self` is a Change action.
54    /// Otherwise passes the action through unchanged
55    pub(super) fn apply_change(self, con: &mut Control) -> Action {
56        match self {
57            Action::Change(c) => {
58                *con = *c;
59                Action::Continue
60            }
61            action => action,
62        }
63    }
64
65    /// Applies the StaticChange action if `self is a StaticChange action.
66    /// Otherwise passes the action through unchanged
67    pub(super) fn apply_static_change(self, con: &mut StaticControl) -> Action {
68        match self {
69            Action::StaticChange(c) => {
70                *con = *c;
71                Action::Continue
72            }
73            action => action,
74        }
75    }
76
77    /// Changes a Action::SkipChildren to Action::Continue.
78    /// Should be called to indicate the boundary of traversing the children
79    /// of a node.
80    pub(super) fn pop(self) -> Self {
81        match self {
82            Action::SkipChildren => Action::Continue,
83            x => x,
84        }
85    }
86}