From a9e5295d8735ff4ffe10e63f48728380edf6d7a0 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 9 Aug 2015 11:07:11 +0100 Subject: Update the interface map to contain all operation arguments This extends the interface map (the intermediate representation) to have information on every operations arguments including overloading and optional arguments. This is important to allow automated checking of passed parameters numbers and types in future. --- src/duk-libdom.c | 108 ++++++--------------- src/interface-map.c | 269 ++++++++++++++++++++++++++++++++++++++++++---------- src/interface-map.h | 33 ++++++- src/webidl-ast.c | 22 ++++- src/webidl-ast.h | 3 +- src/webidl-lexer.l | 2 +- src/webidl-parser.y | 14 ++- 7 files changed, 310 insertions(+), 141 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index a2d65af..195f4a4 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -160,19 +160,13 @@ output_dump_stack(FILE* outf) static int output_add_method(FILE* outf, const char *class_name, - const char *method, - int argc) + 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, ", + fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s, DUK_VARARGS);\n", DLPFX, class_name, method); - if (argc == -1) { - fprintf(outf, "DUK_VARARGS);\n"); - } else { - fprintf(outf, "%d);\n", argc); - } output_dump_stack(outf); fprintf(outf, "\tduk_def_prop(ctx, -3,\n"); fprintf(outf, "\t DUK_DEFPROP_HAVE_VALUE |\n"); @@ -699,35 +693,6 @@ output_interface_fini(FILE* outf, } -/** - * count the number of arguments to an operation - * - * \todo this needs to consider multiple lists (overloaded calls?), varadic - * parameters. - * - * \retuen number of arguments or -1 if variable - */ -static int count_operation_arguments(struct webidl_node *node) -{ - int argc; - struct webidl_node *list_node; - list_node = webidl_node_find_type( - webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_LIST); - if (list_node == NULL) { - /** \todo is having no argument list an error or a warning? */ - return 0; - } - argc = webidl_node_enumerate_type(webidl_node_getnode(list_node), - WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT); - if (argc != 0) { - return -1; - } - return webidl_node_enumerate_type(webidl_node_getnode(list_node), - WEBIDL_NODE_TYPE_ARGUMENT); -} - /** * generate a prototype add for a single class method */ @@ -736,23 +701,12 @@ output_prototype_method(FILE* outf, struct interface_map_entry *interfacee, struct interface_map_operation_entry *operatione) { - int op_argc; - - if (operatione->overloadc > 1) { - /* only generate a method for the first occourance of an - * overloaded method - */ - return 0; - } if (operatione->name != NULL) { - /* normal method of prototype */ - op_argc = count_operation_arguments(operatione->node); - + /* normal method on prototype */ output_add_method(outf, interfacee->class_name, - operatione->name, - op_argc); + operatione->name); } else { /* special method on prototype */ fprintf(outf, @@ -929,44 +883,38 @@ output_interface_operation(FILE* outf, struct interface_map_entry *interfacee, struct interface_map_operation_entry *operatione) { - if (operatione->overloadc > 1) { - /* only generate a method for the first occourance of an - * overloaded method - */ + int cdatac; /* cdata blocks output */ + + if (operatione->name == NULL) { + /* special method definition */ + fprintf(outf, + "/* Special method definition - UNIMPLEMENTED */\n\n"); return 0; } - if (operatione->name != NULL) { - /* normal method definition */ + /* normal method definition */ - int cdatac; /* cdata blocks output */ + fprintf(outf, + "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", + DLPFX, interfacee->class_name, operatione->name); + fprintf(outf,"{\n"); - fprintf(outf, - "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", - DLPFX, interfacee->class_name, operatione->name); - fprintf(outf,"{\n"); - - 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"); - } + output_get_method_private(outf, interfacee->class_name); - fprintf(outf, "}\n\n"); - } else { - /* special method definition */ - fprintf(outf, - "/* Special method definition - UNIMPLEMENTED */\n\n"); + 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; } diff --git a/src/interface-map.c b/src/interface-map.c index 29e9ec0..a5a672a 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -132,31 +132,149 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) return dstinf; } -static int -count_operation_name(struct interface_map_operation_entry *operationv, +static struct interface_map_operation_entry * +find_operation_name(struct interface_map_operation_entry *operationv, int operationc, const char *name) { struct interface_map_operation_entry *cure; int opc; - int res = 0; for (opc = 0; opc < operationc; opc++) { cure = operationv + opc; if (cure->name == name) { /* check pointers for equivalence */ - res++; + return cure; } else { if ((cure->name != NULL) && (name != NULL) && (strcmp(cure->name, name) == 0)) { - res++; + return cure; } } } - return res; + return NULL; +} + +static int +argument_map_new(struct webidl_node *arg_list_node, + int *argumentc_out, + struct interface_map_operation_argument_entry **argumentv_out) +{ + int argumentc; + struct webidl_node *argument; + struct interface_map_operation_argument_entry *argumentv; + struct interface_map_operation_argument_entry *cure; + + argumentc = webidl_node_enumerate_type( + webidl_node_getnode(arg_list_node), + WEBIDL_NODE_TYPE_ARGUMENT); + if (argumentc == 0) { + *argumentc_out = 0; + *argumentv_out = NULL; + return 0; + } + + argumentv = calloc(argumentc, sizeof(*argumentv)); + cure = argumentv; + + /* iterate each argument node within the list */ + argument = webidl_node_find_type(webidl_node_getnode(arg_list_node), + NULL, + WEBIDL_NODE_TYPE_ARGUMENT); + + while (argument != NULL) { + + cure->name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(argument), + NULL, + WEBIDL_NODE_TYPE_IDENT)); + + cure->node = argument; + + + cure->optionalc = webidl_node_enumerate_type( + webidl_node_getnode(argument), + WEBIDL_NODE_TYPE_OPTIONAL); + + cure->elipsisc = webidl_node_enumerate_type( + webidl_node_getnode(argument), + WEBIDL_NODE_TYPE_ELLIPSIS); + + cure++; + + argument = webidl_node_find_type( + webidl_node_getnode(arg_list_node), + argument, + WEBIDL_NODE_TYPE_ARGUMENT); + } + + *argumentc_out = argumentc; + *argumentv_out = argumentv; + + return 0; +} + +/** + * create a new overloaded parameter set on an operation + * + * each operation can be overloaded with multiple function signatures. By + * adding them to the operation as overloads duplicate operation enrtries is + * avoided. + */ +static int +overload_map_new(struct webidl_node *op_node, + int *overloadc_out, + struct interface_map_operation_overload_entry **overloadv_out) +{ + int overloadc = *overloadc_out; + struct interface_map_operation_overload_entry *overloadv; + struct interface_map_operation_overload_entry *cure; + struct webidl_node *arg_list_node; + int argc; + + /* update allocation */ + overloadc++; + overloadv = realloc(*overloadv_out, overloadc * sizeof(*overloadv)); + if (overloadv == NULL) { + return -1; + } + + /* get added entry */ + cure = overloadv + (overloadc - 1); + + /* clear entry */ + cure = memset(cure, 0, sizeof(*cure)); + + /* return type */ + cure->type = webidl_node_find_type(webidl_node_getnode(op_node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + arg_list_node = webidl_node_find_type(webidl_node_getnode(op_node), + NULL, + WEBIDL_NODE_TYPE_LIST); + if (arg_list_node != NULL) { + argument_map_new(arg_list_node, + &cure->argumentc, + &cure->argumentv); + } + + for (argc = 0; argc < cure->argumentc; argc++) { + struct interface_map_operation_argument_entry *arge; + arge = cure->argumentv + argc; + cure->optionalc += arge->optionalc; + cure->elipsisc += arge->elipsisc; + } + + /* return entry list */ + *overloadc_out = overloadc; + *overloadv_out = overloadv; + + return 0; } static int @@ -170,9 +288,8 @@ operation_map_new(struct webidl_node *interface, struct interface_map_operation_entry *cure; /* current entry */ struct interface_map_operation_entry *operationv; int operationc; - int opc; - /* enumerate operationss */ + /* enumerate operationss including overloaded members */ operationc = enumerate_interface_type(interface, WEBIDL_NODE_TYPE_OPERATION); @@ -204,25 +321,49 @@ operation_map_new(struct webidl_node *interface, WEBIDL_NODE_TYPE_OPERATION); while (op_node != NULL) { - cure->node = op_node; + const char *operation_name; + struct interface_map_operation_entry *finde; - cure->name = webidl_node_gettext( + /* get operation name */ + operation_name = webidl_node_gettext( webidl_node_find_type( webidl_node_getnode(op_node), NULL, WEBIDL_NODE_TYPE_IDENT)); + /* if this operation is already an entry in the list + * augment that entry else create a new one + */ + finde = find_operation_name(operationv, + operationc, + operation_name); + if (finde == NULL) { + /* operation does not already exist in list */ + + cure->name = operation_name; + + cure->node = op_node; - cure->method = genbind_node_find_method_ident( + cure->method = genbind_node_find_method_ident( class, NULL, GENBIND_METHOD_TYPE_METHOD, cure->name); - cure->overloadc = count_operation_name(operationv, - operationc, - cure->name); + overload_map_new(op_node, + &cure->overloadc, + &cure->overloadv); - cure++; + cure++; /* advance to next entry */ + } else { + overload_map_new(op_node, + &finde->overloadc, + &finde->overloadv); + /* Overloaded entry does not advance the + * current entry but does reduce list + * length. Do not bother shortening allocation. + */ + operationc--; + } /* move to next operation */ op_node = webidl_node_find_type( @@ -237,20 +378,6 @@ operation_map_new(struct webidl_node *interface, WEBIDL_NODE_TYPE_LIST); } - /* finally take a pass over the table to correct the overload count */ - for (opc = 0; opc < operationc; opc++) { - cure = operationv + opc; - if ((cure->overloadc == 1) && - (count_operation_name(operationv, - operationc, - cure->name) == 1)) { - /* if the "overloaded" member is itself it is not - * overloaded. - */ - cure->overloadc = 0; - } - } - *operationc_out = operationc; *operationv_out = operationv; /* resulting operations map */ @@ -567,46 +694,88 @@ int interface_map_dump(struct interface_map *index) for (eidx = 0; eidx < index->entryc; eidx++) { fprintf(dumpf, "%d %s\n", eidx, ecur->name); if (ecur->inherit_name != NULL) { - fprintf(dumpf, " inherit:%s\n", ecur->inherit_name); + fprintf(dumpf, "\tinherit:%s\n", ecur->inherit_name); } if (ecur->class != NULL) { - fprintf(dumpf, " class:%p\n", ecur->class); + fprintf(dumpf, "\tclass:%p\n", ecur->class); } + if (ecur->operationc > 0) { - int opc = ecur->operationc; - struct interface_map_operation_entry *ope; + int opc; - fprintf(dumpf, " %d operations\n", + fprintf(dumpf, "\t%d operations\n", ecur->operationc); - ope = ecur->operationv; - while (ope != NULL) { + for (opc = 0; opc < ecur->operationc; opc++) { + int ovlc; + struct interface_map_operation_entry *ope; + + ope = ecur->operationv + opc; + fprintf(dumpf, - " %s\n", + "\t\t%s\n", ope->name); fprintf(dumpf, - " method:%p\n", + "\t\t\tmethod:%p\n", ope->method); - fprintf(dumpf, - " overload:%d\n", - ope->overloadc); - ope++; - opc--; - if (opc == 0) { - break; + for(ovlc = 0; ovlc < ope->overloadc;ovlc++) { + int argc; + struct interface_map_operation_overload_entry *ovle; + ovle = ope->overloadv + ovlc; + + fprintf(dumpf, + "\t\t\toverload:%d\n", ovlc); + + fprintf(dumpf, + "\t\t\t\treturn type:%p\n", + ovle->type); + + fprintf(dumpf, + "\t\t\t\targuments:%d\n", + ovle->argumentc); + + fprintf(dumpf, + "\t\t\t\toptionals:%d\n", + ovle->optionalc); + + fprintf(dumpf, + "\t\t\t\telipsis:%d\n", + ovle->elipsisc); + + for (argc = 0; argc < ovle->argumentc; argc++) { + struct interface_map_operation_argument_entry *arge; + arge = ovle->argumentv + argc; + + fprintf(dumpf, + "\t\t\t\t\t%s\n", + arge->name); + + if (arge->optionalc != 0) { + fprintf(dumpf, + "\t\t\t\t\t\toptional:%d\n", + arge->optionalc); + } + + if (arge->elipsisc != 0) { + fprintf(dumpf, + "\t\t\t\t\t\telipsis:%d\n", + arge->elipsisc); + } + + } } } - } + if (ecur->attributec > 0) { int attrc = ecur->attributec; struct interface_map_attribute_entry *attre; - fprintf(dumpf, " %d attributes\n", attrc); + fprintf(dumpf, "\t%d attributes\n", attrc); attre = ecur->attributev; while (attre != NULL) { - fprintf(dumpf, " %s %p", + fprintf(dumpf, "\t\t%s %p", attre->name, attre->getter); if (attre->modifier == WEBIDL_TYPE_MODIFIER_NONE) { @@ -624,13 +793,13 @@ int interface_map_dump(struct interface_map *index) if (ecur->constantc > 0) { int idx; - fprintf(dumpf, " %d constants\n", + fprintf(dumpf, "\t%d constants\n", ecur->constantc); for (idx = 0; idx < ecur->constantc; idx++) { struct interface_map_constant_entry *cone; cone = ecur->constantv + idx; - fprintf(dumpf, " %s\n", + fprintf(dumpf, "\t\t%s\n", cone->name); } } diff --git a/src/interface-map.h b/src/interface-map.h index 04d9df1..5f1926e 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -12,12 +12,37 @@ struct genbind_node; struct webidl_node; +/** + *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 */ + + struct webidl_node *node; +}; + +/** map entry for each overload of an operation */ +struct interface_map_operation_overload_entry { + struct webidl_node *type; /**< The return type of this overload */ + + int optionalc; /**< Number of parameters that are optional */ + int elipsisc; /**< Number of elipsis parameters */ + + int argumentc; /**< the number of parameters */ + struct interface_map_operation_argument_entry *argumentv; +}; + /** map entry for operations on an interface */ struct interface_map_operation_entry { const char *name; /** operation name */ struct webidl_node *node; /**< AST operation node */ - struct genbind_node *method; /**< method from binding (if any) */ - int overloadc; /**< Number of previous overloads of this operation */ + struct genbind_node *method; /**< method from binding */ + + int overloadc; /**< Number of overloads of this operation */ + struct interface_map_operation_overload_entry *overloadv; }; /** map entry for attributes on an interface */ @@ -25,8 +50,8 @@ struct interface_map_attribute_entry { const char *name; /** attribute name */ struct webidl_node *node; /**< AST attribute node */ enum webidl_type_modifier modifier; - struct genbind_node *getter; /**< getter from binding (if any) */ - struct genbind_node *setter; /**< getter from binding (if any) */ + struct genbind_node *getter; /**< getter from binding */ + struct genbind_node *setter; /**< getter from binding */ }; /** map entry for constants on an interface */ diff --git a/src/webidl-ast.c b/src/webidl-ast.c index 0e90767..87e3485 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -100,7 +100,7 @@ webidl_node_add(struct webidl_node *node, struct webidl_node *list) case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: case WEBIDL_NODE_TYPE_ATTRIBUTE: case WEBIDL_NODE_TYPE_OPERATION: - case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT: + case WEBIDL_NODE_TYPE_OPTIONAL: case WEBIDL_NODE_TYPE_ARGUMENT: case WEBIDL_NODE_TYPE_TYPE: case WEBIDL_NODE_TYPE_CONST: @@ -267,6 +267,7 @@ char *webidl_node_gettext(struct webidl_node *node) case WEBIDL_NODE_TYPE_IDENT: case WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE: case WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS: + case WEBIDL_NODE_TYPE_LITERAL_STRING: return node->r.text; default: @@ -286,6 +287,7 @@ webidl_node_getint(struct webidl_node *node) case WEBIDL_NODE_TYPE_TYPE_BASE: case WEBIDL_NODE_TYPE_LITERAL_INT: case WEBIDL_NODE_TYPE_SPECIAL: + case WEBIDL_NODE_TYPE_LITERAL_BOOL: return &node->r.number; default: @@ -313,7 +315,7 @@ struct webidl_node *webidl_node_getnode(struct webidl_node *node) case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: case WEBIDL_NODE_TYPE_ATTRIBUTE: case WEBIDL_NODE_TYPE_OPERATION: - case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT: + case WEBIDL_NODE_TYPE_OPTIONAL: case WEBIDL_NODE_TYPE_ARGUMENT: case WEBIDL_NODE_TYPE_TYPE: case WEBIDL_NODE_TYPE_CONST: @@ -354,8 +356,8 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) case WEBIDL_NODE_TYPE_OPERATION: return "Operation"; - case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT: - return "Argument(opt)"; + case WEBIDL_NODE_TYPE_OPTIONAL: + return "Optional"; case WEBIDL_NODE_TYPE_ARGUMENT: return "Argument"; @@ -381,9 +383,21 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) case WEBIDL_NODE_TYPE_CONST: return "Const"; + case WEBIDL_NODE_TYPE_LITERAL_NULL: + return "Literal (null)"; + case WEBIDL_NODE_TYPE_LITERAL_INT: return "Literal (int)"; + case WEBIDL_NODE_TYPE_LITERAL_BOOL: + return "Literal (bool)"; + + case WEBIDL_NODE_TYPE_LITERAL_FLOAT: + return "Literal (string)"; + + case WEBIDL_NODE_TYPE_LITERAL_STRING: + return "Literal (string)"; + case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: return "Extended Attribute"; diff --git a/src/webidl-ast.h b/src/webidl-ast.h index c17a54b..25ef9a0 100644 --- a/src/webidl-ast.h +++ b/src/webidl-ast.h @@ -28,8 +28,8 @@ enum webidl_node_type { WEBIDL_NODE_TYPE_CONST, WEBIDL_NODE_TYPE_SPECIAL, - WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT, WEBIDL_NODE_TYPE_ARGUMENT, + WEBIDL_NODE_TYPE_OPTIONAL, WEBIDL_NODE_TYPE_ELLIPSIS, WEBIDL_NODE_TYPE_TYPE, WEBIDL_NODE_TYPE_TYPE_BASE, @@ -40,6 +40,7 @@ enum webidl_node_type { WEBIDL_NODE_TYPE_LITERAL_INT, WEBIDL_NODE_TYPE_LITERAL_BOOL, WEBIDL_NODE_TYPE_LITERAL_FLOAT, + WEBIDL_NODE_TYPE_LITERAL_STRING, WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE, diff --git a/src/webidl-lexer.l b/src/webidl-lexer.l index e49b813..8c68fdf 100644 --- a/src/webidl-lexer.l +++ b/src/webidl-lexer.l @@ -228,7 +228,7 @@ legacyiterable return TOK_LEGACYITERABLE; {decimalfloat} yylval->text = strdup(yytext); return TOK_FLOAT_LITERAL; -\"{quotedstring}*\" yylval->text = strdup(yytext); return TOK_STRING_LITERAL; +\"{quotedstring}*\" yylval->text = strdup(yytext + 1); *(yylval->text + yyleng - 2) = 0; return TOK_STRING_LITERAL; {multicomment} { /* multicomment */ diff --git a/src/webidl-parser.y b/src/webidl-parser.y index 953388e..9cfd84e 100644 --- a/src/webidl-parser.y +++ b/src/webidl-parser.y @@ -170,6 +170,8 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %type Ellipsis %type Iterable %type OptionalType +%type Default +%type DefaultValue %type Type %type ReturnType @@ -450,8 +452,14 @@ PartialDictionary: /* [15] */ Default: /* empty */ + { + $$ = NULL; + } | '=' DefaultValue + { + $$ = $2; + } ; @@ -460,6 +468,9 @@ DefaultValue: ConstValue | TOK_STRING_LITERAL + { + $$ = webidl_node_new(WEBIDL_NODE_TYPE_LITERAL_STRING, NULL, $1); + } ; /* [17] */ @@ -874,8 +885,9 @@ OptionalOrRequiredArgument: { struct webidl_node *argument; argument = webidl_node_new(WEBIDL_NODE_TYPE_IDENT, NULL, $3); + argument = webidl_node_new(WEBIDL_NODE_TYPE_OPTIONAL, argument, $4); argument = webidl_node_prepend(argument, $2); /* add type node */ - $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT, NULL, argument); + $$ = webidl_node_new(WEBIDL_NODE_TYPE_ARGUMENT, NULL, argument); } | Type Ellipsis ArgumentName -- cgit v1.2.3