summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile4
-rw-r--r--src/duk-libdom.c1586
-rw-r--r--src/duk-libdom.h14
-rw-r--r--src/interface-map.c874
-rw-r--r--src/interface-map.h141
-rw-r--r--src/jsapi-libdom-const.c195
-rw-r--r--src/jsapi-libdom-function.c (renamed from src/jsapi-libdom-operator.c)357
-rw-r--r--src/jsapi-libdom-init.c286
-rw-r--r--src/jsapi-libdom-jsclass.c180
-rw-r--r--src/jsapi-libdom-new.c395
-rw-r--r--src/jsapi-libdom-property.c476
-rw-r--r--src/jsapi-libdom.c597
-rw-r--r--src/jsapi-libdom.h75
-rw-r--r--src/nsgenbind-ast.c860
-rw-r--r--src/nsgenbind-ast.h228
-rw-r--r--src/nsgenbind-lexer.l41
-rw-r--r--src/nsgenbind-parser.y448
-rw-r--r--src/nsgenbind.c332
-rw-r--r--src/options.h12
-rw-r--r--src/utils.c160
-rw-r--r--src/utils.h46
-rw-r--r--src/webidl-ast.c278
-rw-r--r--src/webidl-ast.h60
-rw-r--r--src/webidl-lexer.l9
-rw-r--r--src/webidl-parser.y202
25 files changed, 5984 insertions, 1872 deletions
diff --git a/src/Makefile b/src/Makefile
index 972beb9..8b034fe 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,7 +1,9 @@
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 utils.c webidl-ast.c nsgenbind-ast.c \
+ interface-map.c duk-libdom.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/duk-libdom.c b/src/duk-libdom.c
new file mode 100644
index 0000000..195f4a4
--- /dev/null
+++ b/src/duk-libdom.c
@@ -0,0 +1,1586 @@
+/* duktape binding generation implementation
+ *
+ * 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>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "options.h"
+#include "utils.h"
+#include "nsgenbind-ast.h"
+#include "webidl-ast.h"
+#include "interface-map.h"
+#include "duk-libdom.h"
+
+/** prefix for all generated functions */
+#define DLPFX "dukky"
+
+#define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_"
+
+#define NSGENBIND_PREAMBLE \
+"/* Generated by nsgenbind\n" \
+" *\n" \
+" * nsgenbind is published under the MIT Licence.\n" \
+" * nsgenbind is similar to a compiler is a purely transformative tool which\n"\
+" * explicitly makes no copyright claim on this generated output\n"\
+" */"
+
+/**
+ * Output code to create a private structure
+ *
+ */
+static int output_create_private(FILE* outf, char *class_name)
+{
+ fprintf(outf, "\t/* create private data and attach to instance */\n");
+ fprintf(outf, "\t%s_private_t *priv = calloc(1, sizeof(*priv));\n",
+ class_name);
+ fprintf(outf, "\tif (priv == NULL) return 0;\n");
+ fprintf(outf, "\tduk_push_pointer(ctx, priv);\n");
+ fprintf(outf,
+ "\tduk_put_prop_string(ctx, 0, \"%sPRIVATE\");\n\n",
+ MAGICPFX);
+
+ return 0;
+}
+
+/**
+ * generate code that gets a private pointer
+ */
+static int output_safe_get_private(FILE* outf, char *class_name, int idx)
+{
+ fprintf(outf, "\t%s_private_t *priv;\n", class_name);
+ fprintf(outf, "\tduk_get_prop_string(ctx, %d, \"%sPRIVATE\");\n",
+ idx, MAGICPFX);
+ fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n");
+ fprintf(outf, "\tduk_pop(ctx);\n");
+ fprintf(outf, "\tif (priv == NULL) return 0;\n\n");
+ return 0;
+}
+
+
+/**
+ * generate a duktape prototype name
+ */
+static char *get_prototype_name(const char *interface_name)
+{
+ char *proto_name;
+ int pnamelen;
+ int pfxlen;
+
+ /* duplicate the interface name in upper case */
+ pfxlen = SLEN(MAGICPFX) + SLEN("PROTOTYPE_");
+ pnamelen = strlen(interface_name) + 1;
+
+ proto_name = malloc(pnamelen + pfxlen);
+ snprintf(proto_name, pnamelen + pfxlen, "%sPROTOTYPE_%s", MAGICPFX, interface_name);
+ for (pnamelen-- ; pnamelen >= 0; pnamelen--) {
+ proto_name[pnamelen + pfxlen] = toupper(interface_name[pnamelen]);
+ }
+ return proto_name;
+}
+
+/**
+ * generate code that gets a prototype by name
+ */
+static int output_get_prototype(FILE* outf, const char *interface_name)
+{
+ char *proto_name;
+
+ proto_name = get_prototype_name(interface_name);
+
+ fprintf(outf, "\t/* get prototype */\n");
+ fprintf(outf,
+ "\tduk_get_global_string(ctx, \"%sPROTOTYPES\");\n", MAGICPFX);
+ fprintf(outf,
+ "\tduk_get_prop_string(ctx, -1, \"%s\");\n", proto_name);
+ fprintf(outf, "\tduk_replace(ctx, -2);\n");
+
+ free(proto_name);
+
+ return 0;
+}
+
+/**
+ * generate code that sets a destructor in a prototype
+ */
+static int output_set_destructor(FILE* outf, char *class_name, int idx)
+{
+ fprintf(outf, "\t/* Set the destructor */\n");
+ fprintf(outf, "\tduk_dup(ctx, %d);\n", idx);
+ fprintf(outf, "\tduk_push_c_function(ctx, %s_%s___destructor, 1);\n",
+ DLPFX, class_name);
+ fprintf(outf, "\tduk_set_finalizer(ctx, -2);\n");
+ fprintf(outf, "\tduk_pop(ctx);\n\n");
+
+ return 0;
+}
+
+/**
+ * generate code that sets a constructor in a prototype
+ */
+static int
+output_set_constructor(FILE* outf, char *class_name, int idx, int argc)
+{
+ fprintf(outf, "\t/* Set the constructor */\n");
+ fprintf(outf, "\tduk_dup(ctx, %d);\n", idx);
+ fprintf(outf, "\tduk_push_c_function(ctx, %s_%s___constructor, %d);\n",
+ DLPFX, class_name, 1 + argc);
+ fprintf(outf, "\tduk_put_prop_string(ctx, -2, \"%sINIT\");\n",
+ MAGICPFX);
+ fprintf(outf, "\tduk_pop(ctx);\n\n");
+
+ return 0;
+}
+
+static int
+output_dump_stack(FILE* outf)
+{
+ if (options->dbglog) {
+ /* dump stack */
+ fprintf(outf, "\tduk_push_context_dump(ctx);\n");
+ fprintf(outf, "\tLOG(\"Stack: %%s\", duk_to_string(ctx, -1));\n");
+ fprintf(outf, "\tduk_pop(ctx);\n");
+ }
+ return 0;
+}
+
+/**
+ * generate code that adds a method in a prototype
+ */
+static int
+output_add_method(FILE* outf,
+ const char *class_name,
+ const char *method)
+{
+ fprintf(outf, "\t/* Add a method */\n");
+ fprintf(outf, "\tduk_dup(ctx, 0);\n");
+ fprintf(outf, "\tduk_push_string(ctx, \"%s\");\n", method);
+ fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s, DUK_VARARGS);\n",
+ DLPFX, class_name, method);
+ output_dump_stack(outf);
+ fprintf(outf, "\tduk_def_prop(ctx, -3,\n");
+ fprintf(outf, "\t DUK_DEFPROP_HAVE_VALUE |\n");
+ fprintf(outf, "\t DUK_DEFPROP_HAVE_WRITABLE |\n");
+ fprintf(outf, "\t DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n");
+ fprintf(outf, "\t DUK_DEFPROP_HAVE_CONFIGURABLE);\n");
+ fprintf(outf, "\tduk_pop(ctx);\n\n");
+
+ return 0;
+}
+
+/**
+ * Generate source to populate a read/write property on a prototype
+ */
+static int
+output_populate_rw_property(FILE* outf, const char *class_name, const char *property)
+{
+ fprintf(outf, "\t/* Add read/write property */\n");
+ fprintf(outf, "\tduk_dup(ctx, 0);\n");
+ fprintf(outf, "\tduk_push_string(ctx, \"%s\");\n", property);
+ fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s_getter, 0);\n",
+ DLPFX, class_name, property);
+ fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s_setter, 1);\n",
+ DLPFX, class_name, property);
+ output_dump_stack(outf);
+ fprintf(outf, "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\n");
+ fprintf(outf, "\t\tDUK_DEFPROP_HAVE_SETTER |\n");
+ fprintf(outf, "\t\tDUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n");
+ fprintf(outf, "\t\tDUK_DEFPROP_HAVE_CONFIGURABLE);\n");
+ fprintf(outf, "\tduk_pop(ctx);\n\n");
+
+ return 0;
+}
+
+/**
+ * Generate source to populate a readonly property on a prototype
+ */
+static int
+output_populate_ro_property(FILE* outf, const char *class_name, const char *property)
+{
+ fprintf(outf, "\t/* Add readonly property */\n");
+ fprintf(outf, "\tduk_dup(ctx, 0);\n");
+ fprintf(outf, "\tduk_push_string(ctx, \"%s\");\n", property);
+ fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s_getter, 0);\n",
+ DLPFX, class_name, property);
+ output_dump_stack(outf);
+ fprintf(outf, "\tduk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER |\n");
+ fprintf(outf, "\t\tDUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n");
+ fprintf(outf, "\t\tDUK_DEFPROP_HAVE_CONFIGURABLE);\n");
+ fprintf(outf, "\tduk_pop(ctx);\n\n");
+
+ return 0;
+}
+
+/**
+ * Generate source to add a constant int value on a prototype
+ */
+static int
+output_prototype_constant_int(FILE *outf, const char *constant_name, int value)
+{
+ fprintf(outf, "\tduk_dup(ctx, 0);\n");
+ fprintf(outf, "\tduk_push_string(ctx, \"%s\");\n", constant_name);
+ fprintf(outf, "\tduk_push_int(ctx, %d);\n", value);
+ fprintf(outf, "\tduk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |\n");
+ fprintf(outf, "\t DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE |\n");
+ fprintf(outf, "\t DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE);\n");
+ fprintf(outf, "\tduk_pop(ctx);\n\n");
+ return 0;
+}
+
+/**
+ * generate code that gets a private pointer for a method
+ */
+static int
+output_get_method_private(FILE* outf, char *class_name)
+{
+ fprintf(outf, "\t/* Get private data for method */\n");
+ fprintf(outf, "\t%s_private_t *priv = NULL;\n", class_name);
+ fprintf(outf, "\tduk_push_this(ctx);\n");
+ fprintf(outf, "\tduk_get_prop_string(ctx, -1, \"%sPRIVATE\");\n",
+ MAGICPFX);
+ fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n");
+ fprintf(outf, "\tduk_pop_2(ctx);\n");
+ fprintf(outf, "\tif (priv == NULL) {\n");
+ if (options->dbglog) {
+ fprintf(outf, "\t\tLOG(\"priv failed\");\n");
+ }
+ fprintf(outf, "\t\treturn 0; /* can do? No can do. */\n");
+ fprintf(outf, "\t}\n\n");
+
+ return 0;
+}
+
+/**
+ * generate preface block for nsgenbind
+ */
+static int output_tool_preface(FILE* outf)
+{
+ fprintf(outf, "%s\n", NSGENBIND_PREAMBLE);
+
+ return 0;
+}
+
+/**
+ * Generate a C class name for the interface.
+ *
+ * The IDL interface names are camelcase and not similar to libdom naming so it
+ * is necessary to convert them to a libdom compatible class name. This
+ * implementation is simple ASCII capable only and cannot cope with multibyte
+ * codepoints.
+ *
+ * The algorithm is:
+ * - copy characters to output lowering their case
+ * - if the previous character in the input name was uppercase and the current
+ * one is lowercase insert an underscore before the *previous* character.
+ */
+static char *gen_class_name(struct interface_map_entry *interfacee)
+{
+ const char *inc;
+ char *outc;
+ char *name;
+ int wasupper;
+
+ /* enpty strings are a bad idea */
+ if ((interfacee->name == NULL) || (interfacee->name[0] == 0)) {
+ return NULL;
+ }
+
+ /* allocate result buffer as twice the input length as thats the
+ * absolute worst case.
+ */
+ name = calloc(2, strlen(interfacee->name));
+
+ outc = name;
+ inc = interfacee->name;
+ wasupper = 0;
+
+ /* first character handled separately as inserting a leading underscore
+ * is undesirable
+ */
+ *outc++ = tolower(*inc++);
+ /* copy input to output */
+ while (*inc != 0) {
+ /* ugly hack as html IDL is always prefixed uppercase and needs
+ * an underscore there
+ */
+ if ((inc == (interfacee->name + 4)) &&
+ (interfacee->name[0] == 'H') &&
+ (interfacee->name[1] == 'T') &&
+ (interfacee->name[2] == 'M') &&
+ (interfacee->name[3] == 'L') &&
+ (islower(inc[1]) == 0)) {
+ *outc++ = '_';
+ }
+ if ((islower(*inc) != 0) && (wasupper != 0)) {
+ *outc = *(outc - 1);
+ *(outc - 1) = '_';
+ outc++;
+ wasupper = 0;
+ } else {
+ wasupper = isupper(*inc);
+ }
+ *outc++ = tolower(*inc++);
+ }
+ return name;
+}
+
+/**
+ * output character data of node of given type.
+ *
+ * used for any cdata including pre/pro/epi/post sections
+ *
+ * \param outf The file handle to write output.
+ * \param node The node to search.
+ * \param nodetype the type of child node to search for.
+ * \return The number of nodes written or 0 for none.
+ */
+static int
+output_cdata(FILE* outf,
+ struct genbind_node *node,
+ enum genbind_node_type nodetype)
+{
+ char *cdata;
+ int res = 0;
+
+ cdata = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(node),
+ NULL, nodetype));
+ if (cdata != NULL) {
+ fprintf(outf, "%s", cdata);
+ res = 1;
+ }
+ return res;
+}
+
+static FILE *open_header(struct interface_map *interface_map, const char *name)
+{
+ FILE *hdrf;
+ char *fname;
+ int fnamel;
+
+ fnamel = strlen(name) + 4;
+ fname = malloc(fnamel);
+ snprintf(fname, fnamel, "%s.h", name);
+
+ /* open output file */
+ hdrf = genb_fopen_tmp(fname);
+ free(fname);
+ if (hdrf == NULL) {
+ return NULL;
+ }
+
+ /* binding preface */
+ output_cdata(hdrf,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_PREFACE);
+
+ /* tool preface */
+ output_tool_preface(hdrf);
+
+ /* header guard */
+ fprintf(hdrf, "\n#ifndef %s_%s_h\n", DLPFX, name);
+ fprintf(hdrf, "#define %s_%s_h\n\n", DLPFX, name);
+
+ return hdrf;
+}
+
+static int close_header(struct interface_map *interface_map,
+ FILE *hdrf,
+ const char *name)
+{
+ char *fname;
+ int fnamel;
+
+ fnamel = strlen(name) + 4;
+ fname = malloc(fnamel);
+ snprintf(fname, fnamel, "%s.h", name);
+
+ fprintf(hdrf, "\n#endif\n");
+
+ /* binding postface */
+ output_cdata(hdrf,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_POSTFACE);
+
+ genb_fclose_tmp(hdrf, fname);
+ free(fname);
+
+ return 0;
+}
+
+
+/**
+ * generate the interface constructor
+ */
+static int
+output_interface_constructor(FILE* outf, struct interface_map_entry *interfacee)
+{
+ int init_argc;
+
+ /* constructor definition */
+ fprintf(outf,
+ "static duk_ret_t %s_%s___constructor(duk_context *ctx)\n",
+ DLPFX, interfacee->class_name);
+ fprintf(outf,"{\n");
+
+ output_create_private(outf, interfacee->class_name);
+
+ /* generate call to initialisor */
+ fprintf(outf,
+ "\t%s_%s___init(ctx, priv",
+ DLPFX, interfacee->class_name);
+ for (init_argc = 1;
+ init_argc <= interfacee->class_init_argc;
+ init_argc++) {
+ fprintf(outf, ", duk_get_pointer(ctx, %d)", init_argc);
+ }
+ fprintf(outf, ");\n");
+
+
+ fprintf(outf, "\tduk_set_top(ctx, 1);\n");
+ fprintf(outf, "\treturn 1;\n");
+
+ fprintf(outf, "}\n\n");
+
+ return 0;
+}
+
+/**
+ * generate the interface destructor
+ */
+static int
+output_interface_destructor(FILE* outf, struct interface_map_entry *interfacee)
+{
+ /* destructor definition */
+ fprintf(outf,
+ "static duk_ret_t %s_%s___destructor(duk_context *ctx)\n",
+ DLPFX, interfacee->class_name);
+ fprintf(outf,"{\n");
+
+ output_safe_get_private(outf, interfacee->class_name, 0);
+
+ /* generate call to finaliser */
+ fprintf(outf,
+ "\t%s_%s___fini(ctx, priv);\n",
+ DLPFX, interfacee->class_name);
+
+ fprintf(outf,"\tfree(priv);\n");
+ fprintf(outf,"\treturn 0;\n");
+
+ fprintf(outf, "}\n\n");
+
+ return 0;
+}
+
+/**
+ * generate an initialisor call to parent interface
+ */
+static int
+output_interface_inherit_init(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_entry *inherite)
+{
+ struct genbind_node *init_node;
+ struct genbind_node *inh_init_node;
+ struct genbind_node *param_node;
+ struct genbind_node *inh_param_node;
+
+ /* only need to call parent initialisor if there is one */
+ if (inherite == NULL) {
+ return 0;
+ }
+
+ /* find the initialisor method on the class (if any) */
+ init_node = genbind_node_find_method(interfacee->class,
+ NULL,
+ GENBIND_METHOD_TYPE_INIT);
+
+
+ inh_init_node = genbind_node_find_method(inherite->class,
+ NULL,
+ GENBIND_METHOD_TYPE_INIT);
+
+
+
+ fprintf(outf, "\t%s_%s___init(ctx, &priv->parent",
+ DLPFX, inherite->class_name);
+
+ /* for each parameter in the parent find a matching named
+ * parameter to pass and cast if necessary
+ */
+
+ inh_param_node = genbind_node_find_type(
+ genbind_node_getnode(inh_init_node),
+ NULL, GENBIND_NODE_TYPE_PARAMETER);
+ while (inh_param_node != NULL) {
+ char *param_name;
+ param_name = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(inh_param_node),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT));
+
+ param_node = genbind_node_find_type_ident(
+ genbind_node_getnode(init_node),
+ NULL,
+ GENBIND_NODE_TYPE_PARAMETER,
+ param_name);
+ if (param_node == NULL) {
+ fprintf(stderr, "class \"%s\" (interface %s) parent class \"%s\" (interface %s) initialisor requires a parameter \"%s\" with compatible identifier\n",
+ interfacee->class_name,
+ interfacee->name,
+ inherite->class_name,
+ inherite->name,
+ param_name);
+ return -1;
+ } else {
+ char *param_type;
+ char *inh_param_type;
+
+ fprintf(outf, ", ");
+
+ /* cast the parameter if required */
+ param_type = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(param_node),
+ NULL,
+ GENBIND_NODE_TYPE_TYPE));
+
+ inh_param_type = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(inh_param_node),
+ NULL,
+ GENBIND_NODE_TYPE_TYPE));
+
+ if (strcmp(param_type, inh_param_type) != 0) {
+ fprintf(outf, "(%s)", inh_param_type);
+ }
+
+ /* output the parameter identifier */
+ output_cdata(outf, param_node, GENBIND_NODE_TYPE_IDENT);
+ }
+
+ inh_param_node = genbind_node_find_type(
+ genbind_node_getnode(inh_init_node),
+ inh_param_node, GENBIND_NODE_TYPE_METHOD);
+ }
+
+ fprintf(outf, ");\n");
+
+ return 0;
+}
+
+static int
+output_interface_init_declaration(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct genbind_node *init_node)
+{
+ struct genbind_node *param_node;
+
+ fprintf(outf,
+ "void %s_%s___init(duk_context *ctx, %s_private_t *priv",
+ DLPFX, interfacee->class_name, interfacee->class_name);
+
+ /* count the number of arguments on the initializer */
+ interfacee->class_init_argc = 0;
+
+ /* output the paramters on the method (if any) */
+ param_node = genbind_node_find_type(
+ genbind_node_getnode(init_node),
+ NULL, GENBIND_NODE_TYPE_PARAMETER);
+ while (param_node != NULL) {
+ interfacee->class_init_argc++;
+ fprintf(outf, ", ");
+ output_cdata(outf, param_node, GENBIND_NODE_TYPE_TYPE);
+ output_cdata(outf, param_node, GENBIND_NODE_TYPE_IDENT);
+
+ param_node = genbind_node_find_type(
+ genbind_node_getnode(init_node),
+ param_node, GENBIND_NODE_TYPE_PARAMETER);
+ }
+
+ fprintf(outf,")");
+
+ return 0;
+}
+
+static int
+output_interface_init(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_entry *inherite)
+{
+ struct genbind_node *init_node;
+ int res;
+
+ /* find the initialisor method on the class (if any) */
+ init_node = genbind_node_find_method(interfacee->class,
+ NULL,
+ GENBIND_METHOD_TYPE_INIT);
+
+ /* initialisor definition */
+ output_interface_init_declaration(outf, interfacee, init_node);
+
+ fprintf(outf,"\n{\n");
+
+ /* if this interface inherits ensure we call its initialisor */
+ res = output_interface_inherit_init(outf, interfacee, inherite);
+ if (res != 0) {
+ return res;
+ }
+
+ /* generate log statement */
+ if (options->dbglog) {
+ fprintf(outf,
+ "\tLOG(\"Initialise %%p (priv=%%p)\", duk_get_heapptr(ctx, 0), priv);\n" );
+ }
+
+ /* output the initaliser code from the binding */
+ output_cdata(outf, init_node, GENBIND_NODE_TYPE_CDATA);
+
+ fprintf(outf, "}\n\n");
+
+ return 0;
+
+}
+
+static int
+output_interface_fini(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_entry *inherite)
+{
+ struct genbind_node *fini_node;
+
+ /* find the finaliser method on the class (if any) */
+ fini_node = genbind_node_find_method(interfacee->class,
+ NULL,
+ GENBIND_METHOD_TYPE_FINI);
+
+ /* finaliser definition */
+ fprintf(outf,
+ "void %s_%s___fini(duk_context *ctx, %s_private_t *priv)\n",
+ DLPFX, interfacee->class_name, interfacee->class_name);
+ fprintf(outf,"{\n");
+
+ /* generate log statement */
+ if (options->dbglog) {
+ fprintf(outf,
+ "\tLOG(\"Finalise %%p\", duk_get_heapptr(ctx, 0));\n" );
+ }
+
+ /* output the finialisor code from the binding */
+ output_cdata(outf, fini_node, GENBIND_NODE_TYPE_CDATA);
+
+ /* if this interface inherits ensure we call its finaliser */
+ if (inherite != NULL) {
+ fprintf(outf,
+ "\t%s_%s___fini(ctx, &priv->parent);\n",
+ DLPFX, inherite->class_name);
+ }
+ fprintf(outf, "}\n\n");
+
+ return 0;
+}
+
+
+/**
+ * generate a prototype add for a single class method
+ */
+static int
+output_prototype_method(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_operation_entry *operatione)
+{
+
+ if (operatione->name != NULL) {
+ /* normal method on prototype */
+ output_add_method(outf,
+ interfacee->class_name,
+ operatione->name);
+ } else {
+ /* special method on prototype */
+ fprintf(outf,
+ "\t/* Special method on prototype - UNIMPLEMENTED */\n\n");
+ }
+
+ return 0;
+}
+
+/**
+ * generate prototype method definitions
+ */
+static int
+output_prototype_methods(FILE *outf, struct interface_map_entry *interfacee)
+{
+ int opc;
+ int res = 0;
+
+ for (opc = 0; opc < interfacee->operationc; opc++) {
+ res = output_prototype_method(outf,
+ interfacee,
+ interfacee->operationv + opc);
+ if (res != 0) {
+ break;
+ }
+ }
+
+ return res;
+}
+
+
+static int
+output_prototype_attribute(FILE *outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_attribute_entry *attributee)
+{
+ if (attributee->modifier == WEBIDL_TYPE_MODIFIER_READONLY) {
+ return output_populate_ro_property(outf,
+ interfacee->class_name,
+ attributee->name);
+ }
+ return output_populate_rw_property(outf,
+ interfacee->class_name,
+ attributee->name);
+}
+
+/**
+ * generate prototype attribute definitions
+ */
+static int
+output_prototype_attributes(FILE *outf, struct interface_map_entry *interfacee)
+{
+ int attrc;
+ int res = 0;
+
+ for (attrc = 0; attrc < interfacee->attributec; attrc++) {
+ res = output_prototype_attribute(outf,interfacee,
+ interfacee->attributev + attrc);
+ if (res != 0) {
+ break;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * output constants on the prototype
+ *
+ * \todo This implementation assumes the constant is a literal int and should
+ * check the type node base value.
+ */
+static int
+output_prototype_constant(FILE *outf,
+ struct interface_map_constant_entry *constante)
+{
+ int *value;
+
+ value = webidl_node_getint(
+ webidl_node_find_type(
+ webidl_node_getnode(constante->node),
+ NULL,
+ WEBIDL_NODE_TYPE_LITERAL_INT));
+
+ output_prototype_constant_int(outf, constante->name, *value);
+
+ return 0;
+}
+
+/**
+ * generate prototype constant definitions
+ */
+static int
+output_prototype_constants(FILE *outf, struct interface_map_entry *interfacee)
+{
+ int attrc;
+ int res = 0;
+
+ for (attrc = 0; attrc < interfacee->constantc; attrc++) {
+ res = output_prototype_constant(outf,
+ interfacee->constantv + attrc);
+ if (res != 0) {
+ break;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * generate the interface prototype creator
+ */
+static int
+output_interface_prototype(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_entry *inherite)
+{
+ struct genbind_node *proto_node;
+
+ /* find the prototype method on the class */
+ proto_node = genbind_node_find_method(interfacee->class,
+ NULL,
+ GENBIND_METHOD_TYPE_PROTOTYPE);
+
+ /* prototype definition */
+ fprintf(outf, "duk_ret_t %s_%s___proto(duk_context *ctx)\n",
+ DLPFX, interfacee->class_name);
+ fprintf(outf,"{\n");
+
+ /* Output any binding data first */
+ if (output_cdata(outf, proto_node, GENBIND_NODE_TYPE_CDATA) != 0) {
+ fprintf(outf,"\n");
+ }
+
+ /* generate prototype chaining if interface has a parent */
+ if (inherite != NULL) {
+ fprintf(outf,
+ "\t/* Set this prototype's prototype (left-parent) */\n");
+ output_get_prototype(outf, inherite->name);
+ fprintf(outf, "\tduk_set_prototype(ctx, 0);\n\n");
+ }
+
+ /* generate setting of methods */
+ output_prototype_methods(outf, interfacee);
+
+ /* generate setting of attributes */
+ output_prototype_attributes(outf, interfacee);
+
+ /* generate setting of constants */
+ output_prototype_constants(outf, interfacee);
+
+ /* generate setting of destructor */
+ output_set_destructor(outf, interfacee->class_name, 0);
+
+ /* generate setting of constructor */
+ output_set_constructor(outf,
+ interfacee->class_name,
+ 0,
+ interfacee->class_init_argc);
+
+ fprintf(outf,"\treturn 1; /* The prototype object */\n");
+
+ fprintf(outf, "}\n\n");
+
+ return 0;
+}
+
+
+/**
+ * generate a single class method for an interface operation
+ */
+static int
+output_interface_operation(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_operation_entry *operatione)
+{
+ int cdatac; /* cdata blocks output */
+
+ if (operatione->name == NULL) {
+ /* special method definition */
+ fprintf(outf,
+ "/* Special method definition - UNIMPLEMENTED */\n\n");
+ return 0;
+ }
+
+ /* normal method definition */
+
+ fprintf(outf,
+ "static duk_ret_t %s_%s_%s(duk_context *ctx)\n",
+ DLPFX, interfacee->class_name, operatione->name);
+ fprintf(outf,"{\n");
+
+ output_get_method_private(outf, interfacee->class_name);
+
+ cdatac = output_cdata(outf,
+ operatione->method,
+ GENBIND_NODE_TYPE_CDATA);
+
+ if (cdatac == 0) {
+ /* no implementation so generate default */
+ WARN(WARNING_UNIMPLEMENTED,
+ "Unimplemented: method %s::%s();",
+ interfacee->name, operatione->name);
+ fprintf(outf,"\treturn 0;\n");
+ }
+
+ fprintf(outf, "}\n\n");
+
+ return 0;
+}
+
+/**
+ * generate class methods for each interface operation
+ */
+static int
+output_interface_operations(FILE* outf, struct interface_map_entry *interfacee)
+{
+ int opc;
+ int res = 0;
+
+ for (opc = 0; opc < interfacee->operationc; opc++) {
+ res = output_interface_operation(outf,
+ interfacee,
+ interfacee->operationv + opc);
+ if (res != 0) {
+ break;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * Generate class property getter/setter for a single attribute
+ */
+static int
+output_interface_attribute(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_attribute_entry *atributee)
+{
+ int cdatac;
+
+ /* getter definition */
+ fprintf(outf,
+ "static duk_ret_t %s_%s_%s_getter(duk_context *ctx)\n",
+ DLPFX, interfacee->class_name, atributee->name);
+ fprintf(outf,"{\n");
+
+ output_get_method_private(outf, interfacee->class_name);
+
+ cdatac = output_cdata(outf, atributee->getter, GENBIND_NODE_TYPE_CDATA);
+
+ if (cdatac == 0) {
+ WARN(WARNING_UNIMPLEMENTED,
+ "Unimplemented: getter %s::%s();",
+ interfacee->name, atributee->name);
+
+ /* no implementation so generate default */
+ fprintf(outf,"\treturn 0;\n");
+ }
+
+ fprintf(outf, "}\n\n");
+
+ /* readonly attributes have no setter */
+ if (atributee->modifier == WEBIDL_TYPE_MODIFIER_READONLY) {
+ return 0;
+ }
+
+ /* setter definition */
+ fprintf(outf,
+ "static duk_ret_t %s_%s_%s_setter(duk_context *ctx)\n",
+ DLPFX, interfacee->class_name, atributee->name);
+ fprintf(outf,"{\n");
+
+ output_get_method_private(outf, interfacee->class_name);
+
+ cdatac = output_cdata(outf, atributee->setter, GENBIND_NODE_TYPE_CDATA);
+
+ if (cdatac == 0) {
+ WARN(WARNING_UNIMPLEMENTED,
+ "Unimplemented: setter %s::%s();",
+ interfacee->name, atributee->name);
+
+ /* no implementation so generate default */
+ fprintf(outf,"\treturn 0;\n");
+ }
+
+
+ fprintf(outf, "}\n\n");
+
+ return 0;
+}
+
+/**
+ * generate class property getters and setters for each interface attribute
+ */
+static int
+output_interface_attributes(FILE* outf,
+ struct interface_map_entry *interfacee)
+{
+ int attrc;
+
+ for (attrc = 0; attrc < interfacee->attributec; attrc++) {
+ output_interface_attribute(outf,
+ interfacee,
+ interfacee->attributev + attrc);
+ }
+
+ return 0;
+}
+
+
+/**
+ * generate preface block for nsgenbind
+ */
+static int output_tool_prologue(FILE* outf)
+{
+ char *fpath;
+
+ fpath = genb_fpath("binding.h");
+ fprintf(outf, "\n#include \"%s\"\n", fpath);
+ free(fpath);
+
+ fpath = genb_fpath("private.h");
+ fprintf(outf, "#include \"%s\"\n", fpath);
+ free(fpath);
+
+ fpath = genb_fpath("prototype.h");
+ fprintf(outf, "#include \"%s\"\n", fpath);
+ free(fpath);
+
+ return 0;
+}
+
+/**
+ * generate a source file to implement an interface using duk and libdom.
+ */
+static int output_interface(struct interface_map *interface_map,
+ struct interface_map_entry *interfacee)
+{
+ FILE *ifacef;
+ int ifacenamelen;
+ struct interface_map_entry *inherite;
+ int res = 0;
+
+ /* do not generate class for interfaces marked no output */
+ if (interfacee->noobject) {
+ return 0;
+ }
+
+ /* compute class name */
+ interfacee->class_name = gen_class_name(interfacee);
+
+ /* generate source filename */
+ ifacenamelen = strlen(interfacee->class_name) + 4;
+ interfacee->filename = malloc(ifacenamelen);
+ snprintf(interfacee->filename, ifacenamelen,
+ "%s.c", interfacee->class_name);
+
+ /* open output file */
+ ifacef = genb_fopen_tmp(interfacee->filename);
+ if (ifacef == NULL) {
+ return -1;
+ }
+
+ /* find parent interface entry */
+ inherite = interface_map_inherit_entry(interface_map, interfacee);
+
+ /* tool preface */
+ output_tool_preface(ifacef);
+
+ /* binding preface */
+ output_cdata(ifacef,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_PREFACE);
+
+ /* class preface */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE);
+
+ /* tool prologue */
+ output_tool_prologue(ifacef);
+
+ /* binding prologue */
+ output_cdata(ifacef,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_PROLOGUE);
+
+ /* class prologue */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PROLOGUE);
+
+ fprintf(ifacef, "\n");
+
+ /* initialisor */
+ res = output_interface_init(ifacef, interfacee, inherite);
+ if (res != 0) {
+ goto op_error;
+ }
+
+ /* finaliser */
+ output_interface_fini(ifacef, interfacee, inherite);
+
+ /* constructor */
+ output_interface_constructor(ifacef, interfacee);
+
+ /* destructor */
+ output_interface_destructor(ifacef, interfacee);
+
+ /* operations */
+ output_interface_operations(ifacef, interfacee);
+
+ /* attributes */
+ output_interface_attributes(ifacef, interfacee);
+
+ /* prototype */
+ output_interface_prototype(ifacef, interfacee, inherite);
+
+ fprintf(ifacef, "\n");
+
+ /* class epilogue */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE);
+
+ /* binding epilogue */
+ output_cdata(ifacef,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_EPILOGUE);
+
+ /* class postface */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_POSTFACE);
+
+ /* binding postface */
+ output_cdata(ifacef,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_POSTFACE);
+
+op_error:
+ genb_fclose_tmp(ifacef, interfacee->filename);
+
+ return res;
+}
+
+/**
+ * generate private header
+ */
+static int
+output_private_header(struct interface_map *interface_map)
+{
+ int idx;
+ FILE *privf;
+
+ /* open header */
+ privf = open_header(interface_map, "private");
+
+ for (idx = 0; idx < interface_map->entryc; idx++) {
+ struct interface_map_entry *interfacee;
+ struct interface_map_entry *inherite;
+ struct genbind_node *priv_node;
+
+ interfacee = interface_map->entries + idx;
+
+ /* do not generate private structs for interfaces marked no
+ * output
+ */
+ if (interfacee->noobject) {
+ continue;
+ }
+
+ /* find parent interface entry */
+ inherite = interface_map_inherit_entry(interface_map,
+ interfacee);
+
+ fprintf(privf, "typedef struct {\n");
+ if (inherite != NULL) {
+ fprintf(privf, "\t%s_private_t parent;\n",
+ inherite->class_name);
+ }
+
+ /* for each private variable on the class output it here. */
+ priv_node = genbind_node_find_type(
+ genbind_node_getnode(interfacee->class),
+ NULL,
+ GENBIND_NODE_TYPE_PRIVATE);
+ while (priv_node != NULL) {
+ fprintf(privf, "\t");
+ output_cdata(privf, priv_node, GENBIND_NODE_TYPE_TYPE);
+ output_cdata(privf, priv_node, GENBIND_NODE_TYPE_IDENT);
+ fprintf(privf, ";\n");
+
+ priv_node = genbind_node_find_type(
+ genbind_node_getnode(interfacee->class),
+ priv_node,
+ GENBIND_NODE_TYPE_PRIVATE);
+ }
+
+ fprintf(privf, "} %s_private_t;\n\n", interfacee->class_name);
+
+ }
+
+ close_header(interface_map, privf, "private");
+
+ return 0;
+}
+
+/**
+ * generate prototype header
+ */
+static int
+output_prototype_header(struct interface_map *interface_map)
+{
+ int idx;
+ FILE *protof;
+
+ /* open header */
+ protof = open_header(interface_map, "prototype");
+
+ for (idx = 0; idx < interface_map->entryc; idx++) {
+ struct interface_map_entry *interfacee;
+ struct genbind_node *init_node;
+
+ interfacee = interface_map->entries + idx;
+
+ /* do not generate prototype declarations for interfaces marked
+ * no output
+ */
+ if (interfacee->noobject) {
+ continue;
+ }
+
+ /* prototype declaration */
+ fprintf(protof, "duk_ret_t %s_%s___proto(duk_context *ctx);\n",
+ DLPFX, interfacee->class_name);
+
+ /** \todo if the interface has no references (no other
+ * interface inherits from it) there is no reason to export
+ * the initalisor/finaliser as no other class
+ * constructor/destructor should call them. Additionally the
+ * init/fini definition should be made static.
+ */
+
+ /* finaliser declaration */
+ fprintf(protof,
+ "void %s_%s___fini(duk_context *ctx, %s_private_t *priv);\n",
+ DLPFX, interfacee->class_name, interfacee->class_name);
+
+ /* find the initialisor method on the class (if any) */
+ init_node = genbind_node_find_method(interfacee->class,
+ NULL,
+ GENBIND_METHOD_TYPE_INIT);
+
+ /* initialisor definition */
+ output_interface_init_declaration(protof, interfacee, init_node);
+ fprintf(protof, ";\n\n");
+ }
+
+ close_header(interface_map, protof, "prototype");
+
+ return 0;
+}
+
+/**
+ * generate makefile fragment
+ */
+static int
+output_makefile(struct interface_map *interface_map)
+{
+ int idx;
+ FILE *makef;
+
+ /* open output file */
+ makef = genb_fopen_tmp("Makefile");
+ if (makef == NULL) {
+ return -1;
+ }
+
+ fprintf(makef, "# duk libdom makefile fragment\n\n");
+
+ fprintf(makef, "NSGENBIND_SOURCES:=binding.c ");
+ for (idx = 0; idx < interface_map->entryc; idx++) {
+ struct interface_map_entry *interfacee;
+
+ interfacee = interface_map->entries + idx;
+
+ /* no source for interfaces marked no output */
+ if (interfacee->noobject) {
+ continue;
+ }
+
+ fprintf(makef, "%s ", interfacee->filename);
+ }
+ fprintf(makef, "\nNSGENBIND_PREFIX:=%s\n", options->outdirname);
+
+ genb_fclose_tmp(makef, "Makefile");
+
+ return 0;
+}
+
+
+/**
+ * generate binding header
+ *
+ * The binding header contains all the duk-libdom specific binding interface
+ * macros and definitions.
+ *
+ * the create prototypes interface is used to cause all the prototype creation
+ * functions for all generated classes to be called in the correct order with
+ * the primary global (if any) generated last.
+ */
+static int
+output_binding_header(struct interface_map *interface_map)
+{
+ FILE *bindf;
+
+ /* open header */
+ bindf = open_header(interface_map, "binding");
+
+ fprintf(bindf,
+ "#define _MAGIC(S) (\"%s\" S)\n"
+ "#define MAGIC(S) _MAGIC(#S)\n"
+ "#define PROTO_MAGIC MAGIC(PROTOTYPES)\n"
+ "#define PRIVATE_MAGIC MAGIC(PRIVATE)\n"
+ "#define INIT_MAGIC MAGIC(INIT)\n"
+ "#define NODE_MAGIC MAGIC(NODE_MAP)\n"
+ "#define _PROTO_NAME(K) _MAGIC(\"PROTOTYPE_\" K)\n"
+ "#define PROTO_NAME(K) _PROTO_NAME(#K)\n"
+ "#define _PROP_NAME(K,V) _MAGIC(K \"_PROPERTY_\" V)\n"
+ "#define PROP_NAME(K,V) _PROP_NAME(#K,#V)\n"
+ "\n",
+ MAGICPFX);
+
+ fprintf(bindf,
+ "duk_bool_t %s_instanceof(duk_context *ctx, const char *klass);\n",
+ DLPFX);
+
+ fprintf(bindf,
+ "duk_ret_t %s_create_prototypes(duk_context *ctx);\n", DLPFX);
+
+ close_header(interface_map, bindf, "binding");
+
+ return 0;
+}
+
+
+/**
+ * generate binding source
+ *
+ * The binding header contains all the duk-libdom specific binding
+ * implementations.
+ */
+static int
+output_binding_src(struct interface_map *interface_map)
+{
+ int idx;
+ FILE *bindf;
+ struct interface_map_entry *pglobale = NULL;
+ char *proto_name;
+
+ /* open output file */
+ bindf = genb_fopen_tmp("binding.c");
+ if (bindf == NULL) {
+ return -1;
+ }
+
+ /* tool preface */
+ output_tool_preface(bindf);
+
+ /* binding preface */
+ output_cdata(bindf,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_PREFACE);
+
+ output_tool_prologue(bindf);
+
+ /* binding prologue */
+ output_cdata(bindf,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_PROLOGUE);
+
+
+ fprintf(bindf, "\n");
+
+ /* instance of helper */
+ fprintf(bindf,
+ "duk_bool_t\n"
+ "%s_instanceof(duk_context *ctx, const char *klass)\n",
+ DLPFX);
+ fprintf(bindf,
+ "{\n"
+ "\t/* ... ??? */\n"
+ "\tif (!duk_check_type(ctx, -1, DUK_TYPE_OBJECT)) {\n"
+ "\t\treturn false;\n"
+ "\t}\n"
+ "\t/* ... obj */\n"
+ "\tduk_get_global_string(ctx, \"%sPROTOTYPES\");\n"
+ "\t/* ... obj protos */\n"
+ "\tduk_get_prop_string(ctx, -1, klass);\n"
+ "\t/* ... obj protos goalproto */\n"
+ "\tduk_get_prototype(ctx, -3);\n"
+ "\t/* ... obj protos goalproto proto? */\n"
+ "\twhile (!duk_is_undefined(ctx, -1)) {\n"
+ "\t\tif (duk_strict_equals(ctx, -1, -2)) {\n"
+ "\t\t\tduk_pop_3(ctx);\n"
+ "\t\t\treturn true;\n"
+ "\t\t}\n"
+ "\t\tduk_get_prototype(ctx, -1);\n"
+ "\t\t/* ... obj protos goalproto proto proto? */\n"
+ "\t\tduk_replace(ctx, -2);\n"
+ "\t\t/* ... obj protos goalproto proto? */\n"
+ "\t}\n"
+ "\tduk_pop_3(ctx);\n"
+ "\t/* ... obj */\n"
+ "\treturn false;\n"
+ "}\n"
+ "\n",
+ MAGICPFX);
+
+ /* prototype creation helper function */
+ fprintf(bindf,
+ "static duk_ret_t\n"
+ "%s_to_string(duk_context *ctx)\n"
+ "{\n"
+ "\t/* */\n"
+ "\tduk_push_this(ctx);\n"
+ "\t/* this */\n"
+ "\tduk_get_prototype(ctx, -1);\n"
+ "\t/* this proto */\n"
+ "\tduk_get_prop_string(ctx, -1, \"%sklass_name\");\n"
+ "\t/* this proto classname */\n"
+ "\tduk_push_string(ctx, \"[object \");\n"
+ "\t/* this proto classname str */\n"
+ "\tduk_insert(ctx, -2);\n"
+ "\t/* this proto str classname */\n"
+ "\tduk_push_string(ctx, \"]\");\n"
+ "\t/* this proto str classname str */\n"
+ "\tduk_concat(ctx, 3);\n"
+ "\t/* this proto str */\n"
+ "\treturn 1;\n"
+ "}\n"
+ "\n",
+ DLPFX,
+ MAGICPFX);
+
+ fprintf(bindf,
+ "static duk_ret_t %s_create_prototype(duk_context *ctx,\n",
+ DLPFX);
+ fprintf(bindf,
+ "\t\t\t\t\tduk_safe_call_function genproto,\n"
+ "\t\t\t\t\tconst char *proto_name,\n"
+ "\t\t\t\t\tconst char *klass_name)\n"
+ "{\n"
+ "\tduk_int_t ret;\n"
+ "\tduk_push_object(ctx);\n"
+ "\tif ((ret = duk_safe_call(ctx, genproto, 1, 1)) != DUK_EXEC_SUCCESS) {\n"
+ "\t\tduk_pop(ctx);\n"
+ "\t\tLOG(\"Failed to register prototype for %%s\", proto_name + 2);\n"
+ "\t\treturn ret;\n"
+ "\t}\n"
+ "\t/* top of stack is the ready prototype, inject it */\n"
+ "\tduk_push_string(ctx, klass_name);\n"
+ "\tduk_put_prop_string(ctx, -2, \"%sklass_name\");\n"
+ "\tduk_push_c_function(ctx, %s_to_string, 0);\n"
+ "\tduk_put_prop_string(ctx, -2, \"toString\");\n"
+ "\tduk_push_string(ctx, \"toString\");\n"
+ "\tduk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_ENUMERABLE);\n"
+ "\tduk_put_global_string(ctx, proto_name);\n"
+ "\treturn DUK_ERR_NONE;\n"
+ "}\n\n",
+ MAGICPFX,
+ DLPFX);
+
+ /* generate prototype creation */
+ fprintf(bindf,
+ "duk_ret_t %s_create_prototypes(duk_context *ctx)\n", DLPFX);
+
+ fprintf(bindf, "{\n");
+
+ for (idx = 0; idx < interface_map->entryc; idx++) {
+ struct interface_map_entry *interfacee;
+
+ interfacee = interface_map->entries + idx;
+
+ /* do not generate prototype calls for interfaces marked
+ * no output
+ */
+ if (interfacee->noobject) {
+ continue;
+ }
+
+ if (interfacee->primary_global) {
+ pglobale = interfacee;
+ continue;
+ }
+
+ proto_name = get_prototype_name(interfacee->name);
+
+ fprintf(bindf,
+ "\t%s_create_prototype(ctx, %s_%s___proto, \"%s\", \"%s\");\n",
+ DLPFX,
+ DLPFX,
+ interfacee->class_name,
+ proto_name,
+ interfacee->name);
+
+ free(proto_name);
+ }
+
+ if (pglobale != NULL) {
+ fprintf(bindf, "\n\t/* Global object prototype is last */\n");
+
+ proto_name = get_prototype_name(pglobale->name);
+ fprintf(bindf,
+ "\t%s_create_prototype(ctx, %s_%s___proto, \"%s\", \"%s\");\n",
+ DLPFX,
+ DLPFX,
+ pglobale->class_name,
+ proto_name,
+ pglobale->name);
+ free(proto_name);
+ }
+
+ fprintf(bindf, "\n\treturn DUK_ERR_NONE;\n");
+
+ fprintf(bindf, "}\n");
+
+ /* binding postface */
+ output_cdata(bindf,
+ interface_map->binding_node,
+ GENBIND_NODE_TYPE_POSTFACE);
+
+ genb_fclose_tmp(bindf, "binding.c");
+
+ return 0;
+}
+
+int duk_libdom_output(struct interface_map *interface_map)
+{
+ int idx;
+ int res = 0;
+
+ /* generate interfaces */
+ for (idx = 0; idx < interface_map->entryc; idx++) {
+ res = output_interface(interface_map,
+ interface_map->entries + idx);
+ if (res != 0) {
+ goto output_err;
+ }
+ }
+
+ /* generate private header */
+ res = output_private_header(interface_map);
+ if (res != 0) {
+ goto output_err;
+ }
+
+ /* generate prototype header */
+ res = output_prototype_header(interface_map);
+ if (res != 0) {
+ goto output_err;
+ }
+
+ /* generate binding header */
+ res = output_binding_header(interface_map);
+ if (res != 0) {
+ goto output_err;
+ }
+
+ /* generate binding source */
+ res = output_binding_src(interface_map);
+ if (res != 0) {
+ goto output_err;
+ }
+
+ /* generate makefile fragment */
+ res = output_makefile(interface_map);
+
+output_err:
+
+ return res;
+}
diff --git a/src/duk-libdom.h b/src/duk-libdom.h
new file mode 100644
index 0000000..e1dd2c4
--- /dev/null
+++ b/src/duk-libdom.h
@@ -0,0 +1,14 @@
+/* DukTape binding generation
+ *
+ * This file is part of nsgenbind.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
+ */
+
+#ifndef nsgenbind_duk_libdom_h
+#define nsgenbind_duk_libdom_h
+
+int duk_libdom_output(struct interface_map *interface_map);
+
+#endif
diff --git a/src/interface-map.c b/src/interface-map.c
new file mode 100644
index 0000000..a5a672a
--- /dev/null
+++ b/src/interface-map.c
@@ -0,0 +1,874 @@
+/* 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].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 interface_map_operation_entry *
+find_operation_name(struct interface_map_operation_entry *operationv,
+ int operationc,
+ const char *name)
+{
+ struct interface_map_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 interface_map_operation_argument_entry **argumentv_out)
+{
+ int argumentc;
+ struct webidl_node *argument;
+ struct interface_map_operation_argument_entry *argumentv;
+ struct interface_map_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 interface_map_operation_overload_entry **overloadv_out)
+{
+ int overloadc = *overloadc_out;
+ struct interface_map_operation_overload_entry *overloadv;
+ struct interface_map_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 interface_map_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 interface_map_operation_entry **operationv_out)
+{
+ struct webidl_node *list_node;
+ struct webidl_node *op_node; /* attribute node */
+ struct interface_map_operation_entry *cure; /* current entry */
+ struct interface_map_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 interface_map_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 interface_map_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 interface_map_attribute_entry **attributev_out)
+{
+ struct webidl_node *list_node;
+ struct webidl_node *at_node; /* attribute node */
+ struct interface_map_attribute_entry *cure; /* current entry */
+ struct interface_map_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 interface_map_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 interface_map_constant_entry **constantv_out)
+{
+ struct webidl_node *list_node;
+ struct webidl_node *constant_node; /* constant node */
+ struct interface_map_constant_entry *cure; /* current entry */
+ struct interface_map_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 interface_map_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 interface_map_new(struct genbind_node *genbind,
+ struct webidl_node *webidl,
+ struct interface_map **map_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 *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 interface_map_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_INTERFACE_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 interface_map));
+ map->entryc = interfacec;
+ map->entries = sorted_entries;
+ map->webidl = webidl;
+ map->binding_node = genbind_node_find_type(genbind, NULL,
+ GENBIND_NODE_TYPE_BINDING);
+
+ *map_out = map;
+
+ return 0;
+}
+
+int interface_map_dump(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-map", "w");
+ if (dumpf == NULL) {
+ return 2;
+ }
+
+ ecur = index->entries;
+ for (eidx = 0; eidx < index->entryc; 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 interface_map_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 interface_map_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 interface_map_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 interface_map_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 interface_map_constant_entry *cone;
+ cone = ecur->constantv + idx;
+ fprintf(dumpf, "\t\t%s\n",
+ cone->name);
+ }
+ }
+ 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");
+
+ fprintf(dumpf, "node [shape=box]\n");
+
+ ecur = index->entries;
+ for (eidx = 0; eidx < index->entryc; 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->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;
+}
+
+struct interface_map_entry *
+interface_map_inherit_entry(struct interface_map *map,
+ struct interface_map_entry *entry)
+{
+ struct interface_map_entry *res = NULL;
+
+ if ((entry != NULL) &&
+ (entry->inherit_idx != -1)) {
+ res = &map->entries[entry->inherit_idx];
+ }
+ return res;
+}
diff --git a/src/interface-map.h b/src/interface-map.h
new file mode 100644
index 0000000..5f1926e
--- /dev/null
+++ b/src/interface-map.h
@@ -0,0 +1,141 @@
+/* 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;
+
+/**
+ *map entry for each argument of an overload on an operation
+ */
+struct interface_map_operation_argument_entry {
+ const char *name;
+
+ int optionalc; /**< Number of parameters that are optional */
+ int elipsisc; /**< Number of elipsis parameters */
+
+ struct webidl_node *node;
+};
+
+/** map entry for each overload of an operation */
+struct interface_map_operation_overload_entry {
+ struct webidl_node *type; /**< The return type of this overload */
+
+ int optionalc; /**< Number of parameters that are optional */
+ int elipsisc; /**< Number of elipsis parameters */
+
+ int argumentc; /**< the number of parameters */
+ struct interface_map_operation_argument_entry *argumentv;
+};
+
+/** map entry for operations on an interface */
+struct interface_map_operation_entry {
+ const char *name; /** operation name */
+ struct webidl_node *node; /**< AST operation node */
+ struct genbind_node *method; /**< method from binding */
+
+ int overloadc; /**< Number of overloads of this operation */
+ struct interface_map_operation_overload_entry *overloadv;
+};
+
+/** map entry for attributes on an interface */
+struct interface_map_attribute_entry {
+ const char *name; /** attribute name */
+ struct webidl_node *node; /**< AST attribute node */
+ enum webidl_type_modifier modifier;
+ struct genbind_node *getter; /**< getter from binding */
+ struct genbind_node *setter; /**< getter from binding */
+};
+
+/** map entry for constants on an interface */
+struct interface_map_constant_entry {
+ const char *name; /** attribute name */
+ struct webidl_node *node; /**< AST constant node */
+};
+
+/** map entry for an interface */
+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 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
+ */
+ bool noobject; /**< flag indicating if no interface object should eb
+ * generated. This allows for interfaces which do not
+ * generate code. For implements (mixin) interfaces
+ */
+ bool primary_global; /**< flag indicating the interface is the primary
+ * global javascript object.
+ */
+
+ int operationc; /**< number of operations on interface */
+ struct interface_map_operation_entry *operationv;
+
+ int attributec; /**< number of attributes on interface */
+ struct interface_map_attribute_entry *attributev;
+
+ int constantc; /**< number of constants on interface */
+ struct interface_map_constant_entry *constantv;
+
+
+ struct genbind_node *class; /**< class from binding (if any) */
+
+ /* The variables are created and used by the output generation but
+ * rtaher than have another allocation and pointer the data they are
+ * just inline here.
+ */
+
+ char *filename; /**< filename used for output */
+
+ char *class_name; /**< the interface name converted to output
+ * appropriate value. e.g. generators targetting c
+ * might lowercase the name or add underscores
+ * instead of caps
+ */
+ int class_init_argc; /**< The number of parameters on the class
+ * initializer.
+ */
+};
+
+/** WebIDL interface map */
+struct interface_map {
+ int entryc; /**< count of interfaces */
+ struct interface_map_entry *entries; /**< interface entries */
+
+ /** The AST node of the binding information */
+ struct genbind_node *binding_node;
+
+ /** Root AST node of the webIDL */
+ struct webidl_node *webidl;
+};
+
+/**
+ * Create a new interface map
+ */
+int interface_map_new(struct genbind_node *genbind,
+ struct webidl_node *webidl,
+ struct interface_map **map_out);
+
+int interface_map_dump(struct interface_map *map);
+
+int interface_map_dumpdot(struct interface_map *map);
+
+/**
+ * interface map parent entry
+ *
+ * \return inherit entry or NULL if there is not one
+ */
+struct interface_map_entry *interface_map_inherit_entry(struct interface_map *map, struct interface_map_entry *entry);
+
+#endif
diff --git a/src/jsapi-libdom-const.c b/src/jsapi-libdom-const.c
deleted file mode 100644
index ac728c7..0000000
--- a/src/jsapi-libdom-const.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* const property generation
- *
- * 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>
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "options.h"
-#include "nsgenbind-ast.h"
-#include "webidl-ast.h"
-#include "jsapi-libdom.h"
-
-static int output_cast_literal(struct binding *binding,
- struct webidl_node *node)
-{
- struct webidl_node *type_node = NULL;
- struct webidl_node *literal_node = NULL;
- struct webidl_node *type_base = NULL;
- enum webidl_type webidl_arg_type;
-
- type_node = webidl_node_find_type(webidl_node_getnode(node),
- NULL,
- WEBIDL_NODE_TYPE_TYPE);
-
- type_base = webidl_node_find_type(webidl_node_getnode(type_node),
- NULL,
- WEBIDL_NODE_TYPE_TYPE_BASE);
-
- webidl_arg_type = webidl_node_getint(type_base);
-
- switch (webidl_arg_type) {
-
- case WEBIDL_TYPE_BOOL:
- /* JSBool */
- literal_node = webidl_node_find_type(webidl_node_getnode(node),
- NULL,
- WEBIDL_NODE_TYPE_LITERAL_BOOL);
- fprintf(binding->outfile, "BOOLEAN_TO_JSVAL(JS_FALSE)");
- break;
-
- case WEBIDL_TYPE_FLOAT:
- case WEBIDL_TYPE_DOUBLE:
- /* double */
- literal_node = webidl_node_find_type(webidl_node_getnode(node),
- NULL,
- WEBIDL_NODE_TYPE_LITERAL_FLOAT);
- fprintf(binding->outfile, "DOUBLE_TO_JSVAL(0.0)");
- break;
-
- case WEBIDL_TYPE_LONG:
- /* int32_t */
- literal_node = webidl_node_find_type(webidl_node_getnode(node),
- NULL,
- WEBIDL_NODE_TYPE_LITERAL_INT);
- fprintf(binding->outfile,
- "INT_TO_JSVAL(%d)",
- webidl_node_getint(literal_node));
- break;
-
- case WEBIDL_TYPE_SHORT:
- /* int16_t */
- literal_node = webidl_node_find_type(webidl_node_getnode(node),
- NULL,
- WEBIDL_NODE_TYPE_LITERAL_INT);
- fprintf(binding->outfile,
- "INT_TO_JSVAL(%d)",
- webidl_node_getint(literal_node));
- break;
-
-
- case WEBIDL_TYPE_STRING:
- case WEBIDL_TYPE_BYTE:
- case WEBIDL_TYPE_OCTET:
- case WEBIDL_TYPE_LONGLONG:
- case WEBIDL_TYPE_SEQUENCE:
- case WEBIDL_TYPE_OBJECT:
- case WEBIDL_TYPE_DATE:
- case WEBIDL_TYPE_VOID:
- case WEBIDL_TYPE_USER:
- default:
- WARN(WARNING_UNIMPLEMENTED, "types not allowed as literal");
- break; /* @todo these types are not allowed here */
- }
-
- return 0;
-}
-
-static int webidl_const_define_cb(struct webidl_node *node, void *ctx)
-{
- struct binding *binding = ctx;
- struct webidl_node *ident_node;
-
- ident_node = webidl_node_find_type(webidl_node_getnode(node),
- NULL,
- WEBIDL_NODE_TYPE_IDENT);
- if (ident_node == NULL) {
- /* Broken AST - must have ident */
- return 1;
- }
-
- fprintf(binding->outfile,
- "\tJS_DefineProperty(cx,\n"
- "\t\tprototype,\n"
- "\t\t\"%s\",\n"
- "\t\t",
- 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");
-
- return 0;
-
-}
-
-
-/* callback to emit implements property spec */
-static int webidl_const_spec_implements_cb(struct webidl_node *node, void *ctx)
-{
- struct binding *binding = ctx;
-
- return output_const_defines(binding, webidl_node_gettext(node));
-}
-
-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;
-
- /* find interface in webidl with correct ident attached */
- interface_node = webidl_node_find_type_ident(binding->wi_ast,
- WEBIDL_NODE_TYPE_INTERFACE,
- interface);
-
- if (interface_node == NULL) {
- fprintf(stderr,
- "Unable to find interface %s in loaded WebIDL\n",
- 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);
-
-
- 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);
-
- if (inherit_node != NULL) {
- res = output_const_defines(binding,
- 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);
- }
-
- return res;
-}
diff --git a/src/jsapi-libdom-operator.c b/src/jsapi-libdom-function.c
index 1d16afe..4f62bcd 100644
--- a/src/jsapi-libdom-operator.c
+++ b/src/jsapi-libdom-function.c
@@ -1,4 +1,4 @@
-/* function/operator generation
+/* jsapi function generation for webidl bodies
*
* This file is part of nsgenbind.
* Licensed under the MIT License,
@@ -17,113 +17,85 @@
#include "webidl-ast.h"
#include "jsapi-libdom.h"
-static int webidl_func_spec_cb(struct webidl_node *node, void *ctx)
+static int webidl_operator_spec(struct binding *binding,
+ struct binding_interface *inf,
+ struct webidl_node *node)
{
- struct binding *binding = ctx;
struct webidl_node *ident_node;
- ident_node = webidl_node_find(webidl_node_getnode(node),
- NULL,
- webidl_cmp_node_type,
- (void *)WEBIDL_NODE_TYPE_IDENT);
-
+ ident_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT);
if (ident_node == NULL) {
/* operation without identifier - must have special keyword
* http://www.w3.org/TR/WebIDL/#idl-operations
*/
} else {
fprintf(binding->outfile,
- "\tJSAPI_FS(%s, 0, JSPROP_ENUMERATE ),\n",
+ "\tJSAPI_FS(%s, %s, 0, JSPROP_ENUMERATE ),\n",
+ inf->name,
webidl_node_gettext(ident_node));
/* @todo number of args to that FN_FS() call should be correct */
}
return 0;
}
-
-static int generate_function_spec(struct binding *binding, const char *interface);
-
-/* callback to emit implements operator spec */
-static int webidl_function_spec_implements_cb(struct webidl_node *node, void *ctx)
+int output_function_spec(struct binding *binding)
{
- struct binding *binding = ctx;
+ int inf;
+ int res;
+ struct webidl_node *list_node;
+ struct webidl_node *op_node; /* operation on list node */
- return generate_function_spec(binding, webidl_node_gettext(node));
-}
+ /* generate functions for each interface in the map */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ if (binding->interfaces[inf].own_functions == 0) {
+ continue;
+ }
-static int
-generate_function_spec(struct binding *binding, const char *interface)
-{
- struct webidl_node *interface_node;
- struct webidl_node *members_node;
- struct webidl_node *inherit_node;
- int res = 0;
-
- /* find interface in webidl with correct ident attached */
- interface_node = webidl_node_find_type_ident(binding->wi_ast,
- WEBIDL_NODE_TYPE_INTERFACE,
- interface);
-
- if (interface_node == NULL) {
- fprintf(stderr,
- "Unable to find interface %s in loaded WebIDL\n",
- interface);
- return -1;
- }
+ fprintf(binding->outfile,
+ "static JSFunctionSpec JSClass_%s_functions[] = {\n",
+ binding->interfaces[inf].name);
+
+ /* iterate each list within an interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through operations in a list */
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_OPERATION);
+
+ while (op_node != NULL) {
+ res = webidl_operator_spec(
+ binding,
+ &binding->interfaces[inf],
+ op_node);
+ if (res != 0) {
+ return res;
+ }
+
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ op_node,
+ WEBIDL_NODE_TYPE_OPERATION);
+ }
- members_node = webidl_node_find(webidl_node_getnode(interface_node),
- NULL,
- webidl_cmp_node_type,
- (void *)WEBIDL_NODE_TYPE_LIST);
- while (members_node != NULL) {
-
- fprintf(binding->outfile,"\t/**** %s ****/\n", interface);
-
- /* for each function emit a JSAPI_FS()*/
- webidl_node_for_each_type(webidl_node_getnode(members_node),
- WEBIDL_NODE_TYPE_OPERATION,
- webidl_func_spec_cb,
- binding);
-
- members_node = webidl_node_find(webidl_node_getnode(interface_node),
- members_node,
- webidl_cmp_node_type,
- (void *)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);
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
- if (inherit_node != NULL) {
- res = generate_function_spec(binding,
- webidl_node_gettext(inherit_node));
- }
+ fprintf(binding->outfile, "\tJSAPI_FS_END\n};\n\n");
- if (res == 0) {
- res = webidl_node_for_each_type(webidl_node_getnode(interface_node),
- WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS,
- webidl_function_spec_implements_cb,
- binding);
}
-
- return res;
-}
-
-int output_function_spec(struct binding *binding)
-{
- int res;
-
- fprintf(binding->outfile,
- "static JSFunctionSpec jsclass_functions[] = {\n");
-
- res = generate_function_spec(binding, binding->interface);
-
- fprintf(binding->outfile, "\tJSAPI_FS_END\n};\n\n");
-
- return res;
+ return 0;
}
static int output_return(struct binding *binding,
@@ -307,7 +279,7 @@ static int output_return_declaration(struct binding *binding,
break;
case WEBIDL_TYPE_LONGLONG:
- WARN(WARNING_UNIMPLEMENTED,
+ WARN(WARNING_UNIMPLEMENTED,
"Unhandled type WEBIDL_TYPE_LONGLONG");
break;
@@ -316,7 +288,7 @@ static int output_return_declaration(struct binding *binding,
type_mod = webidl_node_find_type(webidl_node_getnode(type_node),
NULL,
WEBIDL_NODE_TYPE_MODIFIER);
- if ((type_mod != NULL) &&
+ if ((type_mod != NULL) &&
(webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) {
fprintf(binding->outfile, "\tuint32_t %s = 0;\n", ident);
} else {
@@ -332,7 +304,7 @@ static int output_return_declaration(struct binding *binding,
break;
case WEBIDL_TYPE_SEQUENCE:
- WARN(WARNING_UNIMPLEMENTED,
+ WARN(WARNING_UNIMPLEMENTED,
"Unhandled type WEBIDL_TYPE_SEQUENCE");
break;
@@ -474,14 +446,14 @@ output_variable_definitions(struct binding *binding,
type_mod = webidl_node_find_type(webidl_node_getnode(arg_type),
NULL,
WEBIDL_NODE_TYPE_MODIFIER);
- if ((type_mod != NULL) &&
+ if ((type_mod != NULL) &&
(webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) {
- fprintf(binding->outfile,
- "\tuint32_t %s = 0;\n",
+ fprintf(binding->outfile,
+ "\tuint32_t %s = 0;\n",
webidl_node_gettext(arg_ident));
} else {
- fprintf(binding->outfile,
- "\tint32_t %s = 0;\n",
+ fprintf(binding->outfile,
+ "\tint32_t %s = 0;\n",
webidl_node_gettext(arg_ident));
}
@@ -624,15 +596,15 @@ output_operation_input(struct binding *binding,
type_mod = webidl_node_find_type(webidl_node_getnode(arg_type),
NULL,
WEBIDL_NODE_TYPE_MODIFIER);
- if ((type_mod != NULL) &&
+ if ((type_mod != NULL) &&
(webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) {
- fprintf(binding->outfile,
- "\tJS_ValueToECMAUint32(cx, argv[%d], &%s);\n",
+ fprintf(binding->outfile,
+ "\tJS_ValueToECMAUint32(cx, argv[%d], &%s);\n",
arg_cur,
webidl_node_gettext(arg_ident));
} else {
- fprintf(binding->outfile,
- "\tJS_ValueToECMAInt32(cx, argv[%d], &%s);\n",
+ fprintf(binding->outfile,
+ "\tJS_ValueToECMAInt32(cx, argv[%d], &%s);\n",
arg_cur,
webidl_node_gettext(arg_ident));
}
@@ -690,14 +662,14 @@ output_operation_input(struct binding *binding,
}
-static int
-output_operator_placeholder(struct binding *binding,
- struct webidl_node *oplist,
+static int
+output_operator_placeholder(struct binding *binding,
+ struct webidl_node *oplist,
struct webidl_node *ident_node)
{
oplist = oplist;
- WARN(WARNING_UNIMPLEMENTED,
+ WARN(WARNING_UNIMPLEMENTED,
"operation %s.%s has no implementation\n",
binding->interface,
webidl_node_gettext(ident_node));
@@ -748,131 +720,118 @@ output_private_get(struct binding *binding, const char *argname)
return ret;
}
-static int webidl_operator_body_cb(struct webidl_node *node, void *ctx)
+/**
+ * Generate operator (function) body
+ *
+ *
+ */
+static int webidl_operator_body(struct binding *binding,
+ struct binding_interface *inf,
+ struct webidl_node *node)
{
- struct binding *binding = ctx;
struct webidl_node *ident_node;
struct genbind_node *operation_node;
- ident_node = webidl_node_find(webidl_node_getnode(node),
- NULL,
- webidl_cmp_node_type,
- (void *)WEBIDL_NODE_TYPE_IDENT);
+ ident_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT);
if (ident_node == NULL) {
/* operation without identifier - must have special keyword
* http://www.w3.org/TR/WebIDL/#idl-operations
*/
WARN(WARNING_UNIMPLEMENTED,
- "Unhandled operation with no name on %s\n",
- binding->interface);
-
- } else {
- /* normal operation with identifier */
+ "Unhandled operation with no name on %s\n",
+ binding->interface);
- fprintf(binding->outfile,
- "static JSBool JSAPI_FUNC(%s, JSContext *cx, uintN argc, jsval *vp)\n",
- webidl_node_gettext(ident_node));
- fprintf(binding->outfile,
- "{\n");
+ return 0;
+ }
- /* return value declaration */
- output_return_declaration(binding, "jsret", webidl_node_getnode(node));
+ /* normal operation with identifier */
- output_variable_definitions(binding, webidl_node_getnode(node));
+ fprintf(binding->outfile,
+ "static JSBool JSAPI_FUNC(%s, %s, JSContext *cx, uintN argc, jsval *vp)\n"
+ "{\n",
+ inf->name,
+ webidl_node_gettext(ident_node));
- output_private_get(binding, "private");
+ /* return value declaration */
+ output_return_declaration(binding, "jsret", webidl_node_getnode(node));
- output_operation_input(binding, webidl_node_getnode(node));
+ output_variable_definitions(binding, webidl_node_getnode(node));
- operation_node = genbind_node_find_type_ident(binding->gb_ast,
- NULL,
- GENBIND_NODE_TYPE_OPERATION,
- webidl_node_gettext(ident_node));
+ output_private_get(binding, "private");
- if (operation_node != NULL) {
- output_code_block(binding,
- genbind_node_getnode(operation_node));
+ output_operation_input(binding, webidl_node_getnode(node));
- } else {
- output_operator_placeholder(binding, webidl_node_getnode(node), ident_node);
- }
+ operation_node = genbind_node_find_type_ident(binding->gb_ast,
+ NULL,
+ GENBIND_NODE_TYPE_OPERATION,
+ webidl_node_gettext(ident_node));
- output_return(binding, "jsret", webidl_node_getnode(node));
+ if (operation_node != NULL) {
+ output_code_block(binding,
+ genbind_node_getnode(operation_node));
- /* set return value an return true */
- fprintf(binding->outfile,
- "\treturn JS_TRUE;\n"
- "}\n\n");
+ } else {
+ output_operator_placeholder(binding, webidl_node_getnode(node), ident_node);
}
- return 0;
-}
-/* callback to emit implements operator bodys */
-static int webidl_implements_cb(struct webidl_node *node, void *ctx)
-{
- struct binding *binding = ctx;
+ output_return(binding, "jsret", webidl_node_getnode(node));
- return output_operator_body(binding, webidl_node_gettext(node));
+ /* set return value an return true */
+ fprintf(binding->outfile,
+ "\treturn JS_TRUE;\n"
+ "}\n\n");
+
+ return 0;
}
+
/* exported interface documented in jsapi-libdom.h */
-int
-output_operator_body(struct binding *binding, const char *interface)
+int output_function_bodies(struct binding *binding)
{
- struct webidl_node *interface_node;
- struct webidl_node *members_node;
- struct webidl_node *inherit_node;
- int res = 0;
-
- /* find interface in webidl with correct ident attached */
- interface_node = webidl_node_find_type_ident(binding->wi_ast,
- WEBIDL_NODE_TYPE_INTERFACE,
- interface);
-
- if (interface_node == NULL) {
- fprintf(stderr,
- "Unable to find interface %s in loaded WebIDL\n",
- interface);
- return -1;
- }
-
- members_node = webidl_node_find(webidl_node_getnode(interface_node),
- NULL,
- webidl_cmp_node_type,
- (void *)WEBIDL_NODE_TYPE_LIST);
- while (members_node != NULL) {
-
- fprintf(binding->outfile,"/**** %s ****/\n", interface);
-
- /* for each function emit a JSAPI_FS()*/
- webidl_node_for_each_type(webidl_node_getnode(members_node),
- WEBIDL_NODE_TYPE_OPERATION,
- webidl_operator_body_cb,
- binding);
-
- members_node = webidl_node_find(webidl_node_getnode(interface_node),
- members_node,
- webidl_cmp_node_type,
- (void *)WEBIDL_NODE_TYPE_LIST);
- }
-
- /* check for inherited nodes and insert them too */
- inherit_node = webidl_node_find_type(webidl_node_getnode(interface_node),
- NULL,
- WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE);
+ int inf;
+ int res;
+ struct webidl_node *list_node;
+ struct webidl_node *op_node; /* operation on list node */
+
+ /* generate functions for each interface in the map */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ /* iterate each list within an interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through operations in a list */
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_OPERATION);
+
+ while (op_node != NULL) {
+ res = webidl_operator_body(
+ binding,
+ &binding->interfaces[inf],
+ op_node);
+ if (res != 0) {
+ return res;
+ }
+
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ op_node,
+ WEBIDL_NODE_TYPE_OPERATION);
+ }
- if (inherit_node != NULL) {
- res = output_operator_body(binding,
- 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_implements_cb,
- binding);
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
}
-
- return res;
+ return 0;
}
diff --git a/src/jsapi-libdom-init.c b/src/jsapi-libdom-init.c
new file mode 100644
index 0000000..1077c2d
--- /dev/null
+++ b/src/jsapi-libdom-init.c
@@ -0,0 +1,286 @@
+/* Javascript spidemonkey API to libdom binding generation for class
+ * initilisation
+ *
+ * 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>
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#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_cast_literal(struct binding *binding,
+ struct webidl_node *node)
+{
+ struct webidl_node *type_node = NULL;
+ struct webidl_node *literal_node = NULL;
+ struct webidl_node *type_base = NULL;
+ enum webidl_type webidl_arg_type;
+
+ type_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_TYPE);
+
+ type_base = webidl_node_find_type(webidl_node_getnode(type_node),
+ NULL,
+ WEBIDL_NODE_TYPE_TYPE_BASE);
+
+ webidl_arg_type = webidl_node_getint(type_base);
+
+ switch (webidl_arg_type) {
+
+ case WEBIDL_TYPE_BOOL:
+ /* JSBool */
+ literal_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_LITERAL_BOOL);
+ fprintf(binding->outfile, "BOOLEAN_TO_JSVAL(JS_FALSE)");
+ break;
+
+ case WEBIDL_TYPE_FLOAT:
+ case WEBIDL_TYPE_DOUBLE:
+ /* double */
+ literal_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_LITERAL_FLOAT);
+ fprintf(binding->outfile, "DOUBLE_TO_JSVAL(0.0)");
+ break;
+
+ case WEBIDL_TYPE_LONG:
+ /* int32_t */
+ literal_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_LITERAL_INT);
+ fprintf(binding->outfile,
+ "INT_TO_JSVAL(%d)",
+ webidl_node_getint(literal_node));
+ break;
+
+ case WEBIDL_TYPE_SHORT:
+ /* int16_t */
+ literal_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_LITERAL_INT);
+ fprintf(binding->outfile,
+ "INT_TO_JSVAL(%d)",
+ webidl_node_getint(literal_node));
+ break;
+
+
+ case WEBIDL_TYPE_STRING:
+ case WEBIDL_TYPE_BYTE:
+ case WEBIDL_TYPE_OCTET:
+ case WEBIDL_TYPE_LONGLONG:
+ case WEBIDL_TYPE_SEQUENCE:
+ case WEBIDL_TYPE_OBJECT:
+ case WEBIDL_TYPE_DATE:
+ case WEBIDL_TYPE_VOID:
+ case WEBIDL_TYPE_USER:
+ default:
+ WARN(WARNING_UNIMPLEMENTED, "types not allowed as literal");
+ break; /* @todo these types are not allowed here */
+ }
+
+ return 0;
+}
+
+static int webidl_const_define_cb(struct webidl_node *node, void *ctx)
+{
+ struct binding *binding = ctx;
+ struct webidl_node *ident_node;
+
+ ident_node = webidl_node_find_type(webidl_node_getnode(node),
+ NULL,
+ WEBIDL_NODE_TYPE_IDENT);
+ if (ident_node == NULL) {
+ /* Broken AST - must have ident */
+ return 1;
+ }
+
+ fprintf(binding->outfile,
+ "\tJS_DefineProperty(cx, "
+ "prototype, "
+ "\"%s\", ",
+ webidl_node_gettext(ident_node));
+
+ output_cast_literal(binding, node);
+
+ fprintf(binding->outfile,
+ ", "
+ "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;
+}
+
+
+static int generate_prototype_init(struct binding *binding, int inf)
+{
+ int inherit_inf;
+
+ /* find this interfaces parent interface to inherit prototype from */
+ inherit_inf = binding->interfaces[inf].inherit_idx;
+ while ((inherit_inf != -1) &&
+ (binding->interfaces[inherit_inf].node == NULL)) {
+ inherit_inf = binding->interfaces[inherit_inf].inherit_idx;
+ }
+
+ fprintf(binding->outfile,
+ "\n"
+ "\tprototype = JS_InitClass(cx, "
+ "parent, ");
+
+ /* either this init is being constructed without a chain or is
+ * using a prototype of a previously initialised class
+ */
+ if (inherit_inf == -1) {
+ fprintf(binding->outfile,
+ "NULL, ");
+ } else {
+ fprintf(binding->outfile,
+ "prototypes[%d], ",
+ binding->interfaces[inherit_inf].output_idx);
+ }
+
+ fprintf(binding->outfile,
+ "&JSClass_%s, "
+ "NULL, "
+ "0, "
+ "NULL, "
+ "NULL, "
+ "NULL, "
+ "NULL);\n",
+ binding->interfaces[inf].name);
+
+ /* check prototype construction */
+ fprintf(binding->outfile,
+ "\tif (prototype == NULL) {\n"
+ "\t\treturn %d;\n"
+ "\t}\n\n",
+ binding->interfaces[inf].output_idx);
+
+ /* store result */
+ fprintf(binding->outfile,
+ "\tprototypes[%d] = prototype;\n",
+ binding->interfaces[inf].output_idx);
+
+ /* output the consts for the interface and ancestors if necessary */
+ do {
+ output_interface_consts(binding, binding->interfaces[inf].widl_node);
+ inf = binding->interfaces[inf].inherit_idx;
+ } while (inf != inherit_inf);
+
+ return 0;
+}
+
+/** 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 {
+ /* generate interface init for each class in binding */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ /* skip generating javascript class
+ * initialisation for interfaces not in binding
+ */
+ if (binding->interfaces[inf].node != NULL) {
+ generate_prototype_init(binding, inf);
+ }
+ }
+
+ fprintf(binding->outfile,
+ "\n\treturn %d;\n",
+ inf);
+ }
+
+ fprintf(binding->outfile, "}\n\n");
+
+ return res;
+}
diff --git a/src/jsapi-libdom-jsclass.c b/src/jsapi-libdom-jsclass.c
new file mode 100644
index 0000000..3a5a84c
--- /dev/null
+++ b/src/jsapi-libdom-jsclass.c
@@ -0,0 +1,180 @@
+/* Javascript spidemonkey API to libdom binding generation for class
+ * initilisation
+ *
+ * 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>
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#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"
+
+#define HDROUTF(bndg, fmt, args...) do { \
+ if (bndg->hdrfile != NULL) { \
+ fprintf(bndg->hdrfile, fmt, ##args); \
+ } \
+ } while(0)
+
+static bool interface_is_global(struct genbind_node *interface_node)
+{
+ if (genbind_node_find_type_ident(
+ genbind_node_getnode(interface_node),
+ NULL,
+ GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS,
+ "global") != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+static int output_jsclass(struct binding *binding,
+ const char *interface_name,
+ struct genbind_node *interface_node)
+{
+ /* output the class declaration */
+ HDROUTF(binding, "JSClass JSClass_%s;\n", interface_name);
+
+ /* output the class definition */
+ fprintf(binding->outfile,
+ "JSClass JSClass_%s = {\n"
+ "\t\"%s\",\n",
+ interface_name,
+ interface_name);
+
+ /* generate class flags */
+ if (interface_is_global(interface_node)) {
+ fprintf(binding->outfile, "\tJSCLASS_GLOBAL_FLAGS");
+ } else {
+ fprintf(binding->outfile, "\t0");
+ }
+
+ if (binding->resolve != NULL) {
+ fprintf(binding->outfile, " | JSCLASS_NEW_RESOLVE");
+ }
+
+ if (binding->mark != NULL) {
+ fprintf(binding->outfile, " | JSAPI_JSCLASS_MARK_IS_TRACE");
+ }
+
+ if (binding->has_private) {
+ fprintf(binding->outfile, " | JSCLASS_HAS_PRIVATE");
+ }
+
+ fprintf(binding->outfile, ",\n");
+
+ /* add property */
+ if (binding->addproperty != NULL) {
+ fprintf(binding->outfile,
+ "\tjsapi_property_add,\t/* addProperty */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_PropertyStub,\t/* addProperty */\n");
+ }
+
+ /* del property */
+ if (binding->delproperty != NULL) {
+ fprintf(binding->outfile,
+ "\tjsapi_property_del,\t/* delProperty */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_PropertyStub,\t/* delProperty */\n");
+ }
+
+ /* get property */
+ if (binding->getproperty != NULL) {
+ fprintf(binding->outfile,
+ "\tjsapi_property_get,\t/* getProperty */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_PropertyStub,\t/* getProperty */\n");
+ }
+
+ /* set property */
+ if (binding->setproperty != NULL) {
+ fprintf(binding->outfile,
+ "\tjsapi_property_set,\t/* setProperty */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_StrictPropertyStub,\t/* setProperty */\n");
+ }
+
+ /* enumerate */
+ if (binding->enumerate != NULL) {
+ fprintf(binding->outfile,
+ "\tjsclass_enumerate,\t/* enumerate */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_EnumerateStub,\t/* enumerate */\n");
+ }
+
+ /* resolver */
+ if (binding->resolve != NULL) {
+ fprintf(binding->outfile,
+ "\t(JSResolveOp)jsclass_resolve,\t/* resolve */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_ResolveStub,\t\t/* resolve */\n");
+ }
+
+ fprintf(binding->outfile, "\tJS_ConvertStub,\t\t/* convert */\n");
+
+ if (binding->has_private || (binding->finalise != NULL)) {
+ fprintf(binding->outfile,
+ "\tjsclass_finalize,\t/* finalizer */\n");
+ } else {
+ fprintf(binding->outfile,
+ "\tJS_FinalizeStub,\t/* finalizer */\n");
+ }
+ fprintf(binding->outfile,
+ "\t0,\t\t\t/* reserved */\n"
+ "\tNULL,\t\t\t/* checkAccess */\n"
+ "\tNULL,\t\t\t/* call */\n"
+ "\tNULL,\t\t\t/* construct */\n"
+ "\tNULL,\t\t\t/* xdr Object */\n"
+ "\tNULL,\t\t\t/* hasInstance */\n");
+
+ /* trace/mark */
+ if (binding->mark != NULL) {
+ fprintf(binding->outfile,
+ "\tJSAPI_JSCLASS_MARKOP(jsclass_mark),\n");
+ } else {
+ fprintf(binding->outfile, "\tNULL,\t\t\t/* trace/mark */\n");
+ }
+
+ fprintf(binding->outfile,
+ "\tJSAPI_CLASS_NO_INTERNAL_MEMBERS\n"
+ "};\n\n");
+
+ return 0;
+}
+
+int
+output_jsclasses(struct binding *binding)
+{
+ int inf;
+
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ /* skip generating javascript classes for interfaces
+ * not in binding
+ */
+ if (binding->interfaces[inf].node == NULL) {
+ continue;
+ }
+
+ output_jsclass(binding,
+ binding->interfaces[inf].name,
+ binding->interfaces[inf].node);
+ }
+ return 0;
+}
diff --git a/src/jsapi-libdom-new.c b/src/jsapi-libdom-new.c
new file mode 100644
index 0000000..b78c715
--- /dev/null
+++ b/src/jsapi-libdom-new.c
@@ -0,0 +1,395 @@
+/* Spidemonkey Javascript API to libdom binding generation for class
+ * construction.
+ *
+ * This file is part of nsgenbind.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2013 Vincent Sanders <vince@netsurf-browser.org>
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#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 webidl_private_param_cb(struct genbind_node *node, void *ctx)
+{
+ struct binding *binding = ctx;
+ struct genbind_node *ident_node;
+ struct genbind_node *type_node;
+
+
+ ident_node = genbind_node_find_type(genbind_node_getnode(node),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT);
+ if (ident_node == NULL)
+ return -1; /* bad AST */
+
+ type_node = genbind_node_find_type(genbind_node_getnode(node),
+ NULL,
+ GENBIND_NODE_TYPE_STRING);
+ if (type_node == NULL)
+ return -1; /* bad AST */
+
+ fprintf(binding->outfile,
+ ",\n\t\t%s%s",
+ genbind_node_gettext(type_node),
+ genbind_node_gettext(ident_node));
+
+ return 0;
+}
+
+static int webidl_private_assign_cb(struct genbind_node *node, void *ctx)
+{
+ struct binding *binding = ctx;
+ struct genbind_node *ident_node;
+ const char *ident;
+
+ ident_node = genbind_node_find_type(genbind_node_getnode(node),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT);
+ if (ident_node == NULL)
+ return -1; /* bad AST */
+
+ ident = genbind_node_gettext(ident_node);
+
+ fprintf(binding->outfile, "\tprivate->%s = %s;\n", ident, ident);
+
+ return 0;
+}
+
+
+
+static int
+output_binding_constructor(struct binding *binding)
+{
+ fprintf(binding->outfile,
+ "JSObject *jsapi_new_%s(JSContext *cx, \n",
+ binding->name);
+
+ fprintf(binding->outfile, "\t\tJSObject *prototype, \n");
+
+ if (binding->interfacec != 1) {
+ fprintf(binding->outfile, "\t\tconst char *interface_name, \n");
+ }
+
+ fprintf(binding->outfile, "\t\tJSObject *parent");
+
+ genbind_node_foreach_type(binding->binding_list,
+ GENBIND_NODE_TYPE_BINDING_PRIVATE,
+ webidl_private_param_cb,
+ binding);
+
+ fprintf(binding->outfile, ")");
+
+ return 0;
+}
+
+static int
+output_class_wprivate_multi(struct binding *binding)
+{
+ int inf;
+
+ /* create and initialise private data */
+ fprintf(binding->outfile,
+ "\tstruct jsclass_private *private;\n"
+ "\n"
+ "\tprivate = malloc(sizeof(struct jsclass_private));\n"
+ "\tif (private == NULL) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n");
+
+ genbind_node_foreach_type(binding->binding_list,
+ GENBIND_NODE_TYPE_BINDING_PRIVATE,
+ webidl_private_assign_cb,
+ binding);
+
+
+ fprintf(binding->outfile, "\n\n\t");
+
+ /* for each interface in the map generate initialisor */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+
+ fprintf(binding->outfile,
+ "if (strcmp(interface_name, JSClass_%s.name) == 0) {\n",
+ binding->interfaces[inf].name);
+
+ fprintf(binding->outfile,
+ "\n"
+ "\t\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n",
+ binding->interface);
+
+
+ fprintf(binding->outfile,
+ "\t\tif (newobject == NULL) {\n"
+ "\t\t\tfree(private);\n"
+ "\t\t\treturn NULL;\n"
+ "\t\t}\n\n");
+
+ /* root object to stop it being garbage collected */
+ fprintf(binding->outfile,
+ "\t\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n"
+ "\t\t\tfree(private);\n"
+ "\t\t\treturn NULL;\n"
+ "\t\t}\n\n");
+
+ fprintf(binding->outfile,
+ "\n"
+ "\t\t/* attach private pointer */\n"
+ "\t\tif (JS_SetPrivate(cx, newobject, private) != JS_TRUE) {\n"
+ "\t\t\tfree(private);\n"
+ "\t\t\treturn NULL;\n"
+ "\t\t}\n\n");
+
+
+ /* attach operations and attributes (functions and properties) */
+ fprintf(binding->outfile,
+ "\t\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n"
+ "\t\t\tfree(private);\n"
+ "\t\t\treturn NULL;\n"
+ "\t\t}\n\n");
+
+ fprintf(binding->outfile,
+ "\t\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n"
+ "\t\t\tfree(private);\n"
+ "\t\t\treturn NULL;\n"
+ "\t\t}\n\n");
+
+ /* unroot object */
+ fprintf(binding->outfile,
+ "\t\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n"
+ "\t} else ");
+ }
+ fprintf(binding->outfile,
+ "{\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n");
+
+ return 0;
+}
+
+static int
+output_class_wprivate(struct binding *binding, struct genbind_node *api_node)
+{
+ /* create and initialise private data */
+ fprintf(binding->outfile,
+ "\tstruct jsclass_private *private;\n"
+ "\n"
+ "\tprivate = malloc(sizeof(struct jsclass_private));\n"
+ "\tif (private == NULL) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n");
+
+ genbind_node_foreach_type(binding->binding_list,
+ GENBIND_NODE_TYPE_BINDING_PRIVATE,
+ webidl_private_assign_cb,
+ binding);
+
+ if (api_node != NULL) {
+ output_code_block(binding, genbind_node_getnode(api_node));
+ } else {
+ fprintf(binding->outfile,
+ "\n"
+ "\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n",
+ binding->interface);
+ }
+
+ fprintf(binding->outfile,
+ "\tif (newobject == NULL) {\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ /* root object to stop it being garbage collected */
+ fprintf(binding->outfile,
+ "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ fprintf(binding->outfile,
+ "\n"
+ "\t/* attach private pointer */\n"
+ "\tif (JS_SetPrivate(cx, newobject, private) != JS_TRUE) {\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+
+ /* attach operations and attributes (functions and properties) */
+ fprintf(binding->outfile,
+ "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ fprintf(binding->outfile,
+ "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ /* unroot object */
+ fprintf(binding->outfile,
+ "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n");
+
+ return 0;
+}
+
+static int
+output_class_woprivate_multi(struct binding *binding)
+{
+ int inf;
+
+ fprintf(binding->outfile, "\n\t");
+
+ /* for each interface in the map generate initialisor */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ fprintf(binding->outfile,
+ "if (strcmp(interface_name, JSClass_%s.name) == 0) {\n",
+ binding->interfaces[inf].name);
+
+ fprintf(binding->outfile,
+ "\t\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n",
+ binding->interface);
+
+
+ fprintf(binding->outfile,
+ "\tif (newobject == NULL) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n");
+
+ /* root object to stop it being garbage collected */
+ fprintf(binding->outfile,
+ "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ /* attach operations and attributes (functions and properties) */
+ fprintf(binding->outfile,
+ "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ fprintf(binding->outfile,
+ "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ /* unroot object */
+ fprintf(binding->outfile,
+ "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n");
+
+ }
+ fprintf(binding->outfile,
+ "{\n"
+ "\t\tfree(private);\n"
+ "\t\treturn NULL;\n"
+ "\t}\n");
+
+
+ return 0;
+}
+
+static int
+output_class_woprivate(struct binding *binding, struct genbind_node *api_node)
+{
+
+ if (api_node != NULL) {
+ output_code_block(binding, genbind_node_getnode(api_node));
+ } else {
+ fprintf(binding->outfile,
+ "\n"
+ "\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n",
+ binding->interface);
+
+ }
+
+ fprintf(binding->outfile,
+ "\tif (newobject == NULL) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n");
+
+ /* root object to stop it being garbage collected */
+ fprintf(binding->outfile,
+ "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ /* attach operations and attributes (functions and properties) */
+ fprintf(binding->outfile,
+ "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ fprintf(binding->outfile,
+ "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n"
+ "\t\treturn NULL;\n"
+ "\t}\n\n");
+
+ /* unroot object */
+ fprintf(binding->outfile,
+ "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n");
+
+ return 0;
+}
+
+int
+output_class_new(struct binding *binding)
+{
+ int res = 0;
+ struct genbind_node *api_node;
+
+ /* constructor declaration */
+ if (binding->hdrfile) {
+ binding->outfile = binding->hdrfile;
+
+ output_binding_constructor(binding);
+
+ fprintf(binding->outfile, ";\n");
+
+ binding->outfile = binding->srcfile;
+ }
+
+ /* constructor definition */
+ output_binding_constructor(binding);
+
+ fprintf(binding->outfile,
+ "\n{\n"
+ "\tJSObject *newobject;\n");
+
+ api_node = genbind_node_find_type_ident(binding->gb_ast,
+ NULL,
+ GENBIND_NODE_TYPE_API,
+ "new");
+
+ /* generate correct constructor body */
+ if (binding->has_private) {
+ if ((binding->interfacec == 1) || (api_node != NULL)) {
+ res = output_class_wprivate(binding, api_node);
+ } else {
+ res = output_class_wprivate_multi(binding);
+ }
+ } else {
+ if ((binding->interfacec == 1) || (api_node != NULL)) {
+ res = output_class_woprivate(binding, api_node);
+ } else {
+ res = output_class_woprivate_multi(binding);
+ }
+ }
+
+ /* return newly created object */
+ fprintf(binding->outfile,
+ "\treturn newobject;\n"
+ "}\n");
+
+ return res;
+}
diff --git a/src/jsapi-libdom-property.c b/src/jsapi-libdom-property.c
index 2bd3068..1a6cc33 100644
--- a/src/jsapi-libdom-property.c
+++ b/src/jsapi-libdom-property.c
@@ -19,25 +19,38 @@
static int generate_property_tinyid(struct binding *binding, const char *interface);
static int generate_property_spec(struct binding *binding, const char *interface);
-static int generate_property_body(struct binding *binding, const char *interface);
/* generate context data fetcher if the binding has private data */
static inline int
-output_private_get(struct binding *binding, const char *argname)
+output_private_get(struct binding *binding,
+ struct binding_interface *inf,
+ const char *argname)
{
int ret = 0;
if (binding->has_private) {
ret = fprintf(binding->outfile,
- "\tstruct jsclass_private *%s;\n"
- "\n"
- "\t%s = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n"
- "\tif (%s == NULL) {\n"
- "\t\treturn JS_FALSE;\n"
- "\t}\n\n",
- argname, argname, binding->interface, argname);
+ "\tstruct jsclass_private *%s;\n\n", argname);
+
+ if (inf->refcount == 0) {
+ /* leaf class so use safer getinstance private */
+ ret += fprintf(binding->outfile,
+ "\t%s = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n",
+ argname,
+ inf->name);
+ } else {
+ ret += fprintf(binding->outfile,
+ "\t%s = JS_GetPrivate(obj);\n",
+ argname);
+ }
+
+ ret += fprintf(binding->outfile,
+ "\tif (%s == NULL) {\n"
+ "\t\treturn JS_FALSE;\n"
+ "\t}\n\n",
+ argname);
if (options->dbglog) {
ret += fprintf(binding->outfile,
@@ -108,7 +121,7 @@ output_property_tinyid_get(struct binding *binding, const char *argname)
/******************************** tinyid ********************************/
-static int
+static int
webidl_property_tinyid_cb(struct webidl_node *node, void *ctx)
{
struct binding *binding = ctx;
@@ -131,14 +144,6 @@ webidl_property_tinyid_cb(struct webidl_node *node, void *ctx)
return 0;
}
-/* callback to emit implements property spec */
-static int
-webidl_property_tinyid_implements_cb(struct webidl_node *node, void *ctx)
-{
- struct binding *binding = ctx;
-
- return generate_property_tinyid(binding, webidl_node_gettext(node));
-}
static int
generate_property_tinyid(struct binding *binding, const char *interface)
@@ -190,13 +195,6 @@ generate_property_tinyid(struct binding *binding, const char *interface)
res = generate_property_tinyid(binding, 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_property_tinyid_implements_cb,
- binding);
- }
-
return res;
}
@@ -211,7 +209,7 @@ output_property_tinyid(struct binding *binding)
res = generate_property_tinyid(binding, binding->interface);
- fprintf(binding->outfile,
+ fprintf(binding->outfile,
"\tJSAPI_PROP_TINYID_END,\n"
"};\n\n");
@@ -229,6 +227,7 @@ get_binding_shared_modifier(struct binding *binding, const char *type, const cha
{
struct genbind_node *shared_node;
struct genbind_node *shared_mod_node;
+ enum genbind_type_modifier *shared_modifier;
/* look for node matching the ident first */
shared_node = genbind_node_find_type_ident(binding->binding_list,
@@ -251,9 +250,11 @@ get_binding_shared_modifier(struct binding *binding, const char *type, const cha
shared_mod_node = genbind_node_find_type(genbind_node_getnode(shared_node),
NULL,
GENBIND_NODE_TYPE_MODIFIER);
- if (shared_mod_node != NULL) {
- return genbind_node_getint(shared_mod_node);
+ shared_modifier = (enum genbind_type_modifier *)genbind_node_getint(shared_mod_node);
+ if (shared_modifier != NULL) {
+ return *shared_modifier;
}
+
}
return GENBIND_TYPE_NONE;
}
@@ -333,14 +334,15 @@ static bool property_is_ro(struct webidl_node *node)
return false;
}
-static int webidl_property_spec_cb(struct webidl_node *node, void *ctx)
+static int webidl_property_spec(struct binding *binding,
+ struct binding_interface *inf,
+ struct webidl_node *node)
{
- struct binding *binding = ctx;
-
struct webidl_node *type_node;
const char *type = NULL;
struct webidl_node *ident_node;
const char *ident;
+ bool ro = false;
ident_node = webidl_node_find_type(webidl_node_getnode(node),
NULL,
@@ -368,11 +370,10 @@ static int webidl_property_spec_cb(struct webidl_node *node, void *ctx)
/* if there is a putforwards the property requires a setter */
if ((property_is_ro(node)) &&
(get_keyval_extended_attribute(node, "PutForwards") == NULL)) {
- fprintf(binding->outfile, "\tJSAPI_PS_RO(\"%s\",\n", ident);
- } else {
- fprintf(binding->outfile, "\tJSAPI_PS(\"%s\",\n", ident);
+ ro = true;
}
+
/* generate property shared status */
switch (get_binding_shared_modifier(binding, type, ident)) {
@@ -384,133 +385,109 @@ static int webidl_property_spec_cb(struct webidl_node *node, void *ctx)
* perform all GC management.
*/
fprintf(binding->outfile,
- "\t\t%s,\n"
- "\t\tJSAPI_PROP_TINYID_%s,\n"
- "\t\tJSPROP_SHARED | ",
- ident,
+ "\tJSAPI_PS_%s(%s, %s, JSPROP_SHARED),\n",
+ ro?"RO":"RW",
+ inf->name,
ident);
break;
case GENBIND_TYPE_TYPE:
/* shared property with a type handler */
fprintf(binding->outfile,
- "\t\t%s,\n"
- "\t\tJSAPI_PROP_TINYID_%s,\n"
- "\t\tJSPROP_SHARED | ",
- type,
- ident);
+ "\tJSAPI_PS_ID_%s(%s, %s, JSPROP_SHARED, %s),\n",
+ ro?"RO":"RW",
+ inf->name,
+ ident,
+ type);
break;
case GENBIND_TYPE_UNSHARED:
/* unshared property without type handler */
- fprintf(binding->outfile,
- "\t\t%s,\n"
- "\t\tJSAPI_PROP_TINYID_%s,\n"
- "\t\t",
- ident, ident);
+ fprintf(binding->outfile,
+ "\tJSAPI_PS_%s(%s, %s, 0),\n",
+ ro?"RO":"RW",
+ inf->name,
+ ident);
break;
case GENBIND_TYPE_TYPE_UNSHARED:
/* unshared property with a type handler */
- fprintf(binding->outfile,
- "\t\t%s,\n"
- "\t\tJSAPI_PROP_TINYID_%s,\n"
- "\t\t",
- type, ident);
+ fprintf(binding->outfile,
+ "\tJSAPI_PS_ID_%s(%s, %s, 0, %s),\n",
+ ro?"RO":"RW",
+ inf->name,
+ ident,
+ type);
break;
}
- fprintf(binding->outfile, "JSPROP_ENUMERATE),\n");
return 0;
}
-/* callback to emit implements property spec */
-static int webidl_property_spec_implements_cb(struct webidl_node *node, void *ctx)
-{
- struct binding *binding = ctx;
-
- return generate_property_spec(binding, webidl_node_gettext(node));
-}
-
-static int
-generate_property_spec(struct binding *binding, const char *interface)
-{
- struct webidl_node *interface_node;
- struct webidl_node *members_node;
- struct webidl_node *inherit_node;
- int res = 0;
-
- /* find interface in webidl with correct ident attached */
- interface_node = webidl_node_find_type_ident(binding->wi_ast,
- WEBIDL_NODE_TYPE_INTERFACE,
- interface);
-
- if (interface_node == NULL) {
- fprintf(stderr,
- "Unable to find interface %s in loaded WebIDL\n",
- 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 property emit a JSAPI_PS() */
- webidl_node_for_each_type(webidl_node_getnode(members_node),
- WEBIDL_NODE_TYPE_ATTRIBUTE,
- webidl_property_spec_cb,
- binding);
-
- 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);
-
- if (inherit_node != NULL) {
- res = generate_property_spec(binding,
- 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_property_spec_implements_cb,
- binding);
- }
-
- return res;
-}
-
-
-
/* exported interface documented in jsapi-libdom.h */
int
output_property_spec(struct binding *binding)
{
+ int inf;
int res;
+ struct webidl_node *list_node;
+ struct webidl_node *op_node; /* operation on list node */
+
+ /* for each interface in the map */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ if (binding->interfaces[inf].own_properties == 0) {
+ /* if the interface has no properties then
+ * there is nothing to generate.
+ */
+ continue;
+ }
+
+ /* generate property specifier */
+ fprintf(binding->outfile,
+ "static JSPropertySpec JSClass_%s_properties[] = {\n",
+ binding->interfaces[inf].name);
+
+ /* iterate each list within an interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through operations in a list */
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+
+ while (op_node != NULL) {
+ res = webidl_property_spec(
+ binding,
+ &binding->interfaces[inf],
+ op_node);
+ if (res != 0) {
+ return res;
+ }
+
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ op_node,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+ }
- fprintf(binding->outfile,
- "static JSPropertySpec jsclass_properties[] = {\n");
- res = generate_property_spec(binding, binding->interface);
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
- fprintf(binding->outfile, "\tJSAPI_PS_END\n};\n\n");
+ fprintf(binding->outfile, "\tJSAPI_PS_END\n};\n\n");
- return res;
+ }
+ return 0;
}
@@ -760,6 +737,7 @@ static int output_return_declaration(struct binding *binding,
static int
output_property_placeholder(struct binding *binding,
+ struct binding_interface *inf,
struct webidl_node* oplist,
const char *ident)
{
@@ -767,34 +745,36 @@ output_property_placeholder(struct binding *binding,
WARN(WARNING_UNIMPLEMENTED,
"property %s.%s has no implementation\n",
- binding->interface,
+ inf->name,
ident);
if (options->dbglog) {
fprintf(binding->outfile,
"\tJSLOG(\"property %s.%s has no implementation\");\n",
- binding->interface,
+ inf->name,
ident);
}
return 0;
}
static int output_property_getter(struct binding *binding,
+ struct binding_interface *inf,
struct webidl_node *node,
const char *ident)
{
struct genbind_node *property_node;
fprintf(binding->outfile,
- "static JSBool JSAPI_PROP(%s_get, JSContext *cx, JSObject *obj, jsval *vp)\n"
+ "static JSBool JSAPI_PROP_GET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n"
"{\n",
+ inf->name,
ident);
/* return value declaration */
output_return_declaration(binding, "jsret", node);
- output_private_get(binding, "private");
+ output_private_get(binding, inf, "private");
property_node = genbind_node_find_type_ident(binding->gb_ast,
NULL,
@@ -827,7 +807,7 @@ static int output_property_getter(struct binding *binding,
"\tjsret = private->%s;\n",
ident);
} else {
- output_property_placeholder(binding, node, ident);
+ output_property_placeholder(binding, inf, node, ident);
}
}
@@ -842,8 +822,9 @@ static int output_property_getter(struct binding *binding,
}
static int output_property_setter(struct binding *binding,
+ struct binding_interface *inf,
struct webidl_node *node,
- const char *ident)
+ const char *property_ident)
{
struct genbind_node *property_node;
char *putforwards;
@@ -853,22 +834,23 @@ static int output_property_setter(struct binding *binding,
/* generate a putforwards setter */
fprintf(binding->outfile,
"/* PutForwards setter */\n"
- "static JSBool JSAPI_STRICTPROP(%s_set, JSContext *cx, JSObject *obj, jsval *vp)\n"
+ "static JSBool JSAPI_PROP_SET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n"
"{\n",
- ident);
+ inf->name,
+ property_ident);
fprintf(binding->outfile,
"\tjsval propval;\n"
"\tif (JS_GetProperty(cx, obj, \"%s\", &propval) == JS_TRUE) {\n"
"\t\tJS_SetProperty(cx, JSVAL_TO_OBJECT(propval), \"%s\", vp);\n"
"\t}\n",
- ident, putforwards);
+ property_ident,
+ putforwards);
fprintf(binding->outfile,
"\treturn JS_FALSE; /* disallow the asignment */\n"
"}\n\n");
-
return 0;
}
@@ -880,20 +862,21 @@ static int output_property_setter(struct binding *binding,
property_node = genbind_node_find_type_ident(binding->gb_ast,
NULL,
GENBIND_NODE_TYPE_SETTER,
- ident);
+ property_ident);
fprintf(binding->outfile,
- "static JSBool JSAPI_STRICTPROP(%s_set, JSContext *cx, JSObject *obj, jsval *vp)\n"
+ "static JSBool JSAPI_PROP_SET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n"
"{\n",
- ident);
+ inf->name,
+ property_ident);
- output_private_get(binding, "private");
+ output_private_get(binding, inf, "private");
if (property_node != NULL) {
/* binding source block */
output_code_block(binding, genbind_node_getnode(property_node));
} else {
- output_property_placeholder(binding, node, ident);
+ output_property_placeholder(binding, inf, node, property_ident);
}
fprintf(binding->outfile,
@@ -904,9 +887,13 @@ static int output_property_setter(struct binding *binding,
return 0;
}
-static int webidl_property_body_cb(struct webidl_node *node, void *ctx)
+/**
+ * generate atribute (property) body.
+ */
+static int webidl_property_body(struct binding *binding,
+ struct binding_interface *inf,
+ struct webidl_node *node)
{
- struct binding *binding = ctx;
struct webidl_node *ident_node;
const char *ident;
struct webidl_node *type_node;
@@ -941,93 +928,23 @@ static int webidl_property_body_cb(struct webidl_node *node, void *ctx)
* type handler
*/
if ((shared_mod & GENBIND_TYPE_TYPE) == 0) {
- ret = output_property_setter(binding, node, ident);
+ ret = output_property_setter(binding, inf, node, ident);
if (ret == 0) {
/* property getter */
- ret = output_property_getter(binding, node, ident);
+ ret = output_property_getter(binding, inf, node, ident);
}
}
return ret;
-}
-
-
-/* callback to emit implements property bodys */
-static int webidl_implements_cb(struct webidl_node *node, void *ctx)
-{
- struct binding *binding = ctx;
-
- return generate_property_body(binding, webidl_node_gettext(node));
}
-static int
-generate_property_body(struct binding *binding, const char *interface)
-{
- struct webidl_node *interface_node;
- struct webidl_node *members_node;
- struct webidl_node *inherit_node;
- int res = 0;
-
- /* find interface in webidl with correct ident attached */
- interface_node = webidl_node_find_type_ident(binding->wi_ast,
- WEBIDL_NODE_TYPE_INTERFACE,
- interface);
-
- if (interface_node == NULL) {
- fprintf(stderr,
- "Unable to find interface %s in loaded WebIDL\n",
- interface);
- return -1;
- }
-
- /* generate property bodies */
- members_node = webidl_node_find_type(webidl_node_getnode(interface_node),
- NULL,
- WEBIDL_NODE_TYPE_LIST);
- while (members_node != NULL) {
-
- fprintf(binding->outfile,"/**** %s ****/\n", interface);
-
- /* emit property body */
- webidl_node_for_each_type(webidl_node_getnode(members_node),
- WEBIDL_NODE_TYPE_ATTRIBUTE,
- webidl_property_body_cb,
- binding);
-
-
- 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_type(webidl_node_getnode(interface_node),
- NULL,
- WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE);
-
- if (inherit_node != NULL) {
- res = generate_property_body(binding,
- 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_implements_cb,
- binding);
- }
-
- return res;
-}
-
-
/* setter for type handler */
-static int
-output_property_type_setter(struct binding *binding,
- struct genbind_node *node,
+static int
+output_property_type_setter(struct binding *binding,
+ struct binding_interface *inf,
+ struct genbind_node *node,
const char *type)
{
struct genbind_node *property_node;
@@ -1042,7 +959,7 @@ output_property_type_setter(struct binding *binding,
/* property name vars */
output_property_tinyid_get_vars(binding, "tinyid");
/* context data */
- output_private_get(binding, "private");
+ output_private_get(binding, inf, "private");
/* property name */
output_property_tinyid_get(binding, "tinyid");
@@ -1066,7 +983,10 @@ output_property_type_setter(struct binding *binding,
/* getter for type handlers */
-static int output_property_type_getter(struct binding *binding, struct genbind_node *node, const char *type)
+static int output_property_type_getter(struct binding *binding,
+ struct binding_interface *inf,
+ struct genbind_node *node,
+ const char *type)
{
struct genbind_node *property_node;
node = node;/* currently unused */
@@ -1079,7 +999,7 @@ static int output_property_type_getter(struct binding *binding, struct genbind_n
/* property tinyid vars */
output_property_tinyid_get_vars(binding, "tinyid");
/* context data */
- output_private_get(binding, "private");
+ output_private_get(binding, inf, "private");
/* property tinyid */
output_property_tinyid_get(binding, "tinyid");
@@ -1108,14 +1028,17 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx)
struct genbind_node *ident_node;
const char *type;
struct genbind_node *mod_node;
- enum genbind_type_modifier share_mod;
+ enum genbind_type_modifier *share_mod;
int ret = 0;
+ struct binding_interface *inf;
mod_node = genbind_node_find_type(genbind_node_getnode(node),
NULL,
GENBIND_NODE_TYPE_MODIFIER);
- share_mod = genbind_node_getint(mod_node);
- if ((share_mod & GENBIND_TYPE_TYPE) == GENBIND_TYPE_TYPE) {
+ share_mod = (enum genbind_type_modifier *)genbind_node_getint(mod_node);
+
+ if ((share_mod != NULL) &&
+ ((*share_mod & GENBIND_TYPE_TYPE) == GENBIND_TYPE_TYPE)) {
/* type handler */
ident_node = genbind_node_find_type(genbind_node_getnode(node),
@@ -1123,10 +1046,14 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx)
GENBIND_NODE_TYPE_IDENT);
type = genbind_node_gettext(ident_node);
if (type != NULL) {
- ret = output_property_type_setter(binding, node, type);
+ ret = output_property_type_setter(binding,
+ inf,
+ node,
+ type);
if (ret == 0) {
/* property getter */
ret = output_property_type_getter(binding,
+ inf,
node,
type);
}
@@ -1135,20 +1062,95 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx)
return ret;
}
-/* exported interface documented in jsapi-libdom.h */
-int
-output_property_body(struct binding *binding)
+
+/**
+ * generate atribute (property) type body.
+ *
+ * Output property handler for an entire type of property
+ */
+static int webidl_attribute_typehandler_body(struct binding *binding,
+ struct binding_interface *inf)
{
int res;
- res = generate_property_body(binding, binding->interface);
+ /* check if the interface has any properties with type handlers */
+ if (!inf->has_type_properties) {
+ return 0;
+ }
- if (res == 0) {
- res = genbind_node_for_each_type(binding->binding_list,
+ res = genbind_node_foreach_type(binding->binding_list,
GENBIND_NODE_TYPE_BINDING_PROPERTY,
typehandler_property_cb,
binding);
- }
+
return res;
+
+}
+
+/* exported interface documented in jsapi-libdom.h */
+int
+output_property_body(struct binding *binding)
+{
+ int inf;
+ int res;
+ struct webidl_node *list_node;
+ struct webidl_node *op_node; /* operation on list node */
+
+ /* for each interface in the map */
+ for (inf = 0; inf < binding->interfacec; inf++) {
+ if (binding->interfaces[inf].own_properties == 0) {
+ /* if the interface has no properties then
+ * there is nothing to generate.
+ */
+ continue;
+ }
+
+ /* generate property bodies */
+
+ /* iterate each list within an interface */
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ NULL,
+ WEBIDL_NODE_TYPE_LIST);
+
+ while (list_node != NULL) {
+ /* iterate through operations in a list */
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ NULL,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+
+ while (op_node != NULL) {
+ res = webidl_property_body(
+ binding,
+ &binding->interfaces[inf],
+ op_node);
+ if (res != 0) {
+ return res;
+ }
+
+ op_node = webidl_node_find_type(
+ webidl_node_getnode(list_node),
+ op_node,
+ WEBIDL_NODE_TYPE_ATTRIBUTE);
+ }
+
+
+ list_node = webidl_node_find_type(
+ webidl_node_getnode(binding->interfaces[inf].widl_node),
+ list_node,
+ WEBIDL_NODE_TYPE_LIST);
+ }
+
+ /* generate type handler bodies */
+ res = webidl_attribute_typehandler_body(binding,
+ &binding->interfaces[inf]);
+
+ if (res != 0) {
+ return res;
+ }
+
+ }
+ return 0;
}
diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c
index 7104a83..5e994b9 100644
--- a/src/jsapi-libdom.c
+++ b/src/jsapi-libdom.c
@@ -25,11 +25,6 @@
" * nsgenbind is similar to a compiler is a purely transformative tool which\n" \
" * explicitly makes no copyright claim on this generated output"
-#define HDROUTF(bndg, fmt, args...) do { \
- if (bndg->hdrfile != NULL) { \
- fprintf(bndg->hdrfile, fmt, ##args); \
- } \
- } while(0)
static int webidl_file_cb(struct genbind_node *node, void *ctx)
@@ -47,11 +42,15 @@ read_webidl(struct genbind_node *genbind_ast, struct webidl_node **webidl_ast)
{
int res;
- res = genbind_node_for_each_type(genbind_ast,
+ res = genbind_node_foreach_type(genbind_ast,
GENBIND_NODE_TYPE_WEBIDLFILE,
webidl_file_cb,
webidl_ast);
+ if (res == 0) {
+ res = webidl_intercalate_implements(*webidl_ast);
+ }
+
/* debug dump of web idl AST */
if (options->verbose) {
webidl_ast_dump(*webidl_ast, 0);
@@ -101,7 +100,7 @@ static int webidl_hdrcomments_cb(struct genbind_node *node, void *ctx)
static int webidl_hdrcomment_cb(struct genbind_node *node, void *ctx)
{
- genbind_node_for_each_type(genbind_node_getnode(node),
+ genbind_node_foreach_type(genbind_node_getnode(node),
GENBIND_NODE_TYPE_STRING,
webidl_hdrcomments_cb,
ctx);
@@ -135,51 +134,7 @@ static int webidl_private_cb(struct genbind_node *node, void *ctx)
return 0;
}
-static int webidl_private_param_cb(struct genbind_node *node, void *ctx)
-{
- struct binding *binding = ctx;
- struct genbind_node *ident_node;
- struct genbind_node *type_node;
-
-
- ident_node = genbind_node_find_type(genbind_node_getnode(node),
- NULL,
- GENBIND_NODE_TYPE_IDENT);
- if (ident_node == NULL)
- return -1; /* bad AST */
-
- type_node = genbind_node_find_type(genbind_node_getnode(node),
- NULL,
- GENBIND_NODE_TYPE_STRING);
- if (type_node == NULL)
- return -1; /* bad AST */
-
- fprintf(binding->outfile,
- ",\n\t\t%s%s",
- genbind_node_gettext(type_node),
- genbind_node_gettext(ident_node));
-
- return 0;
-}
-
-static int webidl_private_assign_cb(struct genbind_node *node, void *ctx)
-{
- struct binding *binding = ctx;
- struct genbind_node *ident_node;
- const char *ident;
-
- ident_node = genbind_node_find_type(genbind_node_getnode(node),
- NULL,
- GENBIND_NODE_TYPE_IDENT);
- if (ident_node == NULL)
- return -1; /* bad AST */
-
- ident = genbind_node_gettext(ident_node);
- fprintf(binding->outfile, "\tprivate->%s = %s;\n", ident, ident);
-
- return 0;
-}
/* section output generators */
@@ -187,7 +142,7 @@ static int webidl_private_assign_cb(struct genbind_node *node, void *ctx)
static int
output_epilogue(struct binding *binding)
{
- genbind_node_for_each_type(binding->gb_ast,
+ genbind_node_foreach_type(binding->gb_ast,
GENBIND_NODE_TYPE_EPILOGUE,
webidl_epilogue_cb,
binding);
@@ -211,7 +166,11 @@ output_epilogue(struct binding *binding)
static int
output_prologue(struct binding *binding)
{
- genbind_node_for_each_type(binding->gb_ast,
+ /* forward declare property list */
+ fprintf(binding->outfile,
+ "static JSPropertySpec jsclass_properties[];\n\n");
+
+ genbind_node_foreach_type(binding->gb_ast,
GENBIND_NODE_TYPE_PROLOGUE,
webidl_prologue_cb,
binding);
@@ -285,7 +244,7 @@ output_api_operations(struct binding *binding)
"\n"
"\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n",
binding->interface);
-
+
if (options->dbglog) {
fprintf(binding->outfile,
"\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n");
@@ -320,7 +279,7 @@ output_api_operations(struct binding *binding)
"\n"
"\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n",
binding->interface);
-
+
if (options->dbglog) {
fprintf(binding->outfile,
"\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n");
@@ -355,7 +314,7 @@ output_api_operations(struct binding *binding)
"\n"
"\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n",
binding->interface);
-
+
if (options->dbglog) {
fprintf(binding->outfile,
"\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n");
@@ -390,7 +349,7 @@ output_api_operations(struct binding *binding)
"\n"
"\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n",
binding->interface);
-
+
if (options->dbglog) {
fprintf(binding->outfile,
"\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n");
@@ -527,208 +486,10 @@ 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)
-{
- int res = 0;
- struct genbind_node *api_node;
-
- /* constructor declaration */
- if (binding->hdrfile) {
- binding->outfile = binding->hdrfile;
-
- fprintf(binding->outfile,
- "JSObject *jsapi_new_%s(JSContext *cx,\n"
- "\t\tJSObject *prototype,\n"
- "\t\tJSObject *parent",
- binding->interface);
-
- genbind_node_for_each_type(binding->binding_list,
- GENBIND_NODE_TYPE_BINDING_PRIVATE,
- webidl_private_param_cb,
- binding);
-
- fprintf(binding->outfile, ");");
-
- binding->outfile = binding->srcfile;
- }
-
- /* constructor definition */
- fprintf(binding->outfile,
- "JSObject *jsapi_new_%s(JSContext *cx,\n"
- "\t\tJSObject *prototype,\n"
- "\t\tJSObject *parent",
- binding->interface);
-
- genbind_node_for_each_type(binding->binding_list,
- GENBIND_NODE_TYPE_BINDING_PRIVATE,
- webidl_private_param_cb,
- binding);
-
- fprintf(binding->outfile,
- ")\n"
- "{\n"
- "\tJSObject *newobject;\n");
-
- /* create private data */
- if (binding->has_private) {
- fprintf(binding->outfile,
- "\tstruct jsclass_private *private;\n"
- "\n"
- "\tprivate = malloc(sizeof(struct jsclass_private));\n"
- "\tif (private == NULL) {\n"
- "\t\treturn NULL;\n"
- "\t}\n");
-
- genbind_node_for_each_type(binding->binding_list,
- GENBIND_NODE_TYPE_BINDING_PRIVATE,
- webidl_private_assign_cb,
- binding);
- }
-
- api_node = genbind_node_find_type_ident(binding->gb_ast,
- NULL,
- GENBIND_NODE_TYPE_API,
- "new");
-
- if (api_node != NULL) {
- output_code_block(binding, genbind_node_getnode(api_node));
- } else {
- fprintf(binding->outfile,
- "\n"
- "\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n",
- binding->interface);
- }
-
- if (binding->has_private) {
- fprintf(binding->outfile,
- "\tif (newobject == NULL) {\n"
- "\t\tfree(private);\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
-
- /* root object to stop it being garbage collected */
- fprintf(binding->outfile,
- "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n"
- "\t\tfree(private);\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
-
- fprintf(binding->outfile,
- "\n"
- "\t/* attach private pointer */\n"
- "\tif (JS_SetPrivate(cx, newobject, private) != JS_TRUE) {\n"
- "\t\tfree(private);\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
-
-
- /* attach operations and attributes (functions and properties) */
- fprintf(binding->outfile,
- "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n"
- "\t\tfree(private);\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
-
- fprintf(binding->outfile,
- "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n"
- "\t\tfree(private);\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
- } else {
- fprintf(binding->outfile,
- "\tif (newobject == NULL) {\n"
- "\t\treturn NULL;\n"
- "\t}\n");
-
- /* root object to stop it being garbage collected */
- fprintf(binding->outfile,
- "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
-
- /* attach operations and attributes (functions and properties) */
- fprintf(binding->outfile,
- "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
- fprintf(binding->outfile,
- "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n"
- "\t\treturn NULL;\n"
- "\t}\n\n");
- }
-
- /* unroot object and return it */
- fprintf(binding->outfile,
- "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n"
- "\n"
- "\treturn newobject;\n"
- "}\n");
-
-
- return res;
-}
static int
-output_jsclass(struct binding *binding)
+output_forward_declarations(struct binding *binding)
{
/* forward declare add property */
if (binding->addproperty != NULL) {
@@ -778,147 +539,40 @@ output_jsclass(struct binding *binding)
"static void jsclass_finalize(JSContext *cx, JSObject *obj);\n\n");
}
- /* forward declare property list */
- fprintf(binding->outfile,
- "static JSPropertySpec jsclass_properties[];\n\n");
-
- /* output the class declaration */
- HDROUTF(binding, "JSClass JSClass_%s;\n", binding->interface);
-
- /* output the class definition */
- fprintf(binding->outfile,
- "JSClass JSClass_%s = {\n"
- "\t\"%s\",\n",
- binding->interface,
- binding->interface);
-
- /* generate class flags */
- if (binding->has_global) {
- fprintf(binding->outfile, "\tJSCLASS_GLOBAL_FLAGS");
- } else {
- fprintf(binding->outfile, "\t0");
- }
-
- if (binding->resolve != NULL) {
- fprintf(binding->outfile, " | JSCLASS_NEW_RESOLVE");
- }
-
- if (binding->mark != NULL) {
- fprintf(binding->outfile, " | JSAPI_JSCLASS_MARK_IS_TRACE");
- }
-
- if (binding->has_private) {
- fprintf(binding->outfile, " | JSCLASS_HAS_PRIVATE");
- }
-
- fprintf(binding->outfile, ",\n");
-
- /* add property */
- if (binding->addproperty != NULL) {
- fprintf(binding->outfile,
- "\tjsapi_property_add,\t/* addProperty */\n");
- } else {
- fprintf(binding->outfile,
- "\tJS_PropertyStub,\t/* addProperty */\n");
- }
-
- /* del property */
- if (binding->delproperty != NULL) {
- fprintf(binding->outfile,
- "\tjsapi_property_del,\t/* delProperty */\n");
- } else {
- fprintf(binding->outfile,
- "\tJS_PropertyStub,\t/* delProperty */\n");
- }
-
- /* get property */
- if (binding->getproperty != NULL) {
- fprintf(binding->outfile,
- "\tjsapi_property_get,\t/* getProperty */\n");
- } else {
- fprintf(binding->outfile,
- "\tJS_PropertyStub,\t/* getProperty */\n");
- }
-
- /* set property */
- if (binding->setproperty != NULL) {
- fprintf(binding->outfile,
- "\tjsapi_property_set,\t/* setProperty */\n");
- } else {
- fprintf(binding->outfile,
- "\tJS_StrictPropertyStub,\t/* setProperty */\n");
- }
-
- /* enumerate */
- if (binding->enumerate != NULL) {
- fprintf(binding->outfile,
- "\tjsclass_enumerate,\t/* enumerate */\n");
- } else {
- fprintf(binding->outfile,
- "\tJS_EnumerateStub,\t/* enumerate */\n");
- }
-
- /* resolver */
- if (binding->resolve != NULL) {
- fprintf(binding->outfile, "\t(JSResolveOp)jsclass_resolve,\n");
- } else {
- fprintf(binding->outfile, "\tJS_ResolveStub,\n");
- }
-
- fprintf(binding->outfile, "\tJS_ConvertStub,\t/* convert */\n");
-
- if (binding->has_private || (binding->finalise != NULL)) {
- fprintf(binding->outfile, "\tjsclass_finalize,\n");
- } else {
- fprintf(binding->outfile, "\tJS_FinalizeStub,\n");
- }
- fprintf(binding->outfile,
- "\t0,\t/* reserved */\n"
- "\tNULL,\t/* checkAccess */\n"
- "\tNULL,\t/* call */\n"
- "\tNULL,\t/* construct */\n"
- "\tNULL,\t/* xdr Object */\n"
- "\tNULL,\t/* hasInstance */\n");
-
- /* trace/mark */
- if (binding->mark != NULL) {
- fprintf(binding->outfile, "\tJSAPI_JSCLASS_MARKOP(jsclass_mark),\n");
- } else {
- fprintf(binding->outfile, "\tNULL, /* trace/mark */\n");
- }
-
- fprintf(binding->outfile,
- "\tJSAPI_CLASS_NO_INTERNAL_MEMBERS\n"
- "};\n\n");
return 0;
}
+
+
+/** generate structure definition for internal class data
+ *
+ * Every javascript object instance has an internal context to keep
+ * track of its state in object terms this would be considered the
+ * "this" pointer giving access to the classes members.
+ *
+ * Member access can be considered protected as all interfaces
+ * (classes) and subclasses generated within this binding have access
+ * to members.
+ *
+ * @param binding the binding to generate the structure for.
+ * @return 0 on success with output written and -1 on error.
+ */
static int
output_private_declaration(struct binding *binding)
{
- struct genbind_node *type_node;
if (!binding->has_private) {
return 0;
}
- type_node = genbind_node_find(binding->binding_list,
- NULL,
- genbind_cmp_node_type,
- (void *)GENBIND_NODE_TYPE_TYPE);
-
- if (type_node == NULL) {
- return -1;
- }
-
fprintf(binding->outfile, "struct jsclass_private {\n");
- genbind_node_for_each_type(binding->binding_list,
+ genbind_node_foreach_type(binding->binding_list,
GENBIND_NODE_TYPE_BINDING_PRIVATE,
webidl_private_cb,
binding);
- genbind_node_for_each_type(binding->binding_list,
+ genbind_node_foreach_type(binding->binding_list,
GENBIND_NODE_TYPE_BINDING_INTERNAL,
webidl_private_cb,
binding);
@@ -932,7 +586,7 @@ output_private_declaration(struct binding *binding)
static int
output_preamble(struct binding *binding)
{
- genbind_node_for_each_type(binding->gb_ast,
+ genbind_node_foreach_type(binding->gb_ast,
GENBIND_NODE_TYPE_PREAMBLE,
webidl_preamble_cb,
binding);
@@ -962,7 +616,7 @@ output_header_comments(struct binding *binding)
const char *preamble = HDR_COMMENT_PREAMBLE;
fprintf(binding->outfile, preamble, options->infilename);
- genbind_node_for_each_type(binding->gb_ast,
+ genbind_node_foreach_type(binding->gb_ast,
GENBIND_NODE_TYPE_HDRCOMMENT,
webidl_hdrcomment_cb,
binding);
@@ -974,7 +628,7 @@ output_header_comments(struct binding *binding)
fprintf(binding->outfile, preamble, options->infilename);
- genbind_node_for_each_type(binding->gb_ast,
+ genbind_node_foreach_type(binding->gb_ast,
GENBIND_NODE_TYPE_HDRCOMMENT,
webidl_hdrcomment_cb,
binding);
@@ -1008,120 +662,100 @@ binding_has_private(struct genbind_node *binding_list)
return false;
}
-static bool
-binding_has_global(struct binding *binding)
-{
- struct genbind_node *api_node;
- api_node = genbind_node_find_type_ident(binding->gb_ast,
- NULL,
- GENBIND_NODE_TYPE_API,
- "global");
- if (api_node != NULL) {
- return true;
- }
- return false;
+
+/** obtain the name to use for the binding.
+ *
+ * @todo it should be possible to specify the binding name instead of
+ * just using the name of the first interface.
+ */
+static const char *get_binding_name(struct genbind_node *binding_node)
+{
+ return genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(
+ genbind_node_find_type(
+ genbind_node_getnode(binding_node),
+ NULL,
+ GENBIND_NODE_TYPE_BINDING_INTERFACE)),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT));
}
static struct binding *
-binding_new(char *outfilename,
- char *hdrfilename,
- struct genbind_node *genbind_ast)
+binding_new(struct options *options,
+ struct genbind_node *genbind_ast,
+ struct genbind_node *binding_node)
{
struct binding *nb;
- struct genbind_node *binding_node;
+
+ int interfacec; /* numer of interfaces in the interface map */
+ struct binding_interface *interfaces; /* binding interface map */
+
struct genbind_node *binding_list;
- struct genbind_node *ident_node;
- struct genbind_node *interface_node;
- FILE *outfile = NULL; /* output source file */
- FILE *hdrfile = NULL; /* output header file */
char *hdrguard = NULL;
struct webidl_node *webidl_ast = NULL;
int res;
- binding_node = genbind_node_find_type(genbind_ast,
- NULL,
- GENBIND_NODE_TYPE_BINDING);
- if (binding_node == NULL) {
- return NULL;
- }
-
- binding_list = genbind_node_getnode(binding_node);
- if (binding_list == NULL) {
- return NULL;
- }
-
- ident_node = genbind_node_find_type(binding_list,
- NULL,
- GENBIND_NODE_TYPE_IDENT);
- if (ident_node == NULL) {
- return NULL;
- }
-
- interface_node = genbind_node_find_type(binding_list,
- NULL,
- GENBIND_NODE_TYPE_BINDING_INTERFACE);
- if (interface_node == NULL) {
- return NULL;
- }
-
- /* walk ast and load any web IDL files required */
+ /* 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");
+ fprintf(stderr, "Error: failed reading Web IDL\n");
return NULL;
}
- /* open output file */
- if (outfilename == NULL) {
- outfile = stdout;
- } else {
- outfile = fopen(outfilename, "w");
- }
- if (outfile == NULL) {
- fprintf(stderr, "Error opening source output %s: %s\n",
- outfilename,
- strerror(errno));
+ /* build the bindings interface (class) name map */
+ if (build_interface_map(binding_node,
+ webidl_ast,
+ &interfacec,
+ &interfaces) != 0) {
+ /* the binding must have at least one interface */
+ fprintf(stderr, "Error: Binding must have a valid interface\n");
return NULL;
}
- /* output header file if required */
- if (hdrfilename != NULL) {
+ /* header guard */
+ if (options->hdrfilename != NULL) {
int guardlen;
int pos;
- hdrfile = fopen(hdrfilename, "w");
- if (hdrfile == NULL) {
- fprintf(stderr, "Error opening header output %s: %s\n",
- hdrfilename,
- strerror(errno));
- fclose(outfile);
- return NULL;
- }
- guardlen = strlen(hdrfilename);
+ guardlen = strlen(options->hdrfilename);
hdrguard = calloc(1, guardlen + 1);
for (pos = 0; pos < guardlen; pos++) {
- if (isalpha(hdrfilename[pos])) {
- hdrguard[pos] = toupper(hdrfilename[pos]);
+ if (isalpha(options->hdrfilename[pos])) {
+ hdrguard[pos] = toupper(options->hdrfilename[pos]);
} else {
hdrguard[pos] = '_';
}
}
}
+ 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;
- nb->name = genbind_node_gettext(ident_node);
- nb->interface = genbind_node_gettext(interface_node);
- nb->outfile = outfile;
- nb->srcfile = outfile;
- nb->hdrfile = hdrfile;
+
+ /* keep the binding list node */
+ nb->binding_list = binding_list;
+
+ /* store the interface mapping */
+ nb->interfaces = interfaces;
+ nb->interfacec = interfacec;
+
+ /* @todo get rid of the interface element out of the binding
+ * struct and use the interface map instead.
+ */
+ nb->name = nb->interface = get_binding_name(binding_node);
+ nb->outfile = options->outfilehandle;
+ nb->srcfile = options->outfilehandle;
+ nb->hdrfile = options->hdrfilehandle;
nb->hdrguard = hdrguard;
nb->has_private = binding_has_private(binding_list);
- nb->has_global = binding_has_global(nb);
- nb->binding_list = binding_list;
/* class API */
nb->addproperty = genbind_node_find_type_ident(genbind_ast,
@@ -1145,14 +779,14 @@ binding_new(char *outfilename,
"setproperty");
nb->enumerate = genbind_node_find_type_ident(genbind_ast,
- NULL,
- GENBIND_NODE_TYPE_API,
- "enumerate");
+ NULL,
+ GENBIND_NODE_TYPE_API,
+ "enumerate");
nb->resolve = genbind_node_find_type_ident(genbind_ast,
- NULL,
- GENBIND_NODE_TYPE_API,
- "resolve");
+ NULL,
+ GENBIND_NODE_TYPE_API,
+ "resolve");
nb->finalise = genbind_node_find_type_ident(genbind_ast,
NULL,
@@ -1160,23 +794,23 @@ binding_new(char *outfilename,
"finalise");
nb->mark = genbind_node_find_type_ident(genbind_ast,
- NULL,
- GENBIND_NODE_TYPE_API,
- "mark");
+ NULL,
+ GENBIND_NODE_TYPE_API,
+ "mark");
return nb;
}
int
-jsapi_libdom_output(char *outfilename,
- char *hdrfilename,
- struct genbind_node *genbind_ast)
+jsapi_libdom_output(struct options *options,
+ struct genbind_node *genbind_ast,
+ struct genbind_node *binding_node)
{
int res;
struct binding *binding;
/* get general binding information used in output */
- binding = binding_new(outfilename, hdrfilename, genbind_ast);
+ binding = binding_new(options, genbind_ast, binding_node);
if (binding == NULL) {
return 40;
}
@@ -1197,7 +831,12 @@ jsapi_libdom_output(char *outfilename,
return 70;
}
- res = output_jsclass(binding);
+ res = output_forward_declarations(binding);
+ if (res) {
+ return 75;
+ }
+
+ res = output_jsclasses(binding);
if (res) {
return 80;
}
@@ -1207,15 +846,15 @@ jsapi_libdom_output(char *outfilename,
return 85;
}
- /* user code outout just before function bodies emitted */
+ /* user code output just before interface code bodies emitted */
res = output_prologue(binding);
if (res) {
return 89;
}
- /* operator and atrtribute body generation */
+ /* method (function) and property body generation */
- res = output_operator_body(binding, binding->interface);
+ res = output_function_bodies(binding);
if (res) {
return 90;
}
@@ -1225,7 +864,7 @@ jsapi_libdom_output(char *outfilename,
return 100;
}
- /* operator and atrtribute specifier generation */
+ /* method (function) and property specifier generation */
res = output_function_spec(binding);
if (res) {
diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h
index 7db664d..e8d57c4 100644
--- a/src/jsapi-libdom.h
+++ b/src/jsapi-libdom.h
@@ -9,16 +9,42 @@
#ifndef nsgenbind_jsapi_libdom_h
#define nsgenbind_jsapi_libdom_h
+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 own_properties; /**< the number of properties the interface has */
+ int own_functions; /**< the number of functions the interface has */
+
+ bool has_type_properties; /**< some of the properties on the
+ * interface have a type handler
+ */
+
+ 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 output_idx; /**< for interfaces that will be output (node
+ * is valid) this is the output array index
+ */
+};
+
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 *name; /* name of the binding */
const char *interface; /* webidl interface binding is for */
bool has_private; /* true if the binding requires a private structure */
- bool has_global; /* true if the binding is for a global */
struct genbind_node *binding_list; /* node list of the binding */
struct genbind_node *addproperty; /* binding api add property node or NULL */
@@ -34,38 +60,60 @@ 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 */
};
/** Generate binding between jsapi and netsurf libdom */
-int jsapi_libdom_output(char *outfile, char *hdrfile, struct genbind_node *genbind_root);
+int jsapi_libdom_output(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node);
+
+/** Build interface map.
+ *
+ * Generate a map of all interfaces referenced from a binding and
+ * their relationships to each other.
+ *
+ * The map will contain all the interfaces both directly referenced by
+ * the binding and all those inherited through the WebIDL.
+ *
+ * The map is topoligicaly sorted to ensure no forward inheritance
+ * references.
+ *
+ * The map contains an monotinicaly incrementing index for all
+ * interfaces referenced in the binding (i.e. those to be exported).
+ */
+int 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);
+/** generate classes */
+int output_jsclasses(struct binding *binding);
+
/* Generate jsapi native function specifiers */
int output_function_spec(struct binding *binding);
-/* Generate jsapi native function bodys
+/**
+ * Generate jsapi native function bodies.
*
* web IDL describes methods as operators
* http://www.w3.org/TR/WebIDL/#idl-operations
*
* 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 interface The interface to generate operator bodys for
+ * @param binding The binding information
*/
-int output_operator_body(struct binding *binding, const char *interface);
-
+int output_function_bodies(struct binding *binding);
/** generate property tinyid enum */
int output_property_tinyid(struct binding *binding);
@@ -76,10 +124,11 @@ 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);
+/** generate binding class constructors */
+int output_class_new(struct binding *binding);
#endif
diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c
index 851cbeb..4f0654a 100644
--- a/src/nsgenbind-ast.c
+++ b/src/nsgenbind-ast.c
@@ -14,10 +14,17 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include "utils.h"
#include "nsgenbind-ast.h"
#include "options.h"
+/**
+ * standard IO handle for parse trace logging.
+ */
+static FILE *genbind_parsetracef;
+
/* parser and lexer interface */
extern int nsgenbind_debug;
extern int nsgenbind__flex_debug;
@@ -26,444 +33,639 @@ extern int nsgenbind_parse(struct genbind_node **genbind_ast);
/* terminal nodes have a value only */
struct genbind_node {
- enum genbind_node_type type;
- struct genbind_node *l;
- union {
- void *value;
- struct genbind_node *node;
- char *text;
- int number; /* node data is an integer */
- } r;
+ enum genbind_node_type type;
+ struct genbind_node *l;
+ union {
+ void *value;
+ struct genbind_node *node;
+ char *text;
+ int number; /* node data is an integer */
+ } r;
};
+/* insert node(s) at beginning of a list */
+struct genbind_node *
+genbind_node_prepend(struct genbind_node *list, struct genbind_node *inst)
+{
+ struct genbind_node *end = inst;
+
+ if (inst == NULL) {
+ return list; /* no node to prepend - return existing list */
+ }
+
+ /* find end of inserted node list */
+ while (end->l != NULL) {
+ end = end->l;
+ }
+
+ end->l = list;
+
+ return inst;
+}
+
+/* prepend list to a nodes list
+ *
+ * inserts a list into the beginning of a nodes r list
+ *
+ * CAUTION: if the \a node element is not a node type the node will not be added
+ */
+struct genbind_node *
+genbind_node_add(struct genbind_node *node, struct genbind_node *list)
+{
+ if (node == NULL) {
+ return list;
+ }
+
+ /* this does not use genbind_node_getnode() as it cannot
+ * determine between an empty node and a node which is not a
+ * list type
+ */
+ switch (node->type) {
+ case GENBIND_NODE_TYPE_BINDING:
+ case GENBIND_NODE_TYPE_CLASS:
+ case GENBIND_NODE_TYPE_PRIVATE:
+ case GENBIND_NODE_TYPE_INTERNAL:
+ case GENBIND_NODE_TYPE_PROPERTY:
+ case GENBIND_NODE_TYPE_FLAGS:
+ case GENBIND_NODE_TYPE_METHOD:
+ case GENBIND_NODE_TYPE_PARAMETER:
+ break;
+
+ default:
+ /* not a node type */
+ return list;
+ }
+
+ node->r.node = genbind_node_prepend(node->r.node, list);
+
+ return node;
+}
char *genbind_strapp(char *a, char *b)
{
- char *fullstr;
- int fulllen;
- fulllen = strlen(a) + strlen(b) + 1;
- fullstr = malloc(fulllen);
- snprintf(fullstr, fulllen, "%s%s", a, b);
- free(a);
- free(b);
- return fullstr;
+ char *fullstr;
+ int fulllen;
+ fulllen = strlen(a) + strlen(b) + 1;
+ fullstr = malloc(fulllen);
+ snprintf(fullstr, fulllen, "%s%s", a, b);
+ free(a);
+ free(b);
+ return fullstr;
}
-struct genbind_node *genbind_node_link(struct genbind_node *tgt, struct genbind_node *src)
+struct genbind_node *
+genbind_node_link(struct genbind_node *tgt, struct genbind_node *src)
{
- tgt->l = src;
- return tgt;
+ tgt->l = src;
+ return tgt;
}
struct genbind_node *
genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r)
{
- struct genbind_node *nn;
- nn = calloc(1, sizeof(struct genbind_node));
- nn->type = type;
- nn->l = l;
- nn->r.value = r;
- return nn;
+ struct genbind_node *nn;
+ nn = calloc(1, sizeof(struct genbind_node));
+ nn->type = type;
+ nn->l = l;
+ nn->r.value = r;
+ return nn;
}
+
+/* exported interface defined in nsgenbind-ast.h */
int
-genbind_node_for_each_type(struct genbind_node *node,
- enum genbind_node_type type,
- genbind_callback_t *cb,
- void *ctx)
+genbind_node_foreach_type(struct genbind_node *node,
+ enum genbind_node_type type,
+ genbind_callback_t *cb,
+ void *ctx)
{
- int ret;
-
- if (node == NULL) {
- return -1;
- }
- if (node->l != NULL) {
- ret = genbind_node_for_each_type(node->l, type, cb, ctx);
- if (ret != 0) {
- return ret;
- }
- }
- if (node->type == type) {
- return cb(node, ctx);
- }
+ int ret;
+
+ if (node == NULL) {
+ return -1;
+ }
+ if (node->l != NULL) {
+ ret = genbind_node_foreach_type(node->l, type, cb, ctx);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ if (node->type == type) {
+ return cb(node, ctx);
+ }
+
+ return 0;
+}
- 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 *
genbind_node_find(struct genbind_node *node,
- struct genbind_node *prev,
- genbind_callback_t *cb,
- void *ctx)
+ struct genbind_node *prev,
+ genbind_callback_t *cb,
+ void *ctx)
{
- struct genbind_node *ret;
+ struct genbind_node *ret;
- if ((node == NULL) || (node == prev)) {
- return NULL;
- }
+ if ((node == NULL) || (node == prev)) {
+ return NULL;
+ }
- if (node->l != prev) {
- ret = genbind_node_find(node->l, prev, cb, ctx);
- if (ret != NULL) {
- return ret;
- }
- }
+ if (node->l != prev) {
+ ret = genbind_node_find(node->l, prev, cb, ctx);
+ if (ret != NULL) {
+ return ret;
+ }
+ }
- if (cb(node, ctx) != 0) {
- return node;
- }
+ if (cb(node, ctx) != 0) {
+ return node;
+ }
- return NULL;
+ return NULL;
}
/* exported interface documented in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find_type(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type type)
+ struct genbind_node *prev,
+ enum genbind_node_type type)
{
- return genbind_node_find(node,
- prev,
- genbind_cmp_node_type,
- (void *)type);
+ return genbind_node_find(node,
+ prev,
+ genbind_cmp_node_type,
+ (void *)type);
}
/* exported interface documented in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find_type_ident(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type type,
- const char *ident)
+ struct genbind_node *prev,
+ enum genbind_node_type type,
+ const char *ident)
{
- struct genbind_node *found_node;
- struct genbind_node *ident_node;
-
- if (ident == NULL) {
- return NULL;
- }
-
- found_node = genbind_node_find_type(node, prev, type);
-
-
- while (found_node != NULL) {
- /* look for an ident node */
- ident_node = genbind_node_find_type(genbind_node_getnode(found_node),
- NULL,
- GENBIND_NODE_TYPE_IDENT);
- if (ident_node != NULL) {
- if (strcmp(ident_node->r.text, ident) == 0)
- break;
- }
-
- /* look for next matching node */
- found_node = genbind_node_find_type(node, found_node, type);
- }
- return found_node;
+ struct genbind_node *found_node;
+ struct genbind_node *ident_node;
+
+ if (ident == NULL) {
+ return NULL;
+ }
+
+ found_node = genbind_node_find_type(node, prev, type);
+
+ while (found_node != NULL) {
+ /* look for an ident node */
+ ident_node = genbind_node_find_type(
+ genbind_node_getnode(found_node),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT);
+
+ while (ident_node != NULL) {
+ /* check for matching text */
+ if (strcmp(ident_node->r.text, ident) == 0) {
+ return found_node;
+ }
+
+ ident_node = genbind_node_find_type(
+ genbind_node_getnode(found_node),
+ ident_node,
+ GENBIND_NODE_TYPE_IDENT);
+ }
+
+
+ /* look for next matching node */
+ found_node = genbind_node_find_type(node, found_node, type);
+ }
+ return found_node;
}
/* exported interface documented in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find_type_type(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type type,
- const char *ident)
+ struct genbind_node *prev,
+ enum genbind_node_type type,
+ const char *ident)
{
- struct genbind_node *found_node;
- struct genbind_node *ident_node;
+ struct genbind_node *found_node;
+ struct genbind_node *ident_node;
+
+ found_node = genbind_node_find_type(node, prev, type);
+
+
+ while (found_node != NULL) {
+ /* look for a type node */
+ ident_node = genbind_node_find_type(genbind_node_getnode(found_node),
+ NULL,
+ GENBIND_NODE_TYPE_TYPE);
+ if (ident_node != NULL) {
+ if (strcmp(ident_node->r.text, ident) == 0)
+ break;
+ }
+
+ /* look for next matching node */
+ found_node = genbind_node_find_type(node, found_node, type);
+ }
+ return found_node;
+}
- found_node = genbind_node_find_type(node, prev, type);
+/* exported interface documented in nsgenbind-ast.h */
+struct genbind_node *
+genbind_node_find_method(struct genbind_node *node,
+ struct genbind_node *prev,
+ enum genbind_method_type methodtype)
+{
+ struct genbind_node *res_node;
+
+ res_node = genbind_node_find_type(
+ genbind_node_getnode(node),
+ prev, GENBIND_NODE_TYPE_METHOD);
+ while (res_node != NULL) {
+ struct genbind_node *type_node;
+ enum genbind_method_type *type;
+
+ type_node = genbind_node_find_type(
+ genbind_node_getnode(res_node),
+ NULL, GENBIND_NODE_TYPE_METHOD_TYPE);
+
+ type = (enum genbind_method_type *)genbind_node_getint(type_node);
+ if (*type == methodtype) {
+ break;
+ }
+
+ res_node = genbind_node_find_type(
+ genbind_node_getnode(node),
+ res_node, GENBIND_NODE_TYPE_METHOD);
+ }
+
+ return res_node;
+}
- while (found_node != NULL) {
- /* look for a type node */
- ident_node = genbind_node_find_type(genbind_node_getnode(found_node),
- NULL,
- GENBIND_NODE_TYPE_TYPE);
- if (ident_node != NULL) {
- if (strcmp(ident_node->r.text, ident) == 0)
- break;
- }
- /* look for next matching node */
- found_node = genbind_node_find_type(node, found_node, type);
- }
- return found_node;
+/* exported interface documented in nsgenbind-ast.h */
+struct genbind_node *
+genbind_node_find_method_ident(struct genbind_node *node,
+ struct genbind_node *prev,
+ enum genbind_method_type nodetype,
+ const char *ident)
+{
+ struct genbind_node *res_node;
+ char *method_ident;
+
+ res_node = genbind_node_find_method(node, prev, nodetype);
+ while (res_node != NULL) {
+ method_ident = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(res_node),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT));
+
+ if ((ident != NULL) &&
+ (method_ident != NULL) &&
+ strcmp(ident, method_ident) == 0) {
+ break;
+ }
+
+ res_node = genbind_node_find_method(node, res_node, nodetype);
+ }
+ return res_node;
}
+
+/* exported interface documented in nsgenbind-ast.h */
int genbind_cmp_node_type(struct genbind_node *node, void *ctx)
{
- if (node->type == (enum genbind_node_type)ctx)
- return 1;
- return 0;
+ if (node->type == (enum genbind_node_type)ctx)
+ return 1;
+ return 0;
}
char *genbind_node_gettext(struct genbind_node *node)
{
- if (node != NULL) {
- switch(node->type) {
- case GENBIND_NODE_TYPE_WEBIDLFILE:
- case GENBIND_NODE_TYPE_STRING:
- case GENBIND_NODE_TYPE_PREAMBLE:
- case GENBIND_NODE_TYPE_PROLOGUE:
- case GENBIND_NODE_TYPE_EPILOGUE:
- case GENBIND_NODE_TYPE_IDENT:
- case GENBIND_NODE_TYPE_TYPE:
- case GENBIND_NODE_TYPE_BINDING_INTERFACE:
- case GENBIND_NODE_TYPE_CBLOCK:
- return node->r.text;
-
- default:
- break;
- }
- }
- return NULL;
+ if (node != NULL) {
+ switch(node->type) {
+ case GENBIND_NODE_TYPE_WEBIDL:
+ case GENBIND_NODE_TYPE_STRING:
+ case GENBIND_NODE_TYPE_PREFACE:
+ case GENBIND_NODE_TYPE_PROLOGUE:
+ case GENBIND_NODE_TYPE_EPILOGUE:
+ case GENBIND_NODE_TYPE_POSTFACE:
+ case GENBIND_NODE_TYPE_IDENT:
+ case GENBIND_NODE_TYPE_TYPE:
+ case GENBIND_NODE_TYPE_CDATA:
+ return node->r.text;
+
+ default:
+ break;
+ }
+ }
+ return NULL;
}
struct genbind_node *genbind_node_getnode(struct genbind_node *node)
{
- if (node != NULL) {
- switch(node->type) {
- case GENBIND_NODE_TYPE_HDRCOMMENT:
- case GENBIND_NODE_TYPE_BINDING:
- case GENBIND_NODE_TYPE_BINDING_PRIVATE:
- case GENBIND_NODE_TYPE_BINDING_INTERNAL:
- case GENBIND_NODE_TYPE_BINDING_PROPERTY:
- case GENBIND_NODE_TYPE_OPERATION:
- case GENBIND_NODE_TYPE_API:
- case GENBIND_NODE_TYPE_GETTER:
- case GENBIND_NODE_TYPE_SETTER:
- return node->r.node;
-
- default:
- break;
- }
- }
- return NULL;
+ if (node != NULL) {
+ switch(node->type) {
+ case GENBIND_NODE_TYPE_BINDING:
+ case GENBIND_NODE_TYPE_CLASS:
+ case GENBIND_NODE_TYPE_PRIVATE:
+ case GENBIND_NODE_TYPE_INTERNAL:
+ case GENBIND_NODE_TYPE_PROPERTY:
+ case GENBIND_NODE_TYPE_FLAGS:
+ case GENBIND_NODE_TYPE_METHOD:
+ case GENBIND_NODE_TYPE_PARAMETER:
+ return node->r.node;
+
+ default:
+ break;
+ }
+ }
+ return NULL;
}
-int genbind_node_getint(struct genbind_node *node)
+int *genbind_node_getint(struct genbind_node *node)
{
- if (node != NULL) {
- switch(node->type) {
- case GENBIND_NODE_TYPE_MODIFIER:
- return node->r.number;
-
- default:
- break;
- }
- }
- return -1;
-
+ if (node != NULL) {
+ switch(node->type) {
+ case GENBIND_NODE_TYPE_METHOD_TYPE:
+ case GENBIND_NODE_TYPE_MODIFIER:
+ return &node->r.number;
+
+ default:
+ break;
+ }
+ }
+ return NULL;
}
static const char *genbind_node_type_to_str(enum genbind_node_type type)
{
- switch(type) {
- case GENBIND_NODE_TYPE_IDENT:
- return "Ident";
+ switch(type) {
+ case GENBIND_NODE_TYPE_IDENT:
+ return "Ident";
- case GENBIND_NODE_TYPE_ROOT:
- return "Root";
+ case GENBIND_NODE_TYPE_ROOT:
+ return "Root";
- case GENBIND_NODE_TYPE_WEBIDLFILE:
- return "webidlfile";
+ case GENBIND_NODE_TYPE_WEBIDL:
+ return "webidl";
- case GENBIND_NODE_TYPE_HDRCOMMENT:
- return "HdrComment";
+ case GENBIND_NODE_TYPE_STRING:
+ return "String";
- case GENBIND_NODE_TYPE_STRING:
- return "String";
+ case GENBIND_NODE_TYPE_PREFACE:
+ return "Preface";
- case GENBIND_NODE_TYPE_PREAMBLE:
- return "Preamble";
+ case GENBIND_NODE_TYPE_POSTFACE:
+ return "Postface";
- case GENBIND_NODE_TYPE_BINDING:
- return "Binding";
+ case GENBIND_NODE_TYPE_PROLOGUE:
+ return "Prologue";
- case GENBIND_NODE_TYPE_TYPE:
- return "Type";
+ case GENBIND_NODE_TYPE_EPILOGUE:
+ return "Epilogue";
- case GENBIND_NODE_TYPE_BINDING_PRIVATE:
- return "Private";
+ case GENBIND_NODE_TYPE_BINDING:
+ return "Binding";
- case GENBIND_NODE_TYPE_BINDING_INTERNAL:
- return "Internal";
+ case GENBIND_NODE_TYPE_TYPE:
+ return "Type";
- case GENBIND_NODE_TYPE_BINDING_INTERFACE:
- return "Interface";
+ case GENBIND_NODE_TYPE_PRIVATE:
+ return "Private";
- case GENBIND_NODE_TYPE_BINDING_PROPERTY:
- return "Property";
+ case GENBIND_NODE_TYPE_INTERNAL:
+ return "Internal";
- case GENBIND_NODE_TYPE_OPERATION:
- return "Operation";
+ case GENBIND_NODE_TYPE_CLASS:
+ return "Class";
- case GENBIND_NODE_TYPE_API:
- return "API";
+ case GENBIND_NODE_TYPE_FLAGS:
+ return "Flags";
- case GENBIND_NODE_TYPE_GETTER:
- return "Getter";
+ case GENBIND_NODE_TYPE_PROPERTY:
+ return "Property";
- case GENBIND_NODE_TYPE_SETTER:
- return "Setter";
+ case GENBIND_NODE_TYPE_METHOD:
+ return "Method";
- case GENBIND_NODE_TYPE_CBLOCK:
- return "CBlock";
+ case GENBIND_NODE_TYPE_METHOD_TYPE:
+ return "Type";
- default:
- return "Unknown";
- }
+ case GENBIND_NODE_TYPE_PARAMETER:
+ return "Parameter";
+
+ case GENBIND_NODE_TYPE_CDATA:
+ return "CBlock";
+
+ default:
+ return "Unknown";
+ }
}
-int genbind_ast_dump(struct genbind_node *node, int indent)
+/** dump ast node to file at indent level */
+static int genbind_ast_dump(FILE *dfile, struct genbind_node *node, int indent)
{
- const char *SPACES=" ";
- char *txt;
-
- while (node != NULL) {
- printf("%.*s%s", indent, SPACES, genbind_node_type_to_str(node->type));
-
- txt = genbind_node_gettext(node);
- if (txt == NULL) {
- printf("\n");
- genbind_ast_dump(genbind_node_getnode(node), indent + 2);
- } else {
- printf(": \"%.*s\"\n", 75 - indent, txt);
- }
- node = node->l;
- }
- return 0;
+ const char *SPACES=" ";
+ char *txt;
+ int *val;
+
+ while (node != NULL) {
+ fprintf(dfile, "%.*s%s", indent, SPACES,
+ genbind_node_type_to_str(node->type));
+
+ txt = genbind_node_gettext(node);
+ if (txt == NULL) {
+ val = genbind_node_getint(node);
+ if (val == NULL) {
+ fprintf(dfile, "\n");
+ genbind_ast_dump(dfile,
+ genbind_node_getnode(node),
+ indent + 2);
+ } else {
+ fprintf(dfile, ": %d\n", *val);
+ }
+ } else {
+ fprintf(dfile, ": \"%.*s\"\n", 75 - indent, txt);
+ }
+ node = node->l;
+ }
+ return 0;
}
-FILE *genbindopen(const char *filename)
+
+/* exported interface documented in nsgenbind-ast.h */
+int genbind_dump_ast(struct genbind_node *node)
{
- FILE *genfile;
- char *fullname;
- int fulllen;
- static char *prevfilepath = NULL;
-
- /* try filename raw */
- genfile = fopen(filename, "r");
- if (genfile != NULL) {
- if (options->verbose) {
- printf("Opened Genbind file %s\n", filename);
- }
- if (prevfilepath == NULL) {
- fullname = strrchr(filename, '/');
- if (fullname == NULL) {
- fulllen = strlen(filename);
- } else {
- fulllen = fullname - filename;
- }
- prevfilepath = strndup(filename,fulllen);
- }
- if (options->depfilehandle != NULL) {
- fprintf(options->depfilehandle, " \\\n\t%s",
- filename);
- }
- return genfile;
- }
+ FILE *dumpf;
- /* try based on previous filename */
- if (prevfilepath != NULL) {
- fulllen = strlen(prevfilepath) + strlen(filename) + 2;
- fullname = malloc(fulllen);
- snprintf(fullname, fulllen, "%s/%s", prevfilepath, filename);
- if (options->debug) {
- printf("Attempting to open Genbind file %s\n", fullname);
- }
- genfile = fopen(fullname, "r");
- if (genfile != NULL) {
- if (options->verbose) {
- printf("Opened Genbind file %s\n", fullname);
- }
- if (options->depfilehandle != NULL) {
- fprintf(options->depfilehandle, " \\\n\t%s",
- fullname);
- }
- free(fullname);
- return genfile;
- }
- free(fullname);
- }
+ /* only dump AST to file if required */
+ if (!options->debug) {
+ return 0;
+ }
- /* try on idl path */
- if (options->idlpath != NULL) {
- fulllen = strlen(options->idlpath) + strlen(filename) + 2;
- fullname = malloc(fulllen);
- snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename);
- genfile = fopen(fullname, "r");
- if ((genfile != NULL) && options->verbose) {
- printf("Opend Genbind file %s\n", fullname);
- if (options->depfilehandle != NULL) {
- fprintf(options->depfilehandle, " \\\n\t%s",
- fullname);
- }
- }
-
- free(fullname);
- }
+ dumpf = genb_fopen("binding-ast", "w");
+ if (dumpf == NULL) {
+ return 2;
+ }
+
+ genbind_ast_dump(dumpf, node, 0);
- return genfile;
+ fclose(dumpf);
+
+ return 0;
}
-int genbind_parsefile(char *infilename, struct genbind_node **ast)
+FILE *genbindopen(const char *filename)
{
- FILE *infile;
-
- /* open input file */
- if ((infilename[0] == '-') &&
- (infilename[1] == 0)) {
- if (options->verbose) {
- printf("Using stdin for input\n");
- }
- infile = stdin;
- } else {
- infile = genbindopen(infilename);
- }
-
- if (!infile) {
- fprintf(stderr, "Error opening %s: %s\n",
- infilename,
- strerror(errno));
- return 3;
- }
+ FILE *genfile;
+ char *fullname;
+ int fulllen;
+ static char *prevfilepath = NULL;
+
+ /* try filename raw */
+ genfile = fopen(filename, "r");
+ if (genfile != NULL) {
+ if (options->verbose) {
+ printf("Opened Genbind file %s\n", filename);
+ }
+ if (prevfilepath == NULL) {
+ fullname = strrchr(filename, '/');
+ if (fullname == NULL) {
+ fulllen = strlen(filename);
+ } else {
+ fulllen = fullname - filename;
+ }
+ prevfilepath = strndup(filename,fulllen);
+ }
+#if 0
+ if (options->depfilehandle != NULL) {
+ fprintf(options->depfilehandle, " \\\n\t%s",
+ filename);
+ }
+#endif
+ return genfile;
+ }
+
+ /* try based on previous filename */
+ if (prevfilepath != NULL) {
+ fulllen = strlen(prevfilepath) + strlen(filename) + 2;
+ fullname = malloc(fulllen);
+ snprintf(fullname, fulllen, "%s/%s", prevfilepath, filename);
+ if (options->debug) {
+ printf("Attempting to open Genbind file %s\n", fullname);
+ }
+ genfile = fopen(fullname, "r");
+ if (genfile != NULL) {
+ if (options->verbose) {
+ printf("Opened Genbind file %s\n", fullname);
+ }
+#if 0
+ if (options->depfilehandle != NULL) {
+ fprintf(options->depfilehandle, " \\\n\t%s",
+ fullname);
+ }
+#endif
+ free(fullname);
+ return genfile;
+ }
+ free(fullname);
+ }
+
+ /* try on idl path */
+ if (options->idlpath != NULL) {
+ fulllen = strlen(options->idlpath) + strlen(filename) + 2;
+ fullname = malloc(fulllen);
+ snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename);
+ genfile = fopen(fullname, "r");
+ if ((genfile != NULL) && options->verbose) {
+ printf("Opend Genbind file %s\n", fullname);
+#if 0
+ if (options->depfilehandle != NULL) {
+ fprintf(options->depfilehandle, " \\\n\t%s",
+ fullname);
+ }
+#endif
+ }
- if (options->debug) {
- nsgenbind_debug = 1;
- nsgenbind__flex_debug = 1;
- }
+ free(fullname);
+ }
- /* set flex to read from file */
- nsgenbind_restart(infile);
+ return genfile;
+}
- /* process binding */
- return nsgenbind_parse(ast);
+int genbind_parsefile(char *infilename, struct genbind_node **ast)
+{
+ FILE *infile;
+ int ret;
+
+ /* open input file */
+ infile = genbindopen(infilename);
+ if (!infile) {
+ fprintf(stderr, "Error opening %s: %s\n",
+ infilename,
+ strerror(errno));
+ return 3;
+ }
+
+ /* if debugging enabled enable parser tracing and send to file */
+ if (options->debug) {
+ nsgenbind_debug = 1;
+ nsgenbind__flex_debug = 1;
+ genbind_parsetracef = genb_fopen("binding-trace", "w");
+ } else {
+ genbind_parsetracef = NULL;
+ }
+
+ /* set flex to read from file */
+ nsgenbind_restart(infile);
+
+ /* process binding */
+ ret = nsgenbind_parse(ast);
+
+ /* close tracefile if open */
+ if (genbind_parsetracef != NULL) {
+ fclose(genbind_parsetracef);
+ }
+
+ return ret;
}
-#ifdef NEED_STRNDUP
-
-char *strndup(const char *s, size_t n)
+int genbind_fprintf(FILE *stream, const char *format, ...)
{
- size_t len;
- char *s2;
+ va_list ap;
+ int ret;
- for (len = 0; len != n && s[len]; len++)
- continue;
+ va_start(ap, format);
- s2 = malloc(len + 1);
- if (!s2)
- return 0;
+ if (genbind_parsetracef == NULL) {
+ ret = vfprintf(stream, format, ap);
+ } else {
+ ret = vfprintf(genbind_parsetracef, format, ap);
+ }
+ va_end(ap);
- memcpy(s2, s, len);
- s2[len] = 0;
- return s2;
+ return ret;
}
-
-#endif
-
diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h
index 6513f7f..2a384b2 100644
--- a/src/nsgenbind-ast.h
+++ b/src/nsgenbind-ast.h
@@ -1,4 +1,4 @@
-/* binding file AST interface
+/* binding file AST interface
*
* This file is part of nsnsgenbind.
* Licensed under the MIT License,
@@ -10,43 +10,56 @@
#define nsgenbind_nsgenbind_ast_h
enum genbind_node_type {
- GENBIND_NODE_TYPE_ROOT = 0,
- GENBIND_NODE_TYPE_IDENT, /**< generic identifier string */
- GENBIND_NODE_TYPE_TYPE, /**< generic type string */
- GENBIND_NODE_TYPE_MODIFIER, /**< node modifier */
-
- GENBIND_NODE_TYPE_CBLOCK,
- GENBIND_NODE_TYPE_WEBIDLFILE,
- GENBIND_NODE_TYPE_HDRCOMMENT,
- GENBIND_NODE_TYPE_STRING,
- GENBIND_NODE_TYPE_PREAMBLE,
- GENBIND_NODE_TYPE_PROLOGUE,
- GENBIND_NODE_TYPE_EPILOGUE,
- GENBIND_NODE_TYPE_BINDING,
- GENBIND_NODE_TYPE_BINDING_PRIVATE,
- GENBIND_NODE_TYPE_BINDING_INTERNAL,
- GENBIND_NODE_TYPE_BINDING_INTERFACE,
- GENBIND_NODE_TYPE_BINDING_PROPERTY,
- GENBIND_NODE_TYPE_API,
- GENBIND_NODE_TYPE_OPERATION,
- GENBIND_NODE_TYPE_GETTER,
- GENBIND_NODE_TYPE_SETTER,
+ GENBIND_NODE_TYPE_ROOT = 0,
+ GENBIND_NODE_TYPE_IDENT, /**< generic identifier string */
+ GENBIND_NODE_TYPE_TYPE, /**< generic type string */
+ GENBIND_NODE_TYPE_MODIFIER, /**< node modifier */
+ GENBIND_NODE_TYPE_CDATA, /**< verbatim block of character data */
+ GENBIND_NODE_TYPE_STRING, /**< text string */
+
+ GENBIND_NODE_TYPE_BINDING,
+ GENBIND_NODE_TYPE_WEBIDL,
+ GENBIND_NODE_TYPE_PREFACE,
+ GENBIND_NODE_TYPE_PROLOGUE,
+ GENBIND_NODE_TYPE_EPILOGUE,
+ GENBIND_NODE_TYPE_POSTFACE,
+
+ GENBIND_NODE_TYPE_CLASS, /**< class definition */
+ GENBIND_NODE_TYPE_PRIVATE,
+ GENBIND_NODE_TYPE_INTERNAL,
+ GENBIND_NODE_TYPE_PROPERTY,
+ GENBIND_NODE_TYPE_FLAGS,
+
+ GENBIND_NODE_TYPE_METHOD, /**< binding method */
+ GENBIND_NODE_TYPE_METHOD_TYPE, /**< binding method type */
+ GENBIND_NODE_TYPE_PARAMETER, /**< method parameter */
};
/* modifier flags */
enum genbind_type_modifier {
- GENBIND_TYPE_NONE = 0,
- GENBIND_TYPE_TYPE = 1, /**< identifies a type handler */
- GENBIND_TYPE_UNSHARED = 2, /**< unshared item */
- GENBIND_TYPE_TYPE_UNSHARED = 3, /**< identifies a unshared type handler */
+ GENBIND_TYPE_NONE = 0,
+ GENBIND_TYPE_TYPE = 1, /**< identifies a type handler */
+ GENBIND_TYPE_UNSHARED = 2, /**< unshared item */
+ GENBIND_TYPE_TYPE_UNSHARED = 3, /**< identifies a unshared type handler */
};
+/* binding method types */
+enum genbind_method_type {
+ GENBIND_METHOD_TYPE_INIT = 0, /**< binding method is initialiser */
+ GENBIND_METHOD_TYPE_FINI, /**< binding method is finalizer */
+ GENBIND_METHOD_TYPE_METHOD, /**< binding method is a method */
+ GENBIND_METHOD_TYPE_GETTER, /**< binding method is a getter */
+ GENBIND_METHOD_TYPE_SETTER, /**< binding method is a setter */
+ GENBIND_METHOD_TYPE_PROTOTYPE, /**< binding method is a prototype */
+};
struct genbind_node;
/** callback for search and iteration routines */
typedef int (genbind_callback_t)(struct genbind_node *node, void *ctx);
+int genbind_fprintf(FILE *stream, const char *format, ...);
+
int genbind_cmp_node_type(struct genbind_node *node, void *ctx);
FILE *genbindopen(const char *filename);
@@ -58,77 +71,178 @@ char *genbind_strapp(char *a, char *b);
struct genbind_node *genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r);
struct genbind_node *genbind_node_link(struct genbind_node *tgt, struct genbind_node *src);
-int genbind_ast_dump(struct genbind_node *ast, int indent);
+struct genbind_node *genbind_node_prepend(struct genbind_node *list, struct genbind_node *inst);
+
+struct genbind_node *genbind_node_add(struct genbind_node *node, struct genbind_node *list);
-/** Depth first left hand search using user provided comparison
+/**
+ * Dump the binding AST to file
+ *
+ * If the debug flag has been set this causes the binding AST to be written to
+ * a binding-ast output file
+ *
+ * \param node Node of the tree to start dumping from (usually tree root)
+ * \return 0 on sucess or non zero on faliure and error message printed.
+ */
+int genbind_dump_ast(struct genbind_node *node);
+
+/**
+ *Depth first left hand search using user provided comparison
*
* @param node The node to start the search from
* @param prev The node at which to stop the search, either NULL to
- * search the full tree depth (initial search) or the result
+ * search the full tree depth (initial search) or the result
* of a previous search to continue.
* @param cb Comparison callback
* @param ctx Context for callback
*/
struct genbind_node *
genbind_node_find(struct genbind_node *node,
- struct genbind_node *prev,
- genbind_callback_t *cb,
- void *ctx);
+ struct genbind_node *prev,
+ genbind_callback_t *cb,
+ void *ctx);
-/** Depth first left hand search returning nodes of the specified type
+/**
+ * Depth first left hand search returning nodes of the specified type
*
* @param node The node to start the search from
* @param prev The node at which to stop the search, either NULL to
- * search the full tree depth (initial search) or the result
+ * 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);
+ 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
+/**
+ * Depth first left hand search returning nodes of the specified type
+ * 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
- * search the full tree depth (initial search) or the result
+ * 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
* @param ident The text to match the ident child node to
*/
struct genbind_node *
genbind_node_find_type_ident(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type nodetype,
- const char *ident);
+ struct genbind_node *prev,
+ enum genbind_node_type nodetype,
+ const char *ident);
+
-/** Depth first left hand search returning nodes of the specified type
- * and a type child node with matching text
+/**
+ * Returning node of the specified type with a GENBIND_NODE_TYPE_TYPE
+ * subnode with matching text.
+ *
+ * This is a conveniance wrapper around nested calls to
+ * genbind_node_find_type() which performs a depth first left hand
+ * search returning nodes of the specified type and a child node of
+ * GENBIND_NODE_TYPE_TYPE 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
- * search the full tree depth (initial search) or the result
+ * 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
- * @param type The text to match the type child node to
+ * @param nodetype The type of node to seach for.
+ * @param type The text to match the type child node to.
*/
struct genbind_node *
genbind_node_find_type_type(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type nodetype,
- const char *type);
+ struct genbind_node *prev,
+ enum genbind_node_type nodetype,
+ const char *type_text);
-int genbind_node_for_each_type(struct genbind_node *node, enum genbind_node_type type, genbind_callback_t *cb, void *ctx);
-char *genbind_node_gettext(struct genbind_node *node);
+/**
+ * Find a method node of a given method type
+ *
+ * \param node A node of type GENBIND_NODE_TYPE_CLASS to search for methods.
+ * \param prev The node at which to stop the search, either NULL to
+ * search the full tree depth (initial search) or the result
+ * of a previous search to continue.
+ * \param methodtype The type of method to find.
+ * \return A node of type GENBIND_NODE_TYPE_METHOD on success or NULL on faliure
+ */
+struct genbind_node *
+genbind_node_find_method(struct genbind_node *node,
+ struct genbind_node *prev,
+ enum genbind_method_type methodtype);
+
+
+/**
+ * Find a method node of a given method type and identifier
+ *
+ * \param node A node of type GENBIND_NODE_TYPE_CLASS to search for methods.
+ * \param prev The node at which to stop the search, either NULL to
+ * search the full tree depth (initial search) or the result
+ * of a previous search to continue.
+ * \param methodtype The type of method to find.
+ * \param ident The identifier to search for
+ * \return A node of type GENBIND_NODE_TYPE_METHOD on success or NULL on faliure
+ */
+struct genbind_node *
+genbind_node_find_method_ident(struct genbind_node *node,
+ struct genbind_node *prev,
+ enum genbind_method_type methodtype,
+ const char *ident);
+
+
+/**
+ * Iterate all nodes of a certian type from a node with a callback.
+ *
+ * Depth first search for nodes of the given type calling the callback
+ * with context.
+ *
+ * @param node The node to start the search from.
+ */
+int genbind_node_foreach_type(struct genbind_node *node,
+ enum genbind_node_type type,
+ genbind_callback_t *cb,
+ void *ctx);
+
+/** get a nodes node list content
+ *
+ * @param node The nodes to get node list from
+ * @return pointer to the node list or NULL if the node does not contain a list
+ */
struct genbind_node *genbind_node_getnode(struct genbind_node *node);
-int genbind_node_getint(struct genbind_node *node);
-#ifdef _WIN32
-#define NEED_STRNDUP 1
-char *strndup(const char *s, size_t n);
-#endif
+/** get a nodes text content
+ *
+ * @param node The nodes to get text from
+ * @return pointer to the node text or NULL if the node is not of type
+ * text or is empty.
+ */
+char *genbind_node_gettext(struct genbind_node *node);
+
+/** get a nodes integer value
+ *
+ * @param node The nodes to get integer from
+ * @return pointer to the node value or NULL if the node is not of type
+ * int or is empty.
+ */
+int *genbind_node_getint(struct genbind_node *node);
#endif
diff --git a/src/nsgenbind-lexer.l b/src/nsgenbind-lexer.l
index 8189a72..d092195 100644
--- a/src/nsgenbind-lexer.l
+++ b/src/nsgenbind-lexer.l
@@ -72,7 +72,9 @@ cblockopen \%\{
cblockclose \%\}
/* used for #include directive */
-poundsign ^{whitespace}*#
+poundsign ^{whitespace}*#
+
+dblcolon \:\:
%x cblock
@@ -88,42 +90,57 @@ poundsign ^{whitespace}*#
yylloc->last_column = 0;
}
- /* terminals */
+ /* binding terminals */
-webidlfile return TOK_IDLFILE;
+binding return TOK_BINDING;
-hdrcomment return TOK_HDR_COMMENT;
+webidl return TOK_WEBIDL;
-preamble return TOK_PREAMBLE;
+preface return TOK_PREFACE;
prologue return TOK_PROLOGUE;
epilogue return TOK_EPILOGUE;
-binding return TOK_BINDING;
+postface return TOK_POSTFACE;
-interface return TOK_INTERFACE;
-type return TOK_TYPE;
+ /* class member terminals */
+
+class return TOK_CLASS;
private return TOK_PRIVATE;
internal return TOK_INTERNAL;
+flags return TOK_FLAGS;
+
+type return TOK_TYPE;
+
unshared return TOK_UNSHARED;
shared return TOK_SHARED;
property return TOK_PROPERTY;
-operation return TOK_OPERATION;
+ /* implementation terminals */
+
+init return TOK_INIT;
+
+fini return TOK_FINI;
-api return TOK_API;
+method return TOK_METHOD;
getter return TOK_GETTER;
setter return TOK_SETTER;
+prototype return TOK_PROTOTYPE;
+
+ /* other terminals */
+
+{dblcolon} return TOK_DBLCOLON;
+
{cblockopen} BEGIN(cblock);
{identifier} {
@@ -138,7 +155,7 @@ setter return TOK_SETTER;
{multicomment} /* nothing */
-{poundsign}include BEGIN(incl);
+{poundsign}include BEGIN(incl);
{other} return (int) yytext[0];
@@ -149,7 +166,7 @@ setter return TOK_SETTER;
<cblock>\% yylval->text = strdup(yytext); return TOK_CCODE_LITERAL;
-<incl>[ \t]*\" /* eat the whitespace and open quotes */
+<incl>[ \t]*\" /* eat the whitespace and open quotes */
<incl>[^\t\n\"]+ {
/* got the include file name */
diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y
index 46bc4f3..1462b39 100644
--- a/src/nsgenbind-parser.y
+++ b/src/nsgenbind-parser.y
@@ -10,6 +10,12 @@
#include <stdio.h>
#include <string.h>
+#define YYFPRINTF genbind_fprintf
+#define YY_LOCATION_PRINT(File, Loc) \
+ genbind_fprintf(File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+
#include "nsgenbind-parser.h"
#include "nsgenbind-lexer.h"
#include "webidl-ast.h"
@@ -17,13 +23,74 @@
char *errtxt;
- static void nsgenbind_error(YYLTYPE *locp, struct genbind_node **genbind_ast, const char *str)
+static void nsgenbind_error(YYLTYPE *locp,
+ struct genbind_node **genbind_ast,
+ const char *str)
{
locp = locp;
genbind_ast = genbind_ast;
errtxt = strdup(str);
}
+static struct genbind_node *
+add_method(struct genbind_node **genbind_ast,
+ long methodtype,
+ struct genbind_node *declarator,
+ char *cdata)
+{
+ struct genbind_node *res_node;
+ struct genbind_node *method_node;
+ struct genbind_node *class_node;
+ struct genbind_node *cdata_node;
+ char *class_name;
+
+ /* extract the class name from the declarator */
+ class_name = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(
+ genbind_node_find_type(
+ declarator,
+ NULL,
+ GENBIND_NODE_TYPE_CLASS)),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT));
+
+ if (cdata == NULL) {
+ cdata_node = declarator;
+ } else {
+ cdata_node = genbind_new_node(GENBIND_NODE_TYPE_CDATA,
+ declarator,
+ cdata);
+ }
+
+ /* generate method node */
+ method_node = genbind_new_node(GENBIND_NODE_TYPE_METHOD,
+ NULL,
+ genbind_new_node(GENBIND_NODE_TYPE_METHOD_TYPE,
+ cdata_node,
+ (void *)methodtype));
+
+ class_node = genbind_node_find_type_ident(*genbind_ast,
+ NULL,
+ GENBIND_NODE_TYPE_CLASS,
+ class_name);
+ if (class_node == NULL) {
+ /* no existing class so manufacture one and attach method */
+ res_node = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ method_node,
+ class_name));
+
+ } else {
+ /* update the existing class */
+
+ /* link member node into class_node */
+ genbind_node_add(class_node, method_node);
+
+ res_node = NULL; /* updating so no need to add a new node */
+ }
+ return res_node;
+}
%}
@@ -37,30 +104,37 @@ char *errtxt;
%union
{
- char* text;
+ char *text;
struct genbind_node *node;
long value;
}
-%token TOK_IDLFILE
-%token TOK_HDR_COMMENT
-%token TOK_PREAMBLE
-%token TOK_PROLOGUE;
-%token TOK_EPILOGUE;
-
-%token TOK_API
%token TOK_BINDING
-%token TOK_OPERATION
-%token TOK_GETTER
-%token TOK_SETTER
-%token TOK_INTERFACE
-%token TOK_TYPE
+%token TOK_WEBIDL
+%token TOK_PREFACE
+%token TOK_PROLOGUE
+%token TOK_EPILOGUE
+%token TOK_POSTFACE
+
+%token TOK_CLASS
%token TOK_PRIVATE
%token TOK_INTERNAL
+%token TOK_FLAGS
+%token TOK_TYPE
%token TOK_UNSHARED
%token TOK_SHARED
%token TOK_PROPERTY
+ /* method types */
+%token TOK_INIT
+%token TOK_FINI
+%token TOK_METHOD
+%token TOK_GETTER
+%token TOK_SETTER
+%token TOK_PROTOTYPE
+
+%token TOK_DBLCOLON
+
%token <text> TOK_IDENTIFIER
%token <text> TOK_STRING_LITERAL
%token <text> TOK_CCODE_LITERAL
@@ -72,25 +146,30 @@ char *errtxt;
%type <node> Statement
%type <node> Statements
-%type <node> IdlFile
-%type <node> Preamble
-%type <node> Prologue
-%type <node> Epilogue
-%type <node> HdrComment
-%type <node> Strings
%type <node> Binding
%type <node> BindingArgs
%type <node> BindingArg
-%type <node> Type
+%type <node> Class
+%type <node> ClassArgs
+%type <node> ClassArg
+%type <node> ClassFlag
+%type <node> ClassFlags
+
+%type <node> Method
+%type <node> MethodDeclarator
+%type <value> MethodType
+
+%type <node> WebIDL
+%type <node> Preface
+%type <node> Prologue
+%type <node> Epilogue
+%type <node> Postface
%type <node> Private
%type <node> Internal
-%type <node> Interface
%type <node> Property
-%type <node> Operation
-%type <node> Api
-%type <node> Getter
-%type <node> Setter
+%type <node> ParameterList
+%type <node> TypeIdent
%%
@@ -109,7 +188,7 @@ Statements
|
Statements Statement
{
- $$ = genbind_node_link($2, $1);
+ $$ = *genbind_ast = genbind_node_prepend($2, $1);
}
|
error ';'
@@ -122,68 +201,88 @@ Statements
Statement
:
- IdlFile
- |
- HdrComment
- |
- Preamble
- |
- Prologue
- |
- Epilogue
- |
Binding
|
- Operation
- |
- Api
- |
- Getter
+ Class
|
- Setter
+ Method
;
- /* [3] load a web IDL file */
-IdlFile
- :
- TOK_IDLFILE TOK_STRING_LITERAL ';'
+Binding
+ :
+ TOK_BINDING TOK_IDENTIFIER '{' BindingArgs '}'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_WEBIDLFILE, NULL, $2);
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING,
+ NULL,
+ genbind_new_node(GENBIND_NODE_TYPE_TYPE, $4, $2));
}
;
-HdrComment
- :
- TOK_HDR_COMMENT Strings ';'
+BindingArgs
+ :
+ BindingArg
+ |
+ BindingArgs BindingArg
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_HDRCOMMENT, NULL, $2);
+ $$ = genbind_node_link($2, $1);
}
;
-Strings
+BindingArg
:
- TOK_STRING_LITERAL
+ WebIDL
+ |
+ Preface
+ |
+ Prologue
+ |
+ Epilogue
+ |
+ Postface
+ ;
+
+ /* [3] a web IDL file specifier */
+WebIDL
+ :
+ TOK_WEBIDL TOK_STRING_LITERAL ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_STRING, NULL, $1);
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_WEBIDL, NULL, $2);
}
- |
- Strings TOK_STRING_LITERAL
+ ;
+
+
+ /* type and identifier of a variable */
+TypeIdent
+ :
+ TOK_STRING_LITERAL TOK_IDENTIFIER
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ genbind_new_node(GENBIND_NODE_TYPE_TYPE, NULL, $1), $2);
+ }
+ |
+ TOK_STRING_LITERAL TOK_IDENTIFIER TOK_DBLCOLON TOK_IDENTIFIER
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_STRING, $1, $2);
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ genbind_new_node(GENBIND_NODE_TYPE_TYPE,
+ NULL,
+ $1),
+ $2),
+ $4);
}
;
-Preamble
+Preface
:
- TOK_PREAMBLE CBlock
+ TOK_PREFACE CBlock ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_PREAMBLE, NULL, $2);
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_PREFACE, NULL, $2);
}
;
Prologue
:
- TOK_PROLOGUE CBlock
+ TOK_PROLOGUE CBlock ';'
{
$$ = genbind_new_node(GENBIND_NODE_TYPE_PROLOGUE, NULL, $2);
}
@@ -191,140 +290,208 @@ Prologue
Epilogue
:
- TOK_EPILOGUE CBlock
+ TOK_EPILOGUE CBlock ';'
{
$$ = genbind_new_node(GENBIND_NODE_TYPE_EPILOGUE, NULL, $2);
}
;
+Postface
+ :
+ TOK_POSTFACE CBlock ';'
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_POSTFACE, NULL, $2);
+ }
+ ;
+
CBlock
- :
+ :
TOK_CCODE_LITERAL
- |
- CBlock TOK_CCODE_LITERAL
+ |
+ CBlock TOK_CCODE_LITERAL
{
$$ = genbind_strapp($1, $2);
}
;
-Operation
+MethodType
:
- TOK_OPERATION TOK_IDENTIFIER CBlock
+ TOK_INIT
+ {
+ $$ = GENBIND_METHOD_TYPE_INIT;
+ }
+ |
+ TOK_FINI
+ {
+ $$ = GENBIND_METHOD_TYPE_FINI;
+ }
+ |
+ TOK_METHOD
+ {
+ $$ = GENBIND_METHOD_TYPE_METHOD;
+ }
+ |
+ TOK_GETTER
+ {
+ $$ = GENBIND_METHOD_TYPE_GETTER;
+ }
+ |
+ TOK_SETTER
+ {
+ $$ = GENBIND_METHOD_TYPE_SETTER;
+ }
+ |
+ TOK_PROTOTYPE
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_OPERATION,
- NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- genbind_new_node(GENBIND_NODE_TYPE_CBLOCK,
- NULL,
- $3),
- $2));
+ $$ = GENBIND_METHOD_TYPE_PROTOTYPE;
}
+ ;
-Api
+ParameterList
:
- TOK_API TOK_IDENTIFIER CBlock
+ TypeIdent
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_PARAMETER, NULL, $1);
+ }
+ |
+ ParameterList ',' TypeIdent
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_API,
- NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- genbind_new_node(GENBIND_NODE_TYPE_CBLOCK,
- NULL,
- $3),
- $2));
+ $$ = genbind_node_prepend($1,
+ genbind_new_node(
+ GENBIND_NODE_TYPE_PARAMETER,
+ NULL,
+ $3));
}
+ ;
-Getter
+MethodDeclarator
:
- TOK_GETTER TOK_IDENTIFIER CBlock
+ TOK_IDENTIFIER TOK_DBLCOLON TOK_IDENTIFIER '(' ParameterList ')'
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ $5,
+ $3),
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ NULL,
+ $1));
+ }
+ |
+ TOK_IDENTIFIER TOK_DBLCOLON TOK_IDENTIFIER '(' ')'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_GETTER,
- NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- genbind_new_node(GENBIND_NODE_TYPE_CBLOCK,
- NULL,
- $3),
- $2));
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ NULL,
+ $3),
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ NULL,
+ $1));
}
+ |
+ TOK_IDENTIFIER '(' ParameterList ')'
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS,
+ $3,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ NULL,
+ $1));
+ }
+ |
+ TOK_IDENTIFIER '(' ')'
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ NULL,
+ $1));
+ }
+ ;
-Setter
+Method
:
- TOK_SETTER TOK_IDENTIFIER CBlock
+ MethodType MethodDeclarator CBlock
+ {
+ $$ = add_method(genbind_ast, $1, $2, $3);
+ }
+ |
+ MethodType MethodDeclarator ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_SETTER,
- NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- genbind_new_node(GENBIND_NODE_TYPE_CBLOCK,
- NULL,
- $3),
- $2));
+ $$ = add_method(genbind_ast, $1, $2, NULL);
}
+ ;
-Binding
+Class
:
- TOK_BINDING TOK_IDENTIFIER '{' BindingArgs '}'
+ TOK_CLASS TOK_IDENTIFIER '{' ClassArgs '}'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING,
- NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT, $4, $2));
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT, $4, $2));
}
;
-BindingArgs
+ClassArgs
:
- BindingArg
+ ClassArg
|
- BindingArgs BindingArg
+ ClassArgs ClassArg
{
- $$ = genbind_node_link($2, $1);
+ $$ = genbind_node_link($2, $1);
}
;
-BindingArg
- :
- Type
- |
+ClassArg
+ :
Private
|
Internal
|
- Interface
- |
Property
+ |
+ ClassFlag
+ |
+ Preface
+ |
+ Prologue
+ |
+ Epilogue
+ |
+ Postface
;
-Type
+
+Private
:
- TOK_TYPE TOK_IDENTIFIER ';'
+ TOK_PRIVATE TypeIdent ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_TYPE, NULL, $2);
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_PRIVATE, NULL, $2);
}
;
-Private
+Internal
:
- TOK_PRIVATE TOK_STRING_LITERAL TOK_IDENTIFIER ';'
+ TOK_INTERNAL TypeIdent ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_PRIVATE, NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- genbind_new_node(GENBIND_NODE_TYPE_STRING, NULL, $2), $3));
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_INTERNAL, NULL, $2);
}
;
-Internal
+ClassFlag
:
- TOK_INTERNAL TOK_STRING_LITERAL TOK_IDENTIFIER ';'
+ TOK_FLAGS ClassFlags ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERNAL, NULL,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- genbind_new_node(GENBIND_NODE_TYPE_STRING, NULL, $2), $3));
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_FLAGS, NULL, $2);
}
;
-Interface
- :
- TOK_INTERFACE TOK_IDENTIFIER ';'
+ClassFlags
+ :
+ TOK_IDENTIFIER
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, NULL, $2);
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $1);
+ }
+ |
+ ClassFlags ',' TOK_IDENTIFIER
+ {
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, $1, $3);
}
;
@@ -332,13 +499,12 @@ Property
:
TOK_PROPERTY Modifiers TOK_IDENTIFIER ';'
{
- $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_PROPERTY,
- NULL,
- genbind_new_node(GENBIND_NODE_TYPE_MODIFIER,
- genbind_new_node(GENBIND_NODE_TYPE_IDENT,
- NULL,
- $3),
- (void *)$2));
+ $$ = genbind_new_node(GENBIND_NODE_TYPE_PROPERTY, NULL,
+ genbind_new_node(GENBIND_NODE_TYPE_MODIFIER,
+ genbind_new_node(GENBIND_NODE_TYPE_IDENT,
+ NULL,
+ $3),
+ (void *)$2));
}
;
diff --git a/src/nsgenbind.c b/src/nsgenbind.c
index d993646..173f23d 100644
--- a/src/nsgenbind.c
+++ b/src/nsgenbind.c
@@ -14,149 +14,233 @@
#include <getopt.h>
#include <errno.h>
+#include "options.h"
#include "nsgenbind-ast.h"
+#include "webidl-ast.h"
+#include "interface-map.h"
#include "jsapi-libdom.h"
-#include "options.h"
+#include "duk-libdom.h"
struct options *options;
+enum bindingtype_e {
+ BINDINGTYPE_UNKNOWN,
+ BINDINGTYPE_JSAPI_LIBDOM,
+ BINDINGTYPE_DUK_LIBDOM,
+};
+
static struct options* process_cmdline(int argc, char **argv)
{
- int opt;
-
- options = calloc(1,sizeof(struct options));
- if (options == NULL) {
- fprintf(stderr, "Allocation error\n");
- return NULL;
- }
-
- while ((opt = getopt(argc, argv, "vgDW::d:I:o:h:")) != -1) {
- switch (opt) {
- case 'I':
- options->idlpath = strdup(optarg);
- break;
-
- case 'o':
- options->outfilename = strdup(optarg);
- break;
-
- case 'h':
- options->hdrfilename = strdup(optarg);
- break;
-
- case 'd':
- options->depfilename = strdup(optarg);
- break;
-
- case 'v':
- options->verbose = true;
- break;
-
- case 'D':
- options->debug = true;
- break;
-
- case 'g':
- options->dbglog = true;
- break;
-
- case 'W':
- options->warnings = 1; /* warning flags */
- break;
-
- default: /* '?' */
- fprintf(stderr,
- "Usage: %s [-v] [-g] [-D] [-W] [-d depfilename] [-I idlpath] [-o filename] [-h headerfile] inputfile\n",
- argv[0]);
- free(options);
- return NULL;
-
- }
- }
-
- if (optind >= argc) {
- fprintf(stderr, "Error: expected input filename\n");
- free(options);
- return NULL;
- }
-
- options->infilename = strdup(argv[optind]);
-
- return options;
+ int opt;
+
+ options = calloc(1,sizeof(struct options));
+ if (options == NULL) {
+ fprintf(stderr, "Allocation error\n");
+ return NULL;
+ }
+
+ while ((opt = getopt(argc, argv, "vgDW::I:")) != -1) {
+ switch (opt) {
+ case 'I':
+ options->idlpath = strdup(optarg);
+ break;
+
+ case 'v':
+ options->verbose = true;
+ break;
+
+ case 'D':
+ options->debug = true;
+ break;
+
+ case 'g':
+ options->dbglog = true;
+ break;
+
+ case 'W':
+ if ((optarg == NULL) ||
+ (strcmp(optarg, "all") == 0)) {
+ /* all warnings */
+ options->warnings |= WARNING_ALL;
+ } else if (strcmp(optarg, "unimplemented") == 0) {
+ options->warnings |= WARNING_UNIMPLEMENTED;
+ } else if (strcmp(optarg, "duplicated") == 0) {
+ options->warnings |= WARNING_DUPLICATED;
+ } else {
+ fprintf(stderr,
+ "Unknown warning option \"%s\" valid options are: all, unimplemented\n",
+ optarg);
+ free(options);
+ return NULL;
+
+ }
+ break;
+
+ default: /* '?' */
+ fprintf(stderr,
+ "Usage: %s [-v] [-g] [-D] [-W] [-I idlpath] inputfile outputdir\n",
+ argv[0]);
+ free(options);
+ return NULL;
+ }
+ }
+
+ if (optind > (argc - 2)) {
+ fprintf(stderr,
+ "Error: expected input filename and output directory\n");
+ free(options);
+ return NULL;
+ }
+
+ options->infilename = strdup(argv[optind]);
+
+ options->outdirname = strdup(argv[optind + 1]);
+
+ return options;
}
-int main(int argc, char **argv)
+static int webidl_file_cb(struct genbind_node *node, void *ctx)
{
- int res;
- struct genbind_node *genbind_root;
-
- options = process_cmdline(argc, argv);
- if (options == NULL) {
- return 1; /* bad commandline */
- }
-
- if (options->verbose &&
- (options->outfilename == NULL)) {
- fprintf(stderr,
- "Error: output to stdout with verbose logging would fail\n");
- return 2;
- }
+ struct webidl_node **webidl_ast = ctx;
+ char *filename;
- if (options->depfilename != NULL &&
- options->outfilename == NULL) {
- fprintf(stderr,
- "Error: output to stdout with dep generation would fail\n");
- return 3;
- }
+ filename = genbind_node_gettext(node);
- if (options->depfilename != NULL &&
- options->infilename == NULL) {
- fprintf(stderr,
- "Error: input from stdin with dep generation would fail\n");
- return 3;
- }
+ if (options->verbose) {
+ printf("Opening IDL file \"%s\"\n", filename);
+ }
- if (options->depfilename != NULL) {
- options->depfilehandle = fopen(options->depfilename, "w");
- if (options->depfilehandle == NULL) {
- fprintf(stderr,
- "Error: unable to open dep file\n");
- return 4;
- }
- fprintf(options->depfilehandle,
- "%s %s :", options->depfilename,
- options->outfilename);
- }
+ return webidl_parsefile(filename, webidl_ast);
+}
- res = genbind_parsefile(options->infilename, &genbind_root);
+static int genbind_load_idl(struct genbind_node *genbind,
+ struct webidl_node **webidl_out)
+{
+ int res;
+ struct genbind_node *binding_node;
+
+ binding_node = genbind_node_find_type(genbind, NULL,
+ GENBIND_NODE_TYPE_BINDING);
+
+ /* walk AST and load any web IDL files required */
+ res = genbind_node_foreach_type(
+ genbind_node_getnode(binding_node),
+ GENBIND_NODE_TYPE_WEBIDL,
+ webidl_file_cb,
+ webidl_out);
if (res != 0) {
- fprintf(stderr, "Error: parse failed with code %d\n", res);
- return res;
- }
-
- if (options->verbose) {
- genbind_ast_dump(genbind_root, 0);
+ fprintf(stderr, "Error: failed reading Web IDL\n");
+ return -1;
}
- res = jsapi_libdom_output(options->outfilename,
- options->hdrfilename,
- genbind_root);
+ /* implements are implemented as mixins so intercalate them */
+ res = webidl_intercalate_implements(*webidl_out);
if (res != 0) {
- fprintf(stderr, "Error: output failed with code %d\n", res);
- if (options->outfilename != NULL) {
- unlink(options->outfilename);
- }
- if (options->hdrfilename != NULL) {
- unlink(options->hdrfilename);
- }
- return res;
+ fprintf(stderr, "Error: Failed to intercalate implements\n");
+ return -1;
}
- if (options->depfilehandle != NULL) {
- fputc('\n', options->depfilehandle);
- fclose(options->depfilehandle);
- }
+ return 0;
+}
+
+/**
+ * get the type of binding
+ */
+static enum bindingtype_e genbind_get_type(struct genbind_node *node)
+{
+ struct genbind_node *binding_node;
+ const char *binding_type;
+
+ binding_node = genbind_node_find_type(node,
+ NULL,
+ GENBIND_NODE_TYPE_BINDING);
+ if (binding_node == NULL) {
+ /* binding entry is missing which is invalid */
+ return BINDINGTYPE_UNKNOWN;
+ }
+
+ binding_type = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(binding_node),
+ NULL,
+ GENBIND_NODE_TYPE_TYPE));
+ if (binding_type == NULL) {
+ fprintf(stderr, "Error: missing binding type\n");
+ return BINDINGTYPE_UNKNOWN;
+ }
+
+ if (strcmp(binding_type, "jsapi_libdom") == 0) {
+ return BINDINGTYPE_JSAPI_LIBDOM;
+ }
+
+ if (strcmp(binding_type, "duk_libdom") == 0) {
+ return BINDINGTYPE_DUK_LIBDOM;
+ }
+
+ fprintf(stderr, "Error: unsupported binding type \"%s\"\n", binding_type);
+
+ return BINDINGTYPE_UNKNOWN;
+}
- return 0;
-}
+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);
+ if (options == NULL) {
+ return 1; /* bad commandline */
+ }
+
+ /* parse binding */
+ res = genbind_parsefile(options->infilename, &genbind_root);
+ if (res != 0) {
+ fprintf(stderr, "Error: parse failed with code %d\n", res);
+ return res;
+ }
+
+ /* dump the binding AST */
+ genbind_dump_ast(genbind_root);
+
+ /* get type of binding */
+ bindingtype = genbind_get_type(genbind_root);
+ if (bindingtype == BINDINGTYPE_UNKNOWN) {
+ return 3;
+ }
+
+ /* load the IDL files specified in the binding */
+ res = genbind_load_idl(genbind_root, &webidl_root);
+ if (res != 0) {
+ return 4;
+ }
+
+ /* debug dump of web idl AST */
+ webidl_dump_ast(webidl_root);
+
+ /* generate map of WebIDL interfaces 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);
+
+ /* generate binding */
+ switch (bindingtype) {
+ case BINDINGTYPE_DUK_LIBDOM:
+ res = duk_libdom_output(interface_map);
+ break;
+
+ default:
+ fprintf(stderr, "Unable to generate binding of this type\n");
+ res = 7;
+ }
+
+ return res;
+}
diff --git a/src/options.h b/src/options.h
index 13c02be..02674b7 100644
--- a/src/options.h
+++ b/src/options.h
@@ -12,12 +12,7 @@
/** global options */
struct options {
char *infilename; /**< binding source */
-
- char *outfilename; /**< output source file */
- char *hdrfilename; /**< output header file */
-
- char *depfilename; /**< dependancy output*/
- FILE *depfilehandle; /**< dependancy file handle */
+ char *outdirname; /**< output directory */
char *idlpath; /**< path to IDL files */
bool verbose; /**< verbose processing */
@@ -30,13 +25,14 @@ 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) { \
- fprintf(stderr, "%s: warning:"msg"\n", __func__, ## args); \
+ fprintf(stderr, "%s: warning: "msg"\n", __func__, ## args); \
} \
} while(0)
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..0952744
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,160 @@
+/* utility functions
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "options.h"
+#include "utils.h"
+
+/* exported function documented in utils.h */
+char *genb_fpath(const char *fname)
+{
+ char *fpath;
+ int fpathl;
+
+ fpathl = strlen(options->outdirname) + strlen(fname) + 2;
+ fpath = malloc(fpathl);
+ snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname);
+
+ return fpath;
+}
+
+static char *genb_fpath_tmp(const char *fname)
+{
+ char *fpath;
+ int fpathl;
+
+ fpathl = strlen(options->outdirname) + strlen(fname) + 3;
+ fpath = malloc(fpathl);
+ snprintf(fpath, fpathl, "%s/%s.%d", options->outdirname, fname, getpid());
+
+ return fpath;
+}
+
+/* exported function documented in utils.h */
+FILE *genb_fopen(const char *fname, const char *mode)
+{
+ char *fpath;
+ FILE *filef;
+
+ fpath = genb_fpath(fname);
+
+ filef = fopen(fpath, mode);
+ if (filef == NULL) {
+ fprintf(stderr, "Error: unable to open file %s (%s)\n",
+ fpath, strerror(errno));
+ free(fpath);
+ return NULL;
+ }
+ free(fpath);
+
+ return filef;
+}
+
+/* exported function documented in utils.h */
+FILE *genb_fopen_tmp(const char *fname)
+{
+ char *fpath;
+ FILE *filef;
+
+ fpath = genb_fpath_tmp(fname);
+
+ filef = fopen(fpath, "w+");
+ if (filef == NULL) {
+ fprintf(stderr, "Error: unable to open file %s (%s)\n",
+ fpath, strerror(errno));
+ free(fpath);
+ return NULL;
+ }
+ free(fpath);
+
+ return filef;
+}
+
+int genb_fclose_tmp(FILE *filef_tmp, const char *fname)
+{
+ char *fpath;
+ char *tpath;
+ FILE *filef;
+ char tbuf[1024];
+ char fbuf[1024];
+ size_t trd;
+ size_t frd;
+
+ fpath = genb_fpath(fname);
+ tpath = genb_fpath_tmp(fname);
+
+ filef = fopen(fpath, "r");
+ if (filef == NULL) {
+ /* unable to open target file for comparison */
+
+ fclose(filef_tmp); /* close tmpfile */
+
+ remove(fpath);
+ rename(tpath, fpath);
+ } else {
+ rewind(filef_tmp);
+
+ frd = fread(fbuf, 1, 1024, filef);
+ while (frd != 0) {
+ trd = fread(tbuf, 1, frd, filef_tmp);
+ if ((trd != frd) ||
+ (memcmp(tbuf, fbuf, trd) != 0)) {
+ /* file doesnt match */
+ fclose(filef_tmp);
+ fclose(filef);
+
+ remove(fpath);
+ rename(tpath, fpath);
+
+ goto close_done;
+ }
+
+ frd = fread(fbuf, 1, 1024, filef);
+ }
+
+ /* was the same kill temporary file */
+ fclose(filef_tmp);
+ fclose(filef);
+ remove(tpath);
+ }
+
+close_done:
+ free(fpath);
+ free(tpath);
+
+ return 0;
+}
+
+
+#ifdef NEED_STRNDUP
+
+char *strndup(const char *s, size_t n)
+{
+ size_t len;
+ char *s2;
+
+ for (len = 0; len != n && s[len]; len++)
+ continue;
+
+ s2 = malloc(len + 1);
+ if (!s2)
+ return 0;
+
+ memcpy(s2, s, len);
+ s2[len] = 0;
+ return s2;
+}
+
+#endif
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..508d1c1
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,46 @@
+/* utility helpers
+ *
+ * This file is part of nsnsgenbind.
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
+ */
+
+#ifndef nsgenbind_utils_h
+#define nsgenbind_utils_h
+
+/**
+ * get a pathname with the output prefix prepended
+ *
+ * \param fname leaf filename.
+ * \return full prefixed path to file caller must free
+ */
+char *genb_fpath(const char *fname);
+
+/**
+ * Open file allowing for output path prefix
+ */
+FILE *genb_fopen(const char *fname, const char *mode);
+
+/**
+ * Open file allowing for output path prefix
+ *
+ * file is opened for reading/writing with a temporary suffix allowing for the
+ * matching close call to check the output is different before touching the
+ * target file.
+ */
+FILE *genb_fopen_tmp(const char *fname);
+
+/**
+ * Close file opened with genb_fopen
+ */
+int genb_fclose_tmp(FILE *filef, const char *fname);
+
+#ifdef _WIN32
+#define NEED_STRNDUP 1
+char *strndup(const char *s, size_t n);
+#endif
+
+#define SLEN(x) (sizeof((x)) - 1)
+
+#endif
diff --git a/src/webidl-ast.c b/src/webidl-ast.c
index d75a186..87e3485 100644
--- a/src/webidl-ast.c
+++ b/src/webidl-ast.c
@@ -11,18 +11,25 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <stdarg.h>
+#include "utils.h"
#include "webidl-ast.h"
#include "options.h"
+/**
+ * standard IO handle for parse trace logging.
+ */
+static FILE *webidl_parsetracef;
+
extern int webidl_debug;
extern int webidl__flex_debug;
extern void webidl_restart(FILE*);
extern int webidl_parse(struct webidl_node **webidl_ast);
struct webidl_node {
- enum webidl_node_type type;
- struct webidl_node *l;
+ enum webidl_node_type type; /* the type of the node */
+ struct webidl_node *l; /* link to the next sibling node */
union {
void *value;
struct webidl_node *node; /* node has a list of nodes */
@@ -93,7 +100,7 @@ webidl_node_add(struct webidl_node *node, struct webidl_node *list)
case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE:
case WEBIDL_NODE_TYPE_ATTRIBUTE:
case WEBIDL_NODE_TYPE_OPERATION:
- case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT:
+ case WEBIDL_NODE_TYPE_OPTIONAL:
case WEBIDL_NODE_TYPE_ARGUMENT:
case WEBIDL_NODE_TYPE_TYPE:
case WEBIDL_NODE_TYPE_CONST:
@@ -162,6 +169,26 @@ int webidl_cmp_node_type(struct webidl_node *node, void *ctx)
return 0;
}
+static int webidl_enumerate_node(struct webidl_node *node, void *ctx)
+{
+ node = node;
+ (*((int *)ctx))++;
+ return 0;
+}
+
+/* exported interface defined in nsgenbind-ast.h */
+int
+webidl_node_enumerate_type(struct webidl_node *node,
+ enum webidl_node_type type)
+{
+ int count = 0;
+ webidl_node_for_each_type(node,
+ type,
+ webidl_enumerate_node,
+ &count);
+ return count;
+}
+
/* exported interface defined in webidl-ast.h */
struct webidl_node *
webidl_node_find(struct webidl_node *node,
@@ -203,6 +230,7 @@ webidl_node_find_type(struct webidl_node *node,
}
+/* exported interface defined in webidl-ast.h */
struct webidl_node *
webidl_node_find_type_ident(struct webidl_node *root_node,
enum webidl_node_type type,
@@ -230,6 +258,7 @@ webidl_node_find_type_ident(struct webidl_node *root_node,
}
+/* exported interface defined in webidl-ast.h */
char *webidl_node_gettext(struct webidl_node *node)
{
if (node != NULL) {
@@ -238,16 +267,18 @@ char *webidl_node_gettext(struct webidl_node *node)
case WEBIDL_NODE_TYPE_IDENT:
case WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE:
case WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS:
+ case WEBIDL_NODE_TYPE_LITERAL_STRING:
return node->r.text;
default:
- break;
+ break;
}
}
return NULL;
}
-int
+/* exported interface defined in webidl-ast.h */
+int *
webidl_node_getint(struct webidl_node *node)
{
if (node != NULL) {
@@ -255,22 +286,25 @@ webidl_node_getint(struct webidl_node *node)
case WEBIDL_NODE_TYPE_MODIFIER:
case WEBIDL_NODE_TYPE_TYPE_BASE:
case WEBIDL_NODE_TYPE_LITERAL_INT:
- return node->r.number;
+ case WEBIDL_NODE_TYPE_SPECIAL:
+ case WEBIDL_NODE_TYPE_LITERAL_BOOL:
+ return &node->r.number;
default:
break;
}
}
- return -1;
-
+ return NULL;
}
+/* exported interface defined in webidl-ast.h */
enum webidl_node_type webidl_node_gettype(struct webidl_node *node)
{
return node->type;
}
+/* exported interface defined in webidl-ast.h */
struct webidl_node *webidl_node_getnode(struct webidl_node *node)
{
if (node != NULL) {
@@ -281,7 +315,7 @@ struct webidl_node *webidl_node_getnode(struct webidl_node *node)
case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE:
case WEBIDL_NODE_TYPE_ATTRIBUTE:
case WEBIDL_NODE_TYPE_OPERATION:
- case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT:
+ case WEBIDL_NODE_TYPE_OPTIONAL:
case WEBIDL_NODE_TYPE_ARGUMENT:
case WEBIDL_NODE_TYPE_TYPE:
case WEBIDL_NODE_TYPE_CONST:
@@ -294,6 +328,7 @@ struct webidl_node *webidl_node_getnode(struct webidl_node *node)
}
+/* exported interface defined in webidl-ast.h */
static const char *webidl_node_type_to_str(enum webidl_node_type type)
{
switch(type) {
@@ -321,8 +356,8 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type)
case WEBIDL_NODE_TYPE_OPERATION:
return "Operation";
- case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT:
- return "Argument(opt)";
+ case WEBIDL_NODE_TYPE_OPTIONAL:
+ return "Optional";
case WEBIDL_NODE_TYPE_ARGUMENT:
return "Argument";
@@ -348,24 +383,44 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type)
case WEBIDL_NODE_TYPE_CONST:
return "Const";
+ case WEBIDL_NODE_TYPE_LITERAL_NULL:
+ return "Literal (null)";
+
case WEBIDL_NODE_TYPE_LITERAL_INT:
return "Literal (int)";
+ case WEBIDL_NODE_TYPE_LITERAL_BOOL:
+ return "Literal (bool)";
+
+ case WEBIDL_NODE_TYPE_LITERAL_FLOAT:
+ return "Literal (string)";
+
+ case WEBIDL_NODE_TYPE_LITERAL_STRING:
+ return "Literal (string)";
+
case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE:
return "Extended Attribute";
+ case WEBIDL_NODE_TYPE_SPECIAL:
+ return "Special";
+
default:
return "Unknown";
}
}
-
-int webidl_ast_dump(struct webidl_node *node, int indent)
+/**
+ * Recursively dump the AST nodes increasing indent as appropriate
+ */
+static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent)
{
- const char *SPACES=" "; char *txt;
+ const char *SPACES=" ";
+ char *txt;
+ int *value;
while (node != NULL) {
- printf("%.*s%s", indent, SPACES, webidl_node_type_to_str(node->type));
+ fprintf(dumpf, "%.*s%s", indent, SPACES,
+ webidl_node_type_to_str(node->type));
txt = webidl_node_gettext(node);
if (txt == NULL) {
@@ -374,32 +429,61 @@ int webidl_ast_dump(struct webidl_node *node, int indent)
next = webidl_node_getnode(node);
if (next != NULL) {
- printf("\n");
- webidl_ast_dump(next, indent + 2);
+ fprintf(dumpf, "\n");
+ webidl_ast_dump(dumpf, next, indent + 2);
} else {
- /* not txt or node has to be an int */
- printf(": %d\n", webidl_node_getint(node));
+ /* not txt or node try an int */
+ value = webidl_node_getint(node);
+ if (value != NULL) {
+ fprintf(dumpf, ": %d\n", *value);
+ } else {
+ /* no value */
+ fprintf(dumpf, "\n");
+ }
}
} else {
- printf(": \"%s\"\n", txt);
+ fprintf(dumpf, ": \"%s\"\n", txt);
}
node = node->l;
}
return 0;
}
+/* exported interface documented in webidl-ast.h */
+int webidl_dump_ast(struct webidl_node *node)
+{
+ FILE *dumpf;
+
+ /* only dump AST to file if required */
+ if (!options->debug) {
+ return 0;
+ }
+
+ dumpf = genb_fopen("webidl-ast", "w");
+ if (dumpf == NULL) {
+ return 2;
+ }
+
+ webidl_ast_dump(dumpf, node, 0);
+
+ fclose(dumpf);
+
+ return 0;
+}
+
+/* exported interface defined in webidl-ast.h */
static FILE *idlopen(const char *filename)
{
FILE *idlfile;
char *fullname;
- int fulllen;
+ int fulllen;
if (options->idlpath == NULL) {
if (options->verbose) {
printf("Opening IDL file %s\n", filename);
}
return fopen(filename, "r");
- }
+ }
fulllen = strlen(options->idlpath) + strlen(filename) + 2;
fullname = malloc(fulllen);
@@ -409,14 +493,15 @@ static FILE *idlopen(const char *filename)
}
idlfile = fopen(fullname, "r");
free(fullname);
-
+
return idlfile;
}
+/* exported interface defined in webidl-ast.h */
int webidl_parsefile(char *filename, struct webidl_node **webidl_ast)
{
-
FILE *idlfile;
+ int ret;
idlfile = idlopen(filename);
if (!idlfile) {
@@ -426,14 +511,153 @@ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast)
return 2;
}
- if (options->debug) {
+ /* if debugging enabled enable parser tracing and send to file */
+ if (options->debug) {
+ char *tracename;
+ int tracenamelen;
webidl_debug = 1;
webidl__flex_debug = 1;
- }
+
+ tracenamelen = SLEN("webidl--trace") + strlen(filename) + 1;
+ tracename = malloc(tracenamelen);
+ snprintf(tracename, tracenamelen,"webidl-%s-trace", filename);
+ webidl_parsetracef = genb_fopen(tracename, "w");
+ free(tracename);
+ } else {
+ webidl_parsetracef = NULL;
+ }
/* set flex to read from file */
webidl_restart(idlfile);
/* parse the file */
- return webidl_parse(webidl_ast);
+ ret = webidl_parse(webidl_ast);
+
+ /* close tracefile if open */
+ if (webidl_parsetracef != NULL) {
+ fclose(webidl_parsetracef);
+ }
+ return ret;
+}
+
+/* exported interface defined in webidl-ast.h */
+int webidl_fprintf(FILE *stream, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+
+ if (webidl_parsetracef == NULL) {
+ ret = vfprintf(stream, format, ap);
+ } else {
+ ret = vfprintf(webidl_parsetracef, format, ap);
+ }
+ va_end(ap);
+
+ return ret;
+}
+
+/* unlink a child node from a parent */
+static int
+webidl_unlink(struct webidl_node *parent, struct webidl_node *node)
+{
+ struct webidl_node *child;
+
+ child = webidl_node_getnode(parent);
+ if (child == NULL) {
+ /* parent does not have children to remove node from */
+ return -1;
+ }
+
+ if (child == node) {
+ /* parent is pointing at the node we want to remove */
+ parent->r.node = node->l; /* point parent at next sibing */
+ node->l = NULL;
+ return 0;
+ }
+
+ while (child->l != NULL) {
+ if (child->l == node) {
+ /* found node, unlink from list */
+ child->l = node->l;
+ node->l = NULL;
+ return 0;
+ }
+ child = child->l;
+ }
+ return -1; /* failed to remove node */
+}
+
+static int implements_copy_nodes(struct webidl_node *src_node,
+ struct webidl_node *dst_node)
+{
+ struct webidl_node *src;
+ struct webidl_node *dst;
+
+ src = webidl_node_getnode(src_node);
+ dst = webidl_node_getnode(dst_node);
+
+ while (src != NULL) {
+ if (src->type == WEBIDL_NODE_TYPE_LIST) {
+ /** @todo technicaly this should copy WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE */
+ dst = webidl_node_new(src->type, dst, src->r.text);
+ }
+ src = src->l;
+ }
+
+ dst_node->r.node = dst;
+
+ return 0;
+}
+
+static int
+intercalate_implements(struct webidl_node *interface_node, void *ctx)
+{
+ struct webidl_node *implements_node;
+ struct webidl_node *implements_interface_node;
+ struct webidl_node *webidl_ast = ctx;
+
+ implements_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ NULL,
+ WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS);
+ while (implements_node != NULL) {
+
+ implements_interface_node = webidl_node_find_type_ident(
+ webidl_ast,
+ WEBIDL_NODE_TYPE_INTERFACE,
+ webidl_node_gettext(implements_node));
+
+ /* recurse, ensuring all subordinate interfaces have
+ * their implements intercalated first
+ */
+ intercalate_implements(implements_interface_node, webidl_ast);
+
+ implements_copy_nodes(implements_interface_node, interface_node);
+
+ /* once we have copied the implemntation remove entry */
+ webidl_unlink(interface_node, implements_node);
+
+ implements_node = webidl_node_find_type(
+ webidl_node_getnode(interface_node),
+ implements_node,
+ WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS);
+ }
+ return 0;
+}
+
+/* exported interface defined in webidl-ast.h */
+int webidl_intercalate_implements(struct webidl_node *webidl_ast)
+{
+ /* for each interface:
+ * for each implements entry:
+ * find interface from implemets
+ * recusrse into that interface
+ * copy the interface into this one
+ */
+ return webidl_node_for_each_type(webidl_ast,
+ WEBIDL_NODE_TYPE_INTERFACE,
+ intercalate_implements,
+ webidl_ast);
}
diff --git a/src/webidl-ast.h b/src/webidl-ast.h
index 70518fd..25ef9a0 100644
--- a/src/webidl-ast.h
+++ b/src/webidl-ast.h
@@ -27,8 +27,9 @@ enum webidl_node_type {
WEBIDL_NODE_TYPE_OPERATION,
WEBIDL_NODE_TYPE_CONST,
- WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT,
+ WEBIDL_NODE_TYPE_SPECIAL,
WEBIDL_NODE_TYPE_ARGUMENT,
+ WEBIDL_NODE_TYPE_OPTIONAL,
WEBIDL_NODE_TYPE_ELLIPSIS,
WEBIDL_NODE_TYPE_TYPE,
WEBIDL_NODE_TYPE_TYPE_BASE,
@@ -39,6 +40,7 @@ enum webidl_node_type {
WEBIDL_NODE_TYPE_LITERAL_INT,
WEBIDL_NODE_TYPE_LITERAL_BOOL,
WEBIDL_NODE_TYPE_LITERAL_FLOAT,
+ WEBIDL_NODE_TYPE_LITERAL_STRING,
WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE,
@@ -62,9 +64,19 @@ enum webidl_type {
};
enum webidl_type_modifier {
+ WEBIDL_TYPE_MODIFIER_NONE,
WEBIDL_TYPE_MODIFIER_UNSIGNED,
WEBIDL_TYPE_MODIFIER_UNRESTRICTED,
- WEBIDL_TYPE_READONLY,
+ WEBIDL_TYPE_MODIFIER_READONLY,
+};
+
+/* the type of special node */
+enum webidl_type_special {
+ WEBIDL_TYPE_SPECIAL_GETTER,
+ WEBIDL_TYPE_SPECIAL_SETTER,
+ WEBIDL_TYPE_SPECIAL_CREATOR,
+ WEBIDL_TYPE_SPECIAL_DELETER,
+ WEBIDL_TYPE_SPECIAL_LEGACYCALLER,
};
struct webidl_node;
@@ -86,24 +98,34 @@ struct webidl_node *webidl_node_add(struct webidl_node *node, struct webidl_node
/* node contents acessors */
char *webidl_node_gettext(struct webidl_node *node);
struct webidl_node *webidl_node_getnode(struct webidl_node *node);
-int webidl_node_getint(struct webidl_node *node);
+int *webidl_node_getint(struct webidl_node *node);
enum webidl_node_type webidl_node_gettype(struct webidl_node *node);
/* node searches */
+
+/**
+ * Iterate nodes children matching their type.
+ *
+ * For each child node where the type is matched the callback function is
+ * called with a context value.
+ */
int webidl_node_for_each_type(struct webidl_node *node,
- enum webidl_node_type type,
- webidl_callback_t *cb,
+ enum webidl_node_type type,
+ webidl_callback_t *cb,
void *ctx);
+int webidl_node_enumerate_type(struct webidl_node *node,
+ enum webidl_node_type type);
+
struct webidl_node *
webidl_node_find(struct webidl_node *node,
- struct webidl_node *prev,
- webidl_callback_t *cb,
+ struct webidl_node *prev,
+ webidl_callback_t *cb,
void *ctx);
struct webidl_node *
webidl_node_find_type(struct webidl_node *node,
- struct webidl_node *prev,
+ struct webidl_node *prev,
enum webidl_node_type type);
struct webidl_node *
@@ -112,10 +134,26 @@ webidl_node_find_type_ident(struct webidl_node *root_node,
const char *ident);
-/* debug dump */
-int webidl_ast_dump(struct webidl_node *node, int indent);
-/** parse web idl file */
+/**
+ * parse web idl file into Abstract Syntax Tree
+ */
int webidl_parsefile(char *filename, struct webidl_node **webidl_ast);
+/**
+ * dump AST to file
+ */
+int webidl_dump_ast(struct webidl_node *node);
+
+/**
+ * perform replacement of implements elements with copies of ast data
+ */
+int webidl_intercalate_implements(struct webidl_node *node);
+
+/**
+ * formatted printf to allow webidl trace data to be written to file.
+ */
+int webidl_fprintf(FILE *stream, const char *format, ...);
+
+
#endif
diff --git a/src/webidl-lexer.l b/src/webidl-lexer.l
index 74b9bb8..8c68fdf 100644
--- a/src/webidl-lexer.l
+++ b/src/webidl-lexer.l
@@ -86,7 +86,7 @@ lineend ([\n\r]|{LS}|{PS})
hexdigit [0-9A-Fa-f]
hexint 0(x|X){hexdigit}+
-decimalint 0|([1-9][0-9]*)
+decimalint 0|([\+\-]?[1-9][0-9]*)
octalint (0[0-8]+)
@@ -207,6 +207,11 @@ void return TOK_VOID;
readonly return TOK_READONLY;
+Promise return TOK_PROMISE;
+
+iterable return TOK_ITERABLE;
+
+legacyiterable return TOK_LEGACYITERABLE;
{identifier} {
/* A leading "_" is used to escape an identifier from
@@ -223,7 +228,7 @@ readonly return TOK_READONLY;
{decimalfloat} yylval->text = strdup(yytext); return TOK_FLOAT_LITERAL;
-\"{quotedstring}*\" yylval->text = strdup(yytext); return TOK_STRING_LITERAL;
+\"{quotedstring}*\" yylval->text = strdup(yytext + 1); *(yylval->text + yyleng - 2) = 0; return TOK_STRING_LITERAL;
{multicomment} {
/* multicomment */
diff --git a/src/webidl-parser.y b/src/webidl-parser.y
index 9324212..9cfd84e 100644
--- a/src/webidl-parser.y
+++ b/src/webidl-parser.y
@@ -9,6 +9,9 @@
*
* Derived from the the grammar in apendix A of W3C WEB IDL
* http://www.w3.org/TR/WebIDL/
+ *
+ * WebIDL now has a second edition draft (mid 2015) that the dom and
+ * html specs are using. https://heycam.github.io/webidl
*/
#include <stdio.h>
@@ -17,11 +20,17 @@
#include <stdint.h>
#include <math.h>
-#include "webidl-ast.h"
+#define YYFPRINTF webidl_fprintf
+#define YY_LOCATION_PRINT(File, Loc) \
+ webidl_fprintf(File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
#include "webidl-parser.h"
#include "webidl-lexer.h"
+#include "webidl-ast.h"
+
char *errtxt;
static void
@@ -77,6 +86,8 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str)
%token TOK_INFINITY
%token TOK_INHERIT
%token TOK_INTERFACE
+%token TOK_ITERABLE
+%token TOK_LEGACYITERABLE
%token TOK_LONG
%token TOK_MODULE
%token TOK_NAN
@@ -88,6 +99,7 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str)
%token TOK_OPTIONAL
%token TOK_OR
%token TOK_PARTIAL
+%token TOK_PROMISE
%token TOK_RAISES
%token TOK_READONLY
%token TOK_SETRAISES
@@ -105,12 +117,12 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str)
%token TOK_POUND_SIGN
-%token <text> TOK_IDENTIFIER
-%token <value> TOK_INT_LITERAL
-%token <text> TOK_FLOAT_LITERAL
-%token <text> TOK_STRING_LITERAL
-%token <text> TOK_OTHER_LITERAL
-%token <text> TOK_JAVADOC
+%token <text> TOK_IDENTIFIER
+%token <value> TOK_INT_LITERAL
+%token <text> TOK_FLOAT_LITERAL
+%token <text> TOK_STRING_LITERAL
+%token <text> TOK_OTHER_LITERAL
+%token <text> TOK_JAVADOC
%type <text> Inheritance
@@ -143,6 +155,9 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str)
%type <node> Const
%type <node> Operation
+%type <node> SpecialOperation
+%type <node> Specials
+%type <node> Special
%type <node> OperationRest
%type <node> OptionalIdentifier
@@ -153,6 +168,10 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str)
%type <text> ArgumentName
%type <text> ArgumentNameKeyword
%type <node> Ellipsis
+%type <node> Iterable
+%type <node> OptionalType
+%type <node> Default
+%type <node> DefaultValue
%type <node> Type
%type <node> ReturnType
@@ -165,6 +184,7 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str)
%type <node> FloatType
%type <node> UnsignedIntegerType
%type <node> IntegerType
+%type <node> PromiseType
%type <node> TypeSuffix
%type <node> TypeSuffixStartingWithArray
@@ -356,7 +376,7 @@ InterfaceMembers:
if (ident_node == NULL) {
/* something with no ident - possibly constructors? */
- /* @todo understand this abtter */
+ /* @todo understand this better */
$$ = webidl_node_prepend($1, $3);
@@ -389,11 +409,17 @@ InterfaceMembers:
}
;
- /* [10] */
+ /* [10]
+ * SE[10]
+ * Second edition actually splits up AttributeOrOperation completely
+ * here we "just" add Iterable as thats what the specs use
+ */
InterfaceMember:
Const
|
AttributeOrOperation
+ |
+ Iterable
;
/* [11] */
@@ -426,8 +452,14 @@ PartialDictionary:
/* [15] */
Default:
/* empty */
+ {
+ $$ = NULL;
+ }
|
'=' DefaultValue
+ {
+ $$ = $2;
+ }
;
@@ -436,6 +468,9 @@ DefaultValue:
ConstValue
|
TOK_STRING_LITERAL
+ {
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_LITERAL_STRING, NULL, $1);
+ }
;
/* [17] */
@@ -474,18 +509,28 @@ Enum:
}
;
-/* [21] */
+ /* Second edition changes enumeration rules to allow trailing comma */
+
+ /* SE[20] */
EnumValueList:
- TOK_STRING_LITERAL EnumValues
+ TOK_STRING_LITERAL EnumValueListComma
;
-/* [22] */
-EnumValues:
+ /* SE[21] */
+EnumValueListComma:
+ ',' EnumValueListString
+ |
/* empty */
+ ;
+
+ /* SE[22] */
+EnumValueListString:
+ TOK_STRING_LITERAL EnumValueListComma
|
- ',' TOK_STRING_LITERAL EnumValues
+ /* empty */
;
+
/* [23] - bug in w3c grammar? it doesnt list the equals as a terminal */
CallbackRest:
TOK_IDENTIFIER '=' ReturnType '(' ArgumentList ')' ';'
@@ -658,7 +703,7 @@ Attribute:
/* deal with readonly modifier */
if ($2) {
- attribute = webidl_node_new(WEBIDL_NODE_TYPE_MODIFIER, attribute, (void *)WEBIDL_TYPE_READONLY);
+ attribute = webidl_node_new(WEBIDL_NODE_TYPE_MODIFIER, attribute, (void *)WEBIDL_TYPE_MODIFIER_READONLY);
}
$$ = webidl_node_new(WEBIDL_NODE_TYPE_ATTRIBUTE, NULL, attribute);
@@ -692,55 +737,94 @@ ReadOnly:
}
;
- /* [35] */
+ /* SE[47] */
Operation:
- Qualifiers OperationRest
+ ReturnType OperationRest
+ {
+ /* put return type on the operation */
+ $2 = webidl_node_prepend($1, $2);
+
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPERATION, NULL, $2);
+ }
+ |
+ SpecialOperation
{
- /* @todo fix qualifiers */
- $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPERATION, NULL, $2);
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPERATION, NULL, $1);
}
;
- /* [36] */
-Qualifiers:
- TOK_STATIC
- |
- Specials
+ /* SE[48] */
+SpecialOperation:
+ Special Specials ReturnType OperationRest
+ {
+ /* put return type on the operation */
+ $$ = webidl_node_prepend($4, $3);
+
+ /* specials */
+ $$ = webidl_node_prepend($$, $2);
+
+ /* special */
+ $$ = webidl_node_prepend($$, $1);
+ }
;
- /* [37] */
+ /* SE[49] */
Specials:
/* empty */
+ {
+ $$ = NULL;
+ }
|
Special Specials
+ {
+ $$ = webidl_node_prepend($2, $1);
+ }
;
- /* [38] */
+ /* SE[50] */
Special:
TOK_GETTER
+ {
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL,
+ NULL, (void *)WEBIDL_TYPE_SPECIAL_GETTER);
+ }
|
TOK_SETTER
+ {
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL,
+ NULL, (void *)WEBIDL_TYPE_SPECIAL_SETTER);
+ }
|
TOK_CREATOR
+ {
+ /* second edition removed this special but teh
+ specifications still use it!
+ */
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL,
+ NULL, (void *)WEBIDL_TYPE_SPECIAL_CREATOR);
+ }
|
TOK_DELETER
+ {
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL,
+ NULL, (void *)WEBIDL_TYPE_SPECIAL_DELETER);
+ }
|
TOK_LEGACYCALLER
+ {
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL,
+ NULL, (void *)WEBIDL_TYPE_SPECIAL_LEGACYCALLER);
+ }
;
- /* [39] */
+ /* SE[51] */
OperationRest:
- ReturnType OptionalIdentifier '(' ArgumentList ')' ';'
+ OptionalIdentifier '(' ArgumentList ')' ';'
{
- struct webidl_node *arglist;
-
- /* put return type in argument list */
- arglist = webidl_node_prepend($4, $1);
-
/* argument list */
- $$ = webidl_node_new(WEBIDL_NODE_TYPE_LIST, NULL, arglist);
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_LIST, NULL, $3);
- $$ = webidl_node_prepend($$, $2); /* identifier */
+ $$ = webidl_node_prepend($1, $$); /* identifier */
}
;
@@ -801,8 +885,9 @@ OptionalOrRequiredArgument:
{
struct webidl_node *argument;
argument = webidl_node_new(WEBIDL_NODE_TYPE_IDENT, NULL, $3);
+ argument = webidl_node_new(WEBIDL_NODE_TYPE_OPTIONAL, argument, $4);
argument = webidl_node_prepend(argument, $2); /* add type node */
- $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT, NULL, argument);
+ $$ = webidl_node_new(WEBIDL_NODE_TYPE_ARGUMENT, NULL, argument);
}
|
Type Ellipsis ArgumentName
@@ -835,6 +920,32 @@ Ellipsis:
}
;
+ /* SE[59] */
+Iterable:
+ TOK_ITERABLE '<' Type OptionalType '>' ';'
+ {
+ $$ = NULL;
+ }
+ |
+ TOK_LEGACYITERABLE '<' Type '>' ';'
+ {
+ $$ = NULL;
+ }
+ ;
+
+ /* SE[60] */
+OptionalType:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ |
+ ',' Type
+ {
+ $$ = NULL;
+ }
+ ;
+
/* [47] */
ExceptionMember:
Const
@@ -1301,13 +1412,22 @@ UnionMemberTypes:
TOK_OR UnionMemberType UnionMemberTypes
;
- /* [62] */
+ /* [62]
+ * SE[78]
+ * Second edition adds several types
+ */
NonAnyType:
PrimitiveType TypeSuffix
{
$$ = webidl_node_prepend($1, $2);
}
|
+ PromiseType TypeSuffix
+ {
+ /* second edition adds promise types */
+ $$ = webidl_node_prepend($1, $2);
+ }
+ |
TOK_STRING TypeSuffix
{
$$ = webidl_node_new(WEBIDL_NODE_TYPE_TYPE_BASE, $2, (void *)WEBIDL_TYPE_STRING);
@@ -1442,6 +1562,14 @@ OptionalLong:
}
;
+/* SE[87] */
+PromiseType:
+ TOK_PROMISE '<' ReturnType '>'
+ {
+ $$ = NULL;
+ }
+ ;
+
/* [70] */
TypeSuffix:
/* empty */