diff options
-rw-r--r-- | src/duk-libdom.c | 293 | ||||
-rw-r--r-- | src/interface-map.h | 6 |
2 files changed, 273 insertions, 26 deletions
diff --git a/src/duk-libdom.c b/src/duk-libdom.c index dcedfb2..4eb0432 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -859,25 +859,25 @@ output_interface_prototype(FILE* outf, /* 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->primary_global) { - fprintf(outf, "\t/* Create interface objects */\n"); - for (int idx = 0; idx < interface_map->entryc; idx++) { - struct interface_map_entry *interfacep; - - interfacep = interface_map->entries + idx; - if (interfacep->noobject) continue; - if (interfacep == interfacee) - fprintf(outf, "\tduk_dup(ctx, 0);\n"); - else - output_get_prototype(outf, interfacep->name); - fprintf(outf, - "\tdukky_inject_not_ctr(ctx, 0, \"%s\");\n", - interfacep->name); - } - } + /* if this is the global object, output all interfaces which do not + * prevent us from doing so + */ + if (interfacee->primary_global) { + fprintf(outf, "\t/* Create interface objects */\n"); + for (int idx = 0; idx < interface_map->entryc; idx++) { + struct interface_map_entry *interfacep; + + interfacep = interface_map->entries + idx; + if (interfacep->noobject) continue; + if (interfacep == interfacee) + fprintf(outf, "\tduk_dup(ctx, 0);\n"); + else + output_get_prototype(outf, interfacep->name); + fprintf(outf, + "\tdukky_inject_not_ctr(ctx, 0, \"%s\");\n", + interfacep->name); + } + } /* generate setting of destructor */ output_set_destructor(outf, interfacee->class_name, 0); @@ -895,6 +895,174 @@ output_interface_prototype(FILE* outf, return 0; } +/** + * generate a single class method for an interface operation with elipsis + */ +static int +output_interface_elipsis_operation(FILE* outf, + struct interface_map_entry *interfacee, + struct interface_map_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 interface_map_entry *interfacee, + struct interface_map_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 interface_map_entry *interfacee, + struct interface_map_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 interface_map_operation_argument_entry *argumentv, + int argumentc) +{ + int argc; + for (argc = 0; argc < argumentc; argc++) { + struct interface_map_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; +} /** * generate a single class method for an interface operation @@ -905,21 +1073,85 @@ output_interface_operation(FILE* outf, struct interface_map_operation_entry *operatione) { int cdatac; /* cdata blocks output */ + struct interface_map_operation_overload_entry *overloade; + int fixedargc; /* number of non optional arguments */ + int optargc; /* loop counter for optional arguments */ if (operatione->name == NULL) { - /* special method definition */ - fprintf(outf, - "/* Special method definition - UNIMPLEMENTED */\n\n"); - return 0; + 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_argument_error_fmt, %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", + DLPFX, + overloade->argumentc, + overloade->argumentc); + fprintf(outf, "\t}\n"); + + output_get_method_private(outf, interfacee->class_name); cdatac = output_cdata(outf, @@ -1210,6 +1442,10 @@ output_private_header(struct interface_map *interface_map) NULL, GENBIND_NODE_TYPE_PRIVATE); while (priv_node != NULL) { + /* generate the private variable definition ensuring + * the type is separated from the identifier with + * either a * or space. + */ const char *type_cdata; char cdatae; type_cdata = genbind_node_gettext( @@ -1369,6 +1605,10 @@ output_binding_header(struct interface_map *interface_map) MAGICPFX); fprintf(bindf, + "extern const char *%s_argument_error_fmt;", + DLPFX); + + fprintf(bindf, "duk_bool_t %s_instanceof(duk_context *ctx, const char *klass);\n", DLPFX); @@ -1419,6 +1659,13 @@ output_binding_src(struct interface_map *interface_map) fprintf(bindf, "\n"); + fprintf(bindf, + "/* Error format strings */\n" + "const char *%s_argument_error_fmt =\"%%d argument required, but ony %%d present.\";\n", + DLPFX); + + fprintf(bindf, "\n"); + /* instance of helper */ fprintf(bindf, "duk_bool_t\n" diff --git a/src/interface-map.h b/src/interface-map.h index 5f1926e..079ed96 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -13,13 +13,13 @@ struct genbind_node; struct webidl_node; /** - *map entry for each argument of an overload on an operation + * map entry for each argument of an overload on an operation */ struct interface_map_operation_argument_entry { const char *name; - int optionalc; /**< Number of parameters that are optional */ - int elipsisc; /**< Number of elipsis parameters */ + int optionalc; /**< 1 if the argument is optional */ + int elipsisc; /**< 1 if the argument is an elipsis */ struct webidl_node *node; }; |