Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 62 additions & 18 deletions src/halstead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ impl Serialize for Stats<'_> {
where
S: Serializer,
{
let mut st = serializer.serialize_struct("halstead", 12)?;
st.serialize_field("unique_operands", &self.u_operands())?;
st.serialize_field("operands", &self.operands())?;
st.serialize_field("unique_operators", &self.u_operators())?;
st.serialize_field("operators", &self.operators())?;
let mut st = serializer.serialize_struct("halstead", 14)?;
st.serialize_field("n1", &self.u_operators())?;
st.serialize_field("N1", &self.operators())?;
st.serialize_field("n2", &self.u_operands())?;
st.serialize_field("N2", &self.operands())?;
st.serialize_field("length", &self.length())?;
st.serialize_field("size", &self.size())?;
st.serialize_field("estimated_program_length", &self.estimated_program_length())?;
st.serialize_field("purity_ratio", &self.purity_ratio())?;
st.serialize_field("vocabulary", &self.vocabulary())?;
st.serialize_field("volume", &self.volume())?;
st.serialize_field("difficulty", &self.difficulty())?;
st.serialize_field("level", &self.level())?;
Expand All @@ -38,7 +40,37 @@ impl Serialize for Stats<'_> {

impl<'a> fmt::Display for Stats<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "unique operands: {}, operands: {}, unique operators: {}, operators: {}, length: {}, size: {}, volume: {}, difficulty: {}, level: {}, effort: {}, time: {}, bugs: {}", self.u_operands(), self.operands(), self.u_operators(), self.operators(), self.length(), self.size(), self.volume(), self.difficulty(), self.level(), self.effort(), self.time(), self.bugs())
write!(
f,
"n1: {}, \
N1: {}, \
n2: {}, \
N2: {}, \
length: {}, \
estimated program length: {}, \
purity ratio: {}, \
size: {}, \
volume: {}, \
difficulty: {}, \
level: {}, \
effort: {}, \
time: {}, \
bugs: {}",
self.u_operators(),
self.operators(),
self.u_operands(),
self.operands(),
self.length(),
self.estimated_program_length(),
self.purity_ratio(),
self.vocabulary(),
self.volume(),
self.difficulty(),
self.level(),
self.effort(),
self.time(),
self.bugs(),
)
}
}

Expand Down Expand Up @@ -78,13 +110,24 @@ impl<'a> Stats<'a> {
}

#[inline(always)]
pub fn size(&self) -> f64 {
pub fn estimated_program_length(&self) -> f64 {
self.u_operators() * self.u_operators().log2()
+ self.u_operands() * self.u_operands().log2()
}

#[inline(always)]
pub fn purity_ratio(&self) -> f64 {
self.estimated_program_length() / self.length()
}

#[inline(always)]
pub fn vocabulary(&self) -> f64 {
self.u_operands() + self.u_operators()
}

#[inline(always)]
pub fn volume(&self) -> f64 {
self.length() * self.size().log2()
self.length() * self.vocabulary().log2()
}

#[inline(always)]
Expand Down Expand Up @@ -268,7 +311,7 @@ impl Halstead for RustCode {
| 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 => {
| LTLTEQ | GTGTEQ | Move | DOT | PrimitiveType => {
*stats.operators.entry(id).or_insert(0) += 1;
}
Identifier | StringLiteral | RawStringLiteral | IntegerLiteral | FloatLiteral
Expand All @@ -287,16 +330,17 @@ impl Halstead for CppCode {
let id = node.kind_id();

match id.into() {
DOT | LPAREN | COMMA | STAR | GTGT | COLON | Return | Break | Continue | If | Else
| Switch | Case | Default | For | While | Goto | Do | Delete | New | Try | Catch
| Throw | EQ | AMPAMP | PIPEPIPE | PLUS | PLUSPLUS | SLASH | PERCENT | PIPE | AMP
| LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ | GT | PLUSEQ | BANG | STAREQ
| SLASHEQ | PERCENTEQ | GTGTEQ | LTLTEQ | AMPEQ | CARET | CARETEQ | PIPEEQ | LBRACK
| LBRACE | QMARK | COLONCOLON | TypeSpecifier | Sizeof => {
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 | PLUS | PLUSPLUS
| SLASH | PERCENT | PIPE | AMP | LTLT | TILDE | LT | LTEQ | EQEQ | BANGEQ | GTEQ
| GT | PLUSEQ | BANG | STAREQ | SLASHEQ | PERCENTEQ | GTGTEQ | LTLTEQ | AMPEQ
| CARET | CARETEQ | PIPEEQ | LBRACK | LBRACE | QMARK | COLONCOLON | PrimitiveType
| TypeSpecifier | Sizeof => {
*stats.operators.entry(id).or_insert(0) += 1;
}
Identifier | TypeIdentifier | FieldIdentifier | PrimitiveType | RawStringLiteral
| StringLiteral | NumberLiteral | True | False | Null | Nullptr | DOTDOTDOT => {
Identifier | TypeIdentifier | FieldIdentifier | RawStringLiteral | StringLiteral
| NumberLiteral | True | False | Null | Nullptr | DOTDOTDOT => {
*stats.operands.entry(get_id(node, code)).or_insert(0) += 1;
}
_ => {}
Expand Down
24 changes: 11 additions & 13 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,24 +219,22 @@ impl<'a> FuncSpace<'a> {
writeln!(stdout, "halstead")?;

let prefix = format!("{}{}", prefix, pref_child);

Self::dump_value("n1", stats.u_operators(), &prefix, false, stdout)?;
Self::dump_value("N1", stats.operators(), &prefix, false, stdout)?;
Self::dump_value("n2", stats.u_operands(), &prefix, false, stdout)?;
Self::dump_value("N2", stats.operands(), &prefix, false, stdout)?;

Self::dump_value("length", stats.length(), &prefix, false, stdout)?;
Self::dump_value(
"unique operands",
stats.u_operands(),
&prefix,
false,
stdout,
)?;
Self::dump_value("operands", stats.operands(), &prefix, false, stdout)?;
Self::dump_value(
"unique operators",
stats.u_operators(),
"estimated program length",
stats.estimated_program_length(),
&prefix,
false,
stdout,
)?;
Self::dump_value("operators", stats.operators(), &prefix, false, stdout)?;
Self::dump_value("length", stats.length(), &prefix, false, stdout)?;
Self::dump_value("size", stats.size(), &prefix, false, stdout)?;
Self::dump_value("purity ratio", stats.purity_ratio(), &prefix, false, stdout)?;
Self::dump_value("vocabulary", stats.vocabulary(), &prefix, false, stdout)?;
Self::dump_value("volume", stats.volume(), &prefix, false, stdout)?;
Self::dump_value("difficulty", stats.difficulty(), &prefix, false, stdout)?;
Self::dump_value("level", stats.level(), &prefix, false, stdout)?;
Expand Down
60 changes: 35 additions & 25 deletions src/web/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,13 +640,15 @@ mod tests {
"difficulty": 1.0,
"effort": 4.754_887_502_163_468,
"length": 3.0,
"estimated_program_length": 2.0,
"purity_ratio": 0.666_666_666_666_666_6,
"level": 1.0,
"operands": 1.0,
"operators": 2.0,
"size": 3.0,
"N2": 1.0,
"N1": 2.0,
"vocabulary": 3.0,
"time": 0.264_160_416_786_859_36,
"unique_operands": 1.0,
"unique_operators": 2.0,
"n2": 1.0,
"n1": 2.0,
"volume": 4.754_887_502_163_468},
"loc": {"cloc": 1.0, "lloc": 2.0, "sloc": 3.0}},
"name": "test.py",
Expand All @@ -660,13 +662,15 @@ mod tests {
"difficulty": 1.0,
"effort": 4.754_887_502_163_468,
"length": 3.0,
"estimated_program_length": 2.0,
"purity_ratio": 0.666_666_666_666_666_6,
"level": 1.0,
"operands": 1.0,
"operators": 2.0,
"size": 3.0,
"N2": 1.0,
"N1": 2.0,
"vocabulary": 3.0,
"time": 0.264_160_416_786_859_36,
"unique_operands": 1.0,
"unique_operators": 2.0,
"n2": 1.0,
"n1": 2.0,
"volume": 4.754_887_502_163_468},
"loc": {"cloc": 0.0, "lloc": 2.0, "sloc": 2.0}},
"name": "foo",
Expand Down Expand Up @@ -706,13 +710,15 @@ mod tests {
"difficulty": 1.0,
"effort": 4.754_887_502_163_468,
"length": 3.0,
"estimated_program_length": 2.0,
"purity_ratio": 0.666_666_666_666_666_6,
"level": 1.0,
"operands": 1.0,
"operators": 2.0,
"size": 3.0,
"N2": 1.0,
"N1": 2.0,
"vocabulary": 3.0,
"time": 0.264_160_416_786_859_36,
"unique_operands": 1.0,
"unique_operators": 2.0,
"n2": 1.0,
"n1": 2.0,
"volume": 4.754_887_502_163_468},
"loc": {"cloc": 0.0, "lloc": 2.0, "sloc": 2.0}},
"name": "test.py",
Expand Down Expand Up @@ -748,13 +754,15 @@ mod tests {
"difficulty": 1.0,
"effort": 4.754_887_502_163_468,
"length": 3.0,
"estimated_program_length": 2.0,
"purity_ratio": 0.666_666_666_666_666_6,
"level": 1.0,
"operands": 1.0,
"operators": 2.0,
"size": 3.0,
"N2": 1.0,
"N1": 2.0,
"vocabulary": 3.0,
"time": 0.264_160_416_786_859_36,
"unique_operands": 1.0,
"unique_operators": 2.0,
"n2": 1.0,
"n1": 2.0,
"volume": 4.754_887_502_163_468},
"loc": {"cloc": 0.0, "lloc": 2.0, "sloc": 2.0}},
"name": "test.py",
Expand All @@ -768,13 +776,15 @@ mod tests {
"difficulty": 1.0,
"effort": 4.754_887_502_163_468,
"length": 3.0,
"estimated_program_length": 2.0,
"purity_ratio": 0.666_666_666_666_666_6,
"level": 1.0,
"operands": 1.0,
"operators": 2.0,
"size": 3.0,
"N2": 1.0,
"N1": 2.0,
"vocabulary": 3.0,
"time": 0.264_160_416_786_859_36,
"unique_operands": 1.0,
"unique_operators": 2.0,
"n2": 1.0,
"n1": 2.0,
"volume": 4.754_887_502_163_468},
"loc": {"cloc": 0.0, "lloc": 2.0, "sloc": 2.0}},
"name": "foo",
Expand Down