diff options
author | robot-piglet <[email protected]> | 2025-08-28 14:27:58 +0300 |
---|---|---|
committer | robot-piglet <[email protected]> | 2025-08-28 14:57:06 +0300 |
commit | 81d828c32c8d5477cb2f0ce5da06a1a8d9392ca3 (patch) | |
tree | 3081d566f0d5158d76e9093261344f6406fd09f7 /contrib/tools/swig/Source/Modules/interface.cxx | |
parent | 77ea11423f959e51795cc3ef36a48d808b4ffb98 (diff) |
Intermediate changes
commit_hash:d5b1af16dbe9030537a04c27eb410c88c2f496cd
Diffstat (limited to 'contrib/tools/swig/Source/Modules/interface.cxx')
-rw-r--r-- | contrib/tools/swig/Source/Modules/interface.cxx | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/Modules/interface.cxx b/contrib/tools/swig/Source/Modules/interface.cxx new file mode 100644 index 00000000000..3916c4085b0 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/interface.cxx @@ -0,0 +1,210 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * interface.cxx + * + * This module contains support for the interface feature. + * This feature is used in language modules where the target language does not + * naturally support C++ style multiple inheritance, but does support inheritance + * from multiple interfaces. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static bool interface_feature_enabled = false; + +/* ----------------------------------------------------------------------------- + * collect_interface_methods() + * + * Create a list of all the methods from the base classes of class n that are + * marked as an interface. The resulting list is thus the list of methods that + * need to be implemented in order for n to be non-abstract. + * ----------------------------------------------------------------------------- */ + +static List *collect_interface_methods(Node *n) { + List *methods = NewList(); + if (List *bases = Getattr(n, "interface:bases")) { + for (Iterator base = First(bases); base.item; base = Next(base)) { + Node *cls = base.item; + if (cls == n) + continue; + for (Node *child = firstChild(cls); child; child = nextSibling(child)) { + if (Cmp(nodeType(child), "cdecl") == 0) { + if (GetFlag(child, "feature:ignore") || Getattr(child, "interface:owner")) + continue; // skip methods propagated to bases + if (!checkAttribute(child, "kind", "function")) + continue; + if (checkAttribute(child, "storage", "static")) + continue; // accept virtual methods, non-virtual methods too... mmm??. Warn that the interface class has something that is not a virtual method? + Node *nn = copyNode(child); + Setattr(nn, "interface:owner", cls); + ParmList *parms = CopyParmList(Getattr(child, "parms")); + Setattr(nn, "parms", parms); + Delete(parms); + ParmList *throw_parm_list = Getattr(child, "throws"); + if (throw_parm_list) + Setattr(nn, "throws", CopyParmList(throw_parm_list)); + Append(methods, nn); + } + } + } + } + return methods; +} + +/* ----------------------------------------------------------------------------- + * collect_interface_bases + * ----------------------------------------------------------------------------- */ + +static void collect_interface_bases(List *bases, Node *n) { + if (GetFlag(n, "feature:interface")) { + if (!Swig_item_in_list(bases, n)) + Append(bases, n); + } + + if (List *baselist = Getattr(n, "bases")) { + for (Iterator base = First(baselist); base.item; base = Next(base)) { + if (!GetFlag(base.item, "feature:ignore")) { + if (GetFlag(base.item, "feature:interface")) + collect_interface_bases(bases, base.item); + } + } + } +} + +/* ----------------------------------------------------------------------------- + * collect_interface_base_classes() + * + * Create a list containing all the classes up the inheritance hierarchy + * marked with feature:interface (including this class n). + * Stops going up the inheritance chain as soon as a class is found without + * feature:interface. + * Remove duplicate bases (in the event of multiple inheritance). + * The idea is to find all the base interfaces that a class must implement. + * ----------------------------------------------------------------------------- */ + +static void collect_interface_base_classes(Node *n) { + if (GetFlag(n, "feature:interface")) { + // check all bases are also interfaces + if (List *baselist = Getattr(n, "bases")) { + for (Iterator base = First(baselist); base.item; base = Next(base)) { + if (!GetFlag(base.item, "feature:ignore")) { + if (!GetFlag(base.item, "feature:interface")) { + Swig_error(Getfile(n), Getline(n), "Base class '%s' of '%s' is not similarly marked as an interface.\n", SwigType_namestr(Getattr(base.item, "name")), SwigType_namestr(Getattr(n, "name"))); + Exit(EXIT_FAILURE); + } + } + } + } + } + + List *interface_bases = NewList(); + collect_interface_bases(interface_bases, n); + if (Len(interface_bases) == 0) + Delete(interface_bases); + else + Setattr(n, "interface:bases", interface_bases); +} + +/* ----------------------------------------------------------------------------- + * process_interface_name() + * ----------------------------------------------------------------------------- */ + +static void process_interface_name(Node *n) { + if (GetFlag(n, "feature:interface")) { + String *interface_name = Getattr(n, "feature:interface:name"); + if (!Len(interface_name)) { + Swig_error(Getfile(n), Getline(n), "The interface feature for '%s' is missing the name attribute.\n", SwigType_namestr(Getattr(n, "name"))); + Exit(EXIT_FAILURE); + } + if (Strchr(interface_name, '%')) { + String *name = NewStringf(interface_name, Getattr(n, "sym:name")); + Setattr(n, "interface:name", name); + } else { + Setattr(n, "interface:name", interface_name); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_interface_propagate_methods() + * + * Find all the base classes marked as an interface (with feature:interface) for + * class node n. For each of these, add all of its methods as methods of n so that + * n is not abstract. If class n is also marked as an interface, it will remain + * abstract and not have any methods added. + * ----------------------------------------------------------------------------- */ + +void Swig_interface_propagate_methods(Node *n) { + if (interface_feature_enabled) { + process_interface_name(n); + collect_interface_base_classes(n); + List *methods = collect_interface_methods(n); + bool is_interface = GetFlag(n, "feature:interface") ? true : false; + for (Iterator mi = First(methods); mi.item; mi = Next(mi)) { + if (!is_interface && GetFlag(mi.item, "abstract")) + continue; + String *this_decl = Getattr(mi.item, "decl"); + String *this_decl_resolved = SwigType_typedef_resolve_all(this_decl); + bool identically_overloaded_method = false; // true when a base class' method is implemented in n + if (SwigType_isfunction(this_decl_resolved)) { + String *name = Getattr(mi.item, "name"); + for (Node *child = firstChild(n); child; child = nextSibling(child)) { + if (Getattr(child, "interface:owner")) + break; // at the end of the list are newly appended methods + if (Cmp(nodeType(child), "cdecl") == 0) { + if (checkAttribute(child, "name", name)) { + String *decl = SwigType_typedef_resolve_all(Getattr(child, "decl")); + identically_overloaded_method = Strcmp(decl, this_decl_resolved) == 0; + Delete(decl); + if (identically_overloaded_method) + break; + } + } + } + } + Delete(this_decl_resolved); + if (!identically_overloaded_method) { + // Add method copied from base class to this derived class + Node *cn = mi.item; + Delattr(cn, "sym:overname"); + String *prefix = Getattr(n, "name"); + String *name = Getattr(cn, "name"); + String *decl = Getattr(cn, "decl"); + String *oldname = Getattr(cn, "sym:name"); + + String *symname = Swig_name_make(cn, prefix, name, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + (void)on; + assert(on == cn); + + // Features from the copied base class method are already present, now add in features specific to the added method in the derived class + Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); + Swig_symbol_setscope(oldscope); + appendChild(n, cn); + } + } else { + Delete(mi.item); + } + } + Delete(methods); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_interface_feature_enable() + * + * Turn on interface feature support + * ----------------------------------------------------------------------------- */ + +void Swig_interface_feature_enable() { + interface_feature_enabled = true; +} |