normalize_languages/
scheme.rs1use crate::{ContainerBody, Import, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6pub struct Scheme;
8
9impl Language for Scheme {
10 fn name(&self) -> &'static str {
11 "Scheme"
12 }
13 fn extensions(&self) -> &'static [&'static str] {
14 &["scm", "ss", "rkt"]
15 }
16 fn grammar_name(&self) -> &'static str {
17 "scheme"
18 }
19
20 fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
21 Some(self)
22 }
23
24 fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
25 if node.kind() != "list" {
26 return Vec::new();
27 }
28
29 let text = &content[node.byte_range()];
30 let line = node.start_position().row + 1;
31
32 for prefix in &["(import ", "(require "] {
33 if text.starts_with(prefix) {
34 return vec![Import {
35 module: "import".to_string(),
36 names: Vec::new(),
37 alias: None,
38 is_wildcard: false,
39 is_relative: false,
40 line,
41 }];
42 }
43 }
44
45 Vec::new()
46 }
47
48 fn format_import(&self, import: &Import, names: Option<&[&str]>) -> String {
49 let names_to_use: Vec<&str> = names
51 .map(|n| n.to_vec())
52 .unwrap_or_else(|| import.names.iter().map(|s| s.as_str()).collect());
53 if names_to_use.is_empty() {
54 format!("(import ({}))", import.module)
55 } else {
56 format!(
57 "(import (only ({}) {}))",
58 import.module,
59 names_to_use.join(" ")
60 )
61 }
62 }
63
64 fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
65 let name = symbol.name.as_str();
66 match symbol.kind {
67 crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
68 crate::SymbolKind::Module => name == "tests" || name == "test",
69 _ => false,
70 }
71 }
72
73 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
74 Some(*node)
76 }
77 fn analyze_container_body(
78 &self,
79 body_node: &Node,
80 content: &str,
81 inner_indent: &str,
82 ) -> Option<ContainerBody> {
83 crate::body::analyze_paren_body(body_node, content, inner_indent)
84 }
85
86 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
87 if node.kind() != "list" {
93 return node
94 .child_by_field_name("name")
95 .map(|n| &content[n.byte_range()]);
96 }
97 let mut cursor = node.walk();
98 let mut seen_define = false;
99 for child in node.children(&mut cursor) {
100 match child.kind() {
101 "symbol" if !seen_define => {
102 seen_define = true;
104 }
105 "symbol" if seen_define => {
106 return Some(&content[child.byte_range()]);
108 }
109 "list" if seen_define => {
110 let mut inner_cursor = child.walk();
113 for inner in child.children(&mut inner_cursor) {
114 if inner.kind() == "symbol" {
115 return Some(&content[inner.byte_range()]);
116 }
117 }
118 return None;
119 }
120 _ => {}
121 }
122 }
123 None
124 }
125}
126
127impl LanguageSymbols for Scheme {}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use crate::validate_unused_kinds_audit;
133
134 #[test]
135 fn unused_node_kinds_audit() {
136 #[rustfmt::skip]
137 let documented_unused: &[&str] = &[
138 "block_comment",
139 ];
140 validate_unused_kinds_audit(&Scheme, documented_unused)
141 .expect("Scheme unused node kinds audit failed");
142 }
143}