mirror of https://github.com/swig/swig
Add support for $n special variable expansion in the names of typemap local variables
For example: %typemap(in) int MYINT (int $1_temp) { ... } $1_temp is typically expanded to arg1_temp, arg2_temp etc depending on which argument the typemap is applied to.
This commit is contained in:
parent
fe3a7af855
commit
26b0911a74
|
@ -7,6 +7,15 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.4.0 (in progress)
|
||||
===========================
|
||||
|
||||
2025-02-19: wsfulton
|
||||
Add support for $n special variable expansion in the names of typemap
|
||||
local variables, such as:
|
||||
|
||||
%typemap(in) int MYINT (int $1_temp) { ... }
|
||||
|
||||
$1_temp is typically expanded to arg1_temp, arg2_temp etc depending on
|
||||
which argument the typemap is applied to.
|
||||
|
||||
2025-02-05: wsfulton
|
||||
#3075 Regression fix when using -keyword, kwargs or compactdefaultargs
|
||||
option. Restore generating a non-const cast to the default value when
|
||||
|
|
|
@ -2090,7 +2090,7 @@ wrap_foo() {
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<p>There is an exception: if the variable name starts with the <tt>_global_</tt> prefix,
|
||||
<p>There are two exceptions: First, if the variable name starts with the <tt>_global_</tt> prefix,
|
||||
the argument number is not appended. Such variables can be used throughout the generated
|
||||
wrapper function. For example, the above typemap could be rewritten to use <tt>_global_temp</tt>
|
||||
instead of <tt>temp</tt> and the generated code would then contain a single <tt>_global_temp</tt> variable
|
||||
|
@ -2105,16 +2105,34 @@ instead of <tt>temp1</tt>, <tt>temp2</tt> and <tt>temp3</tt>:
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The second exception occurs if the local variable name contains the special variable <tt>$n</tt> in the variable name.
|
||||
Special variables are covered in the next section, but simply the <tt>$n</tt> special variable is expanded to a unique parameter name, such as <tt>arg1</tt>, <tt>arg2</tt> etc.
|
||||
As this special variable already contains a unique name, there is no further need to append an argument number suffix to make the temporary variable name unique.
|
||||
So in the example below, <tt>$1_temp</tt> is typically expanded to <tt>arg1_temp</tt>, <tt>arg2_temp</tt> etc depending on which argument the typemap is being used for:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%typemap(in) std::string * <b>(std::string $1_temp)</b> {
|
||||
... as above ...
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Some typemaps do not recognize local variables (or they may simply not
|
||||
apply). At this time, only typemaps that apply to argument conversion support this (input typemaps such as the "in" typemap).
|
||||
<b>Compatibility note: </b> Support for <tt>$n</tt> expansion in typemap local variable names was added in SWIG-4.4.0.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note:</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some typemaps do not recognize local variables (or they may simply not
|
||||
apply). At this time, only typemaps that apply to argument conversion support this (input typemaps such as the "in" typemap).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When declaring a typemap for multiple types,
|
||||
each type must have its own local variable declaration.
|
||||
|
|
|
@ -24,5 +24,7 @@ public class runme {
|
|||
throw new Exception("test failed");
|
||||
if (special_variable_macros.provideStringInt(999) != "1000")
|
||||
throw new Exception("test failed");
|
||||
if (special_variable_macros.shortFunction(1, 1) != (200*2 + 200*3))
|
||||
throw new Exception("test failed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,4 +21,5 @@ void main() {
|
|||
enforce(newName.getStoredName().getName() == "factoryname");
|
||||
enforce(makeStringInt("stringint", 999) == "stringint");
|
||||
enforce(provideStringInt(999) == "1000");
|
||||
enforce(shortFunction(1, 1) == (200*2 + 200*3));
|
||||
}
|
||||
|
|
|
@ -31,4 +31,7 @@ func main() {
|
|||
if special_variable_macros.ProvideStringInt(999) != "1000" {
|
||||
panic("test failed")
|
||||
}
|
||||
if special_variable_macros.ShortFunction(1, 1) != (200*2 + 200*3) {
|
||||
panic("test failed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,5 +34,7 @@ public class special_variable_macros_runme {
|
|||
throw new RuntimeException("test failed");
|
||||
if (!special_variable_macros.provideStringInt(999).equals("1000"))
|
||||
throw new RuntimeException("test failed");
|
||||
if (special_variable_macros.shortFunction((short)1, (short)1) != (200*2 + 200*3))
|
||||
throw new RuntimeException("test failed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,3 +35,6 @@ if (special_variable_macros.makeStringInt("stringint", 999) != "stringint") {
|
|||
if (special_variable_macros.provideStringInt(999) != "1000") {
|
||||
throw new Error("test failed");
|
||||
}
|
||||
if (special_variable_macros.shortFunction(1, 1) != (200*2 + 200*3)) {
|
||||
throw new Error("test failed");
|
||||
}
|
||||
|
|
|
@ -13,4 +13,5 @@ let _ =
|
|||
assert (_testJohn '(arg) as int = 123);
|
||||
assert (_makeStringInt '("stringint", 999) as string = "stringint");
|
||||
assert (_provideStringInt '(999) as string = "1000");
|
||||
assert (_shortFunction '(1, 1) as int = (200*2 + 200*3));
|
||||
;;
|
||||
|
|
|
@ -24,3 +24,5 @@ if special_variable_macros.makeStringInt("stringint", 999) != "stringint":
|
|||
raise "test failed"
|
||||
if special_variable_macros.provideStringInt(999) != "1000":
|
||||
raise "test failed"
|
||||
if special_variable_macros.shortFunction(1, 1) != (200*2 + 200*3):
|
||||
raise "test failed"
|
||||
|
|
|
@ -306,3 +306,29 @@ std::string provideStringInt(Space::Pair<std::string, int> p) {
|
|||
return p.first;
|
||||
}
|
||||
%}
|
||||
|
||||
// Part 3: $typemap() and the 'in' typemap $1 variable substitution in the typemap temporary names list
|
||||
%typemap(in) short MYSHORT ($1_type $1_temp_name = 200) %{
|
||||
$1 = $1_temp_name;
|
||||
%}
|
||||
%typemap(in) short MYSHORT_OUTER {
|
||||
// MYSHORT_OUTER 'in' start
|
||||
int $1_outer = 0;
|
||||
$typemap(in, short MYSHORT, 1=$1_outer)
|
||||
$1 = $1_outer;
|
||||
// MYSHORT_OUTER 'in' end
|
||||
}
|
||||
%apply short MYSHORT_OUTER { short x, short y }
|
||||
%inline %{
|
||||
short shortFunction(short x, short y) {
|
||||
return x*2 + y*3;
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(arginit) int MYINT "$1 = 0;"
|
||||
%typemap(in) int MYINT (int $1_temp_name = 300) "" // $1 only appears in temporary list variable name, check this is expanded
|
||||
%typemap(argout) int MYINT %{ $1_temp_name *= 2; %} // check that $1_temp_name is available
|
||||
%apply int MYINT { int myint1, int myint2 }
|
||||
%inline %{
|
||||
void intFunction(int myint1, int myint2) {}
|
||||
%}
|
||||
|
|
|
@ -1,21 +1,39 @@
|
|||
%module typemap_manyargs
|
||||
|
||||
%typemap(in,numinputs=0) (int* a1, int* a2, int* a3, int* a4, int* a5, int* a6, int *a7, int *a8, int *a9, int *a10) (int temp1,int temp2,int temp3,int temp4,int temp5,int temp6,int temp7,int temp8, int temp9, int temp10)
|
||||
%typemap(in,numinputs=0) (double* a1, short* a2, int* a3, int* a4, int* a5, int* a6, int *a7, int *a8, int *a9, int *a10) ($*1_ltype temp1,$*2_ltype temp2,int temp3,int temp4,int $5_tmpvar,int temp6,int temp7,int temp8, int temp9, $*10_ltype temp10)
|
||||
{
|
||||
$1 = &temp1; // the code generate for this is arg2 = &temp1;
|
||||
$2 = &temp2; // the code generate for this is arg3 = &temp2;
|
||||
$1 = &temp1; // the code generated for this is arg2 = &temp1;
|
||||
$2 = &temp2; // the code generated for this is arg3 = &temp2;
|
||||
$3 = &temp3; // and so on...
|
||||
$4 = &temp4;
|
||||
$5 = &temp5;
|
||||
$5 = &$5_tmpvar;
|
||||
$6 = &temp6;
|
||||
$7 = &temp7;
|
||||
$8 = &temp8;
|
||||
$9 = &temp9;
|
||||
$10 = &temp10; // the code generated for this was arg20 = &temp10; and arg20 does not exist.
|
||||
int $10_ptr = 0; // Was arg20_ptr
|
||||
$*1_ltype ltype1 = *$1;
|
||||
$*10_ltype ltype10 = *$10;
|
||||
(void)$10_ptr;
|
||||
(void)ltype1;
|
||||
(void)ltype10;
|
||||
}
|
||||
|
||||
// Test $1, $2 temp variable substitutions
|
||||
%inline %{
|
||||
void my_c_function(char * filename,int* a1, int* a2, int* a3, int* a4, int* a5, int* a6, int *a7, int *a8, int *a9, int *a10) {}
|
||||
void my_c_function(char * filename,double* a1, short* a2, int* a3, int* a4, int* a5, int* a6, int *a7, int *a8, int *a9, int *a10) {}
|
||||
%}
|
||||
|
||||
%typemap(in, numinputs=0) (const char *s, double *d) ($1_type string_temp_$1 = "hello", $*2_ltype double_$2_temp = 0.0, int dummy_$1_$2 = 0)
|
||||
{
|
||||
$1 = const_cast<char *>(string_temp_$1);
|
||||
$2 = &double_$2_temp;
|
||||
(void)dummy_$1_$2;
|
||||
}
|
||||
%typemap(freearg) (const char *s, double *d) ""
|
||||
|
||||
void my_funk(const char *s, double *d, int i, const char *s, double *d) {}
|
||||
%{
|
||||
void my_funk(const char *s1, double *d1, int i, const char *s2, double *d2) {}
|
||||
%}
|
||||
|
|
|
@ -869,16 +869,35 @@ static Hash *typemap_search_multi(const_String_or_char_ptr tmap_method, ParmList
|
|||
}
|
||||
|
||||
|
||||
static void replace_local_types(ParmList *p, const String *name, const String *rep) {
|
||||
SwigType *t;
|
||||
static int replace_with_override(String *src, const DOHString_or_char *token, const DOHString_or_char *replace, int flags, Hash *override_vars) {
|
||||
String *override_replace = override_vars ? Getattr(override_vars, token) : NULL;
|
||||
if (override_replace)
|
||||
return Replace(src, token, override_replace, flags);
|
||||
return Replace(src, token, replace, flags);
|
||||
}
|
||||
|
||||
static void replace_local_types(ParmList *p, const String *name, const String *replace) {
|
||||
while (p) {
|
||||
t = Getattr(p, "type");
|
||||
Replace(t, name, rep, DOH_REPLACE_ANY);
|
||||
SwigType *t = Getattr(p, "type");
|
||||
Replace(t, name, replace, DOH_REPLACE_ANY);
|
||||
p = nextSibling(p);
|
||||
}
|
||||
}
|
||||
|
||||
static int check_locals(ParmList *p, const char *s) {
|
||||
static void replace_local_names(ParmList *p, const String *name, const String *replace, Hash *override_vars) {
|
||||
while (p) {
|
||||
int replaced = 0;
|
||||
SwigType *n = Getattr(p, "name");
|
||||
SwigType *origname = Copy(n);
|
||||
replaced = replace_with_override(n, name, replace, DOH_REPLACE_NUMBER_END, override_vars);
|
||||
if (replaced > 0 && !Getattr(p, "origname"))
|
||||
Setattr(p, "origname", origname);
|
||||
Delete(origname);
|
||||
p = nextSibling(p);
|
||||
}
|
||||
}
|
||||
|
||||
static int check_locals_type(ParmList *p, const char *s) {
|
||||
while (p) {
|
||||
char *c = GetChar(p, "type");
|
||||
if (strstr(c, s))
|
||||
|
@ -888,13 +907,6 @@ static int check_locals(ParmList *p, const char *s) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int replace_with_override(String *src, const DOHString_or_char *token, const DOHString_or_char *rep, int flags, Hash *override_vars) {
|
||||
String *override_replace = override_vars ? Getattr(override_vars, token) : NULL;
|
||||
if (override_replace)
|
||||
return Replace(src, token, override_replace, flags);
|
||||
return Replace(src, token, rep, flags);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* typemap_replace_vars()
|
||||
*
|
||||
|
@ -917,15 +929,15 @@ static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, Swi
|
|||
if (!pname)
|
||||
pname = lname;
|
||||
{
|
||||
Parm *p;
|
||||
int rep = 0;
|
||||
p = locals;
|
||||
int replace = 0;
|
||||
Parm *p = locals;
|
||||
while (p) {
|
||||
if (Strchr(Getattr(p, "type"), '$'))
|
||||
rep = 1;
|
||||
String *pname = Getattr(p, "name");
|
||||
if (Strchr(Getattr(p, "type"), '$') || (pname && Strchr(pname, '$')))
|
||||
replace = 1;
|
||||
p = nextSibling(p);
|
||||
}
|
||||
if (!rep)
|
||||
if (!replace)
|
||||
locals = 0;
|
||||
}
|
||||
|
||||
|
@ -983,7 +995,7 @@ static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, Swi
|
|||
|
||||
sc = Char(s);
|
||||
|
||||
if (strstr(sc, "type") || check_locals(locals, "type")) {
|
||||
if (strstr(sc, "type") || check_locals_type(locals, "type")) {
|
||||
/* Given type : $type */
|
||||
ts = SwigType_str(type, 0);
|
||||
if (index == 1) {
|
||||
|
@ -996,7 +1008,7 @@ static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, Swi
|
|||
Delete(ts);
|
||||
sc = Char(s);
|
||||
}
|
||||
if (strstr(sc, "ltype") || check_locals(locals, "ltype")) {
|
||||
if (strstr(sc, "ltype") || check_locals_type(locals, "ltype")) {
|
||||
/* Local type: $ltype */
|
||||
ltype = SwigType_ltype(type);
|
||||
ts = SwigType_str(ltype, 0);
|
||||
|
@ -1190,6 +1202,8 @@ static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, Swi
|
|||
/* Replace the bare $n variable */
|
||||
sprintf(var, "$%d", index);
|
||||
bare_substitution_count = replace_with_override(s, var, lname, DOH_REPLACE_NUMBER_END, override_vars);
|
||||
replace_local_names(locals, var, lname, override_vars);
|
||||
|
||||
Delete(ftype);
|
||||
return bare_substitution_count;
|
||||
}
|
||||
|
@ -1227,7 +1241,7 @@ static void typemap_locals(String *s, ParmList *l, Wrapper *f, int argnum) {
|
|||
/* If the user gave us $type as the name of the local variable, we'll use
|
||||
the passed datatype instead */
|
||||
|
||||
if ((argnum >= 0) && (!isglobal)) {
|
||||
if ((argnum >= 0) && !isglobal && !Getattr(p, "origname")) {
|
||||
Printf(str, "%s%d", pn, argnum);
|
||||
} else {
|
||||
Append(str, pn);
|
||||
|
|
Loading…
Reference in New Issue