use crate::StrVec;
use crate::analysis::LookaheadDFA;
pub fn render_dfa_dot_string(dfa: &LookaheadDFA, title: &str) -> String {
let start_state = format!("0 [label = \"{}\"];", dfa.states[0]);
let states = dfa
.states
.iter()
.enumerate()
.skip(1)
.fold(StrVec::new(4), |mut acc, (i, s)| {
acc.push(format!("{i} [label = \"{s}\"];"));
acc
});
let transitions =
dfa.transitions
.iter()
.fold(StrVec::new(4), |mut acc, (from_state, trans)| {
for (term, to_state) in trans {
let terminal_string = format!("{term}");
acc.push(
format!(
"{} -> {} [label = \"{}\"];",
from_state,
to_state,
terminal_string.escape_default()
)
.to_string(),
);
}
acc
});
format!(
r#"digraph G {{
rankdir=LR;
label="{title}";
node [shape=point, style=invis]; ""
node [shape=ellipse, color=cyan, style=solid];
"" -> {start_state}
node [shape=ellipse, color=cyan];
{states}
{transitions}
}}"#
)
}
#[cfg(test)]
mod tests {
use crate::analysis::lookahead_dfa::DFAState;
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_render_dfa_dot_string() {
let dfa = LookaheadDFA {
states: vec![
DFAState {
id: 0,
prod_num: -1,
},
DFAState {
id: 1,
prod_num: 64,
},
DFAState {
id: 2,
prod_num: 65,
},
],
transitions: [
(0, [(16, 2), (36, 1)].into_iter().collect()),
(1, [(56, 3)].into_iter().collect()),
]
.into_iter()
.collect(),
k: 1,
};
assert_eq!(
render_dfa_dot_string(&dfa, "Test"),
r#"digraph G {
rankdir=LR;
label="Test";
node [shape=point, style=invis]; ""
node [shape=ellipse, color=cyan, style=solid];
"" -> 0 [label = "Id(0)"];
node [shape=ellipse, color=cyan];
1 [label = "Id(1, accepting), Pr(64)"];
2 [label = "Id(2, accepting), Pr(65)"];
0 -> 2 [label = "16"];
0 -> 1 [label = "36"];
1 -> 3 [label = "56"];
}"#
);
}
}