icb_parser/lang/
common.rs1use crate::facts::RawNode;
9use icb_common::{Language, NodeKind};
10use tree_sitter::Node;
11
12pub fn push_node(
17 facts: &mut Vec<RawNode>,
18 language: Language,
19 kind: NodeKind,
20 name: Option<String>,
21 node: &Node,
22 parent_idx: Option<usize>,
23) -> usize {
24 let start = node.start_position();
25 let end = node.end_position();
26 let start_line = start.row + 1;
27 let end_line = std::cmp::max(end.row + 1, start_line);
28
29 let idx = facts.len();
30 facts.push(RawNode {
31 language,
32 kind,
33 name,
34 usr: None,
35 start_line,
36 start_col: start.column,
37 end_line,
38 end_col: end.column,
39 children: Vec::new(),
40 source_file: None,
41 });
42
43 if let Some(pidx) = parent_idx {
44 facts[pidx].children.push(idx);
45 }
46 idx
47}
48
49pub fn child_of_kind<'a>(node: Node<'a>, kind: &str) -> Option<Node<'a>> {
54 let mut cursor = node.walk();
55 let mut children = node.children(&mut cursor);
56 children.find(|c| c.kind() == kind)
57}
58
59pub fn traverse_node<F>(
68 node: Node,
69 source: &str,
70 facts: &mut Vec<RawNode>,
71 parent_idx: Option<usize>,
72 language: Language,
73 classifier: &F,
74) -> Option<usize>
75where
76 F: Fn(&Node, &str) -> Option<(NodeKind, Option<String>, bool)>,
77{
78 if let Some((kind, name, is_container)) = classifier(&node, source) {
79 let idx = push_node(facts, language, kind, name, &node, parent_idx);
80 if is_container {
81 let new_parent = Some(idx);
82 let mut current_parent = new_parent;
83 let mut cursor = node.walk();
84 for child in node.children(&mut cursor) {
85 current_parent =
86 traverse_node(child, source, facts, current_parent, language, classifier);
87 }
88 new_parent
89 } else {
90 parent_idx
91 }
92 } else {
93 let mut current_parent = parent_idx;
94 let mut cursor = node.walk();
95 for child in node.children(&mut cursor) {
96 current_parent =
97 traverse_node(child, source, facts, current_parent, language, classifier);
98 }
99 current_parent
100 }
101}