import std.stdio;
import std.regex;
import std.conv : to;
import std.file : readText;
import std.string : splitLines, strip;
import std.array : split, join;
string get_user_types(string[] lines) {
bool[string] user_types;
//writeln(lines);
foreach (string line; lines) {
auto m = match(line, regex(r"^(?:class|struct|interface)\s+(\_?[a-z]+\w*)(?:\s*\:\s*(\_?[a-z]+\w*(?:\s*\,\s*)?)*\s*\{?)?", "i"));
if (!m.empty()) {
auto c = m.captures;
user_types[strip(c[1])] = true;
if (c.length > 2) {
foreach (string splitter; split(c[2], ",")) {
user_types[strip(splitter)] = true;
}
}
}
}
//writeln(user_types.keys);
if (user_types.length > 0) {
return "r" ~ join(user_types.keys, "|");
}
return "";
}
void main(string[] args) {
if (args.length == 1) {
writeln("Zuwenige Argumente");
return;
}
const string content = readText(args[1]);
string[] content_lines = splitLines(content);
string user_types = get_user_types(content_lines);
if (user_types.length > 0) {
user_types = r"|" ~ user_types;
}
string[][] vars;
foreach (uint lnr, string line; content_lines) {
// is comment?
auto _m = match(line, regex(r"(?:\/\/+|\/+\*+)"));
if (!_m.empty()) continue;
auto m = match(line, regex(r"((?:u?(?:long|int|short|byte|cent)|(?:(?:i|c)?(?:real|double|float))|bool|(?:w|d)?char|string|Object" ~ user_types ~ r")(?:\s*\[.*?\]\s*)?)\s+(\_?[a-z]+[\-_\w]*?)(\s*\,\s*.+?)?\s*\;", "i"));
if (!m.empty()) {
auto c = m.captures;
//writeln(c);
string hit = strip(c[2]);
vars ~= [to!(string)(lnr + 1), c[1], hit];
if (c.length > 3) {
string[] splitter = split(c[3], ",");
foreach (s; splitter) {
auto m2 = match(s, regex(r"^\s*\_?[a-z]+[\-_\w]*?\s*$", "i"));
if (!m2.empty()) {
//writeln(m2.captures);
hit = strip(m2.captures.hit);
vars ~= [to!(string)(lnr + 1), c[1], hit];
}
}
}
}
}
//writeln(content);
writeln("All variables that were not directly initialized: ");
foreach (string[] var; vars) {
writefln("Variable \"%s\" of Type \"%s\" on line %s", var[2], var[1], var[0]);
}
bool[string] init;
foreach (string line; splitLines(content)) {
//writeln(line);
foreach (string[] var; vars) {
// is comment?
auto _m = match(line, regex(r"(?:\/\/+|\/+\*+)"));
if (!_m.empty()) continue;
/* Wird der Variable etwas zugewiesen? */
auto m = match(line, regex(r"(?:\*|this\.|super\.|\_?[a-z]+[\-_\w]*?\.)?" ~ var[2] ~ r"(?:\[.*?\])?\s*(?:~\s*)?=\s*(?:.+?|\[.*?\])\s*\;"));
/* Wird die Variable per Referenz "befüllt"? */
auto m2 = match(line, regex(r"\&(?:this\.|super\.|\_?[a-z]+[\-_\w]*?\.)?" ~ var[2]));
/* Wird mit der Variable gerechnet, einer anderen zugewiesen oder eine andere Operation durchgeführt? */
auto m3 = match(line, regex(r"\_?[a-z]+[\-_\w]*(?:\[.*?\])?\s*(?:~\s*)?=\s*(?:.*?)" ~ var[2]));
if (!m.empty || !m2.empty() || !m3.empty()) {
init[var[2]] = true;
}
}
}
writeln("\nUnused variables: ");
uint total = 0;
foreach (string[] var; vars) {
if (var[2] !in init) {
writefln("Variable \"%s\" of Type \"%s\" on line %s is unused.", var[2], var[1], var[0]);
++total;
}
}
writefln("%d unused variables.", total);
}