From 13be4238314d1a9903b037ab749074575ef0d1eb Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 25 Jul 2015 21:59:19 +0100 Subject: initial duktape libdom generator This generator creates all the output files and generates the finalisers for every class. --- src/duk-libdom.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 src/duk-libdom.c (limited to 'src/duk-libdom.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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3