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}