diff --git a/src/private/protocolgen/cppgenerator.cpp b/src/private/protocolgen/cppgenerator.cpp index 769da4ef0..8ee2a3b55 100644 --- a/src/private/protocolgen/cppgenerator.cpp +++ b/src/private/protocolgen/cppgenerator.cpp @@ -1,641 +1,649 @@ /* Copyright (c) 2017 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cppgenerator.h" #include "nodetree.h" #include "typehelper.h" #include "cpphelper.h" #include #include CppGenerator::CppGenerator() { } CppGenerator::~CppGenerator() { } bool CppGenerator::generate(Node const *node) { Q_ASSERT(node->type() == Node::Document); mHeaderFile.setFileName(QStringLiteral("protocol_gen.h")); if (!mHeaderFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { std::cerr << qPrintable(mHeaderFile.errorString()) << std::endl; return false; } mHeader.setDevice(&mHeaderFile); mImplFile.setFileName(QStringLiteral("protocol_gen.cpp")); if (!mImplFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { std::cerr << qPrintable(mImplFile.errorString()) << std::endl; return false; } mImpl.setDevice(&mImplFile); return generateDocument(static_cast(node)); } void CppGenerator::writeHeaderHeader(DocumentNode const *node) { mHeader << "// This is an auto-generated file.\n" "// Any changes to this file will be overwritten\n" "\n" "namespace Akonadi {\n" "namespace Protocol {\n" "\n" "AKONADIPRIVATE_EXPORT int version();\n" "\n"; // Forward declarations for (auto child : qAsConst(node->children())) { if (child->type() == Node::Class) { mHeader << "class " << static_cast(child)->className() << ";\n"; } } mHeader << "\n" "} // namespace Protocol\n" "} // namespace Akonadi\n\n"; } void CppGenerator::writeHeaderFooter(DocumentNode const * /*node*/) { // Nothing to do } void CppGenerator::writeImplHeader(DocumentNode const *node) { mImpl << "// This is an auto-generated file.\n" "// Any changs to this file will be overwritten\n" "\n" "namespace Akonadi {\n" "namespace Protocol {\n" "\n" "int version()\n" "{\n" " return " << node->version() << ";\n" "}\n" "\n"; } void CppGenerator::writeImplFooter(DocumentNode const *) { mImpl << "} // namespace Protocol\n" "} // namespace Akonadi\n"; } bool CppGenerator::generateDocument(DocumentNode const *node) { writeHeaderHeader(node); writeImplHeader(node); writeImplSerializer(node); for (auto classNode : node->children()) { if (!generateClass(static_cast(classNode))) { return false; } } writeHeaderFooter(node); writeImplFooter(node); return true; } void CppGenerator::writeImplSerializer(DocumentNode const *node) { mImpl << "void serialize(QIODevice *device, const CommandPtr &cmd)\n" "{\n" " DataStream stream(device);\n" " switch (static_cast(cmd->type() | (cmd->isResponse() ? Command::_ResponseBit : 0))) {\n" " case Command::Invalid:\n" " stream << cmdCast(cmd);\n" " break;\n" " case Command::Invalid | Command::_ResponseBit:\n" " stream << cmdCast(cmd);\n" " break;\n"; for (auto child : qAsConst(node->children())) { auto classNode = static_cast(child); if (classNode->classType() == ClassNode::Response) { mImpl << " case Command::" << classNode->name() << " | Command::_ResponseBit:\n" " stream << cmdCast<" << classNode->className() << ">(cmd);\n" " break;\n"; } else if (classNode->classType() == ClassNode::Command) { mImpl << " case Command::" << classNode->name() << ":\n" " stream << cmdCast<" << classNode->className() << ">(cmd);\n" " break;\n"; } else if (classNode->classType() == ClassNode::Notification) { mImpl << " case Command::" << classNode->name() << "Notification:\n" " stream << cmdCast<" << classNode->className() << ">(cmd);\n" " break;\n"; } } mImpl << " }\n" "}\n\n"; mImpl << "CommandPtr deserialize(QIODevice *device)\n" "{\n" " DataStream stream(device);\n" " stream.waitForData(sizeof(Command::Type));\n" " Command::Type cmdType;\n" " if (Q_UNLIKELY(device->peek((char *) &cmdType, sizeof(Command::Type)) != sizeof(Command::Type))) {\n" " throw ProtocolException(\"Failed to peek command type\");\n" " }\n" " CommandPtr cmd;\n" " if (cmdType & Command::_ResponseBit) {\n" " cmd = Factory::response(Command::Type(cmdType & ~Command::_ResponseBit));\n" " } else {\n" " cmd = Factory::command(cmdType);\n" " }\n\n" " switch (static_cast(cmdType)) {\n" " case Command::Invalid:\n" " stream >> cmdCast(cmd);\n" " return cmd;\n" " case Command::Invalid | Command::_ResponseBit:\n" " stream >> cmdCast(cmd);\n" " return cmd;\n"; for (auto child : qAsConst(node->children())) { auto classNode = static_cast(child); if (classNode->classType() == ClassNode::Response) { mImpl << " case Command::" << classNode->name() << " | Command::_ResponseBit:\n" " stream >> cmdCast<" << classNode->className() << ">(cmd);\n" " return cmd;\n"; } else if (classNode->classType() == ClassNode::Command) { mImpl << " case Command::" << classNode->name() << ":\n" " stream >> cmdCast<" << classNode->className() << ">(cmd);\n" " return cmd;\n"; } else if (classNode->classType() == ClassNode::Notification) { mImpl << " case Command::" << classNode->name() << "Notification:\n" " stream >> cmdCast<" << classNode->className() << ">(cmd);\n" " return cmd;\n"; } } mImpl << " }\n" " return CommandPtr::create();\n" "}\n" "\n"; mImpl << "QString debugString(const Command &cmd)\n" "{\n" " QString out;\n" " switch (static_cast(cmd.type() | (cmd.isResponse() ? Command::_ResponseBit : 0))) {\n" " case Command::Invalid:\n" " QDebug(&out).noquote() << static_cast(cmd);\n" " return out;\n" " case Command::Invalid | Command::_ResponseBit:\n" " QDebug(&out).noquote() << static_cast(cmd);\n" " return out;\n"; for (auto child : qAsConst(node->children())) { auto classNode = static_cast(child); if (classNode->classType() == ClassNode::Response) { mImpl << " case Command::" << classNode->name() << " | Command::_ResponseBit:\n" " QDebug(&out).noquote() << static_castclassName() << " &>(cmd);\n" " return out;\n"; } else if (classNode->classType() == ClassNode::Command) { mImpl << " case Command::" << classNode->name() << ":\n" " QDebug(&out).noquote() << static_castclassName() << " &>(cmd);\n" " return out;\n"; } else if (classNode->classType() == ClassNode::Notification) { mImpl << " case Command::" << classNode->name() << "Notification:\n" " QDebug(&out).noquote() << static_castclassName() << " &>(cmd);\n" " return out;\n"; } } mImpl << " }\n" " return QString();\n" "}\n" "\n"; } void CppGenerator::writeHeaderEnum(EnumNode const *node) { mHeader << " enum " << node->name() << " {\n"; for (auto enumChild : node->children()) { Q_ASSERT(enumChild->type() == Node::EnumValue); const auto valueNode = static_cast(enumChild); mHeader << " " << valueNode->name(); if (!valueNode->value().isEmpty()) { mHeader << " = " << valueNode->value(); } mHeader << ",\n"; } mHeader << " };\n"; if (node->enumType() == EnumNode::TypeFlag) { mHeader << " Q_DECLARE_FLAGS(" << node->name() << "s, " << node->name() << ")\n\n"; } } void CppGenerator::writeHeaderClass(ClassNode const *node) { // Begin class const QString parentClass = node->parentClassName(); const bool isTypeClass = node->classType() == ClassNode::Class; mHeader << "namespace Akonadi {\n" "namespace Protocol {\n\n" "AKONADIPRIVATE_EXPORT DataStream &operator<<(DataStream &stream, const " << node->className() << " &obj);\n" "AKONADIPRIVATE_EXPORT DataStream &operator>>(DataStream &stream, " << node->className() << " &obj);\n" "AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const " << node->className() << " &obj);\n" "\n" "using " << node->className() << "Ptr = QSharedPointer<" << node->className() << ">;\n" "\n"; if (isTypeClass) { mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << "\n"; } else { mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << " : public " << parentClass << "\n"; } mHeader << "{\n\n" "public:\n"; // Enums for (auto child : node->children()) { if (child->type() == Node::Enum) { const auto enumNode = static_cast(child); writeHeaderEnum(enumNode); } } // Ctors, dtor for (auto child : qAsConst(node->children())) { if (child->type() == Node::Ctor) { const auto ctor = static_cast(child); const auto args = ctor->arguments(); mHeader << " explicit " << node->className() << "("; for (int i = 0; i < args.count(); ++i) { const auto &arg = args[i]; if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) { mHeader << arg.type << " " << arg.name; } else { mHeader << "const " << arg.type << " &" << arg.name; } if (!arg.defaultValue.isEmpty()) { mHeader << " = " << arg.defaultValue; } if (i < args.count() - 1) { mHeader << ", "; } } mHeader << ");\n"; } } mHeader << " " << node->className() << "(const " << node->className() << " &other);\n" " ~" << node->className() << "();\n" "\n" " " << node->className() << " &operator=(const " << node->className() << " &other);\n" " bool operator==(const " << node->className() << " &other) const;\n" " inline bool operator!=(const " << node->className() << " &other) const { return !operator==(other); }\n"; // Properties for (auto child : node->children()) { if (child->type() == Node::Property) { const auto prop = static_cast(child); if (prop->asReference()) { mHeader << " inline const " << prop->type() << " &" << prop->name() << "() const { return " << prop->mVariableName() << "; }\n" " inline " << prop->type() << " &" << prop->name() << "() { return " << prop->mVariableName() << "; }\n"; } else { mHeader << " inline " << prop->type() << " " << prop->name() << "() const { return " << prop->mVariableName() << "; }\n"; } if (!prop->readOnly()) { if (auto setter = prop->setter()) { mHeader << " void " << setter->name << "(const " << setter->type << " &" << prop->name() << ");\n"; } else if (!prop->dependencies().isEmpty()) { QString varType; if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) { varType = QLatin1String("(") + prop->type() + QLatin1String(" "); } else { varType = QLatin1String("(const ") + prop->type() + QLatin1String(" &"); } mHeader << " void " << prop->setterName() << varType << prop->name() << ");\n"; } else { QString varType; if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) { varType = QLatin1String("(") + prop->type() + QLatin1String(" "); } else { varType = QLatin1String("(const ") + prop->type() + QLatin1String(" &"); } mHeader << " inline void " << prop->setterName() << varType << prop->name() << ") { " << prop->mVariableName() << " = " << prop->name() << "; }\n"; } } mHeader << "\n"; } } // End of class mHeader << "protected:\n"; const auto properties = node->properties(); for (auto prop : properties) { mHeader << " " << prop->type() << " " << prop->mVariableName() << ";\n"; } mHeader << "\n" "private:\n" " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, const Akonadi::Protocol::" << node->className() << " &obj);\n" " friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, Akonadi::Protocol::" << node->className() << " &obj);\n" " friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::" << node->className() << " &obj);\n" "};\n\n" "} // namespace Protocol\n" "} // namespace Akonadi\n" "\n"; mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << ")\n\n"; if (node->classType() != ClassNode::Class) { mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << "Ptr)\n\n"; } } void CppGenerator::writeImplSerializer(PropertyNode const *node, const char *streamingOperator) { const auto deps = node->dependencies(); if (deps.isEmpty()) { mImpl << " stream " << streamingOperator << " obj." << node->mVariableName() << ";\n"; } else { mImpl << " if ("; auto it = deps.cend(); while (1 + 1 == 2) { --it; const QString mVar = it.key(); mImpl << "(obj." << "m" << mVar[0].toUpper() << mVar.midRef(1) << " & " << it.value() << ")"; if (it == deps.cbegin()) { break; } else { mImpl << " && "; } } mImpl << ") {\n" " stream " << streamingOperator << " obj." << node->mVariableName() << ";\n" " }\n"; } } void CppGenerator::writeImplClass(ClassNode const *node) { const QString parentClass = node->parentClassName(); const auto children = node->children(); const auto properties = node->properties(); // Ctors for (auto child : children) { if (child->type() == Node::Ctor) { const auto ctor = static_cast(child); const auto args = ctor->arguments(); mImpl << node->className() << "::" << node->className() << "("; for (int i = 0; i < args.count(); ++i) { const auto &arg = args[i]; if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) { mImpl << arg.type << " " << arg.name; } else { mImpl << "const " << arg.type << " &" << arg.name; } if (i < args.count() - 1) { mImpl << ", "; } } mImpl << ")\n"; char startChar = ','; if (!parentClass.isEmpty()) { const QString type = node->name() + ((node->classType() == ClassNode::Notification) ? QStringLiteral("Notification") : QString()); mImpl << " : " << parentClass << "(Command::" << type << ")\n"; } else { startChar = ':'; } for (auto prop : properties) { const auto defaultValue = prop->defaultValue(); auto arg = std::find_if(args.cbegin(), args.cend(), [prop](const CtorNode::Argument &arg) { return arg.name == prop->name(); }); if (arg != args.cend()) { mImpl << " " << startChar << " " << prop->mVariableName() << "(" << arg->name << ")\n"; startChar = ','; } else { const bool isDefaultValue = !defaultValue.isEmpty(); const bool isNumeric = TypeHelper::isNumericType(prop->type()); const bool isBool = TypeHelper::isBoolType(prop->type()); if (isDefaultValue || isNumeric || isBool) { mImpl << " " << startChar << " " << prop->mVariableName() << "("; startChar = ','; if (isDefaultValue) { mImpl << defaultValue; } else if (isNumeric) { mImpl << "0"; } else if (isBool) { mImpl << "false"; } mImpl << ")\n"; } } } mImpl << "{\n" "}\n" "\n"; } } // Copy ctor mImpl << node->className() << "::" << node->className() << "(const " << node->className() << "&other)\n"; char startChar = ':'; if (!parentClass.isEmpty()) { mImpl << " : " << parentClass << "(other)\n"; startChar = ','; } for (auto prop : properties) { mImpl << " " << startChar << " " << prop->mVariableName() << "(other." << prop->mVariableName() << ")\n"; startChar = ','; } mImpl << "{\n" "}\n" "\n"; // Dtor mImpl << node->className() << "::~" << node->className() << "()\n" "{\n" "}\n" "\n"; // Assignment operator mImpl << node->className() << " &" << node->className() << "::operator=(const " << node->className() << " &other)\n" << "{\n"; if (!parentClass.isEmpty()) { mImpl << " " << parentClass << "::operator=(other);\n"; } for (auto prop : properties) { mImpl << " " << prop->mVariableName() << " = other." << prop->mVariableName() << ";\n"; } mImpl << " return *this;\n" "}\n" "\n"; // Comparision operator mImpl << "bool " << node->className() << "::operator==(const " << node->className() << " &other) const\n" "{\n"; mImpl << " return true // simplifies generation\n"; if (!parentClass.isEmpty()) { mImpl << " && " << parentClass << "::operator==(other)\n"; } for (auto prop : properties) { - mImpl << " && " << prop->mVariableName() << " == other." << prop->mVariableName() << "\n"; + if (prop->isPointer()) { + mImpl << " && *" << prop->mVariableName() << " == *other." << prop->mVariableName() << "\n"; + } else { + mImpl << " && " << prop->mVariableName() << " == other." << prop->mVariableName() << "\n"; + } } mImpl << " ;\n" "}\n" "\n"; // non-trivial setters for (auto prop : properties) { if (prop->readOnly()) { continue; } if (const auto setter = prop->setter()) { mImpl << "void " << node->className() << "::" << setter->name << "(const " << setter->type << " &val)\n" "{\n"; if (!setter->append.isEmpty()) { mImpl << " m" << setter->append[0].toUpper() << setter->append.midRef(1) << " << val;\n"; } if (!setter->remove.isEmpty()) { const QString mVar = QStringLiteral("m") + setter->remove[0].toUpper() + setter->remove.midRef(1); mImpl << " auto it = std::find(" << mVar << ".begin(), " << mVar << ".end(), val);\n" " if (it != " << mVar << ".end()) {\n" " " << mVar << ".erase(it);\n" " }\n"; } writeImplPropertyDependencies(prop); mImpl << "}\n\n"; } else if (!prop->dependencies().isEmpty()) { QString varType; if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) { mImpl << "void " << node->className() << "::" << prop->setterName() << "(" << prop->type() << " val)\n" "{\n" " " << prop->mVariableName() << " = val;\n"; } else { mImpl << "void " << node->className() << "::" << prop->setterName() << "(const " << prop->type() << " &val)\n" "{\n" " " << prop->mVariableName() << " = val;\n"; } writeImplPropertyDependencies(prop); mImpl << "}\n\n"; } } // serialize auto serializeProperties = properties; CppHelper::sortMembersForSerialization(serializeProperties); mImpl << "DataStream &operator<<(DataStream &stream, const " << node->className() << " &obj)\n" "{\n"; if (!parentClass.isEmpty()) { mImpl << " stream << static_cast(obj);\n"; } for (auto prop : serializeProperties) { writeImplSerializer(prop, "<<"); } mImpl << " return stream;\n" "}\n" "\n"; // deserialize mImpl << "DataStream &operator>>(DataStream &stream, " << node->className() << " &obj)\n" "{\n"; if (!parentClass.isEmpty()) { mImpl << " stream >> static_cast<" << parentClass << " &>(obj);\n"; } for (auto prop : serializeProperties) { writeImplSerializer(prop, ">>"); } mImpl << " return stream;\n" "}\n" "\n"; // debug mImpl << "QDebug operator<<(QDebug dbg, const " << node->className() << " &obj)\n" "{\n"; if (!parentClass.isEmpty()) { mImpl << " return dbg.noquote() << static_cast(obj)\n"; } else { mImpl << " return dbg.noquote()\n"; } for (auto prop : serializeProperties) { - mImpl << " << \"" << prop->name() << ":\" << obj." << prop->mVariableName() << " << \"\\n\"\n"; + if (prop->isPointer()) { + mImpl << " << \"" << prop->name() << ":\" << *obj." << prop->mVariableName() << " << \"\\n\"\n"; + } else { + mImpl << " << \"" << prop->name() << ":\" << obj." << prop->mVariableName() << " << \"\\n\"\n"; + } } mImpl << " ;\n" "}\n" "\n"; } void CppGenerator::writeImplPropertyDependencies(const PropertyNode* node) { const auto deps = node->dependencies(); QString key; QStringList values; QString enumType; for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) { if (key != it.key()) { key = it.key(); const auto children = node->parent()->children(); for (auto child : children) { if (child->type() == Node::Property && child != node) { auto prop = static_cast(child); if (prop->name() == key) { enumType = prop->type(); break; } } } if (!values.isEmpty()) { mImpl << " m" << key[0].toUpper() << key.midRef(1) << " |= " << enumType << "(" << values.join(QStringLiteral(" | ")) << ");\n"; values.clear(); } } values << *it; } if (!values.isEmpty()) { mImpl << " m" << key[0].toUpper() << key.midRef(1) << " |= " << enumType << "(" << values.join(QStringLiteral(" | ")) << ");\n"; } } bool CppGenerator::generateClass(ClassNode const *node) { writeHeaderClass(node); mImpl << "\n\n/************************* " << node->className() << " *************************/\n\n"; writeImplClass(node); return true; } diff --git a/src/private/protocolgen/nodetree.cpp b/src/private/protocolgen/nodetree.cpp index 64f193a3c..ad00bd537 100644 --- a/src/private/protocolgen/nodetree.cpp +++ b/src/private/protocolgen/nodetree.cpp @@ -1,301 +1,306 @@ /* Copyright (c) 2017 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "nodetree.h" #include "cpphelper.h" Node::Node(NodeType type, Node *parent) : mParent(parent) , mType(type) { if (parent) { parent->appendNode(this); } } Node::~Node() { qDeleteAll(mChildren); } Node::NodeType Node::type() const { return mType; } Node *Node::parent() const { return mParent; } void Node::appendNode(Node *child) { child->mParent = this; mChildren.push_back(child); } const QVector &Node::children() const { return mChildren; } DocumentNode::DocumentNode(int version) : Node(Document, Q_NULLPTR) , mVersion(version) {} int DocumentNode::version() const { return mVersion; } ClassNode::ClassNode(const QString &name, ClassType type, DocumentNode *parent) : Node(Node::Class, parent) , mName(name) , mClassType(type) {} QString ClassNode::name() const { return mName; } ClassNode::ClassType ClassNode::classType() const { return mClassType; } QString ClassNode::className() const { switch (mClassType) { case Class: return mName; case Command: return mName + QStringLiteral("Command"); case Response: return mName + QStringLiteral("Response"); case Notification: return mName + QStringLiteral("Notification"); default: Q_ASSERT(false); return QString(); } } QString ClassNode::parentClassName() const { switch (mClassType) { case Class: return QString(); case Command: return QStringLiteral("Command"); case Response: return QStringLiteral("Response"); case Notification: return QStringLiteral("ChangeNotification"); case Invalid: Q_ASSERT(false); return QString(); } Q_UNREACHABLE(); } ClassNode::ClassType ClassNode::elementNameToType(const QStringRef &name) { if (name == QLatin1String("class")) { return Class; } else if (name == QLatin1String("command")) { return Command; } else if (name == QLatin1String("response")) { return Response; } else if (name == QLatin1String("notification")) { return Notification; } else { return Invalid; } } QVector ClassNode::properties() const { QVector rv; for (auto node : qAsConst(mChildren)) { if (node->type() == Node::Property) { rv << static_cast(node); } } CppHelper::sortMembers(rv); return rv; } CtorNode::CtorNode(const QVector &args, ClassNode *parent) : Node(Ctor, parent) , mArgs(args) {} CtorNode::~CtorNode() {} QVector CtorNode::arguments() const { return mArgs; } void CtorNode::setArgumentType(const QString &name, const QString &type) { for (auto &arg : mArgs) { if (arg.name == name) { arg.type = type; break; } } } EnumNode::EnumNode(const QString &name, EnumType type, ClassNode *parent) : Node(Enum, parent) , mName(name) , mEnumType(type) {} QString EnumNode::name() const { return mName; } EnumNode::EnumType EnumNode::enumType() const { return mEnumType; } EnumNode::EnumType EnumNode::elementNameToType(const QStringRef &name) { if (name == QLatin1String("enum")) { return TypeEnum; } else if (name == QLatin1String("flag")) { return TypeFlag; } else { return TypeInvalid; } } EnumValueNode::EnumValueNode(const QString &name, EnumNode *parent) : Node(EnumValue, parent) , mName(name) , mValue() {} QString EnumValueNode::name() const { return mName; } void EnumValueNode::setValue(const QString &value) { mValue = value; } QString EnumValueNode::value() const { return mValue; } PropertyNode::PropertyNode(const QString &name, const QString &type, ClassNode *parent) : Node(Property, parent) , mName(name) , mType(type) , mSetter(nullptr) , mReadOnly(false) , mAsReference(false) {} QString PropertyNode::type() const { return mType; } QString PropertyNode::name() const { return mName; } void PropertyNode::setDefaultValue(const QString &defaultValue) { mDefaultValue = defaultValue; } QString PropertyNode::defaultValue() const { return mDefaultValue; } bool PropertyNode::readOnly() const { return mReadOnly; } void PropertyNode::setReadOnly(bool readOnly) { mReadOnly = readOnly; } bool PropertyNode::asReference() const { return mAsReference; } void PropertyNode::setAsReference(bool asReference) { mAsReference = asReference; } +bool PropertyNode::isPointer() const +{ + return mType.endsWith(QLatin1String("Ptr")); +} + QMultiMap PropertyNode::dependencies() const { return mDepends; } void PropertyNode::addDependency(const QString &enumVar, const QString &enumValue) { mDepends.insert(enumVar, enumValue); } void PropertyNode::setSetter(Setter *setter) { mSetter = setter; } PropertyNode::Setter *PropertyNode::setter() const { return mSetter; } QString PropertyNode::mVariableName() const { return QStringLiteral("m") + mName[0].toUpper() + mName.midRef(1); } QString PropertyNode::setterName() const { return QStringLiteral("set") + mName[0].toUpper() + mName.midRef(1); } diff --git a/src/private/protocolgen/nodetree.h b/src/private/protocolgen/nodetree.h index 2f4e35751..50d72c744 100644 --- a/src/private/protocolgen/nodetree.h +++ b/src/private/protocolgen/nodetree.h @@ -1,199 +1,201 @@ /* Copyright (c) 2017 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef NODETREE_H #define NODETREE_H #include #include class Node { public: enum NodeType { Document, Class, Ctor, Enum, EnumValue, Property }; Node(NodeType type, Node *parent); ~Node(); NodeType type() const; Node *parent() const; void appendNode(Node *child); const QVector &children() const; protected: Node *mParent; QVector mChildren; NodeType mType; }; class DocumentNode : public Node { public: DocumentNode(int version); int version() const; private: int mVersion; }; class PropertyNode; class ClassNode : public Node { public: enum ClassType { Invalid, Class, Command, Response, Notification }; ClassNode(const QString &name, ClassType type, DocumentNode *parent); QString name() const; ClassType classType() const; QString className() const; QString parentClassName() const; QVector properties() const; static ClassType elementNameToType(const QStringRef &name); private: QString mName; ClassType mClassType; }; class CtorNode : public Node { public: struct Argument { QString name; QString type; QString defaultValue; QString mVariableName() const { return QStringLiteral("m") + name[0].toUpper() + name.midRef(1); } }; CtorNode(const QVector &args, ClassNode *parent); ~CtorNode(); QVector arguments() const; void setArgumentType(const QString &name, const QString &type); private: QVector mArgs; }; class EnumNode : public Node { public: enum EnumType { TypeInvalid, TypeEnum, TypeFlag }; EnumNode(const QString &name, EnumType type, ClassNode *parent); QString name() const; EnumType enumType() const; static EnumType elementNameToType(const QStringRef &name); private: QString mName; EnumType mEnumType; }; class EnumValueNode : public Node { public: EnumValueNode(const QString &name, EnumNode *parent); QString name() const; void setValue(const QString &value); QString value() const; private: QString mName; QString mValue; }; class PropertyNode : public Node { public: struct Setter { QString name; QString type; QString append; QString remove; }; PropertyNode(const QString &name, const QString &type, ClassNode *parent); QString type() const; QString name() const; void setDefaultValue(const QString &defaultValue); QString defaultValue() const; bool readOnly() const; void setReadOnly(bool readOnly); bool asReference() const; void setAsReference(bool asReference); + bool isPointer() const; + QMultiMap dependencies() const; void addDependency(const QString &enumVar, const QString &enumValue); Setter *setter() const; void setSetter(Setter *setter); QString mVariableName() const; QString setterName() const; private: QString mName; QString mType; QString mDefaultValue; QMultiMap mDepends; Setter *mSetter; bool mReadOnly; bool mAsReference; }; #endif // NODETREE_H