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