From 35ab8b8e722b73a3a3ed9312379f6ab849252e19 Mon Sep 17 00:00:00 2001 From: Marcelo Lira Date: Mon, 25 Jul 2011 22:44:53 -0300 Subject: Added improved functionality for the 'conversion-rule' tag. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It works for primitive, container and value types. Object types doesn't have conversion rules because they can not have implicit conversions, and the regular conversion is always the same (get C++ object held on Python wrapper, and finding/creating a Python wrapper to a C++ pointer). Unit tests were added. Documentation was updated. Reviewed by Luciano Wolf Reviewed by Renato Araújo --- doc/typesystem.rst | 1 + doc/typesystem_conversionrule.rst | 113 +++++++++++++ tests/testconversionruletag.cpp | 177 ++++++++++++++++++- tests/testconversionruletag.h | 7 +- typesystem.cpp | 346 ++++++++++++++++++++++++++++++++++---- typesystem.h | 92 ++++++++-- typesystem_p.h | 67 ++++---- 7 files changed, 714 insertions(+), 89 deletions(-) create mode 100644 doc/typesystem_conversionrule.rst diff --git a/doc/typesystem.rst b/doc/typesystem.rst index 098a9d9..69dda43 100644 --- a/doc/typesystem.rst +++ b/doc/typesystem.rst @@ -23,6 +23,7 @@ can be found in the PySide/ directory of the PySide package. typesystem_arguments typesystem_solving_compilation typesystem_templates + typesystem_conversionrule typesystem_documentation diff --git a/doc/typesystem_conversionrule.rst b/doc/typesystem_conversionrule.rst new file mode 100644 index 0000000..c62d5bb --- /dev/null +++ b/doc/typesystem_conversionrule.rst @@ -0,0 +1,113 @@ +.. _conversion-rule-tag: + +Conversion Rule Tag +------------------- + +.. _conversion-rule: + +conversion-rule +^^^^^^^^^^^^^^^ + + The **conversion-rule** tag specifies how a **primitive-type**, a **container-type**, + or a **value-type** may be converted to and from the native C++ language types to the + target language types. + + .. code-block:: xml + + + + + // Code to convert a native value to a target language object. + + + + // Code to convert target language type object of type TARGETTYPEA + // to the C++ native type represented by the value/primitive/container-type. + + + // Code to convert target language type object of type TARGETTYPEB + // to the C++ native type represented by the value/primitive/container-type. + + + + + + The example above show the structure of a complete conversion rule. Each of the + child tags comprising the conversion rule are described in their own sections + below. + + +.. _native-to-target: + +native-to-target +^^^^^^^^^^^^^^^^ + + The **native-to-target** tag tells how to convert a native C++ value to its + target language equivalent. The text inside the tag is a C++ code the takes + an input value an does what's needed to convert it to the output value. + ``insert-template`` tags may be used to insert commonly repeating code. + + .. code-block:: xml + + + + // Code to convert a native value to a target language object. + + + + Use the replace node to modify the template code. + Notice that the generator must provide type system variables for the input + and output values and types, namely **%in**, **%out**, **%INTYPE** and + **%OUTTYPE**. In the case of container types, **%INTYPE** refers to the + full container type (e.g. **"list"**) and **%INTYPE_0**, **%INTYPE_1**, + **%INTYPE_#**, should be replaced by the types used in the container template + (e.g. **%INTYPE_0** correspondes to **"int"** for **"list"**). + + +.. _target-to-native: + +target-to-native +^^^^^^^^^^^^^^^^ + + The **target-to-native** tag encloses at least one, but usually many, conversions + from target language values to C++ native values. The *optional* attribute + ``replace`` tells if the target language to C++ conversions will be added to, or if + they will replace the implicit conversions collected by *ApiExtractor*. The default + value for it is *yes*. + + + .. code-block:: xml + + + \ + // List of target to native conversions meant to replace or expand + // the already existing implicit conversions. + + + + +.. _add-conversion: + +add-conversion +^^^^^^^^^^^^^^ + + Each **add-conversion** tag adds a rule for conversion of a target language type, + indicated by the ``type`` attribute, to the C++ native type represented by the + **primitive-type**, a **container-type**, or **value-type**, to which the parent + **conversion-rule** belongs. + + .. code-block:: xml + + + + // Code to convert target language type object of type TARGETTYPE_A + // to the C++ native type represented by the value/primitive/container-type. + + + + The ``check`` attribute tells how a target value should be checked to see if it belongs to + the type expected. This attribute is *optional*, for it can be derived from the ``type`` + attribute, but it isn't unusual that some special check is needed. The variables + **%in**, **%out**, **%INTYPE**, **%INTYPE_#**, and **%OUTTYPE**, must be provided by + the generator as in the ``native-to-target`` tag. + diff --git a/tests/testconversionruletag.cpp b/tests/testconversionruletag.cpp index 609a806..6228ef2 100644 --- a/tests/testconversionruletag.cpp +++ b/tests/testconversionruletag.cpp @@ -27,7 +27,7 @@ #include #include -void TestConversionRuleTag::testConversionRuleTag() +void TestConversionRuleTag::testConversionRuleTagWithFile() { // temp file used later const char conversionData[] = "Hi! I'm a conversion rule."; @@ -38,7 +38,7 @@ void TestConversionRuleTag::testConversionRuleTag() const char cppCode[] = "struct A {};"; QString xmlCode = "\ - \ + \ \ \ \ @@ -52,6 +52,179 @@ void TestConversionRuleTag::testConversionRuleTag() QCOMPARE(typeEntry->conversionRule(), QString(conversionData)); } +void TestConversionRuleTag::testConversionRuleTagReplace() +{ + const char cppCode[] = "\ + struct A {\ + A();\ + A(const char*, int);\ + };\ + struct B {\ + A createA();\ + };\ + "; + const char* xmlCode = "\ + \ + \ + \ + \ + \ + \ + DoThis();\ + return ConvertFromCppToPython(%IN);\ + \ + \ + \ + DoThat();\ + DoSomething();\ + %OUT = A();\ + \ + \ + %OUT = %IN.createA();\ + \ + \ + %OUT = new A(String_AsString(%IN), String_GetSize(%IN));\ + \ + \ + \ + \ + \ + "; + + TestUtil t(cppCode, xmlCode); + TypeDatabase* typeDb = TypeDatabase::instance(); + PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType("A"); + QVERIFY(typeA); + + CustomConversion* conversion = typeA->customConversion(); + QVERIFY(conversion); + + QCOMPARE(typeA, conversion->ownerType()); + QCOMPARE(conversion->nativeToTargetConversion().trimmed(), QString("DoThis(); return ConvertFromCppToPython(%IN);")); + + QVERIFY(conversion->replaceOriginalTargetToNativeConversions()); + QVERIFY(conversion->hasTargetToNativeConversions()); + QCOMPARE(conversion->targetToNativeConversions().size(), 3); + + CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().at(0); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QString("TargetNone")); + QVERIFY(toNative->isCustomType()); + QCOMPARE(toNative->sourceType(), (const TypeEntry*)0); + QCOMPARE(toNative->sourceTypeCheck(), QString("%IN == Target_None")); + QCOMPARE(toNative->conversion().trimmed(), QString("DoThat(); DoSomething(); %OUT = A();")); + + toNative = conversion->targetToNativeConversions().at(1); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QString("B")); + QVERIFY(!toNative->isCustomType()); + TypeEntry* typeB = typeDb->findType("B"); + QVERIFY(typeB); + QCOMPARE(toNative->sourceType(), typeB); + QCOMPARE(toNative->sourceTypeCheck(), QString("CheckIfInputObjectIsB(%IN)")); + QCOMPARE(toNative->conversion().trimmed(), QString("%OUT = %IN.createA();")); + + toNative = conversion->targetToNativeConversions().at(2); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QString("String")); + QVERIFY(toNative->isCustomType()); + QCOMPARE(toNative->sourceType(), (const TypeEntry*)0); + QCOMPARE(toNative->sourceTypeCheck(), QString("String_Check(%IN)")); + QCOMPARE(toNative->conversion().trimmed(), QString("%OUT = new A(String_AsString(%IN), String_GetSize(%IN));")); +} + +void TestConversionRuleTag::testConversionRuleTagAdd() +{ + const char cppCode[] = "\ + struct Date {\ + Date();\ + Date(int, int, int);\ + };\ + "; + const char* xmlCode = "\ + \ + \ + \ + \ + \ + \ + if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\ + %OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));\ + \ + \ + \ + \ + "; + + TestUtil t(cppCode, xmlCode); + AbstractMetaClass* classA = t.builder()->classes().findClass("Date"); + QVERIFY(classA); + + CustomConversion* conversion = classA->typeEntry()->customConversion(); + QVERIFY(conversion); + + QCOMPARE(conversion->nativeToTargetConversion(), QString()); + + QVERIFY(!conversion->replaceOriginalTargetToNativeConversions()); + QVERIFY(conversion->hasTargetToNativeConversions()); + QCOMPARE(conversion->targetToNativeConversions().size(), 1); + + CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().first(); + QVERIFY(toNative); + QCOMPARE(toNative->sourceTypeName(), QString("TargetDate")); + QVERIFY(toNative->isCustomType()); + QCOMPARE(toNative->sourceType(), (const TypeEntry*)0); + QCOMPARE(toNative->sourceTypeCheck(), QString("TargetDate_Check(%IN)")); + QCOMPARE(toNative->conversion().trimmed(), QString("if (!TargetDateTimeAPI) TargetDateTime_IMPORT; %OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));")); +} + +void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate() +{ + const char cppCode[] = "struct A {};"; + const char* xmlCode = "\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + "; + + TestUtil t(cppCode, xmlCode); + TypeDatabase* typeDb = TypeDatabase::instance(); + PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType("A"); + QVERIFY(typeA); + + CustomConversion* conversion = typeA->customConversion(); + QVERIFY(conversion); + + QCOMPARE(typeA, conversion->ownerType()); + QCOMPARE(conversion->nativeToTargetConversion().trimmed(), + QString("// TEMPLATE - native_to_target - START return ConvertFromCppToPython(%IN); // TEMPLATE - native_to_target - END")); + + QVERIFY(conversion->hasTargetToNativeConversions()); + QCOMPARE(conversion->targetToNativeConversions().size(), 1); + + CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().first(); + QVERIFY(toNative); + QCOMPARE(toNative->conversion().trimmed(), + QString("// TEMPLATE - target_to_native - START %OUT = %IN.createA(); // TEMPLATE - target_to_native - END")); +} + QTEST_APPLESS_MAIN(TestConversionRuleTag) #include "testconversionruletag.moc" diff --git a/tests/testconversionruletag.h b/tests/testconversionruletag.h index afab688..8ab1481 100644 --- a/tests/testconversionruletag.h +++ b/tests/testconversionruletag.h @@ -29,7 +29,10 @@ class TestConversionRuleTag : public QObject { Q_OBJECT private slots: - void testConversionRuleTag(); + void testConversionRuleTagWithFile(); + void testConversionRuleTagReplace(); + void testConversionRuleTagAdd(); + void testConversionRuleTagWithInsertTemplate(); }; -#endif \ No newline at end of file +#endif diff --git a/typesystem.cpp b/typesystem.cpp index 9976d47..daffeba 100644 --- a/typesystem.cpp +++ b/typesystem.cpp @@ -33,6 +33,8 @@ static QString strings_char = QLatin1String("char"); static QString strings_jchar = QLatin1String("jchar"); static QString strings_jobject = QLatin1String("jobject"); +static QList customConversionsForReview = QList(); + Handler::Handler(TypeDatabase* database, bool generate) : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) { @@ -70,6 +72,9 @@ Handler::Handler(TypeDatabase* database, bool generate) tagNames["reject-enum-value"] = StackElement::RejectEnumValue; tagNames["replace-type"] = StackElement::ReplaceType; tagNames["conversion-rule"] = StackElement::ConversionRule; + tagNames["native-to-target"] = StackElement::NativeToTarget; + tagNames["target-to-native"] = StackElement::TargetToNative; + tagNames["add-conversion"] = StackElement::AddConversion; tagNames["modify-argument"] = StackElement::ModifyArgument; tagNames["remove-argument"] = StackElement::RemoveArgument; tagNames["remove-default-expression"] = StackElement::RemoveDefaultExpression; @@ -155,6 +160,10 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin if (m_generate == TypeEntry::GenerateAll) { TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions); TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods); + foreach (CustomConversion* customConversion, customConversionsForReview) { + foreach (CustomConversion::TargetToNativeConversion* toNative, customConversion->targetToNativeConversions()) + toNative->setSourceType(m_database->findType(toNative->sourceTypeName())); + } } break; case StackElement::ObjectTypeEntry: @@ -174,6 +183,26 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin } } break; + case StackElement::NativeToTarget: + case StackElement::AddConversion: { + CustomConversion* customConversion = static_cast(m_current->entry)->customConversion(); + if (!customConversion) { + m_error = "CustomConversion object is missing."; + return false; + } + + QString code = m_contextStack.top()->codeSnips.takeLast().code(); + if (m_current->type == StackElement::AddConversion) { + if (customConversion->targetToNativeConversions().isEmpty()) { + m_error = "CustomConversion's target to native conversions missing."; + return false; + } + customConversion->targetToNativeConversions().last()->setConversion(code); + } else { + customConversion->setNativeToTargetConversion(code); + } + } + break; case StackElement::CustomMetaConstructor: { m_current->entry->setCustomConstructor(*m_current->value.customFunction); delete m_current->value.customFunction; @@ -193,18 +222,28 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin m_database->addTemplate(m_current->value.templateEntry); break; case StackElement::TemplateInstanceEnum: - if (m_current->parent->type == StackElement::InjectCode) + switch (m_current->parent->type) { + case StackElement::InjectCode: + case StackElement::NativeToTarget: + case StackElement::AddConversion: m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance); - else if (m_current->parent->type == StackElement::Template) + break; + case StackElement::Template: m_current->parent->value.templateEntry->addTemplateInstance(m_current->value.templateInstance); - else if (m_current->parent->type == StackElement::CustomMetaConstructor - || m_current->parent->type == StackElement::CustomMetaConstructor) + break; + case StackElement::CustomMetaConstructor: + case StackElement::CustomMetaDestructor: m_current->parent->value.customFunction->addTemplateInstance(m_current->value.templateInstance); - else if (m_current->parent->type == StackElement::ConversionRule) + break; + case StackElement::ConversionRule: m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(m_current->value.templateInstance); - else if (m_current->parent->type == StackElement::InjectCodeInFunction) + break; + case StackElement::InjectCodeInFunction: m_contextStack.top()->functionMods.last().snips.last().addTemplateInstance(m_current->value.templateInstance); - + break; + default: + break; // nada + }; break; default: break; @@ -214,7 +253,8 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin || m_current->type == StackElement::NamespaceTypeEntry || m_current->type == StackElement::InterfaceTypeEntry || m_current->type == StackElement::ObjectTypeEntry - || m_current->type == StackElement::ValueTypeEntry) { + || m_current->type == StackElement::ValueTypeEntry + || m_current->type == StackElement::PrimitiveTypeEntry) { StackElementContext* context = m_contextStack.pop(); delete context; } @@ -247,6 +287,11 @@ bool Handler::characters(const QString &ch) return true; } + if (m_current->type == StackElement::NativeToTarget || m_current->type == StackElement::AddConversion) { + m_contextStack.top()->codeSnips.last().addCode(ch); + return true; + } + if (m_current->parent) { if ((m_current->type & StackElement::CodeSnipMask)) { CodeSnipList snips; @@ -417,11 +462,15 @@ bool Handler::startElement(const QString &, const QString &n, StackElement* element = new StackElement(m_current); element->type = tagNames[tagName]; + if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll) + customConversionsForReview.clear(); + if (element->type == StackElement::Root || element->type == StackElement::NamespaceTypeEntry || element->type == StackElement::InterfaceTypeEntry || element->type == StackElement::ObjectTypeEntry - || element->type == StackElement::ValueTypeEntry) { + || element->type == StackElement::ValueTypeEntry + || element->type == StackElement::PrimitiveTypeEntry) { m_contextStack.push(new StackElementContext()); } @@ -953,6 +1002,13 @@ bool Handler::startElement(const QString &, const QString &n, attributes["class"] = QString(); attributes["file"] = QString(); break; + case StackElement::TargetToNative: + attributes["replace"] = QString("yes"); + break; + case StackElement::AddConversion: + attributes["type"] = QString(); + attributes["check"] = QString(); + break; case StackElement::RejectEnumValue: attributes["name"] = ""; break; @@ -1055,11 +1111,10 @@ bool Handler::startElement(const QString &, const QString &n, case StackElement::ConversionRule: { if (topElement.type != StackElement::ModifyArgument && topElement.type != StackElement::ValueTypeEntry - && topElement.type != StackElement::ObjectTypeEntry && topElement.type != StackElement::PrimitiveTypeEntry && topElement.type != StackElement::ContainerTypeEntry) { m_error = "Conversion rules can only be specified for argument modification, " - "value-type, object-type, primitive-type or container-type conversion."; + "value-type, primitive-type or container-type conversion."; return false; } @@ -1082,40 +1137,70 @@ bool Handler::startElement(const QString &, const QString &n, snip.language = lang; m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip); } else { - if (topElement.entry->hasConversionRule()) { + if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) { m_error = "Types can have only one conversion rule"; return false; } + // The old conversion rule tag that uses a file containing the conversion + // will be kept temporarily for compatibility reasons. QString sourceFile = attributes["file"]; - if (sourceFile.isEmpty()) { - m_error = QString("'file' attribute required; the source file containing the" - " containing the conversion functions must be provided"); - return false; - } - - //Handler constructor.... - if (m_generate != TypeEntry::GenerateForSubclass - && m_generate != TypeEntry::GenerateNothing) { - - const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG; - if (lang == TypeSystem::TargetLangCode) - conversionFlag = TARGET_CONVERSION_RULE_FLAG; - - QFile conversionSource(sourceFile); - if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) { - topElement.entry->setConversionRule(conversionFlag + QString::fromUtf8(conversionSource.readAll())); - } else { - ReportHandler::warning("File containing conversion code for " - + topElement.entry->name() - + " type does not exist or is not readable: " - + sourceFile); + if (!sourceFile.isEmpty()) { + if (m_generate != TypeEntry::GenerateForSubclass + && m_generate != TypeEntry::GenerateNothing) { + + const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG; + if (lang == TypeSystem::TargetLangCode) + conversionFlag = TARGET_CONVERSION_RULE_FLAG; + + QFile conversionSource(sourceFile); + if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) { + topElement.entry->setConversionRule(conversionFlag + QString::fromUtf8(conversionSource.readAll())); + } else { + ReportHandler::warning("File containing conversion code for " + + topElement.entry->name() + + " type does not exist or is not readable: " + + sourceFile); + } } } + CustomConversion* customConversion = new CustomConversion(static_cast(m_current->entry)); + customConversionsForReview.append(customConversion); } } - + break; + case StackElement::NativeToTarget: { + if (topElement.type != StackElement::ConversionRule) { + m_error = "Native to Target conversion code can only be specified for custom conversion rules."; + return false; + } + m_contextStack.top()->codeSnips << CodeSnip(0); + } + break; + case StackElement::TargetToNative: { + if (topElement.type != StackElement::ConversionRule) { + m_error = "Target to Native conversions can only be specified for custom conversion rules."; + return false; + } + bool replace = attributes["replace"] == "yes"; + static_cast(m_current->entry)->customConversion()->setReplaceOriginalTargetToNativeConversions(replace); + } + break; + case StackElement::AddConversion: { + if (topElement.type != StackElement::TargetToNative) { + m_error = "Target to Native conversions can only be added inside 'target-to-native' tags."; + return false; + } + QString sourceTypeName = attributes["type"]; + if (sourceTypeName.isEmpty()) { + m_error = "Target to Native conversions must specify the input type with the 'type' attribute."; + return false; + } + QString typeCheck = attributes["check"]; + static_cast(m_current->entry)->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck); + m_contextStack.top()->codeSnips << CodeSnip(0); + } break; case StackElement::ModifyArgument: { if (topElement.type != StackElement::ModifyFunction @@ -1692,8 +1777,11 @@ bool Handler::startElement(const QString &, const QString &n, (topElement.type != StackElement::Template) && (topElement.type != StackElement::CustomMetaConstructor) && (topElement.type != StackElement::CustomMetaDestructor) && + (topElement.type != StackElement::NativeToTarget) && + (topElement.type != StackElement::AddConversion) && (topElement.type != StackElement::ConversionRule)) { - m_error = "Can only insert templates into code snippets, templates, custom-constructors, custom-destructors or conversion-rule."; + m_error = "Can only insert templates into code snippets, templates, custom-constructors, "\ + "custom-destructors, conversion-rule, native-to-target or add-conversion tags."; return false; } element->value.templateInstance = new TemplateInstance(attributes["name"], since); @@ -2162,3 +2250,189 @@ bool TypeEntry::isCppPrimitive() const return res != &cppTypes[N]; } + +// Again, stuff to avoid ABI breakage. +typedef QHash TypeEntryCustomConversionMap; +Q_GLOBAL_STATIC(TypeEntryCustomConversionMap, typeEntryCustomConversionMap); + +TypeEntry::~TypeEntry() +{ + if (typeEntryCustomConversionMap()->contains(this)) { + CustomConversion* customConversion = typeEntryCustomConversionMap()->value(this); + typeEntryCustomConversionMap()->remove(this); + delete customConversion; + } +} + +bool TypeEntry::hasCustomConversion() const +{ + return typeEntryCustomConversionMap()->contains(this); +} +void TypeEntry::setCustomConversion(CustomConversion* customConversion) +{ + if (customConversion) + typeEntryCustomConversionMap()->insert(this, customConversion); + else if (typeEntryCustomConversionMap()->contains(this)) + typeEntryCustomConversionMap()->remove(this); +} +CustomConversion* TypeEntry::customConversion() const +{ + if (typeEntryCustomConversionMap()->contains(this)) + return typeEntryCustomConversionMap()->value(this); + return 0; +} + +/* +static void injectCode(ComplexTypeEntry *e, + const char *signature, + const QByteArray &code, + const ArgumentMap &args) +{ + CodeSnip snip; + snip.language = TypeSystem::NativeCode; + snip.position = CodeSnip::Beginning; + snip.addCode(QString::fromLatin1(code)); + snip.argumentMap = args; + + FunctionModification mod; + mod.signature = QMetaObject::normalizedSignature(signature); + mod.snips << snip; + mod.modifiers = Modification::CodeInjection; +} +*/ + +struct CustomConversion::CustomConversionPrivate +{ + CustomConversionPrivate(const TypeEntry* ownerType) + : ownerType(ownerType), replaceOriginalTargetToNativeConversions(false) + { + } + const TypeEntry* ownerType; + QString nativeToTargetConversion; + bool replaceOriginalTargetToNativeConversions; + TargetToNativeConversions targetToNativeConversions; +}; + +struct CustomConversion::TargetToNativeConversion::TargetToNativeConversionPrivate +{ + TargetToNativeConversionPrivate() + : sourceType(0) + { + } + const TypeEntry* sourceType; + QString sourceTypeName; + QString sourceTypeCheck; + QString conversion; +}; + +CustomConversion::CustomConversion(TypeEntry* ownerType) +{ + m_d = new CustomConversionPrivate(ownerType); + if (ownerType) + ownerType->setCustomConversion(this); +} + +CustomConversion::~CustomConversion() +{ + foreach (TargetToNativeConversion* targetToNativeConversion, m_d->targetToNativeConversions) + delete targetToNativeConversion; + m_d->targetToNativeConversions.clear(); + delete m_d; +} + +const TypeEntry* CustomConversion::ownerType() const +{ + return m_d->ownerType; +} + +QString CustomConversion::nativeToTargetConversion() const +{ + return m_d->nativeToTargetConversion; +} + +void CustomConversion::setNativeToTargetConversion(const QString& nativeToTargetConversion) +{ + m_d->nativeToTargetConversion = nativeToTargetConversion; +} + +bool CustomConversion::replaceOriginalTargetToNativeConversions() const +{ + return m_d->replaceOriginalTargetToNativeConversions; +} + +void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions) +{ + m_d->replaceOriginalTargetToNativeConversions = replaceOriginalTargetToNativeConversions; +} + +bool CustomConversion::hasTargetToNativeConversions() const +{ + return !(m_d->targetToNativeConversions.isEmpty()); +} + +CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() +{ + return m_d->targetToNativeConversions; +} + +const CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() const +{ + return m_d->targetToNativeConversions; +} + +void CustomConversion::addTargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion) +{ + m_d->targetToNativeConversions.append(new TargetToNativeConversion(sourceTypeName, sourceTypeCheck, conversion)); +} + +CustomConversion::TargetToNativeConversion::TargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion) +{ + m_d = new TargetToNativeConversionPrivate; + m_d->sourceTypeName = sourceTypeName; + m_d->sourceTypeCheck = sourceTypeCheck; + m_d->conversion = conversion; +} + +CustomConversion::TargetToNativeConversion::~TargetToNativeConversion() +{ + delete m_d; +} + +const TypeEntry* CustomConversion::TargetToNativeConversion::sourceType() const +{ + return m_d->sourceType; +} + +void CustomConversion::TargetToNativeConversion::setSourceType(const TypeEntry* sourceType) +{ + m_d->sourceType = sourceType; +} + +bool CustomConversion::TargetToNativeConversion::isCustomType() const +{ + return !(m_d->sourceType); +} + +QString CustomConversion::TargetToNativeConversion::sourceTypeName() const +{ + return m_d->sourceTypeName; +} + +QString CustomConversion::TargetToNativeConversion::sourceTypeCheck() const +{ + return m_d->sourceTypeCheck; +} + +QString CustomConversion::TargetToNativeConversion::conversion() const +{ + return m_d->conversion; +} + +void CustomConversion::TargetToNativeConversion::setConversion(const QString& conversion) +{ + m_d->conversion = conversion; +} diff --git a/typesystem.h b/typesystem.h index abba445..c915cd4 100644 --- a/typesystem.h +++ b/typesystem.h @@ -82,7 +82,7 @@ enum Ownership { }; }; -struct ReferenceCount +struct APIEXTRACTOR_API ReferenceCount { ReferenceCount() {} enum Action { // 0x01 - 0xff @@ -102,7 +102,7 @@ struct ReferenceCount QString varName; }; -struct ArgumentOwner +struct APIEXTRACTOR_API ArgumentOwner { enum Action { Invalid = 0x00, @@ -156,7 +156,7 @@ public: QList codeList; }; -class CustomFunction : public CodeSnipAbstract +class APIEXTRACTOR_API CustomFunction : public CodeSnipAbstract { public: CustomFunction(const QString &n = QString()) : name(n) { } @@ -165,7 +165,7 @@ public: QString paramName; }; -class TemplateEntry : public CodeSnipAbstract +class APIEXTRACTOR_API TemplateEntry : public CodeSnipAbstract { public: TemplateEntry(const QString &name, double vr) @@ -190,7 +190,7 @@ private: typedef QHash TemplateEntryHash; -class TemplateInstance +class APIEXTRACTOR_API TemplateInstance { public: TemplateInstance(const QString &name, double vr) @@ -245,7 +245,7 @@ public: }; typedef QList CodeSnipList; -struct ArgumentModification +struct APIEXTRACTOR_API ArgumentModification { ArgumentModification(int idx, double vr) : removedDefaultExpression(false), removed(false), @@ -436,7 +436,7 @@ private: }; typedef QList FunctionModificationList; -struct FieldModification: public Modification +struct APIEXTRACTOR_API FieldModification: public Modification { bool isReadable() const { @@ -547,7 +547,7 @@ private: }; typedef QList AddedFunctionList; -struct ExpensePolicy +struct APIEXTRACTOR_API ExpensePolicy { ExpensePolicy() : limit(-1) {} int limit; @@ -561,7 +561,7 @@ struct ExpensePolicy class InterfaceTypeEntry; class ObjectTypeEntry; -class DocModification +class APIEXTRACTOR_API DocModification { public: enum Mode { @@ -614,6 +614,8 @@ private: typedef QList DocModificationList; +class CustomConversion; + class APIEXTRACTOR_API TypeEntry { public: @@ -662,7 +664,7 @@ public: { }; - virtual ~TypeEntry() { } + virtual ~TypeEntry(); Type type() const { @@ -949,17 +951,23 @@ public: return m_version; } + /// TODO-CONVERTER: mark as deprecated bool hasNativeConversionRule() const { return m_conversionRule.startsWith(NATIVE_CONVERSION_RULE_FLAG); } + /// TODO-CONVERTER: mark as deprecated bool hasTargetConversionRule() const { return m_conversionRule.startsWith(TARGET_CONVERSION_RULE_FLAG); } bool isCppPrimitive() const; + + bool hasCustomConversion() const; + void setCustomConversion(CustomConversion* customConversion); + CustomConversion* customConversion() const; private: QString m_name; Type m_type; @@ -1155,7 +1163,7 @@ private: typedef QList PrimitiveTypeEntryList; -struct EnumValueRedirection +struct APIEXTRACTOR_API EnumValueRedirection { EnumValueRedirection(const QString &rej, const QString &us) : rejected(rej), @@ -1729,7 +1737,7 @@ public: }; -class ValueTypeEntry : public ComplexTypeEntry +class APIEXTRACTOR_API ValueTypeEntry : public ComplexTypeEntry { public: ValueTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, BasicValueType, vr) { } @@ -1749,7 +1757,7 @@ protected: }; -class StringTypeEntry : public ValueTypeEntry +class APIEXTRACTOR_API StringTypeEntry : public ValueTypeEntry { public: StringTypeEntry(const QString &name, double vr) @@ -1768,7 +1776,7 @@ public: } }; -class CharTypeEntry : public ValueTypeEntry +class APIEXTRACTOR_API CharTypeEntry : public ValueTypeEntry { public: CharTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, CharType, vr) @@ -1789,7 +1797,7 @@ public: } }; -class VariantTypeEntry: public ValueTypeEntry +class APIEXTRACTOR_API VariantTypeEntry: public ValueTypeEntry { public: VariantTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, VariantType, vr) { } @@ -1889,7 +1897,7 @@ private: InterfaceTypeEntry *m_interface; }; -struct TypeRejection +struct APIEXTRACTOR_API TypeRejection { QString class_name; QString function_name; @@ -1897,6 +1905,56 @@ struct TypeRejection QString enum_name; }; -QString fixCppTypeName(const QString &name); +APIEXTRACTOR_API QString fixCppTypeName(const QString &name); + +class APIEXTRACTOR_API CustomConversion +{ +public: + CustomConversion(TypeEntry* ownerType); + ~CustomConversion(); + + const TypeEntry* ownerType() const; + QString nativeToTargetConversion() const; + void setNativeToTargetConversion(const QString& nativeToTargetConversion); + + class APIEXTRACTOR_API TargetToNativeConversion + { + public: + TargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion = QString()); + ~TargetToNativeConversion(); + + const TypeEntry* sourceType() const; + void setSourceType(const TypeEntry* sourceType); + bool isCustomType() const; + QString sourceTypeName() const; + QString sourceTypeCheck() const; + QString conversion() const; + void setConversion(const QString& conversion); + private: + struct TargetToNativeConversionPrivate; + TargetToNativeConversionPrivate* m_d; + }; + + /** + * Returns true if the target to C++ custom conversions should + * replace the original existing ones, and false if the custom + * conversions should be added to the original. + */ + bool replaceOriginalTargetToNativeConversions() const; + void setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions); + + typedef QList TargetToNativeConversions; + bool hasTargetToNativeConversions() const; + TargetToNativeConversions& targetToNativeConversions(); + const TargetToNativeConversions& targetToNativeConversions() const; + void addTargetToNativeConversion(const QString& sourceTypeName, + const QString& sourceTypeCheck, + const QString& conversion = QString()); +private: + struct CustomConversionPrivate; + CustomConversionPrivate* m_d; +}; #endif // TYPESYSTEM_H diff --git a/typesystem_p.h b/typesystem_p.h index 0cf5755..371321b 100644 --- a/typesystem_p.h +++ b/typesystem_p.h @@ -35,23 +35,23 @@ class StackElement None = 0x0, // Type tags (0x1, ... , 0xff) - ObjectTypeEntry = 0x1, - ValueTypeEntry = 0x2, - InterfaceTypeEntry = 0x3, - NamespaceTypeEntry = 0x4, - ComplexTypeEntryMask = 0x7, + ObjectTypeEntry = 0x1, + ValueTypeEntry = 0x2, + InterfaceTypeEntry = 0x3, + NamespaceTypeEntry = 0x4, + ComplexTypeEntryMask = 0x7, // Non-complex type tags (0x8, 0x9, ... , 0xf) - PrimitiveTypeEntry = 0x8, - EnumTypeEntry = 0x9, - ContainerTypeEntry = 0xa, - FunctionTypeEntry = 0xb, - TypeEntryMask = 0xf, + PrimitiveTypeEntry = 0x8, + EnumTypeEntry = 0x9, + ContainerTypeEntry = 0xa, + FunctionTypeEntry = 0xb, + TypeEntryMask = 0xf, // Documentation tags - InjectDocumentation = 0x10, - ModifyDocumentation = 0x20, - DocumentationMask = 0xf0, + InjectDocumentation = 0x10, + ModifyDocumentation = 0x20, + DocumentationMask = 0xf0, // Simple tags (0x100, 0x200, ... , 0xf00) ExtraIncludes = 0x0100, @@ -70,32 +70,35 @@ class StackElement TemplateInstanceEnum = 0x0e00, Replace = 0x0f00, AddFunction = 0x1000, + NativeToTarget = 0x1100, + TargetToNative = 0x1200, + AddConversion = 0x1300, SimpleMask = 0x3f00, // Code snip tags (0x1000, 0x2000, ... , 0xf000) - InjectCode = 0x4000, - InjectCodeInFunction = 0x8000, - CodeSnipMask = 0xc000, + InjectCode = 0x4000, + InjectCodeInFunction = 0x8000, + CodeSnipMask = 0xc000, // Function modifier tags (0x010000, 0x020000, ... , 0xf00000) - Access = 0x010000, - Removal = 0x020000, - Rename = 0x040000, - ModifyArgument = 0x080000, - Thread = 0x100000, - FunctionModifiers = 0xff0000, + Access = 0x010000, + Removal = 0x020000, + Rename = 0x040000, + ModifyArgument = 0x080000, + Thread = 0x100000, + FunctionModifiers = 0xff0000, // Argument modifier tags (0x01000000 ... 0xf0000000) - ConversionRule = 0x01000000, - ReplaceType = 0x02000000, - ReplaceDefaultExpression = 0x04000000, - RemoveArgument = 0x08000000, - DefineOwnership = 0x10000000, - RemoveDefaultExpression = 0x20000000, - NoNullPointers = 0x40000000, - ReferenceCount = 0x80000000, - ParentOwner = 0x90000000, - ArgumentModifiers = 0xff000000 + ConversionRule = 0x01000000, + ReplaceType = 0x02000000, + ReplaceDefaultExpression = 0x04000000, + RemoveArgument = 0x08000000, + DefineOwnership = 0x10000000, + RemoveDefaultExpression = 0x20000000, + NoNullPointers = 0x40000000, + ReferenceCount = 0x80000000, + ParentOwner = 0x90000000, + ArgumentModifiers = 0xff000000 }; StackElement(StackElement *p) : entry(0), type(None), parent(p) { } -- cgit v1.2.3