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