fluidattacks-blends-domain 0.40.0

Blends functional core: pure AST graph to syntax graph (no_std)
Documentation
use alloc::vec;
use alloc::vec::Vec;

use crate::query::{match_ast_group, match_ast_group_d};
use crate::syntax::builders::expression_statement::{
    build_variable_declaration_group_node, VarNameEntry,
};
use crate::syntax::builders::variable_declaration::build_variable_declaration_node;
use crate::syntax::fields::go::var_spec;
use crate::syntax::readers::go::common::pair_declaration_value_ids;
use crate::syntax::{SyntaxGraphArgs, SyntaxGraphError};
use crate::utilities::text_nodes::node_to_str;
use crate::NodeId;

fn collect_specs(args: &SyntaxGraphArgs<'_>, n_id: NodeId) -> Vec<NodeId> {
    let mut groups = match_ast_group(args.ast_graph, n_id, &["var_spec", "const_spec"], Some(2));
    let mut spec_ids = groups.remove("var_spec").unwrap_or_default();
    spec_ids.append(&mut groups.remove("const_spec").unwrap_or_default());
    spec_ids
}

fn spec_entries(
    args: &SyntaxGraphArgs<'_>,
    spec_id: NodeId,
) -> Result<Vec<VarNameEntry>, SyntaxGraphError> {
    let graph = args.ast_graph;

    let mut name_ids = match_ast_group_d(graph, spec_id, "identifier", Some(1));
    if name_ids.is_empty() {
        name_ids = vec![args.required_field_alt(spec_id, var_spec::NAME)?];
    }

    let type_name = args
        .optional_field_alt(spec_id, var_spec::TYPE)
        .map(|id| node_to_str(graph, id));

    let value_field_id = args.optional_field_alt(spec_id, var_spec::VALUE);
    let value_ids = pair_declaration_value_ids(graph, value_field_id, name_ids.len());

    Ok(name_ids
        .into_iter()
        .zip(value_ids)
        .map(|(name_id, value_id)| VarNameEntry {
            name: node_to_str(graph, name_id),
            name_id,
            type_name: type_name.clone(),
            value_id,
        })
        .collect())
}

pub fn reader(
    args: &mut SyntaxGraphArgs<'_>,
    n_id: NodeId,
) -> Result<Option<NodeId>, SyntaxGraphError> {
    let spec_ids = collect_specs(args, n_id);

    if spec_ids.is_empty() {
        let var_name = node_to_str(args.ast_graph, n_id);
        return build_variable_declaration_node(args, n_id, var_name, None, None, None, None)
            .map(Some);
    }

    let mut entries: Vec<VarNameEntry> = Vec::new();
    for spec_id in spec_ids {
        entries.extend(spec_entries(args, spec_id)?);
    }

    build_variable_declaration_group_node(args, n_id, &entries).map(Some)
}