use rma_common::Language;
pub mod go;
pub mod java;
pub mod javascript;
pub mod python;
pub mod rust_lang;
#[derive(Debug, Clone)]
pub struct LanguageSemantics {
pub language: &'static str,
pub function_def_kinds: &'static [&'static str],
pub if_kinds: &'static [&'static str],
pub loop_kinds: &'static [&'static str],
pub variable_declaration_kinds: &'static [&'static str],
pub assignment_kinds: &'static [&'static str],
pub augmented_assignment_kinds: &'static [&'static str],
pub return_kinds: &'static [&'static str],
pub call_kinds: &'static [&'static str],
pub try_catch_kinds: &'static [&'static str],
pub throw_kinds: &'static [&'static str],
pub string_literal_kinds: &'static [&'static str],
pub numeric_literal_kinds: &'static [&'static str],
pub boolean_literal_kinds: &'static [&'static str],
pub null_literal_kinds: &'static [&'static str],
pub parameter_kinds: &'static [&'static str],
pub class_kinds: &'static [&'static str],
pub import_kinds: &'static [&'static str],
pub block_scope_kinds: &'static [&'static str],
pub break_kinds: &'static [&'static str],
pub continue_kinds: &'static [&'static str],
pub switch_kinds: &'static [&'static str],
pub case_kinds: &'static [&'static str],
pub member_access_kinds: &'static [&'static str],
pub binary_expression_kinds: &'static [&'static str],
pub identifier_kinds: &'static [&'static str],
pub unsafe_block_kinds: &'static [&'static str],
pub defer_kinds: &'static [&'static str],
pub spawn_kinds: &'static [&'static str],
pub condition_field: &'static str,
pub consequence_field: &'static str,
pub alternative_field: &'static str,
pub body_field: &'static str,
pub initializer_field: &'static str,
pub left_field: &'static str,
pub right_field: &'static str,
pub name_field: &'static str,
pub arguments_field: &'static str,
pub value_field: &'static str,
pub operator_field: &'static str,
pub object_field: &'static str,
pub property_field: &'static str,
pub function_field: &'static str,
pub parameters_field: &'static str,
pub return_type_field: &'static str,
pub type_field: &'static str,
pub handler_field: &'static str,
pub finalizer_field: &'static str,
}
impl LanguageSemantics {
pub fn for_language(language: Language) -> &'static LanguageSemantics {
match language {
Language::JavaScript | Language::TypeScript => &javascript::JAVASCRIPT_SEMANTICS,
Language::Rust => &rust_lang::RUST_SEMANTICS,
Language::Go => &go::GO_SEMANTICS,
Language::Python => &python::PYTHON_SEMANTICS,
Language::Java => &java::JAVA_SEMANTICS,
_ => &javascript::JAVASCRIPT_SEMANTICS,
}
}
pub fn language_enum(&self) -> Language {
match self.language {
"javascript" => Language::JavaScript,
"typescript" => Language::TypeScript,
"rust" => Language::Rust,
"go" => Language::Go,
"python" => Language::Python,
"java" => Language::Java,
_ => Language::Unknown,
}
}
pub fn is_function_def(&self, kind: &str) -> bool {
self.function_def_kinds.contains(&kind)
}
pub fn is_if(&self, kind: &str) -> bool {
self.if_kinds.contains(&kind)
}
pub fn is_loop(&self, kind: &str) -> bool {
self.loop_kinds.contains(&kind)
}
pub fn is_variable_declaration(&self, kind: &str) -> bool {
self.variable_declaration_kinds.contains(&kind)
}
pub fn is_assignment(&self, kind: &str) -> bool {
self.assignment_kinds.contains(&kind)
}
pub fn is_augmented_assignment(&self, kind: &str) -> bool {
self.augmented_assignment_kinds.contains(&kind)
}
pub fn is_return(&self, kind: &str) -> bool {
self.return_kinds.contains(&kind)
}
pub fn is_call(&self, kind: &str) -> bool {
self.call_kinds.contains(&kind)
}
pub fn is_try_catch(&self, kind: &str) -> bool {
self.try_catch_kinds.contains(&kind)
}
pub fn is_throw(&self, kind: &str) -> bool {
self.throw_kinds.contains(&kind)
}
pub fn is_string_literal(&self, kind: &str) -> bool {
self.string_literal_kinds.contains(&kind)
}
pub fn is_numeric_literal(&self, kind: &str) -> bool {
self.numeric_literal_kinds.contains(&kind)
}
pub fn is_boolean_literal(&self, kind: &str) -> bool {
self.boolean_literal_kinds.contains(&kind)
}
pub fn is_null_literal(&self, kind: &str) -> bool {
self.null_literal_kinds.contains(&kind)
}
pub fn is_literal(&self, kind: &str) -> bool {
self.is_string_literal(kind)
|| self.is_numeric_literal(kind)
|| self.is_boolean_literal(kind)
|| self.is_null_literal(kind)
}
pub fn is_parameter(&self, kind: &str) -> bool {
self.parameter_kinds.contains(&kind)
}
pub fn is_class(&self, kind: &str) -> bool {
self.class_kinds.contains(&kind)
}
pub fn is_import(&self, kind: &str) -> bool {
self.import_kinds.contains(&kind)
}
pub fn is_block_scope(&self, kind: &str) -> bool {
self.block_scope_kinds.contains(&kind)
}
pub fn is_break(&self, kind: &str) -> bool {
self.break_kinds.contains(&kind)
}
pub fn is_continue(&self, kind: &str) -> bool {
self.continue_kinds.contains(&kind)
}
pub fn is_switch(&self, kind: &str) -> bool {
self.switch_kinds.contains(&kind)
}
pub fn is_case(&self, kind: &str) -> bool {
self.case_kinds.contains(&kind)
}
pub fn is_member_access(&self, kind: &str) -> bool {
self.member_access_kinds.contains(&kind)
}
pub fn is_binary_expression(&self, kind: &str) -> bool {
self.binary_expression_kinds.contains(&kind)
}
pub fn is_identifier(&self, kind: &str) -> bool {
self.identifier_kinds.contains(&kind)
}
pub fn is_unsafe_block(&self, kind: &str) -> bool {
self.unsafe_block_kinds.contains(&kind)
}
pub fn is_defer(&self, kind: &str) -> bool {
self.defer_kinds.contains(&kind)
}
pub fn is_spawn(&self, kind: &str) -> bool {
self.spawn_kinds.contains(&kind)
}
pub fn is_control_flow(&self, kind: &str) -> bool {
self.is_if(kind)
|| self.is_loop(kind)
|| self.is_switch(kind)
|| self.is_try_catch(kind)
|| self.is_return(kind)
|| self.is_break(kind)
|| self.is_continue(kind)
|| self.is_throw(kind)
}
pub fn is_branch(&self, kind: &str) -> bool {
self.is_if(kind) || self.is_switch(kind) || self.is_try_catch(kind)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_language_semantics_lookup() {
let js_semantics = LanguageSemantics::for_language(Language::JavaScript);
assert_eq!(js_semantics.language, "javascript");
let rust_semantics = LanguageSemantics::for_language(Language::Rust);
assert_eq!(rust_semantics.language, "rust");
let go_semantics = LanguageSemantics::for_language(Language::Go);
assert_eq!(go_semantics.language, "go");
let python_semantics = LanguageSemantics::for_language(Language::Python);
assert_eq!(python_semantics.language, "python");
let java_semantics = LanguageSemantics::for_language(Language::Java);
assert_eq!(java_semantics.language, "java");
}
#[test]
fn test_javascript_function_detection() {
let semantics = LanguageSemantics::for_language(Language::JavaScript);
assert!(semantics.is_function_def("function_declaration"));
assert!(semantics.is_function_def("arrow_function"));
assert!(!semantics.is_function_def("call_expression"));
}
#[test]
fn test_rust_unsafe_detection() {
let semantics = LanguageSemantics::for_language(Language::Rust);
assert!(semantics.is_unsafe_block("unsafe_block"));
assert!(!semantics.is_unsafe_block("block"));
}
#[test]
fn test_control_flow_detection() {
let semantics = LanguageSemantics::for_language(Language::JavaScript);
assert!(semantics.is_control_flow("if_statement"));
assert!(semantics.is_control_flow("for_statement"));
assert!(semantics.is_control_flow("return_statement"));
assert!(!semantics.is_control_flow("call_expression"));
}
}