Add improved namespace support - the nspace feature, working for Java only at the moment.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@11896 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2010-03-04 21:27:23 +00:00
commit 1253657bb4
23 changed files with 645 additions and 266 deletions

View file

@ -56,7 +56,9 @@ class JAVA:public Language {
String *proxy_class_def;
String *proxy_class_code;
String *module_class_code;
String *proxy_class_name;
String *proxy_class_name; // proxy class name
String *full_proxy_class_name;// fully qualified proxy class name when using nspace feature, otherwise same as proxy_class_name
String *full_imclass_name; // fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name
String *variable_name; //Name of a variable being wrapped
String *proxy_class_constants_code;
String *module_class_constants_code;
@ -125,6 +127,8 @@ public:
proxy_class_code(NULL),
module_class_code(NULL),
proxy_class_name(NULL),
full_proxy_class_name(NULL),
full_imclass_name(NULL),
variable_name(NULL),
proxy_class_constants_code(NULL),
module_class_constants_code(NULL),
@ -157,19 +161,35 @@ public:
/* -----------------------------------------------------------------------------
* getProxyName()
*
* Test to see if a type corresponds to something wrapped with a proxy class
* Return NULL if not otherwise the proxy class name
* Test to see if a type corresponds to something wrapped with a proxy class.
* Return NULL if not otherwise the proxy class name, fully qualified with
* package name if the nspace feature is used.
* ----------------------------------------------------------------------------- */
String *getProxyName(SwigType *t) {
if (proxy_flag) {
Node *n = classLookup(t);
if (n) {
return Getattr(n, "sym:name");
}
}
return NULL;
}
String *proxyname = NULL;
if (proxy_flag) {
Node *n = classLookup(t);
if (n) {
proxyname = Getattr(n, "proxyname");
if (!proxyname) {
String *nspace = Getattr(n, "sym:nspace");
String *symname = Getattr(n, "sym:name");
if (nspace) {
if (Len(package) > 0)
proxyname = NewStringf("%s.%s.%s", package, nspace, symname);
else
proxyname = NewStringf("%s.%s", nspace, symname);
} else {
proxyname = Copy(symname);
}
Setattr(n, "proxyname", proxyname);
Delete(proxyname);
}
}
}
return proxyname;
}
/* -----------------------------------------------------------------------------
* makeValidJniName()
@ -410,7 +430,7 @@ public:
Replaceall(package_path, ".", "/");
}
String *jniname = makeValidJniName(imclass_name);
Printf(wrapper_name, "Java_%s%s_%%f", Char(jnipackage), jniname);
Printf(wrapper_name, "Java_%s%s_%%f", jnipackage, jniname);
Delete(jniname);
Swig_name_register("wrapper", Char(wrapper_name));
@ -1099,7 +1119,7 @@ public:
*/
if (proxy_flag && wrapping_member_flag && !enum_constant_flag) {
// Capitalize the first letter in the variable to create a JavaBean type getter/setter function name
bool getter_flag = Cmp(symname, Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) != 0;
bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, proxy_class_name, variable_name))) != 0;
String *getter_setter_name = NewString("");
if (!getter_flag)
@ -1167,6 +1187,24 @@ public:
if (getCurrentClass() && (cplus_mode != PUBLIC))
return SWIG_NOWRAP;
if (proxy_flag && !is_wrapping_class()) {
// Global enums / enums in a namespace
String *nspace = Getattr(n, "sym:nspace");
assert(!full_imclass_name);
if (!nspace) {
full_imclass_name = NewStringf("%s", imclass_name);
} else {
if (Len(package) > 0) {
full_imclass_name = NewStringf("%s.%s", package, imclass_name);
} else {
full_imclass_name = NewStringf("%s", imclass_name);
Printf(stderr, "The nspace feature used on %s is not supported unless a package is specified with -package - Java does not support types declared in the unnamed package accessing types declared in a package.\n", Getattr(n, "name"));
SWIG_exit(EXIT_FAILURE);
}
}
}
enum_code = NewString("");
String *symname = Getattr(n, "sym:name");
String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code;
@ -1224,7 +1262,9 @@ public:
Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL);
} else {
// Global enums are defined in their own file
String *filen = NewStringf("%s%s.java", SWIG_output_directory(), symname);
String *nspace = Getattr(n, "sym:nspace");
String *output_directory = outputDirectory(nspace);
String *filen = NewStringf("%s%s.java", output_directory, symname);
File *f_enum = NewFile(filen, "w", SWIG_output_files());
if (!f_enum) {
FileErrorDisplay(filen);
@ -1237,14 +1277,21 @@ public:
// Start writing out the enum file
emitBanner(f_enum);
if (Len(package) > 0)
Printf(f_enum, "package %s;\n", package);
if (Len(package) > 0 || nspace) {
Printf(f_enum, "package ");
if (Len(package) > 0)
Printv(f_enum, package, nspace ? "." : "", NIL);
if (nspace)
Printv(f_enum, nspace, NIL);
Printf(f_enum, ";\n");
}
Printv(f_enum, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements
"\n", enum_code, "\n", NIL);
Printf(f_enum, "\n");
Close(f_enum);
Delete(output_directory);
}
} else {
// Wrap C++ enum with simple constant
@ -1257,6 +1304,11 @@ public:
Delete(enum_code);
enum_code = NULL;
if (proxy_flag && !is_wrapping_class()) {
Delete(full_imclass_name);
full_imclass_name = 0;
}
}
return SWIG_OK;
}
@ -1418,13 +1470,13 @@ public:
if (classname_substituted_flag) {
if (SwigType_isenum(t)) {
// This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on)
Printf(constants_code, "%s.swigToEnum(%s.%s());\n", return_type, imclass_name, Swig_name_get(symname));
Printf(constants_code, "%s.swigToEnum(%s.%s());\n", return_type, imclass_name, Swig_name_get(getNSpace(), symname));
} else {
// This handles function pointers using the %constant directive
Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(symname));
Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(getNSpace(), symname));
}
} else
Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(symname));
Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(getNSpace(), symname));
// Each constant and enum value is wrapped with a separate JNI function call
SetFlag(n, "feature:immutable");
@ -1691,16 +1743,18 @@ public:
/* Also insert the swigTakeOwnership and swigReleaseOwnership methods */
if (feature_director) {
String *destruct_jnicall, *release_jnicall, *take_jnicall;
String *changeown_method_name = Swig_name_member(getNSpace(), proxy_class_name, "change_ownership");
destruct_jnicall = NewStringf("%s()", destruct_methodname);
release_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, false)", imclass_name, proxy_class_name);
take_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, true)", imclass_name, proxy_class_name);
release_jnicall = NewStringf("%s.%s(this, swigCPtr, false)", full_imclass_name, changeown_method_name);
take_jnicall = NewStringf("%s.%s(this, swigCPtr, true)", full_imclass_name, changeown_method_name);
emitCodeTypemap(n, false, typemap_lookup_type, "directordisconnect", "methodname", destruct_jnicall);
emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_release", "methodname", release_jnicall);
emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_take", "methodname", take_jnicall);
Delete(destruct_jnicall);
Delete(changeown_method_name);
Delete(release_jnicall);
Delete(take_jnicall);
}
@ -1719,14 +1773,14 @@ public:
Replaceall(proxy_class_def, "$module", module_class_name);
Replaceall(proxy_class_code, "$module", module_class_name);
Replaceall(proxy_class_def, "$imclassname", imclass_name);
Replaceall(proxy_class_code, "$imclassname", imclass_name);
Replaceall(proxy_class_def, "$imclassname", full_imclass_name);
Replaceall(proxy_class_code, "$imclassname", full_imclass_name);
// Add code to do C++ casting to base class (only for classes in an inheritance hierarchy)
if (derived) {
Printv(imclass_cppcasts_code, " public final static native long SWIG$javaclassnameUpcast(long jarg1);\n", NIL);
Replaceall(imclass_cppcasts_code, "$javaclassname", proxy_class_name);
Replaceall(imclass_cppcasts_code, "$javaclassname", full_proxy_class_name);
Printv(upcasts_code,
"SWIGEXPORT jlong JNICALL Java_$jnipackage$imimclass_SWIG$imclazznameUpcast",
@ -1735,7 +1789,7 @@ public:
" (void)jenv;\n" " (void)jcls;\n" " *($cbaseclass **)&baseptr = *($cclass **)&jarg1;\n" " return baseptr;\n" "}\n", "\n", NIL);
String *imimclass = makeValidJniName(imclass_name);
String *imclazzname = makeValidJniName(proxy_class_name);
String *imclazzname = makeValidJniName(full_proxy_class_name);
Replaceall(upcasts_code, "$cbaseclass", c_baseclass);
Replaceall(upcasts_code, "$imclazzname", imclazzname);
Replaceall(upcasts_code, "$cclass", c_classname);
@ -1757,21 +1811,37 @@ public:
File *f_proxy = NULL;
if (proxy_flag) {
proxy_class_name = NewString(Getattr(n, "sym:name"));
String *nspace = getNSpace();
if (!addSymbol(proxy_class_name, n))
if (!nspace) {
full_proxy_class_name = NewStringf("%s", proxy_class_name);
full_imclass_name = NewStringf("%s", imclass_name);
if (Cmp(proxy_class_name, imclass_name) == 0) {
Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
if (Cmp(proxy_class_name, module_class_name) == 0) {
Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
} else {
if (Len(package) > 0) {
full_proxy_class_name = NewStringf("%s.%s.%s", package, nspace, proxy_class_name);
full_imclass_name = NewStringf("%s.%s", package, imclass_name);
} else {
full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name);
full_imclass_name = NewStringf("%s", imclass_name);
Printf(stderr, "The nspace feature used on %s is not supported unless a package is specified with -package - Java does not support types declared in the unnamed package accessing types declared in a package.\n", Getattr(n, "name"));
SWIG_exit(EXIT_FAILURE);
}
}
if (!addSymbol(proxy_class_name, n, nspace))
return SWIG_ERROR;
if (Cmp(proxy_class_name, imclass_name) == 0) {
Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
if (Cmp(proxy_class_name, module_class_name) == 0) {
Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
String *filen = NewStringf("%s%s.java", SWIG_output_directory(), proxy_class_name);
String *output_directory = outputDirectory(nspace);
String *filen = NewStringf("%s%s.java", output_directory, proxy_class_name);
f_proxy = NewFile(filen, "w", SWIG_output_files());
if (!f_proxy) {
FileErrorDisplay(filen);
@ -1784,8 +1854,14 @@ public:
// Start writing out the proxy class file
emitBanner(f_proxy);
if (Len(package) > 0)
Printf(f_proxy, "package %s;\n", package);
if (Len(package) > 0 || nspace) {
Printf(f_proxy, "package ");
if (Len(package) > 0)
Printv(f_proxy, package, nspace ? "." : "", NIL);
if (nspace)
Printv(f_proxy, nspace, NIL);
Printf(f_proxy, ";\n");
}
Clear(proxy_class_def);
Clear(proxy_class_code);
@ -1793,6 +1869,7 @@ public:
destructor_call = NewString("");
destructor_throws_clause = NewString("");
proxy_class_constants_code = NewString("");
Delete(output_directory);
}
Language::classHandler(n);
@ -1804,9 +1881,9 @@ public:
Replaceall(proxy_class_def, "$module", module_class_name);
Replaceall(proxy_class_code, "$module", module_class_name);
Replaceall(proxy_class_constants_code, "$module", module_class_name);
Replaceall(proxy_class_def, "$imclassname", imclass_name);
Replaceall(proxy_class_code, "$imclassname", imclass_name);
Replaceall(proxy_class_constants_code, "$imclassname", imclass_name);
Replaceall(proxy_class_def, "$imclassname", full_imclass_name);
Replaceall(proxy_class_code, "$imclassname", full_imclass_name);
Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name);
Printv(f_proxy, proxy_class_def, proxy_class_code, NIL);
// Write out all the constants
@ -1848,6 +1925,10 @@ public:
Delete(proxy_class_name);
proxy_class_name = NULL;
Delete(full_proxy_class_name);
full_proxy_class_name = NULL;
Delete(full_imclass_name);
full_imclass_name = NULL;
Delete(destructor_call);
destructor_call = NULL;
Delete(destructor_throws_clause);
@ -1869,7 +1950,7 @@ public:
if (proxy_flag) {
String *overloaded_name = getOverloadedName(n);
String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name);
String *intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, overloaded_name);
Setattr(n, "proxyfuncname", Getattr(n, "sym:name"));
Setattr(n, "imfuncname", intermediary_function_name);
proxyClassFunctionHandler(n);
@ -1891,7 +1972,7 @@ public:
if (proxy_flag) {
String *overloaded_name = getOverloadedName(n);
String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name);
String *intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, overloaded_name);
Setattr(n, "proxyfuncname", Getattr(n, "sym:name"));
Setattr(n, "imfuncname", intermediary_function_name);
proxyClassFunctionHandler(n);
@ -1967,7 +2048,7 @@ public:
if (wrapping_member_flag && !enum_constant_flag) {
// For wrapping member variables (Javabean setter)
setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) == 0);
setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, proxy_class_name, variable_name))) == 0);
}
/* Start generating the proxy function */
@ -1978,7 +2059,7 @@ public:
Printf(function_code, "static ");
Printf(function_code, "%s %s(", return_type, proxy_function_name);
Printv(imcall, imclass_name, ".$imfuncname(", NIL);
Printv(imcall, full_imclass_name, ".$imfuncname(", NIL);
if (!static_flag) {
Printf(imcall, "swigCPtr");
@ -2121,7 +2202,7 @@ public:
Node *explicit_n = Getattr(n, "explicitcallnode");
if (explicit_n) {
String *ex_overloaded_name = getOverloadedName(explicit_n);
String *ex_intermediary_function_name = Swig_name_member(proxy_class_name, ex_overloaded_name);
String *ex_intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, ex_overloaded_name);
String *ex_imcall = Copy(imcall);
Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name);
@ -2183,7 +2264,7 @@ public:
if (proxy_flag) {
String *overloaded_name = getOverloadedName(n);
String *mangled_overname = Swig_name_construct(overloaded_name);
String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name);
String *imcall = NewString("");
const String *methodmods = Getattr(n, "feature:java:methodmodifiers");
@ -2195,7 +2276,7 @@ public:
Printf(function_code, " %s %s(", methodmods, proxy_class_name);
Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name);
Printv(imcall, imclass_name, ".", mangled_overname, "(", NIL);
Printv(imcall, full_imclass_name, ".", mangled_overname, "(", NIL);
/* Attach the non-standard typemaps to the parameter list */
Swig_typemap_attach_parms("in", l, NULL);
@ -2368,7 +2449,7 @@ public:
String *symname = Getattr(n, "sym:name");
if (proxy_flag) {
Printv(destructor_call, imclass_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL);
Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL);
generateThrowsClause(n, destructor_throws_clause);
}
return SWIG_OK;
@ -2476,7 +2557,7 @@ public:
if (proxy_flag && global_variable_flag) {
// Capitalize the first letter in the variable to create a JavaBean type getter/setter function name
func_name = NewString("");
setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(variable_name)) == 0);
setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), variable_name)) == 0);
if (setter_flag)
Printf(func_name, "set");
else
@ -2681,10 +2762,10 @@ public:
// Strange hack to change the name
Setattr(n, "name", Getattr(n, "value")); /* for wrapping of enums in a namespace when emit_action is used */
constantWrapper(n);
value = NewStringf("%s.%s()", imclass_name, Swig_name_get(symname));
value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname));
} else {
memberconstantHandler(n);
value = NewStringf("%s.%s()", imclass_name, Swig_name_get(Swig_name_member(proxy_class_name, symname)));
value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), Swig_name_member(getNSpace(), proxy_class_name, symname)));
}
}
}
@ -2698,28 +2779,44 @@ public:
* ----------------------------------------------------------------------------- */
String *getEnumName(SwigType *t, bool jnidescriptor) {
Node *enum_name = NULL;
Node *enumname = NULL;
Node *n = enumLookup(t);
if (n) {
String *symname = Getattr(n, "sym:name");
if (symname) {
// Add in class scope when referencing enum if not a global enum
String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name"));
String *proxyname = 0;
if (scopename_prefix) {
proxyname = getProxyName(scopename_prefix);
enumname = Getattr(n, "enumname");
if (!enumname || jnidescriptor) {
String *symname = Getattr(n, "sym:name");
if (symname) {
// Add in class scope when referencing enum if not a global enum
String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name"));
String *proxyname = 0;
if (scopename_prefix) {
proxyname = getProxyName(scopename_prefix);
}
if (proxyname) {
const char *class_separator = jnidescriptor ? "$" : ".";
enumname = NewStringf("%s%s%s", proxyname, class_separator, symname);
} else {
// global enum or enum in a namespace
String *nspace = Getattr(n, "sym:nspace");
if (nspace) {
if (Len(package) > 0)
enumname = NewStringf("%s.%s.%s", package, nspace, symname);
else
enumname = NewStringf("%s.%s", nspace, symname);
} else {
enumname = Copy(symname);
}
}
if (!jnidescriptor) { // not cached
Setattr(n, "enumname", enumname);
Delete(enumname);
}
Delete(scopename_prefix);
}
if (proxyname) {
const char *class_separator = jnidescriptor ? "$" : ".";
enum_name = NewStringf("%s%s%s", proxyname, class_separator, symname);
} else {
enum_name = NewStringf("%s", symname);
}
Delete(scopename_prefix);
}
}
return enum_name;
return enumname;
}
/* -----------------------------------------------------------------------------
@ -3004,10 +3101,10 @@ public:
if (Cmp(jtype, "long") == 0) {
if (proxy_flag) {
if (!GetFlag(p, "tmap:jtype:nopgcpp") && !nopgcpp_flag) {
Node *n = classLookup(t);
if (n) {
String *proxyname = getProxyName(t);
if (proxyname) {
// Found a struct/class parameter passed by value, reference, pointer, or pointer reference
proxyClassName = Getattr(n, "sym:name");
proxyClassName = proxyname;
} else {
// Look for proxy class parameters passed to C++ layer using non-default typemaps, ie not one of above types
String *jstype = NewString(Getattr(p, "tmap:jstype"));
@ -3045,6 +3142,30 @@ public:
return proxyClassName;
}
/* -----------------------------------------------------------------------------
* outputDirectory()
*
* Return the directory to use for generating Java classes/enums and create the
* subdirectory (does not create if language specific outdir does not exist).
* ----------------------------------------------------------------------------- */
String *outputDirectory(String *nspace) {
String *output_directory = Copy(SWIG_output_directory());
if (nspace) {
String *nspace_subdirectory = Copy(nspace);
Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER);
String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory);
if (newdir_error) {
Printf(stderr, "%s\n", newdir_error);
Delete(newdir_error);
SWIG_exit(EXIT_FAILURE);
}
Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0);
Delete(nspace_subdirectory);
}
return output_directory;
}
/*----------------------------------------------------------------------
* Start of director methods
*--------------------------------------------------------------------*/
@ -3155,13 +3276,13 @@ public:
// Output the director connect method:
String *jni_imclass_name = makeValidJniName(imclass_name);
String *norm_name = SwigType_namestr(Getattr(n, "name"));
String *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name);
String *swig_director_connect = Swig_name_member(getNSpace(), proxy_class_name, "director_connect");
String *swig_director_connect_jni = makeValidJniName(swig_director_connect);
String *sym_name = Getattr(n, "sym:name");
Wrapper *code_wrap;
Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean mem_own, boolean weak_global);\n",
swig_director_connect, proxy_class_name);
swig_director_connect, full_proxy_class_name);
code_wrap = NewWrapper();
Printf(code_wrap->def,
@ -3183,10 +3304,10 @@ public:
Delete(swig_director_connect);
// Output the swigReleaseOwnership, swigTakeOwnership methods:
String *changeown_method_name = NewStringf("%s_change_ownership", proxy_class_name);
String *changeown_method_name = Swig_name_member(getNSpace(), proxy_class_name, "change_ownership");
String *changeown_jnimethod_name = makeValidJniName(changeown_method_name);
Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", changeown_method_name, proxy_class_name);
Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", changeown_method_name, full_proxy_class_name);
code_wrap = NewWrapper();
Printf(code_wrap->def,
@ -3342,7 +3463,7 @@ public:
// we're consistent with the sym:overload name in functionWrapper. (?? when
// does the overloaded method name get set?)
imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(classname, overloaded_name));
imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(getNSpace(), classname, overloaded_name));
if (returntype) {