diff --git a/SWIG/CHANGES.current b/SWIG/CHANGES.current index 45c9db62f..0c27ab09a 100644 --- a/SWIG/CHANGES.current +++ b/SWIG/CHANGES.current @@ -1,5 +1,57 @@ Version 1.3.20 (In progress) ============================ +12/04/2003: mmatus (Marcelo Matus) + + - Now the virtual members with no explicit declarator + are properly identified: + + struct A { + virtual int f() = 0; + }; + + struct B { + int f(); + }; + + Here, B::f() is virtual, and the director and the + virtual elimination mechanism now recognize that. + + + - Initial support for protected virtual methods. They are now + properly emitted when using with director (python only by + now). + + %feature("director") A; + struct A { + protected: + virtual int f1() = 0; + }; + + %feature("director") B; + struct B : A{ + protected: + int f1(); + virtual f2(); + }; + + This can be dissabled by using the '-nodirprot' option. + + - The feature 'nodirector' is working now at the top level, + so, it must work for all the languages: + + %feature("director") A; + %feature("nodirector") A::f2; + + struct A { + virtual int f1(); + virtual int f2(); + }; + + in this case, only 'f1' is exported to the director class. + + - Added director support for const TYPE& arguments (python). + + 12/02/2003: cheetah (William Fulton) [Java] Fix for INOUT and OUTPUT typemaps in typemaps.i for when the JNI type is bigger than the C type. For example, unsigned long (32bits on most systems) diff --git a/SWIG/Examples/test-suite/common.mk b/SWIG/Examples/test-suite/common.mk index 18fc9c73e..6f9af51fb 100644 --- a/SWIG/Examples/test-suite/common.mk +++ b/SWIG/Examples/test-suite/common.mk @@ -112,6 +112,8 @@ CPP_TEST_CASES += \ director_basic \ director_exception \ director_finalizer \ + director_nested \ + director_protected \ director_unroll \ director_wombat \ dynamic_cast \ diff --git a/SWIG/Examples/test-suite/director_nested.i b/SWIG/Examples/test-suite/director_nested.i new file mode 100644 index 000000000..6b6ec9f2c --- /dev/null +++ b/SWIG/Examples/test-suite/director_nested.i @@ -0,0 +1,62 @@ +%module(directors="1") director_nested + +%{ +#include +#include +%} + +%include "std_string.i" + +%feature("director") FooBar; + +%newobject *::create(); + +%inline %{ + template + class Foo { + public: + virtual ~Foo() {} + + std::string advance() + { + return "Foo::advance;" + do_advance(); + } + + protected: + virtual std::string do_advance() = 0; + }; +%} + +%template(Foo_int) Foo; + +%inline %{ + + class Bar : public Foo + { + public: + + std::string step() + { + return "Bar::step;" + advance(); + } + + protected: + std::string do_advance() + { + return "Bar::do_advance;" + do_step(); + } + + + virtual std::string do_step() = 0; + }; + + template + class FooBar : public Bar + { + public: + virtual C get_value() = 0; + }; +%} + +%template(FooBar_int) FooBar; + diff --git a/SWIG/Examples/test-suite/director_protected.i b/SWIG/Examples/test-suite/director_protected.i new file mode 100644 index 000000000..4582f48e0 --- /dev/null +++ b/SWIG/Examples/test-suite/director_protected.i @@ -0,0 +1,46 @@ +%module(directors="1") director_protected + +%{ +#include +#include +%} + +%include "std_string.i" + +%feature("director") Foo; +%feature("director") Bar; + +%newobject *::create(); + +%inline %{ +class Foo { +public: + virtual ~Foo() {} + virtual std::string pong() { + return "Foo::pong();" + ping(); + } +protected: + virtual std::string ping() = 0; +}; + +class Bar : public Foo +{ +public: + Foo* create() + { + return new Bar(); + } + + std::string pong() { + return "Bar::pong();" + Foo::pong(); + } + +protected: + std::string ping() { + return "Bar::ping();"; + }; +}; + + +%} + diff --git a/SWIG/Examples/test-suite/python/director_nested_runme.py b/SWIG/Examples/test-suite/python/director_nested_runme.py new file mode 100644 index 000000000..0a1b8c11b --- /dev/null +++ b/SWIG/Examples/test-suite/python/director_nested_runme.py @@ -0,0 +1,36 @@ +from director_nested import * + + +class A(FooBar_int): + def do_step(self): + return "A::do_step;" + + def get_value(self): + return "A::get_value" + + pass + + +a = A() +if a.step() != "Bar::step;Foo::advance;Bar::do_advance;A::do_step;": + raise RuntimeError,"Bad A virtual resolution" + + +class B(FooBar_int): + def do_advance(self): + return "B::do_advance;" + self.do_step() + + def do_step(self): + return "B::do_step;" + + def get_value(self): + return "B::get_value" + + pass + + +b = B() + +if b.step() != "Bar::step;Foo::advance;B::do_advance;B::do_step;": + raise RuntimeError,"Bad B virtual resolution" + diff --git a/SWIG/Examples/test-suite/python/director_protected_runme.py b/SWIG/Examples/test-suite/python/director_protected_runme.py new file mode 100644 index 000000000..66559068c --- /dev/null +++ b/SWIG/Examples/test-suite/python/director_protected_runme.py @@ -0,0 +1,54 @@ +from director_protected import * + + + +class FooBar(Bar): + def ping(self): + return "FooBar::ping();" + + +b = Bar() +f = b.create() +fb = FooBar() + +try: + s1 = b.pong() + if s1 != "Bar::pong();Foo::pong();Bar::ping();": + raise RuntimeError + pass +except: + raise RuntimeError, "bad Bar::pong" + +try: + s2 = f.pong() + if s2 != "Bar::pong();Foo::pong();Bar::ping();": + raise RuntimeError + pass +except: + raise RuntimeError," bad Foo::pong" + +try: + s3 = fb.pong() + if s3 != "Bar::pong();Foo::pong();FooBar::ping();": + raise RuntimeError + pass +except: + raise RuntimeError," bad FooBar::pong" + +private=1 +try: + b.ping() + private=0 +except: + pass +if not private: + raise RuntimeError,"Boo::ping is private" + +private=1 +try: + f.ping() + private=0 +except: + pass +if not private: + raise RuntimeError,"Foo::ping is private" diff --git a/SWIG/Lib/python/python.swg b/SWIG/Lib/python/python.swg index e993e6ddb..f79ad67c3 100644 --- a/SWIG/Lib/python/python.swg +++ b/SWIG/Lib/python/python.swg @@ -440,12 +440,33 @@ %typemap(directorin,parse="i") bool ""; %typemap(directorin,parse="i") enum SWIGTYPE ""; -%typemap(directorin,parse="l") unsigned int, unsigned short, unsigned long, unsigned char "(long) $1_name"; +%typemap(directorin,parse="l") unsigned int, unsigned short, + unsigned long, unsigned char "(long) $1_name"; + -%typemap(directorin) long long - "$input = PyLong_FromLongLong($1_name);"; -%typemap(directorin) unsigned long long - "$input = PyLong_FromUnsignedLongLong($1_name);"; +%typemap(directorin) long long + "$input = PyLong_FromLongLong($1_name);"; +%typemap(directorin) unsigned long long + "$input = PyLong_FromUnsignedLongLong($1_name);"; + +%typemap(directorin,parse="i") const int& ""; +%typemap(directorin,parse="h") const short& ""; +%typemap(directorin,parse="l") const long& ""; +%typemap(directorin,parse="b") const signed char& ""; +%typemap(directorin,parse="f") const float& ""; +%typemap(directorin,parse="d") const double& ""; +%typemap(directorin,parse="i") const bool& ""; + +%typemap(directorin,parse="l") const unsigned int&, + const unsigned short&, const unsigned long&, + const unsigned char& "(long) $1_name"; + + +%typemap(directorin) const long long& + "$input = PyLong_FromLongLong($1_name);"; +%typemap(directorin) const unsigned long long& + "$input = PyLong_FromUnsignedLongLong($1_name);"; + %typemap(directorin, parse="l") int *DIRECTORIN, long* DIRECTORIN, unsigned int *DIRECTORIN, unsigned long *DIRECTORIN, @@ -457,7 +478,7 @@ %typemap(directorin, parse="O") PyObject* ""; -%typemap(directorin, parse="l") std::size_t "(long) $input"; +%typemap(directorin, parse="l") std::size_t, const std::size_t& "(long) $input"; /* // this is rather dangerous %typemap(directorin) SWIGTYPE { @@ -713,6 +734,7 @@ DIRECTOROUT_TYPEMAP(std::size_t, PyInt_AsLong); %ignorewarn("362:operator= ignored") operator=; %ignorewarn("383:operator++ ignored") operator++; %ignorewarn("384:operator-- ignored") operator--; +%ignorewarn("385:operator! ignored") operator!; %ignorewarn("381:operator&& ignored") operator&&; %ignorewarn("382:operator|| ignored") operator||; %ignorewarn("386:operator->* ignored") operator->*; diff --git a/SWIG/Source/CParse/parser.y b/SWIG/Source/CParse/parser.y index eae59be57..682358903 100644 --- a/SWIG/Source/CParse/parser.y +++ b/SWIG/Source/CParse/parser.y @@ -308,7 +308,7 @@ static void add_symbols(Node *n) { } /* Don't add symbols for private/protected members */ - if (inclass && (cplus_mode != CPLUS_PUBLIC)) { + if (inclass && (cplus_mode == CPLUS_PRIVATE)) { while (n) { Swig_symbol_add(0, n); /* Add to C symbol table */ if (cplus_mode == CPLUS_PRIVATE) { @@ -327,6 +327,9 @@ static void add_symbols(Node *n) { n = nextSibling(n); continue; } + if (cplus_mode == CPLUS_PROTECTED) { + Setattr(n,"access", "protected"); + } decl = Getattr(n,"decl"); if (!SwigType_isfunction(decl)) { symname = make_name(Getattr(n,"name"),0); @@ -3506,9 +3509,11 @@ def_args : EQUAL definetype { Node *n = Swig_symbol_clookup($3.id,0); if (n) { String *q = Swig_symbol_qualified(n); - if (Getattr(n,"access")) { - if (cplus_mode == CPLUS_PUBLIC) { - Swig_warning(WARN_PARSE_PRIVATE, cparse_file, cparse_line,"'%s' is private in this context.\n", $3.id); + String *a = Getattr(n,"access"); + if (a && (Strncmp(a,"private",7) == 0)) { + if (cplus_mode != CPLUS_PRIVATE) { + Swig_warning(WARN_PARSE_PRIVATE, cparse_file, + cparse_line,"'%s' is %s in this context.\n", q, a); Swig_warning(WARN_PARSE_BAD_DEFAULT, cparse_file, cparse_line,"Can't set default argument value (ignored)\n"); } $$.val = 0; @@ -4314,7 +4319,9 @@ expr : exprnum { $$ = $1; } /* Check if value is in scope */ n = Swig_symbol_clookup($1,0); if (n) { - if (Getattr(n,"access") && (cplus_mode == CPLUS_PUBLIC)) { + String *a = Getattr(n,"access"); + if (a && (Strncmp(a, "private", 7) == 0) + && (cplus_mode != CPLUS_PRIVATE)) { Swig_warning(WARN_PARSE_PRIVATE,cparse_file, cparse_line, "'%s' is private in this context.\n", $1); $$.type = T_ERROR; } else { diff --git a/SWIG/Source/Modules/allocate.cxx b/SWIG/Source/Modules/allocate.cxx index 0d805bff4..e0bbb3f55 100644 --- a/SWIG/Source/Modules/allocate.cxx +++ b/SWIG/Source/Modules/allocate.cxx @@ -19,6 +19,7 @@ char cvsroot_allocate_cxx[] = "$Header$"; #include "swigmod.h" +#include "utils.h" static int virtual_elimination_mode = 0; /* set to 0 on default */ /* Set virtual_elimination_mode */ @@ -93,6 +94,7 @@ class Allocate : public Dispatcher { (checkAttribute(temp, "type", type)) && (!Strcmp(local_decl, base_decl)) ) { // Indicate a virtual method in the derived class, that is, not the virtual method definition in a base class + Setattr(c, "storage", "virtual"); Setattr(c, "virtual:derived", "1"); if (virtual_elimination_mode) Setattr(c, "feature:ignore", "1"); @@ -146,7 +148,8 @@ class Allocate : public Dispatcher { bases = Getattr(classnode, "bases"); if (!bases) return 0; - if (checkAttribute(member, "storage", "virtual")) { + //if (checkAttribute(member, "storage", "virtual")) + { if (function_is_defined_in_bases(member, bases)) defined = 1; } @@ -318,7 +321,7 @@ class Allocate : public Dispatcher { { for (int i = 0; i < Len(methods); ) { Node *n = Getitem(methods,i); - if (checkAttribute(n,"access","protected") || checkAttribute(n,"access","private")) { + if (!is_public(n)) { Delitem(methods,i); continue; } @@ -490,8 +493,8 @@ public: if (inclass) { /* check whether the member node n is defined in class node inclass's bases */ - if (checkAttribute(n, "storage", "virtual")) - class_member_is_defined_in_bases(n, inclass); + // if (checkAttribute(n, "storage", "virtual")) + class_member_is_defined_in_bases(n, inclass); /* Check to see if this is a static member or not. If so, we add an attribute cplus:staticbase that saves the current class */ diff --git a/SWIG/Source/Modules/lang.cxx b/SWIG/Source/Modules/lang.cxx index 723370440..52449f0bb 100644 --- a/SWIG/Source/Modules/lang.cxx +++ b/SWIG/Source/Modules/lang.cxx @@ -15,8 +15,17 @@ char cvsroot_lang_cxx[] = "$Header$"; #include "swigmod.h" +#include "utils.h" #include +static int director_protected_mode = 0; /* set to 0 on default */ + +/* Set director_protected_mode */ +void Wrapper_director_protected_mode_set(int flag) { + director_protected_mode = flag; +} + + /* Some status variables used during parsing */ static int InClass = 0; /* Parsing C++ or not */ @@ -689,7 +698,7 @@ int Language::cDeclaration(Node *n) { SwigType *ty, *fullty; if (CurrentClass && (cplus_mode != CPLUS_PUBLIC)) return SWIG_NOWRAP; - + if (Cmp(storage,"typedef") == 0) { Swig_save("cDeclaration",n,"type",NIL); SwigType *t = Copy(type); @@ -1421,27 +1430,27 @@ int Language::unrollVirtualMethods(Node *n, // find the methods that need directors classname = Getattr(n, "name"); for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + if (!Cmp(Getattr(ni, "feature:nodirector"), "1")) continue; nodeType = Getattr(ni, "nodeType"); storage = Getattr(ni, "storage"); decl = Getattr(ni, "decl"); if (!Cmp(nodeType, "cdecl") && SwigType_isfunction(decl)) { int is_virtual = storage && !Cmp(storage, "virtual"); - String* access = Getattr(ni, "access"); - if (!access || !Cmp(access, "public")) { - if (is_virtual) { - String *method_id; - String *name = Getattr(ni, "name"); - method_id = NewStringf("%s|%s", name, decl); - String *fqname = NewString(""); - Printf(fqname, "%s::%s", classname, name); - Hash *item = NewHash(); - Setattr(item, "fqName", fqname); - Setattr(item, "methodNode", ni); - Setattr(vm, method_id, item); - Delete(fqname); - Delete(item); - Delete(method_id); - } + if (is_virtual && + (is_public(ni) || (is_protected(ni) && director_protected_mode))) { + Setattr(ni, "feature:director", "1"); + String *method_id; + String *name = Getattr(ni, "name"); + method_id = NewStringf("%s|%s", name, decl); + String *fqname = NewString(""); + Printf(fqname, "%s::%s", classname, name); + Hash *item = NewHash(); + Setattr(item, "fqName", fqname); + Setattr(item, "methodNode", ni); + Setattr(vm, method_id, item); + Delete(fqname); + Delete(item); + Delete(method_id); } } else if (!Cmp(nodeType, "destructor")) { @@ -1504,8 +1513,7 @@ int Language::classDirectorConstructors(Node *n) { for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { nodeType = Getattr(ni, "nodeType"); if (!Cmp(nodeType, "constructor")) { - String* access = Getattr(ni, "access"); - if (!access || !Cmp(access, "public")) { + if (is_public(ni)) { classDirectorConstructor(ni); constructor = 1; } @@ -1637,7 +1645,7 @@ int Language::classDeclaration(Node *n) { ClassType = NewStringf("%s %s", kind, classname); } Setattr(n,"classtype", SwigType_namestr(ClassType)); - Setattr(n,"classtypeobj", Copy(ClassType)); + InClass = 1; CurrentClass = n; diff --git a/SWIG/Source/Modules/python.cxx b/SWIG/Source/Modules/python.cxx index cf452c7ba..21587dfb1 100644 --- a/SWIG/Source/Modules/python.cxx +++ b/SWIG/Source/Modules/python.cxx @@ -12,6 +12,8 @@ char cvsroot_python_cxx[] = "$Header$"; #include "swigmod.h" +#include "utils.h" + #ifndef MACSWIG #include "swigconfig.h" @@ -68,6 +70,8 @@ Python Options (available with -python)\n\ -noexcept - No automatic exception handling\n\ -noproxy - Don't generate proxy classes \n\n"; +extern void Wrapper_director_protected_mode_set(int); + class PYTHON : public Language { public: @@ -79,6 +83,8 @@ public: SWIG_library_directory("python"); + Wrapper_director_protected_mode_set(1); + for (int i = 1; i < argc; i++) { if (argv[i]) { if(strcmp(argv[i],"-interface") == 0) { @@ -122,6 +128,8 @@ public: classic = 0; modern = 1; Swig_mark_arg(i); + } else if (strcmp(argv[i],"-nodirprot") == 0) { + Wrapper_director_protected_mode_set(0); } else if (strcmp(argv[i],"-help") == 0) { fputs(usage,stderr); } else if (strcmp (argv[i], "-ldflags") == 0) { @@ -1304,8 +1312,15 @@ public: /* declare Python return value */ Wrapper_add_local(w, "result", "PyObject *result"); + /* direct call to superclass if _up is set */ - Printf(w->code, "if (swig_get_up()) {\n"); + if (is_protected(n)) { + Printf(w->code, "PyObject *obj = PyObject_GetAttrString(swig_get_self(), \"%s\");\n", + Getattr(n,"sym:name")); + Printf(w->code, "if (!obj) {\n"); + } else { + Printf(w->code, "if (swig_get_up()) {\n"); + } if (pure_virtual) { Printf(w->code, "throw Swig::DirectorPureVirtualException();\n"); } else { diff --git a/SWIG/Source/Modules/typepass.cxx b/SWIG/Source/Modules/typepass.cxx index 3c142bc80..4e80d861c 100644 --- a/SWIG/Source/Modules/typepass.cxx +++ b/SWIG/Source/Modules/typepass.cxx @@ -24,6 +24,7 @@ char cvsroot_typepass_cxx[] = "$Header$"; #include "swigmod.h" +#include "utils.h" struct normal_node { Symtab *symtab; @@ -799,7 +800,7 @@ public: ns = 0; } if (!ns) { - if (!Getattr(n,"access") || ((Strcmp(Getattr(n,"access"),"public") == 0))) { + if (is_public(n)) { Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n,"uname"))); } } else { diff --git a/SWIG/Source/Modules/utils.h b/SWIG/Source/Modules/utils.h new file mode 100644 index 000000000..29b7c6cc2 --- /dev/null +++ b/SWIG/Source/Modules/utils.h @@ -0,0 +1,35 @@ +#ifndef __Modules_utils_h__ +#define __Modules_utils_h__ + + +inline +int is_public(Node* n) +{ + String* access = Getattr(n, "access"); + return !access || !Cmp(access, "public"); +} + +inline +int is_private(Node* n) +{ + String* access = Getattr(n, "access"); + return access && !Cmp(access, "private"); +} + +inline +int is_protected(Node* n) +{ + String* access = Getattr(n, "access"); + return access && !Cmp(access, "protected"); +} + +inline +int is_member_director(Node* classnode, Node* member) +{ + int class_director = !Cmp(Getattr(classnode,"feature:director"), "1"); + int cdecl_nodirector = !Cmp(Getattr(member,"feature:nodirector"),"1"); + return class_director && !cdecl_nodirector; +} + + +#endif //__Modules_utils_h__