summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/repparser/parser.g76
-rw-r--r--tests/auto/repparser/tst_parser.cpp36
-rw-r--r--tools/repc/repcodegenerator.cpp43
-rw-r--r--tools/repc/repcodegenerator.h3
4 files changed, 138 insertions, 20 deletions
diff --git a/src/repparser/parser.g b/src/repparser/parser.g
index 671ee00..ef942ca 100644
--- a/src/repparser/parser.g
+++ b/src/repparser/parser.g
@@ -45,6 +45,7 @@
%token semicolon "[semicolon];"
%token class "[class]class[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
%token pod "[pod]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*\\((?<types>[^\\)]*)\\);?[ \\t]*"
+%token flag "[flag][ \\t]*FLAG[ \t]*\\([ \t]*(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]+(?<enum>[A-Za-z_][A-Za-z0-9_]*)[ \t]*\\)[ \t]*"
%token enum "[enum][ \\t]*ENUM[ \t]+(?:(?<class>class[ \t]+))?(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]*(?::[ \t]*(?<type>[a-zA-Z0-9 _:]*[a-zA-Z0-9_])[ \t]*)?"
%token enum_param "[enum_param][ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \\t]*(=[ \\t]*(?<value>-\\d+|0[xX][0-9A-Fa-f]+|\\d+))?[ \\t]*"
%token prop "[prop][ \\t]*PROP[ \\t]*\\((?<args>[^\\)]+)\\);?[ \\t]*"
@@ -168,9 +169,20 @@ struct ASTEnum
bool isSigned;
bool isScoped;
int max;
+ int flagIndex = -1;
};
Q_DECLARE_TYPEINFO(ASTEnum, Q_RELOCATABLE_TYPE);
+struct ASTFlag
+{
+ explicit ASTFlag(const QString &name = {}, const QString &_enum = {});
+
+ bool isValid() const;
+ QString name;
+ QString _enum;
+};
+Q_DECLARE_TYPEINFO(ASTFlag, Q_RELOCATABLE_TYPE);
+
struct ASTModelRole
{
ASTModelRole(const QString &roleName = QString())
@@ -204,6 +216,7 @@ struct ASTClass
QList<ASTFunction> signalsList;
QList<ASTFunction> slotsList;
QList<ASTEnum> enums;
+ QList<ASTFlag> flags;
bool hasPersisted;
QList<ASTModel> modelMetadata;
QList<int> subClassPropertyIndices;
@@ -236,6 +249,7 @@ struct AST
QList<ASTClass> classes;
QList<POD> pods;
QList<ASTEnum> enums;
+ QList<ASTFlag> flags;
QList<QString> enumUses;
QStringList preprocessorDirectives;
};
@@ -384,6 +398,16 @@ ASTEnum::ASTEnum(const QString &name)
{
}
+ASTFlag::ASTFlag(const QString &name, const QString &_enum)
+ : name(name), _enum(_enum)
+{
+}
+
+bool ASTFlag::isValid() const
+{
+ return !name.isEmpty();
+}
+
ASTClass::ASTClass(const QString &name)
: name(name), hasPersisted(false)
{
@@ -682,6 +706,7 @@ Type: Enum;
}
break;
./
+Type: Flag | Flag Newlines;
Comma: comma | comma Newlines;
@@ -733,7 +758,7 @@ Class: ClassStart Start Stop;
./
ClassTypes: ClassType | ClassType ClassTypes;
-ClassType: DecoratedProp | DecoratedSignal | DecoratedSlot | DecoratedModel | DecoratedClass | Comments;
+ClassType: DecoratedProp | DecoratedSignal | DecoratedSlot | DecoratedModel | DecoratedClass | DecoratedClassFlag | Comments;
ClassType: Enum;
/.
case $rule_number:
@@ -749,6 +774,7 @@ DecoratedProp: Prop | Comments Prop | Prop Newlines | Comments Prop Newlines;
DecoratedModel: Model | Comments Model | Model Newlines | Comments Model Newlines;
DecoratedClass: ChildRep | Comments ChildRep | ChildRep Newlines | Comments ChildRep Newlines;
DecoratedEnumParam: EnumParam | Comments EnumParam | EnumParam Newlines | Comments EnumParam Newlines;
+DecoratedClassFlag: ClassFlag | Comments ClassFlag | ClassFlag Newlines | Comments ClassFlag Newlines;
Start: start | Comments start | start Newlines | Comments start Newlines;
Stop: stop | stop Newlines;
@@ -803,6 +829,29 @@ EnumParam: enum_param;
break;
./
+ClassFlag: flag;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString _enum = captured().value(QLatin1String("enum"));
+ int enumIndex = 0;
+ for (auto &en : m_astClass.enums) {
+ if (en.name == _enum) {
+ en.flagIndex = m_astClass.flags.count();
+ break;
+ }
+ enumIndex++;
+ }
+ if (enumIndex == m_astClass.enums.count()) {
+ setErrorString(QLatin1String("FLAG: Unknown (class) enum: %1").arg(_enum));
+ return false;
+ }
+ m_astClass.flags.append(ASTFlag(name, _enum));
+ }
+ break;
+./
+
Prop: prop;
/.
case $rule_number:
@@ -915,6 +964,31 @@ UseEnum: use_enum;
break;
./
+Flag: flag;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString _enum = captured().value(QLatin1String("enum"));
+ int enumIndex = 0;
+ for (auto &en : m_ast.enums) {
+ if (en.name == _enum) {
+ en.flagIndex = m_ast.flags.count();
+ break;
+ }
+ if (en.name == _enum)
+ break;
+ enumIndex++;
+ }
+ if (enumIndex == m_ast.enums.count()) {
+ setErrorString(QLatin1String("FLAG: Unknown (global) enum: %1").arg(_enum));
+ return false;
+ }
+ m_ast.flags.append(ASTFlag(name, _enum));
+ }
+ break;
+./
+
--Error conditions/messages
ClassType: ClassStart;
/.
diff --git a/tests/auto/repparser/tst_parser.cpp b/tests/auto/repparser/tst_parser.cpp
index 0c15002..5d2e818 100644
--- a/tests/auto/repparser/tst_parser.cpp
+++ b/tests/auto/repparser/tst_parser.cpp
@@ -402,16 +402,19 @@ void tst_Parser::testTypedEnums_data()
QTest::addColumn<QString>("expectedtype");
QTest::addColumn<bool>("inclass");
QTest::addColumn<bool>("isscoped");
+ QTest::addColumn<bool>("isflag");
- for (int i = 0; i <= 3; ++i) {
+ for (int i = 0; i <= 7; ++i) {
bool inclass = i % 2 == 1;
- bool isscoped = i > 1;
- QString identifier = inclass ? QLatin1String("%1 %2 in class") : QLatin1String("%1 %2 outside class");
+ bool isscoped = i % 4 > 1;
+ bool isflag = i > 3;
+ QString identifier = inclass ? QLatin1String("%1 %2 %3 in class") : QLatin1String("%1 %2 %3 outside class");
QString scopeString = isscoped ? QLatin1String("Scoped") : QLatin1String("Non-scoped");
- QTest::newRow(identifier.arg(scopeString, "no type").toLatin1()) << "preset {presetNumber}" << QString() << inclass << isscoped;
- QTest::newRow(identifier.arg(scopeString, "quint16").toLatin1()) << "preset : quint16 {presetNumber}" << "quint16" << inclass << isscoped;
- QTest::newRow(identifier.arg(scopeString, "qint64").toLatin1()) << "preset : qint64 {presetNumber}" << "qint64" << inclass << isscoped;
- QTest::newRow(identifier.arg(scopeString, "unsigned char").toLatin1()) << "preset: unsigned char {presetNumber}" << "unsigned char" << inclass << isscoped;
+ QString flagString = isflag ? QLatin1String("Flag") : QLatin1String("Enum");
+ QTest::newRow(identifier.arg(scopeString, flagString, "no type").toLatin1()) << "preset {presetNumber}" << QString() << inclass << isscoped << isflag;
+ QTest::newRow(identifier.arg(scopeString, flagString, "quint16").toLatin1()) << "preset : quint16 {presetNumber}" << "quint16" << inclass << isscoped << isflag;
+ QTest::newRow(identifier.arg(scopeString, flagString, "qint64").toLatin1()) << "preset : qint64 {presetNumber}" << "qint64" << inclass << isscoped << isflag;
+ QTest::newRow(identifier.arg(scopeString, flagString, "unsigned char").toLatin1()) << "preset: unsigned char {presetNumber}" << "unsigned char" << inclass << isscoped << isflag;
}
}
@@ -421,16 +424,23 @@ void tst_Parser::testTypedEnums()
QFETCH(QString, expectedtype);
QFETCH(bool, inclass);
QFETCH(bool, isscoped);
+ QFETCH(bool, isflag);
QTemporaryFile file;
file.open();
QTextStream stream(&file);
- if (!inclass)
+ if (!inclass) {
stream << "ENUM " << (isscoped ? "class " : "") << enumdeclaration << Qt::endl;
+ if (isflag)
+ stream << "FLAG(MyFlags preset)" << Qt::endl;
+ }
stream << "class TestClass" << Qt::endl;
stream << "{" << Qt::endl;
- if (inclass)
+ if (inclass) {
stream << "ENUM " << (isscoped ? "class " : "") << enumdeclaration << Qt::endl;
+ if (isflag)
+ stream << "FLAG(MyFlags preset)" << Qt::endl;
+ }
stream << "};" << Qt::endl;
file.seek(0);
@@ -440,15 +450,23 @@ void tst_Parser::testTypedEnums()
const AST ast = parser.ast();
QCOMPARE(ast.classes.count(), 1);
ASTEnum enums;
+ ASTFlag flags;
if (inclass) {
const ASTClass astClass = ast.classes.first();
QCOMPARE(astClass.enums.count(), 1);
enums = astClass.enums.first();
+ if (isflag)
+ flags = astClass.flags.first();
} else {
QCOMPARE(ast.enums.count(), 1);
enums = ast.enums.first();
+ if (isflag)
+ flags = ast.flags.first();
}
QVERIFY(enums.isScoped == isscoped);
+ QVERIFY(enums.flagIndex == (isflag ? 0 : -1));
+ QVERIFY(flags.name == (isflag ? "MyFlags" : QString{}));
+ QVERIFY(flags._enum == (isflag ? "preset" : QString{}));
QCOMPARE(enums.type, expectedtype);
const QList<ASTEnumParam> paramList = enums.params;
QVERIFY(paramList.count() == 1);
diff --git a/tools/repc/repcodegenerator.cpp b/tools/repc/repcodegenerator.cpp
index 47e9ff7..c4913f8 100644
--- a/tools/repc/repcodegenerator.cpp
+++ b/tools/repc/repcodegenerator.cpp
@@ -225,8 +225,12 @@ void RepCodeGenerator::generate(const AST &ast, Mode mode, QString fileName)
}
generateHeader(mode, stream, ast);
- for (const ASTEnum &en : ast.enums)
- generateEnumGadget(stream, en, QStringLiteral("%1Enum").arg(en.name));
+ for (const ASTEnum &en : ast.enums) {
+ ASTFlag flag;
+ if (en.flagIndex >= 0)
+ flag = ast.flags.at(en.flagIndex);
+ generateEnumGadget(stream, en, flag, QStringLiteral("%1Enum").arg(en.name));
+ }
for (const POD &pod : ast.pods)
generatePOD(stream, pod);
@@ -499,7 +503,7 @@ void RepCodeGenerator::generatePOD(QTextStream &out, const POD &pod)
QString getEnumType(const ASTEnum &en)
{
- if (en.isScoped && !en.type.isEmpty())
+ if (!en.type.isEmpty())
return en.type;
if (en.isSigned) {
if (en.max < 0x7F)
@@ -532,13 +536,12 @@ void RepCodeGenerator::generateDeclarationsForEnums(QTextStream &out, const QLis
out << " };\n";
- if (generateQENUM) {
+ if (generateQENUM)
out << " Q_ENUM(" << en.name << ")\n";
- }
}
}
-void RepCodeGenerator::generateEnumGadget(QTextStream &out, const ASTEnum &en, const QString &className)
+void RepCodeGenerator::generateEnumGadget(QTextStream &out, const ASTEnum &en, const ASTFlag &flag, const QString &className)
{
out << "class " << className << "\n"
"{\n"
@@ -551,9 +554,15 @@ void RepCodeGenerator::generateEnumGadget(QTextStream &out, const ASTEnum &en, c
auto enums = QList<ASTEnum>() << en;
generateDeclarationsForEnums(out, enums);
+ if (flag.isValid()) {
+ out << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+ out << " Q_FLAG(" << flag.name << ")\n";
+ }
out << "};\n\n";
+ if (flag.isValid())
+ out << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name << ")\n\n";
}
QString RepCodeGenerator::generateMetaTypeRegistration(const QSet<QString> &metaTypes)
@@ -642,6 +651,10 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << "" << Qt::endl;
out << "public:" << Qt::endl;
generateDeclarationsForEnums(out, astClass.enums);
+ for (const auto &flag : astClass.flags) {
+ out << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+ out << " Q_FLAG(" << flag.name << ")\n";
+ }
}
}
@@ -948,6 +961,10 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << " friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);" << Qt::endl;
out << "};\n\n";
+ if (mode != SIMPLE_SOURCE) {
+ for (const ASTFlag &flag : astClass.flags)
+ out << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name << ")\n\n";
+ }
}
void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astClass)
@@ -960,6 +977,8 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
// Include enum definition in SourceAPI
generateDeclarationsForEnums(out, astClass.enums, false);
}
+ for (const auto &flag : astClass.flags)
+ out << QLatin1String(" typedef QFlags<typename ObjectType::%1> %2;").arg(flag._enum, flag.name) << Qt::endl;
out << QString::fromLatin1(" %1(ObjectType *object, const QString &name = QLatin1String(\"%2\"))").arg(className, astClass.name) << Qt::endl;
out << QStringLiteral(" : SourceApiMap(), m_name(name)") << Qt::endl;
out << QStringLiteral(" {") << Qt::endl;
@@ -967,16 +986,22 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
out << QStringLiteral(" Q_UNUSED(object)") << Qt::endl;
const auto enumCount = astClass.enums.count();
+ const auto totalCount = enumCount + astClass.flags.count();
for (int i : astClass.subClassPropertyIndices) {
const ASTProperty &child = astClass.properties.at(i);
out << QString::fromLatin1(" using %1_type_t = typename std::remove_pointer<decltype(object->%1())>::type;")
.arg(child.name) << Qt::endl;
}
- out << QString::fromLatin1(" m_enums[0] = %1;").arg(enumCount) << Qt::endl;
+ out << QString::fromLatin1(" m_enums[0] = %1;").arg(totalCount) << Qt::endl;
for (qsizetype i = 0; i < enumCount; ++i) {
const auto enumerator = astClass.enums.at(i);
out << QString::fromLatin1(" m_enums[%1] = ObjectType::staticMetaObject.indexOfEnumerator(\"%2\");")
- .arg(i+1).arg(enumerator.name) << Qt::endl;
+ .arg(i+1).arg(enumerator.name) << Qt::endl;
+ }
+ for (qsizetype i = enumCount; i < totalCount; ++i) {
+ const auto flag = astClass.flags.at(i - enumCount);
+ out << QString::fromLatin1(" m_enums[%1] = ObjectType::staticMetaObject.indexOfEnumerator(\"%2\");")
+ .arg(i+1).arg(flag.name) << Qt::endl;
}
const auto propCount = astClass.properties.count();
out << QString::fromLatin1(" m_properties[0] = %1;").arg(propCount) << Qt::endl;
@@ -1282,7 +1307,7 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
<< QStringLiteral("\"}; }") << Qt::endl;
out << QStringLiteral("") << Qt::endl;
- out << QString::fromLatin1(" int m_enums[%1];").arg(enumCount + 1) << Qt::endl;
+ out << QString::fromLatin1(" int m_enums[%1];").arg(totalCount + 1) << Qt::endl;
out << QString::fromLatin1(" int m_properties[%1];").arg(propCount+1) << Qt::endl;
out << QString::fromLatin1(" int m_signals[%1];").arg(signalCount+changedCount+1) << Qt::endl;
out << QString::fromLatin1(" int m_methods[%1];").arg(methodCount+1) << Qt::endl;
diff --git a/tools/repc/repcodegenerator.h b/tools/repc/repcodegenerator.h
index e918729..b48bf30 100644
--- a/tools/repc/repcodegenerator.h
+++ b/tools/repc/repcodegenerator.h
@@ -38,6 +38,7 @@ struct AST;
struct ASTClass;
struct POD;
struct ASTEnum;
+struct ASTFlag;
struct ASTProperty;
class QIODevice;
@@ -66,7 +67,7 @@ private:
void generateSimpleSetter(QTextStream &out, const ASTProperty &property, bool generateOverride = true);
void generatePOD(QTextStream &out, const POD &pod);
- void generateEnumGadget(QTextStream &out, const ASTEnum &en, const QString &className);
+ void generateEnumGadget(QTextStream &out, const ASTEnum &en, const ASTFlag &flag, const QString &className);
void generateDeclarationsForEnums(QTextStream &out, const QList<ASTEnum> &enums, bool generateQENUM=true);
QString formatQPropertyDeclarations(const POD &pod);
QString formatConstructors(const POD &pod);