summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2015-08-10 17:31:53 +0100
committerVincent Sanders <vince@kyllikki.org>2015-08-11 00:33:04 +0100
commita5ee3af901408a5d0578360aaecfba7e27cc0954 (patch)
tree1eb9e1982d1dbedf7a9cbf110c17d2cd9a9200ff /src
parentfc6be4af3427f8b317d4d264fa1ec3739ba5427b (diff)
downloadnsgenbind-a5ee3af901408a5d0578360aaecfba7e27cc0954.tar.gz
nsgenbind-a5ee3af901408a5d0578360aaecfba7e27cc0954.tar.bz2
Ensure the number of parameters is correct for operations
For normal operations (not special, overloaded or varadic) check the number of parameters passed is correct and add default values if necessary. This means every normal operation will always have a complete set of parameters and throw an error if there are too few non optional arguments.
Diffstat (limited to 'src')
-rw-r--r--src/duk-libdom.c293
-rw-r--r--src/interface-map.h6
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;
};