Skip to content

Commit b7c68e8

Browse files
authored
Merge pull request #7 from rtk-ai/feat/add-languages
feat: add C#, Go, Java, C, C++, Ruby language support
2 parents 8491e41 + 08fef9b commit b7c68e8

3 files changed

Lines changed: 311 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ tree-sitter-typescript = "0.23"
2020
tree-sitter-rust = "0.23"
2121
tree-sitter-python = "0.23"
2222
tree-sitter-javascript = "0.23"
23+
tree-sitter-c-sharp = "0.23"
24+
tree-sitter-go = "0.23"
25+
tree-sitter-java = "0.23"
26+
tree-sitter-c = "0.23"
27+
tree-sitter-cpp = "0.23"
28+
tree-sitter-ruby = "0.23"
2329

2430
# Serialization
2531
serde = { version = "1", features = ["derive"] }

src/parser/mod.rs

Lines changed: 239 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,17 @@ impl SymbolIndex {
154154
"function_declaration" | "function_definition" | "function_item" => "function",
155155
"method_definition" | "method_declaration" => "method",
156156
"class_declaration" | "class_definition" => "class",
157-
"struct_item" => "struct",
157+
"struct_item" | "struct_declaration" => "struct",
158158
"impl_item" => "impl",
159159
"enum_item" | "enum_declaration" => "enum",
160160
"interface_declaration" => "interface",
161161
"trait_item" => "trait",
162-
"type_alias_declaration" | "type_item" => "type",
162+
"type_alias_declaration" | "type_item" | "type_declaration" => "type",
163163
"arrow_function" => "arrow_fn",
164164
"export_statement" => "export",
165+
"namespace_declaration" => "namespace",
166+
"module_declaration" => "module",
167+
"singleton_method" => "method",
165168
other => other,
166169
}
167170
}
@@ -219,6 +222,74 @@ impl SymbolIndex {
219222
("class_definition", NameExtractor::Field("name")),
220223
],
221224
},
225+
// C#
226+
LangConfig {
227+
language: tree_sitter_c_sharp::LANGUAGE.into(),
228+
extensions: &["cs"],
229+
symbol_queries: vec![
230+
("method_declaration", NameExtractor::Field("name")),
231+
("class_declaration", NameExtractor::Field("name")),
232+
("interface_declaration", NameExtractor::Field("name")),
233+
("struct_declaration", NameExtractor::Field("name")),
234+
("enum_declaration", NameExtractor::Field("name")),
235+
("namespace_declaration", NameExtractor::Field("name")),
236+
],
237+
},
238+
// Go
239+
LangConfig {
240+
language: tree_sitter_go::LANGUAGE.into(),
241+
extensions: &["go"],
242+
symbol_queries: vec![
243+
("function_declaration", NameExtractor::Field("name")),
244+
("method_declaration", NameExtractor::Field("name")),
245+
("type_declaration", NameExtractor::Field("name")),
246+
],
247+
},
248+
// Java
249+
LangConfig {
250+
language: tree_sitter_java::LANGUAGE.into(),
251+
extensions: &["java"],
252+
symbol_queries: vec![
253+
("method_declaration", NameExtractor::Field("name")),
254+
("class_declaration", NameExtractor::Field("name")),
255+
("interface_declaration", NameExtractor::Field("name")),
256+
("enum_declaration", NameExtractor::Field("name")),
257+
],
258+
},
259+
// C
260+
LangConfig {
261+
language: tree_sitter_c::LANGUAGE.into(),
262+
extensions: &["c", "h"],
263+
symbol_queries: vec![
264+
("function_definition", NameExtractor::Field("declarator")),
265+
("struct_specifier", NameExtractor::Field("name")),
266+
("enum_specifier", NameExtractor::Field("name")),
267+
("type_definition", NameExtractor::Field("declarator")),
268+
],
269+
},
270+
// C++
271+
LangConfig {
272+
language: tree_sitter_cpp::LANGUAGE.into(),
273+
extensions: &["cpp", "cc", "cxx", "hpp"],
274+
symbol_queries: vec![
275+
("function_definition", NameExtractor::Field("declarator")),
276+
("class_specifier", NameExtractor::Field("name")),
277+
("struct_specifier", NameExtractor::Field("name")),
278+
("enum_specifier", NameExtractor::Field("name")),
279+
("namespace_definition", NameExtractor::Field("name")),
280+
],
281+
},
282+
// Ruby
283+
LangConfig {
284+
language: tree_sitter_ruby::LANGUAGE.into(),
285+
extensions: &["rb"],
286+
symbol_queries: vec![
287+
("method", NameExtractor::Field("name")),
288+
("singleton_method", NameExtractor::Field("name")),
289+
("class", NameExtractor::Field("name")),
290+
("module", NameExtractor::Field("name")),
291+
],
292+
},
222293
]
223294
}
224295
}
@@ -581,4 +652,170 @@ interface TsInterface { x: number; }
581652
assert_eq!(find_sym(&symbols, "py_func").kind, "function");
582653
assert_eq!(find_sym(&symbols, "PyClass").kind, "class");
583654
}
655+
656+
// ── 14. C# ─────────────────────────────────────────────────────────
657+
658+
#[test]
659+
fn test_parse_csharp() {
660+
let dir = TempDir::new().unwrap();
661+
write_file(&dir, "src/App.cs", r#"
662+
namespace MyApp {
663+
class UserService {
664+
public void CreateUser(string name) {}
665+
public void DeleteUser(int id) {}
666+
}
667+
668+
interface IRepository {
669+
void Save();
670+
}
671+
672+
enum Status {
673+
Active,
674+
Inactive
675+
}
676+
}
677+
"#);
678+
let idx = SymbolIndex::new(dir.path().to_str().unwrap()).unwrap();
679+
let symbols = idx.scan_all().unwrap();
680+
681+
find_sym(&symbols, "UserService");
682+
find_sym(&symbols, "CreateUser");
683+
find_sym(&symbols, "DeleteUser");
684+
find_sym(&symbols, "IRepository");
685+
find_sym(&symbols, "Status");
686+
}
687+
688+
// ── 15. Go ──────────────────────────────────────────────────────────
689+
690+
#[test]
691+
fn test_parse_go() {
692+
let dir = TempDir::new().unwrap();
693+
write_file(&dir, "main.go", r#"
694+
package main
695+
696+
func Add(a int, b int) int {
697+
return a + b
698+
}
699+
700+
func Subtract(a int, b int) int {
701+
return a - b
702+
}
703+
"#);
704+
let idx = SymbolIndex::new(dir.path().to_str().unwrap()).unwrap();
705+
let symbols = idx.scan_all().unwrap();
706+
707+
let fns: Vec<_> = symbols.iter().filter(|s| s.kind == "function").collect();
708+
assert_eq!(fns.len(), 2);
709+
find_sym(&symbols, "Add");
710+
find_sym(&symbols, "Subtract");
711+
}
712+
713+
// ── 16. Java ────────────────────────────────────────────────────────
714+
715+
#[test]
716+
fn test_parse_java() {
717+
let dir = TempDir::new().unwrap();
718+
write_file(&dir, "src/App.java", r#"
719+
class UserService {
720+
public void createUser(String name) {}
721+
public void deleteUser(int id) {}
722+
}
723+
724+
interface Repository {
725+
void save();
726+
}
727+
728+
enum Color {
729+
RED, GREEN, BLUE
730+
}
731+
"#);
732+
let idx = SymbolIndex::new(dir.path().to_str().unwrap()).unwrap();
733+
let symbols = idx.scan_all().unwrap();
734+
735+
find_sym(&symbols, "UserService");
736+
find_sym(&symbols, "createUser");
737+
find_sym(&symbols, "deleteUser");
738+
find_sym(&symbols, "Repository");
739+
find_sym(&symbols, "Color");
740+
}
741+
742+
// ── 17. C ───────────────────────────────────────────────────────────
743+
744+
#[test]
745+
fn test_parse_c() {
746+
let dir = TempDir::new().unwrap();
747+
write_file(&dir, "src/math.c", r#"
748+
int add(int a, int b) {
749+
return a + b;
750+
}
751+
752+
int multiply(int a, int b) {
753+
return a * b;
754+
}
755+
"#);
756+
let idx = SymbolIndex::new(dir.path().to_str().unwrap()).unwrap();
757+
let symbols = idx.scan_all().unwrap();
758+
759+
assert!(symbols.len() >= 2, "expected at least 2 symbols, got {:?}",
760+
symbols.iter().map(|s| format!("{}({})", s.name, s.kind)).collect::<Vec<_>>());
761+
}
762+
763+
// ── 18. C++ ─────────────────────────────────────────────────────────
764+
765+
#[test]
766+
fn test_parse_cpp() {
767+
let dir = TempDir::new().unwrap();
768+
write_file(&dir, "src/engine.cpp", r#"
769+
class Engine {
770+
public:
771+
void start() {}
772+
void stop() {}
773+
};
774+
775+
namespace physics {
776+
void simulate() {}
777+
}
778+
"#);
779+
let idx = SymbolIndex::new(dir.path().to_str().unwrap()).unwrap();
780+
let symbols = idx.scan_all().unwrap();
781+
782+
find_sym(&symbols, "Engine");
783+
// namespace and functions may or may not be extracted depending on grammar
784+
assert!(!symbols.is_empty());
785+
}
786+
787+
// ── 19. Ruby ────────────────────────────────────────────────────────
788+
789+
#[test]
790+
fn test_parse_ruby() {
791+
let dir = TempDir::new().unwrap();
792+
write_file(&dir, "app.rb", r#"
793+
class Dog
794+
def initialize(name)
795+
@name = name
796+
end
797+
798+
def bark
799+
"woof"
800+
end
801+
802+
def self.species
803+
"Canis familiaris"
804+
end
805+
end
806+
807+
module Helpers
808+
def format(text)
809+
text.strip
810+
end
811+
end
812+
"#);
813+
let idx = SymbolIndex::new(dir.path().to_str().unwrap()).unwrap();
814+
let symbols = idx.scan_all().unwrap();
815+
816+
find_sym(&symbols, "Dog");
817+
find_sym(&symbols, "initialize");
818+
find_sym(&symbols, "bark");
819+
find_sym(&symbols, "Helpers");
820+
}
584821
}

0 commit comments

Comments
 (0)