use crate::metrics::halstead::HalsteadType;
use crate::spaces::SpaceKind;
use crate::traits::Search;
use crate::*;
macro_rules! get_operator {
($language:ident) => {
#[inline(always)]
fn get_operator_id_as_str(id: u16) -> &'static str {
let typ: $language = id.into();
match typ {
$language::LPAREN => "()",
$language::LBRACK => "[]",
$language::LBRACE => "{}",
_ => {
let tok: &'static str = typ.into();
tok
}
}
}
};
}
pub trait Getter {
fn get_func_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
Self::get_func_space_name(node, code)
}
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
if let Some(name) = node.object().child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
std::str::from_utf8(code).ok()
} else {
Some("<anonymous>")
}
}
fn get_space_kind(_node: &Node) -> SpaceKind {
SpaceKind::Unknown
}
fn get_op_type(_node: &Node) -> HalsteadType {
HalsteadType::Unknown
}
fn get_operator_id_as_str(_id: u16) -> &'static str {
""
}
}
impl Getter for PythonCode {
fn get_space_kind(node: &Node) -> SpaceKind {
let typ = node.object().kind_id();
match typ.into() {
Python::FunctionDefinition => SpaceKind::Function,
Python::ClassDefinition => SpaceKind::Class,
Python::Module => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Python::*;
let id = node.object().kind_id();
match id.into() {
Import | DOT | From | COMMA | As | STAR | GTGT | Assert | COLONEQ | Return | Def
| Del | Raise | Pass | Break | Continue | If | Elif | Else | Async | For | In
| While | Try | Except | Finally | With | DASHGT | EQ | Global | Exec | AT | Not
| And | Or | PLUS | DASH | SLASH | PERCENT | SLASHSLASH | STARSTAR | PIPE | AMP
| CARET | LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ | GT | LTGT | Is | PLUSEQ
| DASHEQ | STAREQ | SLASHEQ | ATEQ | SLASHSLASHEQ | PERCENTEQ | STARSTAREQ | GTGTEQ
| LTLTEQ | AMPEQ | CARETEQ | PIPEEQ | Yield | Await | Await2 | Print => {
HalsteadType::Operator
}
Identifier | Integer | Float | True | False | None => HalsteadType::Operand,
String => {
let mut operator = HalsteadType::Unknown;
if let Some(parent) = node.object().parent() {
if parent.kind_id() != ExpressionStatement || parent.child_count() != 1 {
operator = HalsteadType::Operand;
};
}
operator
}
_ => HalsteadType::Unknown,
}
}
#[inline(always)]
fn get_operator_id_as_str(id: u16) -> &'static str {
let typ: Python = id.into();
typ.into()
}
}
impl Getter for MozjsCode {
fn get_space_kind(node: &Node) -> SpaceKind {
use Mozjs::*;
let typ = node.object().kind_id();
match typ.into() {
Function
| MethodDefinition
| GeneratorFunction
| FunctionDeclaration
| GeneratorFunctionDeclaration
| ArrowFunction => SpaceKind::Function,
Class | ClassDeclaration => SpaceKind::Class,
Program => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
if let Some(name) = node.object().child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
std::str::from_utf8(code).ok()
} else {
if let Some(parent) = node.object().parent() {
match parent.kind_id().into() {
Mozjs::Pair => {
if let Some(name) = parent.child_by_field_name("key") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
Mozjs::VariableDeclarator => {
if let Some(name) = parent.child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
_ => {}
}
}
Some("<anonymous>")
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Mozjs::*;
let id = node.object().kind_id();
match id.into() {
Export | Import | Import2 | Extends | DOT | From | LPAREN | COMMA | As | STAR
| GTGT | GTGTGT | COLON | Return | Delete | Throw | Break | Continue | If | Else
| Switch | Case | Default | Async | For | In | Of | While | Try | Catch | Finally
| With | EQ | AT | AMPAMP | PIPEPIPE | PLUS | DASH | DASHDASH | PLUSPLUS | SLASH
| PERCENT | STARSTAR | PIPE | AMP | LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ
| GT | PLUSEQ | BANG | BANGEQEQ | EQEQEQ | DASHEQ | STAREQ | SLASHEQ | PERCENTEQ
| STARSTAREQ | GTGTEQ | GTGTGTEQ | LTLTEQ | AMPEQ | CARET | CARETEQ | PIPEEQ
| Yield | LBRACK | LBRACE | Await | QMARK | QMARKQMARK | New | Let | Var | Const
| Function | Function2 | SEMI => HalsteadType::Operator,
Identifier | Identifier2 | MemberExpression | PropertyIdentifier | String | Number
| True | False | Null | Void | This | Super | Undefined | Set | Get | Typeof
| Instanceof => HalsteadType::Operand,
_ => HalsteadType::Unknown,
}
}
get_operator!(Mozjs);
}
impl Getter for JavascriptCode {
fn get_space_kind(node: &Node) -> SpaceKind {
use Javascript::*;
let typ = node.object().kind_id();
match typ.into() {
Function
| MethodDefinition
| GeneratorFunction
| FunctionDeclaration
| GeneratorFunctionDeclaration
| ArrowFunction => SpaceKind::Function,
Class | ClassDeclaration => SpaceKind::Class,
Program => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
if let Some(name) = node.object().child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
std::str::from_utf8(code).ok()
} else {
if let Some(parent) = node.object().parent() {
match parent.kind_id().into() {
Mozjs::Pair => {
if let Some(name) = parent.child_by_field_name("key") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
Mozjs::VariableDeclarator => {
if let Some(name) = parent.child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
_ => {}
}
}
Some("<anonymous>")
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Javascript::*;
let id = node.object().kind_id();
match id.into() {
Export | Import | Import2 | Extends | DOT | From | LPAREN | COMMA | As | STAR
| GTGT | GTGTGT | COLON | Return | Delete | Throw | Break | Continue | If | Else
| Switch | Case | Default | Async | For | In | Of | While | Try | Catch | Finally
| With | EQ | AT | AMPAMP | PIPEPIPE | PLUS | DASH | DASHDASH | PLUSPLUS | SLASH
| PERCENT | STARSTAR | PIPE | AMP | LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ
| GT | PLUSEQ | BANG | BANGEQEQ | EQEQEQ | DASHEQ | STAREQ | SLASHEQ | PERCENTEQ
| STARSTAREQ | GTGTEQ | GTGTGTEQ | LTLTEQ | AMPEQ | CARET | CARETEQ | PIPEEQ
| Yield | LBRACK | LBRACE | Await | QMARK | QMARKQMARK | New | Let | Var | Const
| Function | Function2 | SEMI => HalsteadType::Operator,
Identifier | Identifier2 | MemberExpression | PropertyIdentifier | String | Number
| True | False | Null | Void | This | Super | Undefined | Set | Get | Typeof
| Instanceof => HalsteadType::Operand,
_ => HalsteadType::Unknown,
}
}
get_operator!(Javascript);
}
impl Getter for TypescriptCode {
fn get_space_kind(node: &Node) -> SpaceKind {
use Typescript::*;
let typ = node.object().kind_id();
match typ.into() {
Function
| MethodDefinition
| GeneratorFunction
| FunctionDeclaration
| GeneratorFunctionDeclaration
| ArrowFunction => SpaceKind::Function,
Class | ClassDeclaration => SpaceKind::Class,
InterfaceDeclaration => SpaceKind::Interface,
Program => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
if let Some(name) = node.object().child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
std::str::from_utf8(code).ok()
} else {
if let Some(parent) = node.object().parent() {
match parent.kind_id().into() {
Mozjs::Pair => {
if let Some(name) = parent.child_by_field_name("key") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
Mozjs::VariableDeclarator => {
if let Some(name) = parent.child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
_ => {}
}
}
Some("<anonymous>")
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Typescript::*;
let id = node.object().kind_id();
match id.into() {
Export | Import | Import2 | Extends | DOT | From | LPAREN | COMMA | As | STAR
| GTGT | GTGTGT | COLON | Return | Delete | Throw | Break | Continue | If | Else
| Switch | Case | Default | Async | For | In | Of | While | Try | Catch | Finally
| With | EQ | AT | AMPAMP | PIPEPIPE | PLUS | DASH | DASHDASH | PLUSPLUS | SLASH
| PERCENT | STARSTAR | PIPE | AMP | LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ
| GT | PLUSEQ | BANG | BANGEQEQ | EQEQEQ | DASHEQ | STAREQ | SLASHEQ | PERCENTEQ
| STARSTAREQ | GTGTEQ | GTGTGTEQ | LTLTEQ | AMPEQ | CARET | CARETEQ | PIPEEQ
| Yield | LBRACK | LBRACE | Await | QMARK | QMARKQMARK | New | Let | Var | Const
| Function | Function2 | SEMI => HalsteadType::Operator,
Identifier | NestedIdentifier | MemberExpression | PropertyIdentifier | String
| Number | True | False | Null | Void | This | Super | Undefined | Set | Get
| Typeof | Instanceof => HalsteadType::Operand,
_ => HalsteadType::Unknown,
}
}
get_operator!(Typescript);
}
impl Getter for TsxCode {
fn get_space_kind(node: &Node) -> SpaceKind {
use Tsx::*;
let typ = node.object().kind_id();
match typ.into() {
Function
| MethodDefinition
| GeneratorFunction
| FunctionDeclaration
| GeneratorFunctionDeclaration
| ArrowFunction => SpaceKind::Function,
Class | ClassDeclaration => SpaceKind::Class,
InterfaceDeclaration => SpaceKind::Interface,
Program => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
if let Some(name) = node.object().child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
std::str::from_utf8(code).ok()
} else {
if let Some(parent) = node.object().parent() {
match parent.kind_id().into() {
Mozjs::Pair => {
if let Some(name) = parent.child_by_field_name("key") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
Mozjs::VariableDeclarator => {
if let Some(name) = parent.child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
_ => {}
}
}
Some("<anonymous>")
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Tsx::*;
let id = node.object().kind_id();
match id.into() {
Export | Import | Import2 | Extends | DOT | From | LPAREN | COMMA | As | STAR
| GTGT | GTGTGT | COLON | Return | Delete | Throw | Break | Continue | If | Else
| Switch | Case | Default | Async | For | In | Of | While | Try | Catch | Finally
| With | EQ | AT | AMPAMP | PIPEPIPE | PLUS | DASH | DASHDASH | PLUSPLUS | SLASH
| PERCENT | STARSTAR | PIPE | AMP | LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ
| GT | PLUSEQ | BANG | BANGEQEQ | EQEQEQ | DASHEQ | STAREQ | SLASHEQ | PERCENTEQ
| STARSTAREQ | GTGTEQ | GTGTGTEQ | LTLTEQ | AMPEQ | CARET | CARETEQ | PIPEEQ
| Yield | LBRACK | LBRACE | Await | QMARK | QMARKQMARK | New | Let | Var | Const
| Function | Function2 | SEMI => HalsteadType::Operator,
Identifier | NestedIdentifier | MemberExpression | PropertyIdentifier | String
| Number | True | False | Null | Void | This | Super | Undefined | Set | Get
| Typeof | Instanceof => HalsteadType::Operand,
_ => HalsteadType::Unknown,
}
}
get_operator!(Tsx);
}
impl Getter for RustCode {
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
if let Some(name) = node
.object()
.child_by_field_name("name")
.or_else(|| node.object().child_by_field_name("type"))
{
let code = &code[name.start_byte()..name.end_byte()];
std::str::from_utf8(code).ok()
} else {
Some("<anonymous>")
}
}
fn get_space_kind(node: &Node) -> SpaceKind {
use Rust::*;
let typ = node.object().kind_id();
match typ.into() {
FunctionItem | ClosureExpression => SpaceKind::Function,
TraitItem => SpaceKind::Trait,
ImplItem => SpaceKind::Impl,
SourceFile => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Rust::*;
let id = node.object().kind_id();
match id.into() {
LPAREN | LBRACE | LBRACK | EQGT | PLUS | STAR | Async | Await | Continue | For | If
| Let | Loop | Match | Return | Unsafe | While | BANG | EQ | COMMA | DASHGT | QMARK
| LT | GT | AMP | MutableSpecifier | DOTDOT | DOTDOTEQ | DASH | AMPAMP | PIPEPIPE
| PIPE | CARET | EQEQ | BANGEQ | LTEQ | GTEQ | LTLT | GTGT | SLASH | PERCENT
| PLUSEQ | DASHEQ | STAREQ | SLASHEQ | PERCENTEQ | AMPEQ | PIPEEQ | CARETEQ
| LTLTEQ | GTGTEQ | Move | DOT | PrimitiveType | Fn | SEMI => HalsteadType::Operator,
Identifier | StringLiteral | RawStringLiteral | IntegerLiteral | FloatLiteral
| BooleanLiteral | Zelf | CharLiteral | UNDERSCORE => HalsteadType::Operand,
_ => HalsteadType::Unknown,
}
}
get_operator!(Rust);
}
impl Getter for CppCode {
fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
let typ = node.object().kind_id();
match typ.into() {
Cpp::FunctionDefinition | Cpp::FunctionDefinition2 | Cpp::FunctionDefinition3 => {
if let Some(op_cast) = node.first_child(|id| Cpp::OperatorCast == id) {
let code = &code[op_cast.object().start_byte()..op_cast.object().end_byte()];
return std::str::from_utf8(code).ok();
}
if let Some(declarator) = node.object().child_by_field_name("declarator") {
let declarator_node = Node::new(declarator);
if let Some(fd) = declarator_node.first_occurence(|id| {
Cpp::FunctionDeclarator == id
|| Cpp::FunctionDeclarator2 == id
|| Cpp::FunctionDeclarator3 == id
}) {
if let Some(first) = fd.object().child(0) {
match first.kind_id().into() {
Cpp::TypeIdentifier
| Cpp::Identifier
| Cpp::FieldIdentifier
| Cpp::DestructorName
| Cpp::OperatorName
| Cpp::TemplateFunction
| Cpp::TemplateMethod => {
let code = &code[first.start_byte()..first.end_byte()];
return std::str::from_utf8(code).ok();
}
_ => {}
}
}
}
}
}
_ => {
if let Some(name) = node.object().child_by_field_name("name") {
let code = &code[name.start_byte()..name.end_byte()];
return std::str::from_utf8(code).ok();
}
}
}
None
}
fn get_space_kind(node: &Node) -> SpaceKind {
use Cpp::*;
let typ = node.object().kind_id();
match typ.into() {
FunctionDefinition | FunctionDefinition2 | FunctionDefinition3 => SpaceKind::Function,
StructSpecifier => SpaceKind::Struct,
ClassSpecifier => SpaceKind::Class,
NamespaceDefinition => SpaceKind::Namespace,
TranslationUnit => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Cpp::*;
let id = node.object().kind_id();
match id.into() {
DOT | LPAREN | LPAREN2 | COMMA | STAR | GTGT | COLON | SEMI | Return | Break
| Continue | If | Else | Switch | Case | Default | For | While | Goto | Do | Delete
| New | Try | Catch | Throw | EQ | AMPAMP | PIPEPIPE | DASH | DASHDASH | DASHGT
| PLUS | PLUSPLUS | SLASH | PERCENT | PIPE | AMP | LTLT | TILDE | LT | LTEQ | EQEQ
| BANGEQ | GTEQ | GT | GT2 | PLUSEQ | BANG | STAREQ | SLASHEQ | PERCENTEQ | GTGTEQ
| LTLTEQ | AMPEQ | CARET | CARETEQ | PIPEEQ | LBRACK | LBRACE | QMARK | COLONCOLON
| PrimitiveType | TypeSpecifier | Sizeof => HalsteadType::Operator,
Identifier | TypeIdentifier | FieldIdentifier | RawStringLiteral | StringLiteral
| NumberLiteral | True | False | Null | Nullptr | DOTDOTDOT => HalsteadType::Operand,
_ => HalsteadType::Unknown,
}
}
get_operator!(Cpp);
}
impl Getter for PreprocCode {}
impl Getter for CcommentCode {}
impl Getter for JavaCode {
fn get_space_kind(node: &Node) -> SpaceKind {
use Java::*;
let typ = node.object().kind_id();
match typ.into() {
ClassDeclaration => SpaceKind::Class,
MethodDeclaration | ConstructorDeclaration | LambdaExpression => SpaceKind::Function,
InterfaceDeclaration => SpaceKind::Interface,
Program => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_op_type(node: &Node) -> HalsteadType {
use Java::*;
let typ = node.object().kind_id();
match typ.into() {
MethodInvocation
| If | Else | Switch | Case | Try | Catch | Throw | Throws | Throws2 | For | While | Continue | Break | Do | Finally
| New | Return | Default | Abstract | Assert | Instanceof | Extends | Final | Implements | Transient | Synchronized | Super | This | VoidType
| SEMI | COMMA | COLONCOLON | LBRACE | LBRACK | LPAREN | RBRACE | RBRACK | RPAREN | DOTDOTDOT | DOT
| EQ | LT | GT | BANG | TILDE | QMARK | COLON | EQEQ | LTEQ | GTEQ | BANGEQ | AMPAMP | PIPEPIPE | PLUSPLUS | DASHDASH
| PLUS | DASH | STAR | SLASH | AMP | PIPE | CARET | PERCENT| LTLT | GTGT | GTGTGT
| PLUSEQ | DASHEQ | STAREQ | SLASHEQ | AMPEQ | PIPEEQ | CARETEQ | PERCENTEQ | LTLTEQ | GTGTEQ | GTGTGTEQ
| TypeIdentifier | IntegralType | FloatingPointType | BooleanType
=> {
HalsteadType::Operator
},
Identifier | NullLiteral | ClassLiteral | StringLiteral | CharacterLiteral | HexIntegerLiteral | OctalIntegerLiteral
| BinaryIntegerLiteral | DecimalIntegerLiteral | HexFloatingPointLiteral | DecimalFloatingPointLiteral => {
HalsteadType::Operand
},
_ => {
HalsteadType::Unknown
},
}
}
get_operator!(Java);
}