diff --git a/CHANGES.current b/CHANGES.current index 42c4d089a..481d13a87 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,5 +1,66 @@ Version 1.3.20 (In progress) ============================ +12/10/2003: mmatus (Marcelo Matus) + + [python] Implementing the runtime "reprotected" director + members, if you have: + + %feature("director") B; + + class Bar { + public: + virtual ~Bar(); + virtual int hello() { return do_hello();) + + protected: + virtual int do_hi() {return 0;} + virtual int do_hello() {return 0;} + }; + + then, at the python side + + import my_module + + class Foo(my_module.Bar): + def do_hello(self): + return 1 + pass + + b = Bar() # Pure C++ Director class + f = Foo() # C++ Director + python methods + + b.hello() # Ok, and it calls C++ Bar::do_hello() + f.hello() # Ok, and it calls Python Foo::do_hello() + + b.do_hi() # RuntimeError, do_hi() is protected!! + f.do_hi() # RuntimeError, do_hi() is protected!! + + b.do_hello() # RuntimeError, do_hello() is protected!! + f.do_hello() # Ok, since it its redefined in python. + + Here Bar.do_hello is always protected, but Foo.do_hello + is "public", because it is redefined in python. Before, + all the 'do_hello' methods were public. + + This seems to be a good compromise between C++ and python + philosophies, ie, all the director protected methods keep + protected at the user side (C++ way) until they are + redefined (python way, were all defined methods are always + public). And this is not only a good compromise, it also + seems to be the only way to do it :). + + Now ruby has native director protected members, and python + pure runtime support. I guess these are the two possible + extreme cases. And hopefully, they could be used as + templates to modify the other languages that support + directors, so they can "reprotect" the protected director + members at the target language side. + + This finished the director protected support for the + python language. Java and Ocalm will need to add the + "reprotection" latter. + + 12/08/2003: mmatus (Marcelo Matus) The virtual method detections now properly treats the following cases: diff --git a/Examples/test-suite/python/director_protected_runme.py b/Examples/test-suite/python/director_protected_runme.py index 9314f5845..9d565a1b4 100644 --- a/Examples/test-suite/python/director_protected_runme.py +++ b/Examples/test-suite/python/director_protected_runme.py @@ -6,30 +6,54 @@ class FooBar(Bar): def ping(self): return "FooBar::ping();" +class FooBar2(Bar): + def ping(self): + return "FooBar2::ping();" + def pang(self): + return "FooBar2::pang();" + b = Bar() f = b.create() fb = FooBar() +fb2 = FooBar2() + try: - s1 = b.pong() - if s1 != "Bar::pong();Foo::pong();Bar::ping();": + s = fb.used() + if s != "Foo::pang();Bar::pong();Foo::pong();FooBar::ping();": + raise RuntimeError + pass +except: + raise RuntimeError, "bad FooBar::used" + +try: + s = fb2.used() + if s != "FooBar2::pang();Bar::pong();Foo::pong();FooBar2::ping();": + raise RuntimeError + pass +except: + raise RuntimeError, "bad FooBar2::used" + +try: + s = b.pong() + if s != "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();": + s = f.pong() + if s != "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();": + s = fb.pong() + if s != "Bar::pong();Foo::pong();FooBar::ping();": raise RuntimeError pass except: @@ -52,3 +76,13 @@ except: pass if not protected: raise RuntimeError,"Foo::ping is protected" + + +protected=1 +try: + f.pang() + protected=0 +except: + pass +if not protected: + raise RuntimeError,"FooBar::pang is protected" diff --git a/Lib/python/director.swg b/Lib/python/director.swg index f13073a27..2f1ec89fa 100644 --- a/Lib/python/director.swg +++ b/Lib/python/director.swg @@ -164,6 +164,13 @@ namespace Swig { } } + /* methods to implement pseudo protected director members */ + virtual bool swig_get_inner(const char* name) const { + return true; + } + + virtual void swig_set_inner(const char* name, bool val) const { + } }; bool Swig::Director::swig_up = false; diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 0e8e8e446..35fc89275 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -728,6 +728,13 @@ public: if (/*directorbase &&*/ !constructor && !destructor && isVirtual) { Wrapper_add_local(f, "director", "Swig::Director *director = 0"); Printf(f->code, "director = dynamic_cast(arg1);\n"); + if (dirprot_mode() && is_protected(n)) { + Printf(f->code, "if (director && !(director->swig_get_inner(\"%s\"))) ", name); + Printf(f->code, + "SWIG_exception(SWIG_RuntimeError,\"accessing protected member %s\");\n", + name); + } + Printf(f->code, "if (director && (director->swig_get_self()==obj0)) director->swig_set_up();\n"); } } @@ -1327,11 +1334,16 @@ public: String *pyname = Getattr(n,"sym:name"); /* pass the method call on to the Python object */ + if (dirprot_mode() && is_protected(n)) + Printf(w->code, "swig_set_inner(\"%s\", true);\n", name); + if (Len(parse_args) > 0) { Printf(w->code, "result = PyObject_CallMethod(swig_get_self(), \"%s\", \"%s\" %s);\n", pyname, parse_args, arglist); } else { Printf(w->code, "result = PyObject_CallMethod(swig_get_self(), \"%s\", NULL);\n", pyname); } + if (dirprot_mode() && is_protected(n)) + Printf(w->code, "swig_set_inner(\"%s\", false);\n", name); /* exception handling */ tm = Swig_typemap_lookup_new("director:except", n, "result", 0); @@ -1533,6 +1545,11 @@ public: * ------------------------------------------------------------ */ int classDirectorInit(Node *n) { + if (dirprot_mode()) { + Printf(f_directors_h, "#include \n"); + Printf(f_directors_h, "#include \n\n"); + } + String *declaration = Swig_director_declaration(n); Printf(f_directors_h, "\n"); Printf(f_directors_h, "%s\n", declaration); @@ -1546,6 +1563,29 @@ public: * ------------------------------------------------------------ */ int classDirectorEnd(Node *n) { + if (dirprot_mode()) { + /* + This implementation uses a std::map. + + It should be possible to rewrite it using a more elegant way, + like copying the Java approach for the 'override' array. + + But for know, this seems to be the least intrusive way. + */ + Printf(f_directors_h,"\n\n"); + Printf(f_directors_h,"/* Internal Director utilities */\n"); + Printf(f_directors_h,"public:\n"); + Printf(f_directors_h," bool swig_get_inner(const char* name) const {\n"); + Printf(f_directors_h," std::map::const_iterator iv = inner.find(name);\n"); + Printf(f_directors_h," return (iv != inner.end() ? iv->second : false);\n"); + Printf(f_directors_h," }\n\n"); + + Printf(f_directors_h," void swig_set_inner(const char* name, bool val) const\n"); + Printf(f_directors_h," { inner[name] = val;}\n\n"); + Printf(f_directors_h,"private:\n"); + Printf(f_directors_h," mutable std::map inner;\n"); + + } Printf(f_directors_h, "};\n\n"); return Language::classDirectorEnd(n); }