Browse Source

Add functionality allowing extension functions to interrogate

rdb 15 years ago
parent
commit
beb90c565f

+ 5 - 0
dtool/src/cppparser/cppBison.yxx

@@ -250,6 +250,7 @@ pop_struct() {
 %token KW_ELSE
 %token KW_END_PUBLISH 
 %token KW_ENUM 
+%token KW_EXTENSION
 %token KW_EXTERN
 %token KW_EXPLICIT
 %token KW_PUBLISHED
@@ -547,6 +548,10 @@ storage_class:
         | storage_class KW_BLOCKING
 {
   $$ = $1 | (int)CPPInstance::SC_blocking;
+}
+        | storage_class KW_EXTENSION
+{
+  $$ = $1 | (int)CPPInstance::SC_extension;
 }
         ;
 

+ 16 - 12
dtool/src/cppparser/cppInstance.h

@@ -37,25 +37,29 @@ public:
   // Some of these flags clearly only make sense in certain contexts,
   // e.g. for a function or method.
   enum StorageClass {
-    SC_static       = 0x001,
-    SC_extern       = 0x002,
-    SC_c_binding    = 0x004,
-    SC_virtual      = 0x008,
-    SC_inline       = 0x010,
-    SC_explicit     = 0x020,
-    SC_register     = 0x040,
-    SC_pure_virtual = 0x080,
-    SC_volatile     = 0x100,
-    SC_mutable      = 0x200,
+    SC_static       = 0x0001,
+    SC_extern       = 0x0002,
+    SC_c_binding    = 0x0004,
+    SC_virtual      = 0x0008,
+    SC_inline       = 0x0010,
+    SC_explicit     = 0x0020,
+    SC_register     = 0x0040,
+    SC_pure_virtual = 0x0080,
+    SC_volatile     = 0x0100,
+    SC_mutable      = 0x0200,
 
     // This bit is only set by CPPStructType::check_virtual().
-    SC_inherited_virtual = 0x400,
+    SC_inherited_virtual = 0x0400,
 
     // This is a special "storage class" for methods tagged with the
     // BLOCKING macro (i.e. the special __blocking keyword).  These
     // are methods that might block and therefore need to release
     // Python threads for their duration.
-    SC_blocking     = 0x800,
+    SC_blocking     = 0x0800,
+
+    // And this is for methods tagged with __extension, which declares
+    // extension methods defined separately from the source code.
+    SC_extension    = 0x1000,
   };
 
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);

+ 1 - 0
dtool/src/cppparser/cppPreprocessor.cxx

@@ -1966,6 +1966,7 @@ check_keyword(const string &name) {
   if (name == "__end_publish") return KW_END_PUBLISH;
   if (name == "enum") return KW_ENUM;
   if (name == "extern") return KW_EXTERN;
+  if (name == "__extension") return KW_EXTENSION;
   if (name == "explicit") return KW_EXPLICIT;
   if (name == "__published") return KW_PUBLISHED;
   if (name == "false") return KW_FALSE;

+ 18 - 1
dtool/src/dtoolbase/dtoolbase.h

@@ -325,12 +325,29 @@
 #define END_PUBLISH __end_publish
 #define BLOCKING __blocking
 #define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
-#undef USE_STL_ALLOCATOR  // Don't try to parse these template classes in interrogate.
+#undef USE_STL_ALLOCATOR  /* Don't try to parse these template classes in interrogate. */
+#define EXTENSION(x) __extension x;
+#define EXTEND __extension
+#define EXT_FUNC(func) ::func()
+#define EXT_FUNC_ARGS(func, ...) ::func(__VA_ARGS__)
+#define EXT_METHOD(cl, m) cl::m()
+#define EXT_METHOD_ARGS(cl, m, ...) cl::m(__VA_ARGS__)
+#define EXT_CONST_METHOD(cl, m) cl::m() const
+#define EXT_CONST_METHOD_ARGS(cl, m, ...) cl::m(__VA_ARGS__) const
 #else
 #define BEGIN_PUBLISH
 #define END_PUBLISH
 #define BLOCKING
 #define MAKE_SEQ(seq_name, num_name, element_name)
+#define EXTENSION(x)
+#define EXTEND
+/* If you change this, don't forget to also change it in interrogate itself. */
+#define EXT_FUNC(cl, m) _ext__ ## m ()
+#define EXT_FUNC_ARGS(cl, m, ...) _ext__ ## m (__VA_ARGS__)
+#define EXT_METHOD(cl, m) _ext_ ## cl ## _ ## m (cl * _ext_this)
+#define EXT_METHOD_ARGS(cl, m, ...) _ext_ ## cl ## _ ## m (cl * _ext_this, __VA_ARGS__)
+#define EXT_CONST_METHOD(cl, m) _ext_ ## cl ## _ ## m (const cl * _ext_this)
+#define EXT_CONST_METHOD_ARGS(cl, m, ...) _ext_ ## cl ## _ ## m (const cl * _ext_this, __VA_ARGS__)
 #endif
 
 #ifdef __cplusplus

+ 41 - 19
dtool/src/interrogate/functionRemap.cxx

@@ -44,6 +44,7 @@ FunctionRemap(const InterrogateType &itype, const InterrogateFunction &ifunc,
   _ForcedVoidReturn = false;
   _has_this = false;
   _blocking = false;
+  _extension = false;
   _const_method = false;
   _first_true_parameter = 0;
   _num_default_parameters = num_default_parameters;
@@ -115,10 +116,11 @@ string FunctionRemap::call_function(ostream &out, int indent_level, bool convert
       InterfaceMaker::indent(out, indent_level)
         << "unref_delete(" << container << ");\n";
     } else {
-        if(inside_python_native)
+        if (inside_python_native) {
           InterfaceMaker::indent(out, indent_level) << "Dtool_Py_Delete(self); \n";
-        else
-            InterfaceMaker::indent(out, indent_level) << " delete " << container << ";\n";
+        } else {
+          InterfaceMaker::indent(out, indent_level) << " delete " << container << ";\n";
+        }
     }
 
   } else if (_type == T_typecast_method) {
@@ -376,8 +378,7 @@ get_call_str(const string &container, const vector_string &pexprs) const {
       call << _expression;
     }
 
-  } else if (_type == T_setter) 
-  {
+  } else if (_type == T_setter) {
     if (!container.empty()) {
       call << "(" << container << ")->" << _expression;
     } else {
@@ -388,23 +389,41 @@ get_call_str(const string &container, const vector_string &pexprs) const {
     _parameters[0]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs));
 
   } else {
+    const char *separator = "";
 
-    if (_type == T_constructor) {
-      // Constructors are called differently.
-      call << _cpptype->get_local_name(&parser);
+    // If this function is marked as having an extension function,
+    // call that instead.  The naming convention of the extension
+    // function has to match the EXT_IMPL definition in dtoolbase.h.
+    if (_extension) {
+      if (_cpptype != NULL) {
+        call << "_ext_"  << _cpptype->get_local_name()
+                         << _cppfunc->get_local_name() << "(";
+      } else {
+        call << "_ext__" << _cppfunc->get_local_name() << "(";
+      }
 
-    } else if (_has_this && !container.empty()) {
-      // If we have a "this" parameter, the calling convention is also
-      // a bit different.
-      call << "(" << container << ")->" << _cppfunc->get_local_name();
-      
+      if (_has_this && !container.empty()) {
+        call << container;
+        separator = ", ";
+      }
     } else {
-      call << _cppfunc->get_local_name(&parser);
-    }
 
-    const char *separator = "";
+      if (_type == T_constructor) {
+        // Constructors are called differently.
+        call << _cpptype->get_local_name(&parser);
+
+      } else if (_has_this && !container.empty()) {
+        // If we have a "this" parameter, the calling convention is also
+        // a bit different.
+        call << "(" << container << ")->" << _cppfunc->get_local_name();
+        
+      } else {
+        call << _cppfunc->get_local_name(&parser);
+      }
+
+      call << "(";
+    }
 
-    call << "(";
     if (_flags & F_explicit_self) {
       // Pass on the PyObject * that we stripped off above.
       call << separator << "self";
@@ -472,11 +491,14 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     _type = T_setter;
   }
 
-  if (_cpptype != (CPPType *)NULL &&
-      ((_cppfunc->_storage_class & CPPInstance::SC_blocking) != 0)) {
+  if ((_cppfunc->_storage_class & CPPInstance::SC_blocking) != 0) {
     // If it's marked as a "blocking" method or function, record that.
     _blocking = true;
   }
+  if ((_cppfunc->_storage_class & CPPInstance::SC_extension) != 0) {
+    // Same with functions or methods marked with "extension".
+    _extension = true;
+  }
 
   string fname = _cppfunc->get_simple_name();
 

+ 1 - 0
dtool/src/interrogate/functionRemap.h

@@ -97,6 +97,7 @@ public:
   bool _ForcedVoidReturn;
   bool _has_this;
   bool _blocking;
+  bool _extension;
   bool _const_method;
   int _first_true_parameter;
   int _num_default_parameters;

+ 11 - 5
dtool/src/interrogate/interrogateBuilder.cxx

@@ -376,10 +376,10 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
 
   declaration_bodies << "#include <sstream>\n";
 
-  if (build_python_native  )
-  {
-    if(library_name.size() > 1)
-        declaration_bodies << "#define PANDA_LIBRARY_NAME_" << library_name << "\n";
+  if (build_python_native) {
+    if (library_name.size() > 1) {
+      declaration_bodies << "#define PANDA_LIBRARY_NAME_" << library_name << "\n";
+    }
     declaration_bodies << "#include \"py_panda.h\"  \n";
   }
   declaration_bodies << "\n";
@@ -396,6 +396,12 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
       } else {
         declaration_bodies << "#include <" << filename << ">\n";
       }
+    // Check if it's a special extension file.
+    } else if (filename.length() > 6 && filename.substr(filename.length() - 6) == "_ext.I") {
+      declaration_bodies
+        << "#define this _ext_this\n"
+        << "#include \"" << filename << "\"\n"
+        << "#undef this\n";
     }
   }
   declaration_bodies << "\n";
@@ -921,7 +927,7 @@ in_noinclude(const string &name) const {
 ////////////////////////////////////////////////////////////////////
 bool InterrogateBuilder::
 should_include(const string &filename) const {
-  // Don't directly include any .cxx or .I files.
+  // Don't directly include any .cxx or .I files, except for extensions.
   if (CPPFile::is_c_or_i_file(filename)) {
     return false;
   }