brokk_bifrost_cpp/graph/
syntax.rs1use tree_sitter::Node;
2
3#[derive(Clone)]
4pub struct ExplicitQualifiedCallableValue<'tree> {
5 pub qualified: Node<'tree>,
6 pub global: bool,
7 pub owner_components: Vec<Node<'tree>>,
8 pub member: Node<'tree>,
9}
10
11pub fn explicit_qualified_callable_value(
18 node: Node<'_>,
19) -> Option<ExplicitQualifiedCallableValue<'_>> {
20 if node.kind() != "pointer_expression" || node.child_by_field_name("operator")?.kind() != "&" {
21 return None;
22 }
23 let qualified = node.child_by_field_name("argument")?;
24 if qualified.kind() != "qualified_identifier" {
25 return None;
26 }
27 let mut components = Vec::new();
28 let global = qualified.child_by_field_name("scope").is_none()
29 && qualified.child(0).is_some_and(|child| child.kind() == "::");
30 append_qualified_components(qualified, &mut components)?;
31 let member = components.pop()?;
32 if components.is_empty() {
33 return None;
34 }
35 Some(ExplicitQualifiedCallableValue {
36 qualified,
37 global,
38 owner_components: components,
39 member,
40 })
41}
42
43fn append_qualified_components<'tree>(node: Node<'tree>, out: &mut Vec<Node<'tree>>) -> Option<()> {
44 let mut stack = vec![node];
45 while let Some(current) = stack.pop() {
46 match current.kind() {
47 "identifier" | "namespace_identifier" | "type_identifier" => out.push(current),
48 "qualified_identifier" | "scoped_identifier" => {
49 stack.push(current.child_by_field_name("name")?);
50 if let Some(scope) = current.child_by_field_name("scope") {
51 stack.push(scope);
52 } else if current.child(0).is_none_or(|child| child.kind() != "::") {
53 return None;
54 }
55 }
56 "template_type" | "template_function" => {
57 stack.push(current.child_by_field_name("name")?);
58 }
59 "nested_namespace_specifier" => {
60 for index in (0..current.named_child_count()).rev() {
61 stack.push(current.named_child(index)?);
62 }
63 }
64 _ => return None,
65 }
66 }
67 Some(())
68}