Last active
August 29, 2015 14:19
-
-
Save ashishnegi/193825a627a7472cd34d to your computer and use it in GitHub Desktop.
Gets the function name and arguments : (problem with default values in function signature)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <sstream> | |
#include <vector> | |
#include <algorithm> | |
#include <cctype> | |
#include <map> | |
namespace patch | |
{ | |
template < typename T > std::string to_string( const T& n ) | |
{ | |
std::ostringstream stm ; | |
stm << n ; | |
return stm.str() ; | |
} | |
} | |
auto funcSpace = [](unsigned char const c) { return std::isspace(c); }; | |
std::string trim (std::string str) { | |
std::size_t i = 0; | |
while (i < str.length()) { | |
if (!std::isspace(str[i])) | |
break; | |
++i; | |
} | |
str = str.erase(0, i); | |
i = str.length() - 1; | |
while (i >= 0) { | |
if (!std::isspace(str[i])) | |
break; | |
--i; | |
} | |
str = str.erase(i+1); | |
return str; | |
} | |
bool makeValidLine(std::string & line) { | |
using namespace std; | |
line = trim(line); | |
size_t firstNonDelimCharPos = 0; | |
const size_t lineLen = line.size(); | |
while (firstNonDelimCharPos < lineLen) { | |
const char & ch = line[firstNonDelimCharPos]; | |
if ((ch >= 'a' && ch <= 'z') || | |
(ch >= 'A' && ch <= 'Z')) | |
break; | |
firstNonDelimCharPos += 1; | |
} | |
if (firstNonDelimCharPos == lineLen) | |
return false; | |
line = line.substr(firstNonDelimCharPos); // line changes. | |
// auto pos = line.find_last_of(";"); | |
// if (pos == std::string::npos) | |
// return false; | |
// line = line.substr(0, pos); | |
static const string virtualWord = "virtual"; | |
if ((virtualWord == (line.substr(0, virtualWord.size()))) && | |
line.length() > virtualWord.size() && | |
(std::isspace(line[virtualWord.size()]))) | |
return true; | |
return false; | |
} | |
int main () { | |
std::string line; | |
std::map<std::string, std::size_t> allFunctions; | |
while (std::getline(std::cin, line, '\n')) { | |
if (!makeValidLine(line)) | |
continue; | |
// keep appending to line untill you get a terminator ; | |
while (std::string::npos == line.find_last_of(";")) { | |
std::string nextLine; | |
std::getline(std::cin, nextLine, '\n'); | |
line += nextLine; | |
} | |
const std::string originalLine(line); | |
{ | |
// ok .. this line "now" starts with word `virtual `. | |
// it is highly unlikely that we would have word virtual in the start of c++ code. | |
// unless it is a comment. <- would handle later. | |
} | |
auto pos = line.find_first_of("(", 0); | |
if (std::string::npos == pos) { | |
std::cerr << "0: Unable to generate mock for line : " + line << std::endl; | |
continue; | |
} | |
// word before '(' would be function-name. | |
// virtual return-type function-name ( | |
std::string functionName; | |
std::size_t functionStartIndex = 0; | |
{ | |
std::size_t index = pos ; | |
index -= 1; // start in reverse order from '('. | |
while (index > 0) { // remove all delimiters. | |
if (!std::isspace(line[index])) | |
break; | |
index -= 1; | |
} | |
// find the word. | |
const std::size_t functionEnd = index; | |
index -= 1; // find next space. | |
while (index > 0) { | |
if (!std::isalpha(line[index])) | |
break; | |
index -= 1; | |
} | |
const std::size_t functionStart = index+1; | |
functionName = trim(line.substr(functionStart, functionEnd - functionStart + 1)); | |
{ | |
int iteration = 1; | |
const std::string originalFunctionName(functionName); | |
while (allFunctions.find(functionName) != allFunctions.end() && (iteration < 10)) | |
functionName = originalFunctionName + patch::to_string((long)iteration++); | |
if (iteration == 10) | |
continue; | |
allFunctions[functionName] += 1; | |
} | |
functionStartIndex = functionStart; | |
} | |
if (0 == functionName.size()) { | |
std::cerr << "1. Unable to generate mock for line : " + line << std::endl; | |
continue; | |
} | |
// return type is after word `virtual` --return-type-- function-start-index. | |
const std::size_t virtualLen = std::string("virtual ").length(); | |
const std::string returnType = trim(line.substr(virtualLen, functionStartIndex - virtualLen)); | |
// Get the arguments to the function. | |
// (Type var-name, Typ var-name) | |
// Type can have spaces.. std::vector < int > | |
// but var-name can not. | |
const auto closingBracePos = line.find_first_of(")"); | |
if (std::string::npos == closingBracePos) { | |
std::cerr << "2: Unable to generate mock for line : " + line << std::endl; | |
continue; | |
} | |
const std::size_t startBracePos = line.find_first_of("("); | |
if (std::string::npos == startBracePos || (startBracePos >= closingBracePos)){ | |
std::cerr << "3: Unable to generate mock for line : " + line << std::endl; | |
continue; | |
} | |
const std::string arguments = line.substr(startBracePos, | |
closingBracePos - startBracePos + 1); | |
// pair of {type, name} | |
std::vector< std::pair<std::string, std::string> > argumentPairs; | |
{ | |
std::size_t prev = 0, pos; | |
std::vector<std::string> pairOfTypeVarnameVector; | |
while ((pos = arguments.find_first_of("(,)", prev)) != std::string::npos) | |
{ | |
if (pos > prev) | |
pairOfTypeVarnameVector.push_back(trim(arguments.substr(prev, pos-prev))); | |
prev = pos+1; | |
} | |
if (prev < arguments.length()) | |
pairOfTypeVarnameVector.push_back(trim(line.substr(prev, std::string::npos))); | |
// each entry in pairOfTypeVarnameVector has last word as var-name or no var-name. | |
// if there are 1 word : it is type. | |
// if there are > 1 word , we treat last word as var-name. | |
std::for_each(pairOfTypeVarnameVector.begin(), | |
pairOfTypeVarnameVector.end(), | |
[&argumentPairs](const std::string & typeVarName) { | |
if (0 == typeVarName.size()) | |
return; | |
auto pos = typeVarName.find_last_of(" \t*&"); | |
if (pos == std::string::npos) { | |
{ | |
int i =0; | |
while (i < typeVarName.size()) { | |
if (std::isspace(typeVarName[i])) { | |
i++; continue; | |
} else break; | |
} | |
if (i == typeVarName.size()) | |
return; | |
} | |
argumentPairs.push_back(std::make_pair(trim(typeVarName), "a")); | |
return; | |
} else { | |
const std::size_t indexPos = pos; | |
argumentPairs.push_back(std::make_pair(trim(typeVarName.substr(0, indexPos+1)), | |
trim(typeVarName.substr(indexPos+1)))); | |
} | |
}); | |
} | |
const bool constWord = line.find("const", closingBracePos) != std::string::npos; | |
std::string functionArguments; | |
for(auto it = argumentPairs.begin(), lastIt = --argumentPairs.end(); it != argumentPairs.end(); ++it) { | |
functionArguments += it->second ; | |
if (it != lastIt) | |
functionArguments += " , "; | |
} | |
// so now we have everything .. | |
std::cout << "std::function< " << returnType << arguments << " >" << " mMock" << functionName << " ;\n" | |
// i can not put the original here because original may not have variable-names and then i would suck. | |
<< "virtual " << returnType << " " << functionName << " (" ; | |
for(auto it = argumentPairs.begin(), lastIt = --argumentPairs.end(); it != argumentPairs.end(); ++it) { | |
std::cout << it->first << " " << it->second; | |
if (it != lastIt) | |
std::cout << ", "; | |
} | |
std::cout << ") " | |
<< (constWord ? "const" : "") | |
<< " override {\n" | |
<< " if (!mMock" << functionName << ")\n" | |
<< " return BaseClassName::" << functionName << "(" << functionArguments << ");\n" | |
<< " return mMock" << functionName << "(" << functionArguments << ");\n" | |
<< "}\n"; | |
// std::cout << "function:" << functionName << "\nreturn:" << returnType << "\n"; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment