#104, declarations, func templates, c/dtors, tests

This commit is contained in:
Basile Burg 2016-11-16 09:51:57 +01:00
parent 65373d0b8f
commit f1a6c31fb6
No known key found for this signature in database
GPG Key ID: 1868039F415CB8CF
1 changed files with 401 additions and 33 deletions

View File

@ -1,7 +1,7 @@
module halstead;
import
std.meta, std.traits, std.algorithm.iteration, std.json;
std.meta, std.traits, std.algorithm.iteration, std.json, std.conv;
import
dparse.lexer, dparse.parser, dparse.ast, dparse.rollback_allocator;
import
@ -50,21 +50,20 @@ private final class HalsteadMetric: ASTVisitor
}
override void visit(const(PragmaExpression)){}
override void visit(const(Unittest)){}
//TODO: add share/static/__ctor & __dtor
override void visit(const(FunctionDeclaration) decl)
void beginFunction()
{
if (!decl.functionBody)
return;
operators.clear;
operands.clear;
if (functionNesting++ == 0)
functions.length = functions.length + 1;
}
decl.accept(this);
functions[$-1].name = decl.name.text;
functions[$-1].line = decl.name.line;
void endFunction(string name, size_t line)
{
functions[$-1].name = name;
functions[$-1].line = line;
if (operators.length)
{
@ -94,12 +93,87 @@ private final class HalsteadMetric: ASTVisitor
writeln('\t',operands);
}
operators.clear;
operands.clear;
functionNesting--;
}
override void visit(const(FunctionCallExpression) expr)
{
if (expr.unaryExpression.primaryExpression)
{
const(PrimaryExpression) p = expr.unaryExpression.primaryExpression;
if (p.identifierOrTemplateInstance)
{
if (p.identifierOrTemplateInstance.templateInstance)
++operators[p.identifierOrTemplateInstance.templateInstance.identifier.text];
else
++operators[p.identifierOrTemplateInstance.identifier.text];
}
}
if (expr.templateArguments)
{
if (expr.templateArguments.templateSingleArgument)
++operands[expr.templateArguments.templateSingleArgument.token.text];
else if (expr.templateArguments.templateArgumentList)
{
foreach(arg; expr.templateArguments.templateArgumentList.items)
{}//++operands[arg.token.text];
}
}
expr.accept(this);
}
override void visit(const(FunctionDeclaration) decl)
{
if (!decl.functionBody)
return;
beginFunction;
decl.accept(this);
endFunction(decl.name.text, decl.name.line);
}
override void visit(const(SharedStaticConstructor) ssc)
{
beginFunction;
ssc.accept(this);
endFunction("sharedStaticCtorL" ~ to!string(ssc.line), ssc.line);
}
override void visit(const(StaticConstructor) sc)
{
beginFunction;
sc.accept(this);
endFunction("staticCtorL" ~ to!string(sc.line), sc.line);
}
override void visit(const(Constructor) sc)
{
beginFunction;
sc.accept(this);
endFunction("ctorL" ~ to!string(sc.line), sc.line);
}
override void visit(const(SharedStaticDestructor) ssc)
{
beginFunction;
ssc.accept(this);
endFunction("sharedStaticDtorL" ~ to!string(ssc.line), ssc.line);
}
override void visit(const(StaticDestructor) sc)
{
beginFunction;
sc.accept(this);
endFunction("staticDtorL" ~ to!string(sc.line), sc.line);
}
override void visit(const(Destructor) sc)
{
beginFunction;
sc.accept(this);
endFunction("dtorL" ~ to!string(sc.line), sc.line);
}
override void visit(const(PrimaryExpression) primary)
{
if (primary.identifierOrTemplateInstance !is null
@ -107,8 +181,6 @@ private final class HalsteadMetric: ASTVisitor
{
if (!functionCall)
++operands[primary.identifierOrTemplateInstance.identifier.text];
else
++operators[primary.identifierOrTemplateInstance.identifier.text];
}
else if (primary.primary.type.isLiteral)
@ -129,14 +201,9 @@ private final class HalsteadMetric: ASTVisitor
if (expr.suffix.type)
++operators[str(expr.suffix.type)];
// TODO: detect function name here
if (expr.functionCallExpression)
functionCall = true;
// TODO: detect function call w/o parens
//else if (expr.prefix.type == tok!"" && expr.suffix.type == tok!"")
// functionCall = true;
expr.accept(this);
}
@ -206,6 +273,12 @@ private final class HalsteadMetric: ASTVisitor
expr.accept(this);
}
override void visit(const(DeleteExpression) expr)
{
++operators["delete"];
expr.accept(this);
}
override void visit(const(CastExpression) expr)
{
++operators["cast"];
@ -317,6 +390,27 @@ private final class HalsteadMetric: ASTVisitor
st.accept(this);
}
override void visit(const(VariableDeclaration) decl)
{
if (decl.declarators)
foreach (elem; decl.declarators)
{
++operands[elem.name.text];
if (elem.initializer)
++operators["="];
}
else if (decl.autoDeclaration)
visit(decl.autoDeclaration);
decl.accept(this);
}
final override void visit(const AutoDeclarationPart decl)
{
++operands[decl.identifier.text];
++operators["="];
decl.accept(this);
}
static string exprAliases()
{
import std.range: iota;
@ -367,23 +461,297 @@ version(unittest)
return result;
}
void test(T)(T t)
unittest
{
auto a = 1;
auto b = a++;
auto c = a || b;
auto d = a << c;
auto e = a >>> c;
test(test());
test;
string src =
q{
void foo()
{
Object o = new Object;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 1);
assert(r.operators.length == 2);
}
unittest
{
import std.file;
char[] source = cast(char[]) __FILE__.read;
auto r = source.parseAndVisit!HalsteadMetric;
string src =
q{
void foo()
{
auto o = new Object;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 1);
assert(r.operators.length == 2);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
auto o = 1 + 2;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 3);
assert(r.operators.length == 2);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
foo(bar,baz);
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
int i = foo(bar,baz) + foo(bar,baz);
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 3);
assert(r.operators.length == 3);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
enum E{e0}
E e;
bar!(e,"lit")(baz(e));
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 2);
r.destruct;
}
unittest
{
string src =
q{
void foo();
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 0);
assert(r.operators.length == 0);
r.destruct;
}
unittest
{
string src =
q{
shared static this()
{
int i = 0;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
shared static ~this()
{
int i = 0;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
static this()
{
int i = 0;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
static ~this()
{
int i = 0;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
class Foo
{
this()
{
int i = 0;
}
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
class Foo
{
~this()
{
int i = 0;
}
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 1);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
i += a << b;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 3);
assert(r.operators.length == 2);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
++h;
i--;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 2);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
++i--;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 1);
assert(r.operators.length == 2);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
i = a | b & c && d || e^f + g^^h - a in b + a[0];
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 10);
assert(r.operators.length == 11);
r.destruct;
}
unittest
{
string src =
q{
void foo()
{
Bar bar = new Bar;
auto baz = cast(Baz) bar;
delete bar;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
assert(r.operands.length == 2);
assert(r.operators.length == 4);
r.destruct;
}
unittest
{
// TODO: detect function call w/o parens
string src =
q{
void foo()
{
bar;
}
};
HalsteadMetric r = src.parseAndVisit!HalsteadMetric;
//assert(r.operands.length == 0);
//assert(r.operators.length == 1);
r.destruct;
}
}