fluidattacks-blends-domain 0.40.0

Blends functional core: pure AST graph to syntax graph (no_std)
Documentation
use crate::ast::{AstGraph, AstNode};
use crate::NodeId;
use alloc::borrow::ToOwned;
use tree_sitter::{Node, Parser};

// Mirrors the shell's AST graph builder
// The constuctor via `Content` needs std and therefore cannot be used here
fn add_node(source: &str, graph: &mut AstGraph, node: Node<'_>, counter: &mut u64) -> NodeId {
    *counter = counter.saturating_add(1);
    let id = NodeId(*counter);
    let start = node.start_position();
    let mut ast_node = AstNode::new(
        u32::try_from(start.row.saturating_add(1)).unwrap(),
        u32::try_from(start.column.saturating_add(1)).unwrap(),
        node.kind().to_owned(),
    );
    if node.child_count() == 0 {
        ast_node.text = Some(source[node.byte_range()].to_owned());
    }
    graph.add_node(id, ast_node);

    let mut cursor = node.walk();
    for (index, child) in node.children(&mut cursor).enumerate() {
        let child_id = add_node(source, graph, child, counter);
        graph.add_edge(id, child_id, u32::try_from(index).unwrap());
    }
    id
}

pub fn rust_ast_graph(source: &str) -> AstGraph {
    let mut parser = Parser::new();
    parser
        .set_language(&tree_sitter_rust::LANGUAGE.into())
        .unwrap();
    let tree = parser.parse(source, None).unwrap();
    assert!(!tree.root_node().has_error(), "fixture must parse cleanly");

    let mut graph = AstGraph::new();
    add_node(source, &mut graph, tree.root_node(), &mut 0);
    graph
}

/// Returns the first node of `kind` in `graph`
/// Panics when the fixture holds no node of that kind
pub fn find_node<'a>(graph: &'a AstGraph, kind: &str) -> &'a AstNode {
    graph
        .nodes
        .values()
        .find(|node| node.kind == kind)
        .unwrap_or_else(|| panic!("[ERROR] {kind} not found on source"))
}