tawasuyu

tawasuyu/brahman

Rust 492TOML 194Markdown 53JSON 176939 Sutichaykuna

⎇ 53dbdf0f1deea10d6fc567ea2b43e1e75d6d60cd crates/modules/semantic_dht/minga-core/src/ast.rs Rust · 52 siq'ikuna · 1.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

chore: monorepo inicial con arje + minga + yahweh absorbidos 53dbdf0f1 · Sergio ·

1use tree_sitter::Node;
2
3/// Nodo de AST normalizado: descarta posiciones, whitespace y trivia
4/// (comentarios marcados como `extra` en la gramática). Dos fragmentos de
5/// código semánticamente equivalentes producen árboles idénticos.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct SemanticNode {
8    pub kind: String,
9    pub field_name: Option<String>,
10    pub leaf_text: Option<Vec<u8>>,
11    pub children: Vec<SemanticNode>,
12}
13
14impl SemanticNode {
15    pub fn from_tree_sitter(node: Node<'_>, source: &[u8]) -> Self {
16        Self::build(node, source, None)
17    }
18
19    fn build(node: Node<'_>, source: &[u8], field_name: Option<String>) -> Self {
20        let kind = node.kind().to_string();
21        let mut children = Vec::new();
22
23        // Incluimos todos los hijos no-`extra`: nombrados (rules de la
24        // gramática) y anónimos (tokens literales como operadores y
25        // separadores). Lo único que descartamos son `extras` —
26        // comentarios y whitespace en gramáticas tree-sitter — que es
27        // exactamente la invariancia que queremos: dos formas con el
28        // mismo contenido y estructura producen el mismo árbol.
29        let mut cursor = node.walk();
30        if cursor.goto_first_child() {
31            loop {
32                let child = cursor.node();
33                if !child.is_extra() {
34                    let field = cursor.field_name().map(|s| s.to_string());
35                    children.push(Self::build(child, source, field));
36                }
37                if !cursor.goto_next_sibling() {
38                    break;
39                }
40            }
41        }
42
43        let leaf_text = if children.is_empty() {
44            let range = node.byte_range();
45            Some(source[range].to_vec())
46        } else {
47            None
48        };
49
50        SemanticNode { kind, field_name, leaf_text, children }
51    }
52}