summaryrefslogtreecommitdiff
path: root/src/ir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.c')
-rw-r--r--src/ir.c874
1 files changed, 874 insertions, 0 deletions
diff --git a/src/ir.c b/src/ir.c
new file mode 100644
index 0000000..ab2add7
--- /dev/null
+++ b/src/ir.c
@@ -0,0 +1,874 @@
+/* intermediate representation of WebIDL and binding data
+ *
+ * This file is part of nsgenbind.
+ * Published under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "options.h"
+#include "utils.h"
+#include "nsgenbind-ast.h"
+#include "webidl-ast.h"
+#include "ir.h"
+
+/** count the number of nodes of a given type on an interface */
+static int
+enumerate_interface_type(struct webidl_node *interface_node,
+ enum webidl_node_type node_type)
+{
+ int count = 0;
+ struct webidl_node *members_node;
+
+ members_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+ while (members_node != NULL) {
+ count += webidl_node_enumerate_type(
+ webidl_node_getnode(members_node),
+ node_type);
+
+ members_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ members_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
+
+ return count;
+}
+
+/* find index of inherited node if it is one of those listed in the
+ * binding also maintain refcounts
+ */
+static void
+compute_inherit_refcount(struct ir_interface_entry *entries, int entryc)
+{
+ int idx;
+ int inf;
+
+ for (idx = 0; idx < entryc; idx++ ) {
+ entries[idx].inherit_idx = -1;
+ for (inf = 0; inf < entryc; inf++ ) {
+ /* cannot inherit from self and name must match */
+ if ((inf != idx) &&
+ (entries[idx].inherit_name != NULL ) &&
+ (strcmp(entries[idx].inherit_name,
+ entries[inf].name) == 0)) {
+ entries[idx].inherit_idx = inf;
+ entries[inf].refcount++;
+ break;
+ }
+ }
+ }
+}
+
+/** Topoligical sort based on the refcount
+ *
+ * do not need to consider loops as constructed graph is a acyclic
+ *
+ * alloc a second copy of the map
+ * repeat until all entries copied:
+ * walk source mapping until first entry with zero refcount
+ * put the entry at the end of the output map
+ * reduce refcount on inherit index if !=-1
+ * remove entry from source map
+ */
+static struct ir_interface_entry *
+interface_topoligical_sort(struct ir_interface_entry *srcinf, int infc)
+{
+ struct ir_interface_entry *dstinf;
+ int idx;
+ int inf;
+
+ dstinf = calloc(infc, sizeof(struct ir_interface_entry));
+ if (dstinf == NULL) {
+ return NULL;
+ }
+
+ for (idx = infc - 1; idx >= 0; idx--) {
+ /* walk source map until first valid entry with zero refcount */
+ inf = 0;
+ while ((inf < infc) &&
+ ((srcinf[inf].name == NULL) ||
+ (srcinf[inf].refcount > 0))) {
+ inf++;
+ }
+ if (inf == infc) {
+ free(dstinf);
+ return NULL;
+ }
+
+ /* copy entry to the end of the output map */
+ dstinf[idx].name = srcinf[inf].name;
+ dstinf[idx].node = srcinf[inf].node;
+ dstinf[idx].inherit_name = srcinf[inf].inherit_name;
+ dstinf[idx].noobject = srcinf[inf].noobject;
+ dstinf[idx].primary_global = srcinf[inf].primary_global;
+ dstinf[idx].operationc = srcinf[inf].operationc;
+ dstinf[idx].operationv = srcinf[inf].operationv;
+ dstinf[idx].attributec = srcinf[inf].attributec;
+ dstinf[idx].attributev = srcinf[inf].attributev;
+ dstinf[idx].constantc = srcinf[inf].constantc;
+ dstinf[idx].constantv = srcinf[inf].constantv;
+ dstinf[idx].class = srcinf[inf].class;
+
+ /* reduce refcount on inherit index if !=-1 */
+ if (srcinf[inf].inherit_idx != -1) {
+ srcinf[srcinf[inf].inherit_idx].refcount--;
+ }
+
+ /* remove entry from source map */
+ srcinf[inf].name = NULL;
+ }
+
+ return dstinf;
+}
+
+static struct ir_operation_entry *
+find_operation_name(struct ir_operation_entry *operationv,
+ int operationc,
+ const char *name)
+{
+ struct ir_operation_entry *cure;
+ int opc;
+
+ for (opc = 0; opc < operationc; opc++) {
+ cure = operationv + opc;
+
+ if (cure->name == name) {
+ /* check pointers for equivalence */
+ return cure;
+ } else {
+ if ((cure->name != NULL) &&
+ (name != NULL) &&
+ (strcmp(cure->name, name) == 0)) {
+ return cure;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int
+argument_map_new(struct webidl_node *arg_list_node,
+ int *argumentc_out,
+ struct ir_operation_argument_entry **argumentv_out)
+{
+ int argumentc;
+ struct webidl_node *argument;
+ struct ir_operation_argument_entry *argumentv;
+ struct ir_operation_argument_entry *cure;
+
+ argumentc = webidl_node_enumerate_type(
+ webidl_node_getnode(arg_list_node),
+ WEBIDL_NODE_TYPE_ARGUMENT);
+ if (argumentc == 0) {
+ *argumentc_out = 0;
+ *argumentv_out = NULL;
+ return 0;
+ }
+
+ argumentv = calloc(argumentc, sizeof(*argumentv));
+ cure = argumentv;
+
+ /* iterate each argument node within the list */
+ argument = webidl_node_find_type(webidl_node_getnode(arg_list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_ARGUMENT);
+
+ while (argument != NULL) {
+
+ cure->name = webidl_node_gettext(
+ webidl_node_find_type(
+ webidl_node_getnode(argument),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT));
+
+ cure->node = argument;
+
+
+ cure->optionalc = webidl_node_enumerate_type(
+ webidl_node_getnode(argument),
+ WEBIDL_NODE_TYPE_OPTIONAL);
+
+ cure->elipsisc = webidl_node_enumerate_type(
+ webidl_node_getnode(argument),
+ WEBIDL_NODE_TYPE_ELLIPSIS);
+
+ cure++;
+
+ argument = webidl_node_find_type(
+ webidl_node_getnode(arg_list_node),
+ argument,
+ WEBIDL_NODE_TYPE_ARGUMENT);
+ }
+
+ *argumentc_out = argumentc;
+ *argumentv_out = argumentv;
+
+ return 0;
+}
+
+/**
+ * create a new overloaded parameter set on an operation
+ *
+ * each operation can be overloaded with multiple function signatures. By
+ * adding them to the operation as overloads duplicate operation enrtries is
+ * avoided.
+ */
+static int
+overload_map_new(struct webidl_node *op_node,
+ int *overloadc_out,
+ struct ir_operation_overload_entry **overloadv_out)
+{
+ int overloadc = *overloadc_out;
+ struct ir_operation_overload_entry *overloadv;
+ struct ir_operation_overload_entry *cure;
+ struct webidl_node *arg_list_node;
+ int argc;
+
+ /* update allocation */
+ overloadc++;
+ overloadv = realloc(*overloadv_out, overloadc * sizeof(*overloadv));
+ if (overloadv == NULL) {
+ return -1;
+ }
+
+ /* get added entry */
+ cure = overloadv + (overloadc - 1);
+
+ /* clear entry */
+ cure = memset(cure, 0, sizeof(*cure));
+
+ /* return type */
+ cure->type = webidl_node_find_type(webidl_node_getnode(op_node),
+ NULL,
+ WEBIDL_NODE_TYPE_TYPE);
+
+ arg_list_node = webidl_node_find_type(webidl_node_getnode(op_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+ if (arg_list_node != NULL) {
+ argument_map_new(arg_list_node,
+ &cure->argumentc,
+ &cure->argumentv);
+ }
+
+ for (argc = 0; argc < cure->argumentc; argc++) {
+ struct ir_operation_argument_entry *arge;
+ arge = cure->argumentv + argc;
+ cure->optionalc += arge->optionalc;
+ cure->elipsisc += arge->elipsisc;
+ }
+
+ /* return entry list */
+ *overloadc_out = overloadc;
+ *overloadv_out = overloadv;
+
+ return 0;
+}
+
+static int
+operation_map_new(struct webidl_node *interface,
+ struct genbind_node *class,
+ int *operationc_out,
+ struct ir_operation_entry **operationv_out)
+{
+ struct webidl_node *list_node;
+ struct webidl_node *op_node; /* attribute node */
+ struct ir_operation_entry *cure; /* current entry */
+ struct ir_operation_entry *operationv;
+ int operationc;
+
+ /* enumerate operationss including overloaded members */
+ operationc = enumerate_interface_type(interface,
+ WEBIDL_NODE_TYPE_OPERATION);
+
+ if (operationc < 1) {
+ /* no operations so empty map */
+ *operationc_out = 0;
+ *operationv_out = NULL;
+ return 0;
+ }
+
+ operationv = calloc(operationc,
+ sizeof(struct ir_operation_entry));
+ if (operationv == NULL) {
+ return -1;
+ };
+ cure = operationv;
+
+ /* iterate each list node within the interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(interface),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through operations on list */
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_OPERATION);
+
+ while (op_node != NULL) {
+ const char *operation_name;
+ struct ir_operation_entry *finde;
+
+ /* get operation name */
+ operation_name = webidl_node_gettext(
+ webidl_node_find_type(
+ webidl_node_getnode(op_node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT));
+ /* if this operation is already an entry in the list
+ * augment that entry else create a new one
+ */
+ finde = find_operation_name(operationv,
+ operationc,
+ operation_name);
+ if (finde == NULL) {
+ /* operation does not already exist in list */
+
+ cure->name = operation_name;
+
+ cure->node = op_node;
+
+ cure->method = genbind_node_find_method_ident(
+ class,
+ NULL,
+ GENBIND_METHOD_TYPE_METHOD,
+ cure->name);
+
+ overload_map_new(op_node,
+ &cure->overloadc,
+ &cure->overloadv);
+
+ cure++; /* advance to next entry */
+ } else {
+ overload_map_new(op_node,
+ &finde->overloadc,
+ &finde->overloadv);
+ /* Overloaded entry does not advance the
+ * current entry but does reduce list
+ * length. Do not bother shortening allocation.
+ */
+ operationc--;
+ }
+
+ /* move to next operation */
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ op_node,
+ WEBIDL_NODE_TYPE_OPERATION);
+ }
+
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(interface),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
+
+ *operationc_out = operationc;
+ *operationv_out = operationv; /* resulting operations map */
+
+ return 0;
+}
+
+static int
+attribute_map_new(struct webidl_node *interface,
+ struct genbind_node *class,
+ int *attributec_out,
+ struct ir_attribute_entry **attributev_out)
+{
+ struct webidl_node *list_node;
+ struct webidl_node *at_node; /* attribute node */
+ struct ir_attribute_entry *cure; /* current entry */
+ struct ir_attribute_entry *attributev;
+ int attributec;
+
+ /* enumerate attributes */
+ attributec = enumerate_interface_type(interface,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+ *attributec_out = attributec;
+
+ if (attributec < 1) {
+ *attributev_out = NULL; /* no attributes so empty map */
+ return 0;
+ }
+
+ attributev = calloc(attributec,
+ sizeof(struct ir_attribute_entry));
+ if (attributev == NULL) {
+ return -1;
+ };
+ cure = attributev;
+
+ /* iterate each list node within the interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(interface),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through attributes on list */
+ at_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+
+ while (at_node != NULL) {
+ enum webidl_type_modifier *modifier;
+
+ cure->node = at_node;
+
+ cure->name = webidl_node_gettext(
+ webidl_node_find_type(
+ webidl_node_getnode(at_node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT));
+
+ cure->getter = genbind_node_find_method_ident(
+ class,
+ NULL,
+ GENBIND_METHOD_TYPE_GETTER,
+ cure->name);
+
+ /* check fo readonly attributes */
+ modifier = (enum webidl_type_modifier *)webidl_node_getint(
+ webidl_node_find_type(
+ webidl_node_getnode(at_node),
+ NULL,
+ WEBIDL_NODE_TYPE_MODIFIER));
+ if ((modifier != NULL) &&
+ (*modifier == WEBIDL_TYPE_MODIFIER_READONLY)) {
+ cure->modifier = WEBIDL_TYPE_MODIFIER_READONLY;
+ } else {
+ cure->modifier = WEBIDL_TYPE_MODIFIER_NONE;
+ cure->setter = genbind_node_find_method_ident(
+ class,
+ NULL,
+ GENBIND_METHOD_TYPE_SETTER,
+ cure->name);
+ }
+
+ cure++;
+
+ /* move to next attribute */
+ at_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ at_node,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+ }
+
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(interface),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
+
+ *attributev_out = attributev; /* resulting attributes map */
+
+ return 0;
+}
+
+static int
+constant_map_new(struct webidl_node *interface,
+ int *constantc_out,
+ struct ir_constant_entry **constantv_out)
+{
+ struct webidl_node *list_node;
+ struct webidl_node *constant_node; /* constant node */
+ struct ir_constant_entry *cure; /* current entry */
+ struct ir_constant_entry *constantv;
+ int constantc;
+
+ /* enumerate constants */
+ constantc = enumerate_interface_type(interface,
+ WEBIDL_NODE_TYPE_CONST);
+
+ if (constantc < 1) {
+ *constantc_out = 0;
+ *constantv_out = NULL; /* no constants so empty map */
+ return 0;
+ }
+
+ *constantc_out = constantc;
+
+ constantv = calloc(constantc,
+ sizeof(struct ir_constant_entry));
+ if (constantv == NULL) {
+ return -1;
+ };
+ cure = constantv;
+
+ /* iterate each list node within the interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(interface),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through constants on list */
+ constant_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_CONST);
+
+ while (constant_node != NULL) {
+ cure->node = constant_node;
+
+ cure->name = webidl_node_gettext(
+ webidl_node_find_type(
+ webidl_node_getnode(constant_node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT));
+
+ cure++;
+
+ /* move to next constant */
+ constant_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ constant_node,
+ WEBIDL_NODE_TYPE_CONST);
+ }
+
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(interface),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
+
+ *constantv_out = constantv; /* resulting constants map */
+
+ return 0;
+}
+
+int ir_new(struct genbind_node *genbind,
+ struct webidl_node *webidl,
+ struct ir **map_out)
+{
+ int interfacec;
+ struct ir_interface_entry *entries;
+ struct ir_interface_entry *sorted_entries;
+ struct ir_interface_entry *ecur;
+ struct webidl_node *node;
+ struct ir *map;
+
+ interfacec = webidl_node_enumerate_type(webidl,
+ WEBIDL_NODE_TYPE_INTERFACE);
+
+ if (options->verbose) {
+ printf("Mapping %d interfaces\n", interfacec);
+ }
+
+ entries = calloc(interfacec, sizeof(struct ir_interface_entry));
+ if (entries == NULL) {
+ return -1;
+ }
+
+ /* for each interface populate an entry in the map */
+ ecur = entries;
+ node = webidl_node_find_type(webidl, NULL, WEBIDL_NODE_TYPE_INTERFACE);
+ while (node != NULL) {
+
+ /* fill map entry */
+ ecur->node = node;
+
+ /* name of interface */
+ ecur->name = webidl_node_gettext(
+ webidl_node_find_type(
+ webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT));
+
+ /* name of the inherited interface (if any) */
+ ecur->inherit_name = webidl_node_gettext(
+ webidl_node_find_type(
+ webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_INHERITANCE));
+
+ /* is the interface marked as not generating an object */
+ if (webidl_node_find_type_ident(
+ webidl_node_getnode(node),
+ WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE,
+ "NoInterfaceObject") != NULL) {
+ /** \todo we should ensure inherit is unset as this
+ * cannot form part of an inheritance chain if it is
+ * not generating an output class
+ */
+ ecur->noobject = true;
+ }
+
+ /* is the interface marked as the primary global */
+ if (webidl_node_find_type_ident(
+ webidl_node_getnode(node),
+ WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE,
+ "PrimaryGlobal") != NULL) {
+ /** \todo we should ensure nothing inherits *from* this
+ * class or all hell will break loose having two
+ * primary globals.
+ */
+ ecur->primary_global = true;
+ }
+
+ /* matching class from binding */
+ ecur->class = genbind_node_find_type_ident(genbind,
+ NULL, GENBIND_NODE_TYPE_CLASS, ecur->name);
+
+ /* enumerate and map the interface operations */
+ operation_map_new(node,
+ ecur->class,
+ &ecur->operationc,
+ &ecur->operationv);
+
+ /* enumerate and map the interface attributes */
+ attribute_map_new(node,
+ ecur->class,
+ &ecur->attributec,
+ &ecur->attributev);
+
+ /* enumerate and map the interface constants */
+ constant_map_new(node,
+ &ecur->constantc,
+ &ecur->constantv);
+
+ /* move to next interface */
+ node = webidl_node_find_type(webidl, node,
+ WEBIDL_NODE_TYPE_INTERFACE);
+ ecur++;
+ }
+
+ /* compute inheritance and refcounts on map */
+ compute_inherit_refcount(entries, interfacec);
+
+ /* sort interfaces to ensure correct ordering */
+ sorted_entries = interface_topoligical_sort(entries, interfacec);
+ free(entries);
+ if (sorted_entries == NULL) {
+ return -1;
+ }
+
+ /* compute inheritance and refcounts on sorted map */
+ compute_inherit_refcount(sorted_entries, interfacec);
+
+ map = malloc(sizeof(struct ir));
+ map->interfacec = interfacec;
+ map->interfaces = sorted_entries;
+ map->webidl = webidl;
+ map->binding_node = genbind_node_find_type(genbind, NULL,
+ GENBIND_NODE_TYPE_BINDING);
+
+ *map_out = map;
+
+ return 0;
+}
+
+int ir_dump(struct ir *index)
+{
+ FILE *dumpf;
+ int eidx;
+ struct ir_interface_entry *ecur;
+
+ /* only dump AST to file if required */
+ if (!options->debug) {
+ return 0;
+ }
+
+ dumpf = genb_fopen("interface-map", "w");
+ if (dumpf == NULL) {
+ return 2;
+ }
+
+ ecur = index->interfaces;
+ for (eidx = 0; eidx < index->interfacec; eidx++) {
+ fprintf(dumpf, "%d %s\n", eidx, ecur->name);
+ if (ecur->inherit_name != NULL) {
+ fprintf(dumpf, "\tinherit:%s\n", ecur->inherit_name);
+ }
+ if (ecur->class != NULL) {
+ fprintf(dumpf, "\tclass:%p\n", ecur->class);
+ }
+
+ if (ecur->operationc > 0) {
+ int opc;
+
+ fprintf(dumpf, "\t%d operations\n",
+ ecur->operationc);
+
+ for (opc = 0; opc < ecur->operationc; opc++) {
+ int ovlc;
+ struct ir_operation_entry *ope;
+
+ ope = ecur->operationv + opc;
+
+ fprintf(dumpf,
+ "\t\t%s\n",
+ ope->name);
+ fprintf(dumpf,
+ "\t\t\tmethod:%p\n",
+ ope->method);
+ for(ovlc = 0; ovlc < ope->overloadc;ovlc++) {
+ int argc;
+ struct ir_operation_overload_entry *ovle;
+ ovle = ope->overloadv + ovlc;
+
+ fprintf(dumpf,
+ "\t\t\toverload:%d\n", ovlc);
+
+ fprintf(dumpf,
+ "\t\t\t\treturn type:%p\n",
+ ovle->type);
+
+ fprintf(dumpf,
+ "\t\t\t\targuments:%d\n",
+ ovle->argumentc);
+
+ fprintf(dumpf,
+ "\t\t\t\toptionals:%d\n",
+ ovle->optionalc);
+
+ fprintf(dumpf,
+ "\t\t\t\telipsis:%d\n",
+ ovle->elipsisc);
+
+ for (argc = 0; argc < ovle->argumentc; argc++) {
+ struct ir_operation_argument_entry *arge;
+ arge = ovle->argumentv + argc;
+
+ fprintf(dumpf,
+ "\t\t\t\t\t%s\n",
+ arge->name);
+
+ if (arge->optionalc != 0) {
+ fprintf(dumpf,
+ "\t\t\t\t\t\toptional:%d\n",
+ arge->optionalc);
+ }
+
+ if (arge->elipsisc != 0) {
+ fprintf(dumpf,
+ "\t\t\t\t\t\telipsis:%d\n",
+ arge->elipsisc);
+ }
+
+ }
+ }
+ }
+ }
+
+ if (ecur->attributec > 0) {
+ int attrc = ecur->attributec;
+ struct ir_attribute_entry *attre;
+
+ fprintf(dumpf, "\t%d attributes\n", attrc);
+
+ attre = ecur->attributev;
+ while (attre != NULL) {
+ fprintf(dumpf, "\t\t%s %p",
+ attre->name,
+ attre->getter);
+ if (attre->modifier == WEBIDL_TYPE_MODIFIER_NONE) {
+ fprintf(dumpf, " %p\n", attre->setter);
+ } else {
+ fprintf(dumpf, "\n");
+ }
+ attre++;
+ attrc--;
+ if (attrc == 0) {
+ break;
+ }
+ }
+ }
+ if (ecur->constantc > 0) {
+ int idx;
+
+ fprintf(dumpf, "\t%d constants\n",
+ ecur->constantc);
+
+ for (idx = 0; idx < ecur->constantc; idx++) {
+ struct ir_constant_entry *cone;
+ cone = ecur->constantv + idx;
+ fprintf(dumpf, "\t\t%s\n",
+ cone->name);
+ }
+ }
+ ecur++;
+ }
+
+ fclose(dumpf);
+
+ return 0;
+}
+
+int ir_dumpdot(struct ir *index)
+{
+ FILE *dumpf;
+ int eidx;
+ struct ir_interface_entry *ecur;
+
+ /* only dump AST to file if required */
+ if (!options->debug) {
+ return 0;
+ }
+
+ dumpf = genb_fopen("interface.dot", "w");
+ if (dumpf == NULL) {
+ return 2;
+ }
+
+ fprintf(dumpf, "digraph interfaces {\n");
+
+ fprintf(dumpf, "node [shape=box]\n");
+
+ ecur = index->interfaces;
+ for (eidx = 0; eidx < index->interfacec; eidx++) {
+ fprintf(dumpf, "%04d [label=\"%s\"", eidx, ecur->name);
+ if (ecur->noobject == true) {
+ /* noobject interfaces in red */
+ fprintf(dumpf, "fontcolor=\"red\"");
+ } else if (ecur->class != NULL) {
+ /* interfaces bound to a class are shown in blue */
+ fprintf(dumpf, "fontcolor=\"blue\"");
+ }
+ fprintf(dumpf, "];\n");
+ ecur++;
+ }
+
+ ecur = index->interfaces;
+ for (eidx = 0; eidx < index->interfacec; eidx++) {
+ if (index->interfaces[eidx].inherit_idx != -1) {
+ fprintf(dumpf, "%04d -> %04d;\n",
+ eidx, index->interfaces[eidx].inherit_idx);
+ }
+ }
+
+ fprintf(dumpf, "}\n");
+
+ fclose(dumpf);
+
+ return 0;
+}
+
+struct ir_interface_entry *
+ir_inherit_entry(struct ir *map,
+ struct ir_interface_entry *entry)
+{
+ struct ir_interface_entry *res = NULL;
+
+ if ((entry != NULL) &&
+ (entry->inherit_idx != -1)) {
+ res = &map->interfaces[entry->inherit_idx];
+ }
+ return res;
+}