diff options
author | Vincent Sanders <vince@kyllikki.org> | 2015-07-25 21:59:19 +0100 |
---|---|---|
committer | Vincent Sanders <vince@kyllikki.org> | 2015-07-25 21:59:19 +0100 |
commit | 13be4238314d1a9903b037ab749074575ef0d1eb (patch) | |
tree | 48a6f817a612173d7415730f2e0f44afb660848e | |
parent | 6406dae8c4da597da888345cf145f366b8297d7c (diff) | |
download | nsgenbind-13be4238314d1a9903b037ab749074575ef0d1eb.tar.gz nsgenbind-13be4238314d1a9903b037ab749074575ef0d1eb.tar.bz2 |
initial duktape libdom generator
This generator creates all the output files and generates the
finalisers for every class.
-rw-r--r-- | src/Makefile | 3 | ||||
-rw-r--r-- | src/duk-libdom.c | 268 | ||||
-rw-r--r-- | src/duk-libdom.h | 16 | ||||
-rw-r--r-- | src/interface-map.c | 13 | ||||
-rw-r--r-- | src/interface-map.h | 32 | ||||
-rw-r--r-- | src/nsgenbind.c | 52 | ||||
-rw-r--r-- | src/options.h | 4 | ||||
-rw-r--r-- | test/data/bindings/HTMLUnknownElement.bnd | 17 | ||||
-rw-r--r-- | test/data/bindings/browser-duk.bnd | 12 |
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; |