use alloc::vec::Vec;
use crate::ir::{Block, Chart, Exec, ExecKind, State, Transition};
#[derive(Clone, Copy, Debug)]
pub enum DocNode<'a> {
State(&'a State),
Transition {
source: &'a str,
index: usize,
transition: &'a Transition,
},
InitialTransition {
state: &'a str,
transition: &'a Transition,
},
Exec(&'a Exec),
}
pub fn document_order(chart: &Chart) -> Vec<DocNode<'_>> {
let mut out = Vec::new();
for s in &chart.states {
walk_state(s, &mut out);
}
out
}
pub fn state_order(chart: &Chart) -> Vec<&str> {
let mut out = Vec::new();
fn go<'a>(s: &'a State, out: &mut Vec<&'a str>) {
out.push(s.id.as_str());
for c in &s.children {
go(c, out);
}
}
for s in &chart.states {
go(s, &mut out);
}
out
}
fn walk_state<'a>(s: &'a State, out: &mut Vec<DocNode<'a>>) {
out.push(DocNode::State(s));
if let Some(init) = &s.initial_element {
out.push(DocNode::InitialTransition {
state: s.id.as_str(),
transition: &init.transition,
});
walk_block(&init.transition.body, out);
}
for b in &s.onentry {
walk_block(b, out);
}
for b in &s.onexit {
walk_block(b, out);
}
for (index, t) in s.transitions.iter().enumerate() {
out.push(DocNode::Transition {
source: s.id.as_str(),
index,
transition: t,
});
walk_block(&t.body, out);
}
for inv in &s.invokes {
walk_block(&inv.finalize, out);
}
for c in &s.children {
walk_state(c, out);
}
}
fn walk_block<'a>(b: &'a Block, out: &mut Vec<DocNode<'a>>) {
for e in b {
out.push(DocNode::Exec(e));
match &e.kind {
ExecKind::If { branches } => {
for br in branches {
walk_block(&br.body, out);
}
}
ExecKind::Foreach { body, .. } => walk_block(body, out),
_ => {}
}
}
}
pub fn same_chart(a: &Chart, b: &Chart) -> bool {
a == b
}