summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile2
-rw-r--r--src/jsapi-libdom-infmap.c338
-rw-r--r--src/jsapi-libdom.c162
-rw-r--r--src/jsapi-libdom.h11
-rw-r--r--src/options.h3
-rw-r--r--test/data/bindings/htmlelement.bnd4
6 files changed, 353 insertions, 167 deletions
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 <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;
+}
+
+/* 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;