summaryrefslogtreecommitdiff
path: root/src/ir.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2015-08-17 19:12:51 +0200
committerVincent Sanders <vince@kyllikki.org>2015-08-17 19:12:51 +0200
commite8d19a2821bfd15bcbe8d17f6564439c1673cbf7 (patch)
tree4ee0523aabdf146967a12761c5050bd74bba917c /src/ir.c
parent40cd6a199d8a5f92f71c5638f4da021a779e7a5c (diff)
downloadnsgenbind-e8d19a2821bfd15bcbe8d17f6564439c1673cbf7.tar.gz
nsgenbind-e8d19a2821bfd15bcbe8d17f6564439c1673cbf7.tar.bz2
rename interface map to be intermediate representation
The interface map is now completely inapropriately named and is in fact now an intermediate representation of the webidl and bindings kept in a sorted order.
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;
+}