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:
William S Fulton 2025-02-19 18:37:08 +00:00
parent fe3a7af855
commit 26b0911a74
12 changed files with 128 additions and 29 deletions

View File

@ -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

View File

@ -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.

View File

@ -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");
}
}

View File

@ -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));
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}

View File

@ -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));
;;

View File

@ -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"

View File

@ -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) {}
%}

View File

@ -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) {}
%}

View File

@ -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);