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