diff --git a/SWIG/Source/Modules/java.cxx b/SWIG/Source/Modules/java.cxx index f282a36a9..3fe7307ab 100644 --- a/SWIG/Source/Modules/java.cxx +++ b/SWIG/Source/Modules/java.cxx @@ -19,15 +19,34 @@ char cvsroot_java_cxx[] = "$Header$"; #endif #include +/* Hash type used for JNI upcall data */ +typedef DOH UpcallData; + +extern SwigType *cplus_value_type(SwigType *t); + +/* External functions borrowed from python.cxx module: */ + +extern String *Swig_csuperclass_call(String* base, String* method, ParmList* l); +extern String *Swig_class_declaration(Node *n, String *name); +extern String *Swig_class_name(Node *n); +extern String *Swig_director_declaration(Node *n); +extern String *Swig_method_call(String_or_char *name, ParmList *parms); +extern String *method_decl(SwigType *s, const String_or_char *id, List *args, int strip, int values); + +//------------------------------------------------------------------------ + class JAVA : public Language { static const char *usage; const String *empty_string; Hash *swig_types_hash; File *f_runtime; + File *f_runtime_h; File *f_header; File *f_wrappers; File *f_init; + File *f_directors; + File *f_directors_h; bool proxy_flag; // Flag for generating proxy classes bool have_default_constructor_flag; @@ -37,7 +56,9 @@ class JAVA : public Language { bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const bool global_variable_flag; // Flag for when wrapping a global variable + bool member_func_flag; // flag set when wrapping a member function + String *module; // module name String *imclass_name; // intermediary class name String *module_class_name; // module class name String *imclass_class_code; // intermediary class code @@ -50,6 +71,7 @@ class JAVA : public Language { String *module_class_constants_code; String *package; // Package name String *jnipackage; // Package name used in the JNI code + String *package_path; // Package name used internally by JNI (slashes) String *imclass_imports; //intermediary class imports from %pragma String *module_imports; //module imports from %pragma String *imclass_baseclass; //inheritance for intermediary class class from %pragma @@ -60,8 +82,16 @@ class JAVA : public Language { String *module_class_modifiers; //class modifiers for module class overriden by %pragma String *upcasts_code; //C++ casts for inheritance hierarchies C++ code String *imclass_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *imclass_directors; // Intermediate class director Java code String *destructor_call; //C++ destructor call if any + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + bool emitted_connect; + enum type_additions {none, pointer, reference}; public: @@ -75,9 +105,12 @@ class JAVA : public Language { swig_types_hash(NULL), f_runtime(NULL), + f_runtime_h(NULL), f_header(NULL), f_wrappers(NULL), f_init(NULL), + f_directors(NULL), + f_directors_h(NULL), proxy_flag(true), have_default_constructor_flag(false), @@ -87,6 +120,7 @@ class JAVA : public Language { variable_wrapper_flag(false), wrapping_member_flag(false), global_variable_flag(false), + member_func_flag(false), imclass_name(NULL), module_class_name(NULL), @@ -100,6 +134,7 @@ class JAVA : public Language { module_class_constants_code(NULL), package(NULL), jnipackage(NULL), + package_path(NULL), imclass_imports(NULL), module_imports(NULL), imclass_baseclass(NULL), @@ -110,8 +145,14 @@ class JAVA : public Language { module_class_modifiers(NULL), upcasts_code(NULL), imclass_cppcasts_code(NULL), - destructor_call(NULL) + imclass_directors(NULL), + destructor_call(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(0), + emitted_connect(false) { } @@ -200,31 +241,61 @@ class JAVA : public Language { * --------------------------------------------------------------------- */ virtual int top(Node *n) { + // Make the intermediary class and module class names. The + // intermediary class name can be set in the module directive. + + Node* optionsnode = Getattr( Getattr(n,"module"), "options"); + + if (optionsnode) { + if (Getattr(optionsnode,"jniclassname")) + imclass_name = Copy(Getattr(optionsnode,"jniclassname")); + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + if (Getattr(optionsnode, "directors")) { + allow_directors(); + } + } /* Initialize all of the output files */ String *outfile = Getattr(n,"outfile"); + String *outfile_h = Getattr(n, "outfile_h"); f_runtime = NewFile(outfile,"w"); if (!f_runtime) { Printf(stderr,"Unable to open %s\n", outfile); SWIG_exit(EXIT_FAILURE); } + + if (directorsEnabled()) { + f_runtime_h = NewFile(outfile_h,"w"); + if (!f_runtime_h) { + Printf(stderr,"*** Can't open '%s'\n", outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + f_init = NewString(""); f_header = NewString(""); f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); /* Register file targets with the SWIG file handler */ Swig_register_filebyname("header",f_header); Swig_register_filebyname("wrapper",f_wrappers); Swig_register_filebyname("runtime",f_runtime); Swig_register_filebyname("init",f_init); + Swig_register_filebyname("director",f_directors); + Swig_register_filebyname("director_h",f_directors_h); + swig_types_hash = NewHash(); - // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. - Node* optionsnode = Getattr( Getattr(n,"module") ,"options"); - if (optionsnode) - if (Getattr(optionsnode,"jniclassname")) - imclass_name = Copy(Getattr(optionsnode,"jniclassname")); if (!imclass_name) { imclass_name = NewStringf("%sJNI", Getattr(n,"name")); module_class_name = Copy(Getattr(n,"name")); @@ -236,7 +307,7 @@ class JAVA : public Language { module_class_name = Copy(Getattr(n,"name")); } - + module = Copy(Getattr(n,"name")); imclass_class_code = NewString(""); proxy_class_def = NewString(""); proxy_class_code = NewString(""); @@ -251,9 +322,16 @@ class JAVA : public Language { module_class_modifiers = NewString("public"); imclass_imports = NewString(""); imclass_cppcasts_code = NewString(""); + imclass_directors = NewString(""); upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + emitted_connect = false; if (!package) package = NewString(""); jnipackage = NewString(""); + package_path = NewString(""); Swig_banner(f_runtime); // Print the SWIG banner message @@ -261,13 +339,33 @@ class JAVA : public Language { Printf(f_runtime,"#define SWIG_NOINCLUDE\n"); } + if (directorsEnabled()) { + Printf(f_runtime,"#define SWIG_DIRECTORS\n"); + } + + /* Emit initial director header and director code: */ + if (directorsEnabled()) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "#ifndef __%s_WRAP_H__\n", module); + Printf(f_directors_h, "#define __%s_WRAP_H__\n\n", module); + Printf(f_directors_h, "class __DIRECTOR__;\n\n"); + Swig_insert_file("director.swg", f_directors); + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + Printf(f_directors, "#include \"%s\"\n\n", outfile_h); + } + String *wrapper_name = NewString(""); if(Len(package)) { String *jniname = makeValidJniName(package); Printv(jnipackage, jniname, NIL); + Printv(package_path, jniname, NIL); Delete(jniname); Replaceall(jnipackage,".","_"); + Replaceall(package_path, ".", "/"); Append(jnipackage, "_"); } String *jniname = makeValidJniName(imclass_name); @@ -319,6 +417,18 @@ class JAVA : public Language { // Add the intermediary class methods Printv(f_im, imclass_class_code, NIL); Printv(f_im, imclass_cppcasts_code, NIL); + if (Len(imclass_directors) > 0) { + Printf(f_im, "\n/* Director upcall methods: */\n\n"); + Printv(f_im, imclass_directors, NIL); + } + + if (n_dmethods > 0) { + Putc('\n', f_im); + Printf(f_im, " private final static native void __module_init();\n"); + Printf(f_im, " static {\n"); + Printf(f_im, " __module_init();\n"); + Printf(f_im, " }\n"); + } // Finish off the class Printf(f_im, "}\n"); @@ -401,6 +511,8 @@ class JAVA : public Language { if(upcasts_code) Printv(f_wrappers,upcasts_code,NIL); + emitDirectorUpcalls(); + Printf(f_wrappers,"#ifdef __cplusplus\n"); Printf(f_wrappers,"}\n"); Printf(f_wrappers,"#endif\n"); @@ -410,6 +522,17 @@ class JAVA : public Language { emitTypeWrapperClass(swig_type, Getattr(swig_types_hash, swig_type)); } + /* Close all of the files */ + Dump(f_header,f_runtime); + + if (directorsEnabled()) { + Dump(f_directors, f_runtime); + Dump(f_directors_h, f_runtime_h); + + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif /* __%s_WRAP_H__ */\n", module); + } + Delete(swig_types_hash); swig_types_hash = NULL; Delete(imclass_name); imclass_name = NULL; Delete(imclass_class_code); imclass_class_code = NULL; @@ -427,12 +550,24 @@ class JAVA : public Language { Delete(module_class_modifiers); module_class_modifiers = NULL; Delete(imclass_imports); imclass_imports = NULL; Delete(imclass_cppcasts_code); imclass_cppcasts_code = NULL; + Delete(imclass_directors); imclass_directors = NULL; Delete(upcasts_code); upcasts_code = NULL; Delete(package); package = NULL; Delete(jnipackage); jnipackage = NULL; + Delete(package_path); package_path = NULL; + Delete(dmethods_seq); dmethods_seq = NULL; + Delete(dmethods_table); dmethods_table = NULL; + n_dmethods = 0; + emitted_connect = false; + + if (f_runtime_h) { + Close(f_runtime_h); + Delete(f_runtime_h); f_runtime_h = NULL; + } + + Delete(f_directors); f_directors = NULL; + Delete(f_directors_h); f_directors_h = NULL; - /* Close all of the files */ - Dump(f_header,f_runtime); Dump(f_wrappers,f_runtime); Wrapper_pretty_print(f_init,f_runtime); Delete(f_header); @@ -457,6 +592,60 @@ class JAVA : public Language { Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); } + /*----------------------------------------------------------------------- + * Add new director upcall signature + *----------------------------------------------------------------------*/ + + String * + addUpcallMethod(String *director_class, String *method, String *signature) + { + UpcallData *udata; + String *methodno; + Hash *new_udata; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, director_class)) != NULL) + return Getattr(udata, "methodoff"); + + /* Clearly not, so make sure we don't already know about the Java + method and field descriptor signature */ + for (udata = Firstitem(dmethods_seq); udata != NULL; udata = Nextitem(dmethods_seq)) { + if (!Cmp(Getattr(udata, "method"), method) && !Cmp(Getattr(udata, "fdesc"), signature)) { + Setattr(dmethods_table, director_class, udata); + return Getattr(udata, "methodoff"); + } + } + + methodno = NewStringf("%d", n_dmethods); + n_dmethods++; + + new_udata = NewHash(); + Setattr(new_udata, "method", Copy(method)); + Setattr(new_udata, "fdesc", Copy(signature)); + Setattr(new_udata, "methodoff", methodno); + + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, director_class, new_udata); + + return methodno; + } + + /*----------------------------------------------------------------------- + * Get director upcall signature + *----------------------------------------------------------------------*/ + + String * + getUpcallMethod(String *director_class) + { + String *retval = NULL; + UpcallData *udata = Getattr(dmethods_table, director_class); + + if (udata) + retval = Getattr(udata, "methodoff"); + + return retval; + } + /* ---------------------------------------------------------------------- * nativeWrapper() * ---------------------------------------------------------------------- */ @@ -486,6 +675,7 @@ class JAVA : public Language { virtual int functionWrapper(Node *n) { String *symname = Getattr(n,"sym:name"); + Node *parent = parentNode(n); SwigType *t = Getattr(n,"type"); ParmList *l = Getattr(n,"parms"); String *tm; @@ -498,9 +688,45 @@ class JAVA : public Language { String *body = NewString(""); int num_arguments = 0; int num_required = 0; + int gencomma = 0; bool is_void_return; String *overloaded_name = getOverloadedName(n); + String *nodeType = nodeType(n); + int constructor = !(Cmp(nodeType, "constructor") && Cmp(nodeType, "class")); + int destructor = (!Cmp(nodeType, "destructor")); + String *storage = Getattr(n,"storage"); + int isVirtual = (!Cmp(storage,"virtual")); + bool pure_virtual = false; + bool director_method = false; + bool feature_director = false; + bool recursive_upcall = false; + bool feature_extend = !Cmp(Getattr(n, "feature:extend"), "1"); + String *director_class = NULL; + Wrapper *director_wrap = NewWrapper(); + int director_tmp = 1; + String *director_cargs = NewString(""); + String *director_uargs = NewString("jself"); + String *dirimclass_meth = NewStringf("__DIRECTOR__%s", overloaded_name); + + /* Do we have to emit the director hair version of the code? */ + + feature_director = (parent && Swig_directorclass(n)); + + if (member_func_flag + && isVirtual + && feature_director + && !(static_flag || constructor || destructor)) { + director_method = true; + director_class = NewStringf("__DIRECTOR__%s", proxy_class_name); + + recursive_upcall = !(Cmp(Getattr(n, "feature:director:recursive"), "1") + && Cmp(Getattr(parent, "feature:director:recursive"), "1")); + } + + if (!Cmp(Getattr(n, "value"), "0")) + pure_virtual = true; + if (!Getattr(n,"sym:overloaded")) { if (!addSymbol(Getattr(n,"sym:name"),n)) return SWIG_ERROR; } @@ -545,6 +771,8 @@ class JAVA : public Language { /* Attach the non-standard typemaps to the parameter list. */ Swig_typemap_attach_parms("jni", l, f); Swig_typemap_attach_parms("jtype", l, f); + if (director_method) + Setattr(n, "tmap:inv", Swig_typemap_lookup_new("inv", n, "", 0)); /* Get return types */ if ((tm = Swig_typemap_lookup_new("jni",n,"",0))) { @@ -566,13 +794,40 @@ class JAVA : public Language { Wrapper_add_localv(f,"jresult", c_return_type, "jresult = 0",NIL); Printf(imclass_class_code, " public final static native %s %s(", im_return_type, overloaded_name); - Printv(f->def, "JNIEXPORT ", c_return_type, " JNICALL ", wname, "(JNIEnv *jenv, jclass jcls", NIL); + if (director_method) + Printf(director_wrap->def, " public static %s %s(", im_return_type, dirimclass_meth); + + // Usually these function parameters are unused - The code below ensures + // that compilers do not issue such a warning if configured to do so. - // Usually these function parameters are unused - The code below ensures that compilers do not issue such a warning if configured to do so. Printv(f->code," (void)jenv;\n",NIL); Printv(f->code," (void)jcls;\n",NIL); + /* Add the class's java object, when applicable */ + if (member_func_flag && !(static_flag || feature_extend || constructor || destructor)) { + Printf(f->def, ", jobject jself"); + Printf(imclass_class_code, "%s self", proxy_class_name); + Append(f->code," (void)jself;\n"); + + if (director_method) { + String *director_decl = NewStringf("%s *", director_class); + Wrapper_add_localv(f, "director", director_decl, "director = 0", NIL); + Printf(director_wrap->def, "%s self", proxy_class_name); + Delete(director_decl); + } + + ++gencomma; + } + + /* Don't make director methods do work if all the code will do is + * call Java next, encapsulate the ordinary argument marshalling. */ + + if (director_method) { + Printf(f->code, "director = dynamic_cast<%s *>(arg1);\n", director_class); + Printf(f->code, "if (director == NULL || !director->__is_derived()) {\n"); + } + // Emit all of the local variables for holding arguments. emit_args(t,l,f); @@ -583,7 +838,6 @@ class JAVA : public Language { /* Get number of required and total arguments */ num_arguments = emit_num_arguments(l); num_required = emit_num_required(l); - int gencomma = 0; // Now walk the function parameter list and generate code to get arguments for (i = 0, p=l; i < num_arguments; i++) { @@ -620,11 +874,64 @@ class JAVA : public Language { if(gencomma) Printf(imclass_class_code, ", "); Printf(imclass_class_code, "%s %s", im_param_type, arg); - gencomma = 1; - // Add parameter to C function Printv(f->def, ", ", c_param_type, " ", arg, NIL); + if (director_method) { + String *out_tm; + String *base_type = SwigType_base(pt); + Node *tn; + Parm *tp = NewParm(c_param_type, arg); + + /* Make sure base_type isn't actually a class */ + tn = Swig_symbol_clookup(base_type, Getattr(n, "sym:symtab")); + if (tn != NULL) { + Delete(base_type); + base_type = Copy(Getattr(tn, "sym:name")); + } + + /* Add argument to director call arguments */ + + Append(director_uargs, ", "); + Append(director_uargs, arg); + + if (i > 0) { + out_tm = Swig_typemap_lookup_new("directorin", p, "", 0); + if (out_tm) { + String *darg = NewStringf("darg%d", director_tmp++); + String *darg_init = NULL; + + Replaceall(out_tm, "$javaclassname", base_type); + Replaceall(out_tm, "$jniinput", arg); + + if (gencomma > 1) + Append(director_wrap->def, ", "); + if (gencomma > 2) + Append(director_cargs, ", "); + + Printf(director_wrap->def, "%s %s", im_param_type, arg); + + if (Cmp(out_tm, arg)) { + darg_init = NewStringf("%s = %s", darg, out_tm); + Wrapper_add_localv(director_wrap, darg, base_type, darg_init, NIL); + Append(director_cargs, darg); + } else + Append(director_cargs, arg); + + Delete(darg); + if (darg_init) + Delete(darg_init); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "No directorin typemap defined for %s\n", SwigType_str(tp,0)); + } + } + + Delete(base_type); + } + + ++gencomma; + // Get typemap for this argument if ((tm = Getattr(p,"tmap:in"))) { addThrows(n, "tmap:in", p); @@ -755,10 +1062,119 @@ class JAVA : public Language { } } + /* Director code generation */ + if (director_method) { + String *jdescrip, *upcall_method; + + Printf(f->code, "} else {\n"); + + if ((tm= Getattr(n, "tmap:inv")) != NULL && (jdescrip = Getattr(n, "tmap:inv:parse")) != NULL) { + String *jni_canon = canonicalJNIFDesc(jdescrip, proxy_class_name); + + Delete(jdescrip); + jdescrip = jni_canon; + + upcall_method = getUpcallJNIMethod(jdescrip); + + if (upcall_method != NULL) { + String *methid = getUpcallMethod(dirimclass_meth); + + assert(methid != NULL); + + if (!recursive_upcall) { + Printf(f->code, " if (!director->__get_ricochet()) {\n"); + Printf(f->code, " director->__set_ricochet();\n"); + } + + if (!is_void_return) + Printf(f->code, " jresult = (%s) jenv->%s(jcls, __SWIG_director_methids[%s], %s);\n", + c_return_type, upcall_method, methid, director_uargs); + else + Printf(f->code, " jenv->%s(jcls, __SWIG_director_methids[%s], %s);\n", + upcall_method, methid, director_uargs); + + if (!recursive_upcall) { + Printf(f->code, " director->__clear_ricochet();\n"); + Printf(f->code, " } else {\n"); + + if (!pure_virtual) { + Printf(f->code, " SWIG_JavaThrowException(jenv, SWIG_JavaDirectorRicochet,\n"); + Printf(f->code, " \"Recursive loop into director method %s::%s detected.\");\n", + proxy_class_name, Getattr(n, "name")); + } else { + Printf(f->code, " SWIG_JavaThrowException(jenv, SWIG_JavaDirectorPureVirtual,\n"); + Printf(f->code, " \"Pure virtual director method %s::%s invoked.\");\n", + proxy_class_name, Getattr(n, "name")); + } + + Printf(f->code, "}"); + } + + Delete(methid); + Delete(upcall_method); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_NODIRECTOR_CODE, input_file, line_number, + "Cannot determine Java method for %s, no upcall generated.\n", jdescrip); + } + + Delete(jdescrip); + } else { + Swig_warning(WARN_TYPEMAP_INV_UNDEF, input_file, line_number, + "No or improper inv typemap defined for %s\n", c_return_type); + } + + Printf(f->code, " }\n"); + } + /* Finish C function and intermediary class function definitions */ Printf(imclass_class_code, ")"); generateThrowsClause(n, imclass_class_code); Printf(imclass_class_code, ";\n"); + + if (director_method) { + String *upcall_name; + + upcall_name = Getattr(n, "memberfunctionHandler:sym:name"); + if (upcall_name == NULL) + upcall_name = Getattr(n, "sym:name"); + + /* Finish off the intermediate class's upcall wrapper's definition */ + Printf(director_wrap->def, ")"); + generateThrowsClause(n, director_wrap->def); + Printf(director_wrap->def, " {"); + + /* Add the code to do the actual upcall... */ + + if (!is_void_return) { + String *out_tm; + String *upcall; + String *jclassname = NULL; + Node *rn; + String *basetype = SwigType_base(Getattr(n, "type")); + + upcall = NewStringf("self.%s(%s)", upcall_name, director_cargs); + + rn = Swig_symbol_clookup(basetype, Getattr(n, "sym:symtab")); + if (rn != NULL) + jclassname = Getattr(rn, "sym:name"); + + out_tm = Swig_typemap_lookup_new("directorout", n, "", 0); + if (out_tm != NULL) { + if (jclassname != NULL) + Replaceall(out_tm, "$javaclassname", jclassname); + Replaceall(out_tm, "$javacall", upcall); + Printf(director_wrap->code, "return %s;\n", out_tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "No directorout typemap defined for %s\n", proxy_class_name); + } + } else + Printf(director_wrap->code, "self.%s(%s);\n", upcall_name, director_cargs); + + Printf(director_wrap->code, "}\n"); + Wrapper_print(director_wrap, imclass_directors); + } + Printf(f->def,") {"); if(!is_void_return) @@ -789,6 +1205,10 @@ class JAVA : public Language { moduleClassFunctionHandler(n); } + if (director_class) + Delete(director_class); + Delete(dirimclass_meth); + Delete(director_cargs); Delete(c_return_type); Delete(im_return_type); Delete(cleanup); @@ -804,7 +1224,9 @@ class JAVA : public Language { * ----------------------------------------------------------------------- */ virtual int variableWrapper(Node *n) { + variable_wrapper_flag = true; Language::variableWrapper(n); /* Default to functions */ + variable_wrapper_flag = false; return SWIG_OK; } @@ -1159,6 +1581,13 @@ class JAVA : public Language { "\n", NIL); + /* Insert declaration for __director_connect(), if this class has + directors enabled */ + if (parentNode(n) && Swig_directorclass(n)) { + Printf(proxy_class_def, " private final native static void __director_connect(%s self, long cptr);\n\n", + proxy_class_name); + } + // Substitute various strings into the above template Replaceall(proxy_class_code, "$javaclassname", proxy_class_name); Replaceall(proxy_class_def, "$javaclassname", proxy_class_name); @@ -1249,6 +1678,7 @@ class JAVA : public Language { destructor_call = NewString(""); proxy_class_constants_code = NewString(""); } + Language::classHandler(n); if (proxy_flag) { @@ -1269,6 +1699,10 @@ class JAVA : public Language { Delete(destructor_call); destructor_call = NULL; Delete(proxy_class_constants_code); proxy_class_constants_code = NULL; } + + /* Reinitialize per-class director vars */ + emitted_connect = false; + return SWIG_OK; } @@ -1277,6 +1711,7 @@ class JAVA : public Language { * ---------------------------------------------------------------------- */ virtual int memberfunctionHandler(Node *n) { + member_func_flag = true; Language::memberfunctionHandler(n); if (proxy_flag) { @@ -1287,6 +1722,7 @@ class JAVA : public Language { proxyClassFunctionHandler(n); Delete(overloaded_name); } + member_func_flag = false; return SWIG_OK; } @@ -1297,6 +1733,7 @@ class JAVA : public Language { virtual int staticmemberfunctionHandler(Node *n) { static_flag = true; + member_func_flag = true; Language::staticmemberfunctionHandler(n); if (proxy_flag) { @@ -1308,6 +1745,7 @@ class JAVA : public Language { Delete(overloaded_name); } static_flag = false; + member_func_flag = false; return SWIG_OK; } @@ -1331,6 +1769,7 @@ class JAVA : public Language { String *tm; Parm *p; int i; + bool feature_extend = !(Cmp(Getattr(n, "feature:extend"), "1")); String *imcall = NewString(""); String *return_type = NewString(""); String *function_code = NewString(""); @@ -1364,8 +1803,12 @@ class JAVA : public Language { Printf(function_code, "%s %s(", return_type, proxy_function_name); Printv(imcall, imclass_name, ".", intermediary_function_name, "(", NIL); - if (!static_flag) - Printv(imcall, "swigCPtr", NIL); + if (!static_flag) { + if (member_func_flag && !feature_extend) + Printf(imcall, "this, "); + + Printf(imcall, "swigCPtr"); + } emit_mark_varargs(l); @@ -1387,7 +1830,7 @@ class JAVA : public Language { } /* Ignore the 'this' argument for variable wrappers */ - if (!(variable_wrapper_flag && i==0)) + if (!(variable_wrapper_flag && i==0) || static_flag) { SwigType *pt = Getattr(p,"type"); String *param_type = NewString(""); @@ -1420,7 +1863,7 @@ class JAVA : public Language { /* Add parameter to proxy function */ if (gencomma >= 2) Printf(function_code, ", "); - gencomma = 2; + ++gencomma; Printf(function_code, "%s %s", param_type, arg); Delete(arg); @@ -1465,15 +1908,17 @@ class JAVA : public Language { String *tm; Parm *p; int i; + bool feature_director = (Cmp(Getattr(n, "feature:director"), "1") == 0); Language::constructorHandler(n); if(proxy_flag) { String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(overloaded_name); String *imcall = NewString(""); Printf(proxy_class_code, " %s %s(", Getattr(n,"feature:java:methodmodifiers"), proxy_class_name); - Printv(imcall, "this(", imclass_name, ".", Swig_name_construct(overloaded_name), "(", NIL); + Printv(imcall, "this(", imclass_name, ".", mangled_overname, "(", NIL); /* Attach the non-standard typemaps to the parameter list */ Swig_typemap_attach_parms("in", l, NULL); @@ -1483,6 +1928,7 @@ class JAVA : public Language { emit_mark_varargs(l); int gencomma = 0; + int ctor_arg_cnt = 0; /* Output each parameter */ for (i = 0, p=l; p; i++) { @@ -1531,7 +1977,8 @@ class JAVA : public Language { if(gencomma) Printf(proxy_class_code, ", "); Printf(proxy_class_code, "%s %s", param_type, arg); - gencomma = 1; + ++gencomma; + ctor_arg_cnt++; Delete(arg); Delete(param_type); @@ -1544,9 +1991,38 @@ class JAVA : public Language { generateThrowsClause(n, proxy_class_code); Printf(proxy_class_code, " {\n"); Printf(proxy_class_code, " %s", imcall); + + /* Add director connection call if this class has directors. */ + + if (feature_director) { + Printf(proxy_class_code, " __director_connect(this, swigCPtr);\n"); + + if (!emitted_connect) { + String *jni_class_name = makeValidJniName(proxy_class_name); + Wrapper *conn_wrap; + + conn_wrap = NewWrapper(); + Printf(conn_wrap->def, "JNIEXPORT void JNICALL Java_%s%s__1_1director_1connect(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg) {", + jnipackage, jni_class_name); + Printf(conn_wrap->code, " %s *obj = *((%s **) &objarg);\n", Getattr(n, "name"), Getattr(n, "name")); + Printf(conn_wrap->code, " __DIRECTOR__%s *director = dynamic_cast<__DIRECTOR__%s *>(obj);\n", + Getattr(n, "sym:name"), Getattr(n, "sym:name")); + Printf(conn_wrap->code, " if (director) {\n"); + Printf(conn_wrap->code, " director->__set_self(jenv, jself);\n"); + Printf(conn_wrap->code, " director->__connect_methods(jenv, jenv->GetObjectClass(jself));\n"); + Printf(conn_wrap->code, " }\n"); + Printf(conn_wrap->code, "}\n"); + + Wrapper_print(conn_wrap, f_wrappers); + Delete(jni_class_name); + DelWrapper(conn_wrap); + emitted_connect = true; + } + } + Printf(proxy_class_code, " }\n\n"); - if(!gencomma) // We must have a default constructor + if(!ctor_arg_cnt) // We must have a default constructor have_default_constructor_flag = true; Delete(overloaded_name); @@ -1616,8 +2092,11 @@ class JAVA : public Language { String *getOverloadedName(Node *n) { - /* Although JNI functions are designed to handle overloaded Java functions, a Java long is used for all classes in the SWIG - * intermediary class. The intermediary class methods are thus mangled when overloaded to give a unique name. */ + /* Although JNI functions are designed to handle overloaded Java functions, + * a Java long is used for all classes in the SWIG intermediary class. + * The intermediary class methods are thus mangled when overloaded to give + * a unique name. */ + String *overloaded_name = NewStringf("%s", Getattr(n,"sym:name")); if (Getattr(n,"sym:overloaded")) { @@ -1981,6 +2460,684 @@ class JAVA : public Language { } } + /*---------------------------------------------------------------------- + * getUpcallJNIMethod() + *--------------------------------------------------------------------*/ + + String * getUpcallJNIMethod(String *descrip) + { + static struct { + char code; + const char *method; + } upcall_methods[] = { + { 'B', "CallStaticByteMethod" }, + { 'C', "CallStaticCharMethod" }, + { 'D', "CallStaticDoubleMethod" }, + { 'F', "CallStaticFloatMethod" }, + { 'I', "CallStaticIntMethod" }, + { 'J', "CallStaticLongMethod" }, + { 'L', "CallStaticObjectMethod" }, + { 'S', "CallStaticShortMethod" }, + { 'V', "CallStaticVoidMethod" }, + { 'Z', "CallStaticBooleanMethod" }, + { '[', "CallStaticObjectMethod" } + }; + + char code; + int i; + + code = *Char(descrip); + for (i = 0; i < (int) (sizeof(upcall_methods)/sizeof(upcall_methods[0])); ++i) + if (code == upcall_methods[i].code) + return NewString(upcall_methods[i].method); + return NULL; + } + + /*---------------------------------------------------------------------- + * emitDirectorUpcalls() + *--------------------------------------------------------------------*/ + + void emitDirectorUpcalls() + { + if (n_dmethods) { + Wrapper *w = NewWrapper(); + String *jni_imclass_name = makeValidJniName(imclass_name); + UpcallData *udata; + + Printf(f_runtime, "static jclass __SWIG_jclass_%s = NULL;\n", imclass_name); + Printf(f_runtime, "static jmethodID __SWIG_director_methids[%d];\n", n_dmethods); + + Printf(w->def, "JNIEXPORT void JNICALL Java_%s%s__1_1module_1init(JNIEnv *jenv, jclass jcls) {", + jnipackage, jni_imclass_name); + Printf(w->code, "static struct {\n"); + Printf(w->code, " const char *method;\n"); + Printf(w->code, " const char *signature;\n"); + Printf(w->code, "} methods[%d] = {\n", n_dmethods); + + udata = Firstitem(dmethods_seq); + while ( udata) { + Printf(w->code, " { \"%s\", \"%s\" }", Getattr(udata, "method"), Getattr(udata, "fdesc")); + udata = Nextitem(dmethods_seq); + if (udata) + Putc(',', w->code); + Putc('\n', w->code); + } + + Printf(w->code, "};\n"); + + Wrapper_add_local(w, "i", "int i"); + + Printf(w->code, "__SWIG_jclass_%s = (jclass) jenv->NewGlobalRef(jcls);\n", imclass_name); + Printf(w->code, "if (__SWIG_jclass_%s == NULL) return;\n", imclass_name); + Printf(w->code, "for (i = 0; i < (int) (sizeof(methods)/sizeof(methods[0])); ++i) {\n"); + Printf(w->code, " __SWIG_director_methids[i] = jenv->GetStaticMethodID(jcls, methods[i].method, methods[i].signature);\n"); + Printf(w->code, " if (__SWIG_director_methids[i] == NULL) return;\n"); + Printf(w->code, "}\n"); + + Printf(w->code, "}\n"); + + Wrapper_print(w, f_wrappers); + Delete(jni_imclass_name); + DelWrapper(w); + } + } + + /* --------------------------------------------------------------- + * Canonicalize the JNI field descriptor + * !!SFM!! If $packagepath occurs in the field descriptor, but + * package_path isn't set (length == 0), then strip it and the + * optional trailing '/' from the resulting name. + * + * --------------------------------------------------------------- */ + + String *canonicalJNIFDesc(String *in_desc, String *classname) + { + String *mod_desc = Copy(in_desc); + + if (Len(package_path) > 0) { + Replaceall(mod_desc, "$packagepath", package_path); + } else { + String *empty_str = NewString(""); + + Replaceall(mod_desc, "$packagepath/", empty_str); + Replaceall(mod_desc, "$packagepath", empty_str); + } + + Replaceall(mod_desc, "$javaclassname", SwigType_base(classname)); + return mod_desc; + } + + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // (scottm) Class director mods: + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Java object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) + { + String *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *name = Getattr(n, "name"); + String *type = Getattr(n, "type"); + String *c_classname = NULL; + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *return_type = Copy(type); + String *tm; + Parm *p; + int i, num_arguments, num_required; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(type, "void")); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + bool is_const = SwigType_isconst(decl); + int status = SWIG_OK; + + bool output_director = true; + bool recursive_upcall = false; + String *jclassname = NewStringf("__DIRECTOR__%s", classname); + String *qualified_name = NewStringf("%s::%s", jclassname, name); + String *jnidesc = NewString("("); + String *jniret_desc = NewString(""); + String *jniret_type = NULL; + String *jupcall_args = NewString("__self"); + + c_classname = Getattr(parent, "name"); + if (!(Cmp(type, "class"))) + c_classname = classname; + + // This is a kludge: functionWrapper has sym:overload set properly, but it + // isn't at this point, so we have to manufacture it ourselves. At least + // we're consistent with the sym:overload name in functionWrapper. (?? when + // does the overloaded method name get set?) + String *imclass_dmethod = NewStringf("__DIRECTOR__%s", Swig_name_member(classname, overloaded_name)); + + /* Check if the user wants upcall recursion */ + recursive_upcall = !(Cmp(Getattr(n, "feature:director:recursive"), "1") + && Cmp(Getattr(parent, "feature:director:recursive"), "1")); + + /* Handle and form complete return type, including the modification + to a pointer, if return type is a reference. */ + + if (return_type) { + if (!is_void) { + SwigType *t = Copy(decl); + SwigType *f = SwigType_pop_function(t); + + SwigType_push(return_type, t); + + Delete(f); + Delete(t); + + if (!SwigType_isclass(return_type)) { + Wrapper_add_localv(w, "result", SwigType_lstr(return_type, "result"), "= 0", NIL); + } else { + SwigType *vt = NULL; + vt = cplus_value_type(return_type); + if (vt == NULL) { + Wrapper_add_localv(w, "result", SwigType_lstr(return_type, "result"), "= 0", NIL); + } else { + Wrapper_add_localv(w, "result", SwigType_lstr(vt, "result"), "= 0", NIL); + Delete(vt); + } + } + } + } + + /* Go through argument list, attach lnames, doing special handling + * for references (out typemap needs the lname set. */ + for (i = 0, p=l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (arg == NULL && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, w); + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("inv", l, w); + Swig_typemap_attach_parms("jni", l, 0); + + /* Get the JNI field descriptor for this return type */ + + if ((jniret_type = Swig_typemap_lookup_new("jni", n, "", 0)) != NULL) { + String *jdesc; + Parm *tp = NewParm(jniret_type, empty_str); + + if (!is_void) { + String *jretval_decl = NewStringf("%s jresult", jniret_type); + Wrapper_add_localv(w, "jresult", jretval_decl, " = 0", NIL); + Delete(jretval_decl); + } + + if ((tm = Swig_typemap_lookup_new("inv", tp, "", 0)) != NULL + && (jdesc = Getattr(tp, "tmap:inv:parse")) != NULL) { + String *jnidesc_canon; + + jnidesc_canon = canonicalJNIFDesc(jdesc, classname); + Append(jniret_desc, jnidesc_canon); + Delete(jnidesc_canon); + } else { + Swig_warning(WARN_TYPEMAP_INV_UNDEF, input_file, line_number, + "No or improper inv typemap defined for %s\n", SwigType_str(jniret_type,0)); + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, + "No jni typemap defined for %s\n", SwigType_str(type,0)); + output_director = false; + } + + /* header declaration */ + { + String *target; + + target = method_decl(decl, qualified_name, l, 0, 0); + String *rtype = SwigType_str(type, 0); + + Printf(w->def, "%s %s {", rtype, target); + Delete(qualified_name); + Delete(target); + + target = method_decl(decl, name, l, 0, 1); + Printf(declaration, " virtual %s %s;\n", rtype, target); + Delete(rtype); + Delete(target); + } + + /* Add Java environment pointer to wrapper */ + { + String *jenvstr = NewString("jenv"); + + Wrapper_add_localv(w, jenvstr, "JNIEnv *", jenvstr, "= (JNIEnv *) NULL", NIL); + Delete(jenvstr); + } + + /* Preamble code */ + Printf(w->code, "if (!__is_derived()) {\n"); + if (!pure_virtual) { + if (is_void) { + Printf(w->code, "%s;\n", Swig_method_call(super,l)); + Printf(w->code, "return;\n"); + } else { + String *super_call = Swig_method_call(super, l); + Printf(w->code, "return %s;\n", super_call); + Delete(super_call); + } + } else { + Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaDirectorPureVirtual,\n"); + Printf(w->code, " \"Attempted to invoke pure virtual method %s::%s.\");\n", + c_classname, name); + } + Printf(w->code, "}\n"); + + /* Start the Java field descriptor for this upcall (insert self object) */ + + { + Parm *tp = NewParm(classname, empty_str); + String *jdesc; + + if ((tm = Swig_typemap_lookup_new("inv", tp, "", 0)) != NULL + && (jdesc = Getattr(tp, "tmap:inv:parse")) != NULL) { + String *jni_canon; + + jni_canon = canonicalJNIFDesc(jdesc, SwigType_base(classname)); + Append(jnidesc, jni_canon); + Delete(jni_canon); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_INV_UNDEF, input_file, line_number, + "No or improper inv typemap defined for %s\n", SwigType_str(classname, 0)); + output_director = false; + } + + Delete(tp); + } + + Printf(w->code, "jenv = __acquire_jenv();\n"); + Printf(w->code, "assert(jenv);\n"); + Printf(w->code, "assert(__self);\n"); + if (!recursive_upcall) { + if (!is_const) + Printf(w->code, "if (!__get_ricochet()) {\n"); + else + Printf(w->code, "if (!const_cast<%s *>(this)->__get_ricochet()) {\n", jclassname); + } + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + /* Go through argument list, convert from native to Java */ + for (i = 0, p=l; i < num_arguments; i++) { + while (checkAttribute(p,"tmap:in:numinputs","0")) { + p = Getattr(p,"tmap:in:next"); + } + + SwigType *pt = Getattr(p,"type"); + String *ln = Copy(Getattr(p,"name")); + String *c_param_type = NULL; + String *c_decl = NewString(""); + String *arg = NewString(""); + + Printf(arg,"j%s", ln); + + /* And add to the upcall args */ + Printf(jupcall_args, ", %s", arg); + + /* Get parameter's JNI C type */ + if ((c_param_type = Getattr(p, "tmap:jni")) != NULL) { + Parm *tp = NewParm(c_param_type, empty_str); + String *desc_tm, *jdesc; + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + Wrapper_add_local(w, arg, c_decl); + + /* Add input marshalling code and update JNI field descriptor */ + if ((desc_tm = Swig_typemap_lookup_new("inv", tp, "", 0)) != NULL + && (jdesc = Getattr(tp, "tmap:inv:parse")) != NULL) { + if ((tm = Getattr(p, "tmap:inv")) != NULL) { + String *jni_canon; + + jni_canon = canonicalJNIFDesc(jdesc, SwigType_base(pt)); + Append(jnidesc, jni_canon); + Delete(jni_canon); + + Replaceall(tm,"$input", arg); + + if (Len(tm)) + Printf(w->code,"%s\n", tm); + + Delete(tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_INV_UNDEF, input_file, line_number, + "No or improper inv typemap defined for %s\n", SwigType_str(pt, 0)); + output_director = false; + p = nextSibling(p); + } + + Delete(desc_tm); + } else { + Swig_warning(WARN_TYPEMAP_INV_UNDEF, input_file, line_number, + "No or improper inv typemap defined for %s\n", SwigType_str(c_param_type, 0)); + output_director = false; + p = nextSibling(p); + } + + Delete(tp); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, + "No jni typemap defined for %s\n", SwigType_str(pt,0)); + output_director = false; + p = nextSibling(p); + } + + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + } + + /* Finish off the JNI field descriptor */ + Printf(jnidesc, ")%s", jniret_desc); + + /* Emit the actual upcall through JNI */ + String *methid = addUpcallMethod(imclass_dmethod, imclass_dmethod, jnidesc); + String *methop = getUpcallJNIMethod(jniret_desc); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("result"); + Parm *tp = NewParm(return_type, result_str); + + if (!recursive_upcall) { + if (!is_const) + Printf(w->code, " __set_ricochet();\n"); + else + Printf(w->code, " const_cast<%s *>(this)->__set_ricochet();\n", jclassname); + } + + Printf(w->code, "jresult = (%s) jenv->%s(__SWIG_jclass_%s, __SWIG_director_methids[%s], %s);\n", + jniret_type, methop, imclass_name, methid, jupcall_args); + + if (!recursive_upcall) { + if (!is_const) + Printf(w->code, "__clear_ricochet();\n"); + else + Printf(w->code, " const_cast<%s *>(this)->__clear_ricochet();\n", jclassname); + } + + /* Copy jresult into result... */ + if ((tm = Swig_typemap_lookup_new("in", tp, result_str, 0))) { + addThrows(n, "tmap:in", tp); + Replaceall(tm,"$source", jresult_str); /* deprecated */ + Replaceall(tm,"$target", result_str); /* deprecated */ + Replaceall(tm,"$arg", jresult_str); /* deprecated? */ + Replaceall(tm,"$input", jresult_str); + Printf(w->code,"%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument.\n",SwigType_str(tp,0)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } else { + if (!recursive_upcall) { + if (!is_const) + Printf(w->code, " __set_ricochet();\n"); + else + Printf(w->code, " const_cast<%s *>(this)->__set_ricochet();\n", jclassname); + } + + Printf(w->code, "jenv->%s(__SWIG_jclass_%s, __SWIG_director_methids[%s], %s);\n", + methop, imclass_name, methid, jupcall_args); + if (!recursive_upcall) { + if (!is_const) + Printf(w->code, "__clear_ricochet();\n"); + else + Printf(w->code, " const_cast<%s *>(this)->__clear_ricochet();\n", jclassname); + } + } + + if (!recursive_upcall) { + Printf(w->code, "} else {\n"); + Printf(w->code, " SWIG_JavaThrowException(jenv, SWIG_JavaDirectorRicochet,\n"); + Printf(w->code, " \"Recursive loop into director method %s::%s detected.\");\n", + c_classname, name); + Printf(w->code, "}\n"); + } + + /* Terminate wrapper code */ + if (!is_void) + Printf(w->code, "return (%s);\n", SwigType_rcaststr(return_type, "result")); + + Printf(w->code, "}\n"); + + /* emit code */ + if (status == SWIG_OK && output_director) { + if(!is_void) + Replaceall(w->code,"$null", (!SwigType_isreference(return_type) ? "result" : "*result")); + else + Replaceall(w->code,"$null",""); + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + } + + Delete(jclassname); + Delete(jnidesc); + Delete(jniret_type); + Delete(jniret_desc); + Delete(declaration); + DelWrapper(w); + + return status; + } + + /* ------------------------------------------------------------ + * directorPrefixArgs() + * ------------------------------------------------------------ */ + + void directorPrefixArgs(Node *n) + { + Parm *p; + + /* Need to prepend 'jenv' to the director constructor's argument list */ + + String *jenv_type = NewString("JNIEnv"); + + SwigType_add_pointer(jenv_type); + + p = NewParm(jenv_type, NewString("jenv")); + Setattr(p, "arg:byname", "1"); + set_nextSibling(p, NULL); + + Setattr(n, "director:prefix_args", p); + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = parentNode(n); + String *decl = Getattr(n, "decl");; + String *supername = Swig_class_name(parent); + String *classname = NewStringf("__DIRECTOR__%s", supername); + String *sub = NewString(""); + + /* insert jenv prefix argument */ + /* Note the reverse order for prepending arguments to the constructor. */ + /* Also note that this code adds prefix parameters for the director's + constructor. */ + Parm *p, *p2; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + + String *jenv_type = NewString("JNIEnv"); + SwigType_add_pointer(jenv_type); + p = NewParm(jenv_type, NewString("jenv")); + p2 = CopyParm(p); + set_nextSibling(p, parms); + parms = p; + + directorPrefixArgs(n); + + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = method_decl(decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, __DIRECTOR__(jenv), __derived(false) {", classname, target, call); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Delete(target); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = method_decl(decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(jenv_type); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname; + classname = Swig_class_name(n); + { + Wrapper *w = NewWrapper(); + Printf(w->def, "__DIRECTOR__%s::__DIRECTOR__%s(JNIEnv *jenv): __DIRECTOR__(jenv) {", + classname, classname); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " __DIRECTOR__%s(JNIEnv *jenv);\n", classname); + Delete(classname); + directorPrefixArgs(n); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + String *internal_classname; + String *classname = Getattr(n, "sym:name"); + String *director_classname = NewStringf("__DIRECTOR__%s", classname); + + if (Len(package_path) > 0) + internal_classname = NewStringf("%s/%s", package_path, classname); + else + internal_classname = NewStringf("%s", classname); + + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " bool __derived;\n"); + Printf(f_directors_h, "\npublic:\n"); + Printf(f_directors_h, " virtual ~%s();\n", director_classname); + Printf(f_directors_h, " void __connect_methods(JNIEnv *, jclass);\n"); + Printf(f_directors_h, " inline bool __is_derived() const { return __derived; };\n"); + Delete(declaration); + + Printf(f_directors, "%s::~%s() { /* NOP */ }\n\n", director_classname, director_classname); + + Delete(internal_classname); + Delete(director_classname); + + return Language::classDirectorInit(n); + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + String *classname = Getattr(n, "sym:name"); + String *director_classname = NewStringf("__DIRECTOR__%s", classname); + String *internal_classname; + + Printf(f_directors_h, "};\n\n"); + + Wrapper *w = NewWrapper(); + + if (Len(package_path) > 0) + internal_classname = NewStringf("%s/%s", package_path, classname); + else + internal_classname = NewStringf("%s", classname); + + Wrapper_add_local(w, "baseclass", "jclass baseclass"); + Printf(w->def, "void %s::__connect_methods(JNIEnv *jenv, jclass jcls) {", director_classname); + Printf(w->code, "baseclass = jenv->FindClass(\"%s\");\n", internal_classname); + Printf(w->code, "assert(baseclass);\n"); + Printf(w->code, "__derived = (jenv->IsSameObject(baseclass, jcls) ? false : true);\n"); + Printf(w->code, "}\n"); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(director_classname); + Delete(internal_classname); + + return Language::classDirectorEnd(n); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + virtual int classDirectorDisown(Node *n) + { + /* NOP */ + return SWIG_OK; + } }; /* class JAVA */ /* ----------------------------------------------------------------------------- diff --git a/SWIG/Source/Modules/lang.cxx b/SWIG/Source/Modules/lang.cxx index 4f2cf7e37..3f74b1a77 100644 --- a/SWIG/Source/Modules/lang.cxx +++ b/SWIG/Source/Modules/lang.cxx @@ -202,6 +202,16 @@ Language::Language() { symbols = NewHash(); classtypes = NewHash(); none_comparison = NewString("$arg != 0"); + director_ctor_code = NewString(""); + + /* Default director constructor code, passed to Swig_ConstructorToFunction */ + Printv(director_ctor_code, + "if ( $comparison ) { /*subclassed */\n", + " $director_new \n", + "} else {\n", + " $nondirector_new \n", + "}\n", NIL); + overloading = 0; multiinput = 0; directors = 0; @@ -1609,11 +1619,7 @@ int Language::classDeclaration(Node *n) { InClass = 1; CurrentClass = n; - if (Getattr(n,"abstract")) { - Abstract = 1; - } else { - Abstract = 0; - } + Abstract = (Getattr(n,"abstract") ? 1 : 0); /* Call classHandler() here */ if (!ImportMode) { @@ -1767,7 +1773,7 @@ Language::constructorHandler(Node *n) { mrename = Swig_name_construct(symname); if (CPlusPlus) patch_parms(parms); - Swig_ConstructorToFunction(n, ClassType, none_comparison, CPlusPlus, Getattr(n, "template") ? 0 :Extend); + Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor_code, CPlusPlus, Getattr(n, "template") ? 0 :Extend); Setattr(n,"sym:name", mrename); functionWrapper(n); Delete(mrename); @@ -1787,7 +1793,7 @@ Language::copyconstructorHandler(Node *n) { Parm *parms = Getattr(n,"parms"); if (CPlusPlus) patch_parms(parms); mrename = Swig_name_copyconstructor(symname); - Swig_ConstructorToFunction(n,ClassType, none_comparison, + Swig_ConstructorToFunction(n,ClassType, none_comparison, director_ctor_code, CPlusPlus, Getattr(n,"template") ? 0 : Extend); Setattr(n,"sym:name", mrename); functionWrapper(n); diff --git a/SWIG/Source/Modules/ocaml.cxx b/SWIG/Source/Modules/ocaml.cxx index 8390608c0..e8cf9af02 100755 --- a/SWIG/Source/Modules/ocaml.cxx +++ b/SWIG/Source/Modules/ocaml.cxx @@ -1826,6 +1826,9 @@ public: p = NewParm(NewString("int"), NewString("__disown")); Setattr(p, "CAML_VALUE", "1"); + Setattr(n, "director:postfix_args", p); + Setattr(p, "args:byname", "1"); + Setattr(p, "value", "0"); set_nextSibling(ip, p); /* constructor */ diff --git a/SWIG/Source/Modules/python.cxx b/SWIG/Source/Modules/python.cxx index eb1d744c6..4ef2bd979 100644 --- a/SWIG/Source/Modules/python.cxx +++ b/SWIG/Source/Modules/python.cxx @@ -374,7 +374,6 @@ public: * ------------------------------------------------------------ */ virtual int top(Node *n) { - /* check if directors are enabled for this module. note: this * is a "master" switch, without which no director code will be * emitted. %feature("director") statements are also required @@ -444,7 +443,7 @@ public: Printf(f_runtime,"#define SWIG_DIRECTORS\n"); } - /* Set module name */ + /* Set module name */ module = Copy(Getattr(n,"name")); mainmodule = Getattr(n,"name"); @@ -1629,7 +1628,9 @@ public: parms = p; for (ip = parms; nextSibling(ip); ) ip = nextSibling(ip); p = NewParm(NewString("int"), NewString("__disown")); - Setattr(p, "value", "1"); + Setattr(p, "arg:byname", "1"); + Setattr(n, "director:postfix_args", p); + Setattr(p, "value", "0"); set_nextSibling(ip, p); /* constructor */ diff --git a/SWIG/Source/Modules/ruby.cxx b/SWIG/Source/Modules/ruby.cxx index 1164d50d1..e5be68176 100644 --- a/SWIG/Source/Modules/ruby.cxx +++ b/SWIG/Source/Modules/ruby.cxx @@ -2088,7 +2088,9 @@ public: parms = p; for (ip = parms; nextSibling(ip); ) ip = nextSibling(ip); p = NewParm(NewString("int"), NewString("__disown")); - Setattr(p, "value", "1"); + Setattr(p, "arg:byname", "1"); + Setattr(n, "director:postfix_args", p); + Setattr(p, "value", "0"); set_nextSibling(ip, p); /* constructor */ diff --git a/SWIG/Source/Modules/swigmod.h b/SWIG/Source/Modules/swigmod.h index 2fbeff9c0..7e9d98d61 100644 --- a/SWIG/Source/Modules/swigmod.h +++ b/SWIG/Source/Modules/swigmod.h @@ -39,6 +39,8 @@ extern int Verbose; extern int IsVirtual; extern int ImportMode; extern int NoExcept; // -no_except option +extern int Abstract; // abstract base class +extern int SmartPointer; // smart pointer methods being emitted /* Miscellaneous stuff */ @@ -238,10 +240,15 @@ public: /* Return true if the current method is part of a smart-pointer */ int is_smart_pointer() const; + /* Director subclass comparison test */ + String *none_comparison; + + /* Director constructor "template" code */ + String *director_ctor_code; + private: Hash *symbols; Hash *classtypes; - String *none_comparison; int overloading; int multiinput; int directors;