code_moniker_core/lang/
strategy.rs1use tree_sitter::Node;
2
3use crate::core::code_graph::{CodeGraph, Position};
4use crate::core::moniker::Moniker;
5
6pub enum NodeShape<'src> {
7 Symbol(Symbol<'src>),
8 Annotation { kind: &'static [u8] },
9 Skip,
10 Recurse,
11}
12
13pub struct Symbol<'src> {
14 pub moniker: Moniker,
15 pub kind: &'static [u8],
16 pub visibility: &'static [u8],
17 pub signature: Option<Vec<u8>>,
18 pub body: Option<Node<'src>>,
19 pub position: Position,
20 pub annotated_by: Vec<RefSpec>,
21}
22
23pub struct RefSpec {
24 pub kind: &'static [u8],
25 pub target: Moniker,
26 pub confidence: &'static [u8],
27 pub position: Position,
28 pub receiver_hint: &'static [u8],
29 pub alias: &'static [u8],
30}
31
32pub trait LangStrategy {
33 fn classify<'src>(
34 &self,
35 node: Node<'src>,
36 scope: &Moniker,
37 source: &'src [u8],
38 graph: &mut CodeGraph,
39 ) -> NodeShape<'src>;
40
41 #[allow(unused_variables)]
42 fn before_body(
43 &self,
44 node: Node<'_>,
45 kind: &[u8],
46 moniker: &Moniker,
47 source: &[u8],
48 graph: &mut CodeGraph,
49 ) {
50 }
51
52 #[allow(unused_variables)]
53 fn after_body(&self, kind: &[u8], moniker: &Moniker) {}
54
55 #[allow(unused_variables)]
56 fn on_symbol_emitted(
57 &self,
58 node: Node<'_>,
59 sym_kind: &[u8],
60 sym_moniker: &Moniker,
61 source: &[u8],
62 graph: &mut CodeGraph,
63 ) {
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::core::moniker::MonikerBuilder;
71
72 struct FakeStrategy;
73
74 impl LangStrategy for FakeStrategy {
75 fn classify<'src>(
76 &self,
77 node: Node<'src>,
78 _scope: &Moniker,
79 _source: &'src [u8],
80 _graph: &mut CodeGraph,
81 ) -> NodeShape<'src> {
82 match node.kind() {
83 "line_comment" => NodeShape::Annotation { kind: b"comment" },
84 _ => NodeShape::Recurse,
85 }
86 }
87 }
88
89 fn anchor() -> Moniker {
90 MonikerBuilder::new().project(b"app").build()
91 }
92
93 #[test]
94 fn fake_strategy_classifies_line_comment_as_annotation() {
95 let s = FakeStrategy;
96 let mut p = tree_sitter::Parser::new();
97 p.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap();
98 let src = b"// hi\nfn main() {}";
99 let tree = p.parse(src, None).unwrap();
100 let mut cursor = tree.root_node().walk();
101 let scope = anchor();
102 let mut g = CodeGraph::new(scope.clone(), b"module");
103 let mut saw_comment = false;
104 for child in tree.root_node().children(&mut cursor) {
105 if let NodeShape::Annotation { kind } = s.classify(child, &scope, src, &mut g) {
106 assert_eq!(kind, b"comment");
107 saw_comment = true;
108 }
109 }
110 assert!(saw_comment);
111 }
112
113 #[test]
114 fn fake_strategy_recurses_on_unknown_kinds() {
115 let s = FakeStrategy;
116 let mut p = tree_sitter::Parser::new();
117 p.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap();
118 let src = b"fn main() {}";
119 let tree = p.parse(src, None).unwrap();
120 let mut cursor = tree.root_node().walk();
121 let scope = anchor();
122 let mut g = CodeGraph::new(scope.clone(), b"module");
123 for child in tree.root_node().children(&mut cursor) {
124 assert!(matches!(
125 s.classify(child, &scope, src, &mut g),
126 NodeShape::Recurse
127 ));
128 }
129 }
130}