From 26e5be085e5c7a17cea4af7cb9e13502ffb0ebd1 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 3 Jan 2014 02:07:11 +0000 Subject: complete implementation of interface map generation and split out to own module --- src/Makefile | 2 +- src/jsapi-libdom-infmap.c | 338 +++++++++++++++++++++++++++++++++++++ src/jsapi-libdom.c | 162 ------------------ src/jsapi-libdom.h | 11 +- src/options.h | 3 +- test/data/bindings/htmlelement.bnd | 4 +- 6 files changed, 353 insertions(+), 167 deletions(-) create mode 100644 src/jsapi-libdom-infmap.c diff --git a/src/Makefile b/src/Makefile index 2f42c4a..6b98bd8 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 webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c +DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c jsapi-libdom-infmap.c SOURCES := $(SOURCES) $(BUILDDIR)/nsgenbind-parser.c $(BUILDDIR)/nsgenbind-lexer.c $(BUILDDIR)/webidl-parser.c $(BUILDDIR)/webidl-lexer.c diff --git a/src/jsapi-libdom-infmap.c b/src/jsapi-libdom-infmap.c new file mode 100644 index 0000000..d02ae65 --- /dev/null +++ b/src/jsapi-libdom-infmap.c @@ -0,0 +1,338 @@ +/* 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 + */ + +#include +#include +#include +#include +#include +#include + +#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; +} + +/* build interface map and return the first interface */ +struct genbind_node * +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 NULL; + } + if (options->verbose) { + printf("Binding has %d interfaces\n", interfacec); + } + + interfaces = calloc(interfacec, sizeof(struct binding_interface)); + if (interfaces == NULL) { + return NULL; + } + + /* 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 NULL; + } + + /* get interface info from webidl */ + if (fill_binding_interface(webidl_ast, interfaces + idx) == -1) { + free(interfaces); + return NULL; + } + + 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 NULL; + } + interfaces = reinterfaces; + + /* setup all fileds 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 NULL; + } + + 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 NULL; + } + interfaces = reinterfaces; + + /* compute inheritance and refcounts on sorted map */ + compute_inherit_refcount(interfaces, interfacec); + + /* 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\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); + } + } + + *interfacec_out = interfacec; + *interfaces_out = interfaces; + + return interfaces[0].node; +} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 547e66e..f011342 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -820,168 +820,6 @@ binding_has_private(struct genbind_node *binding_list) } -/** 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; -} - -/* build interface map and return the first interface */ -static struct genbind_node * -build_interface_map(struct genbind_node *binding_node, - struct webidl_node *webidl_ast, - int *interfacec_out, - struct binding_interface **interfaces_out) -{ - int interfacec; - int idx; - struct binding_interface *interfaces; - struct genbind_node *node = NULL; - - /* 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 NULL; - } - if (options->verbose) { - printf("Binding has %d interfaces\n", interfacec); - } - - interfaces = malloc(interfacec * sizeof(struct binding_interface)); - if (interfaces == NULL) { - return NULL; - } - - /* fill in map with node data */ - for (idx = 0; idx < interfacec; idx++ ) { - node = genbind_node_find_type( - genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); - if (node == NULL) { - free(interfaces); - return NULL; - } - - 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 NULL; - } - - /* get web IDL node for interface */ - interfaces[idx].widl_node = webidl_node_find_type_ident( - webidl_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interfaces[idx].name); - if (interfaces[idx].widl_node == NULL) { - free(interfaces); - return NULL; - } - - /* enumerate the number of functions */ - interfaces[idx].own_functions = enumerate_interface_own( - interfaces[idx].widl_node, - WEBIDL_NODE_TYPE_OPERATION); - - /* enumerate the number of properties */ - interfaces[idx].own_properties = enumerate_interface_own( - interfaces[idx].widl_node, - WEBIDL_NODE_TYPE_ATTRIBUTE); - - /* extract the name of the inherited interface (if any) */ - interfaces[idx].inherit_name = webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(interfaces[idx].widl_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); - - interfaces[idx].refcount = 0; - } - - /* find index of inherited node if it is one of those listed - * in the binding also maintain refcounts - */ - for (idx = 0; idx < interfacec; idx++ ) { - int inf; - interfaces[idx].inherit_idx = -1; - for (inf = 0; inf < interfacec; inf++ ) { - /* cannot inherit from self and name must match */ - if ((inf != idx) && - (strcmp(interfaces[idx].inherit_name, - interfaces[inf].name) == 0)) { - interfaces[idx].inherit_idx = inf; - interfaces[inf].refcount++; - break; - } - } - } - - /** @todo There should be a 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 - */ - - /* 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\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); - } - } - - *interfacec_out = interfacec; - *interfaces_out = interfaces; - - return interfaces[0].node; -} static struct binding * binding_new(struct options *options, diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index ce50589..82258ae 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -16,11 +16,11 @@ struct binding_interface { struct genbind_node *node; /* node of interface in binding */ struct webidl_node *widl_node; /* node of interface in webidl */ const char *inherit_name; /* name of interface this inherits from */ - int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ - int refcount; /* number of entries in map that refer to this interface */ int own_properties; /* the number of properties the interface has */ int own_functions; /* the number of functions the interface has */ + int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ + int refcount; /* number of entries in map that refer to this interface */ }; struct binding { @@ -58,6 +58,13 @@ struct binding { /** Generate binding between jsapi and netsurf libdom */ int jsapi_libdom_output(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node); +/** build interface mapping */ +struct genbind_node * +build_interface_map(struct genbind_node *binding_node, + struct webidl_node *webidl_ast, + int *interfacec_out, + struct binding_interface **interfaces_out); + /** output code block from a node */ void output_code_block(struct binding *binding, struct genbind_node *codelist); diff --git a/src/options.h b/src/options.h index e002a11..cbac9a3 100644 --- a/src/options.h +++ b/src/options.h @@ -34,9 +34,10 @@ extern struct options *options; enum opt_warnings { WARNING_UNIMPLEMENTED = 1, + WARNING_DUPLICATED = 2, }; -#define WARNING_ALL (WARNING_UNIMPLEMENTED) +#define WARNING_ALL (WARNING_UNIMPLEMENTED | WARNING_DUPLICATED) #define WARN(flags, msg, args...) do { \ if ((options->warnings & flags) != 0) { \ diff --git a/test/data/bindings/htmlelement.bnd b/test/data/bindings/htmlelement.bnd index d702147..1457a32 100644 --- a/test/data/bindings/htmlelement.bnd +++ b/test/data/bindings/htmlelement.bnd @@ -37,15 +37,17 @@ preamble %{ binding jsapi_libdom { + interface Text; + interface Comment; interface HTMLElement; interface HTMLAnchorElement; + interface HTMLAnchorElement; interface HTMLAppletElement; interface HTMLAreaElement; interface HTMLBaseElement; interface HTMLBaseFontElement; interface HTMLBodyElement; interface HTMLBRElement; - interface HTMLButtonElement; interface HTMLCanvasElement; interface HTMLCommandElement; -- cgit v1.2.3