summaryrefslogtreecommitdiffstats
path: root/contrib/tools/swig/Source/Modules/interface.cxx
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-08-28 14:27:58 +0300
committerrobot-piglet <[email protected]>2025-08-28 14:57:06 +0300
commit81d828c32c8d5477cb2f0ce5da06a1a8d9392ca3 (patch)
tree3081d566f0d5158d76e9093261344f6406fd09f7 /contrib/tools/swig/Source/Modules/interface.cxx
parent77ea11423f959e51795cc3ef36a48d808b4ffb98 (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.cxx210
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;
+}