use syn::ExprIf;
use crate::cfg_builder::builder::CfgBuilder;
use crate::cfg_builder::node::{CfgNode, ConditionalExpr};
use proc_macro2::Span;
use quote::quote;
use syn::{token, visit::Visit, Expr, ExprParen, ExprUnary, Pat, UnOp};
impl CfgBuilder {
pub fn handle_if_statement(&mut self, expr_if: &ExprIf) {
let cond_str = self.format_condition(&expr_if.cond);
let cond_label = if self.next_edge_label == Some("false".to_string()) {
format!("else if: {}", cond_str)
} else {
format!("if: {}", cond_str)
};
let cond_expr = ConditionalExpr::If(expr_if.cond.clone());
let cond_node = self.add_node(CfgNode::new_condition(cond_label, cond_expr));
self.next_edge_label = Some("true".to_string());
self.current_node = Some(cond_node.clone());
self.visit_block(&expr_if.then_branch);
let true_branch_end = self.current_node;
let merge_node = self.add_node_without_edge(CfgNode::MergePoint);
if let Some(true_end) = true_branch_end {
self.add_edge_with_label(true_end, merge_node, "".to_string());
}
if let Some((_, else_branch)) = &expr_if.else_branch {
self.current_node = Some(cond_node.clone());
self.next_edge_label = Some("false".to_string());
match &**else_branch {
Expr::If(elseif) => {
self.handle_if_statement(elseif);
}
Expr::Block(block) => {
self.visit_block(&block.block);
}
_ => {
self.visit_expr(else_branch);
}
}
if let Some(false_end) = self.current_node {
self.add_edge_with_label(false_end, merge_node, "".to_string());
}
} else {
self.add_edge_with_label(cond_node, merge_node, "false".to_string());
}
self.current_node = Some(merge_node);
}
pub fn format_pattern_condition(&self, pat: &Pat) -> String {
let raw_string = quote!(#pat).to_string();
Self::clean_up_formatting(&raw_string)
}
pub fn negate_condition(expr: Expr) -> Expr {
let paren_expr = ExprParen {
attrs: Vec::new(),
paren_token: token::Paren(Span::call_site()),
expr: Box::new(expr),
};
let not_expr = ExprUnary {
attrs: Vec::new(),
op: UnOp::Not(token::Bang {
spans: [Span::call_site()],
}),
expr: Box::new(Expr::Paren(paren_expr)),
};
Expr::Unary(not_expr)
}
}