From 8bf966a65c2120d2bf050857587e7e7bd7cafd58 Mon Sep 17 00:00:00 2001 From: Oliver Buchtala Date: Tue, 24 Sep 2013 01:47:13 +0200 Subject: [PATCH] Fix %nspace support and activated relevant tests. --- Examples/test-suite/director_nspace.i | 16 +-- Examples/test-suite/javascript/Makefile.in | 2 + .../javascript/nspace_extend_runme.js | 27 ++++++ .../test-suite/javascript/nspace_runme.js | 77 +++++++++++++++ Examples/test-suite/nspace.i | 2 +- Examples/test-suite/nspace_extend.i | 2 +- Source/Modules/javascript.cxx | 97 +++++++++++++------ 7 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 Examples/test-suite/javascript/nspace_extend_runme.js create mode 100644 Examples/test-suite/javascript/nspace_runme.js diff --git a/Examples/test-suite/director_nspace.i b/Examples/test-suite/director_nspace.i index 6814a43a3..264604877 100644 --- a/Examples/test-suite/director_nspace.i +++ b/Examples/test-suite/director_nspace.i @@ -15,10 +15,10 @@ namespace Bar FooBar() {} FooBar(const FooBar&) {} virtual ~FooBar() {} - + std::string FooBarDo() { return "Bar::Foo2::Foo2Bar()"; } }; - + class Foo { public: virtual ~Foo() {} @@ -37,7 +37,7 @@ namespace Bar %include // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGJAVASCRIPT) %nspace Bar::Foo; %nspace Bar::FooBar; #else @@ -47,17 +47,17 @@ namespace Bar %feature("director") Bar::Foo; namespace Bar -{ +{ class FooBar { public: FooBar(); FooBar(const FooBar&); virtual ~FooBar(); - + std::string FooBarDo(); - + }; - + class Foo { public: @@ -67,7 +67,7 @@ namespace Bar virtual std::string fooBar(FooBar* fb); virtual Foo makeFoo(); virtual FooBar makeFooBar(); - + static Foo* get_self(Foo *self_); }; } diff --git a/Examples/test-suite/javascript/Makefile.in b/Examples/test-suite/javascript/Makefile.in index d7e7fce40..40aa0ec86 100755 --- a/Examples/test-suite/javascript/Makefile.in +++ b/Examples/test-suite/javascript/Makefile.in @@ -45,6 +45,8 @@ CPP_TEST_CASES = \ cpp_static \ enum_template \ namespace_virtual_method \ + nspace \ + nspace_extend \ overload_copy \ rename_simple \ rename_scope \ diff --git a/Examples/test-suite/javascript/nspace_extend_runme.js b/Examples/test-suite/javascript/nspace_extend_runme.js new file mode 100644 index 000000000..ab81c19d3 --- /dev/null +++ b/Examples/test-suite/javascript/nspace_extend_runme.js @@ -0,0 +1,27 @@ +var nspace_extend = require("./nspace_extend"); + +// constructors and destructors +var color1 = new nspace_extend.Outer.Inner1.Color(); +var color = new nspace_extend.Outer.Inner1.Color(color1); +delete color1; + +// class methods +color.colorInstanceMethod(20.0); +nspace_extend.Outer.Inner1.Color.colorStaticMethod(20.0); +var created = nspace_extend.Outer.Inner1.Color.create(); + + +// constructors and destructors +var color2 = new nspace_extend.Outer.Inner2.Color(); +color = new nspace_extend.Outer.Inner2.Color(color2); +delete color2; + +// class methods +color.colorInstanceMethod(20.0); +nspace_extend.Outer.Inner2.Color.colorStaticMethod(20.0); +created = nspace_extend.Outer.Inner2.Color.create(); + +// Same class different namespaces +var col1 = new nspace_extend.Outer.Inner1.Color(); +var col2 = nspace_extend.Outer.Inner2.Color.create(); +col2.colors(col1, col1, col2, col2, col2); diff --git a/Examples/test-suite/javascript/nspace_runme.js b/Examples/test-suite/javascript/nspace_runme.js new file mode 100644 index 000000000..929a6b21d --- /dev/null +++ b/Examples/test-suite/javascript/nspace_runme.js @@ -0,0 +1,77 @@ +var nspace = require("./nspace"); + +var color1 = new nspace.Outer.Inner1.Color(); +var color = new nspace.Outer.Inner1.Color(color1); +delete color1; + +// class methods +color.colorInstanceMethod(20.0); +nspace.Outer.Inner1.Color.colorStaticMethod(20.0); +var created = nspace.Outer.Inner1.Color.create(); + +// class enums +var someClass = new nspace.Outer.SomeClass(); +var channel = someClass.GetInner1ColorChannel(); +if (channel != nspace.Outer.Inner1.Color.Transmission) { + throw new Error("Failed."); +} + +// class anonymous enums +var val1 = nspace.Outer.Inner1.Color.ColorEnumVal1; +var val2 = nspace.Outer.Inner1.Color.ColorEnumVal2; +if (val1 !== 0 || val2 !== 0x22) { + throw new Error("Failed."); +} + +// instance member variables +color.instanceMemberVariable = 123; +if (color.instanceMemberVariable !== 123) { + throw new Error("Failed."); +} + +// static member variables +nspace.Outer.Inner1.Color.staticMemberVariable = 789; +if (nspace.Outer.Inner1.Color.staticMemberVariable !== 789) { + throw new Error("Failed."); +} + +if (nspace.Outer.Inner1.Color.staticConstMemberVariable !== 222) { + throw new Error("Failed."); +} + +if (nspace.Outer.Inner1.Color.staticConstEnumMemberVariable !== nspace.Outer.Inner1.Color.Transmission) { + throw new Error("Failed."); +} + +// Same class different namespaces +var col1 = new nspace.Outer.Inner1.Color(); +var col2 = nspace.Outer.Inner2.Color.create(); +col2.colors(col1, col1, col2, col2, col2); + +// TODO: why isn't it scoped in the namespace??? +nspace.namespaceFunction(color); +nspace.Outer.Inner1.namespaceVar = 111; +if (nspace.Outer.Inner1.namespaceVar !== 111) { + throw new Error("Failed."); +} + +// global enums +var outerChannel1 = someClass.GetInner1Channel(); +if (outerChannel1 != nspace.Outer.Inner1.Transmission1) { + throw new Error("Failed."); +} + +var outerChannel2 = someClass.GetInner2Channel(); +if (outerChannel2 !== nspace.Outer.Inner2.Transmission2) { + throw new Error("Failed."); +} + +// turn feature off / ignoring +var ns = new nspace.Outer.namespce(); +var nons = new nspace.NoNSpacePlease(); + +// Derived class +var blue3 = new nspace.Outer.Inner3.Blue(); +blue3.blueInstanceMethod(); +var blue4 = new nspace.Outer.Inner4.Blue(); +blue4.blueInstanceMethod(); diff --git a/Examples/test-suite/nspace.i b/Examples/test-suite/nspace.i index 2e10542d3..9bffc21ff 100644 --- a/Examples/test-suite/nspace.i +++ b/Examples/test-suite/nspace.i @@ -2,7 +2,7 @@ %module nspace // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGJAVASCRIPT) #if defined(SWIGJAVA) SWIG_JAVABODY_PROXY(public, public, SWIGTYPE) diff --git a/Examples/test-suite/nspace_extend.i b/Examples/test-suite/nspace_extend.i index 1965ef8f6..7c1b075ed 100644 --- a/Examples/test-suite/nspace_extend.i +++ b/Examples/test-suite/nspace_extend.i @@ -2,7 +2,7 @@ %module nspace_extend // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGJAVASCRIPT) #if defined(SWIGJAVA) SWIG_JAVABODY_PROXY(public, public, SWIGTYPE) diff --git a/Source/Modules/javascript.cxx b/Source/Modules/javascript.cxx index 3807e072a..13a0aab7d 100644 --- a/Source/Modules/javascript.cxx +++ b/Source/Modules/javascript.cxx @@ -396,7 +396,6 @@ int JAVASCRIPT::variableHandler(Node *n) { * --------------------------------------------------------------------- */ int JAVASCRIPT::globalvariableHandler(Node *n) { - emitter->switchNamespace(n); Language::globalvariableHandler(n); @@ -410,6 +409,7 @@ int JAVASCRIPT::globalvariableHandler(Node *n) { * --------------------------------------------------------------------- */ int JAVASCRIPT::constantWrapper(Node *n) { + emitter->switchNamespace(n); // Note: callbacks trigger this wrapper handler // TODO: handle callback declarations @@ -464,7 +464,6 @@ int JAVASCRIPT::fragmentDirective(Node *n) { * --------------------------------------------------------------------- */ int JAVASCRIPT::top(Node *n) { - emitter->initialize(n); Language::top(n); @@ -482,7 +481,6 @@ int JAVASCRIPT::top(Node *n) { * --------------------------------------------------------------------- */ void JAVASCRIPT::main(int argc, char *argv[]) { - // Set javascript subdirectory in SWIG library SWIG_library_directory("javascript"); @@ -667,7 +665,7 @@ int JSEmitter::emitWrapperFunction(Node *n) { if (kind) { if (Cmp(kind, "function") == 0) { - bool is_member = GetFlag(n, "ismember"); + bool is_member = GetFlag(n, "ismember") | GetFlag(n, "feature:extend"); bool is_static = GetFlag(state.function(), IS_STATIC); ret = emitFunction(n, is_member, is_static); } else if (Cmp(kind, "variable") == 0) { @@ -707,18 +705,23 @@ int JSEmitter::emitWrapperFunction(Node *n) { } int JSEmitter::enterClass(Node *n) { - state.clazz(true); state.clazz(NAME, Getattr(n, "sym:name")); - //state.clazz(NAME_MANGLED, SwigType_manglestr(Getattr(n, "name"))); - state.clazz(NAME_MANGLED, Getattr(n, "sym:name")); + state.clazz("nspace", current_namespace); + + // Creating a mangled name using the current namespace and the symbol name + String *mangled_name = NewString(""); + Printf(mangled_name, "%s_%s", Getattr(current_namespace, NAME_MANGLED), Getattr(n, "sym:name")); + state.clazz(NAME_MANGLED, SwigType_manglestr(mangled_name)); + Delete(mangled_name); + state.clazz(TYPE, NewString(Getattr(n, "classtype"))); String *type = SwigType_manglestr(Getattr(n, "classtypeobj")); String *classtype_mangled = NewString(""); Printf(classtype_mangled, "p%s", type); - Delete(type); state.clazz(TYPE_MANGLED, classtype_mangled); + Delete(type); String *ctor_wrapper = NewString("_wrap_new_veto_"); Append(ctor_wrapper, state.clazz(NAME)); @@ -734,23 +737,19 @@ int JSEmitter::enterClass(Node *n) { } int JSEmitter::enterFunction(Node *n) { - state.function(true); state.function(NAME, Getattr(n, "sym:name")); if(Equal(Getattr(n, "storage"), "static")) { SetFlag(state.function(), IS_STATIC); } - return SWIG_OK; } int JSEmitter::enterVariable(Node *n) { - // reset the state information for variables. state.variable(true); // Retrieve a pure symbol name. Using 'sym:name' as a basis, as it considers %renamings. - if (Equal(Getattr(n, "view"), "memberconstantHandler")) { // Note: this is kind of hacky/experimental // For constants/enums 'sym:name' contains e.g., 'Foo_Hello' instead of 'Hello' @@ -763,10 +762,12 @@ int JSEmitter::enterVariable(Node *n) { SetFlag(state.variable(), IS_STATIC); } - if (!Language::instance()->is_assignable(n) - // FIXME: test "arrays_global" does not compile with that as it is not allowed to assign to char[] - // probably some error in char[] typemap - || Equal(Getattr(n, "type"), "a().char")) { + if (!Language::instance()->is_assignable(n)) { + SetFlag(state.variable(), IS_IMMUTABLE); + } + + // FIXME: test "arrays_global" does not compile with that as it is not allowed to assign to char[] + if (Equal(Getattr(n, "type"), "a().char")) { SetFlag(state.variable(), IS_IMMUTABLE); } @@ -1273,23 +1274,43 @@ void JSEmitter::emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params) { } int JSEmitter::switchNamespace(Node *n) { + // HACK: somehow this gets called when member functions are processed...ignoring + if (GetFlag(n, "ismember")) { + return SWIG_OK; + } + String *nspace = Getattr(n, "sym:nspace"); + + // if nspace is deactivated, everything goes into the global scope if (!GetFlag(n, "feature:nspace")) { current_namespace = Getattr(namespaces, "::"); - } else { - String *scope = Swig_scopename_prefix(Getattr(n, "name")); - if (scope) { - // if the scope is not yet registered - // create (parent) namespaces recursively - if (!Getattr(namespaces, scope)) { - createNamespace(scope); - } - current_namespace = Getattr(namespaces, scope); - } else { - current_namespace = Getattr(namespaces, "::"); + return SWIG_OK; + } + + if (nspace == NULL) { + // enums and constants do not have 'sym:nspace' set + // so we try to get the namespace from the qualified name + if(Equal(Getattr(n, "nodeType"), "enumitem")) { + nspace = Swig_scopename_prefix(Getattr(n, "name")); } } + if (nspace == NULL) { + current_namespace = Getattr(namespaces, "::"); + return SWIG_OK; + } + + String *scope = NewString(nspace); + // replace "." with "::" that we can use Swig_scopename_last + Replaceall(scope, ".", "::"); + + // if the scope is not yet registered + // create (parent) namespaces recursively + if (!Getattr(namespaces, scope)) { + createNamespace(scope); + } + current_namespace = Getattr(namespaces, scope); + return SWIG_OK; } @@ -1434,6 +1455,12 @@ void JSCEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, Ma int i = 0; for (p = parms; p; i++) { String *arg = NewString(""); + String *type = Getattr(p, "type"); + + // ignore varargs + if (SwigType_isvarargs(type)) + break; + switch (mode) { case Getter: case Function: @@ -1556,7 +1583,7 @@ int JSCEmitter::enterFunction(Node *n) { int JSCEmitter::exitFunction(Node *n) { Template t_function = getTemplate("jsc_function_declaration"); - bool is_member = GetFlag(n, "ismember"); + bool is_member = GetFlag(n, "ismember") | GetFlag(n, "feature:extend"); bool is_overloaded = GetFlag(n, "sym:overloaded"); // handle overloaded functions @@ -1682,7 +1709,7 @@ int JSCEmitter::exitClass(Node *n) { Template t_registerclass(getTemplate("jsc_class_registration")); t_registerclass.replace("$jsname", state.clazz(NAME)) .replace("$jsmangledname", state.clazz(NAME_MANGLED)) - .replace("$jsnspace", Getattr(current_namespace, NAME_MANGLED)) + .replace("$jsnspace", Getattr(state.clazz("nspace"),NAME_MANGLED)) .pretty_print(state.global(INITIALIZER)); return SWIG_OK; @@ -1973,7 +2000,7 @@ int V8Emitter::exitClass(Node *n) Template t_register = getTemplate("jsv8_register_class"); t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) .replace("$jsname", state.clazz(NAME)) - .replace("$jsparent", Getattr(current_namespace, "name_mangled")) + .replace("$jsparent", Getattr(state.clazz("nspace"),NAME_MANGLED)) .trim() .pretty_print(f_init_register_classes); @@ -2014,7 +2041,7 @@ int V8Emitter::exitVariable(Node* n) // Note: a global variable is treated like a static variable // with the parent being a nspace object (instead of class object) Template t_register = getTemplate("jsv8_register_static_variable"); - t_register.replace("$jsparent", Getattr(current_namespace, NAME)) + t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED)) .replace("$jsname", state.variable(NAME)) .replace("$jsgetter", state.variable(GETTER)) .replace("$jssetter", state.variable(SETTER)) @@ -2027,7 +2054,7 @@ int V8Emitter::exitVariable(Node* n) int V8Emitter::exitFunction(Node* n) { - bool is_member = GetFlag(n, "ismember"); + bool is_member = GetFlag(n, "ismember") | GetFlag(n, "feature:extend"); // create a dispatcher for overloaded functions bool is_overloaded = GetFlag(n, "sym:overloaded"); @@ -2090,6 +2117,12 @@ void V8Emitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, Mar int i = 0; for (p = parms; p; i++) { String *arg = NewString(""); + String *type = Getattr(p, "type"); + + // ignore varargs + if (SwigType_isvarargs(type)) + break; + switch (mode) { case Getter: if (is_member && !is_static && i == 0) {