diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/interface-map.c | 292 | ||||
-rw-r--r-- | src/interface-map.h | 43 | ||||
-rw-r--r-- | src/jsapi-libdom-infmap.c | 348 | ||||
-rw-r--r-- | src/nsgenbind-ast.h | 2 | ||||
-rw-r--r-- | src/nsgenbind.c | 13 |
6 files changed, 349 insertions, 351 deletions
diff --git a/src/Makefile b/src/Makefile index 3e5b8af..b7b142a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c utils.c webidl-ast.c nsgenbind-ast.c +DIR_SOURCES := nsgenbind.c utils.c webidl-ast.c nsgenbind-ast.c interface-map.c # jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c jsapi-libdom-infmap.c jsapi-libdom-jsclass.c SOURCES := $(SOURCES) $(BUILDDIR)/nsgenbind-parser.c $(BUILDDIR)/nsgenbind-lexer.c $(BUILDDIR)/webidl-parser.c $(BUILDDIR)/webidl-lexer.c diff --git a/src/interface-map.c b/src/interface-map.c new file mode 100644 index 0000000..aef697e --- /dev/null +++ b/src/interface-map.c @@ -0,0 +1,292 @@ +/* interface mapping + * + * 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 "interface-map.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 interface_map_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 interface_map_entry * +interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) +{ + struct interface_map_entry *dstinf; + int idx; + int inf; + + dstinf = calloc(infc, sizeof(struct interface_map_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].operations = srcinf[inf].operations; + dstinf[idx].attributes = srcinf[inf].attributes; + 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; +} + +int interface_map_new(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map **index_out) +{ + int interfacec; + struct interface_map_entry *entries; + struct interface_map_entry *sorted_entries; + struct interface_map_entry *ecur; + struct webidl_node *node; + struct interface_map *index; + + interfacec = webidl_node_enumerate_type(webidl, + WEBIDL_NODE_TYPE_INTERFACE); + + if (options->verbose) { + printf("Indexing %d interfaces\n", interfacec); + } + + entries = calloc(interfacec, sizeof(struct interface_map_entry)); + if (entries == NULL) { + return -1; + } + + /* for each interface populate an entry in the index */ + ecur = entries; + node = webidl_node_find_type(webidl, NULL, WEBIDL_NODE_TYPE_INTERFACE); + while (node != NULL) { + + /* fill index entry */ + ecur->node = node; + + /* name of interface */ + ecur->name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(node), + NULL, + GENBIND_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_INTERFACE_INHERITANCE)); + + + /* enumerate the number of operations */ + ecur->operations = enumerate_interface_type(node, + WEBIDL_NODE_TYPE_OPERATION); + + /* enumerate the number of attributes */ + ecur->attributes = enumerate_interface_type(node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + + /* matching class from binding */ + ecur->class = genbind_node_find_type_ident(genbind, + NULL, GENBIND_NODE_TYPE_CLASS, ecur->name); + + /* 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); + + index = malloc(sizeof(struct interface_map)); + index->entryc = interfacec; + index->entries = sorted_entries; + + *index_out = index; + + return 0; +} + +int interface_map_dump(struct interface_map *index) +{ + FILE *dumpf; + int eidx; + struct interface_map_entry *ecur; + const char *inherit_name; + + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } + + dumpf = genb_fopen("interface-index", "w"); + if (dumpf == NULL) { + return 2; + } + + ecur = index->entries; + for (eidx = 0; eidx < index->entryc; eidx++) { + inherit_name = ecur->inherit_name; + if (inherit_name == NULL) { + inherit_name = ""; + } + fprintf(dumpf, "%d %s %s i:%d a:%d %p\n", eidx, ecur->name, + inherit_name, ecur->operations, ecur->attributes, + ecur->class); + ecur++; + } + + fclose(dumpf); + + return 0; +} + +int interface_map_dumpdot(struct interface_map *index) +{ + FILE *dumpf; + int eidx; + struct interface_map_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"); + + ecur = index->entries; + for (eidx = 0; eidx < index->entryc; eidx++) { + if (ecur->class != NULL) { + /* interfaces bound to a class are shown in blue */ + fprintf(dumpf, "%04d [label=\"%s\" fontcolor=\"blue\"];\n", eidx, ecur->name); + } else { + fprintf(dumpf, "%04d [label=\"%s\"];\n", eidx, ecur->name); + } + ecur++; + } + + ecur = index->entries; + for (eidx = 0; eidx < index->entryc; eidx++) { + if (index->entries[eidx].inherit_idx != -1) { + fprintf(dumpf, "%04d -> %04d;\n", + eidx, index->entries[eidx].inherit_idx); + } + } + + fprintf(dumpf, "}\n"); + + fclose(dumpf); + + return 0; +} diff --git a/src/interface-map.h b/src/interface-map.h new file mode 100644 index 0000000..c9dd654 --- /dev/null +++ b/src/interface-map.h @@ -0,0 +1,43 @@ +/* Interface mapping + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org> + */ + +#ifndef nsgenbind_interface_map_h +#define nsgenbind_interface_map_h + +struct genbind_node; +struct webidl_node; + +struct interface_map_entry { + const char *name; /** interface name */ + struct webidl_node *node; /**< AST interface node */ + const char *inherit_name; /**< Name of interface inhertited from */ + int operations; /**< number of operations on interface */ + int attributes; /**< number of attributes on interface */ + int inherit_idx; /**< index into map of inherited interface or -1 for + * not in map + */ + int refcount; /**< number of interfacess in map that refer to this + * interface + */ + struct genbind_node *class; /**< class from binding (if any) */ +}; + +struct interface_map { + int entryc; /**< count of interfaces */ + struct interface_map_entry *entries; +}; + +int interface_map_new(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map **index_out); + +int interface_map_dump(struct interface_map *index); + +int interface_map_dumpdot(struct interface_map *index); + +#endif diff --git a/src/jsapi-libdom-infmap.c b/src/jsapi-libdom-infmap.c deleted file mode 100644 index 09fce1e..0000000 --- a/src/jsapi-libdom-infmap.c +++ /dev/null @@ -1,348 +0,0 @@ -/* interface map builder - * - * This file is part of nsgenbind. - * Published under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2014 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 "nsgenbind-ast.h" -#include "webidl-ast.h" -#include "jsapi-libdom.h" - -/** count the number of methods or properties for an interface */ -static int -enumerate_interface_own(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; -} - -static int -fill_binding_interface(struct webidl_node *webidl_ast, - struct binding_interface *interface) -{ - /* get web IDL node for interface */ - interface->widl_node = webidl_node_find_type_ident( - webidl_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface->name); - if (interface->widl_node == NULL) { - return -1; - } - - /* enumerate the number of functions */ - interface->own_functions = enumerate_interface_own( - interface->widl_node, - WEBIDL_NODE_TYPE_OPERATION); - - /* enumerate the number of properties */ - interface->own_properties = enumerate_interface_own( - interface->widl_node, - WEBIDL_NODE_TYPE_ATTRIBUTE); - - /* extract the name of the inherited interface (if any) */ - interface->inherit_name = webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(interface->widl_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); - - return 0; -} - -/* find index of inherited node if it is one of those listed in the - * binding also maintain refcounts - */ -static void -compute_inherit_refcount(struct binding_interface *interfaces, - int interfacec) -{ - int idx; - int inf; - - for (idx = 0; idx < interfacec; idx++ ) { - interfaces[idx].inherit_idx = -1; - for (inf = 0; inf < interfacec; inf++ ) { - /* cannot inherit from self and name must match */ - if ((inf != idx) && - (interfaces[idx].inherit_name != NULL ) && - (strcmp(interfaces[idx].inherit_name, - interfaces[inf].name) == 0)) { - interfaces[idx].inherit_idx = inf; - interfaces[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 binding_interface * -interface_topoligical_sort(struct binding_interface *srcinf, int infc) -{ - struct binding_interface *dstinf; - int idx; - int inf; - - dstinf = calloc(infc, sizeof(struct binding_interface)); - 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].widl_node = srcinf[inf].widl_node; - dstinf[idx].inherit_name = srcinf[inf].inherit_name; - dstinf[idx].own_properties = srcinf[inf].own_properties; - dstinf[idx].own_functions = srcinf[inf].own_functions; - - /* 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; -} - -/* exported interface documented in jsapi-libdom.h */ -int build_interface_map(struct genbind_node *binding_node, - struct webidl_node *webidl_ast, - int *interfacec_out, - struct binding_interface **interfaces_out) -{ - int interfacec; - int inf; /* interface loop counter */ - int idx; /* map index counter */ - struct binding_interface *interfaces; - struct genbind_node *node = NULL; - struct binding_interface *reinterfaces; - - /* count number of interfaces listed in binding */ - interfacec = genbind_node_enumerate_type( - genbind_node_getnode(binding_node), - GENBIND_NODE_TYPE_BINDING_INTERFACE); - - if (interfacec == 0) { - return -1; - } - if (options->verbose) { - printf("Binding has %d interfaces\n", interfacec); - } - - interfaces = calloc(interfacec, sizeof(struct binding_interface)); - if (interfaces == NULL) { - return -1; - } - - /* fill in map with binding node data */ - idx = 0; - node = genbind_node_find_type(genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); - while (node != NULL) { - - /* binding node */ - interfaces[idx].node = node; - - /* get interface name */ - interfaces[idx].name = genbind_node_gettext( - genbind_node_find_type(genbind_node_getnode(node), - NULL, - GENBIND_NODE_TYPE_IDENT)); - if (interfaces[idx].name == NULL) { - free(interfaces); - return -1; - } - - /* get interface info from webidl */ - if (fill_binding_interface(webidl_ast, interfaces + idx) == -1) { - free(interfaces); - return -1; - } - - interfaces[idx].refcount = 0; - - /* ensure it is not a duplicate */ - for (inf = 0; inf < idx; inf++) { - if (strcmp(interfaces[inf].name, interfaces[idx].name) == 0) { - break; - } - } - if (inf != idx) { - WARN(WARNING_DUPLICATED, - "interface %s duplicated in binding", - interfaces[idx].name); - } else { - idx++; - } - - /* next node */ - node = genbind_node_find_type( - genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); - } - - /* update count which may have changed if there were duplicates */ - interfacec = idx; - - /* compute inheritance and refcounts on map */ - compute_inherit_refcount(interfaces, interfacec); - - /* the map must be augmented with all the interfaces not in - * the binding but in the dependancy chain - */ - for (idx = 0; idx < interfacec; idx++ ) { - if ((interfaces[idx].inherit_idx == -1) && - (interfaces[idx].inherit_name != NULL)) { - /* interface inherits but not currently in map */ - - /* grow map */ - reinterfaces = realloc(interfaces, - (interfacec + 1) * sizeof(struct binding_interface)); - if (reinterfaces == NULL) { - fprintf(stderr,"Unable to grow interface map\n"); - free(interfaces); - return -1; - } - interfaces = reinterfaces; - - /* setup all fields in new interface */ - - /* this interface is not in the binding and - * will not be exported - */ - interfaces[interfacec].node = NULL; - - interfaces[interfacec].name = interfaces[idx].inherit_name; - - if (fill_binding_interface(webidl_ast, - interfaces + interfacec) == -1) { - fprintf(stderr, - "Interface %s inherits from %s which is not in the WebIDL\n", - interfaces[idx].name, - interfaces[idx].inherit_name); - free(interfaces); - return -1; - } - - interfaces[interfacec].inherit_idx = -1; - interfaces[interfacec].refcount = 0; - - /* update dependancy info and refcount */ - for (inf = 0; inf < interfacec; inf++) { - if (strcmp(interfaces[inf].inherit_name, - interfaces[interfacec].name) == 0) { - interfaces[inf].inherit_idx = interfacec; - interfaces[interfacec].refcount++; - } - } - - /* update interface count in map */ - interfacec++; - - } - } - - /* sort interfaces to ensure correct ordering */ - reinterfaces = interface_topoligical_sort(interfaces, interfacec); - free(interfaces); - if (reinterfaces == NULL) { - return -1; - } - interfaces = reinterfaces; - - /* compute inheritance and refcounts on sorted map */ - compute_inherit_refcount(interfaces, interfacec); - - /* setup output index values */ - inf = 0; - for (idx = 0; idx < interfacec; idx++ ) { - if (interfaces[idx].node == NULL) { - interfaces[idx].output_idx = -1; - } else { - interfaces[idx].output_idx = inf; - inf++; - } - } - - /* show the interface map */ - if (options->verbose) { - for (idx = 0; idx < interfacec; idx++ ) { - printf("interface num:%d\n" - " name:%s node:%p widl:%p\n" - " inherit:%s inherit idx:%d refcount:%d\n" - " own functions:%d own properties:%d output idx:%d\n", - idx, - interfaces[idx].name, - interfaces[idx].node, - interfaces[idx].widl_node, - interfaces[idx].inherit_name, - interfaces[idx].inherit_idx, - interfaces[idx].refcount, - interfaces[idx].own_functions, - interfaces[idx].own_properties, - interfaces[idx].output_idx); - } - } - - *interfacec_out = interfacec; - *interfaces_out = interfaces; - - return 0; -} diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index e7215b1..9c564b9 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -130,7 +130,7 @@ genbind_node_enumerate_type(struct genbind_node *node, enum genbind_node_type type); /** Depth first left hand search returning nodes of the specified type - * and a ident child node with matching text + * with an ident child node with matching text * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 914f58e..18db196 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -14,10 +14,11 @@ #include <getopt.h> #include <errno.h> +#include "options.h" #include "nsgenbind-ast.h" #include "webidl-ast.h" #include "jsapi-libdom.h" -#include "options.h" +#include "interface-map.h" struct options *options; @@ -194,6 +195,7 @@ int main(int argc, char **argv) int res; struct genbind_node *genbind_root = NULL; struct webidl_node *webidl_root = NULL; + struct interface_map *interface_map = NULL; enum bindingtype_e bindingtype; options = process_cmdline(argc, argv); @@ -226,6 +228,15 @@ int main(int argc, char **argv) /* debug dump of web idl AST */ webidl_dump_ast(webidl_root); + /* generate index of interfaces in idl sorted by inheritance */ + res = interface_map_new(genbind_root, webidl_root, &interface_map); + if (res != 0) { + return 5; + } + + /* dump the interface mapping */ + interface_map_dump(interface_map); + interface_map_dumpdot(interface_map); #if 0 /* generate output for each binding */ |