[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Additions to kconfig_compiler for enum types
From:       David Jarvie <lists () astrojar ! org ! uk>
Date:       2007-02-18 19:07:29
Message-ID: 200702181907.30024.lists () astrojar ! org ! uk
[Download RAW message or body]

I'd like to add two extra options to kconfig_compiler for enum type items. The 
aim of the changes is to make it more straightforward for application code to 
use enums rather than int values when handling enum config options. Using 
enums is more type-safe, so it should encourage safer coding. Note that the 
proposed changes are backwards compatible - existing .kcfg and .kcfgc files 
and their generated code will be unchanged.

1) the option to use enum types instead of int for the parameter of the 
manipulator and the return value of the accessor. This would be specified by 
the use of a new option in the .kcfgc file, "UseEnumTypes=true". This option 
would be ignored unless GlobalEnums=false is also specified. The method 
signatures would become
    void setFoo( EnumFoo::type v );
    EnumFoo::type foo();

This option removes the need for application code to cast from int to enum.

2) the option to specify the name of the enum. The reason for this is that 
generated enum type names can currently be rather long and cumbersome, and 
the new option would allow shorter enum names to be used, and possibly for 
the names to be more understandable in the context of the application code. 
Again, this option would be ignored unless GlobalEnums=false is specified. 
The option is specified using an optional parameter to the <choices> element:
    <choices enum="Bar">

When this option is used, the generated enum class would be "Bar". A typedef 
will also be generated:
    typedef Bar::type BarEnum;

When used together with UseEnumTypes=true, the method signatures would become:
    void setFoo( BarEnum v );
    BarEnum foo();


I attach a patch - is it okay to apply? If so, I'll also amend the KConfig_XT 
tutorial on developernew.kde.org for KDE 4.

-- 
David Jarvie.
KAlarm author and maintainer.
http://www.astrojar.org.uk/linux/kalarm.html

["diff" (text/x-diff)]

Index: kcfg.xsd
===================================================================
--- kcfg.xsd	(revision 633699)
+++ kcfg.xsd	(working copy)
@@ -94,6 +94,8 @@
                                                         </xsd:complexType>
                                                     </xsd:element>
                                                 </xsd:sequence>
+                                                <xsd:attribute name="enum" \
use="optional" type="xsd:string"/> +
                                             </xsd:complexType>
                                         </xsd:element>
                                         
Index: kconfig_compiler.cpp
===================================================================
--- kconfig_compiler.cpp	(revision 633699)
+++ kconfig_compiler.cpp	(working copy)
@@ -95,6 +95,7 @@
 }
 
 bool globalEnums;
+bool useEnumTypes;
 bool itemAccessors;
 bool dpointer;
 QStringList allNames;
@@ -124,11 +125,16 @@
       QString label;
       QString whatsThis;
     };
+    struct Choices
+    {
+      QString name;
+      QList<Choice> choices;
+    };
 
     CfgEntry( const QString &group, const QString &type, const QString &key,
               const QString &name, const QString &label,
               const QString &whatsThis, const QString &code,
-              const QString &defaultValue, const QList<Choice> &choices, const \
QList<Signal> signalList, +              const QString &defaultValue, const Choices \
&choices, const QList<Signal> signalList,  bool hidden )
       : mGroup( group ), mType( type ), mKey( key ), mName( name ),
         mLabel( label ), mWhatsThis( whatsThis ), mCode( code ),
@@ -176,8 +182,8 @@
     void setParamType( const QString &d ) { mParamType = d; }
     QString paramType() const { return mParamType; }
 
-    void setChoices( const QList<Choice> &d ) { mChoices = d; }
-    QList<Choice> choices() const { return mChoices; }
+    void setChoices( const QList<Choice> &d, const QString &n ) { mChoices.choices = \
d; mChoices.name = n; } +    Choices choices() const { return mChoices; }
 
     void setParamValues( const QStringList &d ) { mParamValues = d; }
     QStringList paramValues() const { return mParamValues; }
@@ -230,7 +236,7 @@
     QString mParam;
     QString mParamName;
     QString mParamType;
-    QList<Choice> mChoices;
+    Choices mChoices;
     QList<Signal> mSignalList;
     QStringList mParamValues;
     QStringList mParamDefaultValues;
@@ -275,13 +281,44 @@
   return result;
 }
 
-static QString enumName(const QString &n)
+static QString enumPrefix(const QString &n)
 {
   QString result = "Enum"+n;
   result[4] = result[4].toUpper();
   return result;
 }
 
+static QString enumName(const QString &n, const CfgEntry::Choices &c)
+{
+  QString result;
+  if ( c.name.isEmpty() )
+  {
+    result = "Enum" + n;
+    result[4] = result[4].toUpper();
+  }
+  else
+    result = c.name;
+  return result;
+}
+
+static QString enumName(const CfgEntry *e)
+{
+  return enumName(e->name(), e->choices());
+}
+
+static QString enumType(const CfgEntry *e)
+{
+  QString result;
+  if ( e->choices().name.isEmpty() )
+  {
+    result = "Enum" + e->name() + "::type";
+    result[4] = result[4].toUpper();
+  }
+  else
+    result = e->choices().name + "Enum";
+  return result;
+}
+
 static QString setFunction(const QString &n, const QString &className = QString())
 {
   QString result = "set"+n;
@@ -363,7 +400,7 @@
 
 static void preProcessDefault( QString &defaultValue, const QString &name,
                                const QString &type,
-                               const QList<CfgEntry::Choice> &choices,
+                               const CfgEntry::Choices &choices,
                                QString &code )
 {
     if ( type == "String" && !defaultValue.isEmpty() ) {
@@ -400,9 +437,9 @@
     } else if ( type == "Enum" ) {
       if ( !globalEnums ) {
         QList<CfgEntry::Choice>::ConstIterator it;
-        for( it = choices.begin(); it != choices.end(); ++it ) {
+        for( it = choices.choices.begin(); it != choices.choices.end(); ++it ) {
           if ( (*it).name == defaultValue ) {
-            defaultValue.prepend( enumName(name) + "::");
+            defaultValue.prepend( enumName(name, choices) + "::");
             break;
           }
         }
@@ -442,7 +479,7 @@
   QString param;
   QString paramName;
   QString paramType;
-  QList<CfgEntry::Choice> choices;
+  CfgEntry::Choices choices;
   QList<Signal> signalList;
   QStringList paramValues;
   QStringList paramDefaultValues;
@@ -519,6 +556,7 @@
       }
     }
     else if ( tag == "choices" ) {
+      choices.name = e.attribute( "enum" );
       for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = \
e2.nextSiblingElement() ) {  if ( e2.tagName() == "choice" ) {
           CfgEntry::Choice choice;
@@ -530,7 +568,7 @@
             if ( e3.tagName() == "label" ) choice.label = e3.text();
             if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text();
           }
-          choices.append( choice );
+          choices.choices.append( choice );
         }
       }
     }
@@ -917,8 +955,13 @@
     QString n = e->name();
     QString t = e->type();
 
-    out << "return " << This << varPath(n);
+    out << "return ";
+    if (useEnumTypes && t == "Enum")
+      out << "static_cast<" << enumType(e) << ">(";
+    out << This << varPath(n);
     if (!e->param().isEmpty()) out << "[i]";
+    if (useEnumTypes && t == "Enum")
+      out << ")";
     out << ";" << endl;
 
     return result;
@@ -964,9 +1007,9 @@
       out << "QLatin1String( ";
 
       if (globalEnums)
-        out << enumName(e->param()) << "ToString[i]";
+        out << enumPrefix(e->param()) << "ToString[i]";
       else
-        out << enumName(e->param()) << "::enumToString[i]";
+        out << enumPrefix(e->param()) << "::enumToString[i]";
 
         out << " )";
     }
@@ -1076,6 +1119,7 @@
   bool setUserTexts = codegenConfig.value("SetUserTexts", false).toBool();
 
   globalEnums = codegenConfig.value("GlobalEnums", false).toBool();
+  useEnumTypes = !globalEnums && codegenConfig.value("UseEnumTypes", \
false).toBool();  
   dpointer = (memberVariables == "dpointer");
 
@@ -1262,7 +1306,8 @@
   // enums
   QList<CfgEntry*>::ConstIterator itEntry;
   for( itEntry = entries.begin(); itEntry != entries.end(); ++itEntry ) {
-    QList<CfgEntry::Choice> choices = (*itEntry)->choices();
+    QString choicesName = (*itEntry)->choices().name;
+    QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices;
     if ( !choices.isEmpty() ) {
       QStringList values;
       QList<CfgEntry::Choice>::ConstIterator itChoice;
@@ -1272,11 +1317,13 @@
       if ( globalEnums ) {
         h << "    enum { " << values.join( ", " ) << " };" << endl;
       } else {
-        h << "    class " << enumName( (*itEntry)->name() ) << endl;
+        h << "    class " << enumName( *itEntry ) << endl;
         h << "    {" << endl;
         h << "      public:" << endl;
         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
         h << "    };" << endl;
+        if ( !(*itEntry)->choices().name.isEmpty() )
+          h << "    typedef " << enumName( *itEntry ) << "::type " << enumType( \
*itEntry ) << ";" << endl;  }
     }
     QStringList values = (*itEntry)->paramValues();
@@ -1286,17 +1333,19 @@
         // make the following string table an index-based string search!
         // ###
         h << "    enum { " << values.join( ", " ) << " };" << endl;
-        h << "    static const char* const " << enumName( (*itEntry)->param() ) << \
                "ToString[];" << endl;
-        cppPreamble += "const char* const " + className + "::" + enumName( \
(*itEntry)->param() ) + +        h << "    static const char* const " << enumPrefix( \
(*itEntry)->param() ) << "ToString[];" << endl; +        cppPreamble += "const char* \
const " + className + "::" + enumPrefix( (*itEntry)->param() ) +  "ToString[] = { \"" \
+ values.join( "\", \"" ) + "\" };\n";  } else {
-        h << "    class " << enumName( (*itEntry)->param() ) << endl;
+        h << "    class " << enumName( *itEntry ) << endl;
         h << "    {" << endl;
         h << "      public:" << endl;
         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
         h << "      static const char* const enumToString[];" << endl;
         h << "    };" << endl;
-        cppPreamble += "const char* const " + className + "::" + enumName( \
(*itEntry)->param() ) + +        if ( !(*itEntry)->choices().name.isEmpty() )
+          h << "    typedef " << enumName( *itEntry ) << "::type " << enumType( \
*itEntry ) << ";" << endl; +        cppPreamble += "const char* const " + className + \
                "::" + enumPrefix( (*itEntry)->param() ) +
            "::enumToString[] = { \"" + values.join( "\", \"" ) + "\" };\n";
       }
     }
@@ -1358,7 +1407,11 @@
       h << "    void " << setFunction(n) << "( ";
       if (!(*itEntry)->param().isEmpty())
         h << cppType((*itEntry)->paramType()) << " i, ";
-      h << param( t ) << " v )";
+      if (useEnumTypes && t == "Enum")
+        h << enumType(*itEntry);
+      else
+        h << param( t );
+      h << " v )";
       // function body inline only if not using dpointer
       // for BC mode
       if ( !dpointer )
@@ -1379,7 +1432,12 @@
     h << "    */" << endl;
     if (staticAccessors)
       h << "    static" << endl;
-    h << "    " << cppType(t) << " " << getFunction(n) << "(";
+    h << "    ";
+    if (useEnumTypes && t == "Enum")
+      h << enumType(*itEntry);
+    else
+      h << cppType(t);
+    h << " " << getFunction(n) << "(";
     if (!(*itEntry)->param().isEmpty())
       h << " " << cppType((*itEntry)->paramType()) <<" i ";
     h << ")" << Const;
@@ -1689,7 +1747,7 @@
     if ( (*itEntry)->type() == "Enum" ) {
       cpp << "  QList<KConfigSkeleton::ItemEnum::Choice> values"
           << (*itEntry)->name() << ";" << endl;
-      QList<CfgEntry::Choice> choices = (*itEntry)->choices();
+      QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices;
       QList<CfgEntry::Choice>::ConstIterator it;
       for( it = choices.begin(); it != choices.end(); ++it ) {
         cpp << "  {" << endl;
@@ -1780,7 +1838,11 @@
         cpp << "void " << setFunction(n, className) << "( ";
         if ( !(*itEntry)->param().isEmpty() )
           cpp << cppType( (*itEntry)->paramType() ) << " i, ";
-        cpp << param( t ) << " v )" << endl;
+        if (useEnumTypes && t == "Enum")
+          cpp << enumType(*itEntry);
+        else
+          cpp << param( t );
+        cpp << " v )";
         // function body inline only if not using dpointer
         // for BC mode
         cpp << "{" << endl;
@@ -1789,7 +1851,11 @@
       }
 
       // Accessor
-      cpp << cppType(t) << " " << getFunction(n, className) << "(";
+      if (useEnumTypes && t == "Enum")
+        cpp << enumType(*itEntry);
+      else
+        cpp << cppType(t);
+      cpp << " " << getFunction(n, className) << "(";
       if ( !(*itEntry)->param().isEmpty() )
         cpp << " " << cppType( (*itEntry)->paramType() ) <<" i ";
       cpp << ")" << Const << endl;



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic