summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2013-12-29 15:25:39 +0000
committerVincent Sanders <vince@kyllikki.org>2014-05-16 14:38:56 +0100
commit0c9803cf78453a19ec37fbc2b3fdba3c106cfd84 (patch)
tree7c16ce916986e137c15634fdf6fd9ace120e0d31
parentc25cc0e348a1abf0ee0719cf30515b3cc07f1848 (diff)
downloadnsgenbind-0c9803cf78453a19ec37fbc2b3fdba3c106cfd84.tar.gz
nsgenbind-0c9803cf78453a19ec37fbc2b3fdba3c106cfd84.tar.bz2
construct topoligicaly consitant (dependancy correct) interface map
use dependancy map to generate javascript prototype for all interfaces in the binding.
-rw-r--r--src/Makefile2
-rw-r--r--src/jsapi-libdom-init.c (renamed from src/jsapi-libdom-const.c)219
-rw-r--r--src/jsapi-libdom.c240
-rw-r--r--src/jsapi-libdom.h26
-rw-r--r--src/nsgenbind-ast.c21
-rw-r--r--src/nsgenbind-ast.h15
6 files changed, 394 insertions, 129 deletions
diff --git a/src/Makefile b/src/Makefile
index 972beb9..8bad59a 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-operator.c jsapi-libdom-property.c jsapi-libdom-const.c
+DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-operator.c jsapi-libdom-property.c jsapi-libdom-init.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-const.c b/src/jsapi-libdom-init.c
index ac728c7..1f6b80d 100644
--- a/src/jsapi-libdom-const.c
+++ b/src/jsapi-libdom-init.c
@@ -11,12 +11,15 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <assert.h>
#include "options.h"
#include "nsgenbind-ast.h"
#include "webidl-ast.h"
#include "jsapi-libdom.h"
+static int output_const_defines(struct binding *binding, const char *interface);
+
static int output_cast_literal(struct binding *binding,
struct webidl_node *node)
{
@@ -106,25 +109,55 @@ static int webidl_const_define_cb(struct webidl_node *node, void *ctx)
}
fprintf(binding->outfile,
- "\tJS_DefineProperty(cx,\n"
- "\t\tprototype,\n"
- "\t\t\"%s\",\n"
- "\t\t",
+ "\tJS_DefineProperty(cx, "
+ "prototype, "
+ "\"%s\", ",
webidl_node_gettext(ident_node));
output_cast_literal(binding, node);
fprintf(binding->outfile,
- ",\n"
- "\t\tJS_PropertyStub,\n"
- "\t\tJS_StrictPropertyStub,\n"
- "\t\tJSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);\n\n");
+ ", "
+ "JS_PropertyStub, "
+ "JS_StrictPropertyStub, "
+ "JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);\n\n");
return 0;
}
+/** output all the constant property defines for an interface */
+static int
+output_interface_consts(struct binding *binding,
+ struct webidl_node *interface_node)
+{
+ struct webidl_node *members_node;
+
+ /* generate property entries for each list (partial interfaces) */
+ members_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (members_node != NULL) {
+
+ /* for each const emit a property define */
+ webidl_node_for_each_type(webidl_node_getnode(members_node),
+ WEBIDL_NODE_TYPE_CONST,
+ webidl_const_define_cb,
+ binding);
+
+
+ members_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ members_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
+
+ return 0;
+}
+
/* callback to emit implements property spec */
static int webidl_const_spec_implements_cb(struct webidl_node *node, void *ctx)
{
@@ -133,11 +166,11 @@ static int webidl_const_spec_implements_cb(struct webidl_node *node, void *ctx)
return output_const_defines(binding, webidl_node_gettext(node));
}
-int
+/** generate property definitions for constants */
+static int
output_const_defines(struct binding *binding, const char *interface)
{
struct webidl_node *interface_node;
- struct webidl_node *members_node;
struct webidl_node *inherit_node;
int res = 0;
@@ -153,43 +186,157 @@ output_const_defines(struct binding *binding, const char *interface)
return -1;
}
- /* generate property entries for each list (partial interfaces) */
- members_node = webidl_node_find_type(webidl_node_getnode(interface_node),
- NULL,
- WEBIDL_NODE_TYPE_LIST);
-
- while (members_node != NULL) {
- fprintf(binding->outfile,"\t/**** %s ****/\n", interface);
-
- /* for each const emit a property define */
- webidl_node_for_each_type(webidl_node_getnode(members_node),
- WEBIDL_NODE_TYPE_CONST,
- webidl_const_define_cb,
- binding);
+ fprintf(binding->outfile, "\t/**** %s ****/\n", interface);
+ /* write the property defines for this interface */
+ res = output_interface_consts(binding, interface_node);
- members_node = webidl_node_find_type(webidl_node_getnode(interface_node),
- members_node,
- WEBIDL_NODE_TYPE_LIST);
- }
/* check for inherited nodes and insert them too */
- inherit_node = webidl_node_find(webidl_node_getnode(interface_node),
- NULL,
- webidl_cmp_node_type,
- (void *)WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE);
+ inherit_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ NULL,
+ WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE);
if (inherit_node != NULL) {
res = output_const_defines(binding,
- webidl_node_gettext(inherit_node));
+ webidl_node_gettext(inherit_node));
}
if (res == 0) {
- res = webidl_node_for_each_type(webidl_node_getnode(interface_node),
- WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS,
- webidl_const_spec_implements_cb,
- binding);
+ res = webidl_node_for_each_type(
+ webidl_node_getnode(interface_node),
+ WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS,
+ webidl_const_spec_implements_cb,
+ binding);
+ }
+
+ return res;
+}
+
+/** generate class initialisers
+ *
+ * Generates function to create the javascript class prototypes for
+ * each interface in the binding.
+ *
+ */
+int output_class_init(struct binding *binding)
+{
+ int res = 0;
+ struct genbind_node *api_node;
+ int inf;
+
+ /* class Initialisor declaration */
+ if (binding->hdrfile) {
+
+ if (binding->interfacec > 1) {
+ fprintf(binding->hdrfile,
+ "\n#define %s_INTERFACE_COUNT %d",
+ binding->name,
+ binding->interfacec);
+ }
+
+ fprintf(binding->hdrfile,
+ "\nint jsapi_InitClass_%s(JSContext *cx, JSObject *parent, JSObject **prototypes);\n\n",
+ binding->name);
+
+
}
+ /* class Initialisor definition */
+ fprintf(binding->outfile,
+ "int\n"
+ "jsapi_InitClass_%s(JSContext *cx, "
+ "JSObject *parent, "
+ "JSObject **prototypes)\n"
+ "{\n"
+ "\tJSObject *prototype;\n",
+ binding->name);
+
+ /* check for the binding having an init override */
+ api_node = genbind_node_find_type_ident(binding->gb_ast,
+ NULL,
+ GENBIND_NODE_TYPE_API,
+ "init");
+
+ if (api_node != NULL) {
+ output_code_block(binding, genbind_node_getnode(api_node));
+ } else {
+ for (inf = 0; inf < binding->interfacec; inf++) {
+
+ fprintf(binding->outfile,
+ "\n"
+ "\tprototype = JS_InitClass(cx, "
+ "parent, ");
+
+ if (binding->interfaces[inf].inherit_idx == -1) {
+ /* interface does not get its
+ * prototypes from another interface
+ * we are generating
+ */
+ fprintf(binding->outfile,
+ "NULL, "
+ "&JSClass_%s, "
+ "NULL, "
+ "0, "
+ "NULL, "
+ "NULL, "
+ "NULL, "
+ "NULL);\n",
+ binding->interfaces[inf].name);
+
+ fprintf(binding->outfile,
+ "\tif (prototype == NULL) {\n"
+ "\t\treturn %d;\n"
+ "\t}\n\n",
+ inf);
+
+ fprintf(binding->outfile,
+ "\tprototypes[%d] = prototype;\n",
+ inf);
+
+ output_const_defines(binding,
+ binding->interfaces[inf].name);
+
+ } else {
+ /* interface prototype is based on one
+ * we already generated (interface map
+ * is topologicaly sorted */
+ assert(binding->interfaces[inf].inherit_idx < inf);
+
+ fprintf(binding->outfile,
+ "prototypes[%d], "
+ "&JSClass_%s, "
+ "NULL, "
+ "0, "
+ "NULL, "
+ "NULL, "
+ "NULL, "
+ "NULL);\n",
+ binding->interfaces[inf].inherit_idx,
+ binding->interfaces[inf].name);
+
+ fprintf(binding->outfile,
+ "\tif (prototype == NULL) {\n"
+ "\t\treturn %d;\n"
+ "\t}\n\n",
+ inf);
+
+ fprintf(binding->outfile,
+ "\tprototypes[%d] = prototype;\n",
+ inf);
+
+ output_interface_consts(binding,
+ binding->interfaces[inf].widl_node);
+
+ }
+ }
+ fprintf(binding->outfile,
+ "\n\treturn %d;\n",
+ inf);
+ }
+
+ fprintf(binding->outfile, "}\n\n");
+
return res;
}
diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c
index f0dc5a3..de82678 100644
--- a/src/jsapi-libdom.c
+++ b/src/jsapi-libdom.c
@@ -531,62 +531,6 @@ output_code_block(struct binding *binding, struct genbind_node *codelist)
}
}
-/** generate class initialiser which create the javascript class prototype */
-static int
-output_class_init(struct binding *binding)
-{
- int res = 0;
- struct genbind_node *api_node;
-
- /* class Initialisor declaration */
- if (binding->hdrfile) {
- binding->outfile = binding->hdrfile;
-
- fprintf(binding->outfile,
- "JSObject *jsapi_InitClass_%s(JSContext *cx, JSObject *parent);\n",
- binding->interface);
-
- binding->outfile = binding->srcfile;
- }
-
- /* class Initialisor definition */
- fprintf(binding->outfile,
- "JSObject *jsapi_InitClass_%s(JSContext *cx, JSObject *parent)\n"
- "{\n"
- "\tJSObject *prototype;\n",
- binding->interface);
-
- api_node = genbind_node_find_type_ident(binding->gb_ast,
- NULL,
- GENBIND_NODE_TYPE_API,
- "init");
-
- if (api_node != NULL) {
- output_code_block(binding, genbind_node_getnode(api_node));
- } else {
- fprintf(binding->outfile,
- "\n"
- "\tprototype = JS_InitClass(cx,\n"
- "\t\tparent,\n"
- "\t\tNULL,\n"
- "\t\t&JSClass_%s,\n"
- "\t\tNULL,\n"
- "\t\t0,\n"
- "\t\tNULL,\n"
- "\t\tNULL, \n"
- "\t\tNULL, \n"
- "\t\tNULL);\n",
- binding->interface);
- }
-
- output_const_defines(binding, binding->interface);
-
- fprintf(binding->outfile,
- "\treturn prototype;\n"
- "}\n\n");
-
- return res;
-}
static int
output_class_new(struct binding *binding)
@@ -1061,47 +1005,158 @@ binding_has_private(struct genbind_node *binding_list)
return false;
}
+/* 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;
+ }
+
+ 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 name:%s node:%p widl:%p inherit:%s inherit idx:%d refcount:%d\n",
+ idx,
+ interfaces[idx].name,
+ interfaces[idx].node,
+ interfaces[idx].widl_node,
+ interfaces[idx].inherit_name,
+ interfaces[idx].inherit_idx,
+ interfaces[idx].refcount);
+ }
+ }
+
+ *interfacec_out = interfacec;
+ *interfaces_out = interfaces;
+
+ return interfaces[0].node;
+}
+
static struct binding *
binding_new(struct options *options,
struct genbind_node *genbind_ast,
struct genbind_node *binding_node)
{
struct binding *nb;
+
+ int interfacec; /* numer of interfaces in the interface map */
+ struct binding_interface *interfaces; /* binding interface map */
+
struct genbind_node *interface_node;
struct genbind_node *binding_list;
- struct genbind_node *binding_ident;
char *hdrguard = NULL;
struct webidl_node *webidl_ast = NULL;
int res;
- binding_list = genbind_node_getnode(binding_node);
- if (binding_list == NULL) {
+ /* walk AST and load any web IDL files required */
+ res = read_webidl(genbind_ast, &webidl_ast);
+ if (res != 0) {
+ fprintf(stderr, "Error: failed reading Web IDL\n");
return NULL;
}
- /* find the first interface node - there must be at least one */
- interface_node = genbind_node_find_type(binding_list,
- NULL,
- GENBIND_NODE_TYPE_BINDING_INTERFACE);
+ /* build the bindings interface (class) name map */
+ interface_node = build_interface_map(binding_node,
+ webidl_ast,
+ &interfacec,
+ &interfaces);
if (interface_node == NULL) {
- return NULL;
- }
-
- /* get the binding identifier */
- /* @todo it should be possible to specify this as part of the
- * binding instead of just using the first interface
- */
- binding_ident = genbind_node_find_type(genbind_node_getnode(interface_node),
- NULL,
- GENBIND_NODE_TYPE_IDENT);
- if (binding_ident == NULL) {
- return NULL;
- }
-
- /* walk AST and load any web IDL files required */
- res = read_webidl(genbind_ast, &webidl_ast);
- if (res != 0) {
- fprintf(stderr, "Error reading Web IDL files\n");
+ /* the binding must have at least one interface */
+ fprintf(stderr, "Error: Binding must have a valid interface\n");
return NULL;
}
@@ -1121,18 +1176,35 @@ binding_new(struct options *options,
}
}
+ binding_list = genbind_node_getnode(binding_node);
+ if (binding_list == NULL) {
+ return NULL;
+ }
+
nb = calloc(1, sizeof(struct binding));
nb->gb_ast = genbind_ast;
nb->wi_ast = webidl_ast;
- /* @todo binding name should not be called interface */
- nb->interface = genbind_node_gettext(binding_ident);
+
+ /* keep the binding list node */
+ nb->binding_list = binding_list;
+
+ /* store the interface mapping */
+ nb->interfaces = interfaces;
+ nb->interfacec = interfacec;
+
+ /* @todo it should be possible to specify the binding name
+ * instead of just using the name of the first interface.
+ *
+ * @todo get rid of the interface element out of the binding
+ * struct and use the interface map instead.
+ */
+ nb->name = nb->interface = interfaces[0].name;
nb->outfile = options->outfilehandle;
nb->srcfile = options->outfilehandle;
nb->hdrfile = options->hdrfilehandle;
nb->hdrguard = hdrguard;
nb->has_private = binding_has_private(binding_list);
- nb->binding_list = binding_list;
/* class API */
nb->addproperty = genbind_node_find_type_ident(genbind_ast,
diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h
index b83eeb0..ee1b2f9 100644
--- a/src/jsapi-libdom.h
+++ b/src/jsapi-libdom.h
@@ -11,10 +11,23 @@
struct options;
+struct binding_interface {
+ const char *name; /* name of 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 */
+};
+
struct binding {
struct genbind_node *gb_ast; /* root node of binding AST */
struct webidl_node *wi_ast; /* root node of webidl AST */
+ const char *name; /* Name of binding (first interface name by default) */
+ int interfacec; /* numer of interfaces in the interface map */
+ struct binding_interface *interfaces; /* binding interface map */
+
const char *interface; /* webidl interface binding is for */
bool has_private; /* true if the binding requires a private structure */
@@ -33,7 +46,7 @@ struct binding {
FILE *outfile ; /* file handle output should be written to,
* allows reuse of callback routines to output
- * to headers and source files
+ * to headers and source files
*/
FILE *srcfile ; /* output source file */
FILE *hdrfile ; /* output header file */
@@ -55,17 +68,16 @@ int output_function_spec(struct binding *binding);
*
* This walks the web IDL AST to find all operator interface members
* and construct appropriate jsapi native function body to implement
- * them.
+ * them.
*
* Function body contents can be overriden with an operator code
* block in the binding definition.
*
- * @param binding The binding information
+ * @param binding The binding information
* @param interface The interface to generate operator bodys for
*/
int output_operator_body(struct binding *binding, const char *interface);
-
/** generate property tinyid enum */
int output_property_tinyid(struct binding *binding);
@@ -75,10 +87,8 @@ int output_property_spec(struct binding *binding);
/** generate property function bodies */
int output_property_body(struct binding *binding);
-/** generate property definitions for constants */
-int output_const_defines(struct binding *binding, const char *interface);
-
-
+/** generate binding initialisation */
+int output_class_init(struct binding *binding);
#endif
diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c
index fc1e196..2f630b7 100644
--- a/src/nsgenbind-ast.c
+++ b/src/nsgenbind-ast.c
@@ -68,6 +68,8 @@ genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r)
return nn;
}
+
+/* exported interface defined in nsgenbind-ast.h */
int
genbind_node_foreach_type(struct genbind_node *node,
enum genbind_node_type type,
@@ -92,6 +94,25 @@ genbind_node_foreach_type(struct genbind_node *node,
return 0;
}
+static int genbind_enumerate_node(struct genbind_node *node, void *ctx)
+{
+ node = node;
+ (*((int *)ctx))++;
+ return 0;
+}
+
+/* exported interface defined in nsgenbind-ast.h */
+int
+genbind_node_enumerate_type(struct genbind_node *node,
+ enum genbind_node_type type)
+{
+ int count = 0;
+ genbind_node_foreach_type(node,
+ type,
+ genbind_enumerate_node,
+ &count);
+ return count;
+}
/* exported interface defined in nsgenbind-ast.h */
struct genbind_node *
diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h
index 128dce7..4911f5a 100644
--- a/src/nsgenbind-ast.h
+++ b/src/nsgenbind-ast.h
@@ -82,12 +82,27 @@ genbind_node_find(struct genbind_node *node,
* search the full tree depth (initial search) or the result
* of a previous search to continue.
* @param nodetype The type of node to seach for
+ * @return The found node or NULL for no nodes.
*/
struct genbind_node *
genbind_node_find_type(struct genbind_node *node,
struct genbind_node *prev,
enum genbind_node_type nodetype);
+/** count how many nodes of a specified type.
+ *
+ * Enumerate how many nodes of the specified type there are by
+ * performing a depth first search for nodes of the given type and
+ * counting the number of results.
+ *
+ * @param node The node to start the search from
+ * @param nodetype The type of node to count
+ * @return The number of nodes found.
+ */
+int
+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
*