Skip to main content

code_moniker_core/lang/
strategy.rs

1use 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}