10203040506070809010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910 module trial.discovery.code; import std.algorithm; import std.string; import std.range; import std.file; import std.stdio; import std.conv; version(Have_libdparse) { public import dparse.ast; public import dparse.lexer; public import dparse.parser; } string getModuleName(string fileName) { if (!exists(fileName)) { return ""; } if (isDir(fileName)) { return ""; } auto file = File(fileName); auto moduleLine = file.byLine().map!(a => a.to!string).filter!(a => a.startsWith("module")); if (moduleLine.empty) { return ""; } return moduleLine.front.split(' ')[1].split(";")[0]; } version(Have_libdparse) { const(Token)[] stringToDTokens(string data) { try { ubyte[] fileBytes = cast(ubyte[]) data; StringCache cache = StringCache(StringCache.defaultBucketCount); LexerConfig config; config.stringBehavior = StringBehavior.source; config.fileName = ""; config.commentBehavior = CommentBehavior.intern; auto lexer = DLexer(fileBytes, config, &cache); const(Token)[] tokens = lexer.array; return tokens.map!(token => const Token(token.type, token.text.idup, token.line, token.column, token.index)).array; } catch(Throwable t) { t.writeln; return []; } } struct DLangAttribute { const(Token)[] tokens; inout { string identifier() { string result; foreach (token; tokens) { if (str(token.type) == "(") { break; } result ~= token.text; } return result; } string value() { bool after; string result; foreach (token; tokens) { if (after) { result ~= token.text.strip('"').strip('`').strip('\''); } if (str(token.type) == "(") { after = true; } } return result; } auto line() { return tokens[0].line; } } } struct DLangFunction { const(DLangAttribute)[] attributes; const(Token)[] tokens; string name() { auto result = TokenIterator(tokens).readUntilType("(").replace("\n", " ") .replace("\r", " ").replace("\t", " ").split(" "); std.algorithm.reverse(result); return result[0]; } bool hasAttribute(string name) { return !attributes.filter!(a => a.identifier == name).empty; } auto getAttribute(string name) { return attributes.filter!(a => a.identifier == name).front; } string testName() { foreach (attribute; attributes) { if (attribute.identifier == "") { return attribute.value; } } return name.camelToSentence; } size_t line() { return TokenIterator(tokens).skipUntilType("(").currentToken.line; } } struct DLangClass { const(Token)[] tokens; string name() { auto iterator = TokenIterator(tokens); auto name = iterator.readUntilType("{"); import std.stdio; if (name.indexOf(":") != -1) { name = name.split(":")[0]; } return name.strip; } DLangFunction[] functions() { int paranthesisCount; auto iterator = TokenIterator(tokens); iterator.skipUntilType("{"); const(Token)[] currentTokens; DLangFunction[] discoveredFunctions; DLangAttribute[] attributes; bool readingFunction; int functionLevel = 1; foreach (token; iterator) { string type = token.type.str; currentTokens ~= token; if (type == "@") { attributes ~= iterator.readAttribute; } if (type == "{") { paranthesisCount++; } if (type == "}") { paranthesisCount--; if (paranthesisCount == functionLevel) { discoveredFunctions ~= DLangFunction(attributes, currentTokens); } } readingFunction = paranthesisCount > functionLevel; if (type == "}" || (!readingFunction && type == ";")) { currentTokens = []; attributes = []; } } return discoveredFunctions; } } struct TokenIterator { private { const(Token)[] tokens; size_t index; } int opApply(int delegate(const(Token)) dg) { int result = 0; while (index < tokens.length) { result = dg(tokens[index]); index++; if (result) { break; } } return result; } ref auto skipWsAndComments() { while (index < tokens.length) { auto type = str(tokens[index].type); if (type != "comment" && type != "whitespace") { break; } index++; } return this; } auto currentToken() { return tokens[index]; } ref auto skipUntil(string text) { while (index < tokens.length) { if (tokens[index].text == text) { break; } index++; } return this; } ref auto skipNextBlock() { readNextBlock(); return this; } auto readNextBlock() { const(Token)[] blockTokens = []; bool readingBlock; int paranthesisCount; while (index < tokens.length) { auto type = str(tokens[index].type); if (type == "{") { paranthesisCount++; readingBlock = true; } if (type == "}") { paranthesisCount--; } blockTokens ~= tokens[index]; index++; if (readingBlock && paranthesisCount == 0) { break; } } return blockTokens; } ref auto skipUntilType(string type) { while (index < tokens.length) { if (str(tokens[index].type) == type) { break; } index++; } return this; } ref auto skipOne() { index++; return this; } string readUntilType(string type) { string result; while (index < tokens.length) { if (str(tokens[index].type) == type) { break; } result ~= tokens[index].text == "" ? str(tokens[index].type) : tokens[index].text; index++; } return result; } DLangClass readClass() { const(Token)[] classTokens = []; bool readingClass; int paranthesisCount; while (index < tokens.length) { auto type = str(tokens[index].type); if (type == "{") { paranthesisCount++; readingClass = true; } if (type == "}") { paranthesisCount--; } classTokens ~= tokens[index]; index++; if (readingClass && paranthesisCount == 0) { break; } } return DLangClass(classTokens); } DLangAttribute readAttribute() { const(Token)[] attributeTokens = []; int paranthesisCount; bool readingParams; bool foundWs; while (index < tokens.length) { auto type = str(tokens[index].type); if (type == "whitespace" && paranthesisCount == 0 && !readingParams) { foundWs = true; } if (foundWs && type == ".") { foundWs = false; } if (foundWs && type != "(") { break; } if (type == "(") { paranthesisCount++; readingParams = true; foundWs = false; } if (type == ")") { paranthesisCount--; } attributeTokens ~= tokens[index]; if (readingParams && paranthesisCount == 0) { break; } index++; } return DLangAttribute(attributeTokens); } } } string camelToSentence(const string name) pure { string sentence; foreach (ch; name) { if (ch.toUpper == ch) { sentence ~= " " ~ ch.toLower.to!string; } else { sentence ~= ch; } } return sentence.capitalize; }
module trial.discovery.code; import std.algorithm; import std.string; import std.range; import std.file; import std.stdio; import std.conv; version(Have_libdparse) { public import dparse.ast; public import dparse.lexer; public import dparse.parser; } string getModuleName(string fileName) { if (!exists(fileName)) { return ""; } if (isDir(fileName)) { return ""; } auto file = File(fileName); auto moduleLine = file.byLine().map!(a => a.to!string).filter!(a => a.startsWith("module")); if (moduleLine.empty) { return ""; } return moduleLine.front.split(' ')[1].split(";")[0]; } version(Have_libdparse) { const(Token)[] stringToDTokens(string data) { try { ubyte[] fileBytes = cast(ubyte[]) data; StringCache cache = StringCache(StringCache.defaultBucketCount); LexerConfig config; config.stringBehavior = StringBehavior.source; config.fileName = ""; config.commentBehavior = CommentBehavior.intern; auto lexer = DLexer(fileBytes, config, &cache); const(Token)[] tokens = lexer.array; return tokens.map!(token => const Token(token.type, token.text.idup, token.line, token.column, token.index)).array; } catch(Throwable t) { t.writeln; return []; } } struct DLangAttribute { const(Token)[] tokens; inout { string identifier() { string result; foreach (token; tokens) { if (str(token.type) == "(") { break; } result ~= token.text; } return result; } string value() { bool after; string result; foreach (token; tokens) { if (after) { result ~= token.text.strip('"').strip('`').strip('\''); } if (str(token.type) == "(") { after = true; } } return result; } auto line() { return tokens[0].line; } } } struct DLangFunction { const(DLangAttribute)[] attributes; const(Token)[] tokens; string name() { auto result = TokenIterator(tokens).readUntilType("(").replace("\n", " ") .replace("\r", " ").replace("\t", " ").split(" "); std.algorithm.reverse(result); return result[0]; } bool hasAttribute(string name) { return !attributes.filter!(a => a.identifier == name).empty; } auto getAttribute(string name) { return attributes.filter!(a => a.identifier == name).front; } string testName() { foreach (attribute; attributes) { if (attribute.identifier == "") { return attribute.value; } } return name.camelToSentence; } size_t line() { return TokenIterator(tokens).skipUntilType("(").currentToken.line; } } struct DLangClass { const(Token)[] tokens; string name() { auto iterator = TokenIterator(tokens); auto name = iterator.readUntilType("{"); import std.stdio; if (name.indexOf(":") != -1) { name = name.split(":")[0]; } return name.strip; } DLangFunction[] functions() { int paranthesisCount; auto iterator = TokenIterator(tokens); iterator.skipUntilType("{"); const(Token)[] currentTokens; DLangFunction[] discoveredFunctions; DLangAttribute[] attributes; bool readingFunction; int functionLevel = 1; foreach (token; iterator) { string type = token.type.str; currentTokens ~= token; if (type == "@") { attributes ~= iterator.readAttribute; } if (type == "{") { paranthesisCount++; } if (type == "}") { paranthesisCount--; if (paranthesisCount == functionLevel) { discoveredFunctions ~= DLangFunction(attributes, currentTokens); } } readingFunction = paranthesisCount > functionLevel; if (type == "}" || (!readingFunction && type == ";")) { currentTokens = []; attributes = []; } } return discoveredFunctions; } } struct TokenIterator { private { const(Token)[] tokens; size_t index; } int opApply(int delegate(const(Token)) dg) { int result = 0; while (index < tokens.length) { result = dg(tokens[index]); index++; if (result) { break; } } return result; } ref auto skipWsAndComments() { while (index < tokens.length) { auto type = str(tokens[index].type); if (type != "comment" && type != "whitespace") { break; } index++; } return this; } auto currentToken() { return tokens[index]; } ref auto skipUntil(string text) { while (index < tokens.length) { if (tokens[index].text == text) { break; } index++; } return this; } ref auto skipNextBlock() { readNextBlock(); return this; } auto readNextBlock() { const(Token)[] blockTokens = []; bool readingBlock; int paranthesisCount; while (index < tokens.length) { auto type = str(tokens[index].type); if (type == "{") { paranthesisCount++; readingBlock = true; } if (type == "}") { paranthesisCount--; } blockTokens ~= tokens[index]; index++; if (readingBlock && paranthesisCount == 0) { break; } } return blockTokens; } ref auto skipUntilType(string type) { while (index < tokens.length) { if (str(tokens[index].type) == type) { break; } index++; } return this; } ref auto skipOne() { index++; return this; } string readUntilType(string type) { string result; while (index < tokens.length) { if (str(tokens[index].type) == type) { break; } result ~= tokens[index].text == "" ? str(tokens[index].type) : tokens[index].text; index++; } return result; } DLangClass readClass() { const(Token)[] classTokens = []; bool readingClass; int paranthesisCount; while (index < tokens.length) { auto type = str(tokens[index].type); if (type == "{") { paranthesisCount++; readingClass = true; } if (type == "}") { paranthesisCount--; } classTokens ~= tokens[index]; index++; if (readingClass && paranthesisCount == 0) { break; } } return DLangClass(classTokens); } DLangAttribute readAttribute() { const(Token)[] attributeTokens = []; int paranthesisCount; bool readingParams; bool foundWs; while (index < tokens.length) { auto type = str(tokens[index].type); if (type == "whitespace" && paranthesisCount == 0 && !readingParams) { foundWs = true; } if (foundWs && type == ".") { foundWs = false; } if (foundWs && type != "(") { break; } if (type == "(") { paranthesisCount++; readingParams = true; foundWs = false; } if (type == ")") { paranthesisCount--; } attributeTokens ~= tokens[index]; if (readingParams && paranthesisCount == 0) { break; } index++; } return DLangAttribute(attributeTokens); } } } string camelToSentence(const string name) pure { string sentence; foreach (ch; name) { if (ch.toUpper == ch) { sentence ~= " " ~ ch.toLower.to!string; } else { sentence ~= ch; } } return sentence.capitalize; }