pub mod c_base;
pub mod definitions;
use std::collections::HashMap;
use std::sync::OnceLock;
pub trait Language: Send + Sync {
fn name(&self) -> &'static str;
fn extensions(&self) -> &'static [&'static str];
fn line_comment(&self) -> Option<&'static str>;
fn block_comment(&self) -> Option<(&'static str, &'static str)>;
fn import_keywords(&self) -> &'static [&'static str];
fn indent_size(&self) -> usize {
4
}
fn default_thresholds(&self) -> crate::Thresholds {
crate::Thresholds::default()
}
}
#[macro_export]
macro_rules! define_language {
(
$struct_name:ident,
$display_name:expr,
extensions: [$($ext:expr),*],
line_comment: $line_comment:expr,
block_comment: $block_comment:expr,
import_keywords: [$($kw:expr),*]
$(, thresholds: $thresholds:expr )?
) => {
pub struct $struct_name;
impl $crate::languages::Language for $struct_name {
fn name(&self) -> &'static str { $display_name }
fn extensions(&self) -> &'static [&'static str] { &[$($ext),*] }
fn line_comment(&self) -> Option<&'static str> { $line_comment }
fn block_comment(&self) -> Option<(&'static str, &'static str)> { $block_comment }
fn import_keywords(&self) -> &'static [&'static str] { &[$($kw),*] }
$(
fn default_thresholds(&self) -> $crate::Thresholds { $thresholds }
)?
}
};
}
pub struct LanguageRegistry {
languages: Vec<Box<dyn Language>>,
extension_map: HashMap<&'static str, usize>,
}
static REGISTRY: OnceLock<LanguageRegistry> = OnceLock::new();
impl LanguageRegistry {
#[must_use]
pub fn get() -> &'static Self {
REGISTRY.get_or_init(Self::new)
}
fn new() -> Self {
let languages: Vec<Box<dyn Language>> = vec![
Box::new(definitions::rust::Rust),
Box::new(definitions::python::Python),
Box::new(definitions::javascript::JavaScript),
Box::new(definitions::typescript::TypeScript),
Box::new(definitions::java::Java),
Box::new(definitions::csharp::CSharp),
Box::new(definitions::gdscript::GDScript),
Box::new(definitions::lua::Lua),
Box::new(definitions::go::Go),
Box::new(definitions::php::PHP),
Box::new(definitions::cpp::Cpp),
];
let mut extension_map = HashMap::new();
for (i, lang) in languages.iter().enumerate() {
for ext in lang.extensions() {
extension_map.insert(*ext, i);
}
}
Self {
languages,
extension_map,
}
}
#[must_use]
pub fn get_by_extension(&self, ext: &str) -> Option<&dyn Language> {
self.extension_map
.get(ext)
.map(|&i| self.languages[i].as_ref())
}
#[must_use]
pub fn supported_extensions(&self) -> Vec<&'static str> {
let mut extensions: Vec<&'static str> = self.extension_map.keys().copied().collect();
extensions.sort_unstable();
extensions
}
}