normalize_languages/
prolog.rs1use crate::{Import, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6pub struct Prolog;
8
9impl Language for Prolog {
10 fn name(&self) -> &'static str {
11 "Prolog"
12 }
13 fn extensions(&self) -> &'static [&'static str] {
14 &["pl", "pro", "prolog"]
15 }
16 fn grammar_name(&self) -> &'static str {
17 "prolog"
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() != "directive_term" {
26 return Vec::new();
27 }
28
29 let text = &content[node.byte_range()];
30 if text.contains("use_module(") {
31 return vec![Import {
32 module: text.trim().to_string(),
33 names: Vec::new(),
34 alias: None,
35 is_wildcard: false,
36 is_relative: false,
37 line: node.start_position().row + 1,
38 }];
39 }
40
41 Vec::new()
42 }
43
44 fn format_import(&self, import: &Import, names: Option<&[&str]>) -> String {
45 let names_to_use: Vec<&str> = names
47 .map(|n| n.to_vec())
48 .unwrap_or_else(|| import.names.iter().map(|s| s.as_str()).collect());
49 if names_to_use.is_empty() {
50 format!(":- use_module({}).", import.module)
51 } else {
52 format!(
53 ":- use_module({}, [{}]).",
54 import.module,
55 names_to_use.join(", ")
56 )
57 }
58 }
59
60 fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
61 let name = symbol.name.as_str();
62 match symbol.kind {
63 crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
64 crate::SymbolKind::Module => name == "tests" || name == "test",
65 _ => false,
66 }
67 }
68
69 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
70 let mut cursor = node.walk();
77 for child in node.children(&mut cursor) {
78 match child.kind() {
79 "atom" => return Some(&content[child.byte_range()]),
80 "functional_notation" => {
81 if let Some(name_node) = child.child_by_field_name("function") {
82 return Some(&content[name_node.byte_range()]);
83 }
84 }
85 "operator_notation" => {
86 let mut inner = child.walk();
88 for inner_child in child.children(&mut inner) {
89 if inner_child.kind() == "functional_notation"
90 && let Some(name_node) = inner_child.child_by_field_name("function")
91 {
92 return Some(&content[name_node.byte_range()]);
93 }
94 }
95 }
96 _ => {}
97 }
98 }
99 None
100 }
101}
102
103impl LanguageSymbols for Prolog {}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::validate_unused_kinds_audit;
109
110 #[test]
111 fn unused_node_kinds_audit() {
112 #[rustfmt::skip]
113 let documented_unused: &[&str] = &[
114 "binary_operator", "prefix_operator", "prexif_operator",
115 ];
116 validate_unused_kinds_audit(&Prolog, documented_unused)
117 .expect("Prolog unused node kinds audit failed");
118 }
119}