From 72984676ca9549ed7ac4d7fac8a2dbc7f67c5bb3 Mon Sep 17 00:00:00 2001 From: Marcelo Matus Date: Thu, 11 Dec 2003 01:59:12 +0000 Subject: [PATCH] Lateral change to add runtime "reprotection" at the python side for protected director members. Lib/python/director.swg: added needed code for runtime checking Source/Modules/python.cxx: added needed code for runtime checking director_protected_runme.py: checks now that the runtime protection is working The extra runtime checking is only done for protected members, so, the old public directors members don't feel any overhead. This finished the director protected support for the python language. Java and Ocalm will need to add the "reprotection" mechanism latter. But as in the python case, the changes will be localized in the languages files, and there will be no need to touch the core files anymore. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@5532 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- CHANGES.current | 61 +++++++++++++++++++ .../python/director_protected_runme.py | 46 ++++++++++++-- Lib/python/director.swg | 7 +++ Source/Modules/python.cxx | 40 ++++++++++++ 4 files changed, 148 insertions(+), 6 deletions(-) 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); }