diff --git a/dtool/src/cppparser/cppBison.yxx b/dtool/src/cppparser/cppBison.yxx index 28e3577990..025d34f24e 100644 --- a/dtool/src/cppparser/cppBison.yxx +++ b/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; } ; diff --git a/dtool/src/cppparser/cppInstance.h b/dtool/src/cppparser/cppInstance.h index 2e9642381f..e2ecbc0ced 100644 --- a/dtool/src/cppparser/cppInstance.h +++ b/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); diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx index f48a057cb1..3e332e5ec6 100644 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ b/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; diff --git a/dtool/src/dtoolbase/dtoolbase.h b/dtool/src/dtoolbase/dtoolbase.h index 69afa9993e..b6fe152dba 100644 --- a/dtool/src/dtoolbase/dtoolbase.h +++ b/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 diff --git a/dtool/src/interrogate/functionRemap.cxx b/dtool/src/interrogate/functionRemap.cxx index 2fc33fc21a..c58c80db1f 100644 --- a/dtool/src/interrogate/functionRemap.cxx +++ b/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 { - - 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); - } - const char *separator = ""; - call << "("; + // 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() << "("; + } + + if (_has_this && !container.empty()) { + call << container; + separator = ", "; + } + } else { + + 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 << "("; + } + 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(); diff --git a/dtool/src/interrogate/functionRemap.h b/dtool/src/interrogate/functionRemap.h index 931bb8634c..644693bd9b 100644 --- a/dtool/src/interrogate/functionRemap.h +++ b/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; diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx index 6a05255f22..f1813cd775 100644 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ b/dtool/src/interrogate/interrogateBuilder.cxx @@ -376,10 +376,10 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int declaration_bodies << "#include \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; }