From ef1eb5b59df798dc9a3e8df93fe46500aa4244e9 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 26 Jul 2015 17:52:27 +0100 Subject: make the duktape libdom generator output initializers --- src/duk-libdom.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 299 insertions(+), 27 deletions(-) (limited to 'src/duk-libdom.c') diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 4d8ecf5..ee45eaf 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -22,6 +22,9 @@ #include "interface-map.h" #include "duk-libdom.h" +/** prefix for all generated functions */ +#define DLPFX "duckky" + #define NSGENBIND_PREAMBLE \ "/* Generated by nsgenbind\n" \ " *\n" \ @@ -94,6 +97,40 @@ static char *gen_class_name(struct interface_map_entry *interfacee) return name; } +/** + * find method by type on class + */ +static struct genbind_node * +find_class_method(struct genbind_node *node, + struct genbind_node *prev, + enum genbind_node_type nodetype) +{ + struct genbind_node *res_node; + + res_node = genbind_node_find_type( + genbind_node_getnode(node), + prev, GENBIND_NODE_TYPE_METHOD); + while (res_node != NULL) { + struct genbind_node *type_node; + enum genbind_node_type *type; + + type_node = genbind_node_find_type( + genbind_node_getnode(res_node), + NULL, GENBIND_NODE_TYPE_METHOD_TYPE); + + type = (enum genbind_node_type *)genbind_node_getint(type_node); + if (*type == nodetype) { + break; + } + + res_node = genbind_node_find_type( + genbind_node_getnode(node), + res_node, GENBIND_NODE_TYPE_METHOD); + } + + return res_node; +} + /** * output character data of node of given type. * @@ -110,19 +147,258 @@ output_cdata(FILE* outf, genbind_node_getnode(node), NULL, nodetype)); if (cdata != NULL) { - fprintf(outf, "%s\n", cdata); + fprintf(outf, "%s", cdata); + } + return 0; +} + +/** + * Output code to create a private structure + * + */ +static int output_duckky_create_private(FILE* outf, char *class_name) +{ + 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, PRIVATE_MAGIC)\n\n"); + + return 0; +} + +/** + * generate code that gets a private pointer + */ +static int output_ducky_safe_get_private(FILE* outf, char *class_name, int idx) +{ + fprintf(outf, + "\t%s_private_t *priv = dukky_get_private(ctx, %d);\n", + class_name, idx); + fprintf(outf, "\tif (priv == NULL) return 0;\n\n"); + return 0; +} + + +/** + * generate the interface constructor + */ +static int +output_interface_constructor(FILE* outf, struct interface_map_entry *interfacee) +{ + /* constructor definition */ + fprintf(outf, + "duk_ret_t %s_%s___constructor(duk_context *ctx)\n", + DLPFX, interfacee->class_name); + fprintf(outf,"{\n"); + + output_duckky_create_private(outf, interfacee->class_name); + + /* generate call to initialisor */ + fprintf(outf, + "\t%s_%s___init(ctx, priv, duk_get_pointer(ctx, 1));\n", + DLPFX, interfacee->class_name); + + 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 interface_map_entry *interfacee) +{ + /* destructor definition */ + fprintf(outf, + "duk_ret_t %s_%s___destructor(duk_context *ctx)\n", + DLPFX, interfacee->class_name); + fprintf(outf,"{\n"); + + output_ducky_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 interface_map_entry *interfacee, + struct interface_map_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 = find_class_method(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_INIT); + + + inh_init_node = find_class_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(FILE* outf, + struct interface_map_entry *interfacee, + struct interface_map_entry *inherite) +{ + struct genbind_node *init_node; + struct genbind_node *param_node; + int res; + + /* find the initialisor method on the class (if any) */ + init_node = find_class_method(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_INIT); + + /* initialisor definition */ + fprintf(outf, + "void %s_%s___init(duk_context *ctx, %s_private_t *priv", + DLPFX, interfacee->class_name, interfacee->class_name); + + /* 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) { + 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_METHOD); + } + + 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 interface_map_entry *interfacee, struct interface_map_entry *inherite) { struct genbind_node *fini_node; - struct genbind_node *type_node; - int *type; + + /* find the finaliser method on the class (if any) */ + fini_node = find_class_method(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_FINI); /* finaliser definition */ fprintf(outf, @@ -136,24 +412,7 @@ output_interface_fini(FILE* 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 the finialisor code from the binding */ output_cdata(outf, fini_node, GENBIND_NODE_TYPE_CDATA); /* if this interface inherits ensure we call its finaliser */ @@ -162,7 +421,7 @@ output_interface_fini(FILE* outf, "\tdukky_%s___fini(ctx, &priv->parent);\n", inherite->class_name); } - fprintf(outf, "}\n"); + fprintf(outf, "}\n\n"); return 0; } @@ -180,7 +439,9 @@ static int output_interface(struct genbind_node *genbind, int ifacenamelen; struct genbind_node *binding_node; struct interface_map_entry *inherite; + int res = 0; + /* compute clas name */ interfacee->class_name = gen_class_name(interfacee); /* generate source filename */ @@ -198,15 +459,15 @@ static int output_interface(struct genbind_node *genbind, /* 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); + /* nsgenbind preamble */ + fprintf(ifacef, "\n%s\n", NSGENBIND_PREAMBLE); + /* class preface */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE); @@ -216,14 +477,24 @@ static int output_interface(struct genbind_node *genbind, /* class prologue */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PROLOGUE); + fprintf(ifacef, "\n"); + /* initialisor */ - //output_interface_init(); + 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); + + fprintf(ifacef, "\n"); /* class epilogue */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE); @@ -237,9 +508,10 @@ static int output_interface(struct genbind_node *genbind, /* binding postface */ output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_POSTFACE); +op_error: fclose(ifacef); - return 0; + return res; } int duk_libdom_output(struct genbind_node *genbind, -- cgit v1.2.3