fluidattacks-blends-domain 0.3.0

Blends functional core: pure AST graph to syntax graph (no_std)
Documentation
//! Cfg builder that connects a switch section to its steps, falling empty
//! sections through to the next non-empty sibling.

use alloc::vec::Vec;

use crate::query::{adj_ast, pred_ast};
use crate::syntax::cfg::{SyntaxCfgArgs, SyntaxCfgError};
use crate::syntax::SyntaxGraph;
use crate::NodeId;

fn fallthrough_childs(graph: &SyntaxGraph, n_id: NodeId) -> Result<Vec<NodeId>, SyntaxCfgError> {
    let parent_id = pred_ast(graph, n_id, None)
        .first()
        .copied()
        .ok_or(SyntaxCfgError::UnexpectedSyntaxShape { n_id })?;
    let siblings = adj_ast(graph, parent_id, None, &[]);
    let next_sibling = siblings
        .iter()
        .copied()
        .find(|sibling| !adj_ast(graph, *sibling, None, &[]).is_empty() && *sibling > n_id)
        .or_else(|| siblings.last().copied())
        .ok_or(SyntaxCfgError::UnexpectedSyntaxShape { n_id })?;
    Ok(adj_ast(graph, next_sibling, None, &[]))
}

pub fn build(
    args: &mut SyntaxCfgArgs<'_>,
    n_id: NodeId,
    nxt_id: Option<NodeId>,
) -> Result<NodeId, SyntaxCfgError> {
    let mut childs = adj_ast(args.graph, n_id, None, &[]);
    if childs.is_empty() {
        childs = fallthrough_childs(args.graph, n_id)?;
    }
    for c_id in childs {
        let built = args.generic(c_id, nxt_id)?;
        args.graph.add_cfg_edge(n_id, built);
    }
    Ok(n_id)
}