#[allow(unused_macros)]
macro_rules! get_language {
(tree_sitter_cpp) => {
tree_sitter_mozcpp::LANGUAGE.into()
};
(tree_sitter_typescript) => {
tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()
};
(tree_sitter_tsx) => {
tree_sitter_typescript::LANGUAGE_TSX.into()
};
(tree_sitter_php) => {
tree_sitter_php::LANGUAGE_PHP.into()
};
($name:ident) => {
$name::LANGUAGE.into()
};
}
macro_rules! implement_metric_trait {
(Abc, $($code:ident),+) => (
implement_metric_trait!(@code_taking Abc, $($code),+);
);
(Cognitive, $($code:ident),+) => (
$(
impl Cognitive for $code {
fn compute<'a>(
_node: &Node<'a>,
_code: &'a [u8],
_stats: &mut Stats,
_nesting_map: &mut HashMap<usize, (usize, usize, usize)>,
) {}
}
)+
);
(Halstead, $($code:ident),+) => (
$(
impl Halstead for $code {
fn compute<'a>(_node: &Node<'a>, _code: &'a [u8], _halstead_maps: &mut HalsteadMaps<'a>) {}
}
)+
);
(@code_taking $trait:ident, $($code:ident),+) => (
$(
impl $trait for $code {
fn compute<'a>(_node: &Node<'a>, _code: &'a [u8], _stats: &mut Stats) {}
}
)+
);
(Exit, $($code:ident),+) => (
implement_metric_trait!(@code_taking Exit, $($code),+);
);
(Cyclomatic, $($code:ident),+) => (
implement_metric_trait!(@code_taking Cyclomatic, $($code),+);
);
(Npa, $($code:ident),+) => (
implement_metric_trait!(@code_taking Npa, $($code),+);
);
(Npm, $($code:ident),+) => (
implement_metric_trait!(@code_taking Npm, $($code),+);
);
(Loc, $($code:ident),+) => (
$(
impl Loc for $code {
fn compute(_node: &Node, _stats: &mut Stats, _is_func_space: bool, _is_unit: bool) {}
}
)+
);
(Wmc, $($code:ident),+) => (
$(
impl Wmc for $code {
fn compute(_space_kind: SpaceKind, _cyclomatic: &cyclomatic::Stats, _stats: &mut Stats) {}
}
)+
);
([$trait:ident], $($code:ident),+) => (
$(
impl $trait for $code {}
)+
);
($trait:ident, $($code:ident),+) => (
$(
impl $trait for $code {
fn compute(_node: &Node, _stats: &mut Stats) {}
}
)+
)
}
macro_rules! mk_lang {
( $( ($feature:literal, $camel:ident, $name:ident, $display: expr, $description:expr) ),* ) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LANG {
$(
#[doc = $description]
$camel,
)*
}
impl LANG {
pub fn into_enum_iter() -> impl Iterator<Item=LANG> {
use LANG::*;
[$( $camel, )*].into_iter()
}
pub fn get_name(&self) -> &'static str {
match self {
$(
LANG::$camel => $display,
)*
}
}
#[must_use]
pub fn is_enabled(&self) -> bool {
match self {
$(
#[cfg(feature = $feature)]
LANG::$camel => true,
#[cfg(not(feature = $feature))]
LANG::$camel => false,
)*
}
}
pub(crate) fn get_ts_language(&self) -> Result<Language, crate::MetricsError> {
match self {
$(
#[cfg(feature = $feature)]
LANG::$camel => Ok(get_language!($name)),
#[cfg(not(feature = $feature))]
LANG::$camel => Err(crate::MetricsError::LanguageDisabled(*self)),
)*
}
}
pub fn get_tree_sitter_language(&self) -> Result<::tree_sitter::Language, crate::MetricsError> {
self.get_ts_language()
}
}
};
}
macro_rules! mk_action {
( $( ($feature:literal, $camel:ident, $parser:ident) ),* ) => {
#[inline]
pub fn action<T: Callback>(lang: &LANG, source: Vec<u8>, path: &Path, pr: Option<Arc<PreprocResults>>, cfg: T::Cfg) -> Result<T::Res, MetricsError> {
match lang {
$(
#[cfg(feature = $feature)]
LANG::$camel => {
let parser = $parser::new(source, path, pr);
Ok(T::call(cfg, &parser))
},
#[cfg(not(feature = $feature))]
LANG::$camel => {
let _ = (source, path, pr, cfg);
Err(MetricsError::LanguageDisabled(*lang))
},
)*
}
}
#[deprecated(
since = "0.0.26",
note = "Use `analyze(Source::new(lang, &code).with_name(Some(name)), MetricsOptions::default())` instead — the path-positional shim derives the top-level FuncSpace name via lossy UTF-8 conversion."
)]
#[inline]
pub fn get_function_spaces(lang: &LANG, source: Vec<u8>, path: &Path, pr: Option<Arc<PreprocResults>>) -> Result<FuncSpace, MetricsError> {
#[allow(deprecated)]
match lang {
$(
#[cfg(feature = $feature)]
LANG::$camel => {
let parser = $parser::new(source, &path, pr);
metrics(&parser, &path)
},
#[cfg(not(feature = $feature))]
LANG::$camel => {
let _ = (source, path, pr);
Err(MetricsError::LanguageDisabled(*lang))
},
)*
}
}
pub(crate) enum AstInner {
$(
#[cfg(feature = $feature)]
$camel($parser),
)*
}
impl AstInner {
pub(crate) fn run_metrics(
&self,
name: Option<String>,
options: MetricsOptions,
) -> Result<FuncSpace, MetricsError> {
match self {
$(
#[cfg(feature = $feature)]
AstInner::$camel(parser) => metrics_inner(parser, name, options),
)*
#[cfg(not(any( $( feature = $feature ),* )))]
_ => {
let _ = (name, options);
match *self {}
},
}
}
pub(crate) fn language(&self) -> LANG {
match self {
$(
#[cfg(feature = $feature)]
AstInner::$camel(_) => LANG::$camel,
)*
#[cfg(not(any( $( feature = $feature ),* )))]
_ => match *self {},
}
}
pub(crate) fn code_bytes(&self) -> &[u8] {
match self {
$(
#[cfg(feature = $feature)]
AstInner::$camel(parser) => parser.get_code(),
)*
#[cfg(not(any( $( feature = $feature ),* )))]
_ => match *self {},
}
}
pub(crate) fn ts_tree(&self) -> &::tree_sitter::Tree {
match self {
$(
#[cfg(feature = $feature)]
AstInner::$camel(parser) => parser.get_ts_tree(),
)*
#[cfg(not(any( $( feature = $feature ),* )))]
_ => match *self {},
}
}
}
pub(crate) fn ast_parse_dispatch(
lang: LANG,
source: &[u8],
preproc_path: Option<&Path>,
preproc: Option<Arc<PreprocResults>>,
) -> Result<AstInner, MetricsError> {
let preproc_path = preproc_path.unwrap_or(Path::new(""));
let source = source.to_vec();
match lang {
$(
#[cfg(feature = $feature)]
LANG::$camel => Ok(AstInner::$camel($parser::new(source, preproc_path, preproc))),
#[cfg(not(feature = $feature))]
LANG::$camel => {
let _ = (source, preproc_path, preproc);
Err(MetricsError::LanguageDisabled(lang))
},
)*
}
}
pub(crate) fn ast_from_tree_dispatch(
lang: LANG,
tree: ::tree_sitter::Tree,
source: Vec<u8>,
) -> Result<AstInner, MetricsError> {
match lang {
$(
#[cfg(feature = $feature)]
LANG::$camel => Ok(AstInner::$camel($parser::from_tree(tree, source))),
#[cfg(not(feature = $feature))]
LANG::$camel => {
let _ = (tree, source);
Err(MetricsError::LanguageDisabled(lang))
},
)*
}
}
#[doc(hidden)]
pub fn analyze_dispatch(
lang: LANG,
source: &[u8],
name: Option<String>,
preproc_path: Option<&Path>,
preproc: Option<Arc<PreprocResults>>,
options: MetricsOptions,
) -> Result<FuncSpace, MetricsError> {
ast_parse_dispatch(lang, source, preproc_path, preproc)?.run_metrics(name, options)
}
#[deprecated(
since = "0.0.26",
note = "Use `analyze(Source::new(lang, &code).with_name(Some(name)), options)` instead — the path-positional shim derives the top-level FuncSpace name via lossy UTF-8 conversion."
)]
#[inline]
pub fn get_function_spaces_with_options(lang: &LANG, source: Vec<u8>, path: &Path, pr: Option<Arc<PreprocResults>>, options: MetricsOptions) -> Result<FuncSpace, MetricsError> {
#[allow(deprecated)]
match lang {
$(
#[cfg(feature = $feature)]
LANG::$camel => {
let parser = $parser::new(source, &path, pr);
metrics_with_options(&parser, &path, options)
},
#[cfg(not(feature = $feature))]
LANG::$camel => {
let _ = (source, path, pr, options);
Err(MetricsError::LanguageDisabled(*lang))
},
)*
}
}
#[inline]
pub fn metrics_from_tree(
lang: &LANG,
tree: ::tree_sitter::Tree,
source: Vec<u8>,
path: &Path,
pr: Option<Arc<PreprocResults>>,
options: MetricsOptions,
) -> Result<FuncSpace, MetricsError> {
let _ = pr;
let name = Some(path.to_string_lossy().into_owned());
ast_from_tree_dispatch(*lang, tree, source)?.run_metrics(name, options)
}
#[inline]
pub fn get_ops(lang: &LANG, source: Vec<u8>, path: &Path, pr: Option<Arc<PreprocResults>>) -> Result<Ops, MetricsError> {
match lang {
$(
#[cfg(feature = $feature)]
LANG::$camel => {
let parser = $parser::new(source, &path, pr);
operands_and_operators(&parser, &path)
},
#[cfg(not(feature = $feature))]
LANG::$camel => {
let _ = (source, path, pr);
Err(MetricsError::LanguageDisabled(*lang))
},
)*
}
}
};
}
macro_rules! mk_extensions {
( $( ($camel:ident, [ $( $ext:ident ),* ]) ),* ) => {
pub fn get_from_ext(ext: &str) -> Option<LANG>{
match ext {
$(
$(
stringify!($ext) => Some(LANG::$camel),
)*
)*
_ => None,
}
}
impl LANG {
#[must_use]
pub fn get_extensions(&self) -> &'static [&'static str] {
match self {
$(
LANG::$camel => &[ $( stringify!($ext), )* ],
)*
}
}
}
};
}
macro_rules! mk_emacs_mode {
( $( ($camel:ident, [ $( $emacs_mode:expr ),* ]) ),* ) => {
pub fn get_from_emacs_mode(mode: &str) -> Option<LANG>{
match mode {
$(
$(
$emacs_mode => Some(LANG::$camel),
)*
)*
_ => None,
}
}
};
}
macro_rules! mk_code {
( $( ($camel:ident, $code:ident, $parser:ident, $name:ident, $docname:expr) ),* ) => {
$(
#[doc = concat!("Per-language code type tag for ", $docname, "; carries no data.")]
pub struct $code { _guard: (), }
impl LanguageInfo for $code {
type BaseLang = $camel;
fn get_lang() -> LANG {
LANG::$camel
}
fn get_lang_name() -> &'static str {
$docname
}
}
#[doc = "The `"]
#[doc = $docname]
#[doc = "` language parser."]
pub type $parser = Parser<$code>;
)*
};
}
macro_rules! mk_langs {
( $( ($feature:literal, $camel:ident, $description: expr, $display: expr, $code:ident, $parser:ident, $name:ident, [ $( $ext:ident ),* ], [ $( $emacs_mode:expr ),* ]) ),* ) => {
mk_lang!($( ($feature, $camel, $name, $display, $description) ),*);
mk_action!($( ($feature, $camel, $parser) ),*);
mk_extensions!($( ($camel, [ $( $ext ),* ]) ),*);
mk_emacs_mode!($( ($camel, [ $( $emacs_mode ),* ]) ),*);
mk_code!($( ($camel, $code, $parser, $name, stringify!($camel)) ),*);
};
}
macro_rules! csharp_invocation_expr_kinds {
() => {
$crate::Csharp::InvocationExpression
| $crate::Csharp::InvocationExpression2
| $crate::Csharp::InvocationExpression3
};
}
macro_rules! csharp_paren_expr_kinds {
() => {
$crate::Csharp::ParenthesizedExpression
| $crate::Csharp::ParenthesizedExpression2
| $crate::Csharp::ParenthesizedExpression3
};
}
macro_rules! csharp_prefix_unary_expr_kinds {
() => {
$crate::Csharp::PrefixUnaryExpression | $crate::Csharp::PrefixUnaryExpression2
};
}
macro_rules! csharp_var_decl_kinds {
() => {
$crate::Csharp::VariableDeclaration | $crate::Csharp::VariableDeclaration2
};
}
macro_rules! csharp_var_declarator_kinds {
() => {
$crate::Csharp::VariableDeclarator | $crate::Csharp::VariableDeclarator2
};
}
pub(crate) use implement_metric_trait;
pub(crate) use {
csharp_invocation_expr_kinds, csharp_paren_expr_kinds, csharp_prefix_unary_expr_kinds,
csharp_var_decl_kinds, csharp_var_declarator_kinds, get_language, mk_action, mk_code,
mk_emacs_mode, mk_extensions, mk_lang, mk_langs,
};