brokk_bifrost_cpp/graph/
syntax.rs1use tree_sitter::Node;
2
3#[derive(Clone)]
4pub struct QualifiedCallableValue<'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(node: Node<'_>) -> Option<QualifiedCallableValue<'_>> {
18 if node.kind() != "pointer_expression" || node.child_by_field_name("operator")?.kind() != "&" {
19 return None;
20 }
21 let qualified = node.child_by_field_name("argument")?;
22 qualified_callable_value_from_node(qualified)
23}
24
25pub fn qualified_callable_value(node: Node<'_>) -> Option<QualifiedCallableValue<'_>> {
31 if let Some(value) = explicit_qualified_callable_value(node) {
32 return Some(value);
33 }
34 if node.kind() != "qualified_identifier" {
35 return None;
36 }
37 if node.parent().is_some_and(|parent| {
38 parent.child_by_field_name("type") == Some(node)
39 || (parent.kind() == "call_expression"
40 && parent.child_by_field_name("function") == Some(node))
41 || (parent.kind() == "pointer_expression"
42 && parent.child_by_field_name("argument") == Some(node))
43 || matches!(
44 parent.kind(),
45 "qualified_identifier" | "scoped_identifier" | "scoped_type_identifier"
46 )
47 }) {
48 return None;
49 }
50 qualified_callable_value_from_node(node)
51}
52
53fn qualified_callable_value_from_node(qualified: Node<'_>) -> Option<QualifiedCallableValue<'_>> {
54 if qualified.kind() != "qualified_identifier" {
55 return None;
56 }
57 let mut components = Vec::new();
58 let global = qualified.child_by_field_name("scope").is_none()
59 && qualified.child(0).is_some_and(|child| child.kind() == "::");
60 append_qualified_components(qualified, &mut components)?;
61 let member = components.pop()?;
62 if components.is_empty() {
63 return None;
64 }
65 Some(QualifiedCallableValue {
66 qualified,
67 global,
68 owner_components: components,
69 member,
70 })
71}
72
73fn append_qualified_components<'tree>(node: Node<'tree>, out: &mut Vec<Node<'tree>>) -> Option<()> {
74 let mut stack = vec![node];
75 while let Some(current) = stack.pop() {
76 match current.kind() {
77 "identifier" | "namespace_identifier" | "type_identifier" | "operator_name" => {
78 out.push(current)
79 }
80 "qualified_identifier" | "scoped_identifier" => {
81 stack.push(current.child_by_field_name("name")?);
82 if let Some(scope) = current.child_by_field_name("scope") {
83 stack.push(scope);
84 } else if current.child(0).is_none_or(|child| child.kind() != "::") {
85 return None;
86 }
87 }
88 "template_type" | "template_function" => {
89 stack.push(current.child_by_field_name("name")?);
90 }
91 "nested_namespace_specifier" => {
92 for index in (0..current.named_child_count()).rev() {
93 stack.push(current.named_child(index)?);
94 }
95 }
96 _ => return None,
97 }
98 }
99 Some(())
100}