1use crate::facts::RawNode;
7use icb_common::{IcbError, Language, NodeKind};
8use tree_sitter::Parser;
9
10use super::common::{child_of_kind, traverse_node};
11
12pub fn parse_go(source: &str) -> Result<Vec<RawNode>, IcbError> {
14 let mut parser = Parser::new();
15 parser
16 .set_language(&tree_sitter_go::language())
17 .map_err(|e| IcbError::Parse(format!("cannot set tree-sitter-go language: {e}")))?;
18
19 let tree = parser
20 .parse(source, None)
21 .ok_or_else(|| IcbError::Parse("tree-sitter parse returned None for Go source".into()))?;
22
23 let mut facts = Vec::new();
24
25 let classifier =
26 |node: &tree_sitter::Node, source: &str| -> Option<(NodeKind, Option<String>, bool)> {
27 match node.kind() {
28 "function_declaration" => {
29 let name = child_of_kind(*node, "identifier")
30 .and_then(|n| n.utf8_text(source.as_bytes()).ok())
31 .map(|s| s.to_string());
32 Some((NodeKind::Function, name, true))
33 }
34 "method_declaration" => {
35 let name = child_of_kind(*node, "field_identifier")
36 .and_then(|n| n.utf8_text(source.as_bytes()).ok())
37 .map(|s| s.to_string());
38 Some((NodeKind::Function, name, true))
39 }
40 "type_declaration" => {
41 if let Some(type_spec) = child_of_kind(*node, "type_spec").or_else(|| {
43 child_of_kind(*node, "type_spec_list")
44 .and_then(|list| child_of_kind(list, "type_spec"))
45 }) {
46 if child_of_kind(type_spec, "struct_type").is_some()
47 || child_of_kind(type_spec, "interface_type").is_some()
48 {
49 let name = child_of_kind(type_spec, "type_identifier")
50 .or_else(|| child_of_kind(type_spec, "identifier"))
51 .and_then(|n| n.utf8_text(source.as_bytes()).ok())
52 .map(|s| s.to_string());
53 return Some((NodeKind::Class, name, true));
54 }
55 }
56 None
57 }
58 "call_expression" => {
59 let name_node = child_of_kind(*node, "identifier")
60 .or_else(|| child_of_kind(*node, "selector_expression"));
61 let name = name_node
62 .and_then(|n| n.utf8_text(source.as_bytes()).ok())
63 .map(|s| s.to_string());
64 Some((NodeKind::CallSite, name, false))
65 }
66 _ => None,
67 }
68 };
69
70 traverse_node(
71 tree.root_node(),
72 source,
73 &mut facts,
74 None,
75 Language::Go,
76 &classifier,
77 );
78 Ok(facts)
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use icb_common::NodeKind;
85
86 #[test]
87 fn test_simple_function() {
88 let code = "package main\nfunc foo() {}\n";
89 let facts = parse_go(code).unwrap();
90 let funcs: Vec<_> = facts
91 .iter()
92 .filter(|n| n.kind == NodeKind::Function)
93 .collect();
94 assert_eq!(funcs.len(), 1);
95 assert_eq!(funcs[0].name.as_deref(), Some("foo"));
96 }
97
98 #[test]
99 fn test_method() {
100 let code = "package main\ntype S struct{}\nfunc (s S) bar() {}\n";
101 let facts = parse_go(code).unwrap();
102 let methods: Vec<_> = facts
103 .iter()
104 .filter(|n| n.kind == NodeKind::Function && n.name.as_deref() == Some("bar"))
105 .collect();
106 assert!(!methods.is_empty(), "expected method 'bar'");
107 }
108
109 #[test]
110 fn test_call_expression() {
111 let code = "package main\nfunc baz() { foo() }\n";
112 let facts = parse_go(code).unwrap();
113 let calls: Vec<_> = facts
114 .iter()
115 .filter(|n| n.kind == NodeKind::CallSite)
116 .collect();
117 assert_eq!(calls.len(), 1);
118 assert_eq!(calls[0].name.as_deref(), Some("foo"));
119 }
120
121 #[test]
122 fn test_struct_type() {
123 let code = "package main\ntype MyStruct struct {}\n";
124 let facts = parse_go(code).unwrap();
125 let classes: Vec<_> = facts
126 .iter()
127 .filter(|n| n.kind == NodeKind::Class && n.name.as_deref() == Some("MyStruct"))
128 .collect();
129 assert!(!classes.is_empty(), "expected class 'MyStruct'");
130 }
131}