use rusty_regex::ast::Ast;
use crate::graph::{VisualGraph, VisualNode, VisualEdge, NodeType, ShapeHint, EdgeStyle};
pub fn ast_to_graph(ast: &Ast) -> VisualGraph {
let mut graph = VisualGraph::new();
let mut next_id = 0;
fn walk(node: &Ast, graph: &mut VisualGraph, next_id: &mut usize, parent: Option<usize>) -> usize {
let id = *next_id;
*next_id += 1;
let label = match node {
Ast::Literal(c) => format!("'{}'", c),
Ast::Dot => ".".to_string(),
Ast::CharacterClass { .. } => "[class]".to_string(),
Ast::PredefinedClass(p) => format!("{:?}", p),
Ast::Quantifier { .. } => "Quant".to_string(),
Ast::Group { capturing, .. } => {
if *capturing { "Group".to_string() } else { "NonCap".to_string() }
},
Ast::Alternation(_, _) => "Alt".to_string(),
Ast::Sequence(_) => "Seq".to_string(),
Ast::Scoped { case_i, .. } => format!("(?i:{})", case_i),
Ast::AnchorStart => "^".to_string(),
Ast::AnchorEnd => "$".to_string(),
Ast::WordBoundary => "\\b".to_string(),
Ast::LookAhead { positive, .. } => if *positive { "Look+".to_string() } else { "Look-".to_string() },
};
graph.nodes.push(VisualNode {
id,
label: label.clone(),
shape: ShapeHint::Box,
is_accept: false,
node_type: NodeType::Ast,
});
if let Some(p) = parent {
graph.edges.push(VisualEdge {
from: p,
to: id,
label,
style: EdgeStyle::Solid,
bend_offset: 0.0,
});
}
match node {
Ast::Quantifier { node, .. } => {
walk(node, graph, next_id, Some(id));
}
Ast::Group { ast: inner, .. } => {
walk(inner, graph, next_id, Some(id));
}
Ast::Alternation(a, b) => {
walk(a, graph, next_id, Some(id));
walk(b, graph, next_id, Some(id));
}
Ast::Sequence(seq) => {
for child in seq {
walk(child, graph, next_id, Some(id));
}
}
Ast::Scoped { inner, .. } => {
walk(inner, graph, next_id, Some(id));
}
Ast::LookAhead { ast: inner, .. } => {
walk(inner, graph, next_id, Some(id));
}
_ => {}
}
id
}
walk(ast, &mut graph, &mut next_id, None);
graph
}