Menu
Home
Create new Paste
Log in
NotNull Parser
Code
Theme: cobalt
Theme: eclipse
Theme: elegant
Theme: monokai
Theme: neat
Theme: night
Theme: rubyblue
debug import std.stdio; import std.regex; import std.file : readText, write; import std.string : strip, format; import std.array : replace, replaceInPlace; import std.algorithm : reverse, split, join, countUntil; import std.conv : to; import std.path : dirName, baseName; debug import std.datetime; enum : string { OpToken = r"\@", InsertMakro = "#manual_precondition", ErrorMsg = "\"Object is null\"", //AdditionalParams = "%sstring filename = __FILE__, uint line = __LINE__)", AdditionalParamFilename = "%sstring filename = __FILE__", AdditionalParamLine = "%suint line = __LINE__", AdditionalParams = AdditionalParamFilename ~ AdditionalParamLine ~ ")", Assertion = "\tif (%s is null) throw new Exception(%s, %s, %s);" ~ InsertMakro, PreCondition = " in {\n%s\n} body {" } uint[string] parse_class_names(string[] lines) { uint[string] class_names; foreach (uint line_nr, string line; lines) { if (auto m = match(line, r"class\s*(\w+).*?\s*\{")) { class_names[m.captures[1]] = line_nr; } } return class_names; } int countUntilLast(alias pred = "a == b", R, N)(const R haystack, const N needle) { auto copy = haystack.dup; reverse(copy); const int pos = countUntil!(pred)(copy, needle); if (pos > -1) { return cast(int) (haystack.length - 1) - pos; } return -1; } unittest { const string test1 = "void bar(vec2!(short) v) {"; const string test2 = "void bar(vec2!(long long) v) {"; const string test3 = "void bar(vec2fs v) {"; static assert(test1.length - test1.countUntil(")") == 7); assert(test1.length - test1.countUntilLast(")") == 3); static assert(test2.length - test2.countUntil(")") == 7); assert(test2.length - test2.countUntilLast(")") == 3); static assert(test3.length - test3.countUntil(")") == 3); assert(test3.length - test3.countUntilLast(")") == 3); } string getCurrentClass(uint line_nr, const uint[string] class_names, uint line = __LINE__) { string _class; foreach (string class_name, index; class_names) { if (index <= line_nr) { _class = class_name; } if (index > line_nr) { break; } } if (_class.length > 0) { return _class; } assert(0, "Keine Klasse gefunden @ " ~ to!(string)(line)); } debug { version = Debug; } else { version = Release; } void main(string[] args) { version (Debug) { StopWatch sw1, sw2; sw1.start(); } // read file content const string buffer = readText(args[1]); // split into lines string[] lines = split(buffer, "\n"); // count how many lines will be added? const bool count_new_lines = args.length > 2 && args[2] == "#t"; uint new_lines = void; if (count_new_lines) { new_lines = 0; } // available classes const uint[string] class_names = parse_class_names(lines); debug { writeln("CLASSES:"); writeln(class_names); } // involved functions string[uint] func_names; bool comment = false; version (Debug) { sw1.stop(); sw2.start(); } // walk through the lines and search for OpToken foreach (uint line_nr, ref string line; lines) { if (line.length < 5) { continue; } /// multi line comment if (match(line, r"\/+\*+")) { comment = true; } if (match(line, r"\*+\/+")) { comment = false; } if (comment) { continue; } /// single comment if (match(line, r"^\s*\/\/+")) { continue; } bool found = false; /// loop every line until there are valid matches do { /// if found a line which use the OpToken... if (auto m = match(line, regex(r"([a-zA-Z_]+[\w_-]*(?:!\(?[\w\s,]+\)?)?)\s*(" ~ OpToken ~ r")\s*([a-zA-Z_]+[\w_-]*)", "m"))) { /** * c[0] -> whole match * c[1] -> Parameter Type (Object, class name, whatever) * c[2] -> operator (for replacement) * c[3] -> Parameter name */ auto c = m.captures; debug writeln(c); found = true; /// replace the OpToken //line = line.replace(c[2], ""); const uint tok_pos = line.countUntil(c[2]); //line = line[0 .. tok_pos] ~ line[tok_pos + c[2].length .. $]; line.replaceInPlace(tok_pos, tok_pos + c[2].length, ""); // if the parameter type is a valid class name... // if (c[1] in class_names && class_names[c[1]] != line_nr) { /// search for function or method name // search first bracket auto func = match(line, r"([a-zA-Z_]+[\w_-]*(?:!\(?[\w\s,]+\)?)?)\s*\("); if (func.captures[1].length == 0) { debug writeln(" -> ", func.captures); throw new Exception("Strange behaviour."); } // cast because of linux const uint first_bracket = line.countUntil(func.captures[1]) + func.captures[1].length; //func_names[line_nr] = func.captures[1] != "this" ? func.captures[1] : getCurrentClass(line_nr, class_names); if (func.captures[1] == "this" || func.captures[1] == "opCall") { debug writeln(func.captures); version (all) { func_names[line_nr] = getCurrentClass(line_nr, class_names); } else { continue; } /** until now: no extra work because of opCall or CTor calls **/ } else { func_names[line_nr] = func.captures[1]; } // search for last closed bracket int pos = line.countUntilLast(")"); if (pos < 0) { continue; } /// check if a precondition still exists //int pre_cond_pos = line[pos .. $].countUntil("in {"); int pre_cond_pos = -1; //if (auto pre_cond = match(line[pos .. $], r"(?:\s*in|\}\s*body)\s*\{")) { if (auto pre_cond = match(line, r"\s*in\s*\{")) { pre_cond_pos = line.countUntil(pre_cond.captures[0]); } /// check for filename and line number parameters auto m_file_param = match(line, r"string\s+([a-zA-Z_]+[\w_-]*)\s*=\s*__FILE__"); auto m_line_param = match(line, r"(?:u?int|size_t)\s+([a-zA-Z_]+[\w_-]*)\s*=\s*__LINE__"); // [a-zA-z]+\w* auto c_file = m_file_param.captures; auto c_line = m_line_param.captures; version (Debug) { writeln("===="); writeln(c_file); writeln(c_line); writeln("===="); } /// add addtional parameters for filename and line number // if line has already additional parameters, do nothing if (c_file[1].length > 0 || c_line[1].length > 0) { // has additional filename param? if (c_file[1].length == 0) { throw new Exception("Parameter problem."); } // has additional line number param? if (c_line[1].length == 0) { throw new Exception("Parameter problem."); } } else { const string add_params = format(AdditionalParams, ((pos - first_bracket) > 0 ? ", " : ""), ", "); line = line[0 .. pos] ~ add_params ~ line[pos + 1 .. $]; } // search for first open bracket pos = line.countUntil("{"); // Last? if (pos < 0) { continue; } /// check if additional paramter exist. // if: rename Exception parameter. const string param_filename = c_file[1].length == 0 ? "filename" : c_file[1]; string param_line = c_line[1].length == 0 ? "line" : c_line[1]; /// validate line numer if optional parameter is passed if (count_new_lines) { param_line ~= " - " ~ to!(string)(new_lines + ((pre_cond_pos == -1) ? 2 : 1)); } string assert_replacement = format(Assertion, c[3], ErrorMsg, param_filename, param_line); if (pre_cond_pos > 0) { // if a precondition still exists, only format Assertion (don't forget the opened bracket) assert_replacement = " {\n" ~ assert_replacement; } else { // else format PreCondition with formated Assertion assert_replacement = format(PreCondition, assert_replacement); } /// add assertion if (line.length > pos) { const int insert_makro_pos = line.countUntil(InsertMakro); // if a assertion for this line already exist if (insert_makro_pos > -1) { line = line.replace(InsertMakro, assert_replacement[2 .. $]); } else { // if not append assertion line = line[0 .. pos] ~ assert_replacement ~ line[pos + 1 .. $]; } } else { const int insert_makro_pos = line.countUntil(InsertMakro); // if a assertion for this line already exist if (insert_makro_pos > -1) { line = line.replace(InsertMakro, assert_replacement[2 .. $]); } else { // if not append assertion line = line[0 .. pos] ~ assert_replacement; } } // increment new lines if (count_new_lines) { new_lines += (pre_cond_pos == -1) ? 2 : 1; } //} } else { found = false; } } while (found); } version (Debug) { sw2.stop(); } /// replace all existing makros foreach (ref string line; lines) { line = line.replace(InsertMakro, ""); } version (Debug) { const float init_time = sw1.peek().to!("seconds", float)(); const float run_time = sw2.peek().to!("seconds", float)(); writefln("NEW LINES: %d, init time: %f sec., replacement time: %f sec.", (count_new_lines ? new_lines : -1), init_time, run_time); } /// write original code as copy version (Release) { if (count_new_lines) { string dir = dirName(args[1]); if (dir != ".") { dir ~= '/'; } else { dir = ""; } write(dir ~ "org_" ~ baseName(args[1]), buffer); } } else { writeln("----"); } version (Debug) { writeln(join(lines, "\n")); writeln("----"); writeln(func_names); } else { // write new valid D code into file write(args[1], join(lines, "\n")); } }
Username
Message
Add comment
Paste info
Author:
Namespace
Views:
178
Private:
no
Expires:
Never
Uploaded:
03.08.12 12:26
Votes
:
0
Tweet
Actions
Download
Fork
Raw
×
Confirm
Are you sure you want to delete this paste?
There's no way back!
×
Confirm
Reason