| /* |
| * 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 |