[glibmm] gmmproc, _WRAP_ENUM: Generate enum class; enums can be inside classes
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glibmm] gmmproc, _WRAP_ENUM: Generate enum class; enums can be inside classes
- Date: Tue, 11 Apr 2017 17:38:19 +0000 (UTC)
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]