[glibmm] gmmproc, _WRAP_ENUM: Generate enum class; enums can be inside classes



commit 77c00208d07a74f4fdf185feb90017ae959f1763
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Tue Apr 11 19:31:33 2017 +0200

    gmmproc, _WRAP_ENUM: Generate enum class; enums can be inside classes
    
    Two modifications of _WRAP_ENUM:
      1. It is expanded to an enum class instead of a plain enum. It means that
      it can't be implicitly converted to an int, and that enumerator names are
      local to the enum.
    
      2. It can be located in a class, with some restrictions.
      When located in a class, and a Value specialization shall be generated
      (NO_GTYPE is not specified) or it's a Flags type (i.e. bitwise operators
      shall be generated), then the following requirements must be met:
      2.1. _WRAP_ENUM must be located in the public part of the class.
      2.2. The class must contain a class macro (_CLASS_GENERIC, _CLASS_GOBJECT,
           _CLASS_GTKOBJECT, etc.) before _WRAP_ENUM.
    
    Two new elements can be included in docs_override.xml files:
    substitute_type_name and substitute_enumerator_name. They improve the
    translation of C names to C++ names in documentation. See examples in
    glibmm and in gtkmm.
    
    Bug 86864

 tools/m4/convert_base.m4 |   14 +++++-
 tools/m4/convert_glib.m4 |   11 ++++
 tools/m4/enum.m4         |  120 +++++++++++++++++++++++++++++-----------------
 tools/pm/DocsParser.pm   |   94 +++++++++++++++++++++++++++++++++---
 tools/pm/Enum.pm         |   42 +++++++++++++---
 tools/pm/Output.pm       |   60 ++++++++++++++++-------
 tools/pm/WrapParser.pm   |   25 +++++++---
 7 files changed, 280 insertions(+), 86 deletions(-)
---
diff --git a/tools/m4/convert_base.m4 b/tools/m4/convert_base.m4
index 8d372fa..c560633 100644
--- a/tools/m4/convert_base.m4
+++ b/tools/m4/convert_base.m4
@@ -1,5 +1,3 @@
-dnl $Id$
-
 #
 #  Define a hashing for names
 #
@@ -52,6 +50,8 @@ define(`_EQUAL',`define(EV`'__HASH(`$1'),`$2')')
 
 
 define(`__ARG3__',`$`'3')
+
+# _CONV_ENUM(namespace, enum_name)
 define(`_CONV_ENUM',`dnl
 _CONVERSION(`$1$2', `$2', (($2)(__ARG3__)))
 _CONVERSION(`$1$2', `$1::$2', (($1::$2)(__ARG3__)))
@@ -59,6 +59,16 @@ _CONVERSION(`$2', `$1$2', (($1$2)(__ARG3__)))
 _CONVERSION(`$1::$2', `$1$2', (($1$2)(__ARG3__)))
 ')dnl
 
+# _CONV_INCLASS_ENUM(namespace, class_name, enum_name)
+define(`_CONV_INCLASS_ENUM',`dnl
+_CONVERSION(`$1$2$3', `$3', (($3)(__ARG3__)))
+_CONVERSION(`$1$2$3', `$2::$3', (($2::$3)(__ARG3__)))
+_CONVERSION(`$1$2$3', `$1::$2::$3', (($1::$2::$3)(__ARG3__)))
+_CONVERSION(`$3', `$1$2$3', (($1$2$3)(__ARG3__)))
+_CONVERSION(`$2::$3', `$1$2$3', (($1$2$3)(__ARG3__)))
+_CONVERSION(`$1::$2::$3', `$1$2$3', (($1$2$3)(__ARG3__)))
+')dnl
+
 # e.g. Glib::RefPtr<Gdk::Something> to GdkSomething*
 define(`__CONVERT_REFPTR_TO_P',`Glib::unwrap($`'3)')
 
diff --git a/tools/m4/convert_glib.m4 b/tools/m4/convert_glib.m4
index 0c70cdf..22711ab 100644
--- a/tools/m4/convert_glib.m4
+++ b/tools/m4/convert_glib.m4
@@ -1,6 +1,7 @@
 dnl
 dnl Glib C names have prefix 'G' but C++ namespace Glib
 dnl
+# _CONV_GLIB_ENUM(enum_name)
 define(`_CONV_GLIB_ENUM',`dnl
 _CONVERSION(`G$1', `$1', (($1)(__ARG3__)))
 _CONVERSION(`G$1', `Glib::$1', ((Glib::$1)(__ARG3__)))
@@ -8,6 +9,16 @@ _CONVERSION(`$1', `G$1', ((G$1)(__ARG3__)))
 _CONVERSION(`Glib::$1', `G$1', ((G$1)(__ARG3__)))
 ')dnl
 
+# _CONV_GLIB_INCLASS_ENUM(class_name, enum_name)
+define(`_CONV_GLIB_INCLASS_ENUM',`dnl
+_CONVERSION(`G$1$2', `$2', (($2)(__ARG3__)))
+_CONVERSION(`G$1$2', `$1::$2', (($1::$2)(__ARG3__)))
+_CONVERSION(`G$1$2', `Glib::$1::$2', ((Glib::$1::$2)(__ARG3__)))
+_CONVERSION(`$2', `G$1$2', ((G$1$2)(__ARG3__)))
+_CONVERSION(`$1::$2', `G$1$2', ((G$1$2)(__ARG3__)))
+_CONVERSION(`Glib::$1::$2', `G$1$2', ((G$1$2)(__ARG3__)))
+')dnl
+
 _EQUAL(gchar,char)
 _EQUAL(gchar*,char*)
 _EQUAL(gchar**,char**)
diff --git a/tools/m4/enum.m4 b/tools/m4/enum.m4
index 9064e35..5e908dc 100644
--- a/tools/m4/enum.m4
+++ b/tools/m4/enum.m4
@@ -1,13 +1,26 @@
 dnl
-dnl _ENUM(cpp_type, c_type, value_suffix, `element_list', `no_gtype', `optional_refdoc_comment', 
'deprecated')
-dnl          $1       $2         $3             $4           $5              $6                        $7
+dnl _ENUM(cpp_type, c_type, value_suffix, `element_list', `no_gtype', in_class,
+dnl          $1       $2         $3             $4           $5          $6
+dnl `optional_refdoc_comment', 'deprecated')
+dnl           $7                   $8
 dnl
 m4_define(`_ENUM',`dnl
 _PUSH()
 
+dnl Concerning __ENUM_CLASS_NOLINK__:
+dnl The percent signs prevent Doxygen from creating links in the html files.
+dnl If a % precedes the class name, another % must precede the enum name,
+dnl otherwise Doxygen removes the double colons.
+dnl Possibly the percent signs are unnecessary. Even without them Doxygen
+dnl version 1.7.1 does not create links from the enum descriptions.
+dnl Other versions may behave differently.
+
 m4_define(`__ENUM_CPPNAME__',`$1')
 m4_define(`__ENUM_CNAME__',`$2')
-m4_define(`__ENUM_VALUE_BASE__',`Glib::Value_$3<__NAMESPACE__::__ENUM_CPPNAME__>')
+m4_define(`__ENUM_CLASS_CPPNAME__',m4_ifelse($6,0,,`__CPPNAME__::')`__ENUM_CPPNAME__')
+m4_define(`__ENUM_CLASS_NOLINK__',m4_ifelse($6,0,,`%__CPPNAME__::')`%__ENUM_CPPNAME__')
+m4_define(`__ENUM_INDENT__',m4_ifelse($6,0,,`  '))
+m4_define(`__ENUM_VALUE_BASE__',`Glib::Value_$3<__NAMESPACE__::__ENUM_CLASS_CPPNAME__>')
 
 _POP()
 dnl
@@ -17,88 +30,107 @@ m4_ifdef(`__DOCGROUP_'__MODULE_CANONICAL__`_ENUMS__',,`dnl else
 m4_define(`__DOCGROUP_'__MODULE_CANONICAL__`_ENUMS__')dnl
 /** @addtogroup '__MODULE_CANONICAL__`Enums __MODULE_CANONICAL__ Enums and Flags */
 
-')dnl endif
+__ENUM_INDENT__')`'dnl endif
 dnl
 dnl
-ifelse(`$7',,,`_DEPRECATE_IFDEF_START')`'dnl The expansion of _DEPRECATE_IFDEF_START ends with a newline
-/** $6
- *
- * @ingroup __MODULE_CANONICAL__`'Enums
-m4_ifelse($3,Flags,`dnl
- * @par Bitwise operators:
- * <tt>%__ENUM_CPPNAME__ operator|(__ENUM_CPPNAME__, __ENUM_CPPNAME__)</tt><br>
- * <tt>%__ENUM_CPPNAME__ operator&(__ENUM_CPPNAME__, __ENUM_CPPNAME__)</tt><br>
- * <tt>%__ENUM_CPPNAME__ operator^(__ENUM_CPPNAME__, __ENUM_CPPNAME__)</tt><br>
- * <tt>%__ENUM_CPPNAME__ operator~(__ENUM_CPPNAME__)</tt><br>
- * <tt>%__ENUM_CPPNAME__& operator|=(__ENUM_CPPNAME__&, __ENUM_CPPNAME__)</tt><br>
- * <tt>%__ENUM_CPPNAME__& operator&=(__ENUM_CPPNAME__&, __ENUM_CPPNAME__)</tt><br>
- * <tt>%__ENUM_CPPNAME__& operator^=(__ENUM_CPPNAME__&, __ENUM_CPPNAME__)</tt><br>
+ifelse(`$8',,,`_DEPRECATE_IFDEF_START'`'__ENUM_INDENT__)`'dnl The expansion of _DEPRECATE_IFDEF_START ends 
with a newline
+/** $7
+__ENUM_INDENT__ *
+__ENUM_INDENT__ * @ingroup __MODULE_CANONICAL__`'Enums
+m4_ifelse($3,`Flags',`dnl
+__ENUM_INDENT__ * @par Bitwise operators:
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__ operator|(__ENUM_CLASS_CPPNAME__, 
__ENUM_CLASS_CPPNAME__)</tt><br>
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__ operator&(__ENUM_CLASS_CPPNAME__, 
__ENUM_CLASS_CPPNAME__)</tt><br>
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__ operator^(__ENUM_CLASS_CPPNAME__, 
__ENUM_CLASS_CPPNAME__)</tt><br>
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__ operator~(__ENUM_CLASS_CPPNAME__)</tt><br>
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__& operator|=(__ENUM_CLASS_CPPNAME__&, 
__ENUM_CLASS_CPPNAME__)</tt><br>
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__& operator&=(__ENUM_CLASS_CPPNAME__&, 
__ENUM_CLASS_CPPNAME__)</tt><br>
+__ENUM_INDENT__ * <tt>__ENUM_CLASS_NOLINK__& operator^=(__ENUM_CLASS_CPPNAME__&, 
__ENUM_CLASS_CPPNAME__)</tt><br>
 ')dnl endif
- */
-enum __ENUM_CPPNAME__
-{
+__ENUM_INDENT__ */
+__ENUM_INDENT__`'enum class __ENUM_CPPNAME__
+__ENUM_INDENT__{
 $4
-};
-m4_ifelse($3,Flags,`dnl
+__ENUM_INDENT__};
+m4_ifelse($3,`Flags',`dnl
+m4_ifelse($6,0,,`dnl  in_class
+_PUSH(SECTION_HEADER3)
+__NAMESPACE_BEGIN__
+ifelse(`$8',,,`_DEPRECATE_IFDEF_START')`'dnl
+')dnl endif
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__ operator|(__ENUM_CPPNAME__ lhs, __ENUM_CPPNAME__ rhs)
-  { return static_cast<__ENUM_CPPNAME__>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)); }
+inline __ENUM_CLASS_CPPNAME__ operator|(__ENUM_CLASS_CPPNAME__ lhs, __ENUM_CLASS_CPPNAME__ rhs)
+  { return static_cast<__ENUM_CLASS_CPPNAME__>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)); }
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__ operator&(__ENUM_CPPNAME__ lhs, __ENUM_CPPNAME__ rhs)
-  { return static_cast<__ENUM_CPPNAME__>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)); }
+inline __ENUM_CLASS_CPPNAME__ operator&(__ENUM_CLASS_CPPNAME__ lhs, __ENUM_CLASS_CPPNAME__ rhs)
+  { return static_cast<__ENUM_CLASS_CPPNAME__>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)); }
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__ operator^(__ENUM_CPPNAME__ lhs, __ENUM_CPPNAME__ rhs)
-  { return static_cast<__ENUM_CPPNAME__>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)); }
+inline __ENUM_CLASS_CPPNAME__ operator^(__ENUM_CLASS_CPPNAME__ lhs, __ENUM_CLASS_CPPNAME__ rhs)
+  { return static_cast<__ENUM_CLASS_CPPNAME__>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)); }
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__ operator~(__ENUM_CPPNAME__ flags)
-  { return static_cast<__ENUM_CPPNAME__>(~static_cast<unsigned>(flags)); }
+inline __ENUM_CLASS_CPPNAME__ operator~(__ENUM_CLASS_CPPNAME__ flags)
+  { return static_cast<__ENUM_CLASS_CPPNAME__>(~static_cast<unsigned>(flags)); }
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__& operator|=(__ENUM_CPPNAME__& lhs, __ENUM_CPPNAME__ rhs)
-  { return (lhs = static_cast<__ENUM_CPPNAME__>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs))); }
+inline __ENUM_CLASS_CPPNAME__& operator|=(__ENUM_CLASS_CPPNAME__& lhs, __ENUM_CLASS_CPPNAME__ rhs)
+  { return (lhs = static_cast<__ENUM_CLASS_CPPNAME__>(static_cast<unsigned>(lhs) | 
static_cast<unsigned>(rhs))); }
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__& operator&=(__ENUM_CPPNAME__& lhs, __ENUM_CPPNAME__ rhs)
-  { return (lhs = static_cast<__ENUM_CPPNAME__>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs))); }
+inline __ENUM_CLASS_CPPNAME__& operator&=(__ENUM_CLASS_CPPNAME__& lhs, __ENUM_CLASS_CPPNAME__ rhs)
+  { return (lhs = static_cast<__ENUM_CLASS_CPPNAME__>(static_cast<unsigned>(lhs) & 
static_cast<unsigned>(rhs))); }
 
 /** @ingroup __MODULE_CANONICAL__`'Enums */
-inline __ENUM_CPPNAME__& operator^=(__ENUM_CPPNAME__& lhs, __ENUM_CPPNAME__ rhs)
-  { return (lhs = static_cast<__ENUM_CPPNAME__>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs))); }
-')dnl endif Flags
-ifelse(`$7',,,`_DEPRECATE_IFDEF_END')`'dnl The expansion of _DEPRECATE_IFDEF_END ends with a newline
+inline __ENUM_CLASS_CPPNAME__& operator^=(__ENUM_CLASS_CPPNAME__& lhs, __ENUM_CLASS_CPPNAME__ rhs)
+  { return (lhs = static_cast<__ENUM_CLASS_CPPNAME__>(static_cast<unsigned>(lhs) ^ 
static_cast<unsigned>(rhs))); }
+m4_ifelse($6,0,,`dnl  in_class
+ifelse(`$8',,,`_DEPRECATE_IFDEF_END')`'dnl
+__NAMESPACE_END__
+_POP()
+')dnl endif
+')dnl endif !NO_OPERATORS
+
+ifelse(`$8',,,`_DEPRECATE_IFDEF_END')`'dnl The expansion of _DEPRECATE_IFDEF_END ends with a newline
 
 m4_ifelse($5,`NO_GTYPE',,`dnl else
+m4_ifelse($6,0,`dnl  not in_class
 __NAMESPACE_END__
+',`dnl else
+_PUSH(SECTION_HEADER3)
+')dnl endif
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 namespace Glib
 {
 
-ifelse(`$7',,,`_DEPRECATE_IFDEF_START')`'dnl
+ifelse(`$8',,,`_DEPRECATE_IFDEF_START')`'dnl
 template <>
-class Value<__NAMESPACE__::__ENUM_CPPNAME__> : public __ENUM_VALUE_BASE__
+class Value<__NAMESPACE__::__ENUM_CLASS_CPPNAME__> : public __ENUM_VALUE_BASE__
 {
 public:
   static GType value_type() G_GNUC_CONST;
 };
-ifelse(`$7',,,`_DEPRECATE_IFDEF_END')`'dnl
+ifelse(`$8',,,`_DEPRECATE_IFDEF_END')`'dnl
 
 } // namespace Glib
 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
 
+m4_ifelse($6,0,`dnl  not in_class
 __NAMESPACE_BEGIN__
+',`dnl else
+_POP()
+')dnl endif
 _PUSH(SECTION_SRC_GENERATED)
-ifelse(`$7',,,`_DEPRECATE_IFDEF_START')`'dnl
+ifelse(`$8',,,`_DEPRECATE_IFDEF_START')`'dnl
 // static
-GType Glib::Value<__NAMESPACE__::__ENUM_CPPNAME__>::value_type()
+GType Glib::Value<__NAMESPACE__::__ENUM_CLASS_CPPNAME__>::value_type()
 {
   return _GET_TYPE_FUNC(__ENUM_CNAME__);
 }
-ifelse(`$7',,,`_DEPRECATE_IFDEF_END')`'dnl
+ifelse(`$8',,,`_DEPRECATE_IFDEF_END')`'dnl
 
 _POP()
 ')dnl endif !NO_GTYPE
diff --git a/tools/pm/DocsParser.pm b/tools/pm/DocsParser.pm
index ccc512f..93928be 100644
--- a/tools/pm/DocsParser.pm
+++ b/tools/pm/DocsParser.pm
@@ -24,6 +24,7 @@ package DocsParser;
 use XML::Parser;
 use strict;
 use warnings;
+use feature 'state';
 
 use Util;
 use Function;
@@ -61,6 +62,9 @@ $DocsParser::currentParam = undef;
 
 $DocsParser::objCurrentFunction = undef; #Function
 %DocsParser::hasharrayFunctions = (); #Function elements
+%DocsParser::type_names = (); # Type names (e.g. enums) with non-standard C-to-C++ translation.
+%DocsParser::enumerator_name_prefixes = (); # Enumerator name prefixes with non-standard C-to-C++ 
translation.
+%DocsParser::enumerator_names = (); # Enumerator names with non-standard C-to-C++ translation.
 
 $DocsParser::commentStart = "  /** ";
 $DocsParser::commentMiddleStart = "   * ";
@@ -89,7 +93,7 @@ sub read_defs($$$)
     return;
   }
 
-  # C++ overide documentation:
+  # C++ override documentation:
   $DocsParser::CurrentFile = $path . '/' . $filename_override;
 
   # It is not an error if the documentation override file does not exist.
@@ -177,6 +181,21 @@ sub parse_on_start($$%)
   {
     $$DocsParser::objCurrentFunction{mapped_class} = $attr{class};
   }
+  elsif($tag eq "substitute_type_name")
+  {
+    $DocsParser::type_names{$attr{from}} = $attr{to};
+  }
+  elsif($tag eq "substitute_enumerator_name")
+  {
+    if (exists $attr{from_prefix})
+    {
+      $DocsParser::enumerator_name_prefixes{$attr{from_prefix}} = $attr{to_prefix};
+    }
+    if (exists $attr{from})
+    {
+      $DocsParser::enumerator_names{$attr{from}} = $attr{to};
+    }
+  }
   elsif($tag ne "root")
   {
     $objParser->xpcroak("\nUnknown tag \"$tag\".");
@@ -769,14 +788,12 @@ sub substitute_identifiers($$)
     s/(^|\s)::([a-z\d-]+)(\(\))*([^:\w]|$)/my $name = "$1signal_$2()$4"; $name =~ s"-"_"g; "$name";/ge;
     s/(#[A-Z]\w+)::([a-z\d-]+)(\(\))*([^:\w]|$)/my $name = "$1::signal_$2()$4"; $name =~ s"-"_"g; 
"$name";/ge;
 
-    s/[#%]([A-Z][a-z]*)([A-Z][A-Za-z]+)\b/$1::$2/g; # type names
+    # Type names
+    s/[#%]([A-Z][a-z]*)([A-Z][A-Za-z]+)\b/&DocsParser::substitute_type_name($1, $2)/eg;
 
-    s/[#%]([A-Z])([A-Z]*)_([A-Z\d_]+)\b/$1\L$2\E::$3/g; # enum values
+    # Enumerator names
+    s/[#%]([A-Z]+)_([A-Z\d_]+)\b/&DocsParser::substitute_enumerator_name($1, $2)/eg;
 
-    # Undo wrong substitutions.
-    s/\bHas::/HAS_/g;
-    s/\bNo::/NO_/g;
-    s/\bO::/O_/g;
     s/\bG:://g; #Rename G::Something to Something.
 
     # Substitute callback types to slot types.
@@ -787,6 +804,69 @@ sub substitute_identifiers($$)
   }
 }
 
+sub substitute_type_name($$)
+{
+  my ($module, $name) = @_;
+  my $c_name = $module . $name;
+
+  if (exists $DocsParser::type_names{$c_name})
+  {
+    return $DocsParser::type_names{$c_name};
+  }
+  #print "DocsParser.pm: Assuming the type $c_name shall become " . (($module eq "G") ? "" : "${module}::") 
. "$name.\n";
+  return $module . "::" . $name;
+}
+
+sub substitute_enumerator_name($$)
+{
+  state $first_call = 1;
+  state @sorted_keys;
+
+  my ($module, $name) = @_;
+  my $c_name = $module . "_" . $name;
+
+  if (exists $DocsParser::enumerator_names{$c_name})
+  {
+    return $DocsParser::enumerator_names{$c_name};
+  }
+
+  if ($first_call)
+  {
+    # Sort only once, on the first call.
+    # "state @sorted_keys = ...;" is not possible. Only a scalar variable
+    # can have a one-time assignment in its defining "state" statement.
+    $first_call = 0;
+    @sorted_keys = reverse sort keys(%DocsParser::enumerator_name_prefixes);
+  }
+
+  # This is a linear search through the keys of %DocsParser::enumerator_name_prefixes.
+  # It's inefficient if %DocsParser::enumerator_name_prefixes contains many values.
+  #
+  # If one key is part of another key (e.g. G_REGEX_MATCH_ and G_REGEX_),
+  # search for a match against the longer key before the shorter key.
+  foreach my $key (@sorted_keys)
+  {
+    if ($c_name =~ m/^$key/)
+    {
+      # $c_name begins with $key. Replace that part of $c_name with the C++ analogue.
+      $c_name =~ s/^$key/$DocsParser::enumerator_name_prefixes{$key}/;
+      return $c_name; # Now it's the C++ name.
+    }
+  }
+
+  # Don't apply the default substitution to these module names.
+  # They are not really modules.
+  if (grep {$module eq $_} qw(HAS NO O SO AF))
+  {
+    return $c_name;
+  }
+
+  my $cxx_name = (($module eq "G") ? "" : (ucfirst(lc($module)) . "::")) . $name;
+
+  print "DocsParser.pm: Assuming the enumerator $c_name shall become $cxx_name.\n";
+
+  return $cxx_name;
+}
 
 sub substitute_function($$)
 {
diff --git a/tools/pm/Enum.pm b/tools/pm/Enum.pm
index ceb705c..c1bdc3c 100644
--- a/tools/pm/Enum.pm
+++ b/tools/pm/Enum.pm
@@ -26,6 +26,7 @@ our @EXPORT_OK;
 #       string module;
 #       string c_type;
 #
+#       string array elem_short_names;
 #       string array elem_names;
 #       string array elem_values;
 #       string c_prefix;
@@ -147,6 +148,7 @@ sub new
   $$self{flags} = 0;
   $$self{c_prefix} = "";
 
+  $$self{elem_short_names}  = [];
   $$self{elem_names}  = [];
   $$self{elem_values} = [];
 
@@ -173,6 +175,7 @@ sub new
   }
 
   # this should never happen
+  warn if(scalar(@{$$self{elem_short_names}}) != scalar(@{$$self{elem_values}}));
   warn if(scalar(@{$$self{elem_names}}) != scalar(@{$$self{elem_values}}));
 
   return $self;
@@ -182,6 +185,7 @@ sub parse_values($$)
 {
   my ($self, $value) = @_;
 
+  my $elem_short_names  = [];
   my $elem_names  = [];
   my $elem_values = [];
   my $common_prefix = undef;
@@ -189,9 +193,9 @@ sub parse_values($$)
   # and handles triples like '("dq-token", "MY_SCANNER_DQ_TOKEN", "'"'").
   foreach (split_enum_tokens($value))
   {
-    if (/^"\S+" "(\S+)" "(.+)"$/)
+    if (/^"(\S+)" "(\S+)" "(.+)"$/)
     {
-      my ($name, $value) = ($1, $2);
+      my ($nick_name, $name, $value) = ($1, $2, $3);
 
       # detect whether there is module prefix common to all names, e.g. GTK_
       my $prefix = $1 if ($name =~ /^([^_]+_)/);
@@ -205,6 +209,16 @@ sub parse_values($$)
         $common_prefix = "";
       }
 
+      # enum.pl generates nick names from the C names of the enum constants.
+      # A nick name consists of the trailing part of the enum name.
+      # The leading part which is common for each constant of an enum type
+      # has been removed. The remaining part is then tranform to lowercase
+      # and hyphens.
+      # Transform the nick name with lowercase letters and hyphens
+      # back to a short name with uppercase letters and underscores.
+      # The short names are suitable for 'enum class' definitions.
+      $nick_name =~ tr/a-z-/A-Z_/;
+      push(@$elem_short_names, $nick_name);
       push(@$elem_names, $name);
       push(@$elem_values, $value);
     }
@@ -223,17 +237,18 @@ sub parse_values($$)
     $$self{c_prefix}  = $common_prefix;
   }
 
+  $$self{elem_short_names}  = $elem_short_names;
   $$self{elem_names}  = $elem_names;
   $$self{elem_values} = $elem_values;
 }
 
-sub beautify_values($)
+sub beautify_values($$)
 {
-  my ($self) = @_;
+  my ($self, $use_short_names) = @_;
 
   return if($$self{flags});
 
-  my $elem_names  = $$self{elem_names};
+  my $elem_names  = $use_short_names ? $$self{elem_short_names} : $$self{elem_names};
   my $elem_values = $$self{elem_values};
 
   my $num_elements = scalar(@$elem_values);
@@ -277,9 +292,9 @@ sub beautify_values($)
 
 sub build_element_list($$$$)
 {
-  my ($self, $ref_subst_in, $ref_subst_out, $indent) = @_;
+  my ($self, $use_short_names, $ref_subst_in, $ref_subst_out, $indent) = @_;
 
-  my $elem_names  = $$self{elem_names};
+  my $elem_names  = $use_short_names ? $$self{elem_short_names} : $$self{elem_names};
   my $elem_values = $$self{elem_values};
 
   my $num_elements = scalar(@$elem_names);
@@ -307,6 +322,19 @@ sub build_element_list($$$$)
   return $elements;
 }
 
+# The name prefix is defined by: $name_prefix . $short_name eq $name
+# I.e. what shall be chopped off the name to get the short name.
+sub get_name_prefix($)
+{
+  my ($self) = @_;
+
+  my $name = ${$$self{elem_names}}[0];
+  my $short_name = ${$$self{elem_short_names}}[0];
+  my $prefix_length = length($name) - length($short_name);
+
+  return substr($name, 0, $prefix_length);
+}
+
 sub dump($)
 {
   my ($self) = @_;
diff --git a/tools/pm/Output.pm b/tools/pm/Output.pm
index b920791..d266e63 100644
--- a/tools/pm/Output.pm
+++ b/tools/pm/Output.pm
@@ -690,12 +690,12 @@ sub output_wrap_sig_decl($$$$$$$$$$$$$$)
 }
 
 # void output_wrap_enum($filename, $line_num, $cpp_type, $c_type,
-#   $comment, $ref_subst_in, $ref_subst_out, $no_gtype,
+#   $comment, $ref_subst_in, $ref_subst_out, $no_gtype, $in_class,
 #   $deprecated, $deprecation_docs, $newin)
-sub output_wrap_enum($$$$$$$$$$$$)
+sub output_wrap_enum($$$$$$$$$$$$$)
 {
   my ($self, $filename, $line_num, $cpp_type, $c_type,
-    $comment, $ref_subst_in, $ref_subst_out, $no_gtype,
+    $comment, $ref_subst_in, $ref_subst_out, $no_gtype, $in_class,
     $deprecated, $deprecation_docs, $newin) = @_;
 
   my $objEnum = GtkDefs::lookup_enum($c_type);
@@ -705,9 +705,11 @@ sub output_wrap_enum($$$$$$$$$$$$)
     return;
   }
 
-  $objEnum->beautify_values();
+  $objEnum->beautify_values(1);
 
-  my $elements = $objEnum->build_element_list($ref_subst_in, $ref_subst_out, "  ");
+  my $indent = "  ";
+  $indent .= "  " if ($in_class);
+  my $elements = $objEnum->build_element_list(1, $ref_subst_in, $ref_subst_out, $indent);
 
   if(!$elements)
   {
@@ -715,37 +717,57 @@ sub output_wrap_enum($$$$$$$$$$$$)
     return;
   }
 
-  my $value_suffix = "Enum";
-  $value_suffix = "Flags" if($$objEnum{flags});
+  # Chop off the name prefix in the documentation.
+  my $name_prefix = $objEnum->get_name_prefix();
+  unshift(@$ref_subst_in, "^$name_prefix");
+  unshift(@$ref_subst_out, "");
 
   # Get the enum documentation from the parsed docs.
+  $indent = " ";
+  $indent .= "  " if ($in_class);
   my $enum_docs = DocsParser::lookup_enum_documentation("$c_type", "$cpp_type",
-    " ", $ref_subst_in, $ref_subst_out, $deprecation_docs, $newin);
+    $indent, $ref_subst_in, $ref_subst_out, $deprecation_docs, $newin);
 
   # Merge the passed in comment to the existing enum documentation.
-  $comment .= "\n * " . $enum_docs if $enum_docs ne "";
+  $comment .= "\n$indent* $enum_docs" if $enum_docs ne "";
+
+  my $value_suffix = "Enum";
+  $value_suffix = "Flags" if ($$objEnum{flags});
 
-  my $str = sprintf("_ENUM(%s,%s,%s,\`%s\',\`%s\',\`%s\',\`%s\')dnl\n",
+  my $str = sprintf("_ENUM(%s,%s,%s,\`%s\',\`%s\',%d,\`%s\',\`%s\')dnl\n",
     $cpp_type,
     $c_type,
     $value_suffix,
     $elements,
     $no_gtype,
+    $in_class,
     $comment,
     $deprecated
   );
-
   $self->append($str);
 }
 
-sub output_wrap_enum_docs_only($$$$$$$$$$$)
+sub output_wrap_enum_docs_only($$$$$$$$$$$$)
 {
   my ($self, $filename, $line_num, $module_canonical, $cpp_type, $c_type,
-    $comment, $ref_subst_in, $ref_subst_out, $deprecation_docs, $newin) = @_;
+    $comment, $ref_subst_in, $ref_subst_out, $in_class, $deprecation_docs, $newin) = @_;
+
+  my $objEnum = GtkDefs::lookup_enum($c_type);
+  if(!$objEnum)
+  {
+    $self->output_wrap_failed($c_type, "enum defs lookup failed.");
+    return;
+  }
+  # Chop off the name prefix in the documentation.
+  my $name_prefix = $objEnum->get_name_prefix();
+  unshift(@$ref_subst_in, "^$name_prefix");
+  unshift(@$ref_subst_out, "");
 
-  # Get the existing enum description from the parsed docs.
+  # Get the enum documentation from the parsed docs.
+  my $indent = " ";
+  $indent .= "  " if ($in_class);
   my $enum_docs = DocsParser::lookup_enum_documentation("$c_type", "$cpp_type",
-    " ", $ref_subst_in, $ref_subst_out, $deprecation_docs, $newin);
+    $indent, $ref_subst_in, $ref_subst_out, $deprecation_docs, $newin);
 
   if($enum_docs eq "")
   {
@@ -754,10 +776,10 @@ sub output_wrap_enum_docs_only($$$$$$$$$$$)
   }
 
   # Include the enum docs in the module's enum docs group.
-  $enum_docs .= "\n *\n * \@ingroup ${module_canonical}Enums";
+  $enum_docs .= "\n$indent*\n$indent* \@ingroup ${module_canonical}Enums";
 
   # Merge the passed in comment to the existing enum documentation.
-  $comment = "/** " . $comment . "\n * " . $enum_docs . "\n */\n";
+  $comment = "/** " . $comment . "\n$indent* " . $enum_docs . "\n$indent*/\n";
 
   $self->append($comment);
 }
@@ -783,7 +805,7 @@ sub output_wrap_gerror($$$$$$$$$$$$$)
   # Shouldn't happen, and if it does, I'd like to know that.
   warn if($$objEnum{flags});
 
-  $objEnum->beautify_values();
+  $objEnum->beautify_values(0);
 
   # cut off the module prefix, e.g. GDK_
   my $prefix = $domain;
@@ -793,7 +815,7 @@ sub output_wrap_gerror($$$$$$$$$$$$$)
   unshift(@$ref_subst_in, "^${prefix}_");
   unshift(@$ref_subst_out, "");
 
-  my $elements = $objEnum->build_element_list($ref_subst_in, $ref_subst_out, "    ");
+  my $elements = $objEnum->build_element_list(0, $ref_subst_in, $ref_subst_out, "    ");
 
   # Get the enum documentation from the parsed docs.
   my $enum_docs = DocsParser::lookup_enum_documentation("$c_type", "Code",
diff --git a/tools/pm/WrapParser.pm b/tools/pm/WrapParser.pm
index 3f71ece..829f9b1 100644
--- a/tools/pm/WrapParser.pm
+++ b/tools/pm/WrapParser.pm
@@ -1449,11 +1449,6 @@ sub on_wrap_any_enum($$)
     {
       $no_gtype = "NO_GTYPE";
     }
-    elsif ($arg =~ /^(get_type_func=)(\s*)$/)
-    {
-      my $part1 = $1;
-      my $part2 = $2;
-    }
     elsif ($arg =~ /^s#([^#]+)#([^#]*)#$/)
     {
       push(@subst_in,  $1);
@@ -1477,6 +1472,22 @@ sub on_wrap_any_enum($$)
     $argDeprecated, $deprecation_docs, $newin);
 }
 
+# void on_wrap_enum()
+# _WRAP_ENUM(cpp_type, c_type [,NO_GTYPE] [,s#regexpr#subst#]*)
+# Optional arguments:
+# NO_GTYPE Don't generate code for a specialization of the template
+#          Glib::Value_Enum or Glib::Value_Flags.
+#          Necessary, if the C type enum is not registered as a GType.
+# s#regexpr#subst# Zero or more substitutions in names of enum constants, e.g. s#^DATE_##.
+#
+# _WRAP_ENUM can be located either in a class or outside all classes.
+# When located in a class, and Value specialization shall be generated or it's
+# a Flags type (i.e. bitwise operators shall be generated), then the following
+# requirements must be fulfilled:
+# 1. _WRAP_ENUM must be located in the public part of the class.
+# 2. The class must contain a class macro (_CLASS_GENERIC, _CLASS_GOBJECT,
+#    _CLASS_GTKOBJECT, etc.) before _WRAP_ENUM.
+#
 sub on_wrap_enum($)
 {
   my ($self) = @_;
@@ -1491,7 +1502,7 @@ sub on_wrap_enum($)
 
   $$self{objOutputter}->output_wrap_enum(
     $$self{filename}, $$self{line_num}, $cpp_type, $c_type,
-    $comment, $ref_subst_in, $ref_subst_out, $no_gtype,
+    $comment, $ref_subst_in, $ref_subst_out, $no_gtype, $$self{in_class},
     $argDeprecated, $deprecation_docs, $newin);
 }
 
@@ -1513,7 +1524,7 @@ sub on_wrap_enum_docs_only($)
 
   $$self{objOutputter}->output_wrap_enum_docs_only(
     $$self{filename}, $$self{line_num}, $module_canonical, $cpp_type, $c_type,
-    $comment, $ref_subst_in, $ref_subst_out, $deprecation_docs, $newin);
+    $comment, $ref_subst_in, $ref_subst_out, $$self{in_class}, $deprecation_docs, $newin);
 }
 
 sub on_wrap_gerror($)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]