Add support for "[not]regexmatch" and "regextarget" to %rename.

"regexmatch" and "notregexmatch" can be used with anonymous %renames in the
same way as "match" and "notmatch" while "regextarget" specifies that the
argument of a non-anonymous %rename should be interpreted as a regular
expression.

Document the new functions.

Also add a new unit test for %regex also testing regexmatch &c and provide
test code for C# and Java verifying that it works as intended.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12174 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Vadim Zeitlin 2010-07-22 17:02:10 +00:00
parent 48a2e0bdea
commit 70c5bb5a47
7 changed files with 216 additions and 8 deletions

View File

@ -9,6 +9,24 @@ Version 2.0.1 (in progress)
Fix wrapping of function pointers and member function pointers when the function
returns by reference.
2010-07-13: vadz
Add "regexmatch", "regextarget" and "notregexmatch" which can be
used to apply %rename directives to the declarations matching the
specified regular expression only. The first two can be used
interchangeably, both of the %renames below do the same thing:
%rename("$ignore", regexmatch$name="Old$") "";
%rename("$ignore", regextarget=1) "Old$";
(namely ignore the declarations having "Old" suffix).
"notregexmatch" restricts the match to only the declarations which
do not match the regular expression, e.g. here is how to rename to
lower case versions all declarations except those consisting from
capital letters only:
%rename("$(lower)s", notregexmatch$name="^[A-Z]+$") "";
2010-07-13: vadz
Add the new "regex" encoder that can be used in %rename, e.g.

View File

@ -1949,10 +1949,12 @@ can be used to achieve the same effect as the simpler
</pre>
</div>
<p>
However <tt>match</tt> can also be applied to the declaration type, for
example <tt>match="class"</tt> restricts the match to class declarations only
(in C++) and <tt>match="enumitem"</tt> restricts it to the enum elements. SWIG
also provides convenience macros for such match expressions, for example
and so is not very interesting on its own. However <tt>match</tt> can also be
applied to the declaration type, for example <tt>match="class"</tt> restricts
the match to class declarations only (in C++) and <tt>match="enumitem"</tt>
restricts it to the enum elements. SWIG also provides convenience macros for
such match expressions, for example
</p>
<div class="code">
<pre>
%rename("%(title)s", %$isenumitem) "";
@ -1983,7 +1985,40 @@ to rename all enums nested in the given class to lower case.
</p>
<p>
Finally, even more powerful variants of <tt>%rename</tt> and <tt>%ignore</tt> directives can be used to help
And in addition to literally matching some string with <tt>match</tt> you can
also use <tt>regexmatch</tt> or <tt>notregexmatch</tt>to match a string
against a regular expression. For example, to ignore all functions having
"Old" suffix you could use
</p>
<div class="code">
<pre>
%rename("$ignore", regexmatch$name="Old$") "";
</pre>
</div>
<p>
For simple cases like this, specifying the regular expression for the
declaration name directly can be preferable and can be done using
<tt>regextarget</tt>:
</p>
<div class="code">
<pre>
%rename("$ignore", regextarget=1) "Old$";
</pre>
</div>
<p>
As for <tt>notregexmatch</tt>, it restricts the match only to the strings not
matching the specified regular expression. So to rename to lower case versions
all declarations except those consisting from capital letters only:
</p>
<div class="code">
<pre>
%rename("$(lower)s", notregexmatch$name="^[A-Z]+$") "";
</pre>
</div>
<p>
Finally, variants of <tt>%rename</tt> and <tt>%ignore</tt> directives can be used to help
wrap C++ overloaded functions and methods or C++ methods which use default arguments. This is described in the
<a href="SWIGPlus.html#SWIGPlus_ambiguity_resolution_renaming">Ambiguity resolution and renaming</a> section in the C++ chapter.
</p>

View File

@ -285,6 +285,7 @@ CPP_TEST_CASES += \
rename_scope \
rename_strip_encoder \
rename_pcre_encoder \
rename_pcre_enum \
restrict_cplusplus \
return_const_value \
return_value_scope \

View File

@ -0,0 +1,24 @@
using System;
using rename_pcre_enumNamespace;
public class runme {
static void Main() {
Foo foo = Foo.First;
if ( foo == Foo.Second )
throw new Exception("Enum values should be different");
// Check that Foo_Max enum element was ignored.
int numFooEnumElements = Enum.GetValues(typeof(Foo)).Length;
if ( numFooEnumElements != 2 )
throw new Exception(String.Format("Enum should have 2 elements, not {0}",
numFooEnumElements));
BoundaryCondition bc = BoundaryCondition.MaxMax;
if ( (int)bc != 2 )
throw new Exception("Wrong enum value");
Colour c = Colour.red;
if ( c == Colour.blue )
throw new Exception("Enum values should be different");
}
}

View File

@ -0,0 +1,26 @@
import rename_pcre_enum.*;
public class rename_pcre_enum_runme {
static { System.loadLibrary("rename_pcre_enum"); }
public static void main(String argv[])
{
Foo foo = Foo.First;
if ( foo == Foo.Second )
throw new RuntimeException("Enum values should be different");
// Check that Foo_Max enum element was ignored.
int numFooEnumElements = Foo.values().length;
if ( numFooEnumElements != 2 )
throw new RuntimeException(String.format("Enum should have 2 elements, not %d",
numFooEnumElements));
BoundaryCondition bc = BoundaryCondition.MaxMax;
if ( bc.ordinal() != 2 )
throw new RuntimeException("Wrong enum value");
Colour c = Colour.red;
if ( c == Colour.blue )
throw new RuntimeException("Enum values should be different");
}
}

View File

@ -0,0 +1,49 @@
%module rename_pcre_enum
// This file is needed for proper enum support in C#/Java backends
#if defined(SWIGCSHARP) || defined(SWIGJAVA)
%include "enums.swg"
#endif
// Apply a rule for renaming the enum elements to avoid the common prefixes
// redundant in C#/Java
%rename("%(regex:/([A-Z][a-z]+)+_(.*)/\\2/)s",%$isenumitem) "";
// Also don't export special end of enum markers which are often used in C++
// code to just have a symbolic name for the number of enum elements but are
// not needed in target language.
%rename("$ignore", regexmatch$name="([A-Z][a-z]+)+_Max$",%$isenumitem) "";
// Test another way of doing the same thing with regextarget:
%rename("$ignore", %$isenumitem, regextarget=1) "([A-Z][a-z]+)+_Internal$";
// Apply this renaming rule to all enum elements that don't contain more than
// one capital letter.
%rename("%(lower)s", notregexmatch$name="[A-Z]\\w*[A-Z]", %$isenumitem) "";
%inline %{
// Foo_Internal and Foo_Max won't be exported.
enum Foo {
Foo_Internal = -1,
Foo_First,
Foo_Second,
Foo_Max
};
// All elements of this enum will be exported because they do not match the
// excluding regex.
enum BoundaryCondition {
BoundaryCondition_MinMax,
BoundaryCondition_MaxMin,
BoundaryCondition_MaxMax
};
// The elements of this enum will have lower-case names.
enum Colour {
Red,
Blue,
Green
};
%}

View File

@ -1062,10 +1062,13 @@ static void Swig_name_object_attach_keys(const char *keys[], Hash *nameobj) {
const char **rkey;
int isnotmatch = 0;
int isrxsmatch = 0;
int isregexmatch = 0;
if ((strncmp(ckey, "match", 5) == 0)
|| (isnotmatch = (strncmp(ckey, "notmatch", 8) == 0))
|| (isrxsmatch = (strncmp(ckey, "rxsmatch", 8) == 0))
|| (isnotmatch = isrxsmatch = (strncmp(ckey, "notrxsmatch", 11) == 0))) {
|| (isregexmatch = (strncmp(ckey, "regexmatch", 10) == 0))
|| (isnotmatch = isrxsmatch = (strncmp(ckey, "notrxsmatch", 11) == 0))
|| (isnotmatch = isregexmatch = (strncmp(ckey, "notregexmatch", 13) == 0))) {
Hash *mi = NewHash();
List *attrlist = Swig_make_attrlist(ckey);
if (!matchlist)
@ -1080,6 +1083,8 @@ static void Swig_name_object_attach_keys(const char *keys[], Hash *nameobj) {
SetFlag(mi, "notmatch");
if (isrxsmatch)
SetFlag(mi, "rxsmatch");
if (isregexmatch)
SetFlag(mi, "regexmatch");
Delete(attrlist);
Append(matchlist, mi);
Delete(mi);
@ -1155,6 +1160,51 @@ static DOH *Swig_get_lattr(Node *n, List *lattr) {
return res;
}
#ifdef HAVE_PCRE
#include <pcre.h>
int Swig_name_regexmatch_value(Node *n, String *pattern, String *s) {
pcre *compiled_pat;
const char *err;
int errpos;
int rc;
compiled_pat = pcre_compile(Char(pattern), 0, &err, &errpos, NULL);
if (!compiled_pat) {
Swig_error("SWIG", Getline(n),
"Invalid regex \"%s\": compilation failed at %d: %s\n",
Char(pattern), errpos, err);
exit(1);
}
rc = pcre_exec(compiled_pat, NULL, Char(s), Len(s), 0, 0, NULL, 0);
pcre_free(compiled_pat);
if (rc == PCRE_ERROR_NOMATCH)
return 0;
if (rc < 0 ) {
Swig_error("SWIG", Getline(n),
"Matching \"%s\" against regex \"%s\" failed: %d\n",
Char(s), Char(pattern), rc);
exit(1);
}
return 1;
}
#else /* !HAVE_PCRE */
int Swig_name_regexmatch_value(Node *n, String *pattern, String *s) {
(void)pattern;
(void)s;
Swig_error("SWIG", Getline(n),
"PCRE regex matching is not available in this SWIG build.\n");
exit(1);
}
#endif /* HAVE_PCRE/!HAVE_PCRE */
#if defined(HAVE_RXSPENCER)
#include <sys/types.h>
#include <rxspencer/regex.h>
@ -1228,6 +1278,7 @@ int Swig_name_match_nameobj(Hash *rn, Node *n) {
String *nval = Swig_get_lattr(n, lattr);
int notmatch = GetFlag(mi, "notmatch");
int rxsmatch = GetFlag(mi, "rxsmatch");
int regexmatch = GetFlag(mi, "regexmatch");
#ifdef SWIG_DEBUG
Printf(stdout, "mi %d %s re %d not %d \n", i, nval, notmatch, rxsmatch);
if (rxsmatch) {
@ -1238,6 +1289,7 @@ int Swig_name_match_nameobj(Hash *rn, Node *n) {
if (nval) {
String *kwval = Getattr(mi, "value");
match = rxsmatch ? Swig_name_rxsmatch_value(kwval, nval)
: regexmatch ? Swig_name_regexmatch_value(n, kwval, nval)
: Swig_name_match_value(kwval, nval);
#ifdef SWIG_DEBUG
Printf(stdout, "val %s %s %d %d \n", nval, kwval, match, ilen);
@ -1278,6 +1330,7 @@ Hash *Swig_name_nameobj_lget(List *namelist, Node *n, String *prefix, String *na
String *sname = 0;
int fullname = GetFlag(rn, "fullname");
int rxstarget = GetFlag(rn, "rxstarget");
int regextarget = GetFlag(rn, "regextarget");
if (sfmt) {
if (fullname && prefix) {
String *pname = NewStringf("%s::%s", prefix, name);
@ -1294,7 +1347,9 @@ Hash *Swig_name_nameobj_lget(List *namelist, Node *n, String *prefix, String *na
DohIncref(name);
}
}
match = rxstarget ? Swig_name_rxsmatch_value(tname, sname) : Swig_name_match_value(tname, sname);
match = rxstarget ? Swig_name_rxsmatch_value(tname, sname)
: regextarget ? Swig_name_regexmatch_value(n, tname, sname)
: Swig_name_match_value(tname, sname);
Delete(sname);
} else {
match = 1;
@ -1393,7 +1448,7 @@ void Swig_name_rename_add(String *prefix, String *name, SwigType *decl, Hash *ne
ParmList *declparms = declaratorparms;
const char *rename_keys[] = { "fullname", "sourcefmt", "targetfmt", "continue", "rxstarget", 0 };
const char *rename_keys[] = { "fullname", "sourcefmt", "targetfmt", "continue", "rxstarget", "regextarget", 0 };
Swig_name_object_attach_keys(rename_keys, newname);
/* Add the name */