blob: 870549562104a40b87ef73956729cb47736d5b18 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "../base_types.hpp"
#include "CPPCodeGenerator.hpp"
#include "Log.hpp"
#include "Helper.hpp"
#include <iostream>
namespace apache {
namespace geode {
namespace client {
namespace pdx_auto_serializer {
int CPPCodeGenerator::s_classId = -1;
std::string CPPCodeGenerator::s_GFSerializerNamespace =
"apache::geode::client::PdxAutoSerializable";
std::string CPPCodeGenerator::s_TempVarPrefix = "var_";
/** The option name for classId. */
std::string CPPCodeGenerator::s_ClassIdOption = "classId";
/** The option name for the output directory. */
std::string CPPCodeGenerator::s_OutDirOption = "outDir";
/**
* The directory to be used in generated files for the included headers.
* If not provided the path of the header file as provided on
* command-line is used.
*/
std::string CPPCodeGenerator::s_HeaderDirOption = "headerDir";
/**
* The option name for the suffix to use for generated files and classes.
*/
std::string CPPCodeGenerator::s_GenSuffixOption = "suffix";
// CodeGenerator method implementations
void CPPCodeGenerator::getOptions(OptionMap& options) const {
std::pair<bool, std::string> optionPair;
// optionPair.first = true;
// optionPair.second
// = "\tThe base classId to be used for the serializers [>= 0, < 2^31] "
// "(SINGLE,OPTIONAL)";
// options[s_ClassIdOption] = optionPair;
optionPair.second =
"\tThe output directory of the generated files "
"(SINGLE,OPTIONAL)";
options[s_OutDirOption] = optionPair;
optionPair.second =
"\tThe suffix of the generated filenames "
"-- default is '" +
defaultGenSuffix() + "' (SINGLE,OPTIONAL)";
options[s_GenSuffixOption] = optionPair;
// optionPair.second = "\tThe directory to be used in generated files for "
// "the included headers.\n\t\t\tIf not provided the "
// "path of the header file as provided on the "
// "command-line is used (SINGLE,OPTIONAL)";
// options[s_HeaderDirOption] = optionPair;
}
void CPPCodeGenerator::init(PropertyMap& properties) {
Helper::getSingleProperty(properties, s_OutDirOption, m_outDir);
m_outDir += '/';
std::string classIdStr;
bool classIdFound =
Helper::getSingleProperty(properties, s_ClassIdOption, classIdStr);
if (!classIdFound) {
// Log::warn(m_moduleName, "No classId given or found for the "
// "class; will not generate the classId method.");
} else {
try {
Helper::lexical_cast(classIdStr, s_classId);
} catch (const std::invalid_argument&) {
Log::fatal(m_moduleName, "classId not a valid integer");
}
if (s_classId < 0) {
Log::fatal(m_moduleName, "classId should be >= 0.");
}
}
Helper::getSingleProperty(properties, s_GenSuffixOption, m_genSuffix);
if (m_genSuffix.length() == 0) {
m_genSuffix = defaultGenSuffix();
}
if (Helper::getSingleProperty(properties, s_HeaderDirOption, m_headerDir) &&
(m_headerDir.length() > 0)) {
char lastChar = m_headerDir[m_headerDir.length() - 1];
if (lastChar != '/' && lastChar != '\\') {
m_headerDir += '/';
}
}
}
void CPPCodeGenerator::initClass(const TypeInfo& classInfo) {
std::string namespacePrefixString = "";
StringVector nameSpaceList = classInfo.m_namespaces;
for (StringVector::iterator iter = nameSpaceList.begin();
iter != nameSpaceList.end(); ++iter) {
namespacePrefixString += *iter;
}
std::string outFile = "";
if (namespacePrefixString == "") {
outFile = m_outDir + classInfo.m_nameOrSize + m_genSuffix + ".cpp";
} else {
outFile = m_outDir + namespacePrefixString + "_" + classInfo.m_nameOrSize +
m_genSuffix + ".cpp";
}
Log::info(m_moduleName, "Writing: " + outFile);
m_cppFormatter->open(outFile);
m_classInfo = classInfo;
}
void CPPCodeGenerator::addFileHeader(int argc, char** argv) {
*m_cppFormatter
<< "// This is auto generated file using \"pdxautoserializer\""
<< "\n";
*m_cppFormatter
<< "// Do not edit this file, unless you are sure what you are doing "
<< "\n";
*m_cppFormatter << "// Options used to generate this files are : "
<< "\n";
for (int i = 1; i < argc; i++) {
*m_cppFormatter << "//\t" << argv[i] << "\n";
}
*m_cppFormatter << "\n";
}
void CPPCodeGenerator::addReferences(const ReferenceVector& references) {
for (ReferenceVectorIterator referenceIterator = references.begin();
referenceIterator != references.end(); ++referenceIterator) {
if (referenceIterator->m_kind == Reference::HEADER) {
std::string headerPath;
std::string::size_type lastSlash =
referenceIterator->m_path.find_last_of("/\\");
if (lastSlash != std::string::npos) {
headerPath =
m_headerDir + referenceIterator->m_path.substr(lastSlash + 1);
} else {
headerPath = m_headerDir + referenceIterator->m_path;
}
*m_cppFormatter << "#include \"" << headerPath << "\"\n\n";
}
}
*m_cppFormatter << "#include <geode/PdxWriter.hpp>"
<< "\n";
*m_cppFormatter << "#include <geode/PdxReader.hpp>"
<< "\n";
*m_cppFormatter << "#include <geode/PdxAutoSerializer.hpp>"
<< "\n\n";
}
void CPPCodeGenerator::startClass(const VariableVector& members) {
genNamespaceHeader(m_classInfo.m_namespaces, m_cppFormatter);
}
// Ticket #905 Changes starts here
void CPPCodeGenerator::addTryBlockStart(const Method::Type type) {
switch (type) {
case Method::TODATA: {
*m_cppFormatter << "try\n";
*m_cppFormatter << "{\n";
break;
}
case Method::FROMDATA: {
*m_cppFormatter << "try\n";
*m_cppFormatter << "{\n";
break;
}
default: { break; }
}
return;
}
void CPPCodeGenerator::finishTryBlock(const Method::Type type) {
switch (type) {
case Method::TODATA: {
*m_cppFormatter << "}\n";
*m_cppFormatter
<< "catch(apache::geode::client::IllegalStateException exception)\n";
*m_cppFormatter << "{\n";
*m_cppFormatter << "}\n";
break;
}
case Method::FROMDATA: {
*m_cppFormatter << "}\n";
*m_cppFormatter
<< "catch(apache::geode::client::IllegalStateException exception)\n";
*m_cppFormatter << "{\n";
*m_cppFormatter << "}\n";
break;
}
default: { break; }
}
return;
}
// Ticket #905 Changes ends here
void CPPCodeGenerator::startMethod(const Method::Type type,
const std::string& varName,
const std::string& methodPrefix) {
std::string var;
StringVector varVec;
std::string className = getTypeString(m_classInfo);
switch (type) {
case Method::TODATA: {
varVec.push_back(
"std::shared_ptr<apache::geode::client::PdxWriter> __var");
genFunctionHeader("toData", className, "void", varVec, true, false,
m_cppFormatter, methodPrefix);
break;
}
case Method::FROMDATA: {
varVec.push_back(
"std::shared_ptr<apache::geode::client::PdxReader> __var ");
genFunctionHeader("fromData", className, "void", varVec, true, false,
m_cppFormatter, methodPrefix);
break;
}
default: { throw std::invalid_argument("unexpected execution"); }
}
}
void CPPCodeGenerator::genMethod(const Method::Type type,
const std::string& varName,
const VariableInfo& var) {
switch (type) {
case Method::TODATA: {
if (var.m_markPdxUnreadField == true) {
*m_cppFormatter << varName << "->writeUnreadFields(" << var.m_name;
} else {
*m_cppFormatter << s_GFSerializerNamespace << "::writePdxObject("
<< varName << ", "
<< "\"" << var.m_name << "\""
<< ", " << var.m_name;
if (var.m_type.m_kind & TypeKind::ARRAY) {
*m_cppFormatter << ", " << var.m_type.m_nameOrSize;
if (var.m_type.m_nameOfArrayElemSize.size() > 0) {
*m_cppFormatter << ", " << var.m_type.m_nameOfArrayElemSize;
}
}
}
*m_cppFormatter << ");\n";
if (var.m_markIdentityField == true) {
*m_cppFormatter << varName << "->markIdentityField("
<< "\"" << var.m_name << "\""
<< ");"
<< "\n"
<< "\n";
}
break;
}
case Method::FROMDATA: {
if (var.m_markPdxUnreadField == true) {
*m_cppFormatter << var.m_name << " = " << varName
<< "->readUnreadFields(";
} else {
*m_cppFormatter << s_GFSerializerNamespace << "::readPdxObject("
<< varName << ", "
<< "\"" << var.m_name << "\""
<< ", " << var.m_name;
if (var.m_type.m_kind & TypeKind::ARRAY) {
*m_cppFormatter << ", " << var.m_type.m_nameOrSize;
if (var.m_type.m_nameOfArrayElemSize.size() > 0) {
*m_cppFormatter << ", " << var.m_type.m_nameOfArrayElemSize;
}
}
}
*m_cppFormatter << ");\n";
break;
}
default: { throw std::invalid_argument("unexpected execution"); }
}
}
void CPPCodeGenerator::endMethod(const Method::Type type,
const std::string& varName) {
switch (type) {
case Method::TODATA: {
genFunctionFooter(m_cppFormatter);
break;
}
case Method::FROMDATA: {
//*m_cppFormatter << "return this;\n";
genFunctionFooter(m_cppFormatter);
break;
}
default: { throw std::invalid_argument("unexpected execution"); }
}
}
void CPPCodeGenerator::genTypeId(const std::string& methodPrefix) {
if (s_classId >= 0) {
StringVector varVec;
std::string className = getTypeString(m_classInfo);
genFunctionHeader("classId", className, "int32_t", varVec, true, true,
m_cppFormatter, methodPrefix);
*m_cppFormatter << "return " << s_classId << ";\n";
genFunctionFooter(m_cppFormatter);
++s_classId;
}
}
void CPPCodeGenerator::genClassNameMethod(
std::map<std::string, std::string>& classNameStringMap,
const std::string& methodPrefix) {
StringVector varVec;
std::string className = getTypeString(m_classInfo);
std::map<std::string, std::string>::iterator found =
classNameStringMap.find(className);
genFunctionHeader("getClassName", className, "const char*", varVec, true,
true, m_cppFormatter, methodPrefix);
if (found != classNameStringMap.end()) {
*m_cppFormatter << "return "
<< "\"" << found->second << "\""
<< ";\n";
} else {
*m_cppFormatter << "return "
<< "\"";
for (StringVector::const_iterator itr = m_classInfo.m_namespaces.begin();
itr != m_classInfo.m_namespaces.end(); ++itr) {
*m_cppFormatter << *itr << ".";
}
*m_cppFormatter << className << "\""
<< ";\n";
}
genFunctionFooter(m_cppFormatter);
}
void CPPCodeGenerator::genCreateDeserializable(
const std::string& methodPrefix) {
StringVector varVec;
std::string className = getTypeString(m_classInfo);
genFunctionHeader("createDeserializable", className,
"apache::geode::client::PdxSerializable*", varVec, true,
false, m_cppFormatter, methodPrefix);
*m_cppFormatter << "return new " << className << "()"
<< ";\n";
genFunctionFooter(m_cppFormatter);
}
void CPPCodeGenerator::endClass() {
genNamespaceFooter(m_classInfo.m_namespaces, m_cppFormatter);
m_cppFormatter->close();
}
void CPPCodeGenerator::cleanup() {
std::string fileName;
if (m_cppFormatter != NULL) {
fileName = m_cppFormatter->getFileName();
m_cppFormatter->close();
if (fileName.length() > 0) {
remove(fileName.c_str());
}
}
}
// End CodeGenerator methods
std::string CPPCodeGenerator::defaultGenSuffix() const {
return "Serializable";
}
std::string CPPCodeGenerator::getNamespacePrefix(
const StringVector& namespaces) const {
std::string namespacePrefix;
for (StringVectorIterator namespaceIterator = namespaces.begin();
namespaceIterator != namespaces.end(); ++namespaceIterator) {
namespacePrefix += *namespaceIterator + "::";
}
return namespacePrefix;
}
std::string CPPCodeGenerator::getTypeString(const TypeInfo& type,
bool prependNS,
std::string* postVarStr,
StringSet* templateArgs) const {
std::string typeString;
if (type.m_kind & TypeKind::VALUE) {
if (prependNS) {
typeString += getNamespacePrefix(type.m_namespaces);
}
typeString += type.m_nameOrSize;
} else if (type.m_kind & TypeKind::TEMPLATEPARAM) {
typeString += type.m_nameOrSize;
if (templateArgs != NULL) {
templateArgs->insert(type.m_nameOrSize);
}
} else if (type.m_kind & TypeKind::POINTER) {
assert(type.m_numChildren == 1);
assert(type.m_children != NULL);
typeString +=
getTypeString(*(type.m_children), prependNS, postVarStr, templateArgs);
if (postVarStr == NULL || postVarStr->length() == 0) {
typeString += '*';
} else {
typeString += "(*";
postVarStr->insert(0, ")");
}
} else if (type.m_kind & TypeKind::REFERENCE) {
assert(type.m_numChildren == 1);
assert(type.m_children != NULL);
typeString +=
getTypeString(*(type.m_children), prependNS, postVarStr, templateArgs);
if (postVarStr == NULL || postVarStr->length() == 0) {
typeString += '&';
} else {
typeString += "(&";
postVarStr->insert(0, ")");
}
} else if (type.m_kind & TypeKind::TEMPLATE) {
if (prependNS) {
typeString += getNamespacePrefix(type.m_namespaces);
}
typeString += type.m_nameOrSize + "< ";
if (type.m_numChildren > 0) {
typeString +=
getTypeString(*type.m_children, prependNS, postVarStr, templateArgs);
for (int childIndex = 1; childIndex < type.m_numChildren; ++childIndex) {
typeString += ", ";
typeString += getTypeString(type.m_children[childIndex], prependNS,
postVarStr, templateArgs);
}
}
typeString += " >";
} else if (type.m_kind & TypeKind::ARRAY) {
assert(type.m_numChildren == 1);
assert(type.m_children != NULL);
typeString +=
getTypeString(*(type.m_children), prependNS, postVarStr, templateArgs);
if (postVarStr == NULL) {
typeString += '*';
} else {
postVarStr->append("[]");
}
} else if (type.m_kind & TypeKind::FIXEDARRAY) {
assert(type.m_numChildren == 1);
assert(type.m_children != NULL);
typeString +=
getTypeString(*(type.m_children), prependNS, postVarStr, templateArgs);
if (postVarStr == NULL) {
typeString += '*';
} else {
postVarStr->append("[" + type.m_nameOrSize + "]");
}
}
return typeString;
}
void CPPCodeGenerator::genNamespaceHeader(const StringVector& namespaces,
OutputFormatter* formatter) {
for (StringVectorIterator namespaceIterator = namespaces.begin();
namespaceIterator != namespaces.end(); ++namespaceIterator) {
*formatter << "namespace " << *namespaceIterator << "\n{\n";
}
*formatter << '\n';
}
void CPPCodeGenerator::genFunctionHeader(const std::string& functionName,
const std::string& className,
const std::string& returnType,
const StringVector& arguments,
bool isDefinition, bool isConst,
OutputFormatter* formatter,
const std::string& methodPrefix) {
*formatter << returnType << ' ';
if (isDefinition) {
if (methodPrefix != "") {
*formatter << methodPrefix << className << "::";
} else {
*formatter << className << "::";
}
}
*formatter << functionName << "(";
if (arguments.size() > 0) {
StringVectorIterator argumentIterator = arguments.begin();
*formatter << *argumentIterator;
while (++argumentIterator != arguments.end()) {
*formatter << ", " << *argumentIterator;
}
}
*formatter << ")";
if (isConst) {
*formatter << " const";
}
*formatter << "\n{\n";
}
void CPPCodeGenerator::genFunctionFooter(OutputFormatter* formatter) {
*formatter << "}\n\n";
}
void CPPCodeGenerator::genNamespaceFooter(const StringVector& namespaces,
OutputFormatter* formatter) {
for (StringVector::size_type i = 0; i < namespaces.size(); ++i) {
*formatter << "}\n";
}
}
CodeGenerator* CPPCodeGenerator::create() { return new CPPCodeGenerator(); }
CPPCodeGenerator::CPPCodeGenerator()
: m_cppFormatter(new OutputFormatter()),
m_outDir("."),
m_moduleName("CPPCodeGenerator") {}
CPPCodeGenerator::~CPPCodeGenerator() {
if (m_cppFormatter != NULL) {
m_cppFormatter->close();
delete m_cppFormatter;
m_cppFormatter = NULL;
}
}
} // namespace pdx_auto_serializer
} // namespace client
} // namespace geode
} // namespace apache