summaryrefslogtreecommitdiff
path: root/src/duk-libdom.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2015-07-25 21:59:19 +0100
committerVincent Sanders <vince@kyllikki.org>2015-07-25 21:59:19 +0100
commit13be4238314d1a9903b037ab749074575ef0d1eb (patch)
tree48a6f817a612173d7415730f2e0f44afb660848e /src/duk-libdom.c
parent6406dae8c4da597da888345cf145f366b8297d7c (diff)
downloadnsgenbind-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.
Diffstat (limited to 'src/duk-libdom.c')
-rw-r--r--src/duk-libdom.c268
1 files changed, 268 insertions, 0 deletions
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;
+}