From bb7bd50eabdf5cc2f07640227713ef75dc1c8fce Mon Sep 17 00:00:00 2001 From: Oliver Buchtala Date: Mon, 16 Sep 2013 00:55:43 +0200 Subject: [PATCH] Add support for IN/OUTPUT typemaps. --- Lib/javascript/jsc/javascriptrun.swg | 40 ++++++ Lib/javascript/jsc/javascripttypemaps.swg | 2 +- Lib/javascript/jsc/typemaps.i | 148 ++++++++++++++++++++++ Lib/javascript/v8/javascriptrun.swg | 18 +++ Lib/javascript/v8/javascripttypemaps.swg | 4 +- Lib/javascript/v8/typemaps.i | 148 ++++++++++++++++++++++ Source/Modules/javascript.cxx | 44 ++++--- 7 files changed, 382 insertions(+), 22 deletions(-) diff --git a/Lib/javascript/jsc/javascriptrun.swg b/Lib/javascript/jsc/javascriptrun.swg index c8f16f36f..0e68b7618 100644 --- a/Lib/javascript/jsc/javascriptrun.swg +++ b/Lib/javascript/jsc/javascriptrun.swg @@ -253,3 +253,43 @@ void _wrap_SwigPackedData_delete(JSObjectRef obj) #define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_JSC_ConvertPacked(context, obj, ptr, sz, ty) #define SWIG_NewMemberObj(ptr, sz, type) SWIG_JSC_NewPackedObj(context, ptr, sz, type) + + +/* --------------------------------------------------------------------------- + * Support for IN/OUTPUT typemaps (see Lib/typemaps/inoutlist.swg) + * + * ---------------------------------------------------------------------------*/ + +unsigned int SWIGJSC_ArrayLength(JSContextRef context, JSObjectRef arr) { + static JSStringRef LENGTH = 0; + JSValueRef exception = NULL; + JSValueRef js_length; + double length; + + if (LENGTH == 0) { + LENGTH = JSStringCreateWithUTF8CString("length"); + } + + js_length = JSObjectGetProperty(context, arr, LENGTH, &exception); + if (exception == 0 && JSValueIsNumber(context, js_length)) { + length = JSValueToNumber(context, js_length, 0); + return (unsigned int) length; + } else { + return 0; + } +} + +SWIGRUNTIME +JSValueRef SWIGJSC_AppendOutput(JSContextRef context, JSValueRef value, JSValueRef obj) { + JSObjectRef arr; + unsigned int length; + + if (JSValueIsUndefined(context, value)) { + arr = JSObjectMakeArray(context, 0, 0, 0); + } else { + arr = JSValueToObject(context, value, 0); + } + + length = SWIGJSC_ArrayLength(context, arr); + JSObjectSetPropertyAtIndex(context, arr, length, obj, 0); +} diff --git a/Lib/javascript/jsc/javascripttypemaps.swg b/Lib/javascript/jsc/javascripttypemaps.swg index 12e78dc2f..e8fbbeca8 100644 --- a/Lib/javascript/jsc/javascripttypemaps.swg +++ b/Lib/javascript/jsc/javascripttypemaps.swg @@ -35,7 +35,7 @@ #define VOID_Object JSValueMakeUndefined(context) /* append output */ -#define SWIG_AppendOutput(result, obj) +#define SWIG_AppendOutput(result, obj) SWIGJSC_AppendOutput(context, result, obj) /* set constant */ #define SWIG_SetConstant(name, obj) diff --git a/Lib/javascript/jsc/typemaps.i b/Lib/javascript/jsc/typemaps.i index e69de29bb..d3d8afb19 100644 --- a/Lib/javascript/jsc/typemaps.i +++ b/Lib/javascript/jsc/typemaps.i @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------------- + * typemaps.i + * + * Pointer handling + * These mappings provide support for input/output arguments and common + * uses for C/C++ pointers. + * ----------------------------------------------------------------------------- */ + +// INPUT typemaps. +// These remap a C pointer to be an "INPUT" value which is passed by value +// instead of reference. + +/* +The following methods can be applied to turn a pointer into a simple +"input" value. That is, instead of passing a pointer to an object, +you would use a real value instead. + + int *INPUT + short *INPUT + long *INPUT + long long *INPUT + unsigned int *INPUT + unsigned short *INPUT + unsigned long *INPUT + unsigned long long *INPUT + unsigned char *INPUT + bool *INPUT + float *INPUT + double *INPUT + +To use these, suppose you had a C function like this : + + double fadd(double *a, double *b) { + return *a+*b; + } + +You could wrap it with SWIG as follows : + + %include + double fadd(double *INPUT, double *INPUT); + +or you can use the %apply directive : + + %include + %apply double *INPUT { double *a, double *b }; + double fadd(double *a, double *b); + +*/ + +// OUTPUT typemaps. These typemaps are used for parameters that +// are output only. The output value is appended to the result as +// a list element. + +/* +The following methods can be applied to turn a pointer into an "output" +value. When calling a function, no input value would be given for +a parameter, but an output value would be returned. In the case of +multiple output values, they are returned in the form of a Python tuple. + + int *OUTPUT + short *OUTPUT + long *OUTPUT + long long *OUTPUT + unsigned int *OUTPUT + unsigned short *OUTPUT + unsigned long *OUTPUT + unsigned long long *OUTPUT + unsigned char *OUTPUT + bool *OUTPUT + float *OUTPUT + double *OUTPUT + +For example, suppose you were trying to wrap the modf() function in the +C math library which splits x into integral and fractional parts (and +returns the integer part in one of its parameters).K: + + double modf(double x, double *ip); + +You could wrap it with SWIG as follows : + + %include + double modf(double x, double *OUTPUT); + +or you can use the %apply directive : + + %include + %apply double *OUTPUT { double *ip }; + double modf(double x, double *ip); + +The Python output of the function would be a tuple containing both +output values. + +*/ + +// INOUT +// Mappings for an argument that is both an input and output +// parameter + +/* +The following methods can be applied to make a function parameter both +an input and output value. This combines the behavior of both the +"INPUT" and "OUTPUT" methods described earlier. Output values are +returned in the form of a Python tuple. + + int *INOUT + short *INOUT + long *INOUT + long long *INOUT + unsigned int *INOUT + unsigned short *INOUT + unsigned long *INOUT + unsigned long long *INOUT + unsigned char *INOUT + bool *INOUT + float *INOUT + double *INOUT + +For example, suppose you were trying to wrap the following function : + + void neg(double *x) { + *x = -(*x); + } + +You could wrap it with SWIG as follows : + + %include + void neg(double *INOUT); + +or you can use the %apply directive : + + %include + %apply double *INOUT { double *x }; + void neg(double *x); + +Unlike C, this mapping does not directly modify the input value (since +this makes no sense in Python). Rather, the modified input value shows +up as the return value of the function. Thus, to apply this function +to a Python variable you might do this : + + x = neg(x) + +Note : previous versions of SWIG used the symbol 'BOTH' to mark +input/output arguments. This is still supported, but will be slowly +phased out in future releases. + +*/ + +%include diff --git a/Lib/javascript/v8/javascriptrun.swg b/Lib/javascript/v8/javascriptrun.swg index bab81613c..14936986f 100644 --- a/Lib/javascript/v8/javascriptrun.swg +++ b/Lib/javascript/v8/javascriptrun.swg @@ -442,3 +442,21 @@ v8::Handle SWIGV8_NewPackedObj(void *data, size_t size, swig_type_inf #define SWIG_ConvertMember(obj, ptr, sz, ty) SWIGV8_ConvertPacked(obj, ptr, sz, ty) #define SWIG_NewMemberObj(ptr, sz, type) SWIGV8_NewPackedObj(ptr, sz, type) + + +/* --------------------------------------------------------------------------- + * Support for IN/OUTPUT typemaps (see Lib/typemaps/inoutlist.swg) + * + * ---------------------------------------------------------------------------*/ + +SWIGRUNTIME +v8::Handle SWIGV8_AppendOutput(v8::Handle result, v8::Handle obj) { + v8::HandleScope scope; + if (result->IsUndefined()) { + result = v8::Array::New(); + } + v8::Handle arr = v8::Handle::Cast(result); + arr->Set(arr->Length(), obj); + + return scope.Close(arr); +} diff --git a/Lib/javascript/v8/javascripttypemaps.swg b/Lib/javascript/v8/javascripttypemaps.swg index b12e5c899..90317a1c7 100644 --- a/Lib/javascript/v8/javascripttypemaps.swg +++ b/Lib/javascript/v8/javascripttypemaps.swg @@ -31,13 +31,13 @@ /* Overload of the output/constant/exception/dirout handling */ /* append output */ -#define SWIG_AppendOutput(result, obj) +#define SWIG_AppendOutput(result, obj) SWIGV8_AppendOutput(result, obj) /* set constant */ #define SWIG_SetConstant(name, obj) /* raise */ #define SWIG_Raise(obj, type, desc) SWIG_V8_Raise(type) - + /* Include the unified typemap library */ %include diff --git a/Lib/javascript/v8/typemaps.i b/Lib/javascript/v8/typemaps.i index e69de29bb..d3d8afb19 100644 --- a/Lib/javascript/v8/typemaps.i +++ b/Lib/javascript/v8/typemaps.i @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------------- + * typemaps.i + * + * Pointer handling + * These mappings provide support for input/output arguments and common + * uses for C/C++ pointers. + * ----------------------------------------------------------------------------- */ + +// INPUT typemaps. +// These remap a C pointer to be an "INPUT" value which is passed by value +// instead of reference. + +/* +The following methods can be applied to turn a pointer into a simple +"input" value. That is, instead of passing a pointer to an object, +you would use a real value instead. + + int *INPUT + short *INPUT + long *INPUT + long long *INPUT + unsigned int *INPUT + unsigned short *INPUT + unsigned long *INPUT + unsigned long long *INPUT + unsigned char *INPUT + bool *INPUT + float *INPUT + double *INPUT + +To use these, suppose you had a C function like this : + + double fadd(double *a, double *b) { + return *a+*b; + } + +You could wrap it with SWIG as follows : + + %include + double fadd(double *INPUT, double *INPUT); + +or you can use the %apply directive : + + %include + %apply double *INPUT { double *a, double *b }; + double fadd(double *a, double *b); + +*/ + +// OUTPUT typemaps. These typemaps are used for parameters that +// are output only. The output value is appended to the result as +// a list element. + +/* +The following methods can be applied to turn a pointer into an "output" +value. When calling a function, no input value would be given for +a parameter, but an output value would be returned. In the case of +multiple output values, they are returned in the form of a Python tuple. + + int *OUTPUT + short *OUTPUT + long *OUTPUT + long long *OUTPUT + unsigned int *OUTPUT + unsigned short *OUTPUT + unsigned long *OUTPUT + unsigned long long *OUTPUT + unsigned char *OUTPUT + bool *OUTPUT + float *OUTPUT + double *OUTPUT + +For example, suppose you were trying to wrap the modf() function in the +C math library which splits x into integral and fractional parts (and +returns the integer part in one of its parameters).K: + + double modf(double x, double *ip); + +You could wrap it with SWIG as follows : + + %include + double modf(double x, double *OUTPUT); + +or you can use the %apply directive : + + %include + %apply double *OUTPUT { double *ip }; + double modf(double x, double *ip); + +The Python output of the function would be a tuple containing both +output values. + +*/ + +// INOUT +// Mappings for an argument that is both an input and output +// parameter + +/* +The following methods can be applied to make a function parameter both +an input and output value. This combines the behavior of both the +"INPUT" and "OUTPUT" methods described earlier. Output values are +returned in the form of a Python tuple. + + int *INOUT + short *INOUT + long *INOUT + long long *INOUT + unsigned int *INOUT + unsigned short *INOUT + unsigned long *INOUT + unsigned long long *INOUT + unsigned char *INOUT + bool *INOUT + float *INOUT + double *INOUT + +For example, suppose you were trying to wrap the following function : + + void neg(double *x) { + *x = -(*x); + } + +You could wrap it with SWIG as follows : + + %include + void neg(double *INOUT); + +or you can use the %apply directive : + + %include + %apply double *INOUT { double *x }; + void neg(double *x); + +Unlike C, this mapping does not directly modify the input value (since +this makes no sense in Python). Rather, the modified input value shows +up as the return value of the function. Thus, to apply this function +to a Python variable you might do this : + + x = neg(x) + +Note : previous versions of SWIG used the symbol 'BOTH' to mark +input/output arguments. This is still supported, but will be slowly +phased out in future releases. + +*/ + +%include diff --git a/Source/Modules/javascript.cxx b/Source/Modules/javascript.cxx index 0ca740caf..2996d6230 100644 --- a/Source/Modules/javascript.cxx +++ b/Source/Modules/javascript.cxx @@ -235,9 +235,9 @@ protected: virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) = 0; - virtual void emitInputTypemap(Node *n, Parm *p, Wrapper *wrapper, String *arg); + virtual void emitInputTypemap(Node *n, Parm *params, Wrapper *wrapper, String *arg); - virtual void marshalOutput(Node *n, Wrapper *wrapper, String *actioncode, const String *cresult=0, bool emitReturnVariable = true); + virtual void marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult=0, bool emitReturnVariable = true); virtual void emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params); @@ -984,7 +984,7 @@ int JSEmitter::emitGetter(Node *n, bool is_member, bool is_static) { // prepare code part String *action = emit_action(n); marshalInputArgs(n, params, wrapper, Getter, is_member, is_static); - marshalOutput(n, wrapper, action); + marshalOutput(n, params, wrapper, action); emitCleanupCode(n, wrapper, params); @@ -1064,7 +1064,7 @@ int JSEmitter::emitConstant(Node *n) { assert(value != NULL); String *action = NewString(""); - marshalOutput(n, wrapper, action, value, false); + marshalOutput(n, 0, wrapper, action, value, false); t_getter.replace("$jswrapper", wrap_name) .replace("$jslocals", wrapper->locals) @@ -1099,14 +1099,15 @@ int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) { emit_parameter_variables(params, wrapper); emit_attach_parmmaps(params, wrapper); - // HACK: in test-case `ignore_parameter` emit_attach_parmmaps generated an extra line of applied typemap. - // Deleting wrapper->code here, to reset, and as it seemed to have no side effect elsewhere + // HACK: in test-case `ignore_parameter` emit_attach_parmmaps generates an extra line of applied typemap. + // Deleting wrapper->code here fixes the problem, and seems to have no side effect elsewhere Delete(wrapper->code); wrapper->code = NewString(""); marshalInputArgs(n, params, wrapper, Function, is_member, is_static); String *action = emit_action(n); - marshalOutput(n, wrapper, action); + + marshalOutput(n, params, wrapper, action); emitCleanupCode(n, wrapper, params); @@ -1210,9 +1211,11 @@ void JSEmitter::emitInputTypemap(Node *n, Parm *p, Wrapper *wrapper, String *arg } } -void JSEmitter::marshalOutput(Node *n, Wrapper *wrapper, String *actioncode, const String *cresult, bool emitReturnVariable) { +void JSEmitter::marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult, bool emitReturnVariable) { SwigType *type = Getattr(n, "type"); String *tm; + Parm *p; + // adds a declaration for the result variable if(emitReturnVariable) emit_return_variable(n, type, wrapper); // if not given, use default result identifier ('result') for output typemap @@ -1226,7 +1229,6 @@ void JSEmitter::marshalOutput(Node *n, Wrapper *wrapper, String *actioncode, co } if (tm) { - Replaceall(tm, "$result", "jsresult"); Replaceall(tm, "$objecttype", Swig_scopename_last(SwigType_str(SwigType_strip_qualifiers(type), 0))); if (should_own) { @@ -1242,22 +1244,26 @@ void JSEmitter::marshalOutput(Node *n, Wrapper *wrapper, String *actioncode, co } else { Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), Getattr(n, "name")); } + + if (params) { + for (p = params; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(wrapper->code, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + } + + Replaceall(wrapper->code, "$result", "jsresult"); } void JSEmitter::emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params) { Parm *p; String *tm; - for (p = params; p;) { - if ((tm = Getattr(p, "tmap:argout"))) { - Replaceall(tm, "$input", Getattr(p, "emit:input")); - Printv(wrapper->code, tm, "\n", NIL); - p = Getattr(p, "tmap:argout:next"); - } else { - p = nextSibling(p); - } - } - for (p = params; p;) { if ((tm = Getattr(p, "tmap:freearg"))) { //addThrows(n, "tmap:freearg", p);