fluidattacks-blends-domain 0.6.0

Blends functional core: pure AST graph to syntax graph (no_std)
Documentation
//! Cfg builder that branches a conditional into its true and false paths,
//! committing to a single path when a multifile condition folds
//! deterministically.

use crate::syntax::cfg::dispatchers::multifile::{get_condition_deterministic_result, CondBranch};
use crate::syntax::cfg::{SyntaxCfgArgs, SyntaxCfgError};
use crate::syntax::{SyntaxGraph, SyntaxNode};
use crate::NodeId;

const fn true_false_ids(node: &SyntaxNode) -> (Option<NodeId>, Option<NodeId>) {
    match node {
        SyntaxNode::If {
            true_id, false_id, ..
        } => (*true_id, *false_id),
        SyntaxNode::TernaryOperation {
            true_id, false_id, ..
        } => (Some(*true_id), Some(*false_id)),
        _ => (None, None),
    }
}

const fn condition_id(node: &SyntaxNode) -> Option<NodeId> {
    match node {
        SyntaxNode::If { condition_id, .. } | SyntaxNode::TernaryOperation { condition_id, .. } => {
            Some(*condition_id)
        }
        _ => None,
    }
}

fn deterministic_branch_id(graph: &mut SyntaxGraph, n_id: NodeId) -> Option<NodeId> {
    let node = graph.nodes.get(&n_id)?;
    let cond_id = condition_id(node)?;
    let (true_id, false_id) = true_false_ids(node);
    match get_condition_deterministic_result(graph, cond_id)? {
        CondBranch::TrueId => true_id,
        CondBranch::FalseId => false_id,
    }
}

pub fn build(
    args: &mut SyntaxCfgArgs<'_>,
    n_id: NodeId,
    nxt_id: Option<NodeId>,
) -> Result<NodeId, SyntaxCfgError> {
    if args.is_multifile {
        if let Some(f_id) = deterministic_branch_id(args.graph, n_id) {
            let built = args.generic(f_id, nxt_id)?;
            args.graph.add_cfg_edge(n_id, built);
            return Ok(n_id);
        }
    }

    let (true_id, false_id) = args
        .graph
        .nodes
        .get(&n_id)
        .map_or((None, None), true_false_ids);

    if let Some(true_id) = true_id {
        let built = args.generic(true_id, nxt_id)?;
        args.graph.add_cfg_edge(n_id, built);
    }

    if let Some(false_id) = false_id {
        let built = args.generic(false_id, nxt_id)?;
        args.graph.add_cfg_edge(n_id, built);
    }

    if let Some(nxt_id) = nxt_id {
        args.graph.add_cfg_edge(n_id, nxt_id);
    }

    Ok(n_id)
}