summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile3
-rw-r--r--src/duk-libdom.c268
-rw-r--r--src/duk-libdom.h16
-rw-r--r--src/interface-map.c13
-rw-r--r--src/interface-map.h32
-rw-r--r--src/nsgenbind.c52
-rw-r--r--src/options.h4
-rw-r--r--test/data/bindings/HTMLUnknownElement.bnd17
-rw-r--r--test/data/bindings/browser-duk.bnd12
9 files changed, 366 insertions, 51 deletions
diff --git a/src/Makefile b/src/Makefile
index b7b142a..8b034fe 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,7 +1,8 @@
CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0
# Sources in this directory
-DIR_SOURCES := nsgenbind.c utils.c webidl-ast.c nsgenbind-ast.c interface-map.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..4d8ecf5
--- /dev/null
+++ b/src/duk-libdom.c
@@ -0,0 +1,268 @@
+/* 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"
+
+#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"\
+" */"
+
+/**
+ * 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 pre/pro/epi/post sections
+ */
+static int
+output_cdata(FILE* outf,
+ struct genbind_node *node,
+ enum genbind_node_type nodetype)
+{
+ char *cdata;
+ cdata = genbind_node_gettext(
+ genbind_node_find_type(
+ genbind_node_getnode(node),
+ NULL, nodetype));
+ if (cdata != NULL) {
+ fprintf(outf, "%s\n", cdata);
+ }
+ return 0;
+}
+
+static int
+output_interface_fini(FILE* outf,
+ struct interface_map_entry *interfacee,
+ struct interface_map_entry *inherite)
+{
+ struct genbind_node *fini_node;
+ struct genbind_node *type_node;
+ int *type;
+
+ /* finaliser definition */
+ fprintf(outf,
+ "void dukky_%s___fini(duk_context *ctx, %s_private_t *priv)\n",
+ 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" );
+ }
+
+ /* find the finaliser method on the class (if any) */
+ fini_node = genbind_node_find_type(
+ genbind_node_getnode(interfacee->class),
+ NULL, GENBIND_NODE_TYPE_METHOD);
+ while (fini_node != NULL) {
+ type_node = genbind_node_find_type(
+ genbind_node_getnode(fini_node),
+ NULL, GENBIND_NODE_TYPE_METHOD_TYPE);
+
+ type = genbind_node_getint(type_node);
+ if (*type == GENBIND_METHOD_TYPE_FINI) {
+ break;
+ }
+
+ fini_node = genbind_node_find_type(
+ genbind_node_getnode(interfacee->class),
+ fini_node, GENBIND_NODE_TYPE_METHOD);
+ }
+ output_cdata(outf, fini_node, GENBIND_NODE_TYPE_CDATA);
+
+ /* if this interface inherits ensure we call its finaliser */
+ if (inherite != NULL) {
+ fprintf(outf,
+ "\tdukky_%s___fini(ctx, &priv->parent);\n",
+ inherite->class_name);
+ }
+ fprintf(outf, "}\n");
+
+ return 0;
+}
+
+
+/**
+ * generate a source file to implement an interface using duk and libdom.
+ */
+static int output_interface(struct genbind_node *genbind,
+ struct webidl_node *webidl,
+ struct interface_map *interface_map,
+ struct interface_map_entry *interfacee)
+{
+ FILE *ifacef;
+ int ifacenamelen;
+ struct genbind_node *binding_node;
+ struct interface_map_entry *inherite;
+
+ 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(interfacee->filename, "w");
+ if (ifacef == NULL) {
+ return -1;
+ }
+
+ /* find parent interface entry */
+ inherite = interface_map_inherit_entry(interface_map, interfacee);
+
+ /* nsgenbind preamble */
+ fprintf(ifacef, "%s\n", NSGENBIND_PREAMBLE);
+
+ binding_node = genbind_node_find_type(genbind, NULL,
+ GENBIND_NODE_TYPE_BINDING);
+
+ /* binding preface */
+ output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PREFACE);
+
+ /* class preface */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE);
+
+ /* binding prologue */
+ output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PROLOGUE);
+
+ /* class prologue */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PROLOGUE);
+
+ /* initialisor */
+ //output_interface_init();
+
+ /* finaliser */
+ output_interface_fini(ifacef, interfacee, inherite);
+
+ /* constructor */
+ /* destructor */
+
+ /* class epilogue */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE);
+
+ /* binding epilogue */
+ output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_EPILOGUE);
+
+ /* class postface */
+ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_POSTFACE);
+
+ /* binding postface */
+ output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_POSTFACE);
+
+ fclose(ifacef);
+
+ return 0;
+}
+
+int duk_libdom_output(struct genbind_node *genbind,
+ struct webidl_node *webidl,
+ struct interface_map *interface_map)
+{
+ int idx;
+ int res = 0;
+
+ /* generate interfaces */
+ for (idx = 0; idx < interface_map->entryc; idx++) {
+ res = output_interface(genbind, webidl, interface_map,
+ &interface_map->entries[idx]);
+ if (res != 0) {
+ break;
+ }
+ }
+
+ /* generate header */
+ /** \todo implement header */
+
+ /* generate makefile fragment */
+ /** \todo implement makefile generation */
+
+ return res;
+}
diff --git a/src/duk-libdom.h b/src/duk-libdom.h
new file mode 100644
index 0000000..8e86d74
--- /dev/null
+++ b/src/duk-libdom.h
@@ -0,0 +1,16 @@
+/* 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 genbind_node *genbind,
+ struct webidl_node *webidl,
+ struct interface_map *interface_map);
+
+#endif
diff --git a/src/interface-map.c b/src/interface-map.c
index aef697e..44ece42 100644
--- a/src/interface-map.c
+++ b/src/interface-map.c
@@ -290,3 +290,16 @@ int interface_map_dumpdot(struct interface_map *index)
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
index c9dd654..8a6ac05 100644
--- a/src/interface-map.h
+++ b/src/interface-map.h
@@ -25,19 +25,39 @@ struct interface_map_entry {
* interface
*/
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
+ */
};
struct interface_map {
- int entryc; /**< count of interfaces */
- struct interface_map_entry *entries;
+ int entryc; /**< count of interfaces */
+ struct interface_map_entry *entries;
};
int interface_map_new(struct genbind_node *genbind,
- struct webidl_node *webidl,
- struct interface_map **index_out);
+ struct webidl_node *webidl,
+ struct interface_map **index_out);
-int interface_map_dump(struct interface_map *index);
+int interface_map_dump(struct interface_map *map);
-int interface_map_dumpdot(struct interface_map *index);
+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/nsgenbind.c b/src/nsgenbind.c
index 18db196..b3191ba 100644
--- a/src/nsgenbind.c
+++ b/src/nsgenbind.c
@@ -17,8 +17,9 @@
#include "options.h"
#include "nsgenbind-ast.h"
#include "webidl-ast.h"
-#include "jsapi-libdom.h"
#include "interface-map.h"
+#include "jsapi-libdom.h"
+#include "duk-libdom.h"
struct options *options;
@@ -85,28 +86,6 @@ static struct options* process_cmdline(int argc, char **argv)
}
-static int generate_binding(struct genbind_node *binding_node, void *ctx)
-{
- struct genbind_node *genbind_root = ctx;
- char *type;
- int res = 10;
-
- type = genbind_node_gettext(
- genbind_node_find_type(
- genbind_node_getnode(binding_node),
- NULL,
- GENBIND_NODE_TYPE_TYPE));
-
- if (strcmp(type, "jsapi_libdom") == 0) {
- res = jsapi_libdom_output(options, genbind_root, binding_node);
- } else {
- fprintf(stderr, "Error: unsupported binding type \"%s\"\n", type);
- }
-
- return res;
-}
-
-
static int webidl_file_cb(struct genbind_node *node, void *ctx)
{
struct webidl_node **webidl_ast = ctx;
@@ -237,24 +216,17 @@ int main(int argc, char **argv)
/* dump the interface mapping */
interface_map_dump(interface_map);
interface_map_dumpdot(interface_map);
-#if 0
- /* generate output for each binding */
- res = genbind_node_foreach_type(genbind_root,
- GENBIND_NODE_TYPE_BINDING,
- generate_binding,
- genbind_root);
- 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;
+ /* generate binding */
+ switch (bindingtype) {
+ case BINDINGTYPE_DUK_LIBDOM:
+ res = duk_libdom_output(genbind_root, webidl_root, interface_map);
+ break;
+
+ default:
+ fprintf(stderr, "Unable to generate binding of this type\n");
+ res = 7;
}
-#endif
- return 0;
+ return res;
}
diff --git a/src/options.h b/src/options.h
index 68a4bc1..85f107e 100644
--- a/src/options.h
+++ b/src/options.h
@@ -13,10 +13,6 @@
struct options {
char *infilename; /**< binding source */
char *outdirname; /**< output directory */
-FILE *hdrfilehandle;
-char *hdrfilename;
-char *outfilename;
-FILE *outfilehandle;
char *idlpath; /**< path to IDL files */
bool verbose; /**< verbose processing */
diff --git a/test/data/bindings/HTMLUnknownElement.bnd b/test/data/bindings/HTMLUnknownElement.bnd
new file mode 100644
index 0000000..376a823
--- /dev/null
+++ b/test/data/bindings/HTMLUnknownElement.bnd
@@ -0,0 +1,17 @@
+class HTMLUnknownElement {
+ preface %{
+/* class pre */
+ %};
+
+ prologue %{
+/* class pro */
+ %};
+
+ epilogue %{
+/* class epi */
+ %};
+
+ postface %{
+/* class post */
+ %};
+}
diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd
index 4e06d23..273eae9 100644
--- a/test/data/bindings/browser-duk.bnd
+++ b/test/data/bindings/browser-duk.bnd
@@ -15,18 +15,30 @@ binding duk_libdom {
webidl "console.idl";
preface %{
+/* DukTape JavaScript bindings for NetSurf browser
+ *
+ * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * Released under the terms of the MIT License,
+ * http://www.opensource.org/licenses/mit-license
+ */
%};
prologue %{
+/* binding prologue */
%};
epilogue %{
+/* binding epilogue */
%};
postface %{
+/* binding postface */
%};
}
+#include "HTMLUnknownElement.bnd"
+
class Node {
private "dom_node *" node;