diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg index 52a0651b3..855f72284 100644 --- a/Lib/javascript/v8/javascriptcode.swg +++ b/Lib/javascript/v8/javascriptcode.swg @@ -1,4 +1,3 @@ - %fragment("v8_initializer", "templates") %{ void ${MODULE}_Initialize(v8::Handle context) { @@ -41,43 +40,34 @@ v8::Handle ${NAME_MANGLED}_new(const v8::Arguments& args) { v8::HandleScope scope; v8::Handle self = args.Holder(); ${LOCALS} - ${MARSHAL_INPUT} - ${ACTION} - self->SetInternalField(0, v8::External::New(ptr)); + ${CODE} + self->SetInternalField(0, v8::External::New(result)); return self; -} -%} +}%} %fragment("v8_getter", "templates") %{ v8::Handle ${NAME_MANGLED}_get(v8::Local property, const v8::AccessorInfo& info) { v8::HandleScope scope; - v8::Handle ret; + v8::Handle jsresult; ${LOCALS} - ${ACTION} - ${MARSHAL_OUTPUT} - return scope.Close(ret); -} -%} + ${CODE} + return scope.Close(jsresult); +}%} %fragment("v8_setter", "templates") %{ void ${NAME_MANGLED}_set(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { ${LOCALS} - ${MARSHAL_INPUT} - ${ACTION} -} -%} + ${CODE} +}%} %fragment("v8_function", "templates") %{ v8::Handle wrap_${NAME_MANGLED}(const Arguments &args) { v8::HandleScope scope; - v8::Handle ret; + v8::Handle jsresult; ${LOCALS} - ${MARSHAL_INPUT} - ${ACTION} - ${MARSHAL_OUTPUT} - return scope.Close(ret); -} -%} + ${CODE} + return scope.Close(jsresult); +}%} %fragment("v8_create_namespace", "templates") %{ v8::Handle ${NAME_MANGLED} = v8::ObjectTemplate::New();%} @@ -96,3 +86,7 @@ SWIGV8_AddGlobalVariable(${CONTEXT}, "${NAME_UNQUALIFIED}", ${GETTER}, ${SETTER} %fragment("v8_register_namespace", "templates") %{ ${CONTEXT}->Set(v8::String::NewSymbol("${NAME_UNQUALIFIED}", ${NAME_MANGLED}->NewInstance()));%} + +%fragment("v8_this_ptr", "templates") %{ +arg1 = SWIGV8_UnwrapThisPointer<${TYPE}>(${ARG}.Holder()); +%} diff --git a/Lib/javascript/v8/javascriptprimitives.swg b/Lib/javascript/v8/javascriptprimitives.swg index d5c89c690..b9b255f86 100644 --- a/Lib/javascript/v8/javascriptprimitives.swg +++ b/Lib/javascript/v8/javascriptprimitives.swg @@ -1,66 +1,84 @@ +%typemap(in) bool +%{ $1 = ($1_ltype) $input->BooleanValue();%} + // Primitive types %typemap(in) char, signed char, unsigned char, - short, + short, unsigned short, - int, - unsigned int, + int +%{ $1 = ($1_ltype) $input->Int32Value();%} + +%typemap(in) unsigned int, long, unsigned long, long long, - unsigned long long, - float, - double -%{ $1 = ($1_ltype)JSValueToNumber(context, $input, NULL); %} + unsigned long long +%{ $1 = ($1_ltype) $input->UInt32Value();%} -%typemap(in) const bool &, bool &, - const char &, char &, - const signed char &, signed char &, - const unsigned char &, unsigned char &, - const short &, short &, - const unsigned short &, unsigned short &, - const int &, int &, - const unsigned int &, unsigned int &, - const long &, long &, - const unsigned long &, unsigned long &, - const long long &, long long &, - const unsigned long long &,unsigned long long &, - const float &, float &, - const double &, double & -%{ $1 = ($1_ltype)&$input; %} +%typemap(in) float, double +%{ $1 = ($1_ltype) $input->NumberValue();%} + + +%typemap(in) const bool &, bool &, + const char &, char &, + const signed char &, signed char &, + const unsigned char &, unsigned char &, + const short &, short &, + const unsigned short &, unsigned short &, + const int &, int &, + const unsigned int &, unsigned int &, + const long &, long &, + const unsigned long &, unsigned long &, + const long long &, long long &, + const unsigned long long &, unsigned long long &, + const float &, float &, + const double &, double & +%{ + // TODO: typemap(in) const bool& at al +} + +%typemap(out) bool +%{ $result = v8::Boolean::New($1);%} %typemap(out) char, signed char, unsigned char, - short, + short, unsigned short, - int, - unsigned int, + int +%{ $result = v8::Int32::New($1);%} + +%typemap(out) unsigned int, long, unsigned long, - long long, - unsigned long long, - float, - double -%{ $result = JSValueMakeNumber(context, $1); %} + long long, + unsigned long long +%{ $result = v8::UInt32::New($1);%} -%typemap(out) const bool &, bool &, - const char &, char &, - const signed char &, signed char &, - const unsigned char &, unsigned char &, - const short &, short &, - const unsigned short &, unsigned short &, - const int &, int &, - const unsigned int &, unsigned int &, - const long &, long &, - const unsigned long &, unsigned long &, - const long long &, long long &, - const unsigned long long &,unsigned long long &, - const float &, float &, - const double &, double & -%{ $result = JSValueMakeNumber(context,*$1); %} +%typemap(out) float, double +%{ $result = v8::Number::New($1); %} +%typemap(out) const bool &, bool &, + const char &, char &, + const signed char &, signed char &, + const unsigned char &, unsigned char &, + const short &, short &, + const unsigned short &, unsigned short &, + const int &, int & +%{ $result = v8::Int32::New((*$1);%} + +%typemap(out) const unsigned int &, unsigned int &, + const long &, long &, + const unsigned long &, unsigned long &, + const long long &, long long &, + const unsigned long long &, unsigned long long & +%{ $result = v8::UInt32::New(*$1);%} + +%typemap(out) const float &, float &, + const double &, double & +%{ $result = v8::Number::New(*$1);%} %typemap(in) short *, unsigned short *, @@ -73,9 +91,7 @@ float *, double * %{ - JSObjectRef o$1 = JSValueToObject(context,$input, NULL); - SWIG_PRV_DATA *$1_privatedata = (SWIG_PRV_DATA *)JSObjectGetPrivate(o$1); - $1 = ($1_ltype)$1_privatedata->swigCObject; + // TODO: typemap(in): short* et al. %} @@ -90,169 +106,88 @@ float *, double * %{ - SWIG_PRV_DATA *privatedata = new SWIG_PRV_DATA(); - privatedata->swigCMemOwn = false; - privatedata->swigCObject = result; - $result = JSObjectMake(context, _wrap_swig_ptr_$*1_ltype_createJSClass(context), privatedata); + // TODO: typemap(out) short* et al. %} -%typemap(in) bool -%{ - $1 = ($1_ltype)JSValueToBoolean(context, $input); -%} - -%typemap(out) bool -%{ - $result = JSValueMakeBoolean(context, $1); -%} - %typemap(out) void -%{ $result = JSValueMakeUndefined(context); %} +%{ $result = v8::Undefined(); %} %typemap(in) char * %{ - JSStringRef $1_str = JSValueToStringCopy(context, $input, NULL); - size_t $1_strsize = JSStringGetMaximumUTF8CStringSize($1_str); - $1 = (char *)malloc($1_strsize * sizeof(char)); - JSStringGetUTF8CString($1_str, $1, $1_strsize); + // TODO: input typemap for char* %} %typemap(out) char * %{ - JSStringRef jsstring = JSStringCreateWithUTF8CString($1); - $result = JSValueMakeString(context, jsstring); - JSStringRelease(jsstring); + // TODO: output typemap for char* %} -%typemap(arginit) char * "" - %typemap(in) char *& ($*1_ltype temp = 0) %{ - temp = ($*1_ltype)$input; - JSStringRef $1_str = JSValueToStringCopy(context, $input, NULL); - size_t $1_strsize = JSStringGetMaximumUTF8CStringSize($1_str); - $1 = (char *)malloc($1_strsize * sizeof(char)); - JSStringGetUTF8CString($1_str, $1, $1_strsize); + // TODO: input typemap for char*& %} %typemap(out) char *& %{ - JSStringRef jsstring = JSStringCreateWithUTF8CString((const char *)*$1); - $result = JSValueMakeString(context, jsstring); - JSStringRelease(jsstring); + // TODO: output typemap for char*& %} /* char arrays - treat as String */ %typemap(in) char[ANY], char[] %{ - JSStringRef $1_str = JSValueToStringCopy(context, $input, NULL); - size_t $1_strsize = JSStringGetMaximumUTF8CStringSize($1_str); - JSStringGetUTF8CString($1_str, $1, $1_strsize); + // TODO: input typemap for char[] %} %typemap(out) char[ANY], char[] %{ - JSStringRef jsstring = JSStringCreateWithUTF8CString($1); - $result = JSValueMakeString(context, jsstring); - JSStringRelease(jsstring); + // TODO: output typemap for char[] %} %typemap(freearg) char *, char *&, char[ANY], char[] //TODO: Not working: A memory leak -%{ free($1); %} +%{ + // TODO: freearg char* et al +%} /* Typemaps for composite types */ %typemap(in) SWIGTYPE ($&1_type argp) // Objects passed by value, convert to a pointer %{ - JSObjectRef o$1 = JSValueToObject(context,$input, NULL); - SWIG_PRV_DATA *$1_privatedata = (SWIG_PRV_DATA *)JSObjectGetPrivate(o$1); - argp = ($&1_ltype)$1_privatedata->swigCObject; - $1 = *argp; + // TODO: input typemap for composite types %} %typemap(out) SWIGTYPE ($&1_type temp) -#ifdef __cplusplus %{ - temp = new $1_ltype((const $1_ltype &)$1); - SWIG_PRV_DATA *privatedata = new SWIG_PRV_DATA(); - privatedata->swigCMemOwn = false; - privatedata->swigCObject = temp; - $result = JSObjectMake(context, _wrap_$1_type_createJSClass(context), privatedata); - //$result = JSObjectMake(context, _wrap_$1_basetype_createJSClass(context), privatedata); - //$result = JSObjectMake(context, _wrap_$objecttype_createJSClass(context), privatedata); - // $1_mangle - // $1_descriptor + // TODO: output typemap for composite types %} -#else -{ - $&1_ltype $1ptr = ($&1_ltype) malloc(sizeof($1_ltype)); - memmove($1ptr, &$1, sizeof($1_type)); - temp = $1ptr; - SWIG_PRV_DATA *privatedata = (SWIG_PRV_DATA *)malloc(sizeof(SWIG_PRV_DATA()); - privatedata->swigCMemOwn = false; - privatedata->swigCObject = temp; - $result = JSObjectMake(context, _wrap_$1_ltype_createJSClass(context), privatedata); - //$result = JSObjectMake(context, _wrap_$1_basetype_createJSClass(context), privatedata); - //$result = JSObjectMake(context, _wrap_$objecttype_createJSClass(context), privatedata); - // $1_mangle - // $1_descriptor -} -#endif %typemap(in) SWIGTYPE *, SWIGTYPE & %{ - JSObjectRef o$1 = JSValueToObject(context,$input, NULL); - SWIG_PRV_DATA *$1_privatedata = (SWIG_PRV_DATA *)JSObjectGetPrivate(o$1); - $1 = ($1_ltype)$1_privatedata->swigCObject; + // TODO: input typemap for ptr types %} %typemap(out) SWIGTYPE *, SWIGTYPE & %{ - SWIG_PRV_DATA *privatedata = new SWIG_PRV_DATA(); - privatedata->swigCMemOwn = false; - privatedata->swigCObject = result; - $result = JSObjectMake(context, _wrap_$*1_ltype_createJSClass(context), privatedata); - //$result = JSObjectMake(context, _wrap_$1_basetype_createJSClass(context), privatedata); - //$result = JSObjectMake(context, _wrap_$objecttype_createJSClass(context), privatedata); - // $1_mangle - // $1_descriptor + // TODO: output typemap for ptr types %} +// TODO: sanity check? %typemap(arginit) SWIGTYPE * -%{ - // Sanity check if the call is not on the global object - if (!JSValueIsEqual(context, - JSValueToObject(context,thisObject,NULL), - JSValueToObject(context,JSContextGetGlobalObject(context), NULL), - NULL)) { - SWIG_PRV_DATA* $1_swigprivatedata = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); - $1 = ($1_ltype)$1_swigprivatedata->swigCObject; - } -%} +%{%} %typemap(in) SWIGTYPE (CLASS::*) "" %typemap(out) SWIGTYPE (CLASS::*) %{ - // Class* out typemap - $result = JSObjectMake(context, _wrap_$*1_ltype_createJSClass(context), result); + // TODO: output typemap for CLASS::* %} - - -/* Typecheck typemaps - The purpose of these is merely to issue a warning for overloaded C++ functions - * that cannot be overloaded in Javascript as more than one C++ type maps to a single Javascript type */ -// TODO - - // Default array handling -%typemap(in) SWIGTYPE [] %{ $1 = ($1_ltype)$input; %} +%typemap(in) SWIGTYPE [] %{ + // TODO: typemap for arrays; +%} + %typemap(out) SWIGTYPE [] %{ $result = $1; %} - -// Javascript specific directives -//TODO - // Some ANSI C typemaps */ %apply unsigned long { size_t }; diff --git a/Source/Modules/javascript_v8.cxx b/Source/Modules/javascript_v8.cxx index 70e0402d4..7d6e9a327 100644 --- a/Source/Modules/javascript_v8.cxx +++ b/Source/Modules/javascript_v8.cxx @@ -22,6 +22,8 @@ #define V8_REGISTER_GLOBAL_VARIABLE "v8_register_global_variable" #define V8_CREATE_NAMESPACE "v8_create_namespace" #define V8_REGISTER_NAMESPACE "v8_register_namespace" +#define V8_THIS_PTR "v8_this_ptr" + // keywords used in templates #define KW_MODULE_NAME "${MODULE}" @@ -30,6 +32,8 @@ #define KW_CLASSNAME_MANGLED "${CLASSNAME_MANGLED}" #define KW_BASE_CLASS "${BASE_CLASS}" #define KW_CONTEXT "${CONTEXT}" +#define KW_TYPE "${TYPE}" +#define KW_ARG "${ARG}" #define KW_WRAPPER "${WRAPPER}" #define KW_GETTER "${GETTER}" #define KW_SETTER "${SETTER}" @@ -42,6 +46,7 @@ #define KW_REGISTER_NS "${PART_REGISTER_NS}" #define KW_LOCALS "${LOCALS}" +#define KW_CODE "${CODE}" #define KW_MARSHAL_INPUT "${MARSHAL_INPUT}" #define KW_ACTION "${ACTION}" #define KW_MARSHAL_OUTPUT "${MARSHAL_OUTPUT}" @@ -196,7 +201,8 @@ int V8Emitter::EnterClass(Node *n) { current_classname_mangled = Swig_string_mangle(Getattr(n, "name")); current_classname_unqualified = Swig_scopename_last(Getattr(n, "name")); - + current_class_type = Getattr(n, "classtype"); + // emit declaration of a v8 class template Template t_decl_class(GetTemplate(V8_DECL_CLASSTEMPLATE)); t_decl_class.Replace(KW_MANGLED_NAME, current_classname_mangled); @@ -233,6 +239,7 @@ int V8Emitter::ExitClass(Node *n) Delete(current_classname_unqualified); current_classname_mangled = 0; current_classname_unqualified = 0; + current_class_type = 0; return SWIG_OK; } @@ -322,23 +329,19 @@ int V8Emitter::ExitFunction(Node* n) int V8Emitter::EmitCtor(Node* n) { - // TODO: - // - handle overloaded ctors using a dispatcher - // - marshal inputs + // TODO: handle overloaded ctors using a dispatcher Template t(GetTemplate(V8_CTOR_WRAPPER)); + + //HACK: manually add declaration of instance pointer + Printf(current_wrapper->locals, "%sresult;", SwigType_str(Getattr(n, "type"),0)); - ParmList *params = Getattr(n,"parms"); - emit_parameter_variables(params, current_wrapper); - emit_attach_parmmaps(params, current_wrapper); - - String* action = Getattr(n, "wrap:action"); - String* input = NewString(""); + String* action = emit_action(n); + Printv(current_wrapper->code, action, 0); t.Replace(KW_MANGLED_NAME, current_classname_mangled) .Replace(KW_UNQUALIFIED_NAME, current_classname_unqualified) .Replace(KW_LOCALS, current_wrapper->locals) - .Replace(KW_ACTION, action) - .Replace(KW_MARSHAL_INPUT, input); + .Replace(KW_CODE, current_wrapper->code); Wrapper_pretty_print(t.str(), f_wrapper); @@ -360,21 +363,21 @@ int V8Emitter::EmitGetter(Node *n, bool is_member) { current_getter = Getattr(n,"wrap:name"); - Printf(current_wrapper->locals, "%s result;\n", SwigType_str(Getattr(n, "type"), 0)); - + ParmList *params = Getattr(n,"parms"); + emit_parameter_variables(params, current_wrapper); + emit_attach_parmmaps(params, current_wrapper); + + int num_args = emit_num_arguments(params); String* action = emit_action(n); - String* output = NewString("// TODO: marshal output.\n ret = v8::Undefined();"); + marshalInputArgs(n, params, num_args, current_wrapper); + marshalOutput(n, action, current_wrapper); t_getter.Replace(KW_MANGLED_NAME, current_variable_mangled) .Replace(KW_LOCALS, current_wrapper->locals) - .Replace(KW_ACTION, action) - .Replace(KW_MARSHAL_OUTPUT, output); + .Replace(KW_CODE, current_wrapper->code); Wrapper_pretty_print(t_getter.str(), f_wrapper); - - // clean up - Delete(output); - + return SWIG_OK; } @@ -388,19 +391,17 @@ int V8Emitter::EmitSetter(Node* n, bool is_member) emit_parameter_variables(params, current_wrapper); emit_attach_parmmaps(params, current_wrapper); + int num_args = emit_num_arguments(params); String* action = emit_action(n); - String* input = NewString("// TODO: marshal input.\n"); + marshalInputArgs(n, params, num_args, current_wrapper); + Printv(current_wrapper->code, action, 0); t_setter.Replace(KW_MANGLED_NAME, current_variable_mangled) .Replace(KW_LOCALS, current_wrapper->locals) - .Replace(KW_ACTION, action) - .Replace(KW_MARSHAL_INPUT, input); + .Replace(KW_CODE, current_wrapper->code); Wrapper_pretty_print(t_setter.str(), f_wrapper); - // clean up - Delete(input); - return SWIG_OK; } @@ -416,26 +417,124 @@ int V8Emitter::EmitFunction(Node* n, bool is_member) ParmList *params = Getattr(n,"parms"); emit_parameter_variables(params, current_wrapper); emit_attach_parmmaps(params, current_wrapper); - Printf(current_wrapper->locals, "%s result;\n", SwigType_str(Getattr(n, "type"), 0)); - String* input = NewString("// TODO: marshal input"); + int num_args = emit_num_arguments(params); String* action = emit_action(n); - String* output = NewString("// TODO: marshal output.\n ret = v8::Undefined();"); + marshalInputArgs(n, params, num_args, current_wrapper); + marshalOutput(n, action, current_wrapper); t_function.Replace(KW_MANGLED_NAME, current_function_mangled) .Replace(KW_LOCALS, current_wrapper->locals) - .Replace(KW_ACTION, action) - .Replace(KW_MARSHAL_INPUT, input) - .Replace(KW_MARSHAL_OUTPUT, output); + .Replace(KW_CODE, current_wrapper->code); Wrapper_pretty_print(t_function.str(), f_wrapper); - // clean up - Delete(input); - Delete(output); - return SWIG_OK; } + + +void V8Emitter::marshalInputArgs(Node *n, ParmList *parms, int numarg, Wrapper *wrapper) { + String *tm; + Parm *p; + + bool is_member = (current_class_type != 0); + bool is_setter = IsSetterMethod(n); + bool is_function = (current_function_mangled != 0); + + int start_idx; + if(is_member) { + start_idx = 1; + } else { + start_idx = 0; + } + + // retrieve this pointer for member functions + if(is_member) { + + Template t_selfptr(GetTemplate(V8_THIS_PTR)); + String *type_str = SwigType_strip_qualifiers(SwigType_str(current_class_type,0)); + String *arg_str; + if(is_function) { + arg_str = NewString("args"); + } else { + arg_str = NewString("info"); + } + + t_selfptr.Replace(KW_TYPE, type_str) + .Replace(KW_ARG, arg_str); + Printv(wrapper->code, t_selfptr.str(), 0); + + Delete(type_str); + Delete(arg_str); + } + + int i = 0; + for (i = 0, p = parms; i < numarg; i++) + { + p = skipIgnoredArgs(p); + SwigType *pt = Getattr(p, "type"); + + String *arg = NewString(""); + if (i == 0) { + if(start_idx == 0) { + Printv(arg, is_setter?"value":"args[0]", 0); + } else { + p = Getattr(p, "tmap:in:next"); + Delete(arg); + continue; // special case: skip the typemaps for the first argument + } + } else { + Printf(arg, is_setter?"value":"args[%d]", i - start_idx); + } + + if ((tm = Getattr(p, "tmap:in"))) // Get typemap for this argument + { + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(wrapper->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + Delete(arg); + } +} + +/* --------------------------------------------------------------------- + * marshalOutput() + * + * Process the return value of the C/C++ function call + * and convert them into the Javascript types using the + * supplied typemaps. + * --------------------------------------------------------------------- */ + +void V8Emitter::marshalOutput(Node *n, String *actioncode, Wrapper *wrapper) { + SwigType *type = Getattr(n, "type"); + Setattr(n, "type", type); + String *tm; + if ((tm = Swig_typemap_lookup_out("out", n, "result", wrapper, actioncode))) + { + Replaceall(tm, "$result", "jsresult"); + // TODO: May not be the correct way + Replaceall(tm, "$objecttype", Swig_scopename_last(SwigType_str(SwigType_strip_qualifiers(type), 0))); + Printf(wrapper->code, "%s", tm); + if (Len(tm)) + Printf(wrapper->code, "\n"); + } 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")); + } + emit_return_variable(n, type, wrapper); +} + +Parm* V8Emitter::skipIgnoredArgs(Parm *p) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + return p; +} + + JSEmitter* create_v8_emitter() { return new V8Emitter(); diff --git a/Source/Modules/javascript_v8.h b/Source/Modules/javascript_v8.h index c70d54e34..7ff11f136 100644 --- a/Source/Modules/javascript_v8.h +++ b/Source/Modules/javascript_v8.h @@ -45,6 +45,12 @@ protected: virtual int EmitSetter(Node *n, bool is_member); + void marshalInputArgs(Node *n, ParmList *parms, int numarg, Wrapper *wrapper); + + void marshalOutput(Node *n, String *actioncode, Wrapper *wrapper); + + Parm *skipIgnoredArgs(Parm *p); + private: File *f_runtime; @@ -64,6 +70,7 @@ private: // state variables String* current_context; + String* current_class_type; String* current_classname_mangled; String* current_classname_unqualified; String* current_variable_mangled;