diff options
author | Vincent Sanders <vince@kyllikki.org> | 2015-08-21 12:53:52 +0200 |
---|---|---|
committer | Vincent Sanders <vince@kyllikki.org> | 2015-08-21 12:53:52 +0200 |
commit | b0f64cff2c94d1a208528e2ed91c15ab037dbbb1 (patch) | |
tree | 85160c531ec6dd0a51c1aaa276e668cbac64298b /src | |
parent | 56eee21ccb63cb7f040c5ce07bc226fbd229330d (diff) | |
download | nsgenbind-b0f64cff2c94d1a208528e2ed91c15ab037dbbb1.tar.gz nsgenbind-b0f64cff2c94d1a208528e2ed91c15ab037dbbb1.tar.bz2 |
split up duk-libdom generation source as it had grown unweildy
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 3 | ||||
-rw-r--r-- | src/duk-libdom-common.c | 78 | ||||
-rw-r--r-- | src/duk-libdom-dictionary.c | 571 | ||||
-rw-r--r-- | src/duk-libdom-interface.c | 1334 | ||||
-rw-r--r-- | src/duk-libdom.c | 1411 | ||||
-rw-r--r-- | src/duk-libdom.h | 35 |
6 files changed, 2021 insertions, 1411 deletions
diff --git a/src/Makefile b/src/Makefile index 9905baf..3ecfbe1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,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 ir.c \ - duk-libdom.c + duk-libdom.c duk-libdom-interface.c duk-libdom-dictionary.c duk-libdom-common.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-common.c b/src/duk-libdom-common.c new file mode 100644 index 0000000..9a0f660 --- /dev/null +++ b/src/duk-libdom-common.c @@ -0,0 +1,78 @@ +/* duktape binding generation implementation + * + * 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> + */ + +#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 "ir.h" +#include "duk-libdom.h" + +#define NSGENBIND_PREFACE \ + "/* 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" \ + " */" + +/* exported interface documented in duk-libdom.h */ +int output_tool_preface(FILE* outf) +{ + fprintf(outf, "%s\n", NSGENBIND_PREFACE); + + return 0; +} + +/* exported interface documented in duk-libdom.h */ +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; +} + +/* exported interface documented in duk-libdom.h */ +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; +} diff --git a/src/duk-libdom-dictionary.c b/src/duk-libdom-dictionary.c new file mode 100644 index 0000000..275855e --- /dev/null +++ b/src/duk-libdom-dictionary.c @@ -0,0 +1,571 @@ +/* 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 "ir.h" +#include "duk-libdom.h" + +/** prefix for all generated functions */ +#define DLPFX "dukky" + +#define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_" + +/** + * 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, %s_magic_string_private);\n\n", + DLPFX); + + 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, %s_magic_string_private);\n", + idx, DLPFX); + 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 the dictionary constructor + */ +static int +output_dictionary_constructor(FILE* outf, struct ir_entry *dictionarye) +{ + int init_argc; + + /* constructor definition */ + fprintf(outf, + "static duk_ret_t %s_%s___constructor(duk_context *ctx)\n", + DLPFX, dictionarye->class_name); + fprintf(outf,"{\n"); + + output_create_private(outf, dictionarye->class_name); + + /* generate call to initialisor */ + fprintf(outf, + "\t%s_%s___init(ctx, priv", + DLPFX, dictionarye->class_name); + for (init_argc = 1; + init_argc <= dictionarye->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 a duktape prototype name + */ +static char *get_prototype_name(const char *dictionary_name) +{ + char *proto_name; + int pnamelen; + int pfxlen; + + /* duplicate the dictionary name in upper case */ + pfxlen = SLEN(MAGICPFX) + SLEN("PROTOTYPE_"); + pnamelen = strlen(dictionary_name) + 1; + + proto_name = malloc(pnamelen + pfxlen); + snprintf(proto_name, pnamelen + pfxlen, "%sPROTOTYPE_%s", MAGICPFX, dictionary_name); + for (pnamelen-- ; pnamelen >= 0; pnamelen--) { + proto_name[pnamelen + pfxlen] = toupper(dictionary_name[pnamelen]); + } + return proto_name; +} + + +/** + * generate code that gets a prototype by name + */ +static int output_get_prototype(FILE* outf, const char *dictionary_name) +{ + char *proto_name; + + proto_name = get_prototype_name(dictionary_name); + + fprintf(outf, + "\t/* get prototype */\n"); + fprintf(outf, + "\tduk_get_global_string(ctx, %s_magic_string_prototypes);\n", + DLPFX); + 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; +} + +/** + * generate the dictionary prototype creator + */ +static int +output_dictionary_prototype(FILE* outf, + struct ir *ir, + struct ir_entry *dictionarye, + struct ir_entry *inherite) +{ + struct genbind_node *proto_node; + + /* find the prototype method on the class */ + proto_node = genbind_node_find_method(dictionarye->class, + NULL, + GENBIND_METHOD_TYPE_PROTOTYPE); + + /* prototype definition */ + fprintf(outf, "duk_ret_t %s_%s___proto(duk_context *ctx)\n", + DLPFX, dictionarye->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 dictionary 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"); + } + + /* dictionary members*/ + + + /* generate setting of destructor */ + output_set_destructor(outf, dictionarye->class_name, 0); + + /* generate setting of constructor */ + output_set_constructor(outf, + dictionarye->class_name, + 0, + dictionarye->class_init_argc); + + fprintf(outf,"\treturn 1; /* The prototype object */\n"); + + fprintf(outf, "}\n\n"); + + return 0; +} + +/** + * generate the dictionary destructor + */ +static int +output_dictionary_destructor(FILE* outf, struct ir_entry *dictionarye) +{ + /* destructor definition */ + fprintf(outf, + "static duk_ret_t %s_%s___destructor(duk_context *ctx)\n", + DLPFX, dictionarye->class_name); + fprintf(outf,"{\n"); + + output_safe_get_private(outf, dictionarye->class_name, 0); + + /* generate call to finaliser */ + fprintf(outf, + "\t%s_%s___fini(ctx, priv);\n", + DLPFX, dictionarye->class_name); + + fprintf(outf,"\tfree(priv);\n"); + fprintf(outf,"\treturn 0;\n"); + + fprintf(outf, "}\n\n"); + + return 0; +} + +/** + * generate an initialisor call to parent dictionary + */ +static int +output_dictionary_inherit_init(FILE* outf, + struct ir_entry *dictionarye, + struct ir_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(dictionarye->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\" (dictionary %s) parent class \"%s\" (dictionary %s) initialisor requires a parameter \"%s\" with compatible identifier\n", + dictionarye->class_name, + dictionarye->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_dictionary_init_declaration(FILE* outf, + struct ir_entry *dictionarye, + struct genbind_node *init_node) +{ + struct genbind_node *param_node; + + fprintf(outf, + "void %s_%s___init(duk_context *ctx, %s_private_t *priv", + DLPFX, dictionarye->class_name, dictionarye->class_name); + + /* count the number of arguments on the initializer */ + dictionarye->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) { + dictionarye->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_dictionary_init(FILE* outf, + struct ir_entry *dictionarye, + struct ir_entry *inherite) +{ + struct genbind_node *init_node; + int res; + + /* find the initialisor method on the class (if any) */ + init_node = genbind_node_find_method(dictionarye->class, + NULL, + GENBIND_METHOD_TYPE_INIT); + + /* initialisor definition */ + output_dictionary_init_declaration(outf, dictionarye, init_node); + + fprintf(outf,"\n{\n"); + + /* if this dictionary inherits ensure we call its initialisor */ + res = output_dictionary_inherit_init(outf, dictionarye, 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_dictionary_fini(FILE* outf, + struct ir_entry *dictionarye, + struct ir_entry *inherite) +{ + struct genbind_node *fini_node; + + /* find the finaliser method on the class (if any) */ + fini_node = genbind_node_find_method(dictionarye->class, + NULL, + GENBIND_METHOD_TYPE_FINI); + + /* finaliser definition */ + fprintf(outf, + "void %s_%s___fini(duk_context *ctx, %s_private_t *priv)\n", + DLPFX, dictionarye->class_name, dictionarye->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 dictionary 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 source file to implement a dictionary using duk and libdom. + */ +int output_dictionary(struct ir *ir, struct ir_entry *dictionarye) +{ + FILE *ifacef; + struct ir_entry *inherite; + int res = 0; + + /* open output file */ + ifacef = genb_fopen_tmp(dictionarye->filename); + if (ifacef == NULL) { + return -1; + } + + /* find parent dictionary entry */ + inherite = ir_inherit_entry(ir, dictionarye); + + /* tool preface */ + output_tool_preface(ifacef); + + /* binding preface */ + output_cdata(ifacef, + ir->binding_node, + GENBIND_NODE_TYPE_PREFACE); + + /* class preface */ + output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_PREFACE); + + /* tool prologue */ + output_tool_prologue(ifacef); + + /* binding prologue */ + output_cdata(ifacef, + ir->binding_node, + GENBIND_NODE_TYPE_PROLOGUE); + + /* class prologue */ + output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_PROLOGUE); + + fprintf(ifacef, "\n"); + + /* initialisor */ + res = output_dictionary_init(ifacef, dictionarye, inherite); + if (res != 0) { + goto op_error; + } + + /* finaliser */ + res = output_dictionary_fini(ifacef, dictionarye, inherite); + if (res != 0) { + goto op_error; + } + + /* constructor */ + res = output_dictionary_constructor(ifacef, dictionarye); + if (res != 0) { + goto op_error; + } + + /* destructor */ + res = output_dictionary_destructor(ifacef, dictionarye); + if (res != 0) { + goto op_error; + } + + /** todo property handlers */ + + /* prototype */ + res = output_dictionary_prototype(ifacef, ir, dictionarye, inherite); + if (res != 0) { + goto op_error; + } + + fprintf(ifacef, "\n"); + + /* class epilogue */ + output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_EPILOGUE); + + /* binding epilogue */ + output_cdata(ifacef, + ir->binding_node, + GENBIND_NODE_TYPE_EPILOGUE); + + /* class postface */ + output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_POSTFACE); + + /* binding postface */ + output_cdata(ifacef, + ir->binding_node, + GENBIND_NODE_TYPE_POSTFACE); + +op_error: + genb_fclose_tmp(ifacef, dictionarye->filename); + + return res; +} diff --git a/src/duk-libdom-interface.c b/src/duk-libdom-interface.c new file mode 100644 index 0000000..7501bea --- /dev/null +++ b/src/duk-libdom-interface.c @@ -0,0 +1,1334 @@ +/* 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 "ir.h" +#include "duk-libdom.h" + +/** prefix for all generated functions */ +#define DLPFX "dukky" + +#define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_" + +/** + * 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, %s_magic_string_private);\n\n", + DLPFX); + + 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, %s_magic_string_private);\n", + idx, DLPFX); + 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, %s_magic_string_prototypes);\n", + DLPFX); + 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, %s_magic_string_private);\n", + DLPFX); + 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 the interface constructor + */ +static int +output_interface_constructor(FILE* outf, struct ir_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 ir_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 ir_entry *interfacee, + struct ir_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 ir_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 ir_entry *interfacee, + struct ir_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 ir_entry *interfacee, + struct ir_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 ir_entry *interfacee, + struct ir_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 ir_entry *entry) +{ + int opc; + int res = 0; + + for (opc = 0; opc < entry->u.interface.operationc; opc++) { + res = output_prototype_method( + outf, + entry, + entry->u.interface.operationv + opc); + if (res != 0) { + break; + } + } + + return res; +} + + +static int +output_prototype_attribute(FILE *outf, + struct ir_entry *interfacee, + struct ir_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 ir_entry *entry) +{ + int attrc; + int res = 0; + + for (attrc = 0; attrc < entry->u.interface.attributec; attrc++) { + res = output_prototype_attribute( + outf, + entry, + entry->u.interface.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 ir_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 ir_entry *entry) +{ + int attrc; + int res = 0; + + for (attrc = 0; attrc < entry->u.interface.constantc; attrc++) { + res = output_prototype_constant( + outf, + entry->u.interface.constantv + attrc); + if (res != 0) { + break; + } + } + + return res; +} + +static int +output_global_create_prototype(FILE* outf, + struct ir *ir, + struct ir_entry *interfacee) +{ + int idx; + + fprintf(outf, "\t/* Create interface objects */\n"); + for (idx = 0; idx < ir->entryc; idx++) { + struct ir_entry *entry; + + entry = ir->entries + idx; + + if (entry->type == IR_ENTRY_TYPE_INTERFACE) { + + if (entry->u.interface.noobject) { + continue; + } + + if (entry == interfacee) { + fprintf(outf, "\tduk_dup(ctx, 0);\n"); + } else { + output_get_prototype(outf, entry->name); + } + + fprintf(outf, + "\tdukky_inject_not_ctr(ctx, 0, \"%s\");\n", + entry->name); + } + } + return 0; +} + + +/** + * generate the interface prototype creator + */ +static int +output_interface_prototype(FILE* outf, + struct ir *ir, + struct ir_entry *interfacee, + struct ir_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); + + /* if this is the global object, output all interfaces which do not + * prevent us from doing so + */ + if (interfacee->u.interface.primary_global) { + output_global_create_prototype(outf, ir, 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 with elipsis + */ +static int +output_interface_elipsis_operation(FILE* outf, + struct ir_entry *interfacee, + struct ir_operation_entry *operatione) +{ + int cdatac; /* cdata blocks output */ + + /* overloaded method definition */ + fprintf(outf, + "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", + DLPFX, interfacee->class_name, operatione->name); + fprintf(outf,"{\n"); + + /** + * \todo This is where the checking of the parameters to the + * operation with elipsis should go + */ + WARN(WARNING_UNIMPLEMENTED, + "Elipsis parameetrs not checked: method %s::%s();", + interfacee->name, operatione->name); + + 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 a single class method for an interface overloaded operation + */ +static int +output_interface_overloaded_operation(FILE* outf, + struct ir_entry *interfacee, + struct ir_operation_entry *operatione) +{ + int cdatac; /* cdata blocks output */ + + /* overloaded method definition */ + fprintf(outf, + "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", + DLPFX, interfacee->class_name, operatione->name); + fprintf(outf,"{\n"); + + /** \todo This is where the checking of the parameters to the + * overloaded operation should go + */ + + 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 a single class method for an interface special operation + */ +static int +output_interface_special_operation(FILE* outf, + struct ir_entry *interfacee, + struct ir_operation_entry *operatione) +{ + /* special method definition */ + fprintf(outf, "/* Special method definition - UNIMPLEMENTED */\n\n"); + + WARN(WARNING_UNIMPLEMENTED, + "Special operation on interface %s (operation entry %p)", + interfacee->name, + operatione); + + return 0; +} + +/** + * generate default values on the duk stack + */ +static int +output_operation_optional_defaults(FILE* outf, + struct ir_operation_argument_entry *argumentv, + int argumentc) +{ + int argc; + for (argc = 0; argc < argumentc; argc++) { + struct ir_operation_argument_entry *cure; + struct webidl_node *lit_node; /* literal node */ + enum webidl_node_type lit_type; + int *lit_int; + char *lit_str; + + cure = argumentv + argc; + + lit_node = webidl_node_getnode( + webidl_node_find_type( + webidl_node_getnode(cure->node), + NULL, + WEBIDL_NODE_TYPE_OPTIONAL)); + + if (lit_node != NULL) { + + lit_type = webidl_node_gettype(lit_node); + + switch (lit_type) { + case WEBIDL_NODE_TYPE_LITERAL_NULL: + fprintf(outf, + "\t\tduk_push_null(ctx);\n"); + break; + + case WEBIDL_NODE_TYPE_LITERAL_INT: + lit_int = webidl_node_getint(lit_node); + fprintf(outf, + "\t\tduk_push_int(ctx, %d);\n", + *lit_int); + break; + + case WEBIDL_NODE_TYPE_LITERAL_BOOL: + lit_int = webidl_node_getint(lit_node); + fprintf(outf, + "\t\tduk_push_boolean(ctx, %d);\n", + *lit_int); + break; + + case WEBIDL_NODE_TYPE_LITERAL_STRING: + lit_str = webidl_node_gettext(lit_node); + fprintf(outf, + "\t\tduk_push_string(ctx, \"%s\");\n", + lit_str); + break; + + case WEBIDL_NODE_TYPE_LITERAL_FLOAT: + default: + fprintf(outf, + "\t\tduk_push_undefined(ctx);\n"); + break; + } + } else { + fprintf(outf, "\t\tduk_push_undefined(ctx);\n"); + } + } + return 0; +} + +static int +output_operation_argument_type_check( + FILE* outf, + struct ir_entry *interfacee, + struct ir_operation_entry *operatione, + struct ir_operation_overload_entry *overloade, + int argidx) +{ + struct ir_operation_argument_entry *argumente; + struct webidl_node *type_node; + enum webidl_type *argument_type; + + argumente = overloade->argumentv + argidx; + + type_node = webidl_node_find_type( + webidl_node_getnode(argumente->node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + if (type_node == NULL) { + fprintf(stderr, "%s:%s %dth argument %s has no type\n", + interfacee->name, + operatione->name, + argidx, + argumente->name); + return -1; + } + + argument_type = (enum webidl_type *)webidl_node_getint( + webidl_node_find_type( + webidl_node_getnode(type_node), + NULL, + WEBIDL_NODE_TYPE_TYPE_BASE)); + + if (argument_type == NULL) { + fprintf(stderr, + "%s:%s %dth argument %s has no type base\n", + interfacee->name, + operatione->name, + argidx, + argumente->name); + return -1; + } + + if (*argument_type == WEBIDL_TYPE_ANY) { + /* allowing any type needs no check */ + return 0; + } + + fprintf(outf, "\tif (%s_argc > %d) {\n", DLPFX, argidx); + + switch (*argument_type) { + case WEBIDL_TYPE_STRING: + fprintf(outf, + "\t\tif (!duk_is_string(ctx, %d)) {\n" + "\t\t\tduk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_string_type, %d, \"%s\");\n" + "\t\t}\n", argidx, DLPFX, argidx, argumente->name); + break; + + case WEBIDL_TYPE_BOOL: + fprintf(outf, + "\t\tif (!duk_is_boolean(ctx, %d)) {\n" + "\t\t\tduk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_bool_type, %d, \"%s\");\n" + "\t\t}\n", argidx, DLPFX, argidx, argumente->name); + break; + + case WEBIDL_TYPE_FLOAT: + case WEBIDL_TYPE_DOUBLE: + case WEBIDL_TYPE_SHORT: + case WEBIDL_TYPE_LONG: + case WEBIDL_TYPE_LONGLONG: + fprintf(outf, + "\t\tif (!duk_is_number(ctx, %d)) {\n" + "\t\t\tduk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_number_type, %d, \"%s\");\n" + "\t\t}\n", argidx, DLPFX, argidx, argumente->name); + break; + + + default: + fprintf(outf, + "\t\t/* unhandled type check */\n"); + } + + fprintf(outf, "\t}\n"); + + return 0; +} + + +/** + * generate a single class method for an interface operation + */ +static int +output_interface_operation(FILE* outf, + struct ir_entry *interfacee, + struct ir_operation_entry *operatione) +{ + int cdatac; /* cdata blocks output */ + struct ir_operation_overload_entry *overloade; + int fixedargc; /* number of non optional arguments */ + int argidx; /* loop counter for arguments */ + int optargc; /* loop counter for optional arguments */ + + if (operatione->name == NULL) { + return output_interface_special_operation(outf, + interfacee, + operatione); + } + + if (operatione->overloadc != 1) { + return output_interface_overloaded_operation(outf, + interfacee, + operatione); + } + + if (operatione->overloadv->elipsisc != 0) { + return output_interface_elipsis_operation(outf, + interfacee, + operatione); + } + + /* normal method definition */ + overloade = operatione->overloadv; + + fprintf(outf, + "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", + DLPFX, interfacee->class_name, operatione->name); + fprintf(outf,"{\n"); + + /* check arguments */ + + /* generate check for minimum number of parameters */ + + fixedargc = overloade->argumentc - overloade->optionalc; + + fprintf(outf, + "\t/* ensure the parameters are present */\n" + "\tduk_idx_t %s_argc = duk_get_top(ctx);\n\t", DLPFX); + + if (fixedargc > 0) { + fprintf(outf, + "if (%s_argc < %d) {\n" + "\t\t/* not enough arguments */\n" + "\t\tduk_error(ctx, DUK_RET_TYPE_ERROR, %s_error_fmt_argument, %d, %s_argc);\n" + "\t} else ", + DLPFX, + fixedargc, + DLPFX, + fixedargc, + DLPFX); + } + + for (optargc = fixedargc; + optargc < overloade->argumentc; + optargc++) { + fprintf(outf, + "if (%s_argc == %d) {\n" + "\t\t/* %d optional arguments need adding */\n", + DLPFX, + optargc, + overloade->argumentc - optargc); + output_operation_optional_defaults(outf, + overloade->argumentv + optargc, + overloade->argumentc - optargc); + fprintf(outf, + "\t} else "); + } + + fprintf(outf, + "if (%s_argc > %d) {\n" + "\t\t/* remove extraneous parameters */\n" + "\t\tduk_set_top(ctx, %d);\n" + "\t}\n", + DLPFX, + overloade->argumentc, + overloade->argumentc); + fprintf(outf, "\n"); + + /* generate argument type checks */ + + fprintf(outf, "\t/* check types of passed arguments are correct */\n"); + + for (argidx = 0; argidx < overloade->argumentc; argidx++) { + output_operation_argument_type_check(outf, + interfacee, + operatione, + overloade, + argidx); + } + + 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 ir_entry *ife) +{ + int opc; + int res = 0; + + for (opc = 0; opc < ife->u.interface.operationc; opc++) { + res = output_interface_operation( + outf, + ife, + ife->u.interface.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 ir_entry *interfacee, + struct ir_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 ir_entry *ife) +{ + int attrc; + + for (attrc = 0; attrc < ife->u.interface.attributec; attrc++) { + output_interface_attribute( + outf, + ife, + ife->u.interface.attributev + attrc); + } + + return 0; +} + + +/* exported interface documented in duk-libdom.h */ +int output_interface(struct ir *ir, struct ir_entry *interfacee) +{ + FILE *ifacef; + struct ir_entry *inherite; + int res = 0; + + /* open output file */ + ifacef = genb_fopen_tmp(interfacee->filename); + if (ifacef == NULL) { + return -1; + } + + /* find parent interface entry */ + inherite = ir_inherit_entry(ir, interfacee); + + /* tool preface */ + output_tool_preface(ifacef); + + /* binding preface */ + output_cdata(ifacef, + ir->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, + ir->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, ir, interfacee, inherite); + + fprintf(ifacef, "\n"); + + /* class epilogue */ + output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE); + + /* binding epilogue */ + output_cdata(ifacef, + ir->binding_node, + GENBIND_NODE_TYPE_EPILOGUE); + + /* class postface */ + output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_POSTFACE); + + /* binding postface */ + output_cdata(ifacef, + ir->binding_node, + GENBIND_NODE_TYPE_POSTFACE); + +op_error: + genb_fclose_tmp(ifacef, interfacee->filename); + + return res; +} + diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 3e20d13..45e7e79 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -3,7 +3,7 @@ * 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> + * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org> */ #include <stdio.h> @@ -27,53 +27,6 @@ #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, %s_magic_string_private);\n\n", - DLPFX); - - 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, %s_magic_string_private);\n", - idx, DLPFX); - 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 */ @@ -95,190 +48,6 @@ static char *get_prototype_name(const char *interface_name) 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, %s_magic_string_prototypes);\n", - DLPFX); - 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, %s_magic_string_private);\n", - DLPFX); - 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. @@ -345,34 +114,6 @@ static char *gen_class_name(struct ir_entry *interfacee) 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 ir *ir, const char *name) { @@ -431,166 +172,7 @@ static int close_header(struct ir *ir, } -/** - * generate the interface constructor - */ -static int -output_interface_constructor(FILE* outf, struct ir_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 ir_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 ir_entry *interfacee, - struct ir_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, @@ -626,997 +208,6 @@ output_interface_init_declaration(FILE* outf, return 0; } -static int -output_interface_init(FILE* outf, - struct ir_entry *interfacee, - struct ir_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 ir_entry *interfacee, - struct ir_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 ir_entry *interfacee, - struct ir_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 ir_entry *entry) -{ - int opc; - int res = 0; - - for (opc = 0; opc < entry->u.interface.operationc; opc++) { - res = output_prototype_method( - outf, - entry, - entry->u.interface.operationv + opc); - if (res != 0) { - break; - } - } - - return res; -} - - -static int -output_prototype_attribute(FILE *outf, - struct ir_entry *interfacee, - struct ir_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 ir_entry *entry) -{ - int attrc; - int res = 0; - - for (attrc = 0; attrc < entry->u.interface.attributec; attrc++) { - res = output_prototype_attribute( - outf, - entry, - entry->u.interface.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 ir_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 ir_entry *entry) -{ - int attrc; - int res = 0; - - for (attrc = 0; attrc < entry->u.interface.constantc; attrc++) { - res = output_prototype_constant( - outf, - entry->u.interface.constantv + attrc); - if (res != 0) { - break; - } - } - - return res; -} - -static int -output_global_create_prototype(FILE* outf, - struct ir *ir, - struct ir_entry *interfacee) -{ - int idx; - - fprintf(outf, "\t/* Create interface objects */\n"); - for (idx = 0; idx < ir->entryc; idx++) { - struct ir_entry *entry; - - entry = ir->entries + idx; - - if (entry->type == IR_ENTRY_TYPE_INTERFACE) { - - if (entry->u.interface.noobject) { - continue; - } - - if (entry == interfacee) { - fprintf(outf, "\tduk_dup(ctx, 0);\n"); - } else { - output_get_prototype(outf, entry->name); - } - - fprintf(outf, - "\tdukky_inject_not_ctr(ctx, 0, \"%s\");\n", - entry->name); - } - } - return 0; -} -/** - * generate the interface prototype creator - */ -static int -output_interface_prototype(FILE* outf, - struct ir *ir, - struct ir_entry *interfacee, - struct ir_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); - - /* if this is the global object, output all interfaces which do not - * prevent us from doing so - */ - if (interfacee->u.interface.primary_global) { - output_global_create_prototype(outf, ir, 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 with elipsis - */ -static int -output_interface_elipsis_operation(FILE* outf, - struct ir_entry *interfacee, - struct ir_operation_entry *operatione) -{ - int cdatac; /* cdata blocks output */ - - /* overloaded method definition */ - fprintf(outf, - "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", - DLPFX, interfacee->class_name, operatione->name); - fprintf(outf,"{\n"); - - /** - * \todo This is where the checking of the parameters to the - * operation with elipsis should go - */ - WARN(WARNING_UNIMPLEMENTED, - "Elipsis parameetrs not checked: method %s::%s();", - interfacee->name, operatione->name); - - 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 a single class method for an interface overloaded operation - */ -static int -output_interface_overloaded_operation(FILE* outf, - struct ir_entry *interfacee, - struct ir_operation_entry *operatione) -{ - int cdatac; /* cdata blocks output */ - - /* overloaded method definition */ - fprintf(outf, - "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", - DLPFX, interfacee->class_name, operatione->name); - fprintf(outf,"{\n"); - - /** \todo This is where the checking of the parameters to the - * overloaded operation should go - */ - - 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 a single class method for an interface special operation - */ -static int -output_interface_special_operation(FILE* outf, - struct ir_entry *interfacee, - struct ir_operation_entry *operatione) -{ - /* special method definition */ - fprintf(outf, "/* Special method definition - UNIMPLEMENTED */\n\n"); - - WARN(WARNING_UNIMPLEMENTED, - "Special operation on interface %s (operation entry %p)", - interfacee->name, - operatione); - - return 0; -} - -/** - * generate default values on the duk stack - */ -static int -output_operation_optional_defaults(FILE* outf, - struct ir_operation_argument_entry *argumentv, - int argumentc) -{ - int argc; - for (argc = 0; argc < argumentc; argc++) { - struct ir_operation_argument_entry *cure; - struct webidl_node *lit_node; /* literal node */ - enum webidl_node_type lit_type; - int *lit_int; - char *lit_str; - - cure = argumentv + argc; - - lit_node = webidl_node_getnode( - webidl_node_find_type( - webidl_node_getnode(cure->node), - NULL, - WEBIDL_NODE_TYPE_OPTIONAL)); - - if (lit_node != NULL) { - - lit_type = webidl_node_gettype(lit_node); - - switch (lit_type) { - case WEBIDL_NODE_TYPE_LITERAL_NULL: - fprintf(outf, - "\t\tduk_push_null(ctx);\n"); - break; - - case WEBIDL_NODE_TYPE_LITERAL_INT: - lit_int = webidl_node_getint(lit_node); - fprintf(outf, - "\t\tduk_push_int(ctx, %d);\n", - *lit_int); - break; - - case WEBIDL_NODE_TYPE_LITERAL_BOOL: - lit_int = webidl_node_getint(lit_node); - fprintf(outf, - "\t\tduk_push_boolean(ctx, %d);\n", - *lit_int); - break; - - case WEBIDL_NODE_TYPE_LITERAL_STRING: - lit_str = webidl_node_gettext(lit_node); - fprintf(outf, - "\t\tduk_push_string(ctx, \"%s\");\n", - lit_str); - break; - - case WEBIDL_NODE_TYPE_LITERAL_FLOAT: - default: - fprintf(outf, - "\t\tduk_push_undefined(ctx);\n"); - break; - } - } else { - fprintf(outf, "\t\tduk_push_undefined(ctx);\n"); - } - } - return 0; -} - -static int -output_operation_argument_type_check( - FILE* outf, - struct ir_entry *interfacee, - struct ir_operation_entry *operatione, - struct ir_operation_overload_entry *overloade, - int argidx) -{ - struct ir_operation_argument_entry *argumente; - struct webidl_node *type_node; - enum webidl_type *argument_type; - - argumente = overloade->argumentv + argidx; - - type_node = webidl_node_find_type( - webidl_node_getnode(argumente->node), - NULL, - WEBIDL_NODE_TYPE_TYPE); - - if (type_node == NULL) { - fprintf(stderr, "%s:%s %dth argument %s has no type\n", - interfacee->name, - operatione->name, - argidx, - argumente->name); - return -1; - } - - argument_type = (enum webidl_type *)webidl_node_getint( - webidl_node_find_type( - webidl_node_getnode(type_node), - NULL, - WEBIDL_NODE_TYPE_TYPE_BASE)); - - if (argument_type == NULL) { - fprintf(stderr, - "%s:%s %dth argument %s has no type base\n", - interfacee->name, - operatione->name, - argidx, - argumente->name); - return -1; - } - - if (*argument_type == WEBIDL_TYPE_ANY) { - /* allowing any type needs no check */ - return 0; - } - - fprintf(outf, "\tif (%s_argc > %d) {\n", DLPFX, argidx); - - switch (*argument_type) { - case WEBIDL_TYPE_STRING: - fprintf(outf, - "\t\tif (!duk_is_string(ctx, %d)) {\n" - "\t\t\tduk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_string_type, %d, \"%s\");\n" - "\t\t}\n", argidx, DLPFX, argidx, argumente->name); - break; - - case WEBIDL_TYPE_BOOL: - fprintf(outf, - "\t\tif (!duk_is_boolean(ctx, %d)) {\n" - "\t\t\tduk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_bool_type, %d, \"%s\");\n" - "\t\t}\n", argidx, DLPFX, argidx, argumente->name); - break; - - case WEBIDL_TYPE_FLOAT: - case WEBIDL_TYPE_DOUBLE: - case WEBIDL_TYPE_SHORT: - case WEBIDL_TYPE_LONG: - case WEBIDL_TYPE_LONGLONG: - fprintf(outf, - "\t\tif (!duk_is_number(ctx, %d)) {\n" - "\t\t\tduk_error(ctx, DUK_ERR_ERROR, %s_error_fmt_number_type, %d, \"%s\");\n" - "\t\t}\n", argidx, DLPFX, argidx, argumente->name); - break; - - - default: - fprintf(outf, - "\t\t/* unhandled type check */\n"); - } - - fprintf(outf, "\t}\n"); - - return 0; -} - - -/** - * generate a single class method for an interface operation - */ -static int -output_interface_operation(FILE* outf, - struct ir_entry *interfacee, - struct ir_operation_entry *operatione) -{ - int cdatac; /* cdata blocks output */ - struct ir_operation_overload_entry *overloade; - int fixedargc; /* number of non optional arguments */ - int argidx; /* loop counter for arguments */ - int optargc; /* loop counter for optional arguments */ - - if (operatione->name == NULL) { - return output_interface_special_operation(outf, - interfacee, - operatione); - } - - if (operatione->overloadc != 1) { - return output_interface_overloaded_operation(outf, - interfacee, - operatione); - } - - if (operatione->overloadv->elipsisc != 0) { - return output_interface_elipsis_operation(outf, - interfacee, - operatione); - } - - /* normal method definition */ - overloade = operatione->overloadv; - - fprintf(outf, - "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", - DLPFX, interfacee->class_name, operatione->name); - fprintf(outf,"{\n"); - - /* check arguments */ - - /* generate check for minimum number of parameters */ - - fixedargc = overloade->argumentc - overloade->optionalc; - - fprintf(outf, - "\t/* ensure the parameters are present */\n" - "\tduk_idx_t %s_argc = duk_get_top(ctx);\n\t", DLPFX); - - if (fixedargc > 0) { - fprintf(outf, - "if (%s_argc < %d) {\n" - "\t\t/* not enough arguments */\n" - "\t\tduk_error(ctx, DUK_RET_TYPE_ERROR, %s_error_fmt_argument, %d, %s_argc);\n" - "\t} else ", - DLPFX, - fixedargc, - DLPFX, - fixedargc, - DLPFX); - } - - for (optargc = fixedargc; - optargc < overloade->argumentc; - optargc++) { - fprintf(outf, - "if (%s_argc == %d) {\n" - "\t\t/* %d optional arguments need adding */\n", - DLPFX, - optargc, - overloade->argumentc - optargc); - output_operation_optional_defaults(outf, - overloade->argumentv + optargc, - overloade->argumentc - optargc); - fprintf(outf, - "\t} else "); - } - - fprintf(outf, - "if (%s_argc > %d) {\n" - "\t\t/* remove extraneous parameters */\n" - "\t\tduk_set_top(ctx, %d);\n" - "\t}\n", - DLPFX, - overloade->argumentc, - overloade->argumentc); - fprintf(outf, "\n"); - - /* generate argument type checks */ - - fprintf(outf, "\t/* check types of passed arguments are correct */\n"); - - for (argidx = 0; argidx < overloade->argumentc; argidx++) { - output_operation_argument_type_check(outf, - interfacee, - operatione, - overloade, - argidx); - } - - 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 ir_entry *ife) -{ - int opc; - int res = 0; - - for (opc = 0; opc < ife->u.interface.operationc; opc++) { - res = output_interface_operation( - outf, - ife, - ife->u.interface.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 ir_entry *interfacee, - struct ir_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 ir_entry *ife) -{ - int attrc; - - for (attrc = 0; attrc < ife->u.interface.attributec; attrc++) { - output_interface_attribute( - outf, - ife, - ife->u.interface.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 a dictionary using duk and libdom. - */ -static int output_dictionary(struct ir *ir, struct ir_entry *dictionarye) -{ - FILE *ifacef; - struct ir_entry *inherite; - int res = 0; - - /* open output file */ - ifacef = genb_fopen_tmp(dictionarye->filename); - if (ifacef == NULL) { - return -1; - } - - /* find parent interface entry */ - inherite = ir_inherit_entry(ir, dictionarye); - - /* tool preface */ - output_tool_preface(ifacef); - - /* binding preface */ - output_cdata(ifacef, - ir->binding_node, - GENBIND_NODE_TYPE_PREFACE); - - /* class preface */ - output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_PREFACE); - - /* tool prologue */ - output_tool_prologue(ifacef); - - /* binding prologue */ - output_cdata(ifacef, - ir->binding_node, - GENBIND_NODE_TYPE_PROLOGUE); - - /* class prologue */ - output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_PROLOGUE); - - fprintf(ifacef, "\n"); - - /* initialisor */ - res = output_interface_init(ifacef, dictionarye, inherite); - if (res != 0) { - goto op_error; - } - - /* finaliser */ - res = output_interface_fini(ifacef, dictionarye, inherite); - if (res != 0) { - goto op_error; - } - - /* constructor */ - res = output_interface_constructor(ifacef, dictionarye); - if (res != 0) { - goto op_error; - } - - /* destructor */ - res = output_interface_destructor(ifacef, dictionarye); - if (res != 0) { - goto op_error; - } - - /* prototype */ - res = output_interface_prototype(ifacef, ir, dictionarye, inherite); - if (res != 0) { - goto op_error; - } - - - fprintf(ifacef, "\n"); - - /* class epilogue */ - output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_EPILOGUE); - - /* binding epilogue */ - output_cdata(ifacef, - ir->binding_node, - GENBIND_NODE_TYPE_EPILOGUE); - - /* class postface */ - output_cdata(ifacef, dictionarye->class, GENBIND_NODE_TYPE_POSTFACE); - - /* binding postface */ - output_cdata(ifacef, - ir->binding_node, - GENBIND_NODE_TYPE_POSTFACE); - -op_error: - genb_fclose_tmp(ifacef, dictionarye->filename); - - return res; -} - -/** - * generate a source file to implement an interface using duk and libdom. - */ -static int output_interface(struct ir *ir, struct ir_entry *interfacee) -{ - FILE *ifacef; - struct ir_entry *inherite; - int res = 0; - - /* open output file */ - ifacef = genb_fopen_tmp(interfacee->filename); - if (ifacef == NULL) { - return -1; - } - - /* find parent interface entry */ - inherite = ir_inherit_entry(ir, interfacee); - - /* tool preface */ - output_tool_preface(ifacef); - - /* binding preface */ - output_cdata(ifacef, - ir->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, - ir->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, ir, interfacee, inherite); - - fprintf(ifacef, "\n"); - - /* class epilogue */ - output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE); - - /* binding epilogue */ - output_cdata(ifacef, - ir->binding_node, - GENBIND_NODE_TYPE_EPILOGUE); - - /* class postface */ - output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_POSTFACE); - - /* binding postface */ - output_cdata(ifacef, - ir->binding_node, - GENBIND_NODE_TYPE_POSTFACE); - -op_error: - genb_fclose_tmp(ifacef, interfacee->filename); - - return res; -} /** * generate private header diff --git a/src/duk-libdom.h b/src/duk-libdom.h index 2ecd482..84fc497 100644 --- a/src/duk-libdom.h +++ b/src/duk-libdom.h @@ -9,6 +9,41 @@ #ifndef nsgenbind_duk_libdom_h #define nsgenbind_duk_libdom_h +/** + * Generate output for duktape and libdom bindings. + */ int duk_libdom_output(struct ir *ir); +/** + * generate a source file to implement an interface using duk and libdom. + */ +int output_interface(struct ir *ir, struct ir_entry *interfacee); + +/** + * generate a source file to implement a dictionary using duk and libdom. + */ +int output_dictionary(struct ir *ir, struct ir_entry *dictionarye); + +/** + * generate preface block for nsgenbind + */ +int output_tool_preface(FILE* outf); + +/** + * generate preface block for nsgenbind + */ +int output_tool_prologue(FILE* outf); + +/** + * 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. + */ +int output_cdata(FILE* outf, struct genbind_node *node, enum genbind_node_type nodetype); + #endif |