From 5755930ae93b6305b40620fff0e90bc2e4c64b46 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 7 Dec 2013 14:28:19 +0000 Subject: move binding type from explicit statement into declaration. As a side effect the binding declaration changes and looses its (unused) name/identifier --- doc/example.bnd | 10 ++- src/jsapi-libdom.c | 121 ++++++++++++----------------------- src/jsapi-libdom.h | 6 +- src/nsgenbind-parser.y | 13 +--- src/nsgenbind.c | 86 +++++++++++++++++++++---- src/options.h | 4 ++ test/data/bindings/htmldocument.bnd | 3 +- test/data/bindings/htmldocument2.bnd | 4 +- test/data/bindings/window.bnd | 3 +- 9 files changed, 130 insertions(+), 120 deletions(-) diff --git a/doc/example.bnd b/doc/example.bnd index 690eace..6003f0d 100644 --- a/doc/example.bnd +++ b/doc/example.bnd @@ -53,17 +53,15 @@ epilogue %{ #include "dom.bnd" -/* this block describes the binding to be generated +/* This block describes the binding to be generated * * Depending on the type of binding being generated multiple blocks * may be allowed. * - * Note: the js_libdom (javascript to libdom) binding as currently - * implemented only allows for a single binding per file, this may - * be improved in future. + * Note: the jsapi_libdom (spidermonkey javascript to libdom) binding + * is the only type currently implemented */ -binding example { - type js_libdom; /* the binding type */ +binding jsapi_libdom { interface Navigator; /* The WebIDL interface to generate a binding for */ diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 7104a83..97a6193 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -285,7 +285,7 @@ output_api_operations(struct binding *binding) "\n" "\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n", binding->interface); - + if (options->dbglog) { fprintf(binding->outfile, "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n"); @@ -320,7 +320,7 @@ output_api_operations(struct binding *binding) "\n" "\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n", binding->interface); - + if (options->dbglog) { fprintf(binding->outfile, "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n"); @@ -355,7 +355,7 @@ output_api_operations(struct binding *binding) "\n" "\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n", binding->interface); - + if (options->dbglog) { fprintf(binding->outfile, "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n"); @@ -390,7 +390,7 @@ output_api_operations(struct binding *binding) "\n" "\tprivate = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n", binding->interface); - + if (options->dbglog) { fprintf(binding->outfile, "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, private);\n"); @@ -893,24 +893,27 @@ output_jsclass(struct binding *binding) return 0; } +/** generate structure definition for internal class data + * + * Every javascript object instance has an internal context to keep + * track of its state in object terms this would be considered the + * "this" pointer giving access to the classes members. + * + * Member access can be considered protected as all interfaces + * (classes) and subclasses generated within this binding have access + * to members. + * + * @param binding the binding to generate the structure for. + * @return 0 on success with output written and -1 on error. + */ static int output_private_declaration(struct binding *binding) { - struct genbind_node *type_node; if (!binding->has_private) { return 0; } - type_node = genbind_node_find(binding->binding_list, - NULL, - genbind_cmp_node_type, - (void *)GENBIND_NODE_TYPE_TYPE); - - if (type_node == NULL) { - return -1; - } - fprintf(binding->outfile, "struct jsclass_private {\n"); genbind_node_for_each_type(binding->binding_list, @@ -1024,40 +1027,22 @@ binding_has_global(struct binding *binding) } static struct binding * -binding_new(char *outfilename, - char *hdrfilename, - struct genbind_node *genbind_ast) +binding_new(struct options *options, + struct genbind_node *genbind_ast, + struct genbind_node *binding_node) { struct binding *nb; - struct genbind_node *binding_node; - struct genbind_node *binding_list; - struct genbind_node *ident_node; struct genbind_node *interface_node; - FILE *outfile = NULL; /* output source file */ - FILE *hdrfile = NULL; /* output header file */ + struct genbind_node *binding_list; char *hdrguard = NULL; struct webidl_node *webidl_ast = NULL; int res; - binding_node = genbind_node_find_type(genbind_ast, - NULL, - GENBIND_NODE_TYPE_BINDING); - if (binding_node == NULL) { - return NULL; - } - binding_list = genbind_node_getnode(binding_node); if (binding_list == NULL) { return NULL; } - ident_node = genbind_node_find_type(binding_list, - NULL, - GENBIND_NODE_TYPE_IDENT); - if (ident_node == NULL) { - return NULL; - } - interface_node = genbind_node_find_type(binding_list, NULL, GENBIND_NODE_TYPE_BINDING_INTERFACE); @@ -1072,37 +1057,16 @@ binding_new(char *outfilename, return NULL; } - /* open output file */ - if (outfilename == NULL) { - outfile = stdout; - } else { - outfile = fopen(outfilename, "w"); - } - if (outfile == NULL) { - fprintf(stderr, "Error opening source output %s: %s\n", - outfilename, - strerror(errno)); - return NULL; - } - - /* output header file if required */ - if (hdrfilename != NULL) { + /* header guard */ + if (options->hdrfilename != NULL) { int guardlen; int pos; - hdrfile = fopen(hdrfilename, "w"); - if (hdrfile == NULL) { - fprintf(stderr, "Error opening header output %s: %s\n", - hdrfilename, - strerror(errno)); - fclose(outfile); - return NULL; - } - guardlen = strlen(hdrfilename); + guardlen = strlen(options->hdrfilename); hdrguard = calloc(1, guardlen + 1); for (pos = 0; pos < guardlen; pos++) { - if (isalpha(hdrfilename[pos])) { - hdrguard[pos] = toupper(hdrfilename[pos]); + if (isalpha(options->hdrfilename[pos])) { + hdrguard[pos] = toupper(options->hdrfilename[pos]); } else { hdrguard[pos] = '_'; } @@ -1113,11 +1077,10 @@ binding_new(char *outfilename, nb->gb_ast = genbind_ast; nb->wi_ast = webidl_ast; - nb->name = genbind_node_gettext(ident_node); nb->interface = genbind_node_gettext(interface_node); - nb->outfile = outfile; - nb->srcfile = outfile; - nb->hdrfile = hdrfile; + nb->outfile = options->outfilehandle; + nb->srcfile = options->outfilehandle; + nb->hdrfile = options->hdrfilehandle; nb->hdrguard = hdrguard; nb->has_private = binding_has_private(binding_list); nb->has_global = binding_has_global(nb); @@ -1145,14 +1108,14 @@ binding_new(char *outfilename, "setproperty"); nb->enumerate = genbind_node_find_type_ident(genbind_ast, - NULL, - GENBIND_NODE_TYPE_API, - "enumerate"); + NULL, + GENBIND_NODE_TYPE_API, + "enumerate"); nb->resolve = genbind_node_find_type_ident(genbind_ast, - NULL, - GENBIND_NODE_TYPE_API, - "resolve"); + NULL, + GENBIND_NODE_TYPE_API, + "resolve"); nb->finalise = genbind_node_find_type_ident(genbind_ast, NULL, @@ -1160,23 +1123,23 @@ binding_new(char *outfilename, "finalise"); nb->mark = genbind_node_find_type_ident(genbind_ast, - NULL, - GENBIND_NODE_TYPE_API, - "mark"); + NULL, + GENBIND_NODE_TYPE_API, + "mark"); return nb; } int -jsapi_libdom_output(char *outfilename, - char *hdrfilename, - struct genbind_node *genbind_ast) +jsapi_libdom_output(struct options *options, + struct genbind_node *genbind_ast, + struct genbind_node *binding_node) { int res; struct binding *binding; /* get general binding information used in output */ - binding = binding_new(outfilename, hdrfilename, genbind_ast); + binding = binding_new(options, genbind_ast, binding_node); if (binding == NULL) { return 40; } diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index 7db664d..5a93ff1 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -9,12 +9,12 @@ #ifndef nsgenbind_jsapi_libdom_h #define nsgenbind_jsapi_libdom_h +struct options; + struct binding { struct genbind_node *gb_ast; /* root node of binding AST */ struct webidl_node *wi_ast; /* root node of webidl AST */ - - const char *name; /* name of the binding */ const char *interface; /* webidl interface binding is for */ bool has_private; /* true if the binding requires a private structure */ @@ -41,7 +41,7 @@ struct binding { }; /** Generate binding between jsapi and netsurf libdom */ -int jsapi_libdom_output(char *outfile, char *hdrfile, struct genbind_node *genbind_root); +int jsapi_libdom_output(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node); /** output code block from a node */ void output_code_block(struct binding *binding, struct genbind_node *codelist); diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index 46bc4f3..b9ec23b 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -81,7 +81,6 @@ char *errtxt; %type Binding %type BindingArgs %type BindingArg -%type Type %type Private %type Internal %type Interface @@ -265,7 +264,7 @@ Binding { $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING, NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, $4, $2)); + genbind_new_node(GENBIND_NODE_TYPE_TYPE, $4, $2)); } ; @@ -281,8 +280,6 @@ BindingArgs BindingArg : - Type - | Private | Internal @@ -292,14 +289,6 @@ BindingArg Property ; -Type - : - TOK_TYPE TOK_IDENTIFIER ';' - { - $$ = genbind_new_node(GENBIND_NODE_TYPE_TYPE, NULL, $2); - } - ; - Private : TOK_PRIVATE TOK_STRING_LITERAL TOK_IDENTIFIER ';' diff --git a/src/nsgenbind.c b/src/nsgenbind.c index d993646..636c22b 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -65,12 +65,12 @@ static struct options* process_cmdline(int argc, char **argv) break; default: /* '?' */ - fprintf(stderr, + fprintf(stderr, "Usage: %s [-v] [-g] [-D] [-W] [-d depfilename] [-I idlpath] [-o filename] [-h headerfile] inputfile\n", argv[0]); free(options); return NULL; - + } } @@ -86,6 +86,27 @@ static struct options* process_cmdline(int argc, char **argv) } +static int generate_binding(struct genbind_node *binding_node, void *ctx) +{ + struct genbind_node *genbind_root = ctx; + char *type; + int res = 10; + + type = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode(binding_node), + NULL, + GENBIND_NODE_TYPE_TYPE)); + + if (strcmp(type, "jsapi_libdom") == 0) { + res = jsapi_libdom_output(options, genbind_root, binding_node); + } else { + fprintf(stderr, "Error: unsupported binding type \"%s\"\n", type); + } + + return res; +} + int main(int argc, char **argv) { int res; @@ -96,9 +117,9 @@ int main(int argc, char **argv) return 1; /* bad commandline */ } - if (options->verbose && + if (options->verbose && (options->outfilename == NULL)) { - fprintf(stderr, + fprintf(stderr, "Error: output to stdout with verbose logging would fail\n"); return 2; } @@ -117,6 +138,7 @@ int main(int argc, char **argv) return 3; } + /* open dependancy file */ if (options->depfilename != NULL) { options->depfilehandle = fopen(options->depfilename, "w"); if (options->depfilehandle == NULL) { @@ -129,19 +151,61 @@ int main(int argc, char **argv) options->outfilename); } + /* parse input and generate dependancy */ res = genbind_parsefile(options->infilename, &genbind_root); if (res != 0) { fprintf(stderr, "Error: parse failed with code %d\n", res); return res; } + /* dependancy generation complete */ + if (options->depfilehandle != NULL) { + fputc('\n', options->depfilehandle); + fclose(options->depfilehandle); + } + + + /* open output file */ + if (options->outfilename == NULL) { + options->outfilehandle = stdout; + } else { + options->outfilehandle = fopen(options->outfilename, "w"); + } + if (options->outfilehandle == NULL) { + fprintf(stderr, "Error opening source output %s: %s\n", + options->outfilename, + strerror(errno)); + return 5; + } + + /* open output header file if required */ + if (options->hdrfilename != NULL) { + options->hdrfilehandle = fopen(options->hdrfilename, "w"); + if (options->hdrfilehandle == NULL) { + fprintf(stderr, "Error opening header output %s: %s\n", + options->hdrfilename, + strerror(errno)); + /* close and unlink output file */ + fclose(options->outfilehandle); + if (options->outfilename != NULL) { + unlink(options->outfilename); + } + return 6; + } + } else { + options->hdrfilehandle = NULL; + } + + /* dump the AST */ if (options->verbose) { genbind_ast_dump(genbind_root, 0); } - res = jsapi_libdom_output(options->outfilename, - options->hdrfilename, - genbind_root); + /* generate output for each binding */ + res = genbind_node_for_each_type(genbind_root, + GENBIND_NODE_TYPE_BINDING, + generate_binding, + genbind_root); if (res != 0) { fprintf(stderr, "Error: output failed with code %d\n", res); if (options->outfilename != NULL) { @@ -149,14 +213,10 @@ int main(int argc, char **argv) } if (options->hdrfilename != NULL) { unlink(options->hdrfilename); - } + } return res; } - if (options->depfilehandle != NULL) { - fputc('\n', options->depfilehandle); - fclose(options->depfilehandle); - } return 0; -} +} diff --git a/src/options.h b/src/options.h index 13c02be..e002a11 100644 --- a/src/options.h +++ b/src/options.h @@ -14,10 +14,14 @@ struct options { char *infilename; /**< binding source */ char *outfilename; /**< output source file */ + FILE *outfilehandle; /**< output file handle */ + char *hdrfilename; /**< output header file */ + FILE *hdrfilehandle; /**< output file handle */ char *depfilename; /**< dependancy output*/ FILE *depfilehandle; /**< dependancy file handle */ + char *idlpath; /**< path to IDL files */ bool verbose; /**< verbose processing */ diff --git a/test/data/bindings/htmldocument.bnd b/test/data/bindings/htmldocument.bnd index 8f85ca3..933695e 100644 --- a/test/data/bindings/htmldocument.bnd +++ b/test/data/bindings/htmldocument.bnd @@ -31,8 +31,7 @@ operation write %{ } %} -binding document { - type js_libdom; /* the binding type */ +binding jsapi_libdom { /* parameters to constructor value stored in private * context structure. diff --git a/test/data/bindings/htmldocument2.bnd b/test/data/bindings/htmldocument2.bnd index e7955d9..63deafd 100644 --- a/test/data/bindings/htmldocument2.bnd +++ b/test/data/bindings/htmldocument2.bnd @@ -26,9 +26,7 @@ operation write %{ } %} -binding document { - type js_libdom; /* the binding type */ - +binding jsapi_libdom { /* parameters to constructor value stored in private * context structure. */ diff --git a/test/data/bindings/window.bnd b/test/data/bindings/window.bnd index e59f65a..2f26f56 100644 --- a/test/data/bindings/window.bnd +++ b/test/data/bindings/window.bnd @@ -27,8 +27,7 @@ epilogue %{ #include "dom.bnd" -binding window { - type js_libdom; /* the binding type */ +binding jsapi_libdom { interface Window; /* Web IDL interface to generate */ -- cgit v1.2.3 From abec5defbb553588dce1c317b74570061705f6d0 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 16 Dec 2013 00:08:27 +0000 Subject: add flags to interface within binding --- doc/example.bnd | 28 ++++++++++++------ src/jsapi-libdom-property.c | 15 ++++++---- src/jsapi-libdom.c | 71 ++++++++++++++++++++++++++++++++------------- src/nsgenbind-ast.c | 13 +++++---- src/nsgenbind-ast.h | 33 ++++++++++++++++++--- src/nsgenbind-lexer.l | 2 ++ src/nsgenbind-parser.y | 54 ++++++++++++++++++++++++++++++++-- 7 files changed, 171 insertions(+), 45 deletions(-) diff --git a/doc/example.bnd b/doc/example.bnd index 6003f0d..7caebf0 100644 --- a/doc/example.bnd +++ b/doc/example.bnd @@ -63,7 +63,24 @@ epilogue %{ */ binding jsapi_libdom { - interface Navigator; /* The WebIDL interface to generate a binding for */ + + /* Interface with specified flags + * + * global - the generated interface will be a global object + * jsapi_constructor - a c function will be generated to + * instansiate the interface (class) + * js_constructor - the interface (class) can be instnsiated from + * javascript + * + */ + interface Example { + flags global, jsapi_constructor, js_constructor; + } + + /* The WebIDL interface to generate a binding for. With no flags + * the default of jsapi_constructor is used + */ + interface Navigator; /* private members: * - stored in private context structure. @@ -246,14 +263,7 @@ api finalise %{ * By default returns JS_TRUE implying that *objp has been updated * * The minimal implementation would be "*objp = NULL;" but is - * equivalent to simply omitting this directive and using the defaul stub. + * equivalent to simply omitting this directive and using the default stub. */ api resolve %{ %} - -/* mark the generated interface as a a global object - * - * The body is discarded. - */ -api global %{ -%} diff --git a/src/jsapi-libdom-property.c b/src/jsapi-libdom-property.c index 2bd3068..091b2c6 100644 --- a/src/jsapi-libdom-property.c +++ b/src/jsapi-libdom-property.c @@ -229,6 +229,7 @@ get_binding_shared_modifier(struct binding *binding, const char *type, const cha { struct genbind_node *shared_node; struct genbind_node *shared_mod_node; + enum genbind_type_modifier *shared_modifier; /* look for node matching the ident first */ shared_node = genbind_node_find_type_ident(binding->binding_list, @@ -251,9 +252,11 @@ get_binding_shared_modifier(struct binding *binding, const char *type, const cha shared_mod_node = genbind_node_find_type(genbind_node_getnode(shared_node), NULL, GENBIND_NODE_TYPE_MODIFIER); - if (shared_mod_node != NULL) { - return genbind_node_getint(shared_mod_node); + shared_modifier = (enum genbind_type_modifier *)genbind_node_getint(shared_mod_node); + if (shared_modifier != NULL) { + return *shared_modifier; } + } return GENBIND_TYPE_NONE; } @@ -1108,14 +1111,16 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx) struct genbind_node *ident_node; const char *type; struct genbind_node *mod_node; - enum genbind_type_modifier share_mod; + enum genbind_type_modifier *share_mod; int ret = 0; mod_node = genbind_node_find_type(genbind_node_getnode(node), NULL, GENBIND_NODE_TYPE_MODIFIER); - share_mod = genbind_node_getint(mod_node); - if ((share_mod & GENBIND_TYPE_TYPE) == GENBIND_TYPE_TYPE) { + share_mod = (enum genbind_type_modifier *)genbind_node_getint(mod_node); + + if ((share_mod != NULL) && + ((*share_mod & GENBIND_TYPE_TYPE) == GENBIND_TYPE_TYPE)) { /* type handler */ ident_node = genbind_node_find_type(genbind_node_getnode(node), diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 97a6193..2389a57 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -211,6 +211,10 @@ output_epilogue(struct binding *binding) static int output_prologue(struct binding *binding) { + /* forward declare property list */ + fprintf(binding->outfile, + "static JSPropertySpec jsclass_properties[];\n\n"); + genbind_node_for_each_type(binding->gb_ast, GENBIND_NODE_TYPE_PROLOGUE, webidl_prologue_cb, @@ -728,7 +732,7 @@ output_class_new(struct binding *binding) } static int -output_jsclass(struct binding *binding) +output_forward_declarations(struct binding *binding) { /* forward declare add property */ if (binding->addproperty != NULL) { @@ -778,10 +782,12 @@ output_jsclass(struct binding *binding) "static void jsclass_finalize(JSContext *cx, JSObject *obj);\n\n"); } - /* forward declare property list */ - fprintf(binding->outfile, - "static JSPropertySpec jsclass_properties[];\n\n"); + return 0; +} +static int +output_jsclass(struct binding *binding) +{ /* output the class declaration */ HDROUTF(binding, "JSClass JSClass_%s;\n", binding->interface); @@ -860,31 +866,36 @@ output_jsclass(struct binding *binding) /* resolver */ if (binding->resolve != NULL) { - fprintf(binding->outfile, "\t(JSResolveOp)jsclass_resolve,\n"); + fprintf(binding->outfile, + "\t(JSResolveOp)jsclass_resolve,\t/* resolve */\n"); } else { - fprintf(binding->outfile, "\tJS_ResolveStub,\n"); + fprintf(binding->outfile, + "\tJS_ResolveStub,\t\t/* resolve */\n"); } - fprintf(binding->outfile, "\tJS_ConvertStub,\t/* convert */\n"); + fprintf(binding->outfile, "\tJS_ConvertStub,\t\t/* convert */\n"); if (binding->has_private || (binding->finalise != NULL)) { - fprintf(binding->outfile, "\tjsclass_finalize,\n"); + fprintf(binding->outfile, + "\tjsclass_finalize,\t/* finalizer */\n"); } else { - fprintf(binding->outfile, "\tJS_FinalizeStub,\n"); + fprintf(binding->outfile, + "\tJS_FinalizeStub,\t/* finalizer */\n"); } fprintf(binding->outfile, - "\t0,\t/* reserved */\n" - "\tNULL,\t/* checkAccess */\n" - "\tNULL,\t/* call */\n" - "\tNULL,\t/* construct */\n" - "\tNULL,\t/* xdr Object */\n" - "\tNULL,\t/* hasInstance */\n"); + "\t0,\t\t\t/* reserved */\n" + "\tNULL,\t\t\t/* checkAccess */\n" + "\tNULL,\t\t\t/* call */\n" + "\tNULL,\t\t\t/* construct */\n" + "\tNULL,\t\t\t/* xdr Object */\n" + "\tNULL,\t\t\t/* hasInstance */\n"); /* trace/mark */ if (binding->mark != NULL) { - fprintf(binding->outfile, "\tJSAPI_JSCLASS_MARKOP(jsclass_mark),\n"); + fprintf(binding->outfile, + "\tJSAPI_JSCLASS_MARKOP(jsclass_mark),\n"); } else { - fprintf(binding->outfile, "\tNULL, /* trace/mark */\n"); + fprintf(binding->outfile, "\tNULL,\t\t\t/* trace/mark */\n"); } fprintf(binding->outfile, @@ -1011,6 +1022,7 @@ binding_has_private(struct genbind_node *binding_list) return false; } +/* determine if the binding has a global api marker */ static bool binding_has_global(struct binding *binding) { @@ -1034,6 +1046,7 @@ binding_new(struct options *options, struct binding *nb; struct genbind_node *interface_node; struct genbind_node *binding_list; + struct genbind_node *binding_ident; char *hdrguard = NULL; struct webidl_node *webidl_ast = NULL; int res; @@ -1043,6 +1056,7 @@ binding_new(struct options *options, return NULL; } + /* find the first interface node - there must be at least one */ interface_node = genbind_node_find_type(binding_list, NULL, GENBIND_NODE_TYPE_BINDING_INTERFACE); @@ -1050,7 +1064,18 @@ binding_new(struct options *options, return NULL; } - /* walk ast and load any web IDL files required */ + /* get the binding identifier */ + /* @todo it should be possible to specify this as part of the + * binding instead of just using the first interface + */ + binding_ident = genbind_node_find_type(genbind_node_getnode(interface_node), + NULL, + GENBIND_NODE_TYPE_IDENT); + if (binding_ident == NULL) { + return NULL; + } + + /* walk AST and load any web IDL files required */ res = read_webidl(genbind_ast, &webidl_ast); if (res != 0) { fprintf(stderr, "Error reading Web IDL files\n"); @@ -1077,7 +1102,8 @@ binding_new(struct options *options, nb->gb_ast = genbind_ast; nb->wi_ast = webidl_ast; - nb->interface = genbind_node_gettext(interface_node); + /* @todo binding name should not be called interface */ + nb->interface = genbind_node_gettext(binding_ident); nb->outfile = options->outfilehandle; nb->srcfile = options->outfilehandle; nb->hdrfile = options->hdrfilehandle; @@ -1160,6 +1186,11 @@ jsapi_libdom_output(struct options *options, return 70; } + res = output_forward_declarations(binding); + if (res) { + return 75; + } + res = output_jsclass(binding); if (res) { return 80; @@ -1170,7 +1201,7 @@ jsapi_libdom_output(struct options *options, return 85; } - /* user code outout just before function bodies emitted */ + /* user code output just before function bodies emitted */ res = output_prologue(binding); if (res) { return 89; diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index 851cbeb..d20975f 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -211,7 +211,6 @@ char *genbind_node_gettext(struct genbind_node *node) case GENBIND_NODE_TYPE_EPILOGUE: case GENBIND_NODE_TYPE_IDENT: case GENBIND_NODE_TYPE_TYPE: - case GENBIND_NODE_TYPE_BINDING_INTERFACE: case GENBIND_NODE_TYPE_CBLOCK: return node->r.text; @@ -231,6 +230,8 @@ struct genbind_node *genbind_node_getnode(struct genbind_node *node) case GENBIND_NODE_TYPE_BINDING_PRIVATE: case GENBIND_NODE_TYPE_BINDING_INTERNAL: case GENBIND_NODE_TYPE_BINDING_PROPERTY: + case GENBIND_NODE_TYPE_BINDING_INTERFACE: + case GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS: case GENBIND_NODE_TYPE_OPERATION: case GENBIND_NODE_TYPE_API: case GENBIND_NODE_TYPE_GETTER: @@ -245,19 +246,18 @@ struct genbind_node *genbind_node_getnode(struct genbind_node *node) } -int genbind_node_getint(struct genbind_node *node) +int *genbind_node_getint(struct genbind_node *node) { if (node != NULL) { switch(node->type) { case GENBIND_NODE_TYPE_MODIFIER: - return node->r.number; + return &node->r.number; default: break; } } - return -1; - + return NULL; } static const char *genbind_node_type_to_str(enum genbind_node_type type) @@ -296,6 +296,9 @@ static const char *genbind_node_type_to_str(enum genbind_node_type type) case GENBIND_NODE_TYPE_BINDING_INTERFACE: return "Interface"; + case GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS: + return "Flags"; + case GENBIND_NODE_TYPE_BINDING_PROPERTY: return "Property"; diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index 6513f7f..d59aeba 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -26,6 +26,7 @@ enum genbind_node_type { GENBIND_NODE_TYPE_BINDING_PRIVATE, GENBIND_NODE_TYPE_BINDING_INTERNAL, GENBIND_NODE_TYPE_BINDING_INTERFACE, + GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, GENBIND_NODE_TYPE_BINDING_PROPERTY, GENBIND_NODE_TYPE_API, GENBIND_NODE_TYPE_OPERATION, @@ -41,6 +42,11 @@ enum genbind_type_modifier { GENBIND_TYPE_TYPE_UNSHARED = 3, /**< identifies a unshared type handler */ }; +/* interface flags */ +enum genbind_interface_flags { + GENBIND_INTERFACE_FLAG_NONE = 0, + GENBIND_INTERFACE_FLAG_GLOBAL = 1, /**< interface is global */ +}; struct genbind_node; @@ -111,8 +117,8 @@ genbind_node_find_type_ident(struct genbind_node *node, * @param prev The node at which to stop the search, either NULL to * search the full tree depth (initial search) or the result * of a previous search to continue. - * @param nodetype The type of node to seach for - * @param type The text to match the type child node to + * @param nodetype The type of node to seach for. + * @param type The text to match the type child node to. */ struct genbind_node * genbind_node_find_type_type(struct genbind_node *node, @@ -122,9 +128,28 @@ genbind_node_find_type_type(struct genbind_node *node, int genbind_node_for_each_type(struct genbind_node *node, enum genbind_node_type type, genbind_callback_t *cb, void *ctx); -char *genbind_node_gettext(struct genbind_node *node); +/** get a nodes node list content + * + * @param node The nodes to get node list from + * @return pointer to the node list or NULL if the node does not contain a list + */ struct genbind_node *genbind_node_getnode(struct genbind_node *node); -int genbind_node_getint(struct genbind_node *node); + +/** get a nodes text content + * + * @param node The nodes to get text from + * @return pointer to the node text or NULL if the node is not of type + * text or is empty. + */ +char *genbind_node_gettext(struct genbind_node *node); + +/** get a nodes integer value + * + * @param node The nodes to get integer from + * @return pointer to the node value or NULL if the node is not of type + * int or is empty. + */ +int *genbind_node_getint(struct genbind_node *node); #ifdef _WIN32 #define NEED_STRNDUP 1 diff --git a/src/nsgenbind-lexer.l b/src/nsgenbind-lexer.l index 8189a72..4b5e225 100644 --- a/src/nsgenbind-lexer.l +++ b/src/nsgenbind-lexer.l @@ -104,6 +104,8 @@ binding return TOK_BINDING; interface return TOK_INTERFACE; +flags return TOK_FLAGS; + type return TOK_TYPE; private return TOK_PRIVATE; diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index b9ec23b..b37ab9d 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -54,6 +54,7 @@ char *errtxt; %token TOK_GETTER %token TOK_SETTER %token TOK_INTERFACE +%token TOK_FLAGS %token TOK_TYPE %token TOK_PRIVATE %token TOK_INTERNAL @@ -84,6 +85,9 @@ char *errtxt; %type Private %type Internal %type Interface +%type InterfaceArgs +%type InterfaceArg +%type InterfaceFlags %type Property %type Operation %type Api @@ -91,6 +95,7 @@ char *errtxt; %type Setter + %% Input @@ -260,7 +265,7 @@ Setter Binding : - TOK_BINDING TOK_IDENTIFIER '{' BindingArgs '}' + TOK_BINDING TOK_IDENTIFIER '{' BindingArgs '}' { $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING, NULL, @@ -313,7 +318,52 @@ Interface : TOK_INTERFACE TOK_IDENTIFIER ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, NULL, $2); + $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $2)); + } + | + TOK_INTERFACE TOK_IDENTIFIER '{' '}' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $2)); + } + | + TOK_INTERFACE TOK_IDENTIFIER '{' InterfaceArgs '}' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, + NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, $4, $2)); + } + ; + +InterfaceArgs + : + InterfaceArg + | + InterfaceArgs InterfaceArg + { + $$ = genbind_node_link($2, $1); + } + ; + +InterfaceArg + : + TOK_FLAGS InterfaceFlags ';' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, NULL, $2); + } + ; + +InterfaceFlags + : + TOK_IDENTIFIER + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $1); + } + | + InterfaceFlags ',' TOK_IDENTIFIER + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, $1, $3); } ; -- cgit v1.2.3 From c25cc0e348a1abf0ee0719cf30515b3cc07f1848 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 21 Dec 2013 22:29:42 +0000 Subject: move flag indicating jsapi object for an interface should be a global from api definition to the interface flags --- src/jsapi-libdom-property.c | 26 ++++++------ src/jsapi-libdom.c | 94 ++++++++++++++++++++++++++----------------- src/jsapi-libdom.h | 1 - src/nsgenbind-ast.c | 30 +++++++++----- src/nsgenbind-ast.h | 42 +++++++++++-------- src/nsgenbind.c | 8 ++-- test/data/bindings/window.bnd | 6 +-- 7 files changed, 124 insertions(+), 83 deletions(-) diff --git a/src/jsapi-libdom-property.c b/src/jsapi-libdom-property.c index 091b2c6..7e67bae 100644 --- a/src/jsapi-libdom-property.c +++ b/src/jsapi-libdom-property.c @@ -108,7 +108,7 @@ output_property_tinyid_get(struct binding *binding, const char *argname) /******************************** tinyid ********************************/ -static int +static int webidl_property_tinyid_cb(struct webidl_node *node, void *ctx) { struct binding *binding = ctx; @@ -132,7 +132,7 @@ webidl_property_tinyid_cb(struct webidl_node *node, void *ctx) } /* callback to emit implements property spec */ -static int +static int webidl_property_tinyid_implements_cb(struct webidl_node *node, void *ctx) { struct binding *binding = ctx; @@ -211,7 +211,7 @@ output_property_tinyid(struct binding *binding) res = generate_property_tinyid(binding, binding->interface); - fprintf(binding->outfile, + fprintf(binding->outfile, "\tJSAPI_PROP_TINYID_END,\n" "};\n\n"); @@ -386,21 +386,21 @@ static int webidl_property_spec_cb(struct webidl_node *node, void *ctx) * js doesnt provide storage and setter/getter must * perform all GC management. */ - fprintf(binding->outfile, + fprintf(binding->outfile, "\t\t%s,\n" "\t\tJSAPI_PROP_TINYID_%s,\n" - "\t\tJSPROP_SHARED | ", - ident, + "\t\tJSPROP_SHARED | ", + ident, ident); break; case GENBIND_TYPE_TYPE: /* shared property with a type handler */ - fprintf(binding->outfile, + fprintf(binding->outfile, "\t\t%s,\n" "\t\tJSAPI_PROP_TINYID_%s,\n" - "\t\tJSPROP_SHARED | ", - type, + "\t\tJSPROP_SHARED | ", + type, ident); break; @@ -1028,9 +1028,9 @@ generate_property_body(struct binding *binding, const char *interface) /* setter for type handler */ -static int -output_property_type_setter(struct binding *binding, - struct genbind_node *node, +static int +output_property_type_setter(struct binding *binding, + struct genbind_node *node, const char *type) { struct genbind_node *property_node; @@ -1149,7 +1149,7 @@ output_property_body(struct binding *binding) res = generate_property_body(binding, binding->interface); if (res == 0) { - res = genbind_node_for_each_type(binding->binding_list, + res = genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_PROPERTY, typehandler_property_cb, binding); diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 2389a57..f0dc5a3 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -47,7 +47,7 @@ read_webidl(struct genbind_node *genbind_ast, struct webidl_node **webidl_ast) { int res; - res = genbind_node_for_each_type(genbind_ast, + res = genbind_node_foreach_type(genbind_ast, GENBIND_NODE_TYPE_WEBIDLFILE, webidl_file_cb, webidl_ast); @@ -101,7 +101,7 @@ static int webidl_hdrcomments_cb(struct genbind_node *node, void *ctx) static int webidl_hdrcomment_cb(struct genbind_node *node, void *ctx) { - genbind_node_for_each_type(genbind_node_getnode(node), + genbind_node_foreach_type(genbind_node_getnode(node), GENBIND_NODE_TYPE_STRING, webidl_hdrcomments_cb, ctx); @@ -187,7 +187,7 @@ static int webidl_private_assign_cb(struct genbind_node *node, void *ctx) static int output_epilogue(struct binding *binding) { - genbind_node_for_each_type(binding->gb_ast, + genbind_node_foreach_type(binding->gb_ast, GENBIND_NODE_TYPE_EPILOGUE, webidl_epilogue_cb, binding); @@ -215,7 +215,7 @@ output_prologue(struct binding *binding) fprintf(binding->outfile, "static JSPropertySpec jsclass_properties[];\n\n"); - genbind_node_for_each_type(binding->gb_ast, + genbind_node_foreach_type(binding->gb_ast, GENBIND_NODE_TYPE_PROLOGUE, webidl_prologue_cb, binding); @@ -604,7 +604,7 @@ output_class_new(struct binding *binding) "\t\tJSObject *parent", binding->interface); - genbind_node_for_each_type(binding->binding_list, + genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_PRIVATE, webidl_private_param_cb, binding); @@ -621,7 +621,7 @@ output_class_new(struct binding *binding) "\t\tJSObject *parent", binding->interface); - genbind_node_for_each_type(binding->binding_list, + genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_PRIVATE, webidl_private_param_cb, binding); @@ -641,7 +641,7 @@ output_class_new(struct binding *binding) "\t\treturn NULL;\n" "\t}\n"); - genbind_node_for_each_type(binding->binding_list, + genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_PRIVATE, webidl_private_assign_cb, binding); @@ -785,21 +785,48 @@ output_forward_declarations(struct binding *binding) return 0; } -static int -output_jsclass(struct binding *binding) +static bool interface_is_global(struct genbind_node *interface_node) { + if (genbind_node_find_type_ident( + genbind_node_getnode(interface_node), + NULL, + GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, + "global") != NULL) { + return true; + } + + return false; +} + +static int output_jsclass(struct genbind_node *interface_node, void *ctx) +{ + struct binding *binding = ctx; + struct genbind_node *interface_list; + const char *interface_ident; + + interface_list = genbind_node_getnode(interface_node); + if (interface_list == NULL) + return -1; /* bad AST */ + + interface_ident = genbind_node_gettext( + genbind_node_find_type(interface_list, + NULL, + GENBIND_NODE_TYPE_IDENT)); + if (interface_ident == NULL) + return -1; /* bad AST */ + /* output the class declaration */ - HDROUTF(binding, "JSClass JSClass_%s;\n", binding->interface); + HDROUTF(binding, "JSClass JSClass_%s;\n", interface_ident); /* output the class definition */ fprintf(binding->outfile, "JSClass JSClass_%s = {\n" "\t\"%s\",\n", - binding->interface, - binding->interface); + interface_ident, + interface_ident); /* generate class flags */ - if (binding->has_global) { + if (interface_is_global(interface_node)) { fprintf(binding->outfile, "\tJSCLASS_GLOBAL_FLAGS"); } else { fprintf(binding->outfile, "\t0"); @@ -901,9 +928,21 @@ output_jsclass(struct binding *binding) fprintf(binding->outfile, "\tJSAPI_CLASS_NO_INTERNAL_MEMBERS\n" "};\n\n"); + return 0; } +static int +output_jsclasses(struct binding *binding) +{ + + return genbind_node_foreach_type(binding->binding_list, + GENBIND_NODE_TYPE_BINDING_INTERFACE, + output_jsclass, + binding); + +} + /** generate structure definition for internal class data * * Every javascript object instance has an internal context to keep @@ -927,12 +966,12 @@ output_private_declaration(struct binding *binding) fprintf(binding->outfile, "struct jsclass_private {\n"); - genbind_node_for_each_type(binding->binding_list, + genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_PRIVATE, webidl_private_cb, binding); - genbind_node_for_each_type(binding->binding_list, + genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_INTERNAL, webidl_private_cb, binding); @@ -946,7 +985,7 @@ output_private_declaration(struct binding *binding) static int output_preamble(struct binding *binding) { - genbind_node_for_each_type(binding->gb_ast, + genbind_node_foreach_type(binding->gb_ast, GENBIND_NODE_TYPE_PREAMBLE, webidl_preamble_cb, binding); @@ -976,7 +1015,7 @@ output_header_comments(struct binding *binding) const char *preamble = HDR_COMMENT_PREAMBLE; fprintf(binding->outfile, preamble, options->infilename); - genbind_node_for_each_type(binding->gb_ast, + genbind_node_foreach_type(binding->gb_ast, GENBIND_NODE_TYPE_HDRCOMMENT, webidl_hdrcomment_cb, binding); @@ -988,7 +1027,7 @@ output_header_comments(struct binding *binding) fprintf(binding->outfile, preamble, options->infilename); - genbind_node_for_each_type(binding->gb_ast, + genbind_node_foreach_type(binding->gb_ast, GENBIND_NODE_TYPE_HDRCOMMENT, webidl_hdrcomment_cb, binding); @@ -1022,22 +1061,6 @@ binding_has_private(struct genbind_node *binding_list) return false; } -/* determine if the binding has a global api marker */ -static bool -binding_has_global(struct binding *binding) -{ - struct genbind_node *api_node; - - api_node = genbind_node_find_type_ident(binding->gb_ast, - NULL, - GENBIND_NODE_TYPE_API, - "global"); - if (api_node != NULL) { - return true; - } - return false; -} - static struct binding * binding_new(struct options *options, struct genbind_node *genbind_ast, @@ -1109,7 +1132,6 @@ binding_new(struct options *options, nb->hdrfile = options->hdrfilehandle; nb->hdrguard = hdrguard; nb->has_private = binding_has_private(binding_list); - nb->has_global = binding_has_global(nb); nb->binding_list = binding_list; /* class API */ @@ -1191,7 +1213,7 @@ jsapi_libdom_output(struct options *options, return 75; } - res = output_jsclass(binding); + res = output_jsclasses(binding); if (res) { return 80; } diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index 5a93ff1..b83eeb0 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -18,7 +18,6 @@ struct binding { const char *interface; /* webidl interface binding is for */ bool has_private; /* true if the binding requires a private structure */ - bool has_global; /* true if the binding is for a global */ struct genbind_node *binding_list; /* node list of the binding */ struct genbind_node *addproperty; /* binding api add property node or NULL */ diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index d20975f..fc1e196 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -49,7 +49,8 @@ char *genbind_strapp(char *a, char *b) return fullstr; } -struct genbind_node *genbind_node_link(struct genbind_node *tgt, struct genbind_node *src) +struct genbind_node * +genbind_node_link(struct genbind_node *tgt, struct genbind_node *src) { tgt->l = src; return tgt; @@ -68,7 +69,7 @@ genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r) } int -genbind_node_for_each_type(struct genbind_node *node, +genbind_node_foreach_type(struct genbind_node *node, enum genbind_node_type type, genbind_callback_t *cb, void *ctx) @@ -79,7 +80,7 @@ genbind_node_for_each_type(struct genbind_node *node, return -1; } if (node->l != NULL) { - ret = genbind_node_for_each_type(node->l, type, cb, ctx); + ret = genbind_node_foreach_type(node->l, type, cb, ctx); if (ret != 0) { return ret; } @@ -147,17 +148,26 @@ genbind_node_find_type_ident(struct genbind_node *node, found_node = genbind_node_find_type(node, prev, type); - while (found_node != NULL) { /* look for an ident node */ - ident_node = genbind_node_find_type(genbind_node_getnode(found_node), - NULL, - GENBIND_NODE_TYPE_IDENT); - if (ident_node != NULL) { - if (strcmp(ident_node->r.text, ident) == 0) - break; + ident_node = genbind_node_find_type( + genbind_node_getnode(found_node), + NULL, + GENBIND_NODE_TYPE_IDENT); + + while (ident_node != NULL) { + /* check for matching text */ + if (strcmp(ident_node->r.text, ident) == 0) { + return found_node; + } + + ident_node = genbind_node_find_type( + genbind_node_getnode(found_node), + ident_node, + GENBIND_NODE_TYPE_IDENT); } + /* look for next matching node */ found_node = genbind_node_find_type(node, found_node, type); } diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index d59aeba..128dce7 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -1,4 +1,4 @@ -/* binding file AST interface +/* binding file AST interface * * This file is part of nsnsgenbind. * Licensed under the MIT License, @@ -42,12 +42,6 @@ enum genbind_type_modifier { GENBIND_TYPE_TYPE_UNSHARED = 3, /**< identifies a unshared type handler */ }; -/* interface flags */ -enum genbind_interface_flags { - GENBIND_INTERFACE_FLAG_NONE = 0, - GENBIND_INTERFACE_FLAG_GLOBAL = 1, /**< interface is global */ -}; - struct genbind_node; /** callback for search and iteration routines */ @@ -66,11 +60,11 @@ struct genbind_node *genbind_node_link(struct genbind_node *tgt, struct genbind_ int genbind_ast_dump(struct genbind_node *ast, int indent); -/** Depth first left hand search using user provided comparison +/** Depth first left hand search using user provided comparison * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to - * search the full tree depth (initial search) or the result + * search the full tree depth (initial search) or the result * of a previous search to continue. * @param cb Comparison callback * @param ctx Context for callback @@ -85,7 +79,7 @@ genbind_node_find(struct genbind_node *node, * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to - * search the full tree depth (initial search) or the result + * search the full tree depth (initial search) or the result * of a previous search to continue. * @param nodetype The type of node to seach for */ @@ -99,7 +93,7 @@ genbind_node_find_type(struct genbind_node *node, * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to - * search the full tree depth (initial search) or the result + * search the full tree depth (initial search) or the result * of a previous search to continue. * @param nodetype The type of node to seach for * @param ident The text to match the ident child node to @@ -110,12 +104,18 @@ genbind_node_find_type_ident(struct genbind_node *node, enum genbind_node_type nodetype, const char *ident); -/** Depth first left hand search returning nodes of the specified type - * and a type child node with matching text +/** Returning node of the specified type with a GENBIND_NODE_TYPE_TYPE + * subnode with matching text. + * + * This is a conveniance wrapper around nested calls to + * genbind_node_find_type() which performs a depth first left hand + * search returning nodes of the specified type and a child node of + * GENBIND_NODE_TYPE_TYPE with matching text. + * * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to - * search the full tree depth (initial search) or the result + * search the full tree depth (initial search) or the result * of a previous search to continue. * @param nodetype The type of node to seach for. * @param type The text to match the type child node to. @@ -124,9 +124,19 @@ struct genbind_node * genbind_node_find_type_type(struct genbind_node *node, struct genbind_node *prev, enum genbind_node_type nodetype, - const char *type); + const char *type_text); -int genbind_node_for_each_type(struct genbind_node *node, enum genbind_node_type type, genbind_callback_t *cb, void *ctx); +/** Iterate all nodes of a certian type from a node with a callback. + * + * Depth first search for nodes of the given type calling the callback + * with context. + * + * @param node The node to start the search from. + */ +int genbind_node_foreach_type(struct genbind_node *node, + enum genbind_node_type type, + genbind_callback_t *cb, + void *ctx); /** get a nodes node list content * diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 636c22b..d81f30f 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -202,10 +202,10 @@ int main(int argc, char **argv) } /* generate output for each binding */ - res = genbind_node_for_each_type(genbind_root, - GENBIND_NODE_TYPE_BINDING, - generate_binding, - genbind_root); + res = genbind_node_foreach_type(genbind_root, + GENBIND_NODE_TYPE_BINDING, + generate_binding, + genbind_root); if (res != 0) { fprintf(stderr, "Error: output failed with code %d\n", res); if (options->outfilename != NULL) { diff --git a/test/data/bindings/window.bnd b/test/data/bindings/window.bnd index 2f26f56..4fb5a46 100644 --- a/test/data/bindings/window.bnd +++ b/test/data/bindings/window.bnd @@ -29,7 +29,9 @@ epilogue %{ binding jsapi_libdom { - interface Window; /* Web IDL interface to generate */ + interface Window { + flags global; + } private "struct browser_window *" bw; private "struct html_content *" htmlc; @@ -62,8 +64,6 @@ api mark %{ } %} -api global %{ -%} api init %{ JSObject *user_proto; -- cgit v1.2.3 From 0c9803cf78453a19ec37fbc2b3fdba3c106cfd84 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 29 Dec 2013 15:25:39 +0000 Subject: construct topoligicaly consitant (dependancy correct) interface map use dependancy map to generate javascript prototype for all interfaces in the binding. --- src/Makefile | 2 +- src/jsapi-libdom-const.c | 195 --------------------------- src/jsapi-libdom-init.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++ src/jsapi-libdom.c | 240 +++++++++++++++++++++------------ src/jsapi-libdom.h | 26 ++-- src/nsgenbind-ast.c | 21 +++ src/nsgenbind-ast.h | 15 +++ 7 files changed, 553 insertions(+), 288 deletions(-) delete mode 100644 src/jsapi-libdom-const.c create mode 100644 src/jsapi-libdom-init.c diff --git a/src/Makefile b/src/Makefile index 972beb9..8bad59a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-operator.c jsapi-libdom-property.c jsapi-libdom-const.c +DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-operator.c jsapi-libdom-property.c jsapi-libdom-init.c SOURCES := $(SOURCES) $(BUILDDIR)/nsgenbind-parser.c $(BUILDDIR)/nsgenbind-lexer.c $(BUILDDIR)/webidl-parser.c $(BUILDDIR)/webidl-lexer.c diff --git a/src/jsapi-libdom-const.c b/src/jsapi-libdom-const.c deleted file mode 100644 index ac728c7..0000000 --- a/src/jsapi-libdom-const.c +++ /dev/null @@ -1,195 +0,0 @@ -/* const property generation - * - * This file is part of nsgenbind. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2012 Vincent Sanders - */ - -#include -#include -#include -#include -#include - -#include "options.h" -#include "nsgenbind-ast.h" -#include "webidl-ast.h" -#include "jsapi-libdom.h" - -static int output_cast_literal(struct binding *binding, - struct webidl_node *node) -{ - struct webidl_node *type_node = NULL; - struct webidl_node *literal_node = NULL; - struct webidl_node *type_base = NULL; - enum webidl_type webidl_arg_type; - - type_node = webidl_node_find_type(webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_TYPE); - - type_base = webidl_node_find_type(webidl_node_getnode(type_node), - NULL, - WEBIDL_NODE_TYPE_TYPE_BASE); - - webidl_arg_type = webidl_node_getint(type_base); - - switch (webidl_arg_type) { - - case WEBIDL_TYPE_BOOL: - /* JSBool */ - literal_node = webidl_node_find_type(webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_LITERAL_BOOL); - fprintf(binding->outfile, "BOOLEAN_TO_JSVAL(JS_FALSE)"); - break; - - case WEBIDL_TYPE_FLOAT: - case WEBIDL_TYPE_DOUBLE: - /* double */ - literal_node = webidl_node_find_type(webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_LITERAL_FLOAT); - fprintf(binding->outfile, "DOUBLE_TO_JSVAL(0.0)"); - break; - - case WEBIDL_TYPE_LONG: - /* int32_t */ - literal_node = webidl_node_find_type(webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_LITERAL_INT); - fprintf(binding->outfile, - "INT_TO_JSVAL(%d)", - webidl_node_getint(literal_node)); - break; - - case WEBIDL_TYPE_SHORT: - /* int16_t */ - literal_node = webidl_node_find_type(webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_LITERAL_INT); - fprintf(binding->outfile, - "INT_TO_JSVAL(%d)", - webidl_node_getint(literal_node)); - break; - - - case WEBIDL_TYPE_STRING: - case WEBIDL_TYPE_BYTE: - case WEBIDL_TYPE_OCTET: - case WEBIDL_TYPE_LONGLONG: - case WEBIDL_TYPE_SEQUENCE: - case WEBIDL_TYPE_OBJECT: - case WEBIDL_TYPE_DATE: - case WEBIDL_TYPE_VOID: - case WEBIDL_TYPE_USER: - default: - WARN(WARNING_UNIMPLEMENTED, "types not allowed as literal"); - break; /* @todo these types are not allowed here */ - } - - return 0; -} - -static int webidl_const_define_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - struct webidl_node *ident_node; - - ident_node = webidl_node_find_type(webidl_node_getnode(node), - NULL, - WEBIDL_NODE_TYPE_IDENT); - if (ident_node == NULL) { - /* Broken AST - must have ident */ - return 1; - } - - fprintf(binding->outfile, - "\tJS_DefineProperty(cx,\n" - "\t\tprototype,\n" - "\t\t\"%s\",\n" - "\t\t", - webidl_node_gettext(ident_node)); - - output_cast_literal(binding, node); - - fprintf(binding->outfile, - ",\n" - "\t\tJS_PropertyStub,\n" - "\t\tJS_StrictPropertyStub,\n" - "\t\tJSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);\n\n"); - - return 0; - -} - - -/* callback to emit implements property spec */ -static int webidl_const_spec_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return output_const_defines(binding, webidl_node_gettext(node)); -} - -int -output_const_defines(struct binding *binding, const char *interface) -{ - struct webidl_node *interface_node; - struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } - - /* generate property entries for each list (partial interfaces) */ - members_node = webidl_node_find_type(webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); - - while (members_node != NULL) { - fprintf(binding->outfile,"\t/**** %s ****/\n", interface); - - /* for each const emit a property define */ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_CONST, - webidl_const_define_cb, - binding); - - - members_node = webidl_node_find_type(webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); - } - - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); - - if (inherit_node != NULL) { - res = output_const_defines(binding, - webidl_node_gettext(inherit_node)); - } - - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_const_spec_implements_cb, - binding); - } - - return res; -} diff --git a/src/jsapi-libdom-init.c b/src/jsapi-libdom-init.c new file mode 100644 index 0000000..1f6b80d --- /dev/null +++ b/src/jsapi-libdom-init.c @@ -0,0 +1,342 @@ +/* const property generation + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2012 Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "jsapi-libdom.h" + +static int output_const_defines(struct binding *binding, const char *interface); + +static int output_cast_literal(struct binding *binding, + struct webidl_node *node) +{ + struct webidl_node *type_node = NULL; + struct webidl_node *literal_node = NULL; + struct webidl_node *type_base = NULL; + enum webidl_type webidl_arg_type; + + type_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + type_base = webidl_node_find_type(webidl_node_getnode(type_node), + NULL, + WEBIDL_NODE_TYPE_TYPE_BASE); + + webidl_arg_type = webidl_node_getint(type_base); + + switch (webidl_arg_type) { + + case WEBIDL_TYPE_BOOL: + /* JSBool */ + literal_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_LITERAL_BOOL); + fprintf(binding->outfile, "BOOLEAN_TO_JSVAL(JS_FALSE)"); + break; + + case WEBIDL_TYPE_FLOAT: + case WEBIDL_TYPE_DOUBLE: + /* double */ + literal_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_LITERAL_FLOAT); + fprintf(binding->outfile, "DOUBLE_TO_JSVAL(0.0)"); + break; + + case WEBIDL_TYPE_LONG: + /* int32_t */ + literal_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_LITERAL_INT); + fprintf(binding->outfile, + "INT_TO_JSVAL(%d)", + webidl_node_getint(literal_node)); + break; + + case WEBIDL_TYPE_SHORT: + /* int16_t */ + literal_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_LITERAL_INT); + fprintf(binding->outfile, + "INT_TO_JSVAL(%d)", + webidl_node_getint(literal_node)); + break; + + + case WEBIDL_TYPE_STRING: + case WEBIDL_TYPE_BYTE: + case WEBIDL_TYPE_OCTET: + case WEBIDL_TYPE_LONGLONG: + case WEBIDL_TYPE_SEQUENCE: + case WEBIDL_TYPE_OBJECT: + case WEBIDL_TYPE_DATE: + case WEBIDL_TYPE_VOID: + case WEBIDL_TYPE_USER: + default: + WARN(WARNING_UNIMPLEMENTED, "types not allowed as literal"); + break; /* @todo these types are not allowed here */ + } + + return 0; +} + +static int webidl_const_define_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + struct webidl_node *ident_node; + + ident_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_IDENT); + if (ident_node == NULL) { + /* Broken AST - must have ident */ + return 1; + } + + fprintf(binding->outfile, + "\tJS_DefineProperty(cx, " + "prototype, " + "\"%s\", ", + webidl_node_gettext(ident_node)); + + output_cast_literal(binding, node); + + fprintf(binding->outfile, + ", " + "JS_PropertyStub, " + "JS_StrictPropertyStub, " + "JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);\n\n"); + + return 0; + +} + + +/** output all the constant property defines for an interface */ +static int +output_interface_consts(struct binding *binding, + struct webidl_node *interface_node) +{ + struct webidl_node *members_node; + + /* generate property entries for each list (partial interfaces) */ + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (members_node != NULL) { + + /* for each const emit a property define */ + webidl_node_for_each_type(webidl_node_getnode(members_node), + WEBIDL_NODE_TYPE_CONST, + webidl_const_define_cb, + binding); + + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + members_node, + WEBIDL_NODE_TYPE_LIST); + } + + return 0; +} + +/* callback to emit implements property spec */ +static int webidl_const_spec_implements_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + + return output_const_defines(binding, webidl_node_gettext(node)); +} + +/** generate property definitions for constants */ +static int +output_const_defines(struct binding *binding, const char *interface) +{ + struct webidl_node *interface_node; + struct webidl_node *inherit_node; + int res = 0; + + /* find interface in webidl with correct ident attached */ + interface_node = webidl_node_find_type_ident(binding->wi_ast, + WEBIDL_NODE_TYPE_INTERFACE, + interface); + + if (interface_node == NULL) { + fprintf(stderr, + "Unable to find interface %s in loaded WebIDL\n", + interface); + return -1; + } + + fprintf(binding->outfile, "\t/**** %s ****/\n", interface); + + /* write the property defines for this interface */ + res = output_interface_consts(binding, interface_node); + + + /* check for inherited nodes and insert them too */ + inherit_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); + + if (inherit_node != NULL) { + res = output_const_defines(binding, + webidl_node_gettext(inherit_node)); + } + + if (res == 0) { + res = webidl_node_for_each_type( + webidl_node_getnode(interface_node), + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, + webidl_const_spec_implements_cb, + binding); + } + + return res; +} + +/** generate class initialisers + * + * Generates function to create the javascript class prototypes for + * each interface in the binding. + * + */ +int output_class_init(struct binding *binding) +{ + int res = 0; + struct genbind_node *api_node; + int inf; + + /* class Initialisor declaration */ + if (binding->hdrfile) { + + if (binding->interfacec > 1) { + fprintf(binding->hdrfile, + "\n#define %s_INTERFACE_COUNT %d", + binding->name, + binding->interfacec); + } + + fprintf(binding->hdrfile, + "\nint jsapi_InitClass_%s(JSContext *cx, JSObject *parent, JSObject **prototypes);\n\n", + binding->name); + + + } + + /* class Initialisor definition */ + fprintf(binding->outfile, + "int\n" + "jsapi_InitClass_%s(JSContext *cx, " + "JSObject *parent, " + "JSObject **prototypes)\n" + "{\n" + "\tJSObject *prototype;\n", + binding->name); + + /* check for the binding having an init override */ + api_node = genbind_node_find_type_ident(binding->gb_ast, + NULL, + GENBIND_NODE_TYPE_API, + "init"); + + if (api_node != NULL) { + output_code_block(binding, genbind_node_getnode(api_node)); + } else { + for (inf = 0; inf < binding->interfacec; inf++) { + + fprintf(binding->outfile, + "\n" + "\tprototype = JS_InitClass(cx, " + "parent, "); + + if (binding->interfaces[inf].inherit_idx == -1) { + /* interface does not get its + * prototypes from another interface + * we are generating + */ + fprintf(binding->outfile, + "NULL, " + "&JSClass_%s, " + "NULL, " + "0, " + "NULL, " + "NULL, " + "NULL, " + "NULL);\n", + binding->interfaces[inf].name); + + fprintf(binding->outfile, + "\tif (prototype == NULL) {\n" + "\t\treturn %d;\n" + "\t}\n\n", + inf); + + fprintf(binding->outfile, + "\tprototypes[%d] = prototype;\n", + inf); + + output_const_defines(binding, + binding->interfaces[inf].name); + + } else { + /* interface prototype is based on one + * we already generated (interface map + * is topologicaly sorted */ + assert(binding->interfaces[inf].inherit_idx < inf); + + fprintf(binding->outfile, + "prototypes[%d], " + "&JSClass_%s, " + "NULL, " + "0, " + "NULL, " + "NULL, " + "NULL, " + "NULL);\n", + binding->interfaces[inf].inherit_idx, + binding->interfaces[inf].name); + + fprintf(binding->outfile, + "\tif (prototype == NULL) {\n" + "\t\treturn %d;\n" + "\t}\n\n", + inf); + + fprintf(binding->outfile, + "\tprototypes[%d] = prototype;\n", + inf); + + output_interface_consts(binding, + binding->interfaces[inf].widl_node); + + } + } + fprintf(binding->outfile, + "\n\treturn %d;\n", + inf); + } + + fprintf(binding->outfile, "}\n\n"); + + return res; +} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index f0dc5a3..de82678 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -531,62 +531,6 @@ output_code_block(struct binding *binding, struct genbind_node *codelist) } } -/** generate class initialiser which create the javascript class prototype */ -static int -output_class_init(struct binding *binding) -{ - int res = 0; - struct genbind_node *api_node; - - /* class Initialisor declaration */ - if (binding->hdrfile) { - binding->outfile = binding->hdrfile; - - fprintf(binding->outfile, - "JSObject *jsapi_InitClass_%s(JSContext *cx, JSObject *parent);\n", - binding->interface); - - binding->outfile = binding->srcfile; - } - - /* class Initialisor definition */ - fprintf(binding->outfile, - "JSObject *jsapi_InitClass_%s(JSContext *cx, JSObject *parent)\n" - "{\n" - "\tJSObject *prototype;\n", - binding->interface); - - api_node = genbind_node_find_type_ident(binding->gb_ast, - NULL, - GENBIND_NODE_TYPE_API, - "init"); - - if (api_node != NULL) { - output_code_block(binding, genbind_node_getnode(api_node)); - } else { - fprintf(binding->outfile, - "\n" - "\tprototype = JS_InitClass(cx,\n" - "\t\tparent,\n" - "\t\tNULL,\n" - "\t\t&JSClass_%s,\n" - "\t\tNULL,\n" - "\t\t0,\n" - "\t\tNULL,\n" - "\t\tNULL, \n" - "\t\tNULL, \n" - "\t\tNULL);\n", - binding->interface); - } - - output_const_defines(binding, binding->interface); - - fprintf(binding->outfile, - "\treturn prototype;\n" - "}\n\n"); - - return res; -} static int output_class_new(struct binding *binding) @@ -1061,47 +1005,158 @@ binding_has_private(struct genbind_node *binding_list) return false; } +/* build interface map and return the first interface */ +static struct genbind_node * +build_interface_map(struct genbind_node *binding_node, + struct webidl_node *webidl_ast, + int *interfacec_out, + struct binding_interface **interfaces_out) +{ + int interfacec; + int idx; + struct binding_interface *interfaces; + struct genbind_node *node = NULL; + + /* count number of interfaces listed in binding */ + interfacec = genbind_node_enumerate_type( + genbind_node_getnode(binding_node), + GENBIND_NODE_TYPE_BINDING_INTERFACE); + + if (interfacec == 0) { + return NULL; + } + if (options->verbose) { + printf("Binding has %d interfaces\n", interfacec); + } + + interfaces = malloc(interfacec * sizeof(struct binding_interface)); + if (interfaces == NULL) { + return NULL; + } + + /* fill in map with node data */ + for (idx = 0; idx < interfacec; idx++ ) { + node = genbind_node_find_type( + genbind_node_getnode(binding_node), + node, + GENBIND_NODE_TYPE_BINDING_INTERFACE); + if (node == NULL) { + free(interfaces); + return NULL; + } + + interfaces[idx].node = node; + + /* get interface name */ + interfaces[idx].name = genbind_node_gettext( + genbind_node_find_type(genbind_node_getnode(node), + NULL, + GENBIND_NODE_TYPE_IDENT)); + if (interfaces[idx].name == NULL) { + free(interfaces); + return NULL; + } + + /* get web IDL node for interface */ + interfaces[idx].widl_node = webidl_node_find_type_ident( + webidl_ast, + WEBIDL_NODE_TYPE_INTERFACE, + interfaces[idx].name); + if (interfaces[idx].widl_node == NULL) { + free(interfaces); + return NULL; + } + + interfaces[idx].inherit_name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(interfaces[idx].widl_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); + + interfaces[idx].refcount = 0; + } + + /* find index of inherited node if it is one of those listed + * in the binding also maintain refcounts + */ + for (idx = 0; idx < interfacec; idx++ ) { + int inf; + interfaces[idx].inherit_idx = -1; + for (inf = 0; inf < interfacec; inf++ ) { + /* cannot inherit from self. and name must match */ + if ((inf != idx) && + (strcmp(interfaces[idx].inherit_name, + interfaces[inf].name) == 0)) { + interfaces[idx].inherit_idx = inf; + interfaces[inf].refcount++; + break; + } + } + } + + /** @todo There should be a topoligical sort based on the refcount + * + * do not need to consider loops as constructed graph is a acyclic + * + * alloc a second copy of the map + * repeat until all entries copied: + * walk source mapping until first entry with zero refcount + * put the entry at the end of the output map + * reduce refcount on inherit index if !=-1 + * remove entry from source map + */ + + /* show the interface map */ + if (options->verbose) { + for (idx = 0; idx < interfacec; idx++ ) { + printf("interface num:%d name:%s node:%p widl:%p inherit:%s inherit idx:%d refcount:%d\n", + idx, + interfaces[idx].name, + interfaces[idx].node, + interfaces[idx].widl_node, + interfaces[idx].inherit_name, + interfaces[idx].inherit_idx, + interfaces[idx].refcount); + } + } + + *interfacec_out = interfacec; + *interfaces_out = interfaces; + + return interfaces[0].node; +} + static struct binding * binding_new(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node) { struct binding *nb; + + int interfacec; /* numer of interfaces in the interface map */ + struct binding_interface *interfaces; /* binding interface map */ + struct genbind_node *interface_node; struct genbind_node *binding_list; - struct genbind_node *binding_ident; char *hdrguard = NULL; struct webidl_node *webidl_ast = NULL; int res; - binding_list = genbind_node_getnode(binding_node); - if (binding_list == NULL) { + /* walk AST and load any web IDL files required */ + res = read_webidl(genbind_ast, &webidl_ast); + if (res != 0) { + fprintf(stderr, "Error: failed reading Web IDL\n"); return NULL; } - /* find the first interface node - there must be at least one */ - interface_node = genbind_node_find_type(binding_list, - NULL, - GENBIND_NODE_TYPE_BINDING_INTERFACE); + /* build the bindings interface (class) name map */ + interface_node = build_interface_map(binding_node, + webidl_ast, + &interfacec, + &interfaces); if (interface_node == NULL) { - return NULL; - } - - /* get the binding identifier */ - /* @todo it should be possible to specify this as part of the - * binding instead of just using the first interface - */ - binding_ident = genbind_node_find_type(genbind_node_getnode(interface_node), - NULL, - GENBIND_NODE_TYPE_IDENT); - if (binding_ident == NULL) { - return NULL; - } - - /* walk AST and load any web IDL files required */ - res = read_webidl(genbind_ast, &webidl_ast); - if (res != 0) { - fprintf(stderr, "Error reading Web IDL files\n"); + /* the binding must have at least one interface */ + fprintf(stderr, "Error: Binding must have a valid interface\n"); return NULL; } @@ -1121,18 +1176,35 @@ binding_new(struct options *options, } } + binding_list = genbind_node_getnode(binding_node); + if (binding_list == NULL) { + return NULL; + } + nb = calloc(1, sizeof(struct binding)); nb->gb_ast = genbind_ast; nb->wi_ast = webidl_ast; - /* @todo binding name should not be called interface */ - nb->interface = genbind_node_gettext(binding_ident); + + /* keep the binding list node */ + nb->binding_list = binding_list; + + /* store the interface mapping */ + nb->interfaces = interfaces; + nb->interfacec = interfacec; + + /* @todo it should be possible to specify the binding name + * instead of just using the name of the first interface. + * + * @todo get rid of the interface element out of the binding + * struct and use the interface map instead. + */ + nb->name = nb->interface = interfaces[0].name; nb->outfile = options->outfilehandle; nb->srcfile = options->outfilehandle; nb->hdrfile = options->hdrfilehandle; nb->hdrguard = hdrguard; nb->has_private = binding_has_private(binding_list); - nb->binding_list = binding_list; /* class API */ nb->addproperty = genbind_node_find_type_ident(genbind_ast, diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index b83eeb0..ee1b2f9 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -11,10 +11,23 @@ struct options; +struct binding_interface { + const char *name; /* name of interface */ + struct genbind_node *node; /* node of interface in binding */ + struct webidl_node *widl_node; /* node of interface in webidl */ + const char *inherit_name; /* name of interface this inherits from */ + int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ + int refcount; /* number of entries in map that refer to this interface */ +}; + struct binding { struct genbind_node *gb_ast; /* root node of binding AST */ struct webidl_node *wi_ast; /* root node of webidl AST */ + const char *name; /* Name of binding (first interface name by default) */ + int interfacec; /* numer of interfaces in the interface map */ + struct binding_interface *interfaces; /* binding interface map */ + const char *interface; /* webidl interface binding is for */ bool has_private; /* true if the binding requires a private structure */ @@ -33,7 +46,7 @@ struct binding { FILE *outfile ; /* file handle output should be written to, * allows reuse of callback routines to output - * to headers and source files + * to headers and source files */ FILE *srcfile ; /* output source file */ FILE *hdrfile ; /* output header file */ @@ -55,17 +68,16 @@ int output_function_spec(struct binding *binding); * * This walks the web IDL AST to find all operator interface members * and construct appropriate jsapi native function body to implement - * them. + * them. * * Function body contents can be overriden with an operator code * block in the binding definition. * - * @param binding The binding information + * @param binding The binding information * @param interface The interface to generate operator bodys for */ int output_operator_body(struct binding *binding, const char *interface); - /** generate property tinyid enum */ int output_property_tinyid(struct binding *binding); @@ -75,10 +87,8 @@ int output_property_spec(struct binding *binding); /** generate property function bodies */ int output_property_body(struct binding *binding); -/** generate property definitions for constants */ -int output_const_defines(struct binding *binding, const char *interface); - - +/** generate binding initialisation */ +int output_class_init(struct binding *binding); #endif diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index fc1e196..2f630b7 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -68,6 +68,8 @@ genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r) return nn; } + +/* exported interface defined in nsgenbind-ast.h */ int genbind_node_foreach_type(struct genbind_node *node, enum genbind_node_type type, @@ -92,6 +94,25 @@ genbind_node_foreach_type(struct genbind_node *node, return 0; } +static int genbind_enumerate_node(struct genbind_node *node, void *ctx) +{ + node = node; + (*((int *)ctx))++; + return 0; +} + +/* exported interface defined in nsgenbind-ast.h */ +int +genbind_node_enumerate_type(struct genbind_node *node, + enum genbind_node_type type) +{ + int count = 0; + genbind_node_foreach_type(node, + type, + genbind_enumerate_node, + &count); + return count; +} /* exported interface defined in nsgenbind-ast.h */ struct genbind_node * diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index 128dce7..4911f5a 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -82,12 +82,27 @@ genbind_node_find(struct genbind_node *node, * search the full tree depth (initial search) or the result * of a previous search to continue. * @param nodetype The type of node to seach for + * @return The found node or NULL for no nodes. */ struct genbind_node * genbind_node_find_type(struct genbind_node *node, struct genbind_node *prev, enum genbind_node_type nodetype); +/** count how many nodes of a specified type. + * + * Enumerate how many nodes of the specified type there are by + * performing a depth first search for nodes of the given type and + * counting the number of results. + * + * @param node The node to start the search from + * @param nodetype The type of node to count + * @return The number of nodes found. + */ +int +genbind_node_enumerate_type(struct genbind_node *node, + enum genbind_node_type type); + /** Depth first left hand search returning nodes of the specified type * and a ident child node with matching text * -- cgit v1.2.3 From 12c40d1dd1bebfe92508e873cb338d419d380a03 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 29 Dec 2013 15:29:03 +0000 Subject: add test with multiple interfaces within on binding --- test/data/bindings/htmlelement.bnd | 720 +++++++++++++++++++++++++++++++++++++ test/testrunner.sh | 15 +- 2 files changed, 732 insertions(+), 3 deletions(-) create mode 100644 test/data/bindings/htmlelement.bnd diff --git a/test/data/bindings/htmlelement.bnd b/test/data/bindings/htmlelement.bnd new file mode 100644 index 0000000..d702147 --- /dev/null +++ b/test/data/bindings/htmlelement.bnd @@ -0,0 +1,720 @@ +/* Binding to generate HTMLElement interface + * + * Copyright 2012 Vincent Sanders + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * Released under the terms of the MIT License, + * http://www.opensource.org/licenses/mit-license + */ + +webidlfile "html.idl"; + +hdrcomment "Copyright 2012 Vincent Sanders "; +hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/"; +hdrcomment "Released under the terms of the MIT License,"; +hdrcomment " http://www.opensource.org/licenses/mit-license"; + +preamble %{ + +#include + +#include "utils/config.h" +#include "utils/log.h" +#include "utils/corestrings.h" +#include "javascript/js.h" +#include "javascript/jsapi.h" +#include "render/html_internal.h" + +#include "htmlelement.h" +#include "text.h" +#include "location.h" +#include "nodelist.h" + +%} + +#include "dom.bnd" + +binding jsapi_libdom { + + interface HTMLElement; + interface HTMLAnchorElement; + interface HTMLAppletElement; + interface HTMLAreaElement; + interface HTMLBaseElement; + interface HTMLBaseFontElement; + interface HTMLBodyElement; + interface HTMLBRElement; + + interface HTMLButtonElement; + interface HTMLCanvasElement; + interface HTMLCommandElement; + interface HTMLDataElement; + interface HTMLDataListElement; + interface HTMLDetailsElement; + interface HTMLDialogElement; + interface HTMLDirectoryElement; + interface HTMLDivElement; + interface HTMLDListElement; + interface HTMLEmbedElement; + interface HTMLFieldSetElement; + interface HTMLFontElement; + interface HTMLFormElement; + interface HTMLFrameElement; + interface HTMLFrameSetElement; + interface HTMLHeadElement; + interface HTMLHeadingElement; + interface HTMLHRElement; + interface HTMLHtmlElement; + interface HTMLIFrameElement; + interface HTMLImageElement; + interface HTMLInputElement; + interface HTMLKeygenElement; + interface HTMLLabelElement; + interface HTMLLegendElement; + interface HTMLLIElement; + interface HTMLLinkElement; + interface HTMLMapElement; + interface HTMLMarqueeElement; + interface HTMLMediaElement; + interface HTMLMenuElement; + interface HTMLMetaElement; + interface HTMLMeterElement; + interface HTMLModElement; + interface HTMLObjectElement; + interface HTMLOListElement; + interface HTMLOptGroupElement; + interface HTMLOptionElement; + interface HTMLOutputElement; + interface HTMLParagraphElement; + interface HTMLParamElement; + interface HTMLPreElement; + interface HTMLProgressElement; + interface HTMLQuoteElement; + interface HTMLScriptElement; + interface HTMLSelectElement; + interface HTMLSourceElement; + interface HTMLSpanElement; + interface HTMLStyleElement; + interface HTMLTableCaptionElement; + interface HTMLTableCellElement; + interface HTMLTableColElement; + interface HTMLTableElement; + interface HTMLTableRowElement; + interface HTMLTableSectionElement; + interface HTMLTextAreaElement; + interface HTMLTimeElement; + interface HTMLTitleElement; + interface HTMLTrackElement; + interface HTMLUListElement; + interface HTMLUnknownElement; + + private "dom_element *" node; + private "struct html_content *" htmlc; + + /* tag name retrieved first time its fetched and doesnt change */ + property unshared tagName; + + /* events through a single interface */ + property unshared type EventHandler; + + +} + +api finalise %{ + if (private != NULL) { + dom_node_unref(private->node); + } +%} + +/* interface Element in dom idl */ + +/* readonly attribute DOMString Element::tagName; */ +getter tagName %{ + if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) { + /* already created - return it */ + return JS_TRUE; + } + + dom_exception exc; + dom_string *name; + + exc = dom_element_get_tag_name(private->node, &name); + if (name != NULL) { + jsret = JS_NewStringCopyN(cx, dom_string_data(name), dom_string_length(name)); + dom_string_unref(name); + } +%} + +/* attribute DOMString Element::id; */ +getter id %{ + dom_string *value; + dom_exception exc; + + exc = dom_element_get_attribute(private->node, corestring_dom_id, &value); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + if (value != NULL) { + jsret = JS_NewStringCopyN(cx, dom_string_data(value), dom_string_length(value)); + dom_string_unref(value); + } +%} + +/* attribute DOMString Element::className; */ +getter className %{ + dom_string *value; + dom_exception exc; + + exc = dom_element_get_attribute(private->node, corestring_dom_class, &value); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + if (value != NULL) { + jsret = JS_NewStringCopyN(cx, dom_string_data(value), dom_string_length(value)); + dom_string_unref(value); + } +%} + +/* DOMString? Element::getAttribute(DOMString name); */ +operation getAttribute %{ + dom_string *value; + dom_string *name_dom; + dom_exception exc; + + exc = dom_string_create((unsigned char*)name, name_len, &name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + exc = dom_element_get_attribute(private->node, name_dom, &value); + dom_string_unref(name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + if (value != NULL) { + jsret = JS_NewStringCopyN(cx, dom_string_data(value), dom_string_length(value)); + dom_string_unref(value); + } +%} + +/* void Element::setAttribute(DOMString name, DOMString value); */ +operation setAttribute %{ + dom_string *value_dom; + dom_string *name_dom; + dom_exception exc; + + exc = dom_string_create((unsigned char*)name, name_len, &name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + exc = dom_string_create((unsigned char*)name, name_len, &value_dom); + if (exc != DOM_NO_ERR) { + dom_string_unref(name_dom); + return JS_FALSE; + } + + exc = dom_element_set_attribute(private->node, name_dom, value_dom); + dom_string_unref(name_dom); + dom_string_unref(value_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } +%} + +/* void Element::removeAttribute(DOMString name); */ +operation removeAttribute %{ + dom_string *name_dom; + dom_exception exc; + + exc = dom_string_create((unsigned char*)name, name_len, &name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + exc = dom_element_remove_attribute(private->node, name_dom); + dom_string_unref(name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } +%} + +/* boolean Element::hasAttribute(DOMString name); */ +operation hasAttribute %{ + bool result; + dom_string *name_dom; + dom_exception exc; + + exc = dom_string_create((unsigned char*)name, name_len, &name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + exc = dom_element_has_attribute(private->node, name_dom, &result); + dom_string_unref(name_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + if (result) { + jsret = JS_TRUE; + } +%} + +/* + * + * Dom 4 says this should return a htmlcollection, libdom currently + * returns DOM 3 spec of a nodelist + */ +/* HTMLCollection Element::getElementsByTagName(DOMString localName); */ +operation getElementsByTagName %{ + dom_string *localName_dom; + /* dom_html_collection *collection;*/ + dom_nodelist *nodelist; + dom_exception exc; + + exc = dom_string_create((uint8_t *)localName, localName_len, &localName_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + exc = dom_element_get_elements_by_tag_name(private->node, localName_dom, /*&collection*/&nodelist); + dom_string_unref(localName_dom); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + if (/*collection*/nodelist != NULL) { + /*jsret = jsapi_new_HTMLCollection(cx, + NULL, + NULL, + collection, + private->htmlc);*/ + jsret = jsapi_new_NodeList(cx, + NULL, + NULL, + nodelist, + private->htmlc); + } + +%} + +/* + * DOM 3 has these as the element traversal extension + * + * http://dev.w3.org/2006/webapi/ElementTraversal/publish/ElementTraversal.html + */ + +getter firstElementChild %{ + dom_node *element; + dom_exception exc; + dom_node_type node_type; + dom_node *next_node; + + exc = dom_node_get_first_child(private->node, &element); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + while (element != NULL) { + exc = dom_node_get_node_type(element, &node_type); + if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) { + /* found it */ + jsret = jsapi_new_HTMLElement(cx, + NULL, + NULL, + (dom_element *)element, + private->htmlc); + break; + } + + exc = dom_node_get_next_sibling(element, &next_node); + dom_node_unref(element); + if (exc == DOM_NO_ERR) { + element = next_node; + } else { + element = NULL; + } + + } + + + %} + +getter lastElementChild %{ + dom_node *element; + dom_exception exc; + dom_node_type node_type; + dom_node *sib_node; + + exc = dom_node_get_last_child(private->node, &element); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + while (element != NULL) { + exc = dom_node_get_node_type(element, &node_type); + if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) { + /* found it */ + jsret = jsapi_new_HTMLElement(cx, + NULL, + NULL, + (dom_element *)element, + private->htmlc); + break; + } + + exc = dom_node_get_previous_sibling(element, &sib_node); + dom_node_unref(element); + if (exc == DOM_NO_ERR) { + element = sib_node; + } else { + element = NULL; + } + + } + %} + +getter previousElementSibling %{ + dom_node *element; + dom_exception exc; + dom_node_type node_type; + dom_node *sib_node; + + exc = dom_node_get_previous_sibling(private->node, &element); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + while (element != NULL) { + exc = dom_node_get_node_type(element, &node_type); + if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) { + /* found it */ + jsret = jsapi_new_HTMLElement(cx, + NULL, + NULL, + (dom_element *)element, + private->htmlc); + break; + } + + exc = dom_node_get_previous_sibling(element, &sib_node); + dom_node_unref(element); + if (exc == DOM_NO_ERR) { + element = sib_node; + } else { + element = NULL; + } + } +%} + +getter nextElementSibling %{ + dom_node *element; + dom_exception exc; + dom_node_type node_type; + dom_node *sib_node; + + exc = dom_node_get_next_sibling(private->node, &element); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + while (element != NULL) { + exc = dom_node_get_node_type(element, &node_type); + if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) { + /* found it */ + jsret = jsapi_new_HTMLElement(cx, + NULL, + NULL, + (dom_element *)element, + private->htmlc); + break; + } + + exc = dom_node_get_next_sibling(element, &sib_node); + dom_node_unref(element); + if (exc == DOM_NO_ERR) { + element = sib_node; + } else { + element = NULL; + } + } +%} + +getter childElementCount %{ + dom_node *element; + dom_exception exc; + dom_node_type node_type; + dom_node *next_node; + + exc = dom_node_get_first_child(private->node, &element); + if (exc != DOM_NO_ERR) { + return JS_FALSE; + } + + while (element != NULL) { + exc = dom_node_get_node_type(element, &node_type); + if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) { + jsret += 1; + } + + exc = dom_node_get_next_sibling(element, &next_node); + dom_node_unref(element); + if (exc == DOM_NO_ERR) { + element = next_node; + } else { + element = NULL; + } + } +%} + +getter EventHandler %{ + JSLOG("propname[%d].name=\"%s\"", + tinyid, + jsclass_properties[tinyid].name); +%} + + +setter EventHandler %{ + dom_string *event_type_dom; + + JSLOG("propname[%d].name=\"%s\"", + tinyid, + jsclass_properties[tinyid].name); + + switch (tinyid) { + case JSAPI_PROP_TINYID_onabort: + event_type_dom = corestring_dom_abort; + break; + + case JSAPI_PROP_TINYID_onblur: + event_type_dom = corestring_dom_blur; + break; + + case JSAPI_PROP_TINYID_oncancel: + event_type_dom = corestring_dom_cancel; + break; + + case JSAPI_PROP_TINYID_oncanplay: + event_type_dom = corestring_dom_canplay; + break; + + case JSAPI_PROP_TINYID_oncanplaythrough: + event_type_dom = corestring_dom_canplaythrough; + break; + + case JSAPI_PROP_TINYID_onchange: + event_type_dom = corestring_dom_change; + break; + + case JSAPI_PROP_TINYID_onclick: + event_type_dom = corestring_dom_click; + break; + + case JSAPI_PROP_TINYID_onclose: + event_type_dom = corestring_dom_close; + break; + + case JSAPI_PROP_TINYID_oncontextmenu: + event_type_dom = corestring_dom_contextmenu; + break; + + case JSAPI_PROP_TINYID_oncuechange: + event_type_dom = corestring_dom_cuechange; + break; + + case JSAPI_PROP_TINYID_ondblclick: + event_type_dom = corestring_dom_dblclick; + break; + + case JSAPI_PROP_TINYID_ondrag: + event_type_dom = corestring_dom_drag; + break; + + case JSAPI_PROP_TINYID_ondragend: + event_type_dom = corestring_dom_dragend; + break; + + case JSAPI_PROP_TINYID_ondragenter: + event_type_dom = corestring_dom_dragenter; + break; + + case JSAPI_PROP_TINYID_ondragleave: + event_type_dom = corestring_dom_dragleave; + break; + + case JSAPI_PROP_TINYID_ondragover: + event_type_dom = corestring_dom_dragover; + break; + + case JSAPI_PROP_TINYID_ondragstart: + event_type_dom = corestring_dom_dragstart; + break; + + case JSAPI_PROP_TINYID_ondrop: + event_type_dom = corestring_dom_drop; + break; + + case JSAPI_PROP_TINYID_ondurationchange: + event_type_dom = corestring_dom_durationchange; + break; + + case JSAPI_PROP_TINYID_onemptied: + event_type_dom = corestring_dom_emptied; + break; + + case JSAPI_PROP_TINYID_onended: + event_type_dom = corestring_dom_ended; + break; + + case JSAPI_PROP_TINYID_onerror: + event_type_dom = corestring_dom_error; + break; + + case JSAPI_PROP_TINYID_onfocus: + event_type_dom = corestring_dom_focus; + break; + + case JSAPI_PROP_TINYID_oninput: + event_type_dom = corestring_dom_input; + break; + + case JSAPI_PROP_TINYID_oninvalid: + event_type_dom = corestring_dom_invalid; + break; + + case JSAPI_PROP_TINYID_onkeydown: + event_type_dom = corestring_dom_keydown; + break; + + case JSAPI_PROP_TINYID_onkeypress: + event_type_dom = corestring_dom_keypress; + break; + + case JSAPI_PROP_TINYID_onkeyup: + event_type_dom = corestring_dom_keyup; + break; + + case JSAPI_PROP_TINYID_onload: + event_type_dom = corestring_dom_load; + break; + + case JSAPI_PROP_TINYID_onloadeddata: + event_type_dom = corestring_dom_loadeddata; + break; + + case JSAPI_PROP_TINYID_onloadedmetadata: + event_type_dom = corestring_dom_loadedmetadata; + break; + + case JSAPI_PROP_TINYID_onloadstart: + event_type_dom = corestring_dom_loadstart; + break; + + case JSAPI_PROP_TINYID_onmousedown: + event_type_dom = corestring_dom_mousedown; + break; + + case JSAPI_PROP_TINYID_onmousemove: + event_type_dom = corestring_dom_mousemove; + break; + + case JSAPI_PROP_TINYID_onmouseout: + event_type_dom = corestring_dom_mouseout; + break; + + case JSAPI_PROP_TINYID_onmouseover: + event_type_dom = corestring_dom_mouseover; + break; + + case JSAPI_PROP_TINYID_onmouseup: + event_type_dom = corestring_dom_mouseup; + break; + + case JSAPI_PROP_TINYID_onmousewheel: + event_type_dom = corestring_dom_mousewheel; + break; + + case JSAPI_PROP_TINYID_onpause: + event_type_dom = corestring_dom_pause; + break; + + case JSAPI_PROP_TINYID_onplay: + event_type_dom = corestring_dom_play; + break; + + case JSAPI_PROP_TINYID_onplaying: + event_type_dom = corestring_dom_playing; + break; + + case JSAPI_PROP_TINYID_onprogress: + event_type_dom = corestring_dom_progress; + break; + + case JSAPI_PROP_TINYID_onratechange: + event_type_dom = corestring_dom_ratechange; + break; + + case JSAPI_PROP_TINYID_onreset: + event_type_dom = corestring_dom_reset; + break; + + case JSAPI_PROP_TINYID_onscroll: + event_type_dom = corestring_dom_scroll; + break; + + case JSAPI_PROP_TINYID_onseeked: + event_type_dom = corestring_dom_seeked; + break; + + case JSAPI_PROP_TINYID_onseeking: + event_type_dom = corestring_dom_seeking; + break; + + case JSAPI_PROP_TINYID_onselect: + event_type_dom = corestring_dom_select; + break; + + case JSAPI_PROP_TINYID_onshow: + event_type_dom = corestring_dom_show; + break; + + case JSAPI_PROP_TINYID_onstalled: + event_type_dom = corestring_dom_stalled; + break; + + case JSAPI_PROP_TINYID_onsubmit: + event_type_dom = corestring_dom_submit; + break; + + case JSAPI_PROP_TINYID_onsuspend: + event_type_dom = corestring_dom_suspend; + break; + + case JSAPI_PROP_TINYID_ontimeupdate: + event_type_dom = corestring_dom_timeupdate; + break; + + case JSAPI_PROP_TINYID_onvolumechange: + event_type_dom = corestring_dom_volumechange; + break; + + case JSAPI_PROP_TINYID_onwaiting: + event_type_dom = corestring_dom_waiting; + break; + + default: + JSLOG("called with unknown tinyid"); + return JS_TRUE; + } + + js_dom_event_add_listener((struct jscontext *)cx, + private->htmlc->document, + (dom_node *)private->node, + event_type_dom, + vp); +%} diff --git a/test/testrunner.sh b/test/testrunner.sh index 1349b84..30a5116 100755 --- a/test/testrunner.sh +++ b/test/testrunner.sh @@ -11,6 +11,8 @@ TESTDIR=$2 # locations LOGFILE=${BUILDDIR}/testlog +RESFILE=${BUILDDIR}/testres +ERRFILE=${BUILDDIR}/testerr GENJSBIND=${BUILDDIR}/nsgenbind @@ -28,11 +30,18 @@ for TEST in ${BINDINGTESTS};do echo -n " TEST: ${TESTNAME}......" outline - echo ${GENJSBIND} -D -v -I ${IDLDIR} -o ${BUILDDIR}/test_${TESTNAME}.c -h ${BUILDDIR}/test_${TESTNAME}.h ${TEST} >>${LOGFILE} 2>&1 + echo ${GENJSBIND} -v -I ${IDLDIR} -o ${BUILDDIR}/test_${TESTNAME}.c -h ${BUILDDIR}/test_${TESTNAME}.h ${TEST} >>${LOGFILE} 2>&1 - ${GENJSBIND} -D -v -I ${IDLDIR} -o ${BUILDDIR}/test_${TESTNAME}.c -h ${BUILDDIR}/test_${TESTNAME}.h ${TEST} >>${LOGFILE} 2>&1 + ${GENJSBIND} -v -I ${IDLDIR} -o ${BUILDDIR}/test_${TESTNAME}.c -h ${BUILDDIR}/test_${TESTNAME}.h ${TEST} >${RESFILE} 2>${ERRFILE} - if [ $? -eq 0 ]; then + RESULT=$? + + echo >> ${LOGFILE} + cat ${ERRFILE} >> ${LOGFILE} + echo >> ${LOGFILE} + cat ${RESFILE} >> ${LOGFILE} + + if [ ${RESULT} -eq 0 ]; then echo "PASS" else echo "FAIL" -- cgit v1.2.3 From ed92dd097848f4628abfa3a8cc8be802a996272d Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 1 Jan 2014 11:44:45 +0000 Subject: make binding constructor multiple interface capable --- src/Makefile | 2 +- src/jsapi-libdom-init.c | 3 +- src/jsapi-libdom-new.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++ src/jsapi-libdom.c | 186 ----------------------- src/jsapi-libdom.h | 3 + 5 files changed, 401 insertions(+), 188 deletions(-) create mode 100644 src/jsapi-libdom-new.c diff --git a/src/Makefile b/src/Makefile index 8bad59a..8233398 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-operator.c jsapi-libdom-property.c jsapi-libdom-init.c +DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-operator.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c SOURCES := $(SOURCES) $(BUILDDIR)/nsgenbind-parser.c $(BUILDDIR)/nsgenbind-lexer.c $(BUILDDIR)/webidl-parser.c $(BUILDDIR)/webidl-lexer.c diff --git a/src/jsapi-libdom-init.c b/src/jsapi-libdom-init.c index 1f6b80d..6dfc66f 100644 --- a/src/jsapi-libdom-init.c +++ b/src/jsapi-libdom-init.c @@ -1,4 +1,5 @@ -/* const property generation +/* Javascript spidemonkey API to libdom binding generation for class + * initilisation * * This file is part of nsgenbind. * Licensed under the MIT License, diff --git a/src/jsapi-libdom-new.c b/src/jsapi-libdom-new.c new file mode 100644 index 0000000..b78c715 --- /dev/null +++ b/src/jsapi-libdom-new.c @@ -0,0 +1,395 @@ +/* Spidemonkey Javascript API to libdom binding generation for class + * construction. + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2013 Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "jsapi-libdom.h" + +static int webidl_private_param_cb(struct genbind_node *node, void *ctx) +{ + struct binding *binding = ctx; + struct genbind_node *ident_node; + struct genbind_node *type_node; + + + ident_node = genbind_node_find_type(genbind_node_getnode(node), + NULL, + GENBIND_NODE_TYPE_IDENT); + if (ident_node == NULL) + return -1; /* bad AST */ + + type_node = genbind_node_find_type(genbind_node_getnode(node), + NULL, + GENBIND_NODE_TYPE_STRING); + if (type_node == NULL) + return -1; /* bad AST */ + + fprintf(binding->outfile, + ",\n\t\t%s%s", + genbind_node_gettext(type_node), + genbind_node_gettext(ident_node)); + + return 0; +} + +static int webidl_private_assign_cb(struct genbind_node *node, void *ctx) +{ + struct binding *binding = ctx; + struct genbind_node *ident_node; + const char *ident; + + ident_node = genbind_node_find_type(genbind_node_getnode(node), + NULL, + GENBIND_NODE_TYPE_IDENT); + if (ident_node == NULL) + return -1; /* bad AST */ + + ident = genbind_node_gettext(ident_node); + + fprintf(binding->outfile, "\tprivate->%s = %s;\n", ident, ident); + + return 0; +} + + + +static int +output_binding_constructor(struct binding *binding) +{ + fprintf(binding->outfile, + "JSObject *jsapi_new_%s(JSContext *cx, \n", + binding->name); + + fprintf(binding->outfile, "\t\tJSObject *prototype, \n"); + + if (binding->interfacec != 1) { + fprintf(binding->outfile, "\t\tconst char *interface_name, \n"); + } + + fprintf(binding->outfile, "\t\tJSObject *parent"); + + genbind_node_foreach_type(binding->binding_list, + GENBIND_NODE_TYPE_BINDING_PRIVATE, + webidl_private_param_cb, + binding); + + fprintf(binding->outfile, ")"); + + return 0; +} + +static int +output_class_wprivate_multi(struct binding *binding) +{ + int inf; + + /* create and initialise private data */ + fprintf(binding->outfile, + "\tstruct jsclass_private *private;\n" + "\n" + "\tprivate = malloc(sizeof(struct jsclass_private));\n" + "\tif (private == NULL) {\n" + "\t\treturn NULL;\n" + "\t}\n"); + + genbind_node_foreach_type(binding->binding_list, + GENBIND_NODE_TYPE_BINDING_PRIVATE, + webidl_private_assign_cb, + binding); + + + fprintf(binding->outfile, "\n\n\t"); + + /* for each interface in the map generate initialisor */ + for (inf = 0; inf < binding->interfacec; inf++) { + + fprintf(binding->outfile, + "if (strcmp(interface_name, JSClass_%s.name) == 0) {\n", + binding->interfaces[inf].name); + + fprintf(binding->outfile, + "\n" + "\t\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n", + binding->interface); + + + fprintf(binding->outfile, + "\t\tif (newobject == NULL) {\n" + "\t\t\tfree(private);\n" + "\t\t\treturn NULL;\n" + "\t\t}\n\n"); + + /* root object to stop it being garbage collected */ + fprintf(binding->outfile, + "\t\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n" + "\t\t\tfree(private);\n" + "\t\t\treturn NULL;\n" + "\t\t}\n\n"); + + fprintf(binding->outfile, + "\n" + "\t\t/* attach private pointer */\n" + "\t\tif (JS_SetPrivate(cx, newobject, private) != JS_TRUE) {\n" + "\t\t\tfree(private);\n" + "\t\t\treturn NULL;\n" + "\t\t}\n\n"); + + + /* attach operations and attributes (functions and properties) */ + fprintf(binding->outfile, + "\t\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n" + "\t\t\tfree(private);\n" + "\t\t\treturn NULL;\n" + "\t\t}\n\n"); + + fprintf(binding->outfile, + "\t\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n" + "\t\t\tfree(private);\n" + "\t\t\treturn NULL;\n" + "\t\t}\n\n"); + + /* unroot object */ + fprintf(binding->outfile, + "\t\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n" + "\t} else "); + } + fprintf(binding->outfile, + "{\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n"); + + return 0; +} + +static int +output_class_wprivate(struct binding *binding, struct genbind_node *api_node) +{ + /* create and initialise private data */ + fprintf(binding->outfile, + "\tstruct jsclass_private *private;\n" + "\n" + "\tprivate = malloc(sizeof(struct jsclass_private));\n" + "\tif (private == NULL) {\n" + "\t\treturn NULL;\n" + "\t}\n"); + + genbind_node_foreach_type(binding->binding_list, + GENBIND_NODE_TYPE_BINDING_PRIVATE, + webidl_private_assign_cb, + binding); + + if (api_node != NULL) { + output_code_block(binding, genbind_node_getnode(api_node)); + } else { + fprintf(binding->outfile, + "\n" + "\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n", + binding->interface); + } + + fprintf(binding->outfile, + "\tif (newobject == NULL) {\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + /* root object to stop it being garbage collected */ + fprintf(binding->outfile, + "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + fprintf(binding->outfile, + "\n" + "\t/* attach private pointer */\n" + "\tif (JS_SetPrivate(cx, newobject, private) != JS_TRUE) {\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + + /* attach operations and attributes (functions and properties) */ + fprintf(binding->outfile, + "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + fprintf(binding->outfile, + "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + /* unroot object */ + fprintf(binding->outfile, + "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n"); + + return 0; +} + +static int +output_class_woprivate_multi(struct binding *binding) +{ + int inf; + + fprintf(binding->outfile, "\n\t"); + + /* for each interface in the map generate initialisor */ + for (inf = 0; inf < binding->interfacec; inf++) { + fprintf(binding->outfile, + "if (strcmp(interface_name, JSClass_%s.name) == 0) {\n", + binding->interfaces[inf].name); + + fprintf(binding->outfile, + "\t\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n", + binding->interface); + + + fprintf(binding->outfile, + "\tif (newobject == NULL) {\n" + "\t\treturn NULL;\n" + "\t}\n"); + + /* root object to stop it being garbage collected */ + fprintf(binding->outfile, + "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + /* attach operations and attributes (functions and properties) */ + fprintf(binding->outfile, + "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + fprintf(binding->outfile, + "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + /* unroot object */ + fprintf(binding->outfile, + "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n"); + + } + fprintf(binding->outfile, + "{\n" + "\t\tfree(private);\n" + "\t\treturn NULL;\n" + "\t}\n"); + + + return 0; +} + +static int +output_class_woprivate(struct binding *binding, struct genbind_node *api_node) +{ + + if (api_node != NULL) { + output_code_block(binding, genbind_node_getnode(api_node)); + } else { + fprintf(binding->outfile, + "\n" + "\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n", + binding->interface); + + } + + fprintf(binding->outfile, + "\tif (newobject == NULL) {\n" + "\t\treturn NULL;\n" + "\t}\n"); + + /* root object to stop it being garbage collected */ + fprintf(binding->outfile, + "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + /* attach operations and attributes (functions and properties) */ + fprintf(binding->outfile, + "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + fprintf(binding->outfile, + "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n" + "\t\treturn NULL;\n" + "\t}\n\n"); + + /* unroot object */ + fprintf(binding->outfile, + "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n\n"); + + return 0; +} + +int +output_class_new(struct binding *binding) +{ + int res = 0; + struct genbind_node *api_node; + + /* constructor declaration */ + if (binding->hdrfile) { + binding->outfile = binding->hdrfile; + + output_binding_constructor(binding); + + fprintf(binding->outfile, ";\n"); + + binding->outfile = binding->srcfile; + } + + /* constructor definition */ + output_binding_constructor(binding); + + fprintf(binding->outfile, + "\n{\n" + "\tJSObject *newobject;\n"); + + api_node = genbind_node_find_type_ident(binding->gb_ast, + NULL, + GENBIND_NODE_TYPE_API, + "new"); + + /* generate correct constructor body */ + if (binding->has_private) { + if ((binding->interfacec == 1) || (api_node != NULL)) { + res = output_class_wprivate(binding, api_node); + } else { + res = output_class_wprivate_multi(binding); + } + } else { + if ((binding->interfacec == 1) || (api_node != NULL)) { + res = output_class_woprivate(binding, api_node); + } else { + res = output_class_woprivate_multi(binding); + } + } + + /* return newly created object */ + fprintf(binding->outfile, + "\treturn newobject;\n" + "}\n"); + + return res; +} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index de82678..895ccf4 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -135,51 +135,7 @@ static int webidl_private_cb(struct genbind_node *node, void *ctx) return 0; } -static int webidl_private_param_cb(struct genbind_node *node, void *ctx) -{ - struct binding *binding = ctx; - struct genbind_node *ident_node; - struct genbind_node *type_node; - - - ident_node = genbind_node_find_type(genbind_node_getnode(node), - NULL, - GENBIND_NODE_TYPE_IDENT); - if (ident_node == NULL) - return -1; /* bad AST */ - - type_node = genbind_node_find_type(genbind_node_getnode(node), - NULL, - GENBIND_NODE_TYPE_STRING); - if (type_node == NULL) - return -1; /* bad AST */ - - fprintf(binding->outfile, - ",\n\t\t%s%s", - genbind_node_gettext(type_node), - genbind_node_gettext(ident_node)); - return 0; -} - -static int webidl_private_assign_cb(struct genbind_node *node, void *ctx) -{ - struct binding *binding = ctx; - struct genbind_node *ident_node; - const char *ident; - - ident_node = genbind_node_find_type(genbind_node_getnode(node), - NULL, - GENBIND_NODE_TYPE_IDENT); - if (ident_node == NULL) - return -1; /* bad AST */ - - ident = genbind_node_gettext(ident_node); - - fprintf(binding->outfile, "\tprivate->%s = %s;\n", ident, ident); - - return 0; -} /* section output generators */ @@ -532,148 +488,6 @@ output_code_block(struct binding *binding, struct genbind_node *codelist) } -static int -output_class_new(struct binding *binding) -{ - int res = 0; - struct genbind_node *api_node; - - /* constructor declaration */ - if (binding->hdrfile) { - binding->outfile = binding->hdrfile; - - fprintf(binding->outfile, - "JSObject *jsapi_new_%s(JSContext *cx,\n" - "\t\tJSObject *prototype,\n" - "\t\tJSObject *parent", - binding->interface); - - genbind_node_foreach_type(binding->binding_list, - GENBIND_NODE_TYPE_BINDING_PRIVATE, - webidl_private_param_cb, - binding); - - fprintf(binding->outfile, ");"); - - binding->outfile = binding->srcfile; - } - - /* constructor definition */ - fprintf(binding->outfile, - "JSObject *jsapi_new_%s(JSContext *cx,\n" - "\t\tJSObject *prototype,\n" - "\t\tJSObject *parent", - binding->interface); - - genbind_node_foreach_type(binding->binding_list, - GENBIND_NODE_TYPE_BINDING_PRIVATE, - webidl_private_param_cb, - binding); - - fprintf(binding->outfile, - ")\n" - "{\n" - "\tJSObject *newobject;\n"); - - /* create private data */ - if (binding->has_private) { - fprintf(binding->outfile, - "\tstruct jsclass_private *private;\n" - "\n" - "\tprivate = malloc(sizeof(struct jsclass_private));\n" - "\tif (private == NULL) {\n" - "\t\treturn NULL;\n" - "\t}\n"); - - genbind_node_foreach_type(binding->binding_list, - GENBIND_NODE_TYPE_BINDING_PRIVATE, - webidl_private_assign_cb, - binding); - } - - api_node = genbind_node_find_type_ident(binding->gb_ast, - NULL, - GENBIND_NODE_TYPE_API, - "new"); - - if (api_node != NULL) { - output_code_block(binding, genbind_node_getnode(api_node)); - } else { - fprintf(binding->outfile, - "\n" - "\tnewobject = JS_NewObject(cx, &JSClass_%s, prototype, parent);\n", - binding->interface); - } - - if (binding->has_private) { - fprintf(binding->outfile, - "\tif (newobject == NULL) {\n" - "\t\tfree(private);\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - - /* root object to stop it being garbage collected */ - fprintf(binding->outfile, - "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n" - "\t\tfree(private);\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - - fprintf(binding->outfile, - "\n" - "\t/* attach private pointer */\n" - "\tif (JS_SetPrivate(cx, newobject, private) != JS_TRUE) {\n" - "\t\tfree(private);\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - - - /* attach operations and attributes (functions and properties) */ - fprintf(binding->outfile, - "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n" - "\t\tfree(private);\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - - fprintf(binding->outfile, - "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n" - "\t\tfree(private);\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - } else { - fprintf(binding->outfile, - "\tif (newobject == NULL) {\n" - "\t\treturn NULL;\n" - "\t}\n"); - - /* root object to stop it being garbage collected */ - fprintf(binding->outfile, - "\tif (JSAPI_ADD_OBJECT_ROOT(cx, &newobject) != JS_TRUE) {\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - - /* attach operations and attributes (functions and properties) */ - fprintf(binding->outfile, - "\tif (JS_DefineFunctions(cx, newobject, jsclass_functions) != JS_TRUE) {\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - - fprintf(binding->outfile, - "\tif (JS_DefineProperties(cx, newobject, jsclass_properties) != JS_TRUE) {\n" - "\t\treturn NULL;\n" - "\t}\n\n"); - } - - /* unroot object and return it */ - fprintf(binding->outfile, - "\tJSAPI_REMOVE_OBJECT_ROOT(cx, &newobject);\n" - "\n" - "\treturn newobject;\n" - "}\n"); - - - return res; -} static int output_forward_declarations(struct binding *binding) diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index ee1b2f9..bdf4bec 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -90,5 +90,8 @@ int output_property_body(struct binding *binding); /** generate binding initialisation */ int output_class_init(struct binding *binding); +/** generate binding class constructors */ +int output_class_new(struct binding *binding); + #endif -- cgit v1.2.3 From 0d89adf43b0c3b85d698e333c157e7589f51beb7 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 1 Jan 2014 15:09:10 +0000 Subject: rename jsapi method generation to be named function rather than oddly named webidl operator nomenclature --- src/Makefile | 2 +- src/jsapi-libdom-function.c | 878 ++++++++++++++++++++++++++++++++++++++++++++ src/jsapi-libdom-operator.c | 878 -------------------------------------------- src/jsapi-libdom.c | 10 +- src/jsapi-libdom.h | 5 +- 5 files changed, 888 insertions(+), 885 deletions(-) create mode 100644 src/jsapi-libdom-function.c delete mode 100644 src/jsapi-libdom-operator.c diff --git a/src/Makefile b/src/Makefile index 8233398..2f42c4a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-operator.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c +DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c SOURCES := $(SOURCES) $(BUILDDIR)/nsgenbind-parser.c $(BUILDDIR)/nsgenbind-lexer.c $(BUILDDIR)/webidl-parser.c $(BUILDDIR)/webidl-lexer.c diff --git a/src/jsapi-libdom-function.c b/src/jsapi-libdom-function.c new file mode 100644 index 0000000..594a100 --- /dev/null +++ b/src/jsapi-libdom-function.c @@ -0,0 +1,878 @@ +/* jsapi function generation for webidl bodies + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2012 Vincent Sanders + */ + +#include +#include +#include +#include +#include + +#include "options.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "jsapi-libdom.h" + +static int webidl_func_spec_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + struct webidl_node *ident_node; + + ident_node = webidl_node_find(webidl_node_getnode(node), + NULL, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_IDENT); + + if (ident_node == NULL) { + /* operation without identifier - must have special keyword + * http://www.w3.org/TR/WebIDL/#idl-operations + */ + } else { + fprintf(binding->outfile, + "\tJSAPI_FS(%s, 0, JSPROP_ENUMERATE ),\n", + webidl_node_gettext(ident_node)); + /* @todo number of args to that FN_FS() call should be correct */ + } + return 0; +} + + +static int generate_function_spec(struct binding *binding, const char *interface); + +/* callback to emit implements operator spec */ +static int webidl_function_spec_implements_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + + return generate_function_spec(binding, webidl_node_gettext(node)); +} + +static int +generate_function_spec(struct binding *binding, const char *interface) +{ + struct webidl_node *interface_node; + struct webidl_node *members_node; + struct webidl_node *inherit_node; + int res = 0; + + /* find interface in webidl with correct ident attached */ + interface_node = webidl_node_find_type_ident(binding->wi_ast, + WEBIDL_NODE_TYPE_INTERFACE, + interface); + + if (interface_node == NULL) { + fprintf(stderr, + "Unable to find interface %s in loaded WebIDL\n", + interface); + return -1; + } + + members_node = webidl_node_find(webidl_node_getnode(interface_node), + NULL, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_LIST); + while (members_node != NULL) { + + fprintf(binding->outfile,"\t/**** %s ****/\n", interface); + + /* for each function emit a JSAPI_FS()*/ + webidl_node_for_each_type(webidl_node_getnode(members_node), + WEBIDL_NODE_TYPE_OPERATION, + webidl_func_spec_cb, + binding); + + members_node = webidl_node_find(webidl_node_getnode(interface_node), + members_node, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_LIST); + } + + /* check for inherited nodes and insert them too */ + inherit_node = webidl_node_find(webidl_node_getnode(interface_node), + NULL, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); + + if (inherit_node != NULL) { + res = generate_function_spec(binding, + webidl_node_gettext(inherit_node)); + } + + if (res == 0) { + res = webidl_node_for_each_type(webidl_node_getnode(interface_node), + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, + webidl_function_spec_implements_cb, + binding); + } + + return res; +} + +int output_function_spec(struct binding *binding) +{ + int res; + + fprintf(binding->outfile, + "static JSFunctionSpec jsclass_functions[] = {\n"); + + res = generate_function_spec(binding, binding->interface); + + fprintf(binding->outfile, "\tJSAPI_FS_END\n};\n\n"); + + return res; +} + +static int output_return(struct binding *binding, + const char *ident, + struct webidl_node *node) +{ + struct webidl_node *arglist_node = NULL; + struct webidl_node *type_node = NULL; + struct webidl_node *type_base = NULL; + enum webidl_type webidl_arg_type; + + arglist_node = webidl_node_find_type(node, + NULL, + WEBIDL_NODE_TYPE_LIST); + + if (arglist_node == NULL) { + return -1; /* @todo check if this is broken AST */ + } + + type_node = webidl_node_find_type(webidl_node_getnode(arglist_node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + type_base = webidl_node_find_type(webidl_node_getnode(type_node), + NULL, + WEBIDL_NODE_TYPE_TYPE_BASE); + + webidl_arg_type = webidl_node_getint(type_base); + + switch (webidl_arg_type) { + case WEBIDL_TYPE_USER: + /* User type are represented with jsobject */ + fprintf(binding->outfile, + "\tJSAPI_FUNC_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(%s));\n", + ident); + + break; + + case WEBIDL_TYPE_BOOL: + /* JSBool */ + fprintf(binding->outfile, + "\tJSAPI_FUNC_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(%s));\n", + ident); + + break; + + case WEBIDL_TYPE_BYTE: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_BYTE"); + break; + + case WEBIDL_TYPE_OCTET: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_OCTET"); + break; + + case WEBIDL_TYPE_FLOAT: + case WEBIDL_TYPE_DOUBLE: + /* double */ + fprintf(binding->outfile, + "\tJSAPI_FUNC_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(%s));\n", + ident); + break; + + case WEBIDL_TYPE_SHORT: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_SHORT"); + break; + + case WEBIDL_TYPE_LONGLONG: + WARN(WARNING_UNIMPLEMENTED, + "Unhandled type WEBIDL_TYPE_LONGLONG"); + break; + + case WEBIDL_TYPE_LONG: + /* int32_t */ + fprintf(binding->outfile, + "\tJSAPI_FUNC_SET_RVAL(cx, vp, INT_TO_JSVAL(%s));\n", + ident); + break; + + case WEBIDL_TYPE_STRING: + /* JSString * */ + fprintf(binding->outfile, + "\tJSAPI_FUNC_SET_RVAL(cx, vp, JSAPI_STRING_TO_JSVAL(%s));\n", + ident); + break; + + case WEBIDL_TYPE_SEQUENCE: + WARN(WARNING_UNIMPLEMENTED, + "Unhandled type WEBIDL_TYPE_SEQUENCE"); + break; + + case WEBIDL_TYPE_OBJECT: + /* JSObject * */ + fprintf(binding->outfile, + "\tJSAPI_FUNC_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(%s));\n", + ident); + break; + + case WEBIDL_TYPE_DATE: + WARN(WARNING_UNIMPLEMENTED, + "Unhandled type WEBIDL_TYPE_DATE"); + break; + + case WEBIDL_TYPE_VOID: + /* specifically requires no value */ + break; + + default: + break; + } + + return 0; +} + + +/* generate variable declaration of the correct type with appropriate default */ +static int output_return_declaration(struct binding *binding, + const char *ident, + struct webidl_node *node) +{ + struct webidl_node *arglist_node = NULL; + struct webidl_node *type_node = NULL; + struct webidl_node *type_name = NULL; + struct webidl_node *type_base = NULL; + enum webidl_type webidl_arg_type; + struct webidl_node *type_mod = NULL; + + arglist_node = webidl_node_find_type(node, + NULL, + WEBIDL_NODE_TYPE_LIST); + + if (arglist_node == NULL) { + return -1; /* @todo check if this is broken AST */ + } + + type_node = webidl_node_find_type(webidl_node_getnode(arglist_node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + type_base = webidl_node_find_type(webidl_node_getnode(type_node), + NULL, + WEBIDL_NODE_TYPE_TYPE_BASE); + + webidl_arg_type = webidl_node_getint(type_base); + + + switch (webidl_arg_type) { + case WEBIDL_TYPE_USER: + /* User type are represented with jsobject */ + type_name = webidl_node_find_type(webidl_node_getnode(type_node), + NULL, + WEBIDL_NODE_TYPE_IDENT); + fprintf(binding->outfile, + "\tJSObject *%s = NULL; /* %s */\n", + ident, + webidl_node_gettext(type_name)); + + break; + + case WEBIDL_TYPE_BOOL: + /* JSBool */ + fprintf(binding->outfile, "\tJSBool %s = JS_FALSE;\n",ident); + + break; + + case WEBIDL_TYPE_BYTE: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_BYTE"); + break; + + case WEBIDL_TYPE_OCTET: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_OCTET"); + break; + + case WEBIDL_TYPE_FLOAT: + case WEBIDL_TYPE_DOUBLE: + /* double */ + fprintf(binding->outfile, "\tdouble %s = 0;\n", ident); + break; + + case WEBIDL_TYPE_SHORT: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_SHORT"); + break; + + case WEBIDL_TYPE_LONGLONG: + WARN(WARNING_UNIMPLEMENTED, + "Unhandled type WEBIDL_TYPE_LONGLONG"); + break; + + case WEBIDL_TYPE_LONG: + /* int32_t */ + type_mod = webidl_node_find_type(webidl_node_getnode(type_node), + NULL, + WEBIDL_NODE_TYPE_MODIFIER); + if ((type_mod != NULL) && + (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { + fprintf(binding->outfile, "\tuint32_t %s = 0;\n", ident); + } else { + fprintf(binding->outfile, "\tint32_t %s = 0;\n", ident); + } + break; + + case WEBIDL_TYPE_STRING: + /* JSString * */ + fprintf(binding->outfile, + "\tJSString *%s = NULL;\n", + ident); + break; + + case WEBIDL_TYPE_SEQUENCE: + WARN(WARNING_UNIMPLEMENTED, + "Unhandled type WEBIDL_TYPE_SEQUENCE"); + break; + + case WEBIDL_TYPE_OBJECT: + /* JSObject * */ + fprintf(binding->outfile, "\tJSObject *%s = NULL;\n", ident); + break; + + case WEBIDL_TYPE_DATE: + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_DATE"); + break; + + case WEBIDL_TYPE_VOID: + /* specifically requires no value */ + break; + + default: + break; + } + return 0; +} + +/** creates all the variable definitions + * + * generate functions variables (including return value) with default + * values as appropriate + */ +static void +output_variable_definitions(struct binding *binding, + struct webidl_node *operation_list) +{ + struct webidl_node *operation_ident; + struct webidl_node *arglist_node; + struct webidl_node *arglist; /* argument list */ + struct webidl_node *arg_node = NULL; + struct webidl_node *arg_ident = NULL; + struct webidl_node *arg_type = NULL; + struct webidl_node *arg_type_base = NULL; + struct webidl_node *arg_type_ident = NULL; + enum webidl_type webidl_arg_type; + struct webidl_node *type_mod = NULL; + + /* input variables */ + arglist_node = webidl_node_find_type(operation_list, + NULL, + WEBIDL_NODE_TYPE_LIST); + + if (arglist_node == NULL) { + return; /* @todo check if this is broken AST */ + } + + arglist = webidl_node_getnode(arglist_node); + + arg_node = webidl_node_find_type(arglist, + arg_node, + WEBIDL_NODE_TYPE_ARGUMENT); + + /* at least one argument or private need to generate argv variable */ + if ((arg_node != NULL) || binding->has_private) { + fprintf(binding->outfile, + "\tjsval *argv = JSAPI_FUNC_ARGV(cx, vp);\n"); + } + + while (arg_node != NULL) { + /* generate variable to hold the argument */ + arg_ident = webidl_node_find_type(webidl_node_getnode(arg_node), + NULL, + WEBIDL_NODE_TYPE_IDENT); + + arg_type = webidl_node_find_type(webidl_node_getnode(arg_node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + arg_type_base = webidl_node_find_type(webidl_node_getnode(arg_type), + NULL, + WEBIDL_NODE_TYPE_TYPE_BASE); + + webidl_arg_type = webidl_node_getint(arg_type_base); + + switch (webidl_arg_type) { + case WEBIDL_TYPE_USER: + if (options->verbose) { + + operation_ident = webidl_node_find_type(operation_list, + NULL, + WEBIDL_NODE_TYPE_IDENT); + + arg_type_ident = webidl_node_find_type(webidl_node_getnode(arg_type), + NULL, + WEBIDL_NODE_TYPE_IDENT); + + fprintf(stderr, + "User type: %s:%s %s\n", + webidl_node_gettext(operation_ident), + webidl_node_gettext(arg_type_ident), + webidl_node_gettext(arg_ident)); + } + /* User type - jsobject then */ + fprintf(binding->outfile, + "\tJSObject *%s = NULL;\n", + webidl_node_gettext(arg_ident)); + + break; + + case WEBIDL_TYPE_BOOL: + /* JSBool */ + fprintf(binding->outfile, + "\tJSBool %s = JS_FALSE;\n", + webidl_node_gettext(arg_ident)); + + break; + + case WEBIDL_TYPE_BYTE: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_BYTE\n"); + break; + + case WEBIDL_TYPE_OCTET: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_OCTET\n"); + break; + + case WEBIDL_TYPE_FLOAT: + case WEBIDL_TYPE_DOUBLE: + /* double */ + fprintf(binding->outfile, + "\tdouble %s = 0;\n", + webidl_node_gettext(arg_ident)); + break; + + case WEBIDL_TYPE_SHORT: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_SHORT\n"); + break; + + case WEBIDL_TYPE_LONGLONG: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_LONGLONG\n"); + break; + + case WEBIDL_TYPE_LONG: + /* int32_t */ + type_mod = webidl_node_find_type(webidl_node_getnode(arg_type), + NULL, + WEBIDL_NODE_TYPE_MODIFIER); + if ((type_mod != NULL) && + (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { + fprintf(binding->outfile, + "\tuint32_t %s = 0;\n", + webidl_node_gettext(arg_ident)); + } else { + fprintf(binding->outfile, + "\tint32_t %s = 0;\n", + webidl_node_gettext(arg_ident)); + } + + break; + + case WEBIDL_TYPE_STRING: + /* JSString * */ + fprintf(binding->outfile, + "\tJSString *%s_jsstr = NULL;\n" + "\tint %s_len = 0;\n" + "\tchar *%s = NULL;\n", + webidl_node_gettext(arg_ident), + webidl_node_gettext(arg_ident), + webidl_node_gettext(arg_ident)); + break; + + case WEBIDL_TYPE_SEQUENCE: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_SEQUENCE\n"); + break; + + case WEBIDL_TYPE_OBJECT: + /* JSObject * */ + fprintf(binding->outfile, + "\tJSObject *%s = NULL;\n", + webidl_node_gettext(arg_ident)); + break; + + case WEBIDL_TYPE_DATE: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_DATE\n"); + break; + + case WEBIDL_TYPE_VOID: + fprintf(stderr, "Unsupported: WEBIDL_TYPE_VOID\n"); + break; + + default: + break; + } + + + /* next argument */ + arg_node = webidl_node_find_type(arglist, + arg_node, + WEBIDL_NODE_TYPE_ARGUMENT); + } + +} + +/** generate code to process operation input from javascript */ +static void +output_operation_input(struct binding *binding, + struct webidl_node *operation_list) +{ + struct webidl_node *arglist_node; + struct webidl_node *arglist; /* argument list */ + struct webidl_node *arg_node = NULL; + struct webidl_node *arg_ident = NULL; + struct webidl_node *arg_type = NULL; + struct webidl_node *arg_type_base = NULL; + struct webidl_node *type_mod = NULL; + enum webidl_type webidl_arg_type; + + int arg_cur = 0; /* current position in the input argument vector */ + + /* input variables */ + arglist_node = webidl_node_find_type(operation_list, + NULL, + WEBIDL_NODE_TYPE_LIST); + + if (arglist_node == NULL) { + return; /* @todo check if this is broken AST */ + } + + arglist = webidl_node_getnode(arglist_node); + + arg_node = webidl_node_find_type(arglist, + arg_node, + WEBIDL_NODE_TYPE_ARGUMENT); + while (arg_node != NULL) { + /* generate variable to hold the argument */ + arg_ident = webidl_node_find_type(webidl_node_getnode(arg_node), + NULL, + WEBIDL_NODE_TYPE_IDENT); + + arg_type = webidl_node_find_type(webidl_node_getnode(arg_node), + NULL, + WEBIDL_NODE_TYPE_TYPE); + + arg_type_base = webidl_node_find_type(webidl_node_getnode(arg_type), + NULL, + WEBIDL_NODE_TYPE_TYPE_BASE); + + webidl_arg_type = webidl_node_getint(arg_type_base); + + switch (webidl_arg_type) { + case WEBIDL_TYPE_USER: + fprintf(binding->outfile, + "\tif (!JSAPI_JSVAL_IS_OBJECT(argv[%d])) {\n" + "\t\tJSType argtype;\n" + "\t\targtype = JS_TypeOfValue(cx, argv[%d]);\n" + "\t\tJSLOG(\"User argument is type %%s not an object\", JS_GetTypeName(cx, argtype));\n" + "\t\treturn JS_FALSE;\n" + "\t}\n" + "\t%s = JSVAL_TO_OBJECT(argv[%d]);\n", + arg_cur, + arg_cur, + webidl_node_gettext(arg_ident), + arg_cur); + break; + + case WEBIDL_TYPE_BOOL: + /* JSBool */ + fprintf(binding->outfile, + "\tif (!JS_ValueToBoolean(cx, argv[%d], &%s)) {\n" + "\t\treturn JS_FALSE;\n" + "\t}\n", + arg_cur, + webidl_node_gettext(arg_ident)); + + break; + + case WEBIDL_TYPE_BYTE: + case WEBIDL_TYPE_OCTET: + break; + + case WEBIDL_TYPE_FLOAT: + case WEBIDL_TYPE_DOUBLE: + /* double */ + fprintf(binding->outfile, + "\tdouble %s = 0;\n", + webidl_node_gettext(arg_ident)); + break; + + case WEBIDL_TYPE_SHORT: + case WEBIDL_TYPE_LONGLONG: + break; + + case WEBIDL_TYPE_LONG: + /* int32_t */ + type_mod = webidl_node_find_type(webidl_node_getnode(arg_type), + NULL, + WEBIDL_NODE_TYPE_MODIFIER); + if ((type_mod != NULL) && + (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { + fprintf(binding->outfile, + "\tJS_ValueToECMAUint32(cx, argv[%d], &%s);\n", + arg_cur, + webidl_node_gettext(arg_ident)); + } else { + fprintf(binding->outfile, + "\tJS_ValueToECMAInt32(cx, argv[%d], &%s);\n", + arg_cur, + webidl_node_gettext(arg_ident)); + } + break; + + case WEBIDL_TYPE_STRING: + /* JSString * */ + fprintf(binding->outfile, + "\tif (argc > %d) {\n" + "\t\t%s_jsstr = JS_ValueToString(cx, argv[%d]);\n" + "\t} else {\n" + "\t\t%s_jsstr = JS_ValueToString(cx, JSVAL_VOID);\n" + "\t}\n" + "\tif (%s_jsstr != NULL) {\n" + "\t\tJSString_to_char(%s_jsstr, %s, %s_len);\n" + "\t}\n\n", + arg_cur, + webidl_node_gettext(arg_ident), + arg_cur, + webidl_node_gettext(arg_ident), + webidl_node_gettext(arg_ident), + webidl_node_gettext(arg_ident), + webidl_node_gettext(arg_ident), + webidl_node_gettext(arg_ident)); + + break; + + case WEBIDL_TYPE_SEQUENCE: + break; + + case WEBIDL_TYPE_OBJECT: + /* JSObject * */ + fprintf(binding->outfile, + "\tJSObject *%s = NULL;\n", + webidl_node_gettext(arg_ident)); + break; + + case WEBIDL_TYPE_DATE: + case WEBIDL_TYPE_VOID: + break; + + default: + break; + } + + + /* next argument */ + arg_node = webidl_node_find_type(arglist, + arg_node, + WEBIDL_NODE_TYPE_ARGUMENT); + + arg_cur++; + } + + +} + +static int +output_operator_placeholder(struct binding *binding, + struct webidl_node *oplist, + struct webidl_node *ident_node) +{ + oplist = oplist; + + WARN(WARNING_UNIMPLEMENTED, + "operation %s.%s has no implementation\n", + binding->interface, + webidl_node_gettext(ident_node)); + + if (options->dbglog) { + fprintf(binding->outfile, + "\tJSLOG(\"operation %s.%s has no implementation\");\n", + binding->interface, + webidl_node_gettext(ident_node)); + } + + return 0; +} + + +/* generate context data fetcher if the binding has private data */ +static inline int +output_private_get(struct binding *binding, const char *argname) +{ + int ret = 0; + + if (binding->has_private) { + + ret = fprintf(binding->outfile, + "\tstruct jsclass_private *%s;\n" + "\n" + "\t%s = JS_GetInstancePrivate(cx,\n" + "\t\t\tJSAPI_THIS_OBJECT(cx,vp),\n" + "\t\t\t&JSClass_%s,\n" + "\t\t\targv);\n" + "\tif (%s == NULL) {\n" + "\t\treturn JS_FALSE;\n" + "\t}\n\n", + argname, argname, binding->interface, argname); + + if (options->dbglog) { + ret += fprintf(binding->outfile, + "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, JSAPI_THIS_OBJECT(cx,vp), %s);\n", argname); + } + } else { + if (options->dbglog) { + ret += fprintf(binding->outfile, + "\tJSLOG(\"jscontext:%%p jsobject:%%p\", cx, JSAPI_THIS_OBJECT(cx,vp));\n"); + } + + } + + return ret; +} + +static int webidl_operator_body_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + struct webidl_node *ident_node; + struct genbind_node *operation_node; + + ident_node = webidl_node_find(webidl_node_getnode(node), + NULL, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_IDENT); + + if (ident_node == NULL) { + /* operation without identifier - must have special keyword + * http://www.w3.org/TR/WebIDL/#idl-operations + */ + WARN(WARNING_UNIMPLEMENTED, + "Unhandled operation with no name on %s\n", + binding->interface); + + } else { + /* normal operation with identifier */ + + fprintf(binding->outfile, + "static JSBool JSAPI_FUNC(%s, JSContext *cx, uintN argc, jsval *vp)\n", + webidl_node_gettext(ident_node)); + fprintf(binding->outfile, + "{\n"); + + /* return value declaration */ + output_return_declaration(binding, "jsret", webidl_node_getnode(node)); + + output_variable_definitions(binding, webidl_node_getnode(node)); + + output_private_get(binding, "private"); + + output_operation_input(binding, webidl_node_getnode(node)); + + operation_node = genbind_node_find_type_ident(binding->gb_ast, + NULL, + GENBIND_NODE_TYPE_OPERATION, + webidl_node_gettext(ident_node)); + + if (operation_node != NULL) { + output_code_block(binding, + genbind_node_getnode(operation_node)); + + } else { + output_operator_placeholder(binding, webidl_node_getnode(node), ident_node); + } + + output_return(binding, "jsret", webidl_node_getnode(node)); + + /* set return value an return true */ + fprintf(binding->outfile, + "\treturn JS_TRUE;\n" + "}\n\n"); + } + return 0; +} + +/* callback to emit implements operator bodys */ +static int webidl_implements_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + + return output_function_body(binding, webidl_node_gettext(node)); +} + +/* exported interface documented in jsapi-libdom.h */ +int +output_function_body(struct binding *binding, const char *interface) +{ + struct webidl_node *interface_node; + struct webidl_node *members_node; + struct webidl_node *inherit_node; + int res = 0; + + /* find interface in webidl with correct ident attached */ + interface_node = webidl_node_find_type_ident(binding->wi_ast, + WEBIDL_NODE_TYPE_INTERFACE, + interface); + + if (interface_node == NULL) { + fprintf(stderr, + "Unable to find interface %s in loaded WebIDL\n", + interface); + return -1; + } + + members_node = webidl_node_find(webidl_node_getnode(interface_node), + NULL, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_LIST); + while (members_node != NULL) { + + fprintf(binding->outfile,"/**** %s ****/\n", interface); + + /* for each function emit a JSAPI_FS()*/ + webidl_node_for_each_type(webidl_node_getnode(members_node), + WEBIDL_NODE_TYPE_OPERATION, + webidl_operator_body_cb, + binding); + + members_node = webidl_node_find(webidl_node_getnode(interface_node), + members_node, + webidl_cmp_node_type, + (void *)WEBIDL_NODE_TYPE_LIST); + } + + /* check for inherited nodes and insert them too */ + inherit_node = webidl_node_find_type(webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); + + if (inherit_node != NULL) { + res = output_function_body(binding, + webidl_node_gettext(inherit_node)); + } + + if (res == 0) { + res = webidl_node_for_each_type(webidl_node_getnode(interface_node), + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, + webidl_implements_cb, + binding); + } + + return res; +} diff --git a/src/jsapi-libdom-operator.c b/src/jsapi-libdom-operator.c deleted file mode 100644 index 1d16afe..0000000 --- a/src/jsapi-libdom-operator.c +++ /dev/null @@ -1,878 +0,0 @@ -/* function/operator generation - * - * This file is part of nsgenbind. - * Licensed under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2012 Vincent Sanders - */ - -#include -#include -#include -#include -#include - -#include "options.h" -#include "nsgenbind-ast.h" -#include "webidl-ast.h" -#include "jsapi-libdom.h" - -static int webidl_func_spec_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - struct webidl_node *ident_node; - - ident_node = webidl_node_find(webidl_node_getnode(node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_IDENT); - - if (ident_node == NULL) { - /* operation without identifier - must have special keyword - * http://www.w3.org/TR/WebIDL/#idl-operations - */ - } else { - fprintf(binding->outfile, - "\tJSAPI_FS(%s, 0, JSPROP_ENUMERATE ),\n", - webidl_node_gettext(ident_node)); - /* @todo number of args to that FN_FS() call should be correct */ - } - return 0; -} - - -static int generate_function_spec(struct binding *binding, const char *interface); - -/* callback to emit implements operator spec */ -static int webidl_function_spec_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return generate_function_spec(binding, webidl_node_gettext(node)); -} - -static int -generate_function_spec(struct binding *binding, const char *interface) -{ - struct webidl_node *interface_node; - struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } - - members_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - - fprintf(binding->outfile,"\t/**** %s ****/\n", interface); - - /* for each function emit a JSAPI_FS()*/ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_OPERATION, - webidl_func_spec_cb, - binding); - - members_node = webidl_node_find(webidl_node_getnode(interface_node), - members_node, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); - } - - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); - - if (inherit_node != NULL) { - res = generate_function_spec(binding, - webidl_node_gettext(inherit_node)); - } - - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_function_spec_implements_cb, - binding); - } - - return res; -} - -int output_function_spec(struct binding *binding) -{ - int res; - - fprintf(binding->outfile, - "static JSFunctionSpec jsclass_functions[] = {\n"); - - res = generate_function_spec(binding, binding->interface); - - fprintf(binding->outfile, "\tJSAPI_FS_END\n};\n\n"); - - return res; -} - -static int output_return(struct binding *binding, - const char *ident, - struct webidl_node *node) -{ - struct webidl_node *arglist_node = NULL; - struct webidl_node *type_node = NULL; - struct webidl_node *type_base = NULL; - enum webidl_type webidl_arg_type; - - arglist_node = webidl_node_find_type(node, - NULL, - WEBIDL_NODE_TYPE_LIST); - - if (arglist_node == NULL) { - return -1; /* @todo check if this is broken AST */ - } - - type_node = webidl_node_find_type(webidl_node_getnode(arglist_node), - NULL, - WEBIDL_NODE_TYPE_TYPE); - - type_base = webidl_node_find_type(webidl_node_getnode(type_node), - NULL, - WEBIDL_NODE_TYPE_TYPE_BASE); - - webidl_arg_type = webidl_node_getint(type_base); - - switch (webidl_arg_type) { - case WEBIDL_TYPE_USER: - /* User type are represented with jsobject */ - fprintf(binding->outfile, - "\tJSAPI_FUNC_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(%s));\n", - ident); - - break; - - case WEBIDL_TYPE_BOOL: - /* JSBool */ - fprintf(binding->outfile, - "\tJSAPI_FUNC_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(%s));\n", - ident); - - break; - - case WEBIDL_TYPE_BYTE: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_BYTE"); - break; - - case WEBIDL_TYPE_OCTET: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_OCTET"); - break; - - case WEBIDL_TYPE_FLOAT: - case WEBIDL_TYPE_DOUBLE: - /* double */ - fprintf(binding->outfile, - "\tJSAPI_FUNC_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(%s));\n", - ident); - break; - - case WEBIDL_TYPE_SHORT: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_SHORT"); - break; - - case WEBIDL_TYPE_LONGLONG: - WARN(WARNING_UNIMPLEMENTED, - "Unhandled type WEBIDL_TYPE_LONGLONG"); - break; - - case WEBIDL_TYPE_LONG: - /* int32_t */ - fprintf(binding->outfile, - "\tJSAPI_FUNC_SET_RVAL(cx, vp, INT_TO_JSVAL(%s));\n", - ident); - break; - - case WEBIDL_TYPE_STRING: - /* JSString * */ - fprintf(binding->outfile, - "\tJSAPI_FUNC_SET_RVAL(cx, vp, JSAPI_STRING_TO_JSVAL(%s));\n", - ident); - break; - - case WEBIDL_TYPE_SEQUENCE: - WARN(WARNING_UNIMPLEMENTED, - "Unhandled type WEBIDL_TYPE_SEQUENCE"); - break; - - case WEBIDL_TYPE_OBJECT: - /* JSObject * */ - fprintf(binding->outfile, - "\tJSAPI_FUNC_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(%s));\n", - ident); - break; - - case WEBIDL_TYPE_DATE: - WARN(WARNING_UNIMPLEMENTED, - "Unhandled type WEBIDL_TYPE_DATE"); - break; - - case WEBIDL_TYPE_VOID: - /* specifically requires no value */ - break; - - default: - break; - } - - return 0; -} - - -/* generate variable declaration of the correct type with appropriate default */ -static int output_return_declaration(struct binding *binding, - const char *ident, - struct webidl_node *node) -{ - struct webidl_node *arglist_node = NULL; - struct webidl_node *type_node = NULL; - struct webidl_node *type_name = NULL; - struct webidl_node *type_base = NULL; - enum webidl_type webidl_arg_type; - struct webidl_node *type_mod = NULL; - - arglist_node = webidl_node_find_type(node, - NULL, - WEBIDL_NODE_TYPE_LIST); - - if (arglist_node == NULL) { - return -1; /* @todo check if this is broken AST */ - } - - type_node = webidl_node_find_type(webidl_node_getnode(arglist_node), - NULL, - WEBIDL_NODE_TYPE_TYPE); - - type_base = webidl_node_find_type(webidl_node_getnode(type_node), - NULL, - WEBIDL_NODE_TYPE_TYPE_BASE); - - webidl_arg_type = webidl_node_getint(type_base); - - - switch (webidl_arg_type) { - case WEBIDL_TYPE_USER: - /* User type are represented with jsobject */ - type_name = webidl_node_find_type(webidl_node_getnode(type_node), - NULL, - WEBIDL_NODE_TYPE_IDENT); - fprintf(binding->outfile, - "\tJSObject *%s = NULL; /* %s */\n", - ident, - webidl_node_gettext(type_name)); - - break; - - case WEBIDL_TYPE_BOOL: - /* JSBool */ - fprintf(binding->outfile, "\tJSBool %s = JS_FALSE;\n",ident); - - break; - - case WEBIDL_TYPE_BYTE: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_BYTE"); - break; - - case WEBIDL_TYPE_OCTET: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_OCTET"); - break; - - case WEBIDL_TYPE_FLOAT: - case WEBIDL_TYPE_DOUBLE: - /* double */ - fprintf(binding->outfile, "\tdouble %s = 0;\n", ident); - break; - - case WEBIDL_TYPE_SHORT: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_SHORT"); - break; - - case WEBIDL_TYPE_LONGLONG: - WARN(WARNING_UNIMPLEMENTED, - "Unhandled type WEBIDL_TYPE_LONGLONG"); - break; - - case WEBIDL_TYPE_LONG: - /* int32_t */ - type_mod = webidl_node_find_type(webidl_node_getnode(type_node), - NULL, - WEBIDL_NODE_TYPE_MODIFIER); - if ((type_mod != NULL) && - (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { - fprintf(binding->outfile, "\tuint32_t %s = 0;\n", ident); - } else { - fprintf(binding->outfile, "\tint32_t %s = 0;\n", ident); - } - break; - - case WEBIDL_TYPE_STRING: - /* JSString * */ - fprintf(binding->outfile, - "\tJSString *%s = NULL;\n", - ident); - break; - - case WEBIDL_TYPE_SEQUENCE: - WARN(WARNING_UNIMPLEMENTED, - "Unhandled type WEBIDL_TYPE_SEQUENCE"); - break; - - case WEBIDL_TYPE_OBJECT: - /* JSObject * */ - fprintf(binding->outfile, "\tJSObject *%s = NULL;\n", ident); - break; - - case WEBIDL_TYPE_DATE: - WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_DATE"); - break; - - case WEBIDL_TYPE_VOID: - /* specifically requires no value */ - break; - - default: - break; - } - return 0; -} - -/** creates all the variable definitions - * - * generate functions variables (including return value) with default - * values as appropriate - */ -static void -output_variable_definitions(struct binding *binding, - struct webidl_node *operation_list) -{ - struct webidl_node *operation_ident; - struct webidl_node *arglist_node; - struct webidl_node *arglist; /* argument list */ - struct webidl_node *arg_node = NULL; - struct webidl_node *arg_ident = NULL; - struct webidl_node *arg_type = NULL; - struct webidl_node *arg_type_base = NULL; - struct webidl_node *arg_type_ident = NULL; - enum webidl_type webidl_arg_type; - struct webidl_node *type_mod = NULL; - - /* input variables */ - arglist_node = webidl_node_find_type(operation_list, - NULL, - WEBIDL_NODE_TYPE_LIST); - - if (arglist_node == NULL) { - return; /* @todo check if this is broken AST */ - } - - arglist = webidl_node_getnode(arglist_node); - - arg_node = webidl_node_find_type(arglist, - arg_node, - WEBIDL_NODE_TYPE_ARGUMENT); - - /* at least one argument or private need to generate argv variable */ - if ((arg_node != NULL) || binding->has_private) { - fprintf(binding->outfile, - "\tjsval *argv = JSAPI_FUNC_ARGV(cx, vp);\n"); - } - - while (arg_node != NULL) { - /* generate variable to hold the argument */ - arg_ident = webidl_node_find_type(webidl_node_getnode(arg_node), - NULL, - WEBIDL_NODE_TYPE_IDENT); - - arg_type = webidl_node_find_type(webidl_node_getnode(arg_node), - NULL, - WEBIDL_NODE_TYPE_TYPE); - - arg_type_base = webidl_node_find_type(webidl_node_getnode(arg_type), - NULL, - WEBIDL_NODE_TYPE_TYPE_BASE); - - webidl_arg_type = webidl_node_getint(arg_type_base); - - switch (webidl_arg_type) { - case WEBIDL_TYPE_USER: - if (options->verbose) { - - operation_ident = webidl_node_find_type(operation_list, - NULL, - WEBIDL_NODE_TYPE_IDENT); - - arg_type_ident = webidl_node_find_type(webidl_node_getnode(arg_type), - NULL, - WEBIDL_NODE_TYPE_IDENT); - - fprintf(stderr, - "User type: %s:%s %s\n", - webidl_node_gettext(operation_ident), - webidl_node_gettext(arg_type_ident), - webidl_node_gettext(arg_ident)); - } - /* User type - jsobject then */ - fprintf(binding->outfile, - "\tJSObject *%s = NULL;\n", - webidl_node_gettext(arg_ident)); - - break; - - case WEBIDL_TYPE_BOOL: - /* JSBool */ - fprintf(binding->outfile, - "\tJSBool %s = JS_FALSE;\n", - webidl_node_gettext(arg_ident)); - - break; - - case WEBIDL_TYPE_BYTE: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_BYTE\n"); - break; - - case WEBIDL_TYPE_OCTET: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_OCTET\n"); - break; - - case WEBIDL_TYPE_FLOAT: - case WEBIDL_TYPE_DOUBLE: - /* double */ - fprintf(binding->outfile, - "\tdouble %s = 0;\n", - webidl_node_gettext(arg_ident)); - break; - - case WEBIDL_TYPE_SHORT: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_SHORT\n"); - break; - - case WEBIDL_TYPE_LONGLONG: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_LONGLONG\n"); - break; - - case WEBIDL_TYPE_LONG: - /* int32_t */ - type_mod = webidl_node_find_type(webidl_node_getnode(arg_type), - NULL, - WEBIDL_NODE_TYPE_MODIFIER); - if ((type_mod != NULL) && - (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { - fprintf(binding->outfile, - "\tuint32_t %s = 0;\n", - webidl_node_gettext(arg_ident)); - } else { - fprintf(binding->outfile, - "\tint32_t %s = 0;\n", - webidl_node_gettext(arg_ident)); - } - - break; - - case WEBIDL_TYPE_STRING: - /* JSString * */ - fprintf(binding->outfile, - "\tJSString *%s_jsstr = NULL;\n" - "\tint %s_len = 0;\n" - "\tchar *%s = NULL;\n", - webidl_node_gettext(arg_ident), - webidl_node_gettext(arg_ident), - webidl_node_gettext(arg_ident)); - break; - - case WEBIDL_TYPE_SEQUENCE: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_SEQUENCE\n"); - break; - - case WEBIDL_TYPE_OBJECT: - /* JSObject * */ - fprintf(binding->outfile, - "\tJSObject *%s = NULL;\n", - webidl_node_gettext(arg_ident)); - break; - - case WEBIDL_TYPE_DATE: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_DATE\n"); - break; - - case WEBIDL_TYPE_VOID: - fprintf(stderr, "Unsupported: WEBIDL_TYPE_VOID\n"); - break; - - default: - break; - } - - - /* next argument */ - arg_node = webidl_node_find_type(arglist, - arg_node, - WEBIDL_NODE_TYPE_ARGUMENT); - } - -} - -/** generate code to process operation input from javascript */ -static void -output_operation_input(struct binding *binding, - struct webidl_node *operation_list) -{ - struct webidl_node *arglist_node; - struct webidl_node *arglist; /* argument list */ - struct webidl_node *arg_node = NULL; - struct webidl_node *arg_ident = NULL; - struct webidl_node *arg_type = NULL; - struct webidl_node *arg_type_base = NULL; - struct webidl_node *type_mod = NULL; - enum webidl_type webidl_arg_type; - - int arg_cur = 0; /* current position in the input argument vector */ - - /* input variables */ - arglist_node = webidl_node_find_type(operation_list, - NULL, - WEBIDL_NODE_TYPE_LIST); - - if (arglist_node == NULL) { - return; /* @todo check if this is broken AST */ - } - - arglist = webidl_node_getnode(arglist_node); - - arg_node = webidl_node_find_type(arglist, - arg_node, - WEBIDL_NODE_TYPE_ARGUMENT); - while (arg_node != NULL) { - /* generate variable to hold the argument */ - arg_ident = webidl_node_find_type(webidl_node_getnode(arg_node), - NULL, - WEBIDL_NODE_TYPE_IDENT); - - arg_type = webidl_node_find_type(webidl_node_getnode(arg_node), - NULL, - WEBIDL_NODE_TYPE_TYPE); - - arg_type_base = webidl_node_find_type(webidl_node_getnode(arg_type), - NULL, - WEBIDL_NODE_TYPE_TYPE_BASE); - - webidl_arg_type = webidl_node_getint(arg_type_base); - - switch (webidl_arg_type) { - case WEBIDL_TYPE_USER: - fprintf(binding->outfile, - "\tif (!JSAPI_JSVAL_IS_OBJECT(argv[%d])) {\n" - "\t\tJSType argtype;\n" - "\t\targtype = JS_TypeOfValue(cx, argv[%d]);\n" - "\t\tJSLOG(\"User argument is type %%s not an object\", JS_GetTypeName(cx, argtype));\n" - "\t\treturn JS_FALSE;\n" - "\t}\n" - "\t%s = JSVAL_TO_OBJECT(argv[%d]);\n", - arg_cur, - arg_cur, - webidl_node_gettext(arg_ident), - arg_cur); - break; - - case WEBIDL_TYPE_BOOL: - /* JSBool */ - fprintf(binding->outfile, - "\tif (!JS_ValueToBoolean(cx, argv[%d], &%s)) {\n" - "\t\treturn JS_FALSE;\n" - "\t}\n", - arg_cur, - webidl_node_gettext(arg_ident)); - - break; - - case WEBIDL_TYPE_BYTE: - case WEBIDL_TYPE_OCTET: - break; - - case WEBIDL_TYPE_FLOAT: - case WEBIDL_TYPE_DOUBLE: - /* double */ - fprintf(binding->outfile, - "\tdouble %s = 0;\n", - webidl_node_gettext(arg_ident)); - break; - - case WEBIDL_TYPE_SHORT: - case WEBIDL_TYPE_LONGLONG: - break; - - case WEBIDL_TYPE_LONG: - /* int32_t */ - type_mod = webidl_node_find_type(webidl_node_getnode(arg_type), - NULL, - WEBIDL_NODE_TYPE_MODIFIER); - if ((type_mod != NULL) && - (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { - fprintf(binding->outfile, - "\tJS_ValueToECMAUint32(cx, argv[%d], &%s);\n", - arg_cur, - webidl_node_gettext(arg_ident)); - } else { - fprintf(binding->outfile, - "\tJS_ValueToECMAInt32(cx, argv[%d], &%s);\n", - arg_cur, - webidl_node_gettext(arg_ident)); - } - break; - - case WEBIDL_TYPE_STRING: - /* JSString * */ - fprintf(binding->outfile, - "\tif (argc > %d) {\n" - "\t\t%s_jsstr = JS_ValueToString(cx, argv[%d]);\n" - "\t} else {\n" - "\t\t%s_jsstr = JS_ValueToString(cx, JSVAL_VOID);\n" - "\t}\n" - "\tif (%s_jsstr != NULL) {\n" - "\t\tJSString_to_char(%s_jsstr, %s, %s_len);\n" - "\t}\n\n", - arg_cur, - webidl_node_gettext(arg_ident), - arg_cur, - webidl_node_gettext(arg_ident), - webidl_node_gettext(arg_ident), - webidl_node_gettext(arg_ident), - webidl_node_gettext(arg_ident), - webidl_node_gettext(arg_ident)); - - break; - - case WEBIDL_TYPE_SEQUENCE: - break; - - case WEBIDL_TYPE_OBJECT: - /* JSObject * */ - fprintf(binding->outfile, - "\tJSObject *%s = NULL;\n", - webidl_node_gettext(arg_ident)); - break; - - case WEBIDL_TYPE_DATE: - case WEBIDL_TYPE_VOID: - break; - - default: - break; - } - - - /* next argument */ - arg_node = webidl_node_find_type(arglist, - arg_node, - WEBIDL_NODE_TYPE_ARGUMENT); - - arg_cur++; - } - - -} - -static int -output_operator_placeholder(struct binding *binding, - struct webidl_node *oplist, - struct webidl_node *ident_node) -{ - oplist = oplist; - - WARN(WARNING_UNIMPLEMENTED, - "operation %s.%s has no implementation\n", - binding->interface, - webidl_node_gettext(ident_node)); - - if (options->dbglog) { - fprintf(binding->outfile, - "\tJSLOG(\"operation %s.%s has no implementation\");\n", - binding->interface, - webidl_node_gettext(ident_node)); - } - - return 0; -} - - -/* generate context data fetcher if the binding has private data */ -static inline int -output_private_get(struct binding *binding, const char *argname) -{ - int ret = 0; - - if (binding->has_private) { - - ret = fprintf(binding->outfile, - "\tstruct jsclass_private *%s;\n" - "\n" - "\t%s = JS_GetInstancePrivate(cx,\n" - "\t\t\tJSAPI_THIS_OBJECT(cx,vp),\n" - "\t\t\t&JSClass_%s,\n" - "\t\t\targv);\n" - "\tif (%s == NULL) {\n" - "\t\treturn JS_FALSE;\n" - "\t}\n\n", - argname, argname, binding->interface, argname); - - if (options->dbglog) { - ret += fprintf(binding->outfile, - "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, JSAPI_THIS_OBJECT(cx,vp), %s);\n", argname); - } - } else { - if (options->dbglog) { - ret += fprintf(binding->outfile, - "\tJSLOG(\"jscontext:%%p jsobject:%%p\", cx, JSAPI_THIS_OBJECT(cx,vp));\n"); - } - - } - - return ret; -} - -static int webidl_operator_body_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - struct webidl_node *ident_node; - struct genbind_node *operation_node; - - ident_node = webidl_node_find(webidl_node_getnode(node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_IDENT); - - if (ident_node == NULL) { - /* operation without identifier - must have special keyword - * http://www.w3.org/TR/WebIDL/#idl-operations - */ - WARN(WARNING_UNIMPLEMENTED, - "Unhandled operation with no name on %s\n", - binding->interface); - - } else { - /* normal operation with identifier */ - - fprintf(binding->outfile, - "static JSBool JSAPI_FUNC(%s, JSContext *cx, uintN argc, jsval *vp)\n", - webidl_node_gettext(ident_node)); - fprintf(binding->outfile, - "{\n"); - - /* return value declaration */ - output_return_declaration(binding, "jsret", webidl_node_getnode(node)); - - output_variable_definitions(binding, webidl_node_getnode(node)); - - output_private_get(binding, "private"); - - output_operation_input(binding, webidl_node_getnode(node)); - - operation_node = genbind_node_find_type_ident(binding->gb_ast, - NULL, - GENBIND_NODE_TYPE_OPERATION, - webidl_node_gettext(ident_node)); - - if (operation_node != NULL) { - output_code_block(binding, - genbind_node_getnode(operation_node)); - - } else { - output_operator_placeholder(binding, webidl_node_getnode(node), ident_node); - } - - output_return(binding, "jsret", webidl_node_getnode(node)); - - /* set return value an return true */ - fprintf(binding->outfile, - "\treturn JS_TRUE;\n" - "}\n\n"); - } - return 0; -} - -/* callback to emit implements operator bodys */ -static int webidl_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return output_operator_body(binding, webidl_node_gettext(node)); -} - -/* exported interface documented in jsapi-libdom.h */ -int -output_operator_body(struct binding *binding, const char *interface) -{ - struct webidl_node *interface_node; - struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } - - members_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - - fprintf(binding->outfile,"/**** %s ****/\n", interface); - - /* for each function emit a JSAPI_FS()*/ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_OPERATION, - webidl_operator_body_cb, - binding); - - members_node = webidl_node_find(webidl_node_getnode(interface_node), - members_node, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); - } - - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find_type(webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); - - if (inherit_node != NULL) { - res = output_operator_body(binding, - webidl_node_gettext(inherit_node)); - } - - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_implements_cb, - binding); - } - - return res; -} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 895ccf4..bd1dbbe 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -897,7 +897,7 @@ build_interface_map(struct genbind_node *binding_node, int inf; interfaces[idx].inherit_idx = -1; for (inf = 0; inf < interfacec; inf++ ) { - /* cannot inherit from self. and name must match */ + /* cannot inherit from self and name must match */ if ((inf != idx) && (strcmp(interfaces[idx].inherit_name, interfaces[inf].name) == 0)) { @@ -1109,15 +1109,15 @@ jsapi_libdom_output(struct options *options, return 85; } - /* user code output just before function bodies emitted */ + /* user code output just before interface code bodies emitted */ res = output_prologue(binding); if (res) { return 89; } - /* operator and atrtribute body generation */ + /* method (function) and property body generation */ - res = output_operator_body(binding, binding->interface); + res = output_function_body(binding, binding->interface); if (res) { return 90; } @@ -1127,7 +1127,7 @@ jsapi_libdom_output(struct options *options, return 100; } - /* operator and atrtribute specifier generation */ + /* method (function) and property specifier generation */ res = output_function_spec(binding); if (res) { diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index bdf4bec..13a5276 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -18,6 +18,9 @@ struct binding_interface { const char *inherit_name; /* name of interface this inherits from */ int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ int refcount; /* number of entries in map that refer to this interface */ + int own_properties; /* the number of properties the interface has */ + int own_functions; /* the number of functions the interface has */ + }; struct binding { @@ -76,7 +79,7 @@ int output_function_spec(struct binding *binding); * @param binding The binding information * @param interface The interface to generate operator bodys for */ -int output_operator_body(struct binding *binding, const char *interface); +int output_function_body(struct binding *binding, const char *interface); /** generate property tinyid enum */ int output_property_tinyid(struct binding *binding); -- cgit v1.2.3 From 188c8f049581143a92e3a710203d9c1d6598056b Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 1 Jan 2014 18:31:37 +0000 Subject: add function and property enumerations to the interface map --- src/jsapi-libdom-function.c | 16 +++++++-------- src/jsapi-libdom-property.c | 14 ++++++++------ src/jsapi-libdom.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- src/webidl-ast.c | 20 +++++++++++++++++++ src/webidl-ast.h | 2 ++ 5 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/jsapi-libdom-function.c b/src/jsapi-libdom-function.c index 594a100..0196c58 100644 --- a/src/jsapi-libdom-function.c +++ b/src/jsapi-libdom-function.c @@ -837,10 +837,10 @@ output_function_body(struct binding *binding, const char *interface) return -1; } - members_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_LIST); while (members_node != NULL) { fprintf(binding->outfile,"/**** %s ****/\n", interface); @@ -851,10 +851,10 @@ output_function_body(struct binding *binding, const char *interface) webidl_operator_body_cb, binding); - members_node = webidl_node_find(webidl_node_getnode(interface_node), - members_node, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + members_node, + WEBIDL_NODE_TYPE_LIST); } /* check for inherited nodes and insert them too */ diff --git a/src/jsapi-libdom-property.c b/src/jsapi-libdom-property.c index 7e67bae..df296cf 100644 --- a/src/jsapi-libdom-property.c +++ b/src/jsapi-libdom-property.c @@ -986,9 +986,10 @@ generate_property_body(struct binding *binding, const char *interface) } /* generate property bodies */ - members_node = webidl_node_find_type(webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_LIST); while (members_node != NULL) { fprintf(binding->outfile,"/**** %s ****/\n", interface); @@ -1000,9 +1001,10 @@ generate_property_body(struct binding *binding, const char *interface) binding); - members_node = webidl_node_find_type(webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + members_node, + WEBIDL_NODE_TYPE_LIST); } diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index bd1dbbe..2edfc83 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -819,6 +819,33 @@ binding_has_private(struct genbind_node *binding_list) return false; } + +/** count the number of methods or properties for an interface */ +static int +enumerate_interface_own(struct webidl_node *interface_node, + enum webidl_node_type node_type) +{ + int count = 0; + struct webidl_node *members_node; + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_LIST); + while (members_node != NULL) { + count += webidl_node_enumerate_type( + webidl_node_getnode(members_node), + node_type); + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + members_node, + WEBIDL_NODE_TYPE_LIST); + } + + return count; +} + /* build interface map and return the first interface */ static struct genbind_node * build_interface_map(struct genbind_node *binding_node, @@ -881,6 +908,17 @@ build_interface_map(struct genbind_node *binding_node, return NULL; } + /* enumerate the number of functions */ + interfaces[idx].own_functions = enumerate_interface_own( + interfaces[idx].widl_node, + WEBIDL_NODE_TYPE_OPERATION); + + /* enumerate the number of properties */ + interfaces[idx].own_properties = enumerate_interface_own( + interfaces[idx].widl_node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + /* extract the name of the inherited interface (if any) */ interfaces[idx].inherit_name = webidl_node_gettext( webidl_node_find_type( webidl_node_getnode(interfaces[idx].widl_node), @@ -923,14 +961,19 @@ build_interface_map(struct genbind_node *binding_node, /* show the interface map */ if (options->verbose) { for (idx = 0; idx < interfacec; idx++ ) { - printf("interface num:%d name:%s node:%p widl:%p inherit:%s inherit idx:%d refcount:%d\n", + printf("interface num:%d\n" + " name:%s node:%p widl:%p\n" + " inherit:%s inherit idx:%d refcount:%d\n" + " own functions:%d own properties:%d\n", idx, interfaces[idx].name, interfaces[idx].node, interfaces[idx].widl_node, interfaces[idx].inherit_name, interfaces[idx].inherit_idx, - interfaces[idx].refcount); + interfaces[idx].refcount, + interfaces[idx].own_functions, + interfaces[idx].own_properties); } } diff --git a/src/webidl-ast.c b/src/webidl-ast.c index d75a186..8acb2fb 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -162,6 +162,26 @@ int webidl_cmp_node_type(struct webidl_node *node, void *ctx) return 0; } +static int webidl_enumerate_node(struct webidl_node *node, void *ctx) +{ + node = node; + (*((int *)ctx))++; + return 0; +} + +/* exported interface defined in nsgenbind-ast.h */ +int +webidl_node_enumerate_type(struct webidl_node *node, + enum webidl_node_type type) +{ + int count = 0; + webidl_node_for_each_type(node, + type, + webidl_enumerate_node, + &count); + return count; +} + /* exported interface defined in webidl-ast.h */ struct webidl_node * webidl_node_find(struct webidl_node *node, diff --git a/src/webidl-ast.h b/src/webidl-ast.h index 70518fd..eaa8d44 100644 --- a/src/webidl-ast.h +++ b/src/webidl-ast.h @@ -95,6 +95,8 @@ int webidl_node_for_each_type(struct webidl_node *node, webidl_callback_t *cb, void *ctx); +int webidl_node_enumerate_type(struct webidl_node *node, enum webidl_node_type type); + struct webidl_node * webidl_node_find(struct webidl_node *node, struct webidl_node *prev, -- cgit v1.2.3 From 202be5081e4b201a3937407b2aff3328139ef1a3 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 2 Jan 2014 13:13:20 +0000 Subject: generate function bodies for all interfaces --- src/jsapi-libdom-function.c | 208 +++++++++++++++++++++++++------------------- src/jsapi-libdom.c | 2 +- src/jsapi-libdom.h | 3 +- 3 files changed, 121 insertions(+), 92 deletions(-) diff --git a/src/jsapi-libdom-function.c b/src/jsapi-libdom-function.c index 0196c58..4970b48 100644 --- a/src/jsapi-libdom-function.c +++ b/src/jsapi-libdom-function.c @@ -17,6 +17,8 @@ #include "webidl-ast.h" #include "jsapi-libdom.h" +static int output_function_body(struct binding *binding, struct webidl_node *node); + static int webidl_func_spec_cb(struct webidl_node *node, void *ctx) { struct binding *binding = ctx; @@ -307,7 +309,7 @@ static int output_return_declaration(struct binding *binding, break; case WEBIDL_TYPE_LONGLONG: - WARN(WARNING_UNIMPLEMENTED, + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_LONGLONG"); break; @@ -316,7 +318,7 @@ static int output_return_declaration(struct binding *binding, type_mod = webidl_node_find_type(webidl_node_getnode(type_node), NULL, WEBIDL_NODE_TYPE_MODIFIER); - if ((type_mod != NULL) && + if ((type_mod != NULL) && (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { fprintf(binding->outfile, "\tuint32_t %s = 0;\n", ident); } else { @@ -332,7 +334,7 @@ static int output_return_declaration(struct binding *binding, break; case WEBIDL_TYPE_SEQUENCE: - WARN(WARNING_UNIMPLEMENTED, + WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_SEQUENCE"); break; @@ -474,14 +476,14 @@ output_variable_definitions(struct binding *binding, type_mod = webidl_node_find_type(webidl_node_getnode(arg_type), NULL, WEBIDL_NODE_TYPE_MODIFIER); - if ((type_mod != NULL) && + if ((type_mod != NULL) && (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { - fprintf(binding->outfile, - "\tuint32_t %s = 0;\n", + fprintf(binding->outfile, + "\tuint32_t %s = 0;\n", webidl_node_gettext(arg_ident)); } else { - fprintf(binding->outfile, - "\tint32_t %s = 0;\n", + fprintf(binding->outfile, + "\tint32_t %s = 0;\n", webidl_node_gettext(arg_ident)); } @@ -624,15 +626,15 @@ output_operation_input(struct binding *binding, type_mod = webidl_node_find_type(webidl_node_getnode(arg_type), NULL, WEBIDL_NODE_TYPE_MODIFIER); - if ((type_mod != NULL) && + if ((type_mod != NULL) && (webidl_node_getint(type_mod) == WEBIDL_TYPE_MODIFIER_UNSIGNED)) { - fprintf(binding->outfile, - "\tJS_ValueToECMAUint32(cx, argv[%d], &%s);\n", + fprintf(binding->outfile, + "\tJS_ValueToECMAUint32(cx, argv[%d], &%s);\n", arg_cur, webidl_node_gettext(arg_ident)); } else { - fprintf(binding->outfile, - "\tJS_ValueToECMAInt32(cx, argv[%d], &%s);\n", + fprintf(binding->outfile, + "\tJS_ValueToECMAInt32(cx, argv[%d], &%s);\n", arg_cur, webidl_node_gettext(arg_ident)); } @@ -690,14 +692,14 @@ output_operation_input(struct binding *binding, } -static int -output_operator_placeholder(struct binding *binding, - struct webidl_node *oplist, +static int +output_operator_placeholder(struct binding *binding, + struct webidl_node *oplist, struct webidl_node *ident_node) { oplist = oplist; - WARN(WARNING_UNIMPLEMENTED, + WARN(WARNING_UNIMPLEMENTED, "operation %s.%s has no implementation\n", binding->interface, webidl_node_gettext(ident_node)); @@ -748,103 +750,79 @@ output_private_get(struct binding *binding, const char *argname) return ret; } -static int webidl_operator_body_cb(struct webidl_node *node, void *ctx) +static int +webidl_operator_body_cb(struct webidl_node *node, void *ctx) { struct binding *binding = ctx; struct webidl_node *ident_node; struct genbind_node *operation_node; - ident_node = webidl_node_find(webidl_node_getnode(node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_IDENT); + ident_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_IDENT); if (ident_node == NULL) { /* operation without identifier - must have special keyword * http://www.w3.org/TR/WebIDL/#idl-operations */ WARN(WARNING_UNIMPLEMENTED, - "Unhandled operation with no name on %s\n", - binding->interface); + "Unhandled operation with no name on %s\n", + binding->interface); - } else { - /* normal operation with identifier */ - - fprintf(binding->outfile, - "static JSBool JSAPI_FUNC(%s, JSContext *cx, uintN argc, jsval *vp)\n", - webidl_node_gettext(ident_node)); - fprintf(binding->outfile, - "{\n"); + return 0; + } - /* return value declaration */ - output_return_declaration(binding, "jsret", webidl_node_getnode(node)); + /* normal operation with identifier */ - output_variable_definitions(binding, webidl_node_getnode(node)); + fprintf(binding->outfile, + "static JSBool JSAPI_FUNC(%s, JSContext *cx, uintN argc, jsval *vp)\n", + webidl_node_gettext(ident_node)); + fprintf(binding->outfile, "{\n"); - output_private_get(binding, "private"); + /* return value declaration */ + output_return_declaration(binding, "jsret", webidl_node_getnode(node)); - output_operation_input(binding, webidl_node_getnode(node)); + output_variable_definitions(binding, webidl_node_getnode(node)); - operation_node = genbind_node_find_type_ident(binding->gb_ast, - NULL, - GENBIND_NODE_TYPE_OPERATION, - webidl_node_gettext(ident_node)); + output_private_get(binding, "private"); - if (operation_node != NULL) { - output_code_block(binding, - genbind_node_getnode(operation_node)); + output_operation_input(binding, webidl_node_getnode(node)); - } else { - output_operator_placeholder(binding, webidl_node_getnode(node), ident_node); - } + operation_node = genbind_node_find_type_ident(binding->gb_ast, + NULL, + GENBIND_NODE_TYPE_OPERATION, + webidl_node_gettext(ident_node)); - output_return(binding, "jsret", webidl_node_getnode(node)); + if (operation_node != NULL) { + output_code_block(binding, + genbind_node_getnode(operation_node)); - /* set return value an return true */ - fprintf(binding->outfile, - "\treturn JS_TRUE;\n" - "}\n\n"); + } else { + output_operator_placeholder(binding, webidl_node_getnode(node), ident_node); } - return 0; -} -/* callback to emit implements operator bodys */ -static int webidl_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; + output_return(binding, "jsret", webidl_node_getnode(node)); - return output_function_body(binding, webidl_node_gettext(node)); + /* set return value an return true */ + fprintf(binding->outfile, + "\treturn JS_TRUE;\n" + "}\n\n"); + + return 0; } -/* exported interface documented in jsapi-libdom.h */ -int -output_function_body(struct binding *binding, const char *interface) +static int +output_interface_functions(struct binding *binding, + struct webidl_node *interface_node) { - struct webidl_node *interface_node; struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } members_node = webidl_node_find_type( webidl_node_getnode(interface_node), NULL, WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - - fprintf(binding->outfile,"/**** %s ****/\n", interface); + while (members_node != NULL) { /* for each function emit a JSAPI_FS()*/ webidl_node_for_each_type(webidl_node_getnode(members_node), WEBIDL_NODE_TYPE_OPERATION, @@ -856,23 +834,75 @@ output_function_body(struct binding *binding, const char *interface) members_node, WEBIDL_NODE_TYPE_LIST); } + return 0; +} + +/* callback to emit implements operator bodys */ +static int webidl_implements_cb(struct webidl_node *node, void *ctx) +{ + struct binding *binding = ctx; + struct webidl_node *interface_node; + + interface_node = webidl_node_find_type_ident(binding->wi_ast, + WEBIDL_NODE_TYPE_INTERFACE, + webidl_node_gettext(node)); + + return output_function_body(binding, interface_node); +} + +/* exported interface documented in jsapi-libdom.h */ +static int +output_function_body(struct binding *binding, + struct webidl_node *interface_node) +{ + struct webidl_node *inherit_node; + int res = 0; + + res = output_interface_functions(binding, interface_node); + + fprintf(binding->outfile, + "/**** %s ****/\n", + webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_IDENT))); /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find_type(webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); + inherit_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); if (inherit_node != NULL) { - res = output_function_body(binding, - webidl_node_gettext(inherit_node)); + res = webidl_implements_cb(inherit_node, binding); } if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_implements_cb, - binding); + res = webidl_node_for_each_type( + webidl_node_getnode(interface_node), + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, + webidl_implements_cb, + binding); } return res; } + +int +output_function_bodies(struct binding *binding) +{ + int inf; + int res; + + for (inf=0; inf < binding->interfacec; inf++) { + if (binding->interfaces[inf].inherit_idx == -1) { + res = output_function_body(binding, + binding->interfaces[inf].widl_node); + } else { + res = output_interface_functions(binding, + binding->interfaces[inf].widl_node); + } + } + return res; +} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 2edfc83..547e66e 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -1160,7 +1160,7 @@ jsapi_libdom_output(struct options *options, /* method (function) and property body generation */ - res = output_function_body(binding, binding->interface); + res = output_function_bodies(binding); if (res) { return 90; } diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index 13a5276..ce50589 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -77,9 +77,8 @@ int output_function_spec(struct binding *binding); * block in the binding definition. * * @param binding The binding information - * @param interface The interface to generate operator bodys for */ -int output_function_body(struct binding *binding, const char *interface); +int output_function_bodies(struct binding *binding); /** generate property tinyid enum */ int output_property_tinyid(struct binding *binding); -- cgit v1.2.3 From 26e5be085e5c7a17cea4af7cb9e13502ffb0ebd1 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 3 Jan 2014 02:07:11 +0000 Subject: complete implementation of interface map generation and split out to own module --- src/Makefile | 2 +- src/jsapi-libdom-infmap.c | 338 +++++++++++++++++++++++++++++++++++++ src/jsapi-libdom.c | 162 ------------------ src/jsapi-libdom.h | 11 +- src/options.h | 3 +- test/data/bindings/htmlelement.bnd | 4 +- 6 files changed, 353 insertions(+), 167 deletions(-) create mode 100644 src/jsapi-libdom-infmap.c diff --git a/src/Makefile b/src/Makefile index 2f42c4a..6b98bd8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c +DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c jsapi-libdom-infmap.c SOURCES := $(SOURCES) $(BUILDDIR)/nsgenbind-parser.c $(BUILDDIR)/nsgenbind-lexer.c $(BUILDDIR)/webidl-parser.c $(BUILDDIR)/webidl-lexer.c diff --git a/src/jsapi-libdom-infmap.c b/src/jsapi-libdom-infmap.c new file mode 100644 index 0000000..d02ae65 --- /dev/null +++ b/src/jsapi-libdom-infmap.c @@ -0,0 +1,338 @@ +/* interface map builder + * + * This file is part of nsgenbind. + * Published under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2014 Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "jsapi-libdom.h" + +/** count the number of methods or properties for an interface */ +static int +enumerate_interface_own(struct webidl_node *interface_node, + enum webidl_node_type node_type) +{ + int count = 0; + struct webidl_node *members_node; + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_LIST); + while (members_node != NULL) { + count += webidl_node_enumerate_type( + webidl_node_getnode(members_node), + node_type); + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + members_node, + WEBIDL_NODE_TYPE_LIST); + } + + return count; +} + +static int +fill_binding_interface(struct webidl_node *webidl_ast, + struct binding_interface *interface) +{ + /* get web IDL node for interface */ + interface->widl_node = webidl_node_find_type_ident( + webidl_ast, + WEBIDL_NODE_TYPE_INTERFACE, + interface->name); + if (interface->widl_node == NULL) { + return -1; + } + + /* enumerate the number of functions */ + interface->own_functions = enumerate_interface_own( + interface->widl_node, + WEBIDL_NODE_TYPE_OPERATION); + + /* enumerate the number of properties */ + interface->own_properties = enumerate_interface_own( + interface->widl_node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + /* extract the name of the inherited interface (if any) */ + interface->inherit_name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(interface->widl_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); + + return 0; +} + +/* find index of inherited node if it is one of those listed in the + * binding also maintain refcounts + */ +static void +compute_inherit_refcount(struct binding_interface *interfaces, + int interfacec) +{ + int idx; + int inf; + + for (idx = 0; idx < interfacec; idx++ ) { + interfaces[idx].inherit_idx = -1; + for (inf = 0; inf < interfacec; inf++ ) { + /* cannot inherit from self and name must match */ + if ((inf != idx) && + (interfaces[idx].inherit_name != NULL ) && + (strcmp(interfaces[idx].inherit_name, + interfaces[inf].name) == 0)) { + interfaces[idx].inherit_idx = inf; + interfaces[inf].refcount++; + break; + } + } + } +} + +/** Topoligical sort based on the refcount + * + * do not need to consider loops as constructed graph is a acyclic + * + * alloc a second copy of the map + * repeat until all entries copied: + * walk source mapping until first entry with zero refcount + * put the entry at the end of the output map + * reduce refcount on inherit index if !=-1 + * remove entry from source map + */ +static struct binding_interface * +interface_topoligical_sort(struct binding_interface *srcinf, int infc) +{ + struct binding_interface *dstinf; + int idx; + int inf; + + dstinf = calloc(infc, sizeof(struct binding_interface)); + if (dstinf == NULL) { + return NULL; + } + + for (idx = infc - 1; idx >= 0; idx--) { + /* walk source map until first valid entry with zero refcount */ + inf = 0; + while ((inf < infc) && + ((srcinf[inf].name == NULL) || + (srcinf[inf].refcount > 0))) { + inf++; + } + if (inf == infc) { + free(dstinf); + return NULL; + } + + /* copy entry to the end of the output map */ + dstinf[idx].name = srcinf[inf].name; + dstinf[idx].node = srcinf[inf].node; + dstinf[idx].widl_node = srcinf[inf].widl_node; + dstinf[idx].inherit_name = srcinf[inf].inherit_name; + dstinf[idx].own_properties = srcinf[inf].own_properties; + dstinf[idx].own_functions = srcinf[inf].own_functions; + + /* reduce refcount on inherit index if !=-1 */ + if (srcinf[inf].inherit_idx != -1) { + srcinf[srcinf[inf].inherit_idx].refcount--; + } + + /* remove entry from source map */ + srcinf[inf].name = NULL; + } + + return dstinf; +} + +/* build interface map and return the first interface */ +struct genbind_node * +build_interface_map(struct genbind_node *binding_node, + struct webidl_node *webidl_ast, + int *interfacec_out, + struct binding_interface **interfaces_out) +{ + int interfacec; + int inf; /* interface loop counter */ + int idx; /* map index counter */ + struct binding_interface *interfaces; + struct genbind_node *node = NULL; + struct binding_interface *reinterfaces; + + /* count number of interfaces listed in binding */ + interfacec = genbind_node_enumerate_type( + genbind_node_getnode(binding_node), + GENBIND_NODE_TYPE_BINDING_INTERFACE); + + if (interfacec == 0) { + return NULL; + } + if (options->verbose) { + printf("Binding has %d interfaces\n", interfacec); + } + + interfaces = calloc(interfacec, sizeof(struct binding_interface)); + if (interfaces == NULL) { + return NULL; + } + + /* fill in map with binding node data */ + idx = 0; + node = genbind_node_find_type( + genbind_node_getnode(binding_node), + node, + GENBIND_NODE_TYPE_BINDING_INTERFACE); + while (node != NULL) { + + /* binding node */ + interfaces[idx].node = node; + + /* get interface name */ + interfaces[idx].name = genbind_node_gettext( + genbind_node_find_type(genbind_node_getnode(node), + NULL, + GENBIND_NODE_TYPE_IDENT)); + if (interfaces[idx].name == NULL) { + free(interfaces); + return NULL; + } + + /* get interface info from webidl */ + if (fill_binding_interface(webidl_ast, interfaces + idx) == -1) { + free(interfaces); + return NULL; + } + + interfaces[idx].refcount = 0; + + /* ensure it is not a duplicate */ + for (inf = 0; inf < idx; inf++) { + if (strcmp(interfaces[inf].name, interfaces[idx].name) == 0) { + break; + } + } + if (inf != idx) { + WARN(WARNING_DUPLICATED, + "interface %s duplicated in binding", + interfaces[idx].name); + } else { + idx++; + } + + /* next node */ + node = genbind_node_find_type( + genbind_node_getnode(binding_node), + node, + GENBIND_NODE_TYPE_BINDING_INTERFACE); + } + + /* update count which may have changed if there were duplicates */ + interfacec = idx; + + /* compute inheritance and refcounts on map */ + compute_inherit_refcount(interfaces, interfacec); + + /* the map must be augmented with all the interfaces not in + * the binding but in the dependancy chain + */ + for (idx = 0; idx < interfacec; idx++ ) { + if ((interfaces[idx].inherit_idx == -1) && + (interfaces[idx].inherit_name != NULL)) { + /* interface inherits but not currently in map */ + + /* grow map */ + reinterfaces = realloc(interfaces, + (interfacec + 1) * sizeof(struct binding_interface)); + if (reinterfaces == NULL) { + fprintf(stderr,"Unable to grow interface map\n"); + free(interfaces); + return NULL; + } + interfaces = reinterfaces; + + /* setup all fileds in new interface */ + + /* this interface is not in the binding and + * will not be exported + */ + interfaces[interfacec].node = NULL; + + interfaces[interfacec].name = interfaces[idx].inherit_name; + + if (fill_binding_interface(webidl_ast, + interfaces + interfacec) == -1) { + fprintf(stderr, + "Interface %s inherits from %s which is not in the WebIDL\n", + interfaces[idx].name, + interfaces[idx].inherit_name); + free(interfaces); + return NULL; + } + + interfaces[interfacec].inherit_idx = -1; + interfaces[interfacec].refcount = 0; + + /* update dependancy info and refcount */ + for (inf = 0; inf < interfacec; inf++) { + if (strcmp(interfaces[inf].inherit_name, + interfaces[interfacec].name) == 0) { + interfaces[inf].inherit_idx = interfacec; + interfaces[interfacec].refcount++; + } + } + + /* update interface count in map */ + interfacec++; + + } + } + + /* sort interfaces to ensure correct ordering */ + reinterfaces = interface_topoligical_sort(interfaces, interfacec); + free(interfaces); + if (reinterfaces == NULL) { + return NULL; + } + interfaces = reinterfaces; + + /* compute inheritance and refcounts on sorted map */ + compute_inherit_refcount(interfaces, interfacec); + + /* show the interface map */ + if (options->verbose) { + for (idx = 0; idx < interfacec; idx++ ) { + printf("interface num:%d\n" + " name:%s node:%p widl:%p\n" + " inherit:%s inherit idx:%d refcount:%d\n" + " own functions:%d own properties:%d\n", + idx, + interfaces[idx].name, + interfaces[idx].node, + interfaces[idx].widl_node, + interfaces[idx].inherit_name, + interfaces[idx].inherit_idx, + interfaces[idx].refcount, + interfaces[idx].own_functions, + interfaces[idx].own_properties); + } + } + + *interfacec_out = interfacec; + *interfaces_out = interfaces; + + return interfaces[0].node; +} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 547e66e..f011342 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -820,168 +820,6 @@ binding_has_private(struct genbind_node *binding_list) } -/** count the number of methods or properties for an interface */ -static int -enumerate_interface_own(struct webidl_node *interface_node, - enum webidl_node_type node_type) -{ - int count = 0; - struct webidl_node *members_node; - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - count += webidl_node_enumerate_type( - webidl_node_getnode(members_node), - node_type); - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); - } - - return count; -} - -/* build interface map and return the first interface */ -static struct genbind_node * -build_interface_map(struct genbind_node *binding_node, - struct webidl_node *webidl_ast, - int *interfacec_out, - struct binding_interface **interfaces_out) -{ - int interfacec; - int idx; - struct binding_interface *interfaces; - struct genbind_node *node = NULL; - - /* count number of interfaces listed in binding */ - interfacec = genbind_node_enumerate_type( - genbind_node_getnode(binding_node), - GENBIND_NODE_TYPE_BINDING_INTERFACE); - - if (interfacec == 0) { - return NULL; - } - if (options->verbose) { - printf("Binding has %d interfaces\n", interfacec); - } - - interfaces = malloc(interfacec * sizeof(struct binding_interface)); - if (interfaces == NULL) { - return NULL; - } - - /* fill in map with node data */ - for (idx = 0; idx < interfacec; idx++ ) { - node = genbind_node_find_type( - genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); - if (node == NULL) { - free(interfaces); - return NULL; - } - - interfaces[idx].node = node; - - /* get interface name */ - interfaces[idx].name = genbind_node_gettext( - genbind_node_find_type(genbind_node_getnode(node), - NULL, - GENBIND_NODE_TYPE_IDENT)); - if (interfaces[idx].name == NULL) { - free(interfaces); - return NULL; - } - - /* get web IDL node for interface */ - interfaces[idx].widl_node = webidl_node_find_type_ident( - webidl_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interfaces[idx].name); - if (interfaces[idx].widl_node == NULL) { - free(interfaces); - return NULL; - } - - /* enumerate the number of functions */ - interfaces[idx].own_functions = enumerate_interface_own( - interfaces[idx].widl_node, - WEBIDL_NODE_TYPE_OPERATION); - - /* enumerate the number of properties */ - interfaces[idx].own_properties = enumerate_interface_own( - interfaces[idx].widl_node, - WEBIDL_NODE_TYPE_ATTRIBUTE); - - /* extract the name of the inherited interface (if any) */ - interfaces[idx].inherit_name = webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(interfaces[idx].widl_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); - - interfaces[idx].refcount = 0; - } - - /* find index of inherited node if it is one of those listed - * in the binding also maintain refcounts - */ - for (idx = 0; idx < interfacec; idx++ ) { - int inf; - interfaces[idx].inherit_idx = -1; - for (inf = 0; inf < interfacec; inf++ ) { - /* cannot inherit from self and name must match */ - if ((inf != idx) && - (strcmp(interfaces[idx].inherit_name, - interfaces[inf].name) == 0)) { - interfaces[idx].inherit_idx = inf; - interfaces[inf].refcount++; - break; - } - } - } - - /** @todo There should be a topoligical sort based on the refcount - * - * do not need to consider loops as constructed graph is a acyclic - * - * alloc a second copy of the map - * repeat until all entries copied: - * walk source mapping until first entry with zero refcount - * put the entry at the end of the output map - * reduce refcount on inherit index if !=-1 - * remove entry from source map - */ - - /* show the interface map */ - if (options->verbose) { - for (idx = 0; idx < interfacec; idx++ ) { - printf("interface num:%d\n" - " name:%s node:%p widl:%p\n" - " inherit:%s inherit idx:%d refcount:%d\n" - " own functions:%d own properties:%d\n", - idx, - interfaces[idx].name, - interfaces[idx].node, - interfaces[idx].widl_node, - interfaces[idx].inherit_name, - interfaces[idx].inherit_idx, - interfaces[idx].refcount, - interfaces[idx].own_functions, - interfaces[idx].own_properties); - } - } - - *interfacec_out = interfacec; - *interfaces_out = interfaces; - - return interfaces[0].node; -} static struct binding * binding_new(struct options *options, diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index ce50589..82258ae 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -16,11 +16,11 @@ struct binding_interface { struct genbind_node *node; /* node of interface in binding */ struct webidl_node *widl_node; /* node of interface in webidl */ const char *inherit_name; /* name of interface this inherits from */ - int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ - int refcount; /* number of entries in map that refer to this interface */ int own_properties; /* the number of properties the interface has */ int own_functions; /* the number of functions the interface has */ + int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ + int refcount; /* number of entries in map that refer to this interface */ }; struct binding { @@ -58,6 +58,13 @@ struct binding { /** Generate binding between jsapi and netsurf libdom */ int jsapi_libdom_output(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node); +/** build interface mapping */ +struct genbind_node * +build_interface_map(struct genbind_node *binding_node, + struct webidl_node *webidl_ast, + int *interfacec_out, + struct binding_interface **interfaces_out); + /** output code block from a node */ void output_code_block(struct binding *binding, struct genbind_node *codelist); diff --git a/src/options.h b/src/options.h index e002a11..cbac9a3 100644 --- a/src/options.h +++ b/src/options.h @@ -34,9 +34,10 @@ extern struct options *options; enum opt_warnings { WARNING_UNIMPLEMENTED = 1, + WARNING_DUPLICATED = 2, }; -#define WARNING_ALL (WARNING_UNIMPLEMENTED) +#define WARNING_ALL (WARNING_UNIMPLEMENTED | WARNING_DUPLICATED) #define WARN(flags, msg, args...) do { \ if ((options->warnings & flags) != 0) { \ diff --git a/test/data/bindings/htmlelement.bnd b/test/data/bindings/htmlelement.bnd index d702147..1457a32 100644 --- a/test/data/bindings/htmlelement.bnd +++ b/test/data/bindings/htmlelement.bnd @@ -37,15 +37,17 @@ preamble %{ binding jsapi_libdom { + interface Text; + interface Comment; interface HTMLElement; interface HTMLAnchorElement; + interface HTMLAnchorElement; interface HTMLAppletElement; interface HTMLAreaElement; interface HTMLBaseElement; interface HTMLBaseFontElement; interface HTMLBodyElement; interface HTMLBRElement; - interface HTMLButtonElement; interface HTMLCanvasElement; interface HTMLCommandElement; -- cgit v1.2.3 From 74158664a1826e5763e7c6949a915c75c8c1a23d Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 4 Jan 2014 09:38:43 +0000 Subject: split out jsapi class generation and make use interface map --- src/Makefile | 2 +- src/jsapi-libdom-infmap.c | 41 ++++++---- src/jsapi-libdom-init.c | 169 +++++++++++++------------------------- src/jsapi-libdom-jsclass.c | 180 +++++++++++++++++++++++++++++++++++++++++ src/jsapi-libdom.c | 196 ++++++--------------------------------------- src/jsapi-libdom.h | 8 +- 6 files changed, 293 insertions(+), 303 deletions(-) create mode 100644 src/jsapi-libdom-jsclass.c diff --git a/src/Makefile b/src/Makefile index 6b98bd8..e93cb99 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.c jsapi-libdom.c jsapi-libdom-function.c jsapi-libdom-property.c jsapi-libdom-init.c jsapi-libdom-new.c jsapi-libdom-infmap.c +DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.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/jsapi-libdom-infmap.c b/src/jsapi-libdom-infmap.c index d02ae65..d0ffbd8 100644 --- a/src/jsapi-libdom-infmap.c +++ b/src/jsapi-libdom-infmap.c @@ -160,7 +160,7 @@ interface_topoligical_sort(struct binding_interface *srcinf, int infc) } /* build interface map and return the first interface */ -struct genbind_node * +int build_interface_map(struct genbind_node *binding_node, struct webidl_node *webidl_ast, int *interfacec_out, @@ -179,7 +179,7 @@ build_interface_map(struct genbind_node *binding_node, GENBIND_NODE_TYPE_BINDING_INTERFACE); if (interfacec == 0) { - return NULL; + return -1; } if (options->verbose) { printf("Binding has %d interfaces\n", interfacec); @@ -187,15 +187,14 @@ build_interface_map(struct genbind_node *binding_node, interfaces = calloc(interfacec, sizeof(struct binding_interface)); if (interfaces == NULL) { - return NULL; + return -1; } /* fill in map with binding node data */ idx = 0; - node = genbind_node_find_type( - genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); + node = genbind_node_find_type(genbind_node_getnode(binding_node), + node, + GENBIND_NODE_TYPE_BINDING_INTERFACE); while (node != NULL) { /* binding node */ @@ -208,13 +207,13 @@ build_interface_map(struct genbind_node *binding_node, GENBIND_NODE_TYPE_IDENT)); if (interfaces[idx].name == NULL) { free(interfaces); - return NULL; + return -1; } /* get interface info from webidl */ if (fill_binding_interface(webidl_ast, interfaces + idx) == -1) { free(interfaces); - return NULL; + return -1; } interfaces[idx].refcount = 0; @@ -260,7 +259,7 @@ build_interface_map(struct genbind_node *binding_node, if (reinterfaces == NULL) { fprintf(stderr,"Unable to grow interface map\n"); free(interfaces); - return NULL; + return -1; } interfaces = reinterfaces; @@ -280,7 +279,7 @@ build_interface_map(struct genbind_node *binding_node, interfaces[idx].name, interfaces[idx].inherit_name); free(interfaces); - return NULL; + return -1; } interfaces[interfacec].inherit_idx = -1; @@ -305,20 +304,31 @@ build_interface_map(struct genbind_node *binding_node, reinterfaces = interface_topoligical_sort(interfaces, interfacec); free(interfaces); if (reinterfaces == NULL) { - return NULL; + return -1; } interfaces = reinterfaces; /* compute inheritance and refcounts on sorted map */ compute_inherit_refcount(interfaces, interfacec); + /* setup output index values */ + inf = 0; + for (idx = 0; idx < interfacec; idx++ ) { + if (interfaces[idx].node == NULL) { + interfaces[idx].output_idx = -1; + } else { + interfaces[idx].output_idx = inf; + inf++; + } + } + /* show the interface map */ if (options->verbose) { for (idx = 0; idx < interfacec; idx++ ) { printf("interface num:%d\n" " name:%s node:%p widl:%p\n" " inherit:%s inherit idx:%d refcount:%d\n" - " own functions:%d own properties:%d\n", + " own functions:%d own properties:%d output idx:%d\n", idx, interfaces[idx].name, interfaces[idx].node, @@ -327,12 +337,13 @@ build_interface_map(struct genbind_node *binding_node, interfaces[idx].inherit_idx, interfaces[idx].refcount, interfaces[idx].own_functions, - interfaces[idx].own_properties); + interfaces[idx].own_properties, + interfaces[idx].output_idx); } } *interfacec_out = interfacec; *interfaces_out = interfaces; - return interfaces[0].node; + return 0; } diff --git a/src/jsapi-libdom-init.c b/src/jsapi-libdom-init.c index 6dfc66f..1077c2d 100644 --- a/src/jsapi-libdom-init.c +++ b/src/jsapi-libdom-init.c @@ -19,8 +19,6 @@ #include "webidl-ast.h" #include "jsapi-libdom.h" -static int output_const_defines(struct binding *binding, const char *interface); - static int output_cast_literal(struct binding *binding, struct webidl_node *node) { @@ -159,60 +157,64 @@ output_interface_consts(struct binding *binding, return 0; } -/* callback to emit implements property spec */ -static int webidl_const_spec_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - return output_const_defines(binding, webidl_node_gettext(node)); -} - -/** generate property definitions for constants */ -static int -output_const_defines(struct binding *binding, const char *interface) +static int generate_prototype_init(struct binding *binding, int inf) { - struct webidl_node *interface_node; - struct webidl_node *inherit_node; - int res = 0; + int inherit_inf; - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; + /* find this interfaces parent interface to inherit prototype from */ + inherit_inf = binding->interfaces[inf].inherit_idx; + while ((inherit_inf != -1) && + (binding->interfaces[inherit_inf].node == NULL)) { + inherit_inf = binding->interfaces[inherit_inf].inherit_idx; } - fprintf(binding->outfile, "\t/**** %s ****/\n", interface); - - /* write the property defines for this interface */ - res = output_interface_consts(binding, interface_node); - + fprintf(binding->outfile, + "\n" + "\tprototype = JS_InitClass(cx, " + "parent, "); + + /* either this init is being constructed without a chain or is + * using a prototype of a previously initialised class + */ + if (inherit_inf == -1) { + fprintf(binding->outfile, + "NULL, "); + } else { + fprintf(binding->outfile, + "prototypes[%d], ", + binding->interfaces[inherit_inf].output_idx); + } - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); + fprintf(binding->outfile, + "&JSClass_%s, " + "NULL, " + "0, " + "NULL, " + "NULL, " + "NULL, " + "NULL);\n", + binding->interfaces[inf].name); + + /* check prototype construction */ + fprintf(binding->outfile, + "\tif (prototype == NULL) {\n" + "\t\treturn %d;\n" + "\t}\n\n", + binding->interfaces[inf].output_idx); - if (inherit_node != NULL) { - res = output_const_defines(binding, - webidl_node_gettext(inherit_node)); - } + /* store result */ + fprintf(binding->outfile, + "\tprototypes[%d] = prototype;\n", + binding->interfaces[inf].output_idx); - if (res == 0) { - res = webidl_node_for_each_type( - webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_const_spec_implements_cb, - binding); - } + /* output the consts for the interface and ancestors if necessary */ + do { + output_interface_consts(binding, binding->interfaces[inf].widl_node); + inf = binding->interfaces[inf].inherit_idx; + } while (inf != inherit_inf); - return res; + return 0; } /** generate class initialisers @@ -263,75 +265,16 @@ int output_class_init(struct binding *binding) if (api_node != NULL) { output_code_block(binding, genbind_node_getnode(api_node)); } else { + /* generate interface init for each class in binding */ for (inf = 0; inf < binding->interfacec; inf++) { - - fprintf(binding->outfile, - "\n" - "\tprototype = JS_InitClass(cx, " - "parent, "); - - if (binding->interfaces[inf].inherit_idx == -1) { - /* interface does not get its - * prototypes from another interface - * we are generating - */ - fprintf(binding->outfile, - "NULL, " - "&JSClass_%s, " - "NULL, " - "0, " - "NULL, " - "NULL, " - "NULL, " - "NULL);\n", - binding->interfaces[inf].name); - - fprintf(binding->outfile, - "\tif (prototype == NULL) {\n" - "\t\treturn %d;\n" - "\t}\n\n", - inf); - - fprintf(binding->outfile, - "\tprototypes[%d] = prototype;\n", - inf); - - output_const_defines(binding, - binding->interfaces[inf].name); - - } else { - /* interface prototype is based on one - * we already generated (interface map - * is topologicaly sorted */ - assert(binding->interfaces[inf].inherit_idx < inf); - - fprintf(binding->outfile, - "prototypes[%d], " - "&JSClass_%s, " - "NULL, " - "0, " - "NULL, " - "NULL, " - "NULL, " - "NULL);\n", - binding->interfaces[inf].inherit_idx, - binding->interfaces[inf].name); - - fprintf(binding->outfile, - "\tif (prototype == NULL) {\n" - "\t\treturn %d;\n" - "\t}\n\n", - inf); - - fprintf(binding->outfile, - "\tprototypes[%d] = prototype;\n", - inf); - - output_interface_consts(binding, - binding->interfaces[inf].widl_node); - + /* skip generating javascript class + * initialisation for interfaces not in binding + */ + if (binding->interfaces[inf].node != NULL) { + generate_prototype_init(binding, inf); } } + fprintf(binding->outfile, "\n\treturn %d;\n", inf); diff --git a/src/jsapi-libdom-jsclass.c b/src/jsapi-libdom-jsclass.c new file mode 100644 index 0000000..3a5a84c --- /dev/null +++ b/src/jsapi-libdom-jsclass.c @@ -0,0 +1,180 @@ +/* Javascript spidemonkey API to libdom binding generation for class + * initilisation + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2012 Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "jsapi-libdom.h" + +#define HDROUTF(bndg, fmt, args...) do { \ + if (bndg->hdrfile != NULL) { \ + fprintf(bndg->hdrfile, fmt, ##args); \ + } \ + } while(0) + +static bool interface_is_global(struct genbind_node *interface_node) +{ + if (genbind_node_find_type_ident( + genbind_node_getnode(interface_node), + NULL, + GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, + "global") != NULL) { + return true; + } + + return false; +} + +static int output_jsclass(struct binding *binding, + const char *interface_name, + struct genbind_node *interface_node) +{ + /* output the class declaration */ + HDROUTF(binding, "JSClass JSClass_%s;\n", interface_name); + + /* output the class definition */ + fprintf(binding->outfile, + "JSClass JSClass_%s = {\n" + "\t\"%s\",\n", + interface_name, + interface_name); + + /* generate class flags */ + if (interface_is_global(interface_node)) { + fprintf(binding->outfile, "\tJSCLASS_GLOBAL_FLAGS"); + } else { + fprintf(binding->outfile, "\t0"); + } + + if (binding->resolve != NULL) { + fprintf(binding->outfile, " | JSCLASS_NEW_RESOLVE"); + } + + if (binding->mark != NULL) { + fprintf(binding->outfile, " | JSAPI_JSCLASS_MARK_IS_TRACE"); + } + + if (binding->has_private) { + fprintf(binding->outfile, " | JSCLASS_HAS_PRIVATE"); + } + + fprintf(binding->outfile, ",\n"); + + /* add property */ + if (binding->addproperty != NULL) { + fprintf(binding->outfile, + "\tjsapi_property_add,\t/* addProperty */\n"); + } else { + fprintf(binding->outfile, + "\tJS_PropertyStub,\t/* addProperty */\n"); + } + + /* del property */ + if (binding->delproperty != NULL) { + fprintf(binding->outfile, + "\tjsapi_property_del,\t/* delProperty */\n"); + } else { + fprintf(binding->outfile, + "\tJS_PropertyStub,\t/* delProperty */\n"); + } + + /* get property */ + if (binding->getproperty != NULL) { + fprintf(binding->outfile, + "\tjsapi_property_get,\t/* getProperty */\n"); + } else { + fprintf(binding->outfile, + "\tJS_PropertyStub,\t/* getProperty */\n"); + } + + /* set property */ + if (binding->setproperty != NULL) { + fprintf(binding->outfile, + "\tjsapi_property_set,\t/* setProperty */\n"); + } else { + fprintf(binding->outfile, + "\tJS_StrictPropertyStub,\t/* setProperty */\n"); + } + + /* enumerate */ + if (binding->enumerate != NULL) { + fprintf(binding->outfile, + "\tjsclass_enumerate,\t/* enumerate */\n"); + } else { + fprintf(binding->outfile, + "\tJS_EnumerateStub,\t/* enumerate */\n"); + } + + /* resolver */ + if (binding->resolve != NULL) { + fprintf(binding->outfile, + "\t(JSResolveOp)jsclass_resolve,\t/* resolve */\n"); + } else { + fprintf(binding->outfile, + "\tJS_ResolveStub,\t\t/* resolve */\n"); + } + + fprintf(binding->outfile, "\tJS_ConvertStub,\t\t/* convert */\n"); + + if (binding->has_private || (binding->finalise != NULL)) { + fprintf(binding->outfile, + "\tjsclass_finalize,\t/* finalizer */\n"); + } else { + fprintf(binding->outfile, + "\tJS_FinalizeStub,\t/* finalizer */\n"); + } + fprintf(binding->outfile, + "\t0,\t\t\t/* reserved */\n" + "\tNULL,\t\t\t/* checkAccess */\n" + "\tNULL,\t\t\t/* call */\n" + "\tNULL,\t\t\t/* construct */\n" + "\tNULL,\t\t\t/* xdr Object */\n" + "\tNULL,\t\t\t/* hasInstance */\n"); + + /* trace/mark */ + if (binding->mark != NULL) { + fprintf(binding->outfile, + "\tJSAPI_JSCLASS_MARKOP(jsclass_mark),\n"); + } else { + fprintf(binding->outfile, "\tNULL,\t\t\t/* trace/mark */\n"); + } + + fprintf(binding->outfile, + "\tJSAPI_CLASS_NO_INTERNAL_MEMBERS\n" + "};\n\n"); + + return 0; +} + +int +output_jsclasses(struct binding *binding) +{ + int inf; + + for (inf = 0; inf < binding->interfacec; inf++) { + /* skip generating javascript classes for interfaces + * not in binding + */ + if (binding->interfaces[inf].node == NULL) { + continue; + } + + output_jsclass(binding, + binding->interfaces[inf].name, + binding->interfaces[inf].node); + } + return 0; +} diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index f011342..1bb6d28 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -25,11 +25,6 @@ " * nsgenbind is similar to a compiler is a purely transformative tool which\n" \ " * explicitly makes no copyright claim on this generated output" -#define HDROUTF(bndg, fmt, args...) do { \ - if (bndg->hdrfile != NULL) { \ - fprintf(bndg->hdrfile, fmt, ##args); \ - } \ - } while(0) static int webidl_file_cb(struct genbind_node *node, void *ctx) @@ -543,163 +538,7 @@ output_forward_declarations(struct binding *binding) return 0; } -static bool interface_is_global(struct genbind_node *interface_node) -{ - if (genbind_node_find_type_ident( - genbind_node_getnode(interface_node), - NULL, - GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, - "global") != NULL) { - return true; - } - - return false; -} - -static int output_jsclass(struct genbind_node *interface_node, void *ctx) -{ - struct binding *binding = ctx; - struct genbind_node *interface_list; - const char *interface_ident; - - interface_list = genbind_node_getnode(interface_node); - if (interface_list == NULL) - return -1; /* bad AST */ - - interface_ident = genbind_node_gettext( - genbind_node_find_type(interface_list, - NULL, - GENBIND_NODE_TYPE_IDENT)); - if (interface_ident == NULL) - return -1; /* bad AST */ - - /* output the class declaration */ - HDROUTF(binding, "JSClass JSClass_%s;\n", interface_ident); - - /* output the class definition */ - fprintf(binding->outfile, - "JSClass JSClass_%s = {\n" - "\t\"%s\",\n", - interface_ident, - interface_ident); - - /* generate class flags */ - if (interface_is_global(interface_node)) { - fprintf(binding->outfile, "\tJSCLASS_GLOBAL_FLAGS"); - } else { - fprintf(binding->outfile, "\t0"); - } - - if (binding->resolve != NULL) { - fprintf(binding->outfile, " | JSCLASS_NEW_RESOLVE"); - } - - if (binding->mark != NULL) { - fprintf(binding->outfile, " | JSAPI_JSCLASS_MARK_IS_TRACE"); - } - - if (binding->has_private) { - fprintf(binding->outfile, " | JSCLASS_HAS_PRIVATE"); - } - - fprintf(binding->outfile, ",\n"); - - /* add property */ - if (binding->addproperty != NULL) { - fprintf(binding->outfile, - "\tjsapi_property_add,\t/* addProperty */\n"); - } else { - fprintf(binding->outfile, - "\tJS_PropertyStub,\t/* addProperty */\n"); - } - - /* del property */ - if (binding->delproperty != NULL) { - fprintf(binding->outfile, - "\tjsapi_property_del,\t/* delProperty */\n"); - } else { - fprintf(binding->outfile, - "\tJS_PropertyStub,\t/* delProperty */\n"); - } - - /* get property */ - if (binding->getproperty != NULL) { - fprintf(binding->outfile, - "\tjsapi_property_get,\t/* getProperty */\n"); - } else { - fprintf(binding->outfile, - "\tJS_PropertyStub,\t/* getProperty */\n"); - } - /* set property */ - if (binding->setproperty != NULL) { - fprintf(binding->outfile, - "\tjsapi_property_set,\t/* setProperty */\n"); - } else { - fprintf(binding->outfile, - "\tJS_StrictPropertyStub,\t/* setProperty */\n"); - } - - /* enumerate */ - if (binding->enumerate != NULL) { - fprintf(binding->outfile, - "\tjsclass_enumerate,\t/* enumerate */\n"); - } else { - fprintf(binding->outfile, - "\tJS_EnumerateStub,\t/* enumerate */\n"); - } - - /* resolver */ - if (binding->resolve != NULL) { - fprintf(binding->outfile, - "\t(JSResolveOp)jsclass_resolve,\t/* resolve */\n"); - } else { - fprintf(binding->outfile, - "\tJS_ResolveStub,\t\t/* resolve */\n"); - } - - fprintf(binding->outfile, "\tJS_ConvertStub,\t\t/* convert */\n"); - - if (binding->has_private || (binding->finalise != NULL)) { - fprintf(binding->outfile, - "\tjsclass_finalize,\t/* finalizer */\n"); - } else { - fprintf(binding->outfile, - "\tJS_FinalizeStub,\t/* finalizer */\n"); - } - fprintf(binding->outfile, - "\t0,\t\t\t/* reserved */\n" - "\tNULL,\t\t\t/* checkAccess */\n" - "\tNULL,\t\t\t/* call */\n" - "\tNULL,\t\t\t/* construct */\n" - "\tNULL,\t\t\t/* xdr Object */\n" - "\tNULL,\t\t\t/* hasInstance */\n"); - - /* trace/mark */ - if (binding->mark != NULL) { - fprintf(binding->outfile, - "\tJSAPI_JSCLASS_MARKOP(jsclass_mark),\n"); - } else { - fprintf(binding->outfile, "\tNULL,\t\t\t/* trace/mark */\n"); - } - - fprintf(binding->outfile, - "\tJSAPI_CLASS_NO_INTERNAL_MEMBERS\n" - "};\n\n"); - - return 0; -} - -static int -output_jsclasses(struct binding *binding) -{ - - return genbind_node_foreach_type(binding->binding_list, - GENBIND_NODE_TYPE_BINDING_INTERFACE, - output_jsclass, - binding); - -} /** generate structure definition for internal class data * @@ -821,6 +660,24 @@ binding_has_private(struct genbind_node *binding_list) +/** obtain the name to use for the binding. + * + * @todo it should be possible to specify the binding name instead of + * just using the name of the first interface. + */ +static const char *get_binding_name(struct genbind_node *binding_node) +{ + return genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode( + genbind_node_find_type( + genbind_node_getnode(binding_node), + NULL, + GENBIND_NODE_TYPE_BINDING_INTERFACE)), + NULL, + GENBIND_NODE_TYPE_IDENT)); +} + static struct binding * binding_new(struct options *options, struct genbind_node *genbind_ast, @@ -831,7 +688,6 @@ binding_new(struct options *options, int interfacec; /* numer of interfaces in the interface map */ struct binding_interface *interfaces; /* binding interface map */ - struct genbind_node *interface_node; struct genbind_node *binding_list; char *hdrguard = NULL; struct webidl_node *webidl_ast = NULL; @@ -845,11 +701,10 @@ binding_new(struct options *options, } /* build the bindings interface (class) name map */ - interface_node = build_interface_map(binding_node, - webidl_ast, - &interfacec, - &interfaces); - if (interface_node == NULL) { + if (build_interface_map(binding_node, + webidl_ast, + &interfacec, + &interfaces) != 0) { /* the binding must have at least one interface */ fprintf(stderr, "Error: Binding must have a valid interface\n"); return NULL; @@ -888,13 +743,10 @@ binding_new(struct options *options, nb->interfaces = interfaces; nb->interfacec = interfacec; - /* @todo it should be possible to specify the binding name - * instead of just using the name of the first interface. - * - * @todo get rid of the interface element out of the binding + /* @todo get rid of the interface element out of the binding * struct and use the interface map instead. */ - nb->name = nb->interface = interfaces[0].name; + nb->name = nb->interface = get_binding_name(binding_node); nb->outfile = options->outfilehandle; nb->srcfile = options->outfilehandle; nb->hdrfile = options->hdrfilehandle; diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index 82258ae..cf27318 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -21,6 +21,7 @@ struct binding_interface { int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ int refcount; /* number of entries in map that refer to this interface */ + int output_idx; /* for interfaces that will be output (node is valid) this is the output array index */ }; struct binding { @@ -59,15 +60,18 @@ struct binding { int jsapi_libdom_output(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node); /** build interface mapping */ -struct genbind_node * -build_interface_map(struct genbind_node *binding_node, +int build_interface_map(struct genbind_node *binding_node, struct webidl_node *webidl_ast, int *interfacec_out, struct binding_interface **interfaces_out); + /** output code block from a node */ void output_code_block(struct binding *binding, struct genbind_node *codelist); +/** generate classes */ +int output_jsclasses(struct binding *binding); + /* Generate jsapi native function specifiers */ int output_function_spec(struct binding *binding); -- cgit v1.2.3 From 6031dd6e55216bd4d9a78c4869bb8b5e5f5aa3c3 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 9 Jan 2014 18:29:29 +0000 Subject: Expand implements statements in the AST after it has been built This greatly simplifies output generation because instead of dealing with implements on every traverse they are expanded once. Additionaly errors in expansion are found and generate error early. --- src/jsapi-libdom-function.c | 24 +-------- src/jsapi-libdom-property.c | 47 ----------------- src/jsapi-libdom.c | 4 ++ src/webidl-ast.c | 125 +++++++++++++++++++++++++++++++++++++++++--- src/webidl-ast.h | 3 ++ 5 files changed, 127 insertions(+), 76 deletions(-) diff --git a/src/jsapi-libdom-function.c b/src/jsapi-libdom-function.c index 4970b48..5540b0e 100644 --- a/src/jsapi-libdom-function.c +++ b/src/jsapi-libdom-function.c @@ -45,13 +45,6 @@ static int webidl_func_spec_cb(struct webidl_node *node, void *ctx) static int generate_function_spec(struct binding *binding, const char *interface); -/* callback to emit implements operator spec */ -static int webidl_function_spec_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return generate_function_spec(binding, webidl_node_gettext(node)); -} static int generate_function_spec(struct binding *binding, const char *interface) @@ -104,13 +97,6 @@ generate_function_spec(struct binding *binding, const char *interface) webidl_node_gettext(inherit_node)); } - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_function_spec_implements_cb, - binding); - } - return res; } @@ -878,14 +864,6 @@ output_function_body(struct binding *binding, res = webidl_implements_cb(inherit_node, binding); } - if (res == 0) { - res = webidl_node_for_each_type( - webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_implements_cb, - binding); - } - return res; } @@ -893,7 +871,7 @@ int output_function_bodies(struct binding *binding) { int inf; - int res; + int res = 0; for (inf=0; inf < binding->interfacec; inf++) { if (binding->interfaces[inf].inherit_idx == -1) { diff --git a/src/jsapi-libdom-property.c b/src/jsapi-libdom-property.c index df296cf..93ffcc5 100644 --- a/src/jsapi-libdom-property.c +++ b/src/jsapi-libdom-property.c @@ -131,14 +131,6 @@ webidl_property_tinyid_cb(struct webidl_node *node, void *ctx) return 0; } -/* callback to emit implements property spec */ -static int -webidl_property_tinyid_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return generate_property_tinyid(binding, webidl_node_gettext(node)); -} static int generate_property_tinyid(struct binding *binding, const char *interface) @@ -190,13 +182,6 @@ generate_property_tinyid(struct binding *binding, const char *interface) res = generate_property_tinyid(binding, webidl_node_gettext(inherit_node)); } - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_property_tinyid_implements_cb, - binding); - } - return res; } @@ -429,13 +414,6 @@ static int webidl_property_spec_cb(struct webidl_node *node, void *ctx) } -/* callback to emit implements property spec */ -static int webidl_property_spec_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return generate_property_spec(binding, webidl_node_gettext(node)); -} static int generate_property_spec(struct binding *binding, const char *interface) @@ -488,13 +466,6 @@ generate_property_spec(struct binding *binding, const char *interface) webidl_node_gettext(inherit_node)); } - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_property_spec_implements_cb, - binding); - } - return res; } @@ -954,17 +925,6 @@ static int webidl_property_body_cb(struct webidl_node *node, void *ctx) } - -/* callback to emit implements property bodys */ -static int webidl_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - - return generate_property_body(binding, webidl_node_gettext(node)); -} - - - static int generate_property_body(struct binding *binding, const char *interface) { @@ -1018,13 +978,6 @@ generate_property_body(struct binding *binding, const char *interface) webidl_node_gettext(inherit_node)); } - if (res == 0) { - res = webidl_node_for_each_type(webidl_node_getnode(interface_node), - WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS, - webidl_implements_cb, - binding); - } - return res; } diff --git a/src/jsapi-libdom.c b/src/jsapi-libdom.c index 1bb6d28..5e994b9 100644 --- a/src/jsapi-libdom.c +++ b/src/jsapi-libdom.c @@ -47,6 +47,10 @@ read_webidl(struct genbind_node *genbind_ast, struct webidl_node **webidl_ast) webidl_file_cb, webidl_ast); + if (res == 0) { + res = webidl_intercalate_implements(*webidl_ast); + } + /* debug dump of web idl AST */ if (options->verbose) { webidl_ast_dump(*webidl_ast, 0); diff --git a/src/webidl-ast.c b/src/webidl-ast.c index 8acb2fb..945b5fa 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -21,8 +21,8 @@ extern void webidl_restart(FILE*); extern int webidl_parse(struct webidl_node **webidl_ast); struct webidl_node { - enum webidl_node_type type; - struct webidl_node *l; + enum webidl_node_type type; /* the type of the node */ + struct webidl_node *l; /* link to the next sibling node */ union { void *value; struct webidl_node *node; /* node has a list of nodes */ @@ -223,6 +223,7 @@ webidl_node_find_type(struct webidl_node *node, } +/* exported interface defined in webidl-ast.h */ struct webidl_node * webidl_node_find_type_ident(struct webidl_node *root_node, enum webidl_node_type type, @@ -250,6 +251,7 @@ webidl_node_find_type_ident(struct webidl_node *root_node, } +/* exported interface defined in webidl-ast.h */ char *webidl_node_gettext(struct webidl_node *node) { if (node != NULL) { @@ -261,12 +263,13 @@ char *webidl_node_gettext(struct webidl_node *node) return node->r.text; default: - break; + break; } } return NULL; } +/* exported interface defined in webidl-ast.h */ int webidl_node_getint(struct webidl_node *node) { @@ -285,12 +288,14 @@ webidl_node_getint(struct webidl_node *node) } +/* exported interface defined in webidl-ast.h */ enum webidl_node_type webidl_node_gettype(struct webidl_node *node) { return node->type; } +/* exported interface defined in webidl-ast.h */ struct webidl_node *webidl_node_getnode(struct webidl_node *node) { if (node != NULL) { @@ -314,6 +319,7 @@ struct webidl_node *webidl_node_getnode(struct webidl_node *node) } +/* exported interface defined in webidl-ast.h */ static const char *webidl_node_type_to_str(enum webidl_node_type type) { switch(type) { @@ -381,6 +387,7 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) } +/* exported interface defined in webidl-ast.h */ int webidl_ast_dump(struct webidl_node *node, int indent) { const char *SPACES=" "; char *txt; @@ -408,18 +415,19 @@ int webidl_ast_dump(struct webidl_node *node, int indent) return 0; } +/* exported interface defined in webidl-ast.h */ static FILE *idlopen(const char *filename) { FILE *idlfile; char *fullname; - int fulllen; + int fulllen; if (options->idlpath == NULL) { if (options->verbose) { printf("Opening IDL file %s\n", filename); } return fopen(filename, "r"); - } + } fulllen = strlen(options->idlpath) + strlen(filename) + 2; fullname = malloc(fulllen); @@ -429,10 +437,11 @@ static FILE *idlopen(const char *filename) } idlfile = fopen(fullname, "r"); free(fullname); - + return idlfile; } +/* exported interface defined in webidl-ast.h */ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast) { @@ -457,3 +466,107 @@ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast) /* parse the file */ return webidl_parse(webidl_ast); } + +/* unlink a child node from a parent */ +static int +webidl_unlink(struct webidl_node *parent, struct webidl_node *node) +{ + struct webidl_node *child; + + child = webidl_node_getnode(parent); + if (child == NULL) { + /* parent does not have children to remove node from */ + return -1; + } + + if (child == node) { + /* parent is pointing at the node we want to remove */ + parent->r.node = node->l; /* point parent at next sibing */ + node->l = NULL; + return 0; + } + + while (child->l != NULL) { + if (child->l == node) { + /* found node, unlink from list */ + child->l = node->l; + node->l = NULL; + return 0; + } + child = child->l; + } + return -1; /* failed to remove node */ +} + +static int implements_copy_nodes(struct webidl_node *src_node, + struct webidl_node *dst_node) +{ + struct webidl_node *src; + struct webidl_node *dst; + + src = webidl_node_getnode(src_node); + dst = webidl_node_getnode(dst_node); + + while (src != NULL) { + if (src->type == WEBIDL_NODE_TYPE_LIST) { + /** @todo technicaly this should copy WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE */ + dst = webidl_node_new(src->type, dst, src->r.text); + } + src = src->l; + } + + dst_node->r.node = dst; + + return 0; +} + +static int +intercalate_implements(struct webidl_node *interface_node, void *ctx) +{ + struct webidl_node *implements_node; + struct webidl_node *implements_interface_node; + struct webidl_node *webidl_ast = ctx; + + implements_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS); + while (implements_node != NULL) { + + implements_interface_node = webidl_node_find_type_ident( + webidl_ast, + WEBIDL_NODE_TYPE_INTERFACE, + webidl_node_gettext(implements_node)); + + /* recurse, ensuring all subordinate interfaces have + * their implements intercalated first + */ + intercalate_implements(implements_interface_node, webidl_ast); + + implements_copy_nodes(implements_interface_node, interface_node); + + /* once we have copied the implemntation remove entry */ + webidl_unlink(interface_node, implements_node); + + implements_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + implements_node, + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS); + } + return 0; +} + +/* exported interface defined in webidl-ast.h */ +int webidl_intercalate_implements(struct webidl_node *webidl_ast) +{ + /* for each interface: + * for each implements entry: + * find interface from implemets + * recusrse into that interface + * copy the interface into this one + */ + return webidl_node_for_each_type(webidl_ast, + WEBIDL_NODE_TYPE_INTERFACE, + intercalate_implements, + webidl_ast); +} diff --git a/src/webidl-ast.h b/src/webidl-ast.h index eaa8d44..a494f4e 100644 --- a/src/webidl-ast.h +++ b/src/webidl-ast.h @@ -120,4 +120,7 @@ int webidl_ast_dump(struct webidl_node *node, int indent); /** parse web idl file */ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast); +/** perform replacement of implements elements with copies of ast data */ +int webidl_intercalate_implements(struct webidl_node *node); + #endif -- cgit v1.2.3 From 4a75f7ee606deeffd9a89d82983bf6e9edb8f27b Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 2 Feb 2014 22:59:04 +0000 Subject: make function specifier and body generation use the interface map --- src/jsapi-libdom-function.c | 252 +++++++++++++++++--------------------------- src/jsapi-libdom-infmap.c | 13 ++- src/jsapi-libdom.h | 50 ++++++--- 3 files changed, 140 insertions(+), 175 deletions(-) diff --git a/src/jsapi-libdom-function.c b/src/jsapi-libdom-function.c index 5540b0e..af9c215 100644 --- a/src/jsapi-libdom-function.c +++ b/src/jsapi-libdom-function.c @@ -17,101 +17,85 @@ #include "webidl-ast.h" #include "jsapi-libdom.h" -static int output_function_body(struct binding *binding, struct webidl_node *node); - -static int webidl_func_spec_cb(struct webidl_node *node, void *ctx) +static int webidl_operator_spec(struct binding *binding, + struct binding_interface *inf, + struct webidl_node *node) { - struct binding *binding = ctx; struct webidl_node *ident_node; - ident_node = webidl_node_find(webidl_node_getnode(node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_IDENT); - + ident_node = webidl_node_find_type(webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_IDENT); if (ident_node == NULL) { /* operation without identifier - must have special keyword * http://www.w3.org/TR/WebIDL/#idl-operations */ } else { fprintf(binding->outfile, - "\tJSAPI_FS(%s, 0, JSPROP_ENUMERATE ),\n", + "\tJSAPI_FS(%s, %s, 0, JSPROP_ENUMERATE ),\n", + inf->name, webidl_node_gettext(ident_node)); /* @todo number of args to that FN_FS() call should be correct */ } return 0; } - -static int generate_function_spec(struct binding *binding, const char *interface); - - -static int -generate_function_spec(struct binding *binding, const char *interface) +int output_function_spec(struct binding *binding) { - struct webidl_node *interface_node; - struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } - - members_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - - fprintf(binding->outfile,"\t/**** %s ****/\n", interface); - - /* for each function emit a JSAPI_FS()*/ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_OPERATION, - webidl_func_spec_cb, - binding); - - members_node = webidl_node_find(webidl_node_getnode(interface_node), - members_node, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_LIST); - } + int inf; + int res; + struct webidl_node *list_node; + struct webidl_node *op_node; /* operation on list node */ - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); + /* generate functions for each interface in the map */ + for (inf = 0; inf < binding->interfacec; inf++) { + if (binding->interfaces[inf].own_functions == 0) { + continue; + } - if (inherit_node != NULL) { - res = generate_function_spec(binding, - webidl_node_gettext(inherit_node)); - } + fprintf(binding->outfile, + "static JSFunctionSpec JSClass_%s_functions[] = {\n", + binding->interfaces[inf].name); - return res; -} + /* iterate each list within an interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + NULL, + WEBIDL_NODE_TYPE_LIST); -int output_function_spec(struct binding *binding) -{ - int res; + while (list_node != NULL) { + /* iterate through operations in a list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_OPERATION); + + while (op_node != NULL) { + res = webidl_operator_spec( + binding, + &binding->interfaces[inf], + op_node); + if (res != 0) { + return res; + } + + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_OPERATION); + } - fprintf(binding->outfile, - "static JSFunctionSpec jsclass_functions[] = {\n"); - res = generate_function_spec(binding, binding->interface); + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + list_node, + WEBIDL_NODE_TYPE_LIST); + } - fprintf(binding->outfile, "\tJSAPI_FS_END\n};\n\n"); + fprintf(binding->outfile, "\tJSAPI_FS_END\n};\n\n"); - return res; + } + return 0; } static int output_return(struct binding *binding, @@ -736,10 +720,10 @@ output_private_get(struct binding *binding, const char *argname) return ret; } -static int -webidl_operator_body_cb(struct webidl_node *node, void *ctx) +static int webidl_operator_body(struct binding *binding, + struct binding_interface *inf, + struct webidl_node *node) { - struct binding *binding = ctx; struct webidl_node *ident_node; struct genbind_node *operation_node; @@ -761,9 +745,10 @@ webidl_operator_body_cb(struct webidl_node *node, void *ctx) /* normal operation with identifier */ fprintf(binding->outfile, - "static JSBool JSAPI_FUNC(%s, JSContext *cx, uintN argc, jsval *vp)\n", + "static JSBool JSAPI_FUNC(%s, %s, JSContext *cx, uintN argc, jsval *vp)\n" + "{\n", + inf->name, webidl_node_gettext(ident_node)); - fprintf(binding->outfile, "{\n"); /* return value declaration */ output_return_declaration(binding, "jsret", webidl_node_getnode(node)); @@ -797,90 +782,51 @@ webidl_operator_body_cb(struct webidl_node *node, void *ctx) return 0; } -static int -output_interface_functions(struct binding *binding, - struct webidl_node *interface_node) -{ - struct webidl_node *members_node; - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); - - while (members_node != NULL) { - /* for each function emit a JSAPI_FS()*/ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_OPERATION, - webidl_operator_body_cb, - binding); - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); - } - return 0; -} - -/* callback to emit implements operator bodys */ -static int webidl_implements_cb(struct webidl_node *node, void *ctx) -{ - struct binding *binding = ctx; - struct webidl_node *interface_node; - - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - webidl_node_gettext(node)); - - return output_function_body(binding, interface_node); -} /* exported interface documented in jsapi-libdom.h */ -static int -output_function_body(struct binding *binding, - struct webidl_node *interface_node) +int output_function_bodies(struct binding *binding) { - struct webidl_node *inherit_node; - int res = 0; - - res = output_interface_functions(binding, interface_node); + int inf; + int res; + struct webidl_node *list_node; + struct webidl_node *op_node; /* operation on list node */ + + /* generate functions for each interface in the map */ + for (inf = 0; inf < binding->interfacec; inf++) { + /* iterate each list within an interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + NULL, + WEBIDL_NODE_TYPE_LIST); - fprintf(binding->outfile, - "/**** %s ****/\n", - webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(interface_node), + while (list_node != NULL) { + /* iterate through operations in a list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), NULL, - WEBIDL_NODE_TYPE_IDENT))); - - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); - - if (inherit_node != NULL) { - res = webidl_implements_cb(inherit_node, binding); - } + WEBIDL_NODE_TYPE_OPERATION); + + while (op_node != NULL) { + res = webidl_operator_body( + binding, + &binding->interfaces[inf], + op_node); + if (res != 0) { + return res; + } + + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_OPERATION); + } - return res; -} -int -output_function_bodies(struct binding *binding) -{ - int inf; - int res = 0; - - for (inf=0; inf < binding->interfacec; inf++) { - if (binding->interfaces[inf].inherit_idx == -1) { - res = output_function_body(binding, - binding->interfaces[inf].widl_node); - } else { - res = output_interface_functions(binding, - binding->interfaces[inf].widl_node); + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + list_node, + WEBIDL_NODE_TYPE_LIST); } } - return res; + return 0; } diff --git a/src/jsapi-libdom-infmap.c b/src/jsapi-libdom-infmap.c index d0ffbd8..09fce1e 100644 --- a/src/jsapi-libdom-infmap.c +++ b/src/jsapi-libdom-infmap.c @@ -159,12 +159,11 @@ interface_topoligical_sort(struct binding_interface *srcinf, int infc) return dstinf; } -/* build interface map and return the first interface */ -int -build_interface_map(struct genbind_node *binding_node, - struct webidl_node *webidl_ast, - int *interfacec_out, - struct binding_interface **interfaces_out) +/* exported interface documented in jsapi-libdom.h */ +int build_interface_map(struct genbind_node *binding_node, + struct webidl_node *webidl_ast, + int *interfacec_out, + struct binding_interface **interfaces_out) { int interfacec; int inf; /* interface loop counter */ @@ -263,7 +262,7 @@ build_interface_map(struct genbind_node *binding_node, } interfaces = reinterfaces; - /* setup all fileds in new interface */ + /* setup all fields in new interface */ /* this interface is not in the binding and * will not be exported diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index cf27318..2925866 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -12,16 +12,22 @@ struct options; struct binding_interface { - const char *name; /* name of interface */ - struct genbind_node *node; /* node of interface in binding */ - struct webidl_node *widl_node; /* node of interface in webidl */ - const char *inherit_name; /* name of interface this inherits from */ - int own_properties; /* the number of properties the interface has */ - int own_functions; /* the number of functions the interface has */ - - int inherit_idx; /* index into binding map of inherited interface or -1 for not in map */ - int refcount; /* number of entries in map that refer to this interface */ - int output_idx; /* for interfaces that will be output (node is valid) this is the output array index */ + const char *name; /**< name of interface */ + struct genbind_node *node; /**< node of interface in binding */ + struct webidl_node *widl_node; /**< node of interface in webidl */ + const char *inherit_name; /**< name of interface this inherits from */ + int own_properties; /**< the number of properties the interface has */ + int own_functions; /**< the number of functions the interface has */ + + int inherit_idx; /**< index into binding map of inherited + * interface or -1 for not in map + */ + int refcount; /**< number of entries in map that refer to this + * interface + */ + int output_idx; /**< for interfaces that will be output (node + * is valid) this is the output array index + */ }; struct binding { @@ -59,11 +65,24 @@ struct binding { /** Generate binding between jsapi and netsurf libdom */ int jsapi_libdom_output(struct options *options, struct genbind_node *genbind_ast, struct genbind_node *binding_node); -/** build interface mapping */ +/** Build interface map. + * + * Generate a map of all interfaces referenced from a binding and + * their relationships to each other. + * + * The map will contain all the interfaces both directly referenced by + * the binding and all those inherited through the WebIDL. + * + * The map is topoligicaly sorted to ensure no forward inheritance + * references. + * + * The map contains an monotinicaly incrementing index for all + * interfaces referenced in the binding (i.e. those to be exported). + */ int build_interface_map(struct genbind_node *binding_node, - struct webidl_node *webidl_ast, - int *interfacec_out, - struct binding_interface **interfaces_out); + struct webidl_node *webidl_ast, + int *interfacec_out, + struct binding_interface **interfaces_out); /** output code block from a node */ @@ -75,7 +94,8 @@ int output_jsclasses(struct binding *binding); /* Generate jsapi native function specifiers */ int output_function_spec(struct binding *binding); -/* Generate jsapi native function bodys +/** + * Generate jsapi native function bodies. * * web IDL describes methods as operators * http://www.w3.org/TR/WebIDL/#idl-operations -- cgit v1.2.3 From 94137186a3e2270e9b96f243a82a77a590c17f01 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 16 May 2014 14:38:10 +0100 Subject: make property generation use map --- src/jsapi-libdom-function.c | 5 + src/jsapi-libdom-property.c | 412 ++++++++++++++++++++----------------- src/jsapi-libdom.h | 4 + test/data/bindings/htmlelement.bnd | 4 +- 4 files changed, 238 insertions(+), 187 deletions(-) diff --git a/src/jsapi-libdom-function.c b/src/jsapi-libdom-function.c index af9c215..4f62bcd 100644 --- a/src/jsapi-libdom-function.c +++ b/src/jsapi-libdom-function.c @@ -720,6 +720,11 @@ output_private_get(struct binding *binding, const char *argname) return ret; } +/** + * Generate operator (function) body + * + * + */ static int webidl_operator_body(struct binding *binding, struct binding_interface *inf, struct webidl_node *node) diff --git a/src/jsapi-libdom-property.c b/src/jsapi-libdom-property.c index 93ffcc5..1a6cc33 100644 --- a/src/jsapi-libdom-property.c +++ b/src/jsapi-libdom-property.c @@ -19,25 +19,38 @@ static int generate_property_tinyid(struct binding *binding, const char *interface); static int generate_property_spec(struct binding *binding, const char *interface); -static int generate_property_body(struct binding *binding, const char *interface); /* generate context data fetcher if the binding has private data */ static inline int -output_private_get(struct binding *binding, const char *argname) +output_private_get(struct binding *binding, + struct binding_interface *inf, + const char *argname) { int ret = 0; if (binding->has_private) { ret = fprintf(binding->outfile, - "\tstruct jsclass_private *%s;\n" - "\n" - "\t%s = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n" - "\tif (%s == NULL) {\n" - "\t\treturn JS_FALSE;\n" - "\t}\n\n", - argname, argname, binding->interface, argname); + "\tstruct jsclass_private *%s;\n\n", argname); + + if (inf->refcount == 0) { + /* leaf class so use safer getinstance private */ + ret += fprintf(binding->outfile, + "\t%s = JS_GetInstancePrivate(cx, obj, &JSClass_%s, NULL);\n", + argname, + inf->name); + } else { + ret += fprintf(binding->outfile, + "\t%s = JS_GetPrivate(obj);\n", + argname); + } + + ret += fprintf(binding->outfile, + "\tif (%s == NULL) {\n" + "\t\treturn JS_FALSE;\n" + "\t}\n\n", + argname); if (options->dbglog) { ret += fprintf(binding->outfile, @@ -321,14 +334,15 @@ static bool property_is_ro(struct webidl_node *node) return false; } -static int webidl_property_spec_cb(struct webidl_node *node, void *ctx) +static int webidl_property_spec(struct binding *binding, + struct binding_interface *inf, + struct webidl_node *node) { - struct binding *binding = ctx; - struct webidl_node *type_node; const char *type = NULL; struct webidl_node *ident_node; const char *ident; + bool ro = false; ident_node = webidl_node_find_type(webidl_node_getnode(node), NULL, @@ -356,11 +370,10 @@ static int webidl_property_spec_cb(struct webidl_node *node, void *ctx) /* if there is a putforwards the property requires a setter */ if ((property_is_ro(node)) && (get_keyval_extended_attribute(node, "PutForwards") == NULL)) { - fprintf(binding->outfile, "\tJSAPI_PS_RO(\"%s\",\n", ident); - } else { - fprintf(binding->outfile, "\tJSAPI_PS(\"%s\",\n", ident); + ro = true; } + /* generate property shared status */ switch (get_binding_shared_modifier(binding, type, ident)) { @@ -371,120 +384,110 @@ static int webidl_property_spec_cb(struct webidl_node *node, void *ctx) * js doesnt provide storage and setter/getter must * perform all GC management. */ - fprintf(binding->outfile, - "\t\t%s,\n" - "\t\tJSAPI_PROP_TINYID_%s,\n" - "\t\tJSPROP_SHARED | ", - ident, + fprintf(binding->outfile, + "\tJSAPI_PS_%s(%s, %s, JSPROP_SHARED),\n", + ro?"RO":"RW", + inf->name, ident); break; case GENBIND_TYPE_TYPE: /* shared property with a type handler */ - fprintf(binding->outfile, - "\t\t%s,\n" - "\t\tJSAPI_PROP_TINYID_%s,\n" - "\t\tJSPROP_SHARED | ", - type, - ident); + fprintf(binding->outfile, + "\tJSAPI_PS_ID_%s(%s, %s, JSPROP_SHARED, %s),\n", + ro?"RO":"RW", + inf->name, + ident, + type); break; case GENBIND_TYPE_UNSHARED: /* unshared property without type handler */ - fprintf(binding->outfile, - "\t\t%s,\n" - "\t\tJSAPI_PROP_TINYID_%s,\n" - "\t\t", - ident, ident); + fprintf(binding->outfile, + "\tJSAPI_PS_%s(%s, %s, 0),\n", + ro?"RO":"RW", + inf->name, + ident); break; case GENBIND_TYPE_TYPE_UNSHARED: /* unshared property with a type handler */ - fprintf(binding->outfile, - "\t\t%s,\n" - "\t\tJSAPI_PROP_TINYID_%s,\n" - "\t\t", - type, ident); + fprintf(binding->outfile, + "\tJSAPI_PS_ID_%s(%s, %s, 0, %s),\n", + ro?"RO":"RW", + inf->name, + ident, + type); break; } - fprintf(binding->outfile, "JSPROP_ENUMERATE),\n"); return 0; } - -static int -generate_property_spec(struct binding *binding, const char *interface) -{ - struct webidl_node *interface_node; - struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } - - /* generate property entries for each list (partial interfaces) */ - members_node = webidl_node_find_type(webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); - - while (members_node != NULL) { - - fprintf(binding->outfile,"\t/**** %s ****/\n", interface); - - /* for each property emit a JSAPI_PS() */ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_ATTRIBUTE, - webidl_property_spec_cb, - binding); - - members_node = webidl_node_find_type(webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); - } - - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find(webidl_node_getnode(interface_node), - NULL, - webidl_cmp_node_type, - (void *)WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); - - if (inherit_node != NULL) { - res = generate_property_spec(binding, - webidl_node_gettext(inherit_node)); - } - - return res; -} - - - /* exported interface documented in jsapi-libdom.h */ int output_property_spec(struct binding *binding) { + int inf; int res; + struct webidl_node *list_node; + struct webidl_node *op_node; /* operation on list node */ + + /* for each interface in the map */ + for (inf = 0; inf < binding->interfacec; inf++) { + if (binding->interfaces[inf].own_properties == 0) { + /* if the interface has no properties then + * there is nothing to generate. + */ + continue; + } - fprintf(binding->outfile, - "static JSPropertySpec jsclass_properties[] = {\n"); + /* generate property specifier */ + fprintf(binding->outfile, + "static JSPropertySpec JSClass_%s_properties[] = {\n", + binding->interfaces[inf].name); - res = generate_property_spec(binding, binding->interface); + /* iterate each list within an interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + NULL, + WEBIDL_NODE_TYPE_LIST); - fprintf(binding->outfile, "\tJSAPI_PS_END\n};\n\n"); + while (list_node != NULL) { + /* iterate through operations in a list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + while (op_node != NULL) { + res = webidl_property_spec( + binding, + &binding->interfaces[inf], + op_node); + if (res != 0) { + return res; + } + + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + } - return res; + + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + fprintf(binding->outfile, "\tJSAPI_PS_END\n};\n\n"); + + } + return 0; } @@ -734,6 +737,7 @@ static int output_return_declaration(struct binding *binding, static int output_property_placeholder(struct binding *binding, + struct binding_interface *inf, struct webidl_node* oplist, const char *ident) { @@ -741,34 +745,36 @@ output_property_placeholder(struct binding *binding, WARN(WARNING_UNIMPLEMENTED, "property %s.%s has no implementation\n", - binding->interface, + inf->name, ident); if (options->dbglog) { fprintf(binding->outfile, "\tJSLOG(\"property %s.%s has no implementation\");\n", - binding->interface, + inf->name, ident); } return 0; } static int output_property_getter(struct binding *binding, + struct binding_interface *inf, struct webidl_node *node, const char *ident) { struct genbind_node *property_node; fprintf(binding->outfile, - "static JSBool JSAPI_PROP(%s_get, JSContext *cx, JSObject *obj, jsval *vp)\n" + "static JSBool JSAPI_PROP_GET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", + inf->name, ident); /* return value declaration */ output_return_declaration(binding, "jsret", node); - output_private_get(binding, "private"); + output_private_get(binding, inf, "private"); property_node = genbind_node_find_type_ident(binding->gb_ast, NULL, @@ -801,7 +807,7 @@ static int output_property_getter(struct binding *binding, "\tjsret = private->%s;\n", ident); } else { - output_property_placeholder(binding, node, ident); + output_property_placeholder(binding, inf, node, ident); } } @@ -816,8 +822,9 @@ static int output_property_getter(struct binding *binding, } static int output_property_setter(struct binding *binding, + struct binding_interface *inf, struct webidl_node *node, - const char *ident) + const char *property_ident) { struct genbind_node *property_node; char *putforwards; @@ -827,22 +834,23 @@ static int output_property_setter(struct binding *binding, /* generate a putforwards setter */ fprintf(binding->outfile, "/* PutForwards setter */\n" - "static JSBool JSAPI_STRICTPROP(%s_set, JSContext *cx, JSObject *obj, jsval *vp)\n" + "static JSBool JSAPI_PROP_SET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", - ident); + inf->name, + property_ident); fprintf(binding->outfile, "\tjsval propval;\n" "\tif (JS_GetProperty(cx, obj, \"%s\", &propval) == JS_TRUE) {\n" "\t\tJS_SetProperty(cx, JSVAL_TO_OBJECT(propval), \"%s\", vp);\n" "\t}\n", - ident, putforwards); + property_ident, + putforwards); fprintf(binding->outfile, "\treturn JS_FALSE; /* disallow the asignment */\n" "}\n\n"); - return 0; } @@ -854,20 +862,21 @@ static int output_property_setter(struct binding *binding, property_node = genbind_node_find_type_ident(binding->gb_ast, NULL, GENBIND_NODE_TYPE_SETTER, - ident); + property_ident); fprintf(binding->outfile, - "static JSBool JSAPI_STRICTPROP(%s_set, JSContext *cx, JSObject *obj, jsval *vp)\n" + "static JSBool JSAPI_PROP_SET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", - ident); + inf->name, + property_ident); - output_private_get(binding, "private"); + output_private_get(binding, inf, "private"); if (property_node != NULL) { /* binding source block */ output_code_block(binding, genbind_node_getnode(property_node)); } else { - output_property_placeholder(binding, node, ident); + output_property_placeholder(binding, inf, node, property_ident); } fprintf(binding->outfile, @@ -878,9 +887,13 @@ static int output_property_setter(struct binding *binding, return 0; } -static int webidl_property_body_cb(struct webidl_node *node, void *ctx) +/** + * generate atribute (property) body. + */ +static int webidl_property_body(struct binding *binding, + struct binding_interface *inf, + struct webidl_node *node) { - struct binding *binding = ctx; struct webidl_node *ident_node; const char *ident; struct webidl_node *type_node; @@ -915,76 +928,22 @@ static int webidl_property_body_cb(struct webidl_node *node, void *ctx) * type handler */ if ((shared_mod & GENBIND_TYPE_TYPE) == 0) { - ret = output_property_setter(binding, node, ident); + ret = output_property_setter(binding, inf, node, ident); if (ret == 0) { /* property getter */ - ret = output_property_getter(binding, node, ident); + ret = output_property_getter(binding, inf, node, ident); } } return ret; -} - - -static int -generate_property_body(struct binding *binding, const char *interface) -{ - struct webidl_node *interface_node; - struct webidl_node *members_node; - struct webidl_node *inherit_node; - int res = 0; - - /* find interface in webidl with correct ident attached */ - interface_node = webidl_node_find_type_ident(binding->wi_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface); - - if (interface_node == NULL) { - fprintf(stderr, - "Unable to find interface %s in loaded WebIDL\n", - interface); - return -1; - } - - /* generate property bodies */ - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - - fprintf(binding->outfile,"/**** %s ****/\n", interface); - - /* emit property body */ - webidl_node_for_each_type(webidl_node_getnode(members_node), - WEBIDL_NODE_TYPE_ATTRIBUTE, - webidl_property_body_cb, - binding); - - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); - - } - /* check for inherited nodes and insert them too */ - inherit_node = webidl_node_find_type(webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE); - - if (inherit_node != NULL) { - res = generate_property_body(binding, - webidl_node_gettext(inherit_node)); - } - - return res; } + /* setter for type handler */ static int output_property_type_setter(struct binding *binding, + struct binding_interface *inf, struct genbind_node *node, const char *type) { @@ -1000,7 +959,7 @@ output_property_type_setter(struct binding *binding, /* property name vars */ output_property_tinyid_get_vars(binding, "tinyid"); /* context data */ - output_private_get(binding, "private"); + output_private_get(binding, inf, "private"); /* property name */ output_property_tinyid_get(binding, "tinyid"); @@ -1024,7 +983,10 @@ output_property_type_setter(struct binding *binding, /* getter for type handlers */ -static int output_property_type_getter(struct binding *binding, struct genbind_node *node, const char *type) +static int output_property_type_getter(struct binding *binding, + struct binding_interface *inf, + struct genbind_node *node, + const char *type) { struct genbind_node *property_node; node = node;/* currently unused */ @@ -1037,7 +999,7 @@ static int output_property_type_getter(struct binding *binding, struct genbind_n /* property tinyid vars */ output_property_tinyid_get_vars(binding, "tinyid"); /* context data */ - output_private_get(binding, "private"); + output_private_get(binding, inf, "private"); /* property tinyid */ output_property_tinyid_get(binding, "tinyid"); @@ -1068,6 +1030,7 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx) struct genbind_node *mod_node; enum genbind_type_modifier *share_mod; int ret = 0; + struct binding_interface *inf; mod_node = genbind_node_find_type(genbind_node_getnode(node), NULL, @@ -1083,10 +1046,14 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx) GENBIND_NODE_TYPE_IDENT); type = genbind_node_gettext(ident_node); if (type != NULL) { - ret = output_property_type_setter(binding, node, type); + ret = output_property_type_setter(binding, + inf, + node, + type); if (ret == 0) { /* property getter */ ret = output_property_type_getter(binding, + inf, node, type); } @@ -1095,20 +1062,95 @@ static int typehandler_property_cb(struct genbind_node *node, void *ctx) return ret; } -/* exported interface documented in jsapi-libdom.h */ -int -output_property_body(struct binding *binding) + +/** + * generate atribute (property) type body. + * + * Output property handler for an entire type of property + */ +static int webidl_attribute_typehandler_body(struct binding *binding, + struct binding_interface *inf) { int res; - res = generate_property_body(binding, binding->interface); + /* check if the interface has any properties with type handlers */ + if (!inf->has_type_properties) { + return 0; + } - if (res == 0) { - res = genbind_node_foreach_type(binding->binding_list, + res = genbind_node_foreach_type(binding->binding_list, GENBIND_NODE_TYPE_BINDING_PROPERTY, typehandler_property_cb, binding); - } + return res; + +} + +/* exported interface documented in jsapi-libdom.h */ +int +output_property_body(struct binding *binding) +{ + int inf; + int res; + struct webidl_node *list_node; + struct webidl_node *op_node; /* operation on list node */ + + /* for each interface in the map */ + for (inf = 0; inf < binding->interfacec; inf++) { + if (binding->interfaces[inf].own_properties == 0) { + /* if the interface has no properties then + * there is nothing to generate. + */ + continue; + } + + /* generate property bodies */ + + /* iterate each list within an interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (list_node != NULL) { + /* iterate through operations in a list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + while (op_node != NULL) { + res = webidl_property_body( + binding, + &binding->interfaces[inf], + op_node); + if (res != 0) { + return res; + } + + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + } + + + list_node = webidl_node_find_type( + webidl_node_getnode(binding->interfaces[inf].widl_node), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + /* generate type handler bodies */ + res = webidl_attribute_typehandler_body(binding, + &binding->interfaces[inf]); + + if (res != 0) { + return res; + } + + } + return 0; } diff --git a/src/jsapi-libdom.h b/src/jsapi-libdom.h index 2925866..e8d57c4 100644 --- a/src/jsapi-libdom.h +++ b/src/jsapi-libdom.h @@ -19,6 +19,10 @@ struct binding_interface { int own_properties; /**< the number of properties the interface has */ int own_functions; /**< the number of functions the interface has */ + bool has_type_properties; /**< some of the properties on the + * interface have a type handler + */ + int inherit_idx; /**< index into binding map of inherited * interface or -1 for not in map */ diff --git a/test/data/bindings/htmlelement.bnd b/test/data/bindings/htmlelement.bnd index 1457a32..999a16f 100644 --- a/test/data/bindings/htmlelement.bnd +++ b/test/data/bindings/htmlelement.bnd @@ -37,8 +37,6 @@ preamble %{ binding jsapi_libdom { - interface Text; - interface Comment; interface HTMLElement; interface HTMLAnchorElement; interface HTMLAnchorElement; @@ -110,6 +108,8 @@ binding jsapi_libdom { interface HTMLTrackElement; interface HTMLUListElement; interface HTMLUnknownElement; + interface Text; + interface Comment; private "dom_element *" node; private "struct html_content *" htmlc; -- cgit v1.2.3 From 1288d8c535edd2ce29eebdc4acca6b2beab89841 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 21 Jul 2015 23:48:45 +0100 Subject: Change binding grammar to new approach. --- README | 62 +- src/Makefile | 3 +- src/nsgenbind-ast.c | 759 +++++------ src/nsgenbind-ast.h | 113 +- src/nsgenbind-lexer.l | 39 +- src/nsgenbind-parser.y | 386 +++--- src/nsgenbind.c | 324 +++-- src/options.h | 15 +- src/utils.c | 52 + src/utils.h | 21 + test/data/bindings/browser-duk.bnd | 66 + test/data/idl/console.idl | 24 + test/data/idl/dom.idl | 343 ++--- test/data/idl/html.idl | 2450 +++++++++++++++++++----------------- 14 files changed, 2556 insertions(+), 2101 deletions(-) create mode 100644 src/utils.c create mode 100644 src/utils.h create mode 100644 test/data/bindings/browser-duk.bnd create mode 100644 test/data/idl/console.idl diff --git a/README b/README index 70d224f..e260642 100644 --- a/README +++ b/README @@ -7,4 +7,64 @@ files and a binding configuration file. building -------- -The tool requires bison and flex as pre-requisites \ No newline at end of file +The tool requires bison and flex as pre-requisites + +Commandline +----------- + +nsgenbind [-v] [-g] [-D] [-W] [-I idlpath] inputfile outputdir + +-v +The verbose switch makes the tool verbose about what operations it is +performing instead of teh default of only reporting errors. + +-g +The generated code will be augmented with runtime debug logging so it +can be traced + +-D +The tool will generate output to allow debugging of output conversion. +This includes dumps of the binding and IDL files AST + +-W +This switch will make the tool generate warnings about various issues +with the binding or IDL files being processed. + +-I +An additional search path may be given so idl files can be located. + +The tool requires a binding file as input and an output directory in +which to place its output. + + +Web IDL +------- + +The IDL is specified in a w3c document[1] but the second edition is in +draft[2] and covers many of the features actually used in the whatwg +dom and html spec. + +The principal usage of the IDL is to define the interface between +scripts and a browsers internal state. For example the DOM[3] and +HTML[4] specs contain all the IDL for acessing the DOM and interacting +with a web browser (this not strictly true as there are several +interfaces simply not in the standards such as console). + +The IDL uses some slightly strange names than other object orientated +systems. + + IDL | JS | OOP | Notes +-----------+------------------+----------------+---------------------------- + interface | prototype | class | The data definition of + | | | the object + constants | read-only value | class variable | Belong to class, one copy + | property on the | | + | prototype | | + operation | method | method | functions that can be called + attribute | property | property | Variables set per instance +-----------+------------------+----------------+---------------------------- + +[1] http://www.w3.org/TR/WebIDL/ +[2] https://heycam.github.io/webidl/ +[3] https://dom.spec.whatwg.org/ +[4] https://html.spec.whatwg.org/ diff --git a/src/Makefile b/src/Makefile index e93cb99..3e5b8af 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,8 @@ CFLAGS := $(CFLAGS) -I$(BUILDDIR) -Isrc/ -g -DYYENABLE_NLS=0 # Sources in this directory -DIR_SOURCES := nsgenbind.c webidl-ast.c nsgenbind-ast.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 +DIR_SOURCES := nsgenbind.c utils.c webidl-ast.c nsgenbind-ast.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/nsgenbind-ast.c b/src/nsgenbind-ast.c index 2f630b7..49477cf 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -14,7 +14,9 @@ #include #include #include +#include +#include "utils.h" #include "nsgenbind-ast.h" #include "options.h" @@ -26,478 +28,521 @@ extern int nsgenbind_parse(struct genbind_node **genbind_ast); /* terminal nodes have a value only */ struct genbind_node { - enum genbind_node_type type; - struct genbind_node *l; - union { - void *value; - struct genbind_node *node; - char *text; - int number; /* node data is an integer */ - } r; + enum genbind_node_type type; + struct genbind_node *l; + union { + void *value; + struct genbind_node *node; + char *text; + int number; /* node data is an integer */ + } r; }; char *genbind_strapp(char *a, char *b) { - char *fullstr; - int fulllen; - fulllen = strlen(a) + strlen(b) + 1; - fullstr = malloc(fulllen); - snprintf(fullstr, fulllen, "%s%s", a, b); - free(a); - free(b); - return fullstr; + char *fullstr; + int fulllen; + fulllen = strlen(a) + strlen(b) + 1; + fullstr = malloc(fulllen); + snprintf(fullstr, fulllen, "%s%s", a, b); + free(a); + free(b); + return fullstr; } struct genbind_node * genbind_node_link(struct genbind_node *tgt, struct genbind_node *src) { - tgt->l = src; - return tgt; + tgt->l = src; + return tgt; } struct genbind_node * genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r) { - struct genbind_node *nn; - nn = calloc(1, sizeof(struct genbind_node)); - nn->type = type; - nn->l = l; - nn->r.value = r; - return nn; + struct genbind_node *nn; + nn = calloc(1, sizeof(struct genbind_node)); + nn->type = type; + nn->l = l; + nn->r.value = r; + return nn; } /* exported interface defined in nsgenbind-ast.h */ int genbind_node_foreach_type(struct genbind_node *node, - enum genbind_node_type type, - genbind_callback_t *cb, - void *ctx) + enum genbind_node_type type, + genbind_callback_t *cb, + void *ctx) { - int ret; - - if (node == NULL) { - return -1; - } - if (node->l != NULL) { - ret = genbind_node_foreach_type(node->l, type, cb, ctx); - if (ret != 0) { - return ret; - } - } - if (node->type == type) { - return cb(node, ctx); - } - - return 0; + int ret; + + if (node == NULL) { + return -1; + } + if (node->l != NULL) { + ret = genbind_node_foreach_type(node->l, type, cb, ctx); + if (ret != 0) { + return ret; + } + } + if (node->type == type) { + return cb(node, ctx); + } + + return 0; } static int genbind_enumerate_node(struct genbind_node *node, void *ctx) { - node = node; - (*((int *)ctx))++; - return 0; + node = node; + (*((int *)ctx))++; + return 0; } /* exported interface defined in nsgenbind-ast.h */ int genbind_node_enumerate_type(struct genbind_node *node, - enum genbind_node_type type) + enum genbind_node_type type) { - int count = 0; - genbind_node_foreach_type(node, - type, - genbind_enumerate_node, - &count); - return count; + int count = 0; + genbind_node_foreach_type(node, + type, + genbind_enumerate_node, + &count); + return count; } /* exported interface defined in nsgenbind-ast.h */ struct genbind_node * genbind_node_find(struct genbind_node *node, - struct genbind_node *prev, - genbind_callback_t *cb, - void *ctx) + struct genbind_node *prev, + genbind_callback_t *cb, + void *ctx) { - struct genbind_node *ret; + struct genbind_node *ret; - if ((node == NULL) || (node == prev)) { - return NULL; - } + if ((node == NULL) || (node == prev)) { + return NULL; + } - if (node->l != prev) { - ret = genbind_node_find(node->l, prev, cb, ctx); - if (ret != NULL) { - return ret; - } - } + if (node->l != prev) { + ret = genbind_node_find(node->l, prev, cb, ctx); + if (ret != NULL) { + return ret; + } + } - if (cb(node, ctx) != 0) { - return node; - } + if (cb(node, ctx) != 0) { + return node; + } - return NULL; + return NULL; } /* exported interface documented in nsgenbind-ast.h */ struct genbind_node * genbind_node_find_type(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type type) + struct genbind_node *prev, + enum genbind_node_type type) { - return genbind_node_find(node, - prev, - genbind_cmp_node_type, - (void *)type); + return genbind_node_find(node, + prev, + genbind_cmp_node_type, + (void *)type); } /* exported interface documented in nsgenbind-ast.h */ struct genbind_node * genbind_node_find_type_ident(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type type, - const char *ident) + struct genbind_node *prev, + enum genbind_node_type type, + const char *ident) { - struct genbind_node *found_node; - struct genbind_node *ident_node; - - if (ident == NULL) { - return NULL; - } - - found_node = genbind_node_find_type(node, prev, type); - - while (found_node != NULL) { - /* look for an ident node */ - ident_node = genbind_node_find_type( - genbind_node_getnode(found_node), - NULL, - GENBIND_NODE_TYPE_IDENT); - - while (ident_node != NULL) { - /* check for matching text */ - if (strcmp(ident_node->r.text, ident) == 0) { - return found_node; - } - - ident_node = genbind_node_find_type( - genbind_node_getnode(found_node), - ident_node, - GENBIND_NODE_TYPE_IDENT); - } - - - /* look for next matching node */ - found_node = genbind_node_find_type(node, found_node, type); - } - return found_node; + struct genbind_node *found_node; + struct genbind_node *ident_node; + + if (ident == NULL) { + return NULL; + } + + found_node = genbind_node_find_type(node, prev, type); + + while (found_node != NULL) { + /* look for an ident node */ + ident_node = genbind_node_find_type( + genbind_node_getnode(found_node), + NULL, + GENBIND_NODE_TYPE_IDENT); + + while (ident_node != NULL) { + /* check for matching text */ + if (strcmp(ident_node->r.text, ident) == 0) { + return found_node; + } + + ident_node = genbind_node_find_type( + genbind_node_getnode(found_node), + ident_node, + GENBIND_NODE_TYPE_IDENT); + } + + + /* look for next matching node */ + found_node = genbind_node_find_type(node, found_node, type); + } + return found_node; } /* exported interface documented in nsgenbind-ast.h */ struct genbind_node * genbind_node_find_type_type(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type type, - const char *ident) + struct genbind_node *prev, + enum genbind_node_type type, + const char *ident) { - struct genbind_node *found_node; - struct genbind_node *ident_node; - - found_node = genbind_node_find_type(node, prev, type); - - - while (found_node != NULL) { - /* look for a type node */ - ident_node = genbind_node_find_type(genbind_node_getnode(found_node), - NULL, - GENBIND_NODE_TYPE_TYPE); - if (ident_node != NULL) { - if (strcmp(ident_node->r.text, ident) == 0) - break; - } - - /* look for next matching node */ - found_node = genbind_node_find_type(node, found_node, type); - } - return found_node; + struct genbind_node *found_node; + struct genbind_node *ident_node; + + found_node = genbind_node_find_type(node, prev, type); + + + while (found_node != NULL) { + /* look for a type node */ + ident_node = genbind_node_find_type(genbind_node_getnode(found_node), + NULL, + GENBIND_NODE_TYPE_TYPE); + if (ident_node != NULL) { + if (strcmp(ident_node->r.text, ident) == 0) + break; + } + + /* look for next matching node */ + found_node = genbind_node_find_type(node, found_node, type); + } + return found_node; } int genbind_cmp_node_type(struct genbind_node *node, void *ctx) { - if (node->type == (enum genbind_node_type)ctx) - return 1; - return 0; + if (node->type == (enum genbind_node_type)ctx) + return 1; + return 0; } char *genbind_node_gettext(struct genbind_node *node) { - if (node != NULL) { - switch(node->type) { - case GENBIND_NODE_TYPE_WEBIDLFILE: - case GENBIND_NODE_TYPE_STRING: - case GENBIND_NODE_TYPE_PREAMBLE: - case GENBIND_NODE_TYPE_PROLOGUE: - case GENBIND_NODE_TYPE_EPILOGUE: - case GENBIND_NODE_TYPE_IDENT: - case GENBIND_NODE_TYPE_TYPE: - case GENBIND_NODE_TYPE_CBLOCK: - return node->r.text; - - default: - break; - } - } - return NULL; + if (node != NULL) { + switch(node->type) { + case GENBIND_NODE_TYPE_WEBIDL: + case GENBIND_NODE_TYPE_STRING: + case GENBIND_NODE_TYPE_PREFACE: + case GENBIND_NODE_TYPE_PROLOGUE: + case GENBIND_NODE_TYPE_EPILOGUE: + case GENBIND_NODE_TYPE_POSTFACE: + case GENBIND_NODE_TYPE_IDENT: + case GENBIND_NODE_TYPE_TYPE: + case GENBIND_NODE_TYPE_CDATA: + return node->r.text; + + default: + break; + } + } + return NULL; } struct genbind_node *genbind_node_getnode(struct genbind_node *node) { - if (node != NULL) { - switch(node->type) { - case GENBIND_NODE_TYPE_HDRCOMMENT: - case GENBIND_NODE_TYPE_BINDING: - case GENBIND_NODE_TYPE_BINDING_PRIVATE: - case GENBIND_NODE_TYPE_BINDING_INTERNAL: - case GENBIND_NODE_TYPE_BINDING_PROPERTY: - case GENBIND_NODE_TYPE_BINDING_INTERFACE: - case GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS: - case GENBIND_NODE_TYPE_OPERATION: - case GENBIND_NODE_TYPE_API: - case GENBIND_NODE_TYPE_GETTER: - case GENBIND_NODE_TYPE_SETTER: - return node->r.node; - - default: - break; - } - } - return NULL; + if (node != NULL) { + switch(node->type) { + case GENBIND_NODE_TYPE_BINDING: + case GENBIND_NODE_TYPE_CLASS: + case GENBIND_NODE_TYPE_PRIVATE: + case GENBIND_NODE_TYPE_INTERNAL: + case GENBIND_NODE_TYPE_PROPERTY: + case GENBIND_NODE_TYPE_FLAGS: + case GENBIND_NODE_TYPE_METHOD: + case GENBIND_NODE_TYPE_PARAMETER: + return node->r.node; + + default: + break; + } + } + return NULL; } int *genbind_node_getint(struct genbind_node *node) { - if (node != NULL) { - switch(node->type) { - case GENBIND_NODE_TYPE_MODIFIER: - return &node->r.number; - - default: - break; - } - } - return NULL; + if (node != NULL) { + switch(node->type) { + case GENBIND_NODE_TYPE_METHOD_TYPE: + case GENBIND_NODE_TYPE_MODIFIER: + return &node->r.number; + + default: + break; + } + } + return NULL; } static const char *genbind_node_type_to_str(enum genbind_node_type type) { - switch(type) { - case GENBIND_NODE_TYPE_IDENT: - return "Ident"; + switch(type) { + case GENBIND_NODE_TYPE_IDENT: + return "Ident"; - case GENBIND_NODE_TYPE_ROOT: - return "Root"; + case GENBIND_NODE_TYPE_ROOT: + return "Root"; - case GENBIND_NODE_TYPE_WEBIDLFILE: - return "webidlfile"; + case GENBIND_NODE_TYPE_WEBIDL: + return "webidl"; - case GENBIND_NODE_TYPE_HDRCOMMENT: - return "HdrComment"; + case GENBIND_NODE_TYPE_STRING: + return "String"; - case GENBIND_NODE_TYPE_STRING: - return "String"; + case GENBIND_NODE_TYPE_PREFACE: + return "Preface"; - case GENBIND_NODE_TYPE_PREAMBLE: - return "Preamble"; + case GENBIND_NODE_TYPE_POSTFACE: + return "Postface"; - case GENBIND_NODE_TYPE_BINDING: - return "Binding"; + case GENBIND_NODE_TYPE_PROLOGUE: + return "Prologue"; - case GENBIND_NODE_TYPE_TYPE: - return "Type"; + case GENBIND_NODE_TYPE_EPILOGUE: + return "Epilogue"; - case GENBIND_NODE_TYPE_BINDING_PRIVATE: - return "Private"; + case GENBIND_NODE_TYPE_BINDING: + return "Binding"; - case GENBIND_NODE_TYPE_BINDING_INTERNAL: - return "Internal"; + case GENBIND_NODE_TYPE_TYPE: + return "Type"; - case GENBIND_NODE_TYPE_BINDING_INTERFACE: - return "Interface"; + case GENBIND_NODE_TYPE_PRIVATE: + return "Private"; - case GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS: - return "Flags"; + case GENBIND_NODE_TYPE_INTERNAL: + return "Internal"; - case GENBIND_NODE_TYPE_BINDING_PROPERTY: - return "Property"; + case GENBIND_NODE_TYPE_CLASS: + return "Class"; - case GENBIND_NODE_TYPE_OPERATION: - return "Operation"; + case GENBIND_NODE_TYPE_FLAGS: + return "Flags"; - case GENBIND_NODE_TYPE_API: - return "API"; + case GENBIND_NODE_TYPE_PROPERTY: + return "Property"; - case GENBIND_NODE_TYPE_GETTER: - return "Getter"; + case GENBIND_NODE_TYPE_METHOD: + return "Method"; - case GENBIND_NODE_TYPE_SETTER: - return "Setter"; + case GENBIND_NODE_TYPE_METHOD_TYPE: + return "Type"; - case GENBIND_NODE_TYPE_CBLOCK: - return "CBlock"; + case GENBIND_NODE_TYPE_PARAMETER: + return "Parameter"; - default: - return "Unknown"; - } + case GENBIND_NODE_TYPE_CDATA: + return "CBlock"; + + default: + return "Unknown"; + } } -int genbind_ast_dump(struct genbind_node *node, int indent) +/** dump ast node to file at indent level */ +static int genbind_ast_dump(FILE *dfile, struct genbind_node *node, int indent) { - const char *SPACES=" "; - char *txt; - - while (node != NULL) { - printf("%.*s%s", indent, SPACES, genbind_node_type_to_str(node->type)); - - txt = genbind_node_gettext(node); - if (txt == NULL) { - printf("\n"); - genbind_ast_dump(genbind_node_getnode(node), indent + 2); - } else { - printf(": \"%.*s\"\n", 75 - indent, txt); - } - node = node->l; - } - return 0; + const char *SPACES=" "; + char *txt; + int *val; + + while (node != NULL) { + fprintf(dfile, "%.*s%s", indent, SPACES, + genbind_node_type_to_str(node->type)); + + txt = genbind_node_gettext(node); + if (txt == NULL) { + val = genbind_node_getint(node); + if (val == NULL) { + fprintf(dfile, "\n"); + genbind_ast_dump(dfile, + genbind_node_getnode(node), + indent + 2); + } else { + fprintf(dfile, ": %d\n", *val); + } + } else { + fprintf(dfile, ": \"%.*s\"\n", 75 - indent, txt); + } + node = node->l; + } + return 0; } -FILE *genbindopen(const char *filename) + +/* exported interface documented in nsgenbind-ast.h */ +int genbind_dump_ast(struct genbind_node *node) { - FILE *genfile; - char *fullname; - int fulllen; - static char *prevfilepath = NULL; - - /* try filename raw */ - genfile = fopen(filename, "r"); - if (genfile != NULL) { - if (options->verbose) { - printf("Opened Genbind file %s\n", filename); - } - if (prevfilepath == NULL) { - fullname = strrchr(filename, '/'); - if (fullname == NULL) { - fulllen = strlen(filename); - } else { - fulllen = fullname - filename; - } - prevfilepath = strndup(filename,fulllen); - } - if (options->depfilehandle != NULL) { - fprintf(options->depfilehandle, " \\\n\t%s", - filename); - } - return genfile; - } - - /* try based on previous filename */ - if (prevfilepath != NULL) { - fulllen = strlen(prevfilepath) + strlen(filename) + 2; - fullname = malloc(fulllen); - snprintf(fullname, fulllen, "%s/%s", prevfilepath, filename); - if (options->debug) { - printf("Attempting to open Genbind file %s\n", fullname); - } - genfile = fopen(fullname, "r"); - if (genfile != NULL) { - if (options->verbose) { - printf("Opened Genbind file %s\n", fullname); - } - if (options->depfilehandle != NULL) { - fprintf(options->depfilehandle, " \\\n\t%s", - fullname); - } - free(fullname); - return genfile; - } - free(fullname); - } - - /* try on idl path */ - if (options->idlpath != NULL) { - fulllen = strlen(options->idlpath) + strlen(filename) + 2; - fullname = malloc(fulllen); - snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename); - genfile = fopen(fullname, "r"); - if ((genfile != NULL) && options->verbose) { - printf("Opend Genbind file %s\n", fullname); - if (options->depfilehandle != NULL) { - fprintf(options->depfilehandle, " \\\n\t%s", - fullname); - } - } - - free(fullname); - } - - return genfile; + FILE *dumpf; + + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } + + dumpf = genb_fopen("binding-ast", "w"); + if (dumpf == NULL) { + return 2; + } + + genbind_ast_dump(dumpf, node, 0); + + fclose(dumpf); + + return 0; } -int genbind_parsefile(char *infilename, struct genbind_node **ast) +FILE *genbindopen(const char *filename) { - FILE *infile; - - /* open input file */ - if ((infilename[0] == '-') && - (infilename[1] == 0)) { - if (options->verbose) { - printf("Using stdin for input\n"); - } - infile = stdin; - } else { - infile = genbindopen(infilename); - } - - if (!infile) { - fprintf(stderr, "Error opening %s: %s\n", - infilename, - strerror(errno)); - return 3; - } - - if (options->debug) { - nsgenbind_debug = 1; - nsgenbind__flex_debug = 1; - } - - /* set flex to read from file */ - nsgenbind_restart(infile); - - /* process binding */ - return nsgenbind_parse(ast); + FILE *genfile; + char *fullname; + int fulllen; + static char *prevfilepath = NULL; + + /* try filename raw */ + genfile = fopen(filename, "r"); + if (genfile != NULL) { + if (options->verbose) { + printf("Opened Genbind file %s\n", filename); + } + if (prevfilepath == NULL) { + fullname = strrchr(filename, '/'); + if (fullname == NULL) { + fulllen = strlen(filename); + } else { + fulllen = fullname - filename; + } + prevfilepath = strndup(filename,fulllen); + } +#if 0 + if (options->depfilehandle != NULL) { + fprintf(options->depfilehandle, " \\\n\t%s", + filename); + } +#endif + return genfile; + } + + /* try based on previous filename */ + if (prevfilepath != NULL) { + fulllen = strlen(prevfilepath) + strlen(filename) + 2; + fullname = malloc(fulllen); + snprintf(fullname, fulllen, "%s/%s", prevfilepath, filename); + if (options->debug) { + printf("Attempting to open Genbind file %s\n", fullname); + } + genfile = fopen(fullname, "r"); + if (genfile != NULL) { + if (options->verbose) { + printf("Opened Genbind file %s\n", fullname); + } +#if 0 + if (options->depfilehandle != NULL) { + fprintf(options->depfilehandle, " \\\n\t%s", + fullname); + } +#endif + free(fullname); + return genfile; + } + free(fullname); + } + + /* try on idl path */ + if (options->idlpath != NULL) { + fulllen = strlen(options->idlpath) + strlen(filename) + 2; + fullname = malloc(fulllen); + snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename); + genfile = fopen(fullname, "r"); + if ((genfile != NULL) && options->verbose) { + printf("Opend Genbind file %s\n", fullname); +#if 0 + if (options->depfilehandle != NULL) { + fprintf(options->depfilehandle, " \\\n\t%s", + fullname); + } +#endif + } + + free(fullname); + } + return genfile; } -#ifdef NEED_STRNDUP +/** + * standard IO handle for parse trace logging. + */ +static FILE *genbind_parsetracef; -char *strndup(const char *s, size_t n) +int genbind_parsefile(char *infilename, struct genbind_node **ast) { - size_t len; - char *s2; - - for (len = 0; len != n && s[len]; len++) - continue; + FILE *infile; + int ret; + + /* open input file */ + infile = genbindopen(infilename); + if (!infile) { + fprintf(stderr, "Error opening %s: %s\n", + infilename, + strerror(errno)); + return 3; + } + + /* if debugging enabled enable parser tracing and send to file */ + if (options->debug) { + nsgenbind_debug = 1; + nsgenbind__flex_debug = 1; + genbind_parsetracef = genb_fopen("binding-trace", "w"); + } else { + genbind_parsetracef = NULL; + } + + /* set flex to read from file */ + nsgenbind_restart(infile); + + /* process binding */ + ret = nsgenbind_parse(ast); + + /* close tracefile if open */ + if (genbind_parsetracef != NULL) { + fclose(genbind_parsetracef); + } + + return ret; +} - s2 = malloc(len + 1); - if (!s2) - return 0; +int genbind_fprintf(FILE *stream, const char *format, ...) +{ + va_list ap; + int ret; - memcpy(s2, s, len); - s2[len] = 0; - return s2; -} + va_start(ap, format); -#endif + if (genbind_parsetracef == NULL) { + ret = vfprintf(stream, format, ap); + } else { + ret = vfprintf(genbind_parsetracef, format, ap); + } + va_end(ap); + return ret; +} diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index 4911f5a..f6800fb 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -10,36 +10,46 @@ #define nsgenbind_nsgenbind_ast_h enum genbind_node_type { - GENBIND_NODE_TYPE_ROOT = 0, - GENBIND_NODE_TYPE_IDENT, /**< generic identifier string */ - GENBIND_NODE_TYPE_TYPE, /**< generic type string */ - GENBIND_NODE_TYPE_MODIFIER, /**< node modifier */ - - GENBIND_NODE_TYPE_CBLOCK, - GENBIND_NODE_TYPE_WEBIDLFILE, - GENBIND_NODE_TYPE_HDRCOMMENT, - GENBIND_NODE_TYPE_STRING, - GENBIND_NODE_TYPE_PREAMBLE, - GENBIND_NODE_TYPE_PROLOGUE, - GENBIND_NODE_TYPE_EPILOGUE, - GENBIND_NODE_TYPE_BINDING, - GENBIND_NODE_TYPE_BINDING_PRIVATE, - GENBIND_NODE_TYPE_BINDING_INTERNAL, - GENBIND_NODE_TYPE_BINDING_INTERFACE, - GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, - GENBIND_NODE_TYPE_BINDING_PROPERTY, - GENBIND_NODE_TYPE_API, - GENBIND_NODE_TYPE_OPERATION, - GENBIND_NODE_TYPE_GETTER, - GENBIND_NODE_TYPE_SETTER, + GENBIND_NODE_TYPE_ROOT = 0, + GENBIND_NODE_TYPE_IDENT, /**< generic identifier string */ + GENBIND_NODE_TYPE_TYPE, /**< generic type string */ + GENBIND_NODE_TYPE_MODIFIER, /**< node modifier */ + GENBIND_NODE_TYPE_CDATA, /**< verbatim block of character data */ + GENBIND_NODE_TYPE_STRING, /**< text string */ + + GENBIND_NODE_TYPE_BINDING, + GENBIND_NODE_TYPE_WEBIDL, + GENBIND_NODE_TYPE_PREFACE, + GENBIND_NODE_TYPE_PROLOGUE, + GENBIND_NODE_TYPE_EPILOGUE, + GENBIND_NODE_TYPE_POSTFACE, + + GENBIND_NODE_TYPE_CLASS, /**< class definition */ + GENBIND_NODE_TYPE_PRIVATE, + GENBIND_NODE_TYPE_INTERNAL, + GENBIND_NODE_TYPE_PROPERTY, + GENBIND_NODE_TYPE_FLAGS, + + GENBIND_NODE_TYPE_METHOD, /**< binding method */ + GENBIND_NODE_TYPE_METHOD_TYPE, /**< binding method type */ + GENBIND_NODE_TYPE_PARAMETER, /**< method parameter */ }; /* modifier flags */ enum genbind_type_modifier { - GENBIND_TYPE_NONE = 0, - GENBIND_TYPE_TYPE = 1, /**< identifies a type handler */ - GENBIND_TYPE_UNSHARED = 2, /**< unshared item */ - GENBIND_TYPE_TYPE_UNSHARED = 3, /**< identifies a unshared type handler */ + GENBIND_TYPE_NONE = 0, + GENBIND_TYPE_TYPE = 1, /**< identifies a type handler */ + GENBIND_TYPE_UNSHARED = 2, /**< unshared item */ + GENBIND_TYPE_TYPE_UNSHARED = 3, /**< identifies a unshared type handler */ +}; + +/* binding method types */ +enum genbind_method_type { + GENBIND_METHOD_TYPE_INIT = 0, + GENBIND_METHOD_TYPE_FINI = 1, /**< */ + GENBIND_METHOD_TYPE_METHOD = 2, /**< */ + GENBIND_METHOD_TYPE_GETTER = 3, /**< */ + GENBIND_METHOD_TYPE_SETTER = 4, /**< */ }; struct genbind_node; @@ -47,6 +57,8 @@ struct genbind_node; /** callback for search and iteration routines */ typedef int (genbind_callback_t)(struct genbind_node *node, void *ctx); +int genbind_fprintf(FILE *stream, const char *format, ...); + int genbind_cmp_node_type(struct genbind_node *node, void *ctx); FILE *genbindopen(const char *filename); @@ -58,9 +70,19 @@ char *genbind_strapp(char *a, char *b); struct genbind_node *genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r); struct genbind_node *genbind_node_link(struct genbind_node *tgt, struct genbind_node *src); -int genbind_ast_dump(struct genbind_node *ast, int indent); +/** + * Dump the binding AST to file + * + * If the debug flag has been set this causes the binding AST to be written to + * a binding-ast output file + * + * \param node Node of the tree to start dumping from (usually tree root) + * \return 0 on sucess or non zero on faliure and error message printed. + */ +int genbind_dump_ast(struct genbind_node *node); -/** Depth first left hand search using user provided comparison +/** + *Depth first left hand search using user provided comparison * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to @@ -71,9 +93,9 @@ int genbind_ast_dump(struct genbind_node *ast, int indent); */ struct genbind_node * genbind_node_find(struct genbind_node *node, - struct genbind_node *prev, - genbind_callback_t *cb, - void *ctx); + struct genbind_node *prev, + genbind_callback_t *cb, + void *ctx); /** Depth first left hand search returning nodes of the specified type * @@ -86,8 +108,8 @@ genbind_node_find(struct genbind_node *node, */ struct genbind_node * genbind_node_find_type(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type nodetype); + struct genbind_node *prev, + enum genbind_node_type nodetype); /** count how many nodes of a specified type. * @@ -101,7 +123,7 @@ genbind_node_find_type(struct genbind_node *node, */ int genbind_node_enumerate_type(struct genbind_node *node, - enum genbind_node_type type); + enum genbind_node_type type); /** Depth first left hand search returning nodes of the specified type * and a ident child node with matching text @@ -115,9 +137,9 @@ genbind_node_enumerate_type(struct genbind_node *node, */ struct genbind_node * genbind_node_find_type_ident(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type nodetype, - const char *ident); + struct genbind_node *prev, + enum genbind_node_type nodetype, + const char *ident); /** Returning node of the specified type with a GENBIND_NODE_TYPE_TYPE * subnode with matching text. @@ -137,9 +159,9 @@ genbind_node_find_type_ident(struct genbind_node *node, */ struct genbind_node * genbind_node_find_type_type(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type nodetype, - const char *type_text); + struct genbind_node *prev, + enum genbind_node_type nodetype, + const char *type_text); /** Iterate all nodes of a certian type from a node with a callback. * @@ -149,9 +171,9 @@ genbind_node_find_type_type(struct genbind_node *node, * @param node The node to start the search from. */ int genbind_node_foreach_type(struct genbind_node *node, - enum genbind_node_type type, - genbind_callback_t *cb, - void *ctx); + enum genbind_node_type type, + genbind_callback_t *cb, + void *ctx); /** get a nodes node list content * @@ -176,9 +198,4 @@ char *genbind_node_gettext(struct genbind_node *node); */ int *genbind_node_getint(struct genbind_node *node); -#ifdef _WIN32 -#define NEED_STRNDUP 1 -char *strndup(const char *s, size_t n); -#endif - #endif diff --git a/src/nsgenbind-lexer.l b/src/nsgenbind-lexer.l index 4b5e225..f7b6528 100644 --- a/src/nsgenbind-lexer.l +++ b/src/nsgenbind-lexer.l @@ -72,7 +72,9 @@ cblockopen \%\{ cblockclose \%\} /* used for #include directive */ -poundsign ^{whitespace}*# +poundsign ^{whitespace}*# + +dblcolon \:\: %x cblock @@ -88,44 +90,55 @@ poundsign ^{whitespace}*# yylloc->last_column = 0; } - /* terminals */ + /* binding terminals */ -webidlfile return TOK_IDLFILE; +binding return TOK_BINDING; -hdrcomment return TOK_HDR_COMMENT; +webidl return TOK_WEBIDL; -preamble return TOK_PREAMBLE; +preface return TOK_PREFACE; prologue return TOK_PROLOGUE; epilogue return TOK_EPILOGUE; -binding return TOK_BINDING; +postface return TOK_POSTFACE; -interface return TOK_INTERFACE; -flags return TOK_FLAGS; + /* class member terminals */ -type return TOK_TYPE; +class return TOK_CLASS; private return TOK_PRIVATE; internal return TOK_INTERNAL; +flags return TOK_FLAGS; + +type return TOK_TYPE; + unshared return TOK_UNSHARED; shared return TOK_SHARED; property return TOK_PROPERTY; -operation return TOK_OPERATION; + /* implementation terminals */ + +init return TOK_INIT; -api return TOK_API; +fini return TOK_FINI; + +method return TOK_METHOD; getter return TOK_GETTER; setter return TOK_SETTER; + /* other terminals */ + +{dblcolon} return TOK_DBLCOLON; + {cblockopen} BEGIN(cblock); {identifier} { @@ -140,7 +153,7 @@ setter return TOK_SETTER; {multicomment} /* nothing */ -{poundsign}include BEGIN(incl); +{poundsign}include BEGIN(incl); {other} return (int) yytext[0]; @@ -151,7 +164,7 @@ setter return TOK_SETTER; \% yylval->text = strdup(yytext); return TOK_CCODE_LITERAL; -[ \t]*\" /* eat the whitespace and open quotes */ +[ \t]*\" /* eat the whitespace and open quotes */ [^\t\n\"]+ { /* got the include file name */ diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index b37ab9d..c8e5154 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -10,6 +10,12 @@ #include #include +#define YYFPRINTF genbind_fprintf +#define YY_LOCATION_PRINT(File, Loc) \ + genbind_fprintf(File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) + #include "nsgenbind-parser.h" #include "nsgenbind-lexer.h" #include "webidl-ast.h" @@ -17,7 +23,9 @@ char *errtxt; - static void nsgenbind_error(YYLTYPE *locp, struct genbind_node **genbind_ast, const char *str) +static void nsgenbind_error(YYLTYPE *locp, + struct genbind_node **genbind_ast, + const char *str) { locp = locp; genbind_ast = genbind_ast; @@ -37,31 +45,36 @@ char *errtxt; %union { - char* text; + char *text; struct genbind_node *node; long value; } -%token TOK_IDLFILE -%token TOK_HDR_COMMENT -%token TOK_PREAMBLE -%token TOK_PROLOGUE; -%token TOK_EPILOGUE; - -%token TOK_API %token TOK_BINDING -%token TOK_OPERATION -%token TOK_GETTER -%token TOK_SETTER -%token TOK_INTERFACE -%token TOK_FLAGS -%token TOK_TYPE +%token TOK_WEBIDL +%token TOK_PREFACE +%token TOK_PROLOGUE +%token TOK_EPILOGUE +%token TOK_POSTFACE + +%token TOK_CLASS %token TOK_PRIVATE %token TOK_INTERNAL +%token TOK_FLAGS +%token TOK_TYPE %token TOK_UNSHARED %token TOK_SHARED %token TOK_PROPERTY + /* method types */ +%token TOK_INIT +%token TOK_FINI +%token TOK_METHOD +%token TOK_GETTER +%token TOK_SETTER + +%token TOK_DBLCOLON + %token TOK_IDENTIFIER %token TOK_STRING_LITERAL %token TOK_CCODE_LITERAL @@ -73,28 +86,30 @@ char *errtxt; %type Statement %type Statements -%type IdlFile -%type Preamble -%type Prologue -%type Epilogue -%type HdrComment -%type Strings %type Binding %type BindingArgs %type BindingArg +%type Class +%type ClassArgs +%type ClassArg +%type ClassFlag +%type ClassFlags + +%type Method +%type MethodDeclarator +%type MethodType + +%type WebIDL +%type Preface +%type Prologue +%type Epilogue +%type Postface %type Private %type Internal -%type Interface -%type InterfaceArgs -%type InterfaceArg -%type InterfaceFlags %type Property -%type Operation -%type Api -%type Getter -%type Setter - +%type ParameterList +%type TypeIdent %% @@ -126,68 +141,77 @@ Statements Statement : - IdlFile - | - HdrComment - | - Preamble - | - Prologue - | - Epilogue - | Binding | - Operation - | - Api + Class | - Getter - | - Setter + Method ; - /* [3] load a web IDL file */ -IdlFile - : - TOK_IDLFILE TOK_STRING_LITERAL ';' +Binding + : + TOK_BINDING TOK_IDENTIFIER '{' BindingArgs '}' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_WEBIDLFILE, NULL, $2); + $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING, + NULL, + genbind_new_node(GENBIND_NODE_TYPE_TYPE, $4, $2)); } ; -HdrComment - : - TOK_HDR_COMMENT Strings ';' +BindingArgs + : + BindingArg + | + BindingArgs BindingArg { - $$ = genbind_new_node(GENBIND_NODE_TYPE_HDRCOMMENT, NULL, $2); + $$ = genbind_node_link($2, $1); } ; -Strings +BindingArg : - TOK_STRING_LITERAL + WebIDL + | + Preface + | + Prologue + | + Epilogue + | + Postface + ; + + /* [3] a web IDL file specifier */ +WebIDL + : + TOK_WEBIDL TOK_STRING_LITERAL ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_STRING, NULL, $1); + $$ = genbind_new_node(GENBIND_NODE_TYPE_WEBIDL, NULL, $2); } - | - Strings TOK_STRING_LITERAL + ; + + + /* type and identifier of a variable */ +TypeIdent + : + TOK_STRING_LITERAL TOK_IDENTIFIER { - $$ = genbind_new_node(GENBIND_NODE_TYPE_STRING, $1, $2); + $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, + genbind_new_node(GENBIND_NODE_TYPE_TYPE, NULL, $1), $2); } ; -Preamble +Preface : - TOK_PREAMBLE CBlock + TOK_PREFACE CBlock ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_PREAMBLE, NULL, $2); + $$ = genbind_new_node(GENBIND_NODE_TYPE_PREFACE, NULL, $2); } ; Prologue : - TOK_PROLOGUE CBlock + TOK_PROLOGUE CBlock ';' { $$ = genbind_new_node(GENBIND_NODE_TYPE_PROLOGUE, NULL, $2); } @@ -195,173 +219,196 @@ Prologue Epilogue : - TOK_EPILOGUE CBlock + TOK_EPILOGUE CBlock ';' { $$ = genbind_new_node(GENBIND_NODE_TYPE_EPILOGUE, NULL, $2); } ; +Postface + : + TOK_POSTFACE CBlock ';' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_POSTFACE, NULL, $2); + } + ; + CBlock - : + : TOK_CCODE_LITERAL - | - CBlock TOK_CCODE_LITERAL + | + CBlock TOK_CCODE_LITERAL { $$ = genbind_strapp($1, $2); } ; -Operation +MethodType : - TOK_OPERATION TOK_IDENTIFIER CBlock + TOK_INIT { - $$ = genbind_new_node(GENBIND_NODE_TYPE_OPERATION, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - genbind_new_node(GENBIND_NODE_TYPE_CBLOCK, - NULL, - $3), - $2)); + $$ = GENBIND_METHOD_TYPE_INIT; } + | + TOK_FINI + { + $$ = GENBIND_METHOD_TYPE_FINI; + } + | + TOK_METHOD + { + $$ = GENBIND_METHOD_TYPE_METHOD; + } + | + TOK_GETTER + { + $$ = GENBIND_METHOD_TYPE_GETTER; + } + | + TOK_SETTER + { + $$ = GENBIND_METHOD_TYPE_SETTER; + } + ; -Api +ParameterList : - TOK_API TOK_IDENTIFIER CBlock + TypeIdent + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_PARAMETER, NULL, $1); + } + | + ParameterList ',' TypeIdent { - $$ = genbind_new_node(GENBIND_NODE_TYPE_API, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - genbind_new_node(GENBIND_NODE_TYPE_CBLOCK, - NULL, - $3), - $2)); + $$ = genbind_node_link($3, $1); } + ; -Getter +MethodDeclarator : - TOK_GETTER TOK_IDENTIFIER CBlock + TOK_IDENTIFIER TOK_DBLCOLON TOK_IDENTIFIER '(' ParameterList ')' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_GETTER, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - genbind_new_node(GENBIND_NODE_TYPE_CBLOCK, - NULL, - $3), - $2)); + $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + $5, + $3), + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + NULL, + $1)); } + | + TOK_IDENTIFIER TOK_DBLCOLON TOK_IDENTIFIER '(' ')' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + NULL, + $3), + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + NULL, + $1)); + } + | + TOK_IDENTIFIER '(' ParameterList ')' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, + $3, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + NULL, + $1)); + } + | + TOK_IDENTIFIER '(' ')' + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + NULL, + $1)); + } + ; -Setter +Method : - TOK_SETTER TOK_IDENTIFIER CBlock + MethodType MethodDeclarator CBlock { - $$ = genbind_new_node(GENBIND_NODE_TYPE_SETTER, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - genbind_new_node(GENBIND_NODE_TYPE_CBLOCK, - NULL, - $3), - $2)); + $$ = genbind_new_node(GENBIND_NODE_TYPE_METHOD, NULL, + genbind_new_node(GENBIND_NODE_TYPE_METHOD_TYPE, + genbind_new_node(GENBIND_NODE_TYPE_CDATA, + $2, $3), + (void *)$1)); } -Binding + +Class : - TOK_BINDING TOK_IDENTIFIER '{' BindingArgs '}' + TOK_CLASS TOK_IDENTIFIER '{' ClassArgs '}' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_TYPE, $4, $2)); + $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, $4, $2)); } ; -BindingArgs +ClassArgs : - BindingArg + ClassArg | - BindingArgs BindingArg + ClassArgs ClassArg { - $$ = genbind_node_link($2, $1); + $$ = genbind_node_link($2, $1); } ; -BindingArg - : +ClassArg + : Private | Internal | - Interface - | Property + | + ClassFlag + | + Preface + | + Prologue + | + Epilogue + | + Postface ; + Private : - TOK_PRIVATE TOK_STRING_LITERAL TOK_IDENTIFIER ';' + TOK_PRIVATE TypeIdent ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_PRIVATE, NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - genbind_new_node(GENBIND_NODE_TYPE_STRING, NULL, $2), $3)); + $$ = genbind_new_node(GENBIND_NODE_TYPE_PRIVATE, NULL, $2); } ; Internal : - TOK_INTERNAL TOK_STRING_LITERAL TOK_IDENTIFIER ';' + TOK_INTERNAL TypeIdent ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERNAL, NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - genbind_new_node(GENBIND_NODE_TYPE_STRING, NULL, $2), $3)); + $$ = genbind_new_node(GENBIND_NODE_TYPE_INTERNAL, NULL, $2); } ; -Interface - : - TOK_INTERFACE TOK_IDENTIFIER ';' - { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $2)); - } - | - TOK_INTERFACE TOK_IDENTIFIER '{' '}' - { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $2)); - } - | - TOK_INTERFACE TOK_IDENTIFIER '{' InterfaceArgs '}' - { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, $4, $2)); - } - ; - -InterfaceArgs +ClassFlag : - InterfaceArg - | - InterfaceArgs InterfaceArg - { - $$ = genbind_node_link($2, $1); - } - ; - -InterfaceArg - : - TOK_FLAGS InterfaceFlags ';' + TOK_FLAGS ClassFlags ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS, NULL, $2); + $$ = genbind_new_node(GENBIND_NODE_TYPE_FLAGS, NULL, $2); } ; -InterfaceFlags +ClassFlags : TOK_IDENTIFIER { $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, NULL, $1); } | - InterfaceFlags ',' TOK_IDENTIFIER + ClassFlags ',' TOK_IDENTIFIER { $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, $1, $3); } @@ -371,13 +418,12 @@ Property : TOK_PROPERTY Modifiers TOK_IDENTIFIER ';' { - $$ = genbind_new_node(GENBIND_NODE_TYPE_BINDING_PROPERTY, - NULL, - genbind_new_node(GENBIND_NODE_TYPE_MODIFIER, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - NULL, - $3), - (void *)$2)); + $$ = genbind_new_node(GENBIND_NODE_TYPE_PROPERTY, NULL, + genbind_new_node(GENBIND_NODE_TYPE_MODIFIER, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + NULL, + $3), + (void *)$2)); } ; diff --git a/src/nsgenbind.c b/src/nsgenbind.c index d81f30f..3174fa0 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -22,201 +22,173 @@ struct options *options; static struct options* process_cmdline(int argc, char **argv) { - int opt; + int opt; - options = calloc(1,sizeof(struct options)); - if (options == NULL) { - fprintf(stderr, "Allocation error\n"); - return NULL; - } + options = calloc(1,sizeof(struct options)); + if (options == NULL) { + fprintf(stderr, "Allocation error\n"); + return NULL; + } - while ((opt = getopt(argc, argv, "vgDW::d:I:o:h:")) != -1) { - switch (opt) { - case 'I': - options->idlpath = strdup(optarg); - break; + while ((opt = getopt(argc, argv, "vgDW::I:")) != -1) { + switch (opt) { + case 'I': + options->idlpath = strdup(optarg); + break; - case 'o': - options->outfilename = strdup(optarg); - break; + case 'v': + options->verbose = true; + break; - case 'h': - options->hdrfilename = strdup(optarg); - break; + case 'D': + options->debug = true; + break; - case 'd': - options->depfilename = strdup(optarg); - break; + case 'g': + options->dbglog = true; + break; - case 'v': - options->verbose = true; - break; + case 'W': + options->warnings = 1; /* warning flags */ + break; - case 'D': - options->debug = true; - break; + default: /* '?' */ + fprintf(stderr, + "Usage: %s [-v] [-g] [-D] [-W] [-I idlpath] inputfile outputdir\n", + argv[0]); + free(options); + return NULL; - case 'g': - options->dbglog = true; - break; + } + } - case 'W': - options->warnings = 1; /* warning flags */ - break; + if (optind > (argc - 2)) { + fprintf(stderr, + "Error: expected input filename and output directory\n"); + free(options); + return NULL; + } - default: /* '?' */ - fprintf(stderr, - "Usage: %s [-v] [-g] [-D] [-W] [-d depfilename] [-I idlpath] [-o filename] [-h headerfile] inputfile\n", - argv[0]); - free(options); - return NULL; + options->infilename = strdup(argv[optind]); - } - } + options->outdirname = strdup(argv[optind + 1]); - if (optind >= argc) { - fprintf(stderr, "Error: expected input filename\n"); - free(options); - return NULL; - } - - options->infilename = strdup(argv[optind]); - - return options; + return options; } static int generate_binding(struct genbind_node *binding_node, void *ctx) { - struct genbind_node *genbind_root = ctx; - char *type; - int res = 10; - - type = genbind_node_gettext( - genbind_node_find_type( - genbind_node_getnode(binding_node), - NULL, - GENBIND_NODE_TYPE_TYPE)); - - if (strcmp(type, "jsapi_libdom") == 0) { - res = jsapi_libdom_output(options, genbind_root, binding_node); - } else { - fprintf(stderr, "Error: unsupported binding type \"%s\"\n", type); - } - - return res; + struct genbind_node *genbind_root = ctx; + char *type; + int res = 10; + + type = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode(binding_node), + NULL, + GENBIND_NODE_TYPE_TYPE)); + + if (strcmp(type, "jsapi_libdom") == 0) { + res = jsapi_libdom_output(options, genbind_root, binding_node); + } else { + fprintf(stderr, "Error: unsupported binding type \"%s\"\n", type); + } + + return res; +} + +enum bindingtype_e { + BINDINGTYPE_UNKNOWN, + BINDINGTYPE_JSAPI_LIBDOM, + BINDINGTYPE_DUK_LIBDOM, +}; + +/** + * get the type of binding + */ +static enum bindingtype_e genbind_get_type(struct genbind_node *node) +{ + struct genbind_node *binding_node; + const char *binding_type; + + binding_node = genbind_node_find_type(node, + NULL, + GENBIND_NODE_TYPE_BINDING); + if (binding_node == NULL) { + /* binding entry is missing which is invalid */ + return BINDINGTYPE_UNKNOWN; + } + + binding_type = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode(binding_node), + NULL, + GENBIND_NODE_TYPE_TYPE)); + if (binding_type == NULL) { + fprintf(stderr, "Error: missing binding type\n"); + return BINDINGTYPE_UNKNOWN; + } + + if (strcmp(binding_type, "jsapi_libdom") == 0) { + return BINDINGTYPE_JSAPI_LIBDOM; + } + + if (strcmp(binding_type, "duk_libdom") == 0) { + return BINDINGTYPE_DUK_LIBDOM; + } + + fprintf(stderr, "Error: unsupported binding type \"%s\"\n", binding_type); + + return BINDINGTYPE_UNKNOWN; } int main(int argc, char **argv) { - int res; - struct genbind_node *genbind_root; - - options = process_cmdline(argc, argv); - if (options == NULL) { - return 1; /* bad commandline */ - } - - if (options->verbose && - (options->outfilename == NULL)) { - fprintf(stderr, - "Error: output to stdout with verbose logging would fail\n"); - return 2; - } - - if (options->depfilename != NULL && - options->outfilename == NULL) { - fprintf(stderr, - "Error: output to stdout with dep generation would fail\n"); - return 3; - } - - if (options->depfilename != NULL && - options->infilename == NULL) { - fprintf(stderr, - "Error: input from stdin with dep generation would fail\n"); - return 3; - } - - /* open dependancy file */ - if (options->depfilename != NULL) { - options->depfilehandle = fopen(options->depfilename, "w"); - if (options->depfilehandle == NULL) { - fprintf(stderr, - "Error: unable to open dep file\n"); - return 4; - } - fprintf(options->depfilehandle, - "%s %s :", options->depfilename, - options->outfilename); - } - - /* parse input and generate dependancy */ - res = genbind_parsefile(options->infilename, &genbind_root); - if (res != 0) { - fprintf(stderr, "Error: parse failed with code %d\n", res); - return res; - } - - /* dependancy generation complete */ - if (options->depfilehandle != NULL) { - fputc('\n', options->depfilehandle); - fclose(options->depfilehandle); - } - - - /* open output file */ - if (options->outfilename == NULL) { - options->outfilehandle = stdout; - } else { - options->outfilehandle = fopen(options->outfilename, "w"); - } - if (options->outfilehandle == NULL) { - fprintf(stderr, "Error opening source output %s: %s\n", - options->outfilename, - strerror(errno)); - return 5; - } - - /* open output header file if required */ - if (options->hdrfilename != NULL) { - options->hdrfilehandle = fopen(options->hdrfilename, "w"); - if (options->hdrfilehandle == NULL) { - fprintf(stderr, "Error opening header output %s: %s\n", - options->hdrfilename, - strerror(errno)); - /* close and unlink output file */ - fclose(options->outfilehandle); - if (options->outfilename != NULL) { - unlink(options->outfilename); - } - return 6; - } - } else { - options->hdrfilehandle = NULL; - } - - /* dump the AST */ - if (options->verbose) { - genbind_ast_dump(genbind_root, 0); - } - - /* generate output for each binding */ - res = genbind_node_foreach_type(genbind_root, - GENBIND_NODE_TYPE_BINDING, - generate_binding, - genbind_root); - if (res != 0) { - fprintf(stderr, "Error: output failed with code %d\n", res); - if (options->outfilename != NULL) { - unlink(options->outfilename); - } - if (options->hdrfilename != NULL) { - unlink(options->hdrfilename); - } - return res; - } - - - return 0; + int res; + struct genbind_node *genbind_root; + enum bindingtype_e bindingtype; + + options = process_cmdline(argc, argv); + if (options == NULL) { + return 1; /* bad commandline */ + } + + /* parse input and generate dependancy */ + res = genbind_parsefile(options->infilename, &genbind_root); + if (res != 0) { + fprintf(stderr, "Error: parse failed with code %d\n", res); + return res; + } + + /* dump the AST */ + genbind_dump_ast(genbind_root); + + /* get bindingtype */ + bindingtype = genbind_get_type(genbind_root); + if (bindingtype == BINDINGTYPE_UNKNOWN) { + return 3; + } + +#if 0 + genbind_load_idl(genbind_root); + + /* generate output for each binding */ + res = genbind_node_foreach_type(genbind_root, + GENBIND_NODE_TYPE_BINDING, + generate_binding, + genbind_root); + if (res != 0) { + fprintf(stderr, "Error: output failed with code %d\n", res); + if (options->outfilename != NULL) { + unlink(options->outfilename); + } + if (options->hdrfilename != NULL) { + unlink(options->hdrfilename); + } + return res; + } + +#endif + return 0; } diff --git a/src/options.h b/src/options.h index cbac9a3..68a4bc1 100644 --- a/src/options.h +++ b/src/options.h @@ -12,16 +12,11 @@ /** global options */ struct options { char *infilename; /**< binding source */ - - char *outfilename; /**< output source file */ - FILE *outfilehandle; /**< output file handle */ - - char *hdrfilename; /**< output header file */ - FILE *hdrfilehandle; /**< output file handle */ - - char *depfilename; /**< dependancy output*/ - FILE *depfilehandle; /**< dependancy file handle */ - + char *outdirname; /**< output directory */ +FILE *hdrfilehandle; +char *hdrfilename; +char *outfilename; +FILE *outfilehandle; char *idlpath; /**< path to IDL files */ bool verbose; /**< verbose processing */ diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..7bab058 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#include "options.h" +#include "utils.h" + +FILE *genb_fopen(const char *fname, const char *mode) +{ + char *fpath; + int fpathl; + FILE *filef; + + fpathl = strlen(options->outdirname) + strlen(fname) + 2; + fpath = malloc(fpathl); + snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname); + + filef = fopen(fpath, mode); + if (filef == NULL) { + fprintf(stderr, "Error: unable to open file %s (%s)\n", + fpath, strerror(errno)); + free(fpath); + return NULL; + } + free(fpath); + + return filef; +} + +#ifdef NEED_STRNDUP + +char *strndup(const char *s, size_t n) +{ + size_t len; + char *s2; + + for (len = 0; len != n && s[len]; len++) + continue; + + s2 = malloc(len + 1); + if (!s2) + return 0; + + memcpy(s2, s, len); + s2[len] = 0; + return s2; +} + +#endif + diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..98a4c6b --- /dev/null +++ b/src/utils.h @@ -0,0 +1,21 @@ +/* utility helpers + * + * This file is part of nsnsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2015 Vincent Sanders + */ + +#ifndef nsgenbind_utils_h +#define nsgenbind_utils_h + +FILE *genb_fopen(const char *fname, const char *mode); + +#ifdef _WIN32 +#define NEED_STRNDUP 1 +char *strndup(const char *s, size_t n); +#endif + +#define SLEN(x) (sizeof((x)) - 1) + +#endif diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd new file mode 100644 index 0000000..c32f6a3 --- /dev/null +++ b/test/data/bindings/browser-duk.bnd @@ -0,0 +1,66 @@ +/* Binding for browser using ductape and libdom + * + * Copyright 2015 Vincent Sanders + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * Released under the terms of the MIT License, + * http://www.opensource.org/licenses/mit-license + */ + +binding duk_libdom { + webidl "dom.idl"; + webidl "html.idl"; + webidl "console.idl"; + + preface %{ + %}; + + prologue %{ + %}; + + epilogue %{ + %}; + + postface %{ + %}; +} + +class Node { + private "dom_node *" node; + + preface %{ + %}; + + prologue %{ + %}; + + epilogue %{ + %}; + + postface %{ + %}; +} + +init Node("dom_node *" node) +%{ + private->node = node; + dom_node_ref(node); +%} + +fini Node() +%{ + dom_node_unref(private->node); +%} + +method Node::AppendChild() +%{ +%} + +getter Node::aprop() +%{ +%} + +setter Node::aprop() +%{ +%} diff --git a/test/data/idl/console.idl b/test/data/idl/console.idl new file mode 100644 index 0000000..5a3d9eb --- /dev/null +++ b/test/data/idl/console.idl @@ -0,0 +1,24 @@ +// de facto set of features for console object +// https://developer.mozilla.org/en-US/docs/DOM/console +// http://msdn.microsoft.com/en-us/library/dd565625%28v=vs.85%29.aspx#consolelogging +// 31st October +// Yay for non-standard standards + +interface Console { + void debug(DOMString msg, Substitition... subst); + void dir(JSObject object); + void error(DOMString msg, Substitition... subst); + void group(); + void groupCollapsed(); + void groupEnd(); + void info(DOMString msg, Substitition... subst); + void log(DOMString msg, Substitition... subst); + void time(DOMString timerName); + void timeEnd(DOMString timerName); + void trace(); + void warn(DOMString msg, Substitition... subst); +}; + +partial interface Window { + readonly attribute Console console; +}; \ No newline at end of file diff --git a/test/data/idl/dom.idl b/test/data/idl/dom.idl index 6ba870c..6a4a95e 100644 --- a/test/data/idl/dom.idl +++ b/test/data/idl/dom.idl @@ -1,43 +1,10 @@ -// DOM core WebIDL -// retrived from http://dom.spec.whatwg.org/ -// 23rd October 2012 - - - -exception DOMException { - const unsigned short INDEX_SIZE_ERR = 1; - const unsigned short DOMSTRING_SIZE_ERR = 2; // historical - const unsigned short HIERARCHY_REQUEST_ERR = 3; - const unsigned short WRONG_DOCUMENT_ERR = 4; - const unsigned short INVALID_CHARACTER_ERR = 5; - const unsigned short NO_DATA_ALLOWED_ERR = 6; // historical - const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7; - const unsigned short NOT_FOUND_ERR = 8; - const unsigned short NOT_SUPPORTED_ERR = 9; - const unsigned short INUSE_ATTRIBUTE_ERR = 10; // historical - const unsigned short INVALID_STATE_ERR = 11; - const unsigned short SYNTAX_ERR = 12; - const unsigned short INVALID_MODIFICATION_ERR = 13; - const unsigned short NAMESPACE_ERR = 14; - const unsigned short INVALID_ACCESS_ERR = 15; - const unsigned short VALIDATION_ERR = 16; // historical - const unsigned short TYPE_MISMATCH_ERR = 17; - const unsigned short SECURITY_ERR = 18; - const unsigned short NETWORK_ERR = 19; - const unsigned short ABORT_ERR = 20; - const unsigned short URL_MISMATCH_ERR = 21; - const unsigned short QUOTA_EXCEEDED_ERR = 22; - const unsigned short TIMEOUT_ERR = 23; - const unsigned short INVALID_NODE_TYPE_ERR = 24; - const unsigned short DATA_CLONE_ERR = 25; - unsigned short code; -}; - -interface DOMError { - readonly attribute DOMString name; -}; +// DOM web IDL +// Retrived from https://dom.spec.whatwg.org/ +// Sat Jul 18 2015 + -[Constructor(DOMString type, optional EventInit eventInitDict)] +[Constructor(DOMString type, optional EventInit eventInitDict), + Exposed=(Window,Worker)] interface Event { readonly attribute DOMString type; readonly attribute EventTarget? target; @@ -57,26 +24,30 @@ interface Event { void preventDefault(); readonly attribute boolean defaultPrevented; - readonly attribute boolean isTrusted; + [Unforgeable] readonly attribute boolean isTrusted; readonly attribute DOMTimeStamp timeStamp; void initEvent(DOMString type, boolean bubbles, boolean cancelable); }; dictionary EventInit { - boolean bubbles; - boolean cancelable; + boolean bubbles = false; + boolean cancelable = false; }; -[Constructor(DOMString type, optional CustomEventInit eventInitDict)] +[Constructor(DOMString type, optional CustomEventInit eventInitDict), + Exposed=(Window,Worker)] interface CustomEvent : Event { readonly attribute any detail; + + void initCustomEvent(DOMString type, boolean bubbles, boolean cancelable, any detail); }; dictionary CustomEventInit : EventInit { - any detail; + any detail = null; }; +[Exposed=(Window,Worker)] interface EventTarget { void addEventListener(DOMString type, EventListener? callback, optional boolean capture = false); void removeEventListener(DOMString type, EventListener? callback, optional boolean capture = false); @@ -87,6 +58,74 @@ callback interface EventListener { void handleEvent(Event event); }; +[NoInterfaceObject, + Exposed=Window] +interface NonElementParentNode { + Element? getElementById(DOMString elementId); +}; +Document implements NonElementParentNode; +DocumentFragment implements NonElementParentNode; + +[NoInterfaceObject, + Exposed=Window] +interface ParentNode { + [SameObject] readonly attribute HTMLCollection children; + readonly attribute Element? firstElementChild; + readonly attribute Element? lastElementChild; + readonly attribute unsigned long childElementCount; + + [Unscopeable] void prepend((Node or DOMString)... nodes); + [Unscopeable] void append((Node or DOMString)... nodes); + + [Unscopeable] Element? query(DOMString relativeSelectors); + [NewObject, Unscopeable] Elements queryAll(DOMString relativeSelectors); + Element? querySelector(DOMString selectors); + [NewObject] NodeList querySelectorAll(DOMString selectors); +}; +Document implements ParentNode; +DocumentFragment implements ParentNode; +Element implements ParentNode; + +[NoInterfaceObject, + Exposed=Window] +interface NonDocumentTypeChildNode { + readonly attribute Element? previousElementSibling; + readonly attribute Element? nextElementSibling; +}; +Element implements NonDocumentTypeChildNode; +CharacterData implements NonDocumentTypeChildNode; + +[NoInterfaceObject, + Exposed=Window] +interface ChildNode { + [Unscopeable] void before((Node or DOMString)... nodes); + [Unscopeable] void after((Node or DOMString)... nodes); + [Unscopeable] void replaceWith((Node or DOMString)... nodes); + [Unscopeable] void remove(); +}; +DocumentType implements ChildNode; +Element implements ChildNode; +CharacterData implements ChildNode; + +class Elements extends Array { + Element? query(DOMString relativeSelectors); + Elements queryAll(DOMString relativeSelectors); +}; + +[Exposed=Window] +interface NodeList { + getter Node? item(unsigned long index); + readonly attribute unsigned long length; + iterable; +}; + +[Exposed=Window] +interface HTMLCollection { + readonly attribute unsigned long length; + getter Element? item(unsigned long index); + getter Element? namedItem(DOMString name); +}; + [Constructor(MutationCallback callback)] interface MutationObserver { void observe(Node target, MutationObserverInit options); @@ -97,20 +136,21 @@ interface MutationObserver { callback MutationCallback = void (sequence mutations, MutationObserver observer); dictionary MutationObserverInit { - boolean childList; + boolean childList = false; boolean attributes; boolean characterData; - boolean subtree; + boolean subtree = false; boolean attributeOldValue; boolean characterDataOldValue; sequence attributeFilter; }; +[Exposed=Window] interface MutationRecord { readonly attribute DOMString type; readonly attribute Node target; - readonly attribute NodeList addedNodes; - readonly attribute NodeList removedNodes; + [SameObject] readonly attribute NodeList addedNodes; + [SameObject] readonly attribute NodeList removedNodes; readonly attribute Node? previousSibling; readonly attribute Node? nextSibling; readonly attribute DOMString? attributeName; @@ -118,6 +158,7 @@ interface MutationRecord { readonly attribute DOMString? oldValue; }; +[Exposed=Window] interface Node : EventTarget { const unsigned short ELEMENT_NODE = 1; const unsigned short ATTRIBUTE_NODE = 2; // historical @@ -140,7 +181,7 @@ interface Node : EventTarget { readonly attribute Node? parentNode; readonly attribute Element? parentElement; boolean hasChildNodes(); - readonly attribute NodeList childNodes; + [SameObject] readonly attribute NodeList childNodes; readonly attribute Node? firstChild; readonly attribute Node? lastChild; readonly attribute Node? previousSibling; @@ -148,37 +189,40 @@ interface Node : EventTarget { attribute DOMString? nodeValue; attribute DOMString? textContent; - Node insertBefore(Node node, Node? child); - Node appendChild(Node node); - Node replaceChild(Node node, Node child); - Node removeChild(Node child); void normalize(); - -Node cloneNode(optional boolean deep = true); - boolean isEqualNode(Node? node); + [NewObject] Node cloneNode(optional boolean deep = false); + boolean isEqualNode(Node? otherNode); const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01; const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02; const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04; const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08; const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10; - const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; // historical + const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; unsigned short compareDocumentPosition(Node other); boolean contains(Node? other); DOMString? lookupPrefix(DOMString? namespace); DOMString? lookupNamespaceURI(DOMString? prefix); boolean isDefaultNamespace(DOMString? namespace); + + Node insertBefore(Node node, Node? child); + Node appendChild(Node node); + Node replaceChild(Node node, Node child); + Node removeChild(Node child); }; -[Constructor] +[Constructor, + Exposed=Window] interface Document : Node { - readonly attribute DOMImplementation implementation; + [SameObject] readonly attribute DOMImplementation implementation; readonly attribute DOMString URL; readonly attribute DOMString documentURI; + readonly attribute DOMString origin; readonly attribute DOMString compatMode; readonly attribute DOMString characterSet; + readonly attribute DOMString inputEncoding; // legacy alias of .characterSet readonly attribute DOMString contentType; readonly attribute DocumentType? doctype; @@ -186,59 +230,54 @@ interface Document : Node { HTMLCollection getElementsByTagName(DOMString localName); HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); HTMLCollection getElementsByClassName(DOMString classNames); - Element? getElementById(DOMString elementId); - Element createElement(DOMString localName); - Element createElementNS(DOMString? namespace, DOMString qualifiedName); - DocumentFragment createDocumentFragment(); - Text createTextNode(DOMString data); - Comment createComment(DOMString data); - ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); + [NewObject] Element createElement(DOMString localName); + [NewObject] Element createElementNS(DOMString? namespace, DOMString qualifiedName); + [NewObject] DocumentFragment createDocumentFragment(); + [NewObject] Text createTextNode(DOMString data); + [NewObject] Comment createComment(DOMString data); + [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - Node importNode(Node node, optional boolean deep = true); + [NewObject] Node importNode(Node node, optional boolean deep = false); Node adoptNode(Node node); - Event createEvent(DOMString interface); + [NewObject] Attr createAttribute(DOMString localName); + [NewObject] Attr createAttributeNS(DOMString? namespace, DOMString name); - Range createRange(); + [NewObject] Event createEvent(DOMString interface); - // NodeFilter.SHOW_ALL = 0xFFFFFFFF - NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); - TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); + [NewObject] Range createRange(); - // NEW - void prepend((Node or DOMString)... nodes); - void append((Node or DOMString)... nodes); + // NodeFilter.SHOW_ALL = 0xFFFFFFFF + [NewObject] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); + [NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); }; +[Exposed=Window] interface XMLDocument : Document {}; +[Exposed=Window] interface DOMImplementation { - DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); - XMLDocument createDocument(DOMString? namespace, [TreatNullAs=EmptyString] DOMString qualifiedName, DocumentType? doctype); - Document createHTMLDocument(optional DOMString title); + [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); + [NewObject] XMLDocument createDocument(DOMString? namespace, [TreatNullAs=EmptyString] DOMString qualifiedName, optional DocumentType? doctype = null); + [NewObject] Document createHTMLDocument(optional DOMString title); - boolean hasFeature(DOMString feature, [TreatNullAs=EmptyString] DOMString version); + boolean hasFeature(); // useless; always returns true }; +[Constructor, + Exposed=Window] interface DocumentFragment : Node { - // NEW - void prepend((Node or DOMString)... nodes); - void append((Node or DOMString)... nodes); }; +[Exposed=Window] interface DocumentType : Node { readonly attribute DOMString name; readonly attribute DOMString publicId; readonly attribute DOMString systemId; - - // NEW - void before((Node or DOMString)... nodes); - void after((Node or DOMString)... nodes); - void replace((Node or DOMString)... nodes); - void remove(); }; +[Exposed=Window] interface Element : Node { readonly attribute DOMString? namespaceURI; readonly attribute DOMString? prefix; @@ -247,9 +286,10 @@ interface Element : Node { attribute DOMString id; attribute DOMString className; - readonly attribute DOMTokenList classList; + [SameObject] readonly attribute DOMTokenList classList; - readonly attribute Attr[] attributes; + boolean hasAttributes(); + [SameObject] readonly attribute NamedNodeMap attributes; DOMString? getAttribute(DOMString name); DOMString? getAttributeNS(DOMString? namespace, DOMString localName); void setAttribute(DOMString name, DOMString value); @@ -259,36 +299,46 @@ interface Element : Node { boolean hasAttribute(DOMString name); boolean hasAttributeNS(DOMString? namespace, DOMString localName); + Attr? getAttributeNode(DOMString name); + Attr? getAttributeNodeNS(DOMString? namespace, DOMString localName); + Attr? setAttributeNode(Attr attr); + Attr? setAttributeNodeNS(Attr attr); + Attr removeAttributeNode(Attr attr); + + Element? closest(DOMString selectors); + boolean matches(DOMString selectors); + HTMLCollection getElementsByTagName(DOMString localName); HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); HTMLCollection getElementsByClassName(DOMString classNames); - - readonly attribute HTMLCollection children; - readonly attribute Element? firstElementChild; - readonly attribute Element? lastElementChild; - readonly attribute Element? previousElementSibling; - readonly attribute Element? nextElementSibling; - readonly attribute unsigned long childElementCount; - - - // NEW - void prepend((Node or DOMString)... nodes); - void append((Node or DOMString)... nodes); - void before((Node or DOMString)... nodes); - void after((Node or DOMString)... nodes); - void replace((Node or DOMString)... nodes); - void remove(); +}; +[Exposed=Window] +interface NamedNodeMap { + readonly attribute unsigned long length; + getter Attr? item(unsigned long index); + getter Attr? getNamedItem(DOMString name); + Attr? getNamedItemNS(DOMString? namespace, DOMString localName); + Attr? setNamedItem(Attr attr); + Attr? setNamedItemNS(Attr attr); + Attr removeNamedItem(DOMString name); + Attr removeNamedItemNS(DOMString? namespace, DOMString localName); }; +[Exposed=Window] interface Attr { - readonly attribute DOMString name; - attribute DOMString value; - readonly attribute DOMString? namespaceURI; readonly attribute DOMString? prefix; readonly attribute DOMString localName; -}; + readonly attribute DOMString name; + attribute DOMString value; + [TreatNullAs=EmptyString] attribute DOMString nodeValue; // legacy alias of .value + [TreatNullAs=EmptyString] attribute DOMString textContent; // legacy alias of .value + + readonly attribute Element? ownerElement; + readonly attribute boolean specified; // useless; always returns true +}; +[Exposed=Window] interface CharacterData : Node { [TreatNullAs=EmptyString] attribute DOMString data; readonly attribute unsigned long length; @@ -297,26 +347,25 @@ interface CharacterData : Node { void insertData(unsigned long offset, DOMString data); void deleteData(unsigned long offset, unsigned long count); void replaceData(unsigned long offset, unsigned long count, DOMString data); - - // NEW - void before((Node or DOMString)... nodes); - void after((Node or DOMString)... nodes); - void replace((Node or DOMString)... nodes); - void remove(); }; +[Constructor(optional DOMString data = ""), + Exposed=Window] interface Text : CharacterData { - Text splitText(unsigned long offset); + [NewObject] Text splitText(unsigned long offset); readonly attribute DOMString wholeText; }; - +[Exposed=Window] interface ProcessingInstruction : CharacterData { readonly attribute DOMString target; }; - +[Constructor(optional DOMString data = ""), + Exposed=Window] interface Comment : CharacterData { }; +[Constructor, + Exposed=Window] interface Range { readonly attribute Node startContainer; readonly attribute unsigned long startOffset; @@ -325,15 +374,15 @@ interface Range { readonly attribute boolean collapsed; readonly attribute Node commonAncestorContainer; - void setStart(Node refNode, unsigned long offset); - void setEnd(Node refNode, unsigned long offset); - void setStartBefore(Node refNode); - void setStartAfter(Node refNode); - void setEndBefore(Node refNode); - void setEndAfter(Node refNode); - void collapse(boolean toStart); - void selectNode(Node refNode); - void selectNodeContents(Node refNode); + void setStart(Node node, unsigned long offset); + void setEnd(Node node, unsigned long offset); + void setStartBefore(Node node); + void setStartAfter(Node node); + void setEndBefore(Node node); + void setEndAfter(Node node); + void collapse(optional boolean toStart = false); + void selectNode(Node node); + void selectNodeContents(Node node); const unsigned short START_TO_START = 0; const unsigned short START_TO_END = 1; @@ -342,12 +391,12 @@ interface Range { short compareBoundaryPoints(unsigned short how, Range sourceRange); void deleteContents(); - DocumentFragment extractContents(); - DocumentFragment cloneContents(); + [NewObject] DocumentFragment extractContents(); + [NewObject] DocumentFragment cloneContents(); void insertNode(Node node); void surroundContents(Node newParent); - Range cloneRange(); + [NewObject] Range cloneRange(); void detach(); boolean isPointInRange(Node node, unsigned long offset); @@ -358,9 +407,10 @@ interface Range { stringifier; }; +[Exposed=Window] interface NodeIterator { - readonly attribute Node root; - readonly attribute Node? referenceNode; + [SameObject] readonly attribute Node root; + readonly attribute Node referenceNode; readonly attribute boolean pointerBeforeReferenceNode; readonly attribute unsigned long whatToShow; readonly attribute NodeFilter? filter; @@ -371,11 +421,11 @@ interface NodeIterator { void detach(); }; +[Exposed=Window] interface TreeWalker { - readonly attribute Node root; + [SameObject] readonly attribute Node root; readonly attribute unsigned long whatToShow; readonly attribute NodeFilter? filter; - attribute Node currentNode; Node? parentNode(); @@ -386,7 +436,7 @@ interface TreeWalker { Node? previousNode(); Node? nextNode(); }; - +[Exposed=Window] callback interface NodeFilter { // Constants for acceptNode() const unsigned short FILTER_ACCEPT = 1; @@ -411,25 +461,6 @@ callback interface NodeFilter { unsigned short acceptNode(Node node); }; -[ArrayClass] -interface NodeList { - getter Node? item(unsigned long index); - readonly attribute unsigned long length; -}; - -interface HTMLCollection { - readonly attribute unsigned long length; - getter Element? item(unsigned long index); - getter object? namedItem(DOMString name); // only returns Element -}; - -[NoInterfaceObject] -interface DOMStringList { - readonly attribute unsigned long length; - getter DOMString? item(unsigned long index); - boolean contains(DOMString string); -}; - interface DOMTokenList { readonly attribute unsigned long length; getter DOMString? item(unsigned long index); @@ -438,9 +469,11 @@ interface DOMTokenList { void remove(DOMString... tokens); boolean toggle(DOMString token, optional boolean force); stringifier; + iterable; }; interface DOMSettableTokenList : DOMTokenList { attribute DOMString value; }; + diff --git a/test/data/idl/html.idl b/test/data/idl/html.idl index d4264c5..62d4967 100644 --- a/test/data/idl/html.idl +++ b/test/data/idl/html.idl @@ -1,37 +1,44 @@ -// HTML WebIDL -// retrived from http://www.whatwg.org/specs/web-apps/current-work/ -// 23rd October 2012 +// HTML web IDL +// Retrived from https://html.spec.whatwg.org/ +// Sat Jul 18 2015 +typedef (Int8Array or Uint8Array or Uint8ClampedArray or + Int16Array or Uint16Array or + Int32Array or Uint32Array or + Float32Array or Float64Array or + DataView) ArrayBufferView; + interface HTMLAllCollection : HTMLCollection { - // inherits length and item() - legacycaller getter object? namedItem(DOMString name); // overrides inherited namedItem() - HTMLAllCollection tags(DOMString tagName); + // inherits length and 'getter' + Element? item(unsigned long index); + (HTMLCollection or Element)? item(DOMString name); + legacycaller getter (HTMLCollection or Element)? namedItem(DOMString name); // shadows inherited namedItem() }; interface HTMLFormControlsCollection : HTMLCollection { // inherits length and item() - legacycaller getter object? namedItem(DOMString name); // overrides inherited namedItem() + legacycaller getter (RadioNodeList or Element)? namedItem(DOMString name); // shadows inherited namedItem() }; interface RadioNodeList : NodeList { - attribute DOMString value; + attribute DOMString value; }; interface HTMLOptionsCollection : HTMLCollection { // inherits item() - attribute unsigned long length; // overrides inherited length - legacycaller getter object? namedItem(DOMString name); // overrides inherited namedItem() + attribute unsigned long length; // shadows inherited length + legacycaller HTMLOptionElement? (DOMString name); setter creator void (unsigned long index, HTMLOptionElement? option); void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); void remove(long index); - attribute long selectedIndex; + attribute long selectedIndex; }; interface HTMLPropertiesCollection : HTMLCollection { // inherits length and item() - getter PropertyNodeList? namedItem(DOMString name); // overrides inherited namedItem() - readonly attribute DOMString[] names; + getter PropertyNodeList? namedItem(DOMString name); // shadows inherited namedItem() + [SameObject] readonly attribute DOMString[] names; }; typedef sequence PropertyValueArray; @@ -40,52 +47,55 @@ interface PropertyNodeList : NodeList { PropertyValueArray getValues(); }; +[OverrideBuiltins, Exposed=(Window,Worker)] interface DOMStringMap { getter DOMString (DOMString name); - setter void (DOMString name, DOMString value); - creator void (DOMString name, DOMString value); + setter creator void (DOMString name, DOMString value); deleter void (DOMString name); }; interface DOMElementMap { getter Element (DOMString name); - setter void (DOMString name, Element value); - creator void (DOMString name, Element value); + setter creator void (DOMString name, Element value); deleter void (DOMString name); }; -[NoInterfaceObject] -interface Transferable { }; +typedef (ArrayBuffer or CanvasProxy or MessagePort) Transferable; + +callback FileCallback = void (File file); + +enum DocumentReadyState { "loading", "interactive", "complete" }; [OverrideBuiltins] -partial interface Document { +partial /*sealed*/ interface Document { // resource metadata management - [PutForwards=href] readonly attribute Location? location; - attribute DOMString domain; + [PutForwards=href, Unforgeable] readonly attribute Location? location; + attribute DOMString domain; readonly attribute DOMString referrer; - attribute DOMString cookie; + attribute DOMString cookie; readonly attribute DOMString lastModified; - readonly attribute DOMString readyState; + readonly attribute DocumentReadyState readyState; // DOM tree accessors getter object (DOMString name); - attribute DOMString title; - attribute DOMString dir; - attribute HTMLElement? body; + attribute DOMString title; + attribute DOMString dir; + attribute HTMLElement? body; readonly attribute HTMLHeadElement? head; - readonly attribute HTMLCollection images; - readonly attribute HTMLCollection embeds; - readonly attribute HTMLCollection plugins; - readonly attribute HTMLCollection links; - readonly attribute HTMLCollection forms; - readonly attribute HTMLCollection scripts; + [SameObject] readonly attribute HTMLCollection images; + [SameObject] readonly attribute HTMLCollection embeds; + [SameObject] readonly attribute HTMLCollection plugins; + [SameObject] readonly attribute HTMLCollection links; + [SameObject] readonly attribute HTMLCollection forms; + [SameObject] readonly attribute HTMLCollection scripts; NodeList getElementsByName(DOMString elementName); - NodeList getItems(optional DOMString typeNames); // microdata - readonly attribute DOMElementMap cssElementMap; + NodeList getItems(optional DOMString typeNames = ""); // microdata + [SameObject] readonly attribute DOMElementMap cssElementMap; + readonly attribute HTMLScriptElement? currentScript; // dynamic markup insertion - Document open(optional DOMString type, optional DOMString replace); - WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace); + Document open(optional DOMString type = "text/html", optional DOMString replace = ""); + WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace = false); void close(); void write(DOMString... text); void writeln(DOMString... text); @@ -94,10 +104,8 @@ partial interface Document { readonly attribute WindowProxy? defaultView; readonly attribute Element? activeElement; boolean hasFocus(); - attribute DOMString designMode; - boolean execCommand(DOMString commandId); - boolean execCommand(DOMString commandId, boolean showUI); - boolean execCommand(DOMString commandId, boolean showUI, DOMString value); + attribute DOMString designMode; + boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = ""); boolean queryCommandEnabled(DOMString commandId); boolean queryCommandIndeterm(DOMString commandId); boolean queryCommandState(DOMString commandId); @@ -105,66 +113,12 @@ partial interface Document { DOMString queryCommandValue(DOMString commandId); readonly attribute HTMLCollection commands; - // event handler IDL attributes - attribute EventHandler onabort; - attribute EventHandler onblur; - attribute EventHandler oncancel; - attribute EventHandler oncanplay; - attribute EventHandler oncanplaythrough; - attribute EventHandler onchange; - attribute EventHandler onclick; - attribute EventHandler onclose; - attribute EventHandler oncontextmenu; - attribute EventHandler oncuechange; - attribute EventHandler ondblclick; - attribute EventHandler ondrag; - attribute EventHandler ondragend; - attribute EventHandler ondragenter; - attribute EventHandler ondragleave; - attribute EventHandler ondragover; - attribute EventHandler ondragstart; - attribute EventHandler ondrop; - attribute EventHandler ondurationchange; - attribute EventHandler onemptied; - attribute EventHandler onended; - attribute OnErrorEventHandler onerror; - attribute EventHandler onfocus; - attribute EventHandler oninput; - attribute EventHandler oninvalid; - attribute EventHandler onkeydown; - attribute EventHandler onkeypress; - attribute EventHandler onkeyup; - attribute EventHandler onload; - attribute EventHandler onloadeddata; - attribute EventHandler onloadedmetadata; - attribute EventHandler onloadstart; - attribute EventHandler onmousedown; - attribute EventHandler onmousemove; - attribute EventHandler onmouseout; - attribute EventHandler onmouseover; - attribute EventHandler onmouseup; - attribute EventHandler onmousewheel; - attribute EventHandler onpause; - attribute EventHandler onplay; - attribute EventHandler onplaying; - attribute EventHandler onprogress; - attribute EventHandler onratechange; - attribute EventHandler onreset; - attribute EventHandler onscroll; - attribute EventHandler onseeked; - attribute EventHandler onseeking; - attribute EventHandler onselect; - attribute EventHandler onshow; - attribute EventHandler onstalled; - attribute EventHandler onsubmit; - attribute EventHandler onsuspend; - attribute EventHandler ontimeupdate; - attribute EventHandler onvolumechange; - attribute EventHandler onwaiting; - // special event handler IDL attributes that only apply to Document objects [LenientThis] attribute EventHandler onreadystatechange; + + // also has obsolete members }; +Document implements GlobalEventHandlers; partial interface XMLDocument { boolean load(DOMString url); @@ -172,35 +126,33 @@ partial interface XMLDocument { interface HTMLElement : Element { // metadata attributes - attribute DOMString title; - attribute DOMString lang; - attribute boolean translate; - attribute DOMString dir; - readonly attribute DOMStringMap dataset; + attribute DOMString title; + attribute DOMString lang; + attribute boolean translate; + attribute DOMString dir; + [SameObject] readonly attribute DOMStringMap dataset; // microdata - attribute boolean itemScope; + attribute boolean itemScope; [PutForwards=value] readonly attribute DOMSettableTokenList itemType; - attribute DOMString itemId; + attribute DOMString itemId; [PutForwards=value] readonly attribute DOMSettableTokenList itemRef; [PutForwards=value] readonly attribute DOMSettableTokenList itemProp; readonly attribute HTMLPropertiesCollection properties; - attribute any itemValue; // acts as DOMString on setting + attribute any itemValue; // acts as DOMString on setting // user interaction - attribute boolean hidden; + attribute boolean hidden; void click(); - attribute long tabIndex; + attribute long tabIndex; void focus(); void blur(); - attribute DOMString accessKey; + attribute DOMString accessKey; readonly attribute DOMString accessKeyLabel; - attribute boolean draggable; + attribute boolean draggable; [PutForwards=value] readonly attribute DOMSettableTokenList dropzone; - attribute DOMString contentEditable; - readonly attribute boolean isContentEditable; - attribute HTMLMenuElement? contextMenu; - attribute boolean spellcheck; + attribute HTMLMenuElement? contextMenu; + attribute boolean spellcheck; void forceSpellCheck(); // command API @@ -210,217 +162,157 @@ interface HTMLElement : Element { readonly attribute boolean? commandHidden; readonly attribute boolean? commandDisabled; readonly attribute boolean? commandChecked; - - // styling - readonly attribute CSSStyleDeclaration style; - - // event handler IDL attributes - attribute EventHandler onabort; - attribute EventHandler onblur; - attribute EventHandler oncancel; - attribute EventHandler oncanplay; - attribute EventHandler oncanplaythrough; - attribute EventHandler onchange; - attribute EventHandler onclick; - attribute EventHandler onclose; - attribute EventHandler oncontextmenu; - attribute EventHandler oncuechange; - attribute EventHandler ondblclick; - attribute EventHandler ondrag; - attribute EventHandler ondragend; - attribute EventHandler ondragenter; - attribute EventHandler ondragleave; - attribute EventHandler ondragover; - attribute EventHandler ondragstart; - attribute EventHandler ondrop; - attribute EventHandler ondurationchange; - attribute EventHandler onemptied; - attribute EventHandler onended; - attribute OnErrorEventHandler onerror; - attribute EventHandler onfocus; - attribute EventHandler oninput; - attribute EventHandler oninvalid; - attribute EventHandler onkeydown; - attribute EventHandler onkeypress; - attribute EventHandler onkeyup; - attribute EventHandler onload; - attribute EventHandler onloadeddata; - attribute EventHandler onloadedmetadata; - attribute EventHandler onloadstart; - attribute EventHandler onmousedown; - attribute EventHandler onmousemove; - attribute EventHandler onmouseout; - attribute EventHandler onmouseover; - attribute EventHandler onmouseup; - attribute EventHandler onmousewheel; - attribute EventHandler onpause; - attribute EventHandler onplay; - attribute EventHandler onplaying; - attribute EventHandler onprogress; - attribute EventHandler onratechange; - attribute EventHandler onreset; - attribute EventHandler onscroll; - attribute EventHandler onseeked; - attribute EventHandler onseeking; - attribute EventHandler onselect; - attribute EventHandler onshow; - attribute EventHandler onstalled; - attribute EventHandler onsubmit; - attribute EventHandler onsuspend; - attribute EventHandler ontimeupdate; - attribute EventHandler onvolumechange; - attribute EventHandler onwaiting; }; +HTMLElement implements GlobalEventHandlers; +HTMLElement implements ElementContentEditable; interface HTMLUnknownElement : HTMLElement { }; -interface HTMLHtmlElement : HTMLElement {}; +interface HTMLHtmlElement : HTMLElement { + // also has obsolete members +}; interface HTMLHeadElement : HTMLElement {}; interface HTMLTitleElement : HTMLElement { - attribute DOMString text; + attribute DOMString text; }; interface HTMLBaseElement : HTMLElement { - attribute DOMString href; - attribute DOMString target; + attribute DOMString href; + attribute DOMString target; }; interface HTMLLinkElement : HTMLElement { - attribute boolean disabled; - attribute DOMString href; - attribute DOMString rel; + attribute DOMString href; + attribute DOMString? crossOrigin; + attribute DOMString rel; readonly attribute DOMTokenList relList; - attribute DOMString media; - attribute DOMString hreflang; - attribute DOMString type; + attribute DOMString media; + attribute DOMString hreflang; + attribute DOMString type; [PutForwards=value] readonly attribute DOMSettableTokenList sizes; + + // also has obsolete members }; HTMLLinkElement implements LinkStyle; interface HTMLMetaElement : HTMLElement { - attribute DOMString name; - attribute DOMString httpEquiv; - attribute DOMString content; + attribute DOMString name; + attribute DOMString httpEquiv; + attribute DOMString content; + + // also has obsolete members }; interface HTMLStyleElement : HTMLElement { - attribute boolean disabled; - attribute DOMString media; - attribute DOMString type; - attribute boolean scoped; + attribute DOMString media; + attribute DOMString type; + attribute boolean scoped; }; HTMLStyleElement implements LinkStyle; -interface HTMLScriptElement : HTMLElement { - attribute DOMString src; - attribute boolean async; - attribute boolean defer; - attribute DOMString type; - attribute DOMString charset; - attribute DOMString text; +interface HTMLBodyElement : HTMLElement { + + // also has obsolete members }; +HTMLBodyElement implements WindowEventHandlers; -interface HTMLBodyElement : HTMLElement { - attribute EventHandler onafterprint; - attribute EventHandler onbeforeprint; - attribute EventHandler onbeforeunload; - attribute EventHandler onblur; - attribute OnErrorEventHandler onerror; - attribute EventHandler onfocus; - attribute EventHandler onhashchange; - attribute EventHandler onload; - attribute EventHandler onmessage; - attribute EventHandler onoffline; - attribute EventHandler ononline; - attribute EventHandler onpopstate; - attribute EventHandler onpagehide; - attribute EventHandler onpageshow; - attribute EventHandler onresize; - attribute EventHandler onscroll; - attribute EventHandler onstorage; - attribute EventHandler onunload; -}; - -interface HTMLHeadingElement : HTMLElement {}; - -interface HTMLParagraphElement : HTMLElement {}; - -interface HTMLHRElement : HTMLElement {}; - -interface HTMLPreElement : HTMLElement {}; +interface HTMLHeadingElement : HTMLElement { + // also has obsolete members +}; + +interface HTMLParagraphElement : HTMLElement { + // also has obsolete members +}; + +interface HTMLHRElement : HTMLElement { + // also has obsolete members +}; + +interface HTMLPreElement : HTMLElement { + // also has obsolete members +}; interface HTMLQuoteElement : HTMLElement { - attribute DOMString cite; + attribute DOMString cite; }; interface HTMLOListElement : HTMLElement { - attribute boolean reversed; - attribute long start; - attribute DOMString type; + attribute boolean reversed; + attribute long start; + attribute DOMString type; + + // also has obsolete members }; -interface HTMLUListElement : HTMLElement {}; +interface HTMLUListElement : HTMLElement { + // also has obsolete members +}; interface HTMLLIElement : HTMLElement { - attribute long value; + attribute long value; + + // also has obsolete members }; -interface HTMLDListElement : HTMLElement {}; +interface HTMLDListElement : HTMLElement { + // also has obsolete members +}; -interface HTMLDivElement : HTMLElement {}; +interface HTMLDivElement : HTMLElement { + // also has obsolete members +}; interface HTMLAnchorElement : HTMLElement { - stringifier attribute DOMString href; - attribute DOMString target; - - attribute DOMString download; - attribute DOMString ping; - - attribute DOMString rel; + attribute DOMString target; + attribute DOMString download; + [PutForwards=value] attribute DOMSettableTokenList ping; + attribute DOMString rel; readonly attribute DOMTokenList relList; - attribute DOMString media; - attribute DOMString hreflang; - attribute DOMString type; + attribute DOMString hreflang; + attribute DOMString type; - attribute DOMString text; + attribute DOMString text; - // URL decomposition IDL attributes - attribute DOMString protocol; - attribute DOMString host; - attribute DOMString hostname; - attribute DOMString port; - attribute DOMString pathname; - attribute DOMString search; - attribute DOMString hash; + // also has obsolete members }; +HTMLAnchorElement implements URLUtils; interface HTMLDataElement : HTMLElement { - attribute DOMString value; + attribute DOMString value; }; interface HTMLTimeElement : HTMLElement { - attribute DOMString datetime; + attribute DOMString dateTime; }; interface HTMLSpanElement : HTMLElement {}; -interface HTMLBRElement : HTMLElement {}; +interface HTMLBRElement : HTMLElement { + // also has obsolete members +}; interface HTMLModElement : HTMLElement { - attribute DOMString cite; - attribute DOMString dateTime; + attribute DOMString cite; + attribute DOMString dateTime; +}; + +interface HTMLPictureElement : HTMLElement {}; + +partial interface HTMLSourceElement { + attribute DOMString srcset; + attribute DOMString sizes; + attribute DOMString media; }; -[NamedConstructor=Image(), - NamedConstructor=Image(unsigned long width), - NamedConstructor=Image(unsigned long width, unsigned long height)] +[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)] interface HTMLImageElement : HTMLElement { attribute DOMString alt; attribute DOMString src; attribute DOMString srcset; - attribute DOMString crossOrigin; + attribute DOMString sizes; + attribute DOMString? crossOrigin; attribute DOMString useMap; attribute boolean isMap; attribute unsigned long width; @@ -428,78 +320,94 @@ interface HTMLImageElement : HTMLElement { readonly attribute unsigned long naturalWidth; readonly attribute unsigned long naturalHeight; readonly attribute boolean complete; + readonly attribute DOMString currentSrc; + + // also has obsolete members }; interface HTMLIFrameElement : HTMLElement { - attribute DOMString src; - attribute DOMString srcdoc; - attribute DOMString name; + attribute DOMString src; + attribute DOMString srcdoc; + attribute DOMString name; [PutForwards=value] readonly attribute DOMSettableTokenList sandbox; - attribute boolean seamless; - attribute DOMString width; - attribute DOMString height; + attribute boolean seamless; + attribute boolean allowFullscreen; + attribute DOMString width; + attribute DOMString height; readonly attribute Document? contentDocument; readonly attribute WindowProxy? contentWindow; + Document? getSVGDocument(); + + // also has obsolete members }; interface HTMLEmbedElement : HTMLElement { - attribute DOMString src; - attribute DOMString type; - attribute DOMString width; - attribute DOMString height; + attribute DOMString src; + attribute DOMString type; + attribute DOMString width; + attribute DOMString height; + Document? getSVGDocument(); legacycaller any (any... arguments); + + // also has obsolete members }; interface HTMLObjectElement : HTMLElement { - attribute DOMString data; - attribute DOMString type; - attribute boolean typeMustMatch; - attribute DOMString name; - attribute DOMString useMap; + attribute DOMString data; + attribute DOMString type; + attribute boolean typeMustMatch; + attribute DOMString name; + attribute DOMString useMap; readonly attribute HTMLFormElement? form; - attribute DOMString width; - attribute DOMString height; + attribute DOMString width; + attribute DOMString height; readonly attribute Document? contentDocument; readonly attribute WindowProxy? contentWindow; + Document? getSVGDocument(); readonly attribute boolean willValidate; readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); legacycaller any (any... arguments); + + // also has obsolete members }; interface HTMLParamElement : HTMLElement { - attribute DOMString name; - attribute DOMString value; + attribute DOMString name; + attribute DOMString value; + + // also has obsolete members }; interface HTMLVideoElement : HTMLMediaElement { - attribute unsigned long width; - attribute unsigned long height; + attribute unsigned long width; + attribute unsigned long height; readonly attribute unsigned long videoWidth; readonly attribute unsigned long videoHeight; - attribute DOMString poster; + attribute DOMString poster; }; -[NamedConstructor=Audio(), - NamedConstructor=Audio(DOMString src)] +[NamedConstructor=Audio(optional DOMString src)] interface HTMLAudioElement : HTMLMediaElement {}; interface HTMLSourceElement : HTMLElement { - attribute DOMString src; - attribute DOMString type; - attribute DOMString media; + attribute DOMString src; + attribute DOMString type; + + // also has obsolete members }; interface HTMLTrackElement : HTMLElement { - attribute DOMString kind; - attribute DOMString src; - attribute DOMString srclang; - attribute DOMString label; - attribute boolean default; + attribute DOMString kind; + attribute DOMString src; + attribute DOMString srclang; + attribute DOMString label; + attribute boolean default; const unsigned short NONE = 0; const unsigned short LOADING = 1; @@ -510,24 +418,27 @@ interface HTMLTrackElement : HTMLElement { readonly attribute TextTrack track; }; +enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" }; +typedef (MediaStream or MediaSource or Blob) MediaProvider; interface HTMLMediaElement : HTMLElement { // error state readonly attribute MediaError? error; // network state - attribute DOMString src; + attribute DOMString src; + attribute MediaProvider? srcObject; readonly attribute DOMString currentSrc; - attribute DOMString crossOrigin; + attribute DOMString? crossOrigin; const unsigned short NETWORK_EMPTY = 0; const unsigned short NETWORK_IDLE = 1; const unsigned short NETWORK_LOADING = 2; const unsigned short NETWORK_NO_SOURCE = 3; readonly attribute unsigned short networkState; - attribute DOMString preload; + attribute DOMString preload; readonly attribute TimeRanges buffered; void load(); - DOMString canPlayType(DOMString type); + CanPlayTypeResult canPlayType(DOMString type); // ready state const unsigned short HAVE_NOTHING = 0; @@ -539,36 +450,36 @@ interface HTMLMediaElement : HTMLElement { readonly attribute boolean seeking; // playback state - attribute double currentTime; + attribute double currentTime; void fastSeek(double time); readonly attribute unrestricted double duration; - readonly attribute Date startDate; + Date getStartDate(); readonly attribute boolean paused; - attribute double defaultPlaybackRate; - attribute double playbackRate; + attribute double defaultPlaybackRate; + attribute double playbackRate; readonly attribute TimeRanges played; readonly attribute TimeRanges seekable; readonly attribute boolean ended; - attribute boolean autoplay; - attribute boolean loop; + attribute boolean autoplay; + attribute boolean loop; void play(); void pause(); // media controller - attribute DOMString mediaGroup; - attribute MediaController? controller; + attribute DOMString mediaGroup; + attribute MediaController? controller; // controls - attribute boolean controls; - attribute double volume; - attribute boolean muted; - attribute boolean defaultMuted; + attribute boolean controls; + attribute double volume; + attribute boolean muted; + attribute boolean defaultMuted; // tracks - readonly attribute AudioTrackList audioTracks; - readonly attribute VideoTrackList videoTracks; - readonly attribute TextTrackList textTracks; - TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language); + [SameObject] readonly attribute AudioTrackList audioTracks; + [SameObject] readonly attribute VideoTrackList videoTracks; + [SameObject] readonly attribute TextTrackList textTracks; + TextTrack addTextTrack(TextTrackKind kind, optional DOMString label = "", optional DOMString language = ""); }; interface MediaError { @@ -584,9 +495,9 @@ interface AudioTrackList : EventTarget { getter AudioTrack (unsigned long index); AudioTrack? getTrackById(DOMString id); - attribute EventHandler onchange; - attribute EventHandler onaddtrack; - attribute EventHandler onremovetrack; + attribute EventHandler onchange; + attribute EventHandler onaddtrack; + attribute EventHandler onremovetrack; }; interface AudioTrack { @@ -594,7 +505,7 @@ interface AudioTrack { readonly attribute DOMString kind; readonly attribute DOMString label; readonly attribute DOMString language; - attribute boolean enabled; + attribute boolean enabled; }; interface VideoTrackList : EventTarget { @@ -603,9 +514,9 @@ interface VideoTrackList : EventTarget { VideoTrack? getTrackById(DOMString id); readonly attribute long selectedIndex; - attribute EventHandler onchange; - attribute EventHandler onaddtrack; - attribute EventHandler onremovetrack; + attribute EventHandler onchange; + attribute EventHandler onaddtrack; + attribute EventHandler onremovetrack; }; interface VideoTrack { @@ -613,7 +524,7 @@ interface VideoTrack { readonly attribute DOMString kind; readonly attribute DOMString label; readonly attribute DOMString language; - attribute boolean selected; + attribute boolean selected; }; enum MediaControllerPlaybackState { "waiting", "playing", "ended" }; @@ -624,7 +535,7 @@ interface MediaController : EventTarget { readonly attribute TimeRanges buffered; readonly attribute TimeRanges seekable; readonly attribute unrestricted double duration; - attribute double currentTime; + attribute double currentTime; readonly attribute boolean paused; readonly attribute MediaControllerPlaybackState playbackState; @@ -633,45 +544,50 @@ interface MediaController : EventTarget { void unpause(); void play(); // calls play() on all media elements as well - attribute double defaultPlaybackRate; - attribute double playbackRate; + attribute double defaultPlaybackRate; + attribute double playbackRate; - attribute double volume; - attribute boolean muted; + attribute double volume; + attribute boolean muted; - attribute EventHandler onemptied; - attribute EventHandler onloadedmetadata; - attribute EventHandler onloadeddata; - attribute EventHandler oncanplay; - attribute EventHandler oncanplaythrough; - attribute EventHandler onplaying; - attribute EventHandler onended; - attribute EventHandler onwaiting; + attribute EventHandler onemptied; + attribute EventHandler onloadedmetadata; + attribute EventHandler onloadeddata; + attribute EventHandler oncanplay; + attribute EventHandler oncanplaythrough; + attribute EventHandler onplaying; + attribute EventHandler onended; + attribute EventHandler onwaiting; - attribute EventHandler ondurationchange; - attribute EventHandler ontimeupdate; - attribute EventHandler onplay; - attribute EventHandler onpause; - attribute EventHandler onratechange; - attribute EventHandler onvolumechange; + attribute EventHandler ondurationchange; + attribute EventHandler ontimeupdate; + attribute EventHandler onplay; + attribute EventHandler onpause; + attribute EventHandler onratechange; + attribute EventHandler onvolumechange; }; interface TextTrackList : EventTarget { readonly attribute unsigned long length; getter TextTrack (unsigned long index); + TextTrack? getTrackById(DOMString id); - attribute EventHandler onaddtrack; - attribute EventHandler onremovetrack; + attribute EventHandler onchange; + attribute EventHandler onaddtrack; + attribute EventHandler onremovetrack; }; -enum TextTrackMode { "disabled", "hidden", "showing" }; +enum TextTrackMode { "disabled", "hidden", "showing" }; +enum TextTrackKind { "subtitles", "captions", "descriptions", "chapters", "metadata" }; interface TextTrack : EventTarget { - readonly attribute DOMString kind; + readonly attribute TextTrackKind kind; readonly attribute DOMString label; readonly attribute DOMString language; + + readonly attribute DOMString id; readonly attribute DOMString inBandMetadataTrackDispatchType; - attribute TextTrackMode mode; + attribute TextTrackMode mode; readonly attribute TextTrackCueList? cues; readonly attribute TextTrackCueList? activeCues; @@ -679,7 +595,7 @@ interface TextTrack : EventTarget { void addCue(TextTrackCue cue); void removeCue(TextTrackCue cue); - attribute EventHandler oncuechange; + attribute EventHandler oncuechange; }; interface TextTrackCueList { @@ -688,26 +604,16 @@ interface TextTrackCueList { TextTrackCue? getCueById(DOMString id); }; -enum AutoKeyword { "auto" }; -[Constructor(double startTime, double endTime, DOMString text)] interface TextTrackCue : EventTarget { readonly attribute TextTrack? track; - attribute DOMString id; - attribute double startTime; - attribute double endTime; - attribute boolean pauseOnExit; - attribute DOMString vertical; - attribute boolean snapToLines; - attribute (long or AutoKeyword) line; - attribute long position; - attribute long size; - attribute DOMString align; - attribute DOMString text; - DocumentFragment getCueAsHTML(); + attribute DOMString id; + attribute double startTime; + attribute double endTime; + attribute boolean pauseOnExit; - attribute EventHandler onenter; - attribute EventHandler onexit; + attribute EventHandler onenter; + attribute EventHandler onexit; }; interface TimeRanges { @@ -718,465 +624,254 @@ interface TimeRanges { [Constructor(DOMString type, optional TrackEventInit eventInitDict)] interface TrackEvent : Event { - readonly attribute object? track; + readonly attribute (VideoTrack or AudioTrack or TextTrack)? track; }; dictionary TrackEventInit : EventInit { - object? track; -}; - -interface HTMLCanvasElement : HTMLElement { - attribute unsigned long width; - attribute unsigned long height; - - DOMString toDataURL(optional DOMString type, any... arguments); - DOMString toDataURLHD(optional DOMString type, any... arguments); - void toBlob(FileCallback? _callback, optional DOMString type, any... arguments); - void toBlobHD(FileCallback? _callback, optional DOMString type, any... arguments); - - object? getContext(DOMString contextId, any... arguments); - boolean supportsContext(DOMString contextId, any... arguments); -}; - -interface CanvasRenderingContext2D { - - // back-reference to the canvas - readonly attribute HTMLCanvasElement canvas; - - // state - void save(); // push state on state stack - void restore(); // pop state stack and restore state - - // transformations (default transform is the identity matrix) - attribute SVGMatrix currentTransform; - void scale(unrestricted double x, unrestricted double y); - void rotate(unrestricted double angle); - void translate(unrestricted double x, unrestricted double y); - void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); - void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); - void resetTransform(); - - // compositing - attribute unrestricted double globalAlpha; // (default 1.0) - attribute DOMString globalCompositeOperation; // (default source-over) - - // image smoothing - attribute boolean imageSmoothingEnabled; // (default true) - - // colors and styles (see also the CanvasDrawingStyles interface) - attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) - attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) - CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); - CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); - CanvasPattern createPattern((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, DOMString repetition); - - // shadows - attribute unrestricted double shadowOffsetX; // (default 0) - attribute unrestricted double shadowOffsetY; // (default 0) - attribute unrestricted double shadowBlur; // (default 0) - attribute DOMString shadowColor; // (default transparent black) - - // rects - void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); - void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); - void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); - - // path API (see also CanvasPathMethods) - void beginPath(); - void fill(); - void fill(Path path); - void stroke(); - void stroke(Path path); - void drawSystemFocusRing(Element element); - void drawSystemFocusRing(Path path, Element element); - boolean drawCustomFocusRing(Element element); - boolean drawCustomFocusRing(Path path, Element element); - void scrollPathIntoView(); - void scrollPathIntoView(Path path); - void clip(); - void clip(Path path); - void resetClip(); - boolean isPointInPath(unrestricted double x, unrestricted double y); - boolean isPointInPath(Path path, unrestricted double x, unrestricted double y); - - // text (see also the CanvasDrawingStyles interface) - void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); - void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); - TextMetrics measureText(DOMString text); - - // drawing images - void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double dx, unrestricted double dy); - void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); - void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); - - // hit regions - void addHitRegion(HitRegionOptions options); - void removeHitRegion(HitRegionOptions options); - - // pixel manipulation - ImageData createImageData(double sw, double sh); - ImageData createImageData(ImageData imagedata); - ImageData createImageDataHD(double sw, double sh); - ImageData getImageData(double sx, double sy, double sw, double sh); - ImageData getImageDataHD(double sx, double sy, double sw, double sh); - void putImageData(ImageData imagedata, double dx, double dy); - void putImageData(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight); - void putImageDataHD(ImageData imagedata, double dx, double dy); - void putImageDataHD(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight); -}; -CanvasRenderingContext2D implements CanvasDrawingStyles; -CanvasRenderingContext2D implements CanvasPathMethods; - -[NoInterfaceObject] -interface CanvasDrawingStyles { - // line caps/joins - attribute unrestricted double lineWidth; // (default 1) - attribute DOMString lineCap; // "butt", "round", "square" (default "butt") - attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter") - attribute unrestricted double miterLimit; // (default 10) - - // dashed lines - void setLineDash(sequence segments); // default empty - sequence getLineDash(); - attribute unrestricted double lineDashOffset; - - // text - attribute DOMString font; // (default 10px sans-serif) - attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start") - attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic") -}; - -[NoInterfaceObject] -interface CanvasPathMethods { - // shared path API methods - void closePath(); - void moveTo(unrestricted double x, unrestricted double y); - void lineTo(unrestricted double x, unrestricted double y); - void quadraticCurveTo(unrestricted double cpx, unrestricted double cpy, unrestricted double x, unrestricted double y); - void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y); - void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius); - void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation); - void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); - void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); - void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, boolean anticlockwise); -}; - -interface CanvasGradient { - // opaque object - void addColorStop(double offset, DOMString color); -}; - -interface CanvasPattern { - // opaque object - void setTransform(SVGMatrix transform); -}; - -interface TextMetrics { - // x-direction - readonly attribute double width; // advance width - readonly attribute double actualBoundingBoxLeft; - readonly attribute double actualBoundingBoxRight; - - // y-direction - readonly attribute double fontBoundingBoxAscent; - readonly attribute double fontBoundingBoxDescent; - readonly attribute double actualBoundingBoxAscent; - readonly attribute double actualBoundingBoxDescent; - readonly attribute double emHeightAscent; - readonly attribute double emHeightDescent; - readonly attribute double hangingBaseline; - readonly attribute double alphabeticBaseline; - readonly attribute double ideographicBaseline; -}; - -dictionary HitRegionOptions { - Path? path = null; - DOMString id = ""; - DOMString? parentID = null; - DOMString cursor = "inherit"; - // for control-backed regions: - Element? control = null; - // for unbacked regions: - DOMString? label = null; - DOMString? role = null; -}; - -interface ImageData { - readonly attribute unsigned long width; - readonly attribute unsigned long height; - readonly attribute Uint8ClampedArray data; -}; - -[Constructor(optional Element scope)] -interface DrawingStyle { }; -DrawingStyle implements CanvasDrawingStyles; - -[Constructor, - Constructor(Path path), - Constructor(DOMString d)] -interface Path { - void addPath(Path path, SVGMatrix? transformation); - void addPathByStrokingPath(Path path, CanvasDrawingStyles styles, SVGMatrix? transformation); - void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); - void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); - void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path path, optional unrestricted double maxWidth); - void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path path, optional unrestricted double maxWidth); -}; -Path implements CanvasPathMethods; - -partial interface Screen { - readonly attribute double canvasResolution; -}; - -partial interface MouseEvent { - readonly attribute DOMString? region; -}; - -partial dictionary MouseEventInit { - DOMString? region; + (VideoTrack or AudioTrack or TextTrack)? track; }; interface HTMLMapElement : HTMLElement { - attribute DOMString name; + attribute DOMString name; readonly attribute HTMLCollection areas; readonly attribute HTMLCollection images; }; interface HTMLAreaElement : HTMLElement { - attribute DOMString alt; - attribute DOMString coords; - attribute DOMString shape; - stringifier attribute DOMString href; - attribute DOMString target; - - attribute DOMString download; - attribute DOMString ping; - - attribute DOMString rel; + attribute DOMString alt; + attribute DOMString coords; + attribute DOMString shape; + attribute DOMString target; + attribute DOMString download; + [PutForwards=value] attribute DOMSettableTokenList ping; + attribute DOMString rel; readonly attribute DOMTokenList relList; - attribute DOMString media; - attribute DOMString hreflang; - attribute DOMString type; + attribute DOMString hreflang; + attribute DOMString type; - // URL decomposition IDL attributes - attribute DOMString protocol; - attribute DOMString host; - attribute DOMString hostname; - attribute DOMString port; - attribute DOMString pathname; - attribute DOMString search; - attribute DOMString hash; + // also has obsolete members }; +HTMLAreaElement implements URLUtils; interface HTMLTableElement : HTMLElement { - attribute HTMLTableCaptionElement? caption; + attribute HTMLTableCaptionElement? caption; HTMLElement createCaption(); void deleteCaption(); - attribute HTMLTableSectionElement? tHead; + attribute HTMLTableSectionElement? tHead; HTMLElement createTHead(); void deleteTHead(); - attribute HTMLTableSectionElement? tFoot; + attribute HTMLTableSectionElement? tFoot; HTMLElement createTFoot(); void deleteTFoot(); readonly attribute HTMLCollection tBodies; HTMLElement createTBody(); readonly attribute HTMLCollection rows; - HTMLElement insertRow(optional long index); + HTMLElement insertRow(optional long index = -1); void deleteRow(long index); + attribute boolean sortable; + void stopSorting(); + + // also has obsolete members }; -interface HTMLTableCaptionElement : HTMLElement {}; +interface HTMLTableCaptionElement : HTMLElement { + // also has obsolete members +}; interface HTMLTableColElement : HTMLElement { - attribute unsigned long span; + attribute unsigned long span; + + // also has obsolete members }; interface HTMLTableSectionElement : HTMLElement { readonly attribute HTMLCollection rows; - HTMLElement insertRow(optional long index); + HTMLElement insertRow(optional long index = -1); void deleteRow(long index); + + // also has obsolete members }; interface HTMLTableRowElement : HTMLElement { readonly attribute long rowIndex; readonly attribute long sectionRowIndex; readonly attribute HTMLCollection cells; - HTMLElement insertCell(optional long index); + HTMLElement insertCell(optional long index = -1); void deleteCell(long index); + + // also has obsolete members }; -interface HTMLTableDataCellElement : HTMLTableCellElement {}; +interface HTMLTableDataCellElement : HTMLTableCellElement { + // also has obsolete members +}; interface HTMLTableHeaderCellElement : HTMLTableCellElement { - attribute DOMString scope; - attribute DOMString abbr; + attribute DOMString scope; + attribute DOMString abbr; + attribute DOMString sorted; + void sort(); }; interface HTMLTableCellElement : HTMLElement { - attribute unsigned long colSpan; - attribute unsigned long rowSpan; + attribute unsigned long colSpan; + attribute unsigned long rowSpan; [PutForwards=value] readonly attribute DOMSettableTokenList headers; readonly attribute long cellIndex; + + // also has obsolete members }; [OverrideBuiltins] interface HTMLFormElement : HTMLElement { - attribute DOMString acceptCharset; - attribute DOMString action; - attribute DOMString autocomplete; - attribute DOMString enctype; - attribute DOMString encoding; - attribute DOMString method; - attribute DOMString name; - attribute boolean noValidate; - attribute DOMString target; + attribute DOMString acceptCharset; + attribute DOMString action; + attribute DOMString autocomplete; + attribute DOMString enctype; + attribute DOMString encoding; + attribute DOMString method; + attribute DOMString name; + attribute boolean noValidate; + attribute DOMString target; readonly attribute HTMLFormControlsCollection elements; readonly attribute long length; getter Element (unsigned long index); - getter object (DOMString name); + getter (RadioNodeList or Element) (DOMString name); void submit(); void reset(); boolean checkValidity(); -}; - -interface HTMLFieldSetElement : HTMLElement { - attribute boolean disabled; - readonly attribute HTMLFormElement? form; - attribute DOMString name; - - readonly attribute DOMString type; - - readonly attribute HTMLFormControlsCollection elements; - - readonly attribute boolean willValidate; - readonly attribute ValidityState validity; - readonly attribute DOMString validationMessage; - boolean checkValidity(); - void setCustomValidity(DOMString error); -}; + boolean reportValidity(); -interface HTMLLegendElement : HTMLElement { - readonly attribute HTMLFormElement? form; + void requestAutocomplete(); }; interface HTMLLabelElement : HTMLElement { readonly attribute HTMLFormElement? form; - attribute DOMString htmlFor; + attribute DOMString htmlFor; readonly attribute HTMLElement? control; }; interface HTMLInputElement : HTMLElement { - attribute DOMString accept; - attribute DOMString alt; - attribute DOMString autocomplete; - attribute boolean autofocus; - attribute boolean defaultChecked; - attribute boolean checked; - attribute DOMString dirName; - attribute boolean disabled; + attribute DOMString accept; + attribute DOMString alt; + attribute DOMString autocomplete; + attribute boolean autofocus; + attribute boolean defaultChecked; + attribute boolean checked; + attribute DOMString dirName; + attribute boolean disabled; readonly attribute HTMLFormElement? form; readonly attribute FileList? files; - attribute DOMString formAction; - attribute DOMString formEnctype; - attribute DOMString formMethod; - attribute boolean formNoValidate; - attribute DOMString formTarget; - attribute unsigned long height; - attribute boolean indeterminate; - attribute DOMString inputMode; + attribute DOMString formAction; + attribute DOMString formEnctype; + attribute DOMString formMethod; + attribute boolean formNoValidate; + attribute DOMString formTarget; + attribute unsigned long height; + attribute boolean indeterminate; + attribute DOMString inputMode; readonly attribute HTMLElement? list; - attribute DOMString max; - attribute long maxLength; - attribute DOMString min; - attribute boolean multiple; - attribute DOMString name; - attribute DOMString pattern; - attribute DOMString placeholder; - attribute boolean readOnly; - attribute boolean required; - attribute unsigned long size; - attribute DOMString src; - attribute DOMString step; - attribute DOMString type; - attribute DOMString defaultValue; + attribute DOMString max; + attribute long maxLength; + attribute DOMString min; + attribute long minLength; + attribute boolean multiple; + attribute DOMString name; + attribute DOMString pattern; + attribute DOMString placeholder; + attribute boolean readOnly; + attribute boolean required; + attribute unsigned long size; + attribute DOMString src; + attribute DOMString step; + attribute DOMString type; + attribute DOMString defaultValue; [TreatNullAs=EmptyString] attribute DOMString value; - attribute Date? valueAsDate; - attribute unrestricted double valueAsNumber; - attribute unsigned long width; + attribute Date? valueAsDate; + attribute unrestricted double valueAsNumber; + attribute double valueLow; + attribute double valueHigh; + attribute unsigned long width; - void stepUp(optional long n); - void stepDown(optional long n); + void stepUp(optional long n = 1); + void stepDown(optional long n = 1); readonly attribute boolean willValidate; readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); readonly attribute NodeList labels; void select(); - attribute unsigned long selectionStart; - attribute unsigned long selectionEnd; - attribute DOMString selectionDirection; - + attribute unsigned long selectionStart; + attribute unsigned long selectionEnd; + attribute DOMString selectionDirection; void setRangeText(DOMString replacement); - void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode); - + void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve"); void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); + + // also has obsolete members }; interface HTMLButtonElement : HTMLElement { - attribute boolean autofocus; - attribute boolean disabled; + attribute boolean autofocus; + attribute boolean disabled; readonly attribute HTMLFormElement? form; - attribute DOMString formAction; - attribute DOMString formEnctype; - attribute DOMString formMethod; - attribute boolean formNoValidate; - attribute DOMString formTarget; - attribute DOMString name; - attribute DOMString type; - attribute DOMString value; + attribute DOMString formAction; + attribute DOMString formEnctype; + attribute DOMString formMethod; + attribute boolean formNoValidate; + attribute DOMString formTarget; + attribute DOMString name; + attribute DOMString type; + attribute DOMString value; + attribute HTMLMenuElement? menu; readonly attribute boolean willValidate; readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); readonly attribute NodeList labels; }; interface HTMLSelectElement : HTMLElement { - attribute boolean autofocus; - attribute boolean disabled; + attribute DOMString autocomplete; + attribute boolean autofocus; + attribute boolean disabled; readonly attribute HTMLFormElement? form; - attribute boolean multiple; - attribute DOMString name; - attribute boolean required; - attribute unsigned long size; + attribute boolean multiple; + attribute DOMString name; + attribute boolean required; + attribute unsigned long size; readonly attribute DOMString type; readonly attribute HTMLOptionsCollection options; - attribute unsigned long length; - getter Element item(unsigned long index); - object namedItem(DOMString name); + attribute unsigned long length; + getter Element? item(unsigned long index); + HTMLOptionElement? namedItem(DOMString name); void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); + void remove(); // ChildNode overload void remove(long index); setter creator void (unsigned long index, HTMLOptionElement? option); readonly attribute HTMLCollection selectedOptions; - attribute long selectedIndex; - attribute DOMString value; + attribute long selectedIndex; + attribute DOMString value; readonly attribute boolean willValidate; readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); readonly attribute NodeList labels; @@ -1187,45 +882,42 @@ interface HTMLDataListElement : HTMLElement { }; interface HTMLOptGroupElement : HTMLElement { - attribute boolean disabled; - attribute DOMString label; + attribute boolean disabled; + attribute DOMString label; }; -[NamedConstructor=Option(), - NamedConstructor=Option(DOMString text), - NamedConstructor=Option(DOMString text, DOMString value), - NamedConstructor=Option(DOMString text, DOMString value, boolean defaultSelected), - NamedConstructor=Option(DOMString text, DOMString value, boolean defaultSelected, boolean selected)] +[NamedConstructor=Option(optional DOMString text = "", optional DOMString value, optional boolean defaultSelected = false, optional boolean selected = false)] interface HTMLOptionElement : HTMLElement { - attribute boolean disabled; + attribute boolean disabled; readonly attribute HTMLFormElement? form; - attribute DOMString label; - attribute boolean defaultSelected; - attribute boolean selected; - attribute DOMString value; + attribute DOMString label; + attribute boolean defaultSelected; + attribute boolean selected; + attribute DOMString value; - attribute DOMString text; + attribute DOMString text; readonly attribute long index; }; interface HTMLTextAreaElement : HTMLElement { - attribute DOMString autocomplete; - attribute boolean autofocus; - attribute unsigned long cols; - attribute DOMString dirName; - attribute boolean disabled; + attribute DOMString autocomplete; + attribute boolean autofocus; + attribute unsigned long cols; + attribute DOMString dirName; + attribute boolean disabled; readonly attribute HTMLFormElement? form; - attribute DOMString inputMode; - attribute long maxLength; - attribute DOMString name; - attribute DOMString placeholder; - attribute boolean readOnly; - attribute boolean required; - attribute unsigned long rows; - attribute DOMString wrap; + attribute DOMString inputMode; + attribute long maxLength; + attribute long minLength; + attribute DOMString name; + attribute DOMString placeholder; + attribute boolean readOnly; + attribute boolean required; + attribute unsigned long rows; + attribute DOMString wrap; readonly attribute DOMString type; - attribute DOMString defaultValue; + attribute DOMString defaultValue; [TreatNullAs=EmptyString] attribute DOMString value; readonly attribute unsigned long textLength; @@ -1233,28 +925,27 @@ interface HTMLTextAreaElement : HTMLElement { readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); readonly attribute NodeList labels; void select(); - attribute unsigned long selectionStart; - attribute unsigned long selectionEnd; - attribute DOMString selectionDirection; - + attribute unsigned long selectionStart; + attribute unsigned long selectionEnd; + attribute DOMString selectionDirection; void setRangeText(DOMString replacement); - void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode); - + void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve"); void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); }; interface HTMLKeygenElement : HTMLElement { - attribute boolean autofocus; - attribute DOMString challenge; - attribute boolean disabled; + attribute boolean autofocus; + attribute DOMString challenge; + attribute boolean disabled; readonly attribute HTMLFormElement? form; - attribute DOMString keytype; - attribute DOMString name; + attribute DOMString keytype; + attribute DOMString name; readonly attribute DOMString type; @@ -1262,6 +953,7 @@ interface HTMLKeygenElement : HTMLElement { readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); readonly attribute NodeList labels; @@ -1270,85 +962,453 @@ interface HTMLKeygenElement : HTMLElement { interface HTMLOutputElement : HTMLElement { [PutForwards=value] readonly attribute DOMSettableTokenList htmlFor; readonly attribute HTMLFormElement? form; - attribute DOMString name; + attribute DOMString name; readonly attribute DOMString type; - attribute DOMString defaultValue; - attribute DOMString value; + attribute DOMString defaultValue; + attribute DOMString value; readonly attribute boolean willValidate; readonly attribute ValidityState validity; readonly attribute DOMString validationMessage; boolean checkValidity(); + boolean reportValidity(); void setCustomValidity(DOMString error); readonly attribute NodeList labels; }; interface HTMLProgressElement : HTMLElement { - attribute double value; - attribute double max; + attribute double value; + attribute double max; readonly attribute double position; readonly attribute NodeList labels; }; interface HTMLMeterElement : HTMLElement { - attribute double value; - attribute double min; - attribute double max; - attribute double low; - attribute double high; - attribute double optimum; + attribute double value; + attribute double min; + attribute double max; + attribute double low; + attribute double high; + attribute double optimum; readonly attribute NodeList labels; }; +interface HTMLFieldSetElement : HTMLElement { + attribute boolean disabled; + readonly attribute HTMLFormElement? form; + attribute DOMString name; -interface ValidityState { - readonly attribute boolean valueMissing; + readonly attribute DOMString type; + + readonly attribute HTMLFormControlsCollection elements; + + readonly attribute boolean willValidate; + [SameObject] readonly attribute ValidityState validity; + readonly attribute DOMString validationMessage; + boolean checkValidity(); + boolean reportValidity(); + void setCustomValidity(DOMString error); +}; + +interface HTMLLegendElement : HTMLElement { + readonly attribute HTMLFormElement? form; + + // also has obsolete members +}; + +enum AutocompleteErrorReason { "" /* empty string */, "cancel", "disabled", "invalid" }; + +[Constructor(DOMString type, optional AutocompleteErrorEventInit eventInitDict)] +interface AutocompleteErrorEvent : Event { + readonly attribute AutocompleteErrorReason reason; +}; + +dictionary AutocompleteErrorEventInit : EventInit { + AutocompleteErrorReason reason; +}; + +enum SelectionMode { + "select", + "start", + "end", + "preserve", // default +}; + +interface ValidityState { + readonly attribute boolean valueMissing; readonly attribute boolean typeMismatch; readonly attribute boolean patternMismatch; readonly attribute boolean tooLong; + readonly attribute boolean tooShort; readonly attribute boolean rangeUnderflow; readonly attribute boolean rangeOverflow; readonly attribute boolean stepMismatch; + readonly attribute boolean badInput; readonly attribute boolean customError; readonly attribute boolean valid; }; interface HTMLDetailsElement : HTMLElement { - attribute boolean open; + attribute boolean open; +}; + +interface HTMLMenuElement : HTMLElement { + attribute DOMString type; + attribute DOMString label; + + // also has obsolete members }; -interface HTMLCommandElement : HTMLElement { - attribute DOMString type; - attribute DOMString label; - attribute DOMString icon; - attribute boolean disabled; - attribute boolean checked; - attribute DOMString radiogroup; +interface HTMLMenuItemElement : HTMLElement { + attribute DOMString type; + attribute DOMString label; + attribute DOMString icon; + attribute boolean disabled; + attribute boolean checked; + attribute DOMString radiogroup; + attribute boolean default; readonly attribute HTMLElement? command; }; -interface HTMLMenuElement : HTMLElement { - attribute DOMString type; - attribute DOMString label; +[Constructor(DOMString type, optional RelatedEventInit eventInitDict)] +interface RelatedEvent : Event { + readonly attribute EventTarget? relatedTarget; +}; + +dictionary RelatedEventInit : EventInit { + EventTarget? relatedTarget; }; interface HTMLDialogElement : HTMLElement { - attribute boolean open; - attribute DOMString returnValue; + attribute boolean open; + attribute DOMString returnValue; void show(optional (MouseEvent or Element) anchor); void showModal(optional (MouseEvent or Element) anchor); void close(optional DOMString returnValue); }; -[NamedPropertiesObject] -interface Window : EventTarget { +interface HTMLScriptElement : HTMLElement { + attribute DOMString src; + attribute DOMString type; + attribute DOMString charset; + attribute boolean async; + attribute boolean defer; + attribute DOMString? crossOrigin; + attribute DOMString text; + + // also has obsolete members +}; + +interface HTMLTemplateElement : HTMLElement { + readonly attribute DocumentFragment content; +}; + +typedef (CanvasRenderingContext2D or WebGLRenderingContext) RenderingContext; + +interface HTMLCanvasElement : HTMLElement { + attribute unsigned long width; + attribute unsigned long height; + + RenderingContext? getContext(DOMString contextId, any... arguments); + boolean probablySupportsContext(DOMString contextId, any... arguments); + + void setContext(RenderingContext context); + CanvasProxy transferControlToProxy(); + + DOMString toDataURL(optional DOMString type, any... arguments); + void toBlob(FileCallback? _callback, optional DOMString type, any... arguments); +}; + +[Exposed=(Window,Worker)] +interface CanvasProxy { + void setContext(RenderingContext context); +}; +// CanvasProxy implements Transferable; + +typedef (HTMLImageElement or + HTMLVideoElement or + HTMLCanvasElement or + CanvasRenderingContext2D or + ImageBitmap) CanvasImageSource; + +enum CanvasFillRule { "nonzero", "evenodd" }; + +dictionary CanvasRenderingContext2DSettings { + boolean alpha = true; +}; + +[Constructor(), + Constructor(unsigned long width, unsigned long height), + Exposed=(Window,Worker)] +interface CanvasRenderingContext2D { + + // back-reference to the canvas + readonly attribute HTMLCanvasElement canvas; + + // canvas dimensions + attribute unsigned long width; + attribute unsigned long height; + + // for contexts that aren't directly fixed to a specific canvas + void commit(); // push the image to the output bitmap + + // state + void save(); // push state on state stack + void restore(); // pop state stack and restore state + + // transformations (default transform is the identity matrix) + attribute SVGMatrix currentTransform; + void scale(unrestricted double x, unrestricted double y); + void rotate(unrestricted double angle); + void translate(unrestricted double x, unrestricted double y); + void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); + void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); + void resetTransform(); + + // compositing + attribute unrestricted double globalAlpha; // (default 1.0) + attribute DOMString globalCompositeOperation; // (default source-over) + + // image smoothing + attribute boolean imageSmoothingEnabled; // (default true) + + // colours and styles (see also the CanvasDrawingStyles interface) + attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) + attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) + CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); + CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); + CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition); + + // shadows + attribute unrestricted double shadowOffsetX; // (default 0) + attribute unrestricted double shadowOffsetY; // (default 0) + attribute unrestricted double shadowBlur; // (default 0) + attribute DOMString shadowColor; // (default transparent black) + + // rects + void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); + void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); + void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); + + // path API (see also CanvasPathMethods) + void beginPath(); + void fill(optional CanvasFillRule fillRule = "nonzero"); + void fill(Path2D path, optional CanvasFillRule fillRule = "nonzero"); + void stroke(); + void stroke(Path2D path); + void drawFocusIfNeeded(Element element); + void drawFocusIfNeeded(Path2D path, Element element); + void scrollPathIntoView(); + void scrollPathIntoView(Path2D path); + void clip(optional CanvasFillRule fillRule = "nonzero"); + void clip(Path2D path, optional CanvasFillRule fillRule = "nonzero"); + void resetClip(); + boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule fillRule = "nonzero"); + boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule fillRule = "nonzero"); + boolean isPointInStroke(unrestricted double x, unrestricted double y); + boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y); + + // text (see also the CanvasDrawingStyles interface) + void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); + void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); + TextMetrics measureText(DOMString text); + + // drawing images + void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy); + void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); + void drawImage(CanvasImageSource image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); + + // hit regions + void addHitRegion(optional HitRegionOptions options); + void removeHitRegion(DOMString id); + void clearHitRegions(); + + // pixel manipulation + ImageData createImageData(double sw, double sh); + ImageData createImageData(ImageData imagedata); + ImageData getImageData(double sx, double sy, double sw, double sh); + void putImageData(ImageData imagedata, double dx, double dy); + void putImageData(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight); +}; +CanvasRenderingContext2D implements CanvasDrawingStyles; +CanvasRenderingContext2D implements CanvasPathMethods; + +[NoInterfaceObject, Exposed=(Window,Worker)] +interface CanvasDrawingStyles { + // line caps/joins + attribute unrestricted double lineWidth; // (default 1) + attribute DOMString lineCap; // "butt", "round", "square" (default "butt") + attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter") + attribute unrestricted double miterLimit; // (default 10) + + // dashed lines + void setLineDash(sequence segments); // default empty + sequence getLineDash(); + attribute unrestricted double lineDashOffset; + + // text + attribute DOMString font; // (default 10px sans-serif) + attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start") + attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic") + attribute DOMString direction; // "ltr", "rtl", "inherit" (default: "inherit") +}; + +[NoInterfaceObject, Exposed=(Window,Worker)] +interface CanvasPathMethods { + // shared path API methods + void closePath(); + void moveTo(unrestricted double x, unrestricted double y); + void lineTo(unrestricted double x, unrestricted double y); + void quadraticCurveTo(unrestricted double cpx, unrestricted double cpy, unrestricted double x, unrestricted double y); + void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y); + void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius); + void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation); + void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); + void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); + void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); +}; + +[Exposed=(Window,Worker)] +interface CanvasGradient { + // opaque object + void addColorStop(double offset, DOMString color); +}; + +[Exposed=(Window,Worker)] +interface CanvasPattern { + // opaque object + void setTransform(SVGMatrix transform); +}; + +[Exposed=(Window,Worker)] +interface TextMetrics { + // x-direction + readonly attribute double width; // advance width + readonly attribute double actualBoundingBoxLeft; + readonly attribute double actualBoundingBoxRight; + + // y-direction + readonly attribute double fontBoundingBoxAscent; + readonly attribute double fontBoundingBoxDescent; + readonly attribute double actualBoundingBoxAscent; + readonly attribute double actualBoundingBoxDescent; + readonly attribute double emHeightAscent; + readonly attribute double emHeightDescent; + readonly attribute double hangingBaseline; + readonly attribute double alphabeticBaseline; + readonly attribute double ideographicBaseline; +}; + +dictionary HitRegionOptions { + Path2D? path = null; + CanvasFillRule fillRule = "nonzero"; + DOMString id = ""; + DOMString? parentID = null; + DOMString cursor = "inherit"; + // for control-backed regions: + Element? control = null; + // for unbacked regions: + DOMString? label = null; + DOMString? role = null; +}; + +[Constructor(unsigned long sw, unsigned long sh), + Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh), + Exposed=(Window,Worker)] +interface ImageData { + readonly attribute unsigned long width; + readonly attribute unsigned long height; + readonly attribute Uint8ClampedArray data; +}; + +[Constructor(optional Element scope), Exposed=(Window,Worker)] +interface DrawingStyle { }; +DrawingStyle implements CanvasDrawingStyles; + +[Constructor, + Constructor(Path2D path), + Constructor(Path2D[] paths, optional CanvasFillRule fillRule = "nonzero"), + Constructor(DOMString d), Exposed=(Window,Worker)] +interface Path2D { + void addPath(Path2D path, optional SVGMatrix? transformation = null); + void addPathByStrokingPath(Path2D path, CanvasDrawingStyles styles, optional SVGMatrix? transformation = null); + void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); + void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); + void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path2D path, optional unrestricted double maxWidth); + void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path2D path, optional unrestricted double maxWidth); +}; +Path2D implements CanvasPathMethods; + +partial interface MouseEvent { + readonly attribute DOMString? region; +}; + +partial dictionary MouseEventInit { + DOMString? region; +}; + +partial interface Touch { + readonly attribute DOMString? region; +}; + +[NoInterfaceObject] +interface ElementContentEditable { + attribute DOMString contentEditable; + readonly attribute boolean isContentEditable; +}; + +interface DataTransfer { + attribute DOMString dropEffect; + attribute DOMString effectAllowed; + + [SameObject] readonly attribute DataTransferItemList items; + + void setDragImage(Element image, long x, long y); + + /* old interface */ + [SameObject] readonly attribute DOMString[] types; + DOMString getData(DOMString format); + void setData(DOMString format, DOMString data); + void clearData(optional DOMString format); + [SameObject] readonly attribute FileList files; +}; + +interface DataTransferItemList { + readonly attribute unsigned long length; + getter DataTransferItem (unsigned long index); + DataTransferItem? add(DOMString data, DOMString type); + DataTransferItem? add(File data); + void remove(unsigned long index); + void clear(); +}; + +interface DataTransferItem { + readonly attribute DOMString kind; + readonly attribute DOMString type; + void getAsString(FunctionStringCallback? _callback); + File? getAsFile(); +}; + +callback FunctionStringCallback = void (DOMString data); + +[Constructor(DOMString type, optional DragEventInit eventInitDict)] +interface DragEvent : MouseEvent { + readonly attribute DataTransfer? dataTransfer; +}; + +dictionary DragEventInit : MouseEventInit { + DataTransfer? dataTransfer; +}; + +[PrimaryGlobal] +/*sealed*/ interface Window : EventTarget { // the current browsing context [Unforgeable] readonly attribute WindowProxy window; [Replaceable] readonly attribute WindowProxy self; [Unforgeable] readonly attribute Document document; - attribute DOMString name; + attribute DOMString name; [PutForwards=href, Unforgeable] readonly attribute Location location; readonly attribute History history; [Replaceable] readonly attribute BarProp locationbar; @@ -1357,8 +1417,9 @@ interface Window : EventTarget { [Replaceable] readonly attribute BarProp scrollbars; [Replaceable] readonly attribute BarProp statusbar; [Replaceable] readonly attribute BarProp toolbar; - attribute DOMString status; + attribute DOMString status; void close(); + readonly attribute boolean closed; void stop(); void focus(); void blur(); @@ -1367,102 +1428,38 @@ interface Window : EventTarget { [Replaceable] readonly attribute WindowProxy frames; [Replaceable] readonly attribute unsigned long length; [Unforgeable] readonly attribute WindowProxy top; - attribute WindowProxy? opener; - readonly attribute WindowProxy parent; + attribute any opener; + [Replaceable] readonly attribute WindowProxy parent; readonly attribute Element? frameElement; - WindowProxy open(optional DOMString url, optional DOMString target, optional DOMString features, optional boolean replace); + WindowProxy open(optional DOMString url = "about:blank", optional DOMString target = "_blank", [TreatNullAs=EmptyString] optional DOMString features = "", optional boolean replace = false); getter WindowProxy (unsigned long index); getter object (DOMString name); // the user agent readonly attribute Navigator navigator; - - readonly attribute External external; + [Replaceable, SameObject] readonly attribute External external; readonly attribute ApplicationCache applicationCache; // user prompts + void alert(); void alert(DOMString message); - boolean confirm(DOMString message); - DOMString? prompt(DOMString message, optional DOMString default); + boolean confirm(optional DOMString message = ""); + DOMString? prompt(optional DOMString message = "", optional DOMString default = ""); void print(); - any showModalDialog(DOMString url, optional any argument); + any showModalDialog(DOMString url, optional any argument); // deprecated + + long requestAnimationFrame(FrameRequestCallback callback); + void cancelAnimationFrame(long handle); - // cross-document messaging void postMessage(any message, DOMString targetOrigin, optional sequence transfer); - // event handler IDL attributes - attribute EventHandler onabort; - attribute EventHandler onafterprint; - attribute EventHandler onbeforeprint; - attribute EventHandler onbeforeunload; - attribute EventHandler onblur; - attribute EventHandler oncancel; - attribute EventHandler oncanplay; - attribute EventHandler oncanplaythrough; - attribute EventHandler onchange; - attribute EventHandler onclick; - attribute EventHandler onclose; - attribute EventHandler oncontextmenu; - attribute EventHandler oncuechange; - attribute EventHandler ondblclick; - attribute EventHandler ondrag; - attribute EventHandler ondragend; - attribute EventHandler ondragenter; - attribute EventHandler ondragleave; - attribute EventHandler ondragover; - attribute EventHandler ondragstart; - attribute EventHandler ondrop; - attribute EventHandler ondurationchange; - attribute EventHandler onemptied; - attribute EventHandler onended; - attribute OnErrorEventHandler onerror; - attribute EventHandler onfocus; - attribute EventHandler onhashchange; - attribute EventHandler oninput; - attribute EventHandler oninvalid; - attribute EventHandler onkeydown; - attribute EventHandler onkeypress; - attribute EventHandler onkeyup; - attribute EventHandler onload; - attribute EventHandler onloadeddata; - attribute EventHandler onloadedmetadata; - attribute EventHandler onloadstart; - attribute EventHandler onmessage; - attribute EventHandler onmousedown; - attribute EventHandler onmousemove; - attribute EventHandler onmouseout; - attribute EventHandler onmouseover; - attribute EventHandler onmouseup; - attribute EventHandler onmousewheel; - attribute EventHandler onoffline; - attribute EventHandler ononline; - attribute EventHandler onpause; - attribute EventHandler onplay; - attribute EventHandler onplaying; - attribute EventHandler onpagehide; - attribute EventHandler onpageshow; - attribute EventHandler onpopstate; - attribute EventHandler onprogress; - attribute EventHandler onratechange; - attribute EventHandler onreset; - attribute EventHandler onresize; - attribute EventHandler onscroll; - attribute EventHandler onseeked; - attribute EventHandler onseeking; - attribute EventHandler onselect; - attribute EventHandler onshow; - attribute EventHandler onstalled; - attribute EventHandler onstorage; - attribute EventHandler onsubmit; - attribute EventHandler onsuspend; - attribute EventHandler ontimeupdate; - attribute EventHandler onunload; - attribute EventHandler onvolumechange; - attribute EventHandler onwaiting; + // also has obsolete members }; +Window implements GlobalEventHandlers; +Window implements WindowEventHandlers; interface BarProp { - attribute boolean visible; + attribute boolean visible; }; interface History { @@ -1471,27 +1468,20 @@ interface History { void go(optional long delta); void back(); void forward(); - void pushState(any data, DOMString title, optional DOMString url); - void replaceState(any data, DOMString title, optional DOMString url); + void pushState(any data, DOMString title, optional DOMString? url = null); + void replaceState(any data, DOMString title, optional DOMString? url = null); }; -interface Location { - stringifier attribute DOMString href; +[Unforgeable] interface Location { void assign(DOMString url); void replace(DOMString url); void reload(); - // URL decomposition IDL attributes - attribute DOMString protocol; - attribute DOMString host; - attribute DOMString hostname; - attribute DOMString port; - attribute DOMString pathname; - attribute DOMString search; - attribute DOMString hash; + [SameObject] readonly attribute DOMString[] ancestorOrigins; }; +Location implements URLUtils; -[Constructor(DOMString type, optional PopStateEventInit eventInitDict)] +[Constructor(DOMString type, optional PopStateEventInit eventInitDict), Exposed=(Window,Worker)] interface PopStateEvent : Event { readonly attribute any state; }; @@ -1500,7 +1490,7 @@ dictionary PopStateEventInit : EventInit { any state; }; -[Constructor(DOMString type, optional HashChangeEventInit eventInitDict)] +[Constructor(DOMString type, optional HashChangeEventInit eventInitDict), Exposed=(Window,Worker)] interface HashChangeEvent : Event { readonly attribute DOMString oldURL; readonly attribute DOMString newURL; @@ -1511,7 +1501,7 @@ dictionary HashChangeEventInit : EventInit { DOMString newURL; }; -[Constructor(DOMString type, optional PageTransitionEventInit eventInitDict)] +[Constructor(DOMString type, optional PageTransitionEventInit eventInitDict), Exposed=(Window,Worker)] interface PageTransitionEvent : Event { readonly attribute boolean persisted; }; @@ -1521,9 +1511,10 @@ dictionary PageTransitionEventInit : EventInit { }; interface BeforeUnloadEvent : Event { - attribute DOMString returnValue; + attribute DOMString returnValue; }; +[Exposed=(Window,SharedWorker)] interface ApplicationCache : EventTarget { // update status @@ -1541,66 +1532,184 @@ interface ApplicationCache : EventTarget { void swapCache(); // events - attribute EventHandler onchecking; - attribute EventHandler onerror; - attribute EventHandler onnoupdate; - attribute EventHandler ondownloading; - attribute EventHandler onprogress; - attribute EventHandler onupdateready; - attribute EventHandler oncached; - attribute EventHandler onobsolete; + attribute EventHandler onchecking; + attribute EventHandler onerror; + attribute EventHandler onnoupdate; + attribute EventHandler ondownloading; + attribute EventHandler onprogress; + attribute EventHandler onupdateready; + attribute EventHandler oncached; + attribute EventHandler onobsolete; }; -[NoInterfaceObject] +[NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorOnLine { readonly attribute boolean onLine; }; -[TreatNonCallableAsNull] +[Constructor(DOMString type, optional ErrorEventInit eventInitDict), Exposed=(Window,Worker)] +interface ErrorEvent : Event { + readonly attribute DOMString message; + readonly attribute DOMString filename; + readonly attribute unsigned long lineno; + readonly attribute unsigned long colno; + readonly attribute any error; +}; + +dictionary ErrorEventInit : EventInit { + DOMString message; + DOMString filename; + unsigned long lineno; + unsigned long colno; + any error; +}; + +[TreatNonObjectAsNull] callback EventHandlerNonNull = any (Event event); typedef EventHandlerNonNull? EventHandler; -[TreatNonCallableAsNull] -callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, DOMString source, unsigned long lineno, unsigned long column); +[TreatNonObjectAsNull] +callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column, optional any error); typedef OnErrorEventHandlerNonNull? OnErrorEventHandler; +[TreatNonObjectAsNull] +callback OnBeforeUnloadEventHandlerNonNull = DOMString? (Event event); +typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnloadEventHandler; + +[NoInterfaceObject] +interface GlobalEventHandlers { + attribute EventHandler onabort; + attribute EventHandler onautocomplete; + attribute EventHandler onautocompleteerror; + attribute EventHandler onblur; + attribute EventHandler oncancel; + attribute EventHandler oncanplay; + attribute EventHandler oncanplaythrough; + attribute EventHandler onchange; + attribute EventHandler onclick; + attribute EventHandler onclose; + attribute EventHandler oncontextmenu; + attribute EventHandler oncuechange; + attribute EventHandler ondblclick; + attribute EventHandler ondrag; + attribute EventHandler ondragend; + attribute EventHandler ondragenter; + attribute EventHandler ondragexit; + attribute EventHandler ondragleave; + attribute EventHandler ondragover; + attribute EventHandler ondragstart; + attribute EventHandler ondrop; + attribute EventHandler ondurationchange; + attribute EventHandler onemptied; + attribute EventHandler onended; + attribute OnErrorEventHandler onerror; + attribute EventHandler onfocus; + attribute EventHandler oninput; + attribute EventHandler oninvalid; + attribute EventHandler onkeydown; + attribute EventHandler onkeypress; + attribute EventHandler onkeyup; + attribute EventHandler onload; + attribute EventHandler onloadeddata; + attribute EventHandler onloadedmetadata; + attribute EventHandler onloadstart; + attribute EventHandler onmousedown; + [LenientThis] attribute EventHandler onmouseenter; + [LenientThis] attribute EventHandler onmouseleave; + attribute EventHandler onmousemove; + attribute EventHandler onmouseout; + attribute EventHandler onmouseover; + attribute EventHandler onmouseup; + attribute EventHandler onmousewheel; + attribute EventHandler onpause; + attribute EventHandler onplay; + attribute EventHandler onplaying; + attribute EventHandler onprogress; + attribute EventHandler onratechange; + attribute EventHandler onreset; + attribute EventHandler onresize; + attribute EventHandler onscroll; + attribute EventHandler onseeked; + attribute EventHandler onseeking; + attribute EventHandler onselect; + attribute EventHandler onshow; + attribute EventHandler onsort; + attribute EventHandler onstalled; + attribute EventHandler onsubmit; + attribute EventHandler onsuspend; + attribute EventHandler ontimeupdate; + attribute EventHandler ontoggle; + attribute EventHandler onvolumechange; + attribute EventHandler onwaiting; +}; + [NoInterfaceObject] +interface WindowEventHandlers { + attribute EventHandler onafterprint; + attribute EventHandler onbeforeprint; + attribute OnBeforeUnloadEventHandler onbeforeunload; + attribute EventHandler onhashchange; + attribute EventHandler onlanguagechange; + attribute EventHandler onmessage; + attribute EventHandler onoffline; + attribute EventHandler ononline; + attribute EventHandler onpagehide; + attribute EventHandler onpageshow; + attribute EventHandler onpopstate; + attribute EventHandler onstorage; + attribute EventHandler onunload; +}; + +[NoInterfaceObject, Exposed=(Window,Worker)] interface WindowBase64 { DOMString btoa(DOMString btoa); DOMString atob(DOMString atob); }; Window implements WindowBase64; -[NoInterfaceObject] +[NoInterfaceObject, Exposed=(Window,Worker)] interface WindowTimers { - long setTimeout(Function handler, optional long timeout, any... arguments); - long setTimeout(DOMString handler, optional long timeout, any... arguments); - void clearTimeout(long handle); - long setInterval(Function handler, optional long timeout, any... arguments); - long setInterval(DOMString handler, optional long timeout, any... arguments); - void clearInterval(long handle); + long setTimeout(Function handler, optional long timeout = 0, any... arguments); + long setTimeout(DOMString handler, optional long timeout = 0, any... arguments); + void clearTimeout(optional long handle = 0); + long setInterval(Function handler, optional long timeout = 0, any... arguments); + long setInterval(DOMString handler, optional long timeout = 0, any... arguments); + void clearInterval(optional long handle = 0); }; Window implements WindowTimers; -[NoInterfaceObject] interface WindowModal { +[NoInterfaceObject] +interface WindowModal { readonly attribute any dialogArguments; - attribute DOMString returnValue; + attribute any returnValue; }; interface Navigator { // objects implementing this interface also implement the interfaces given below }; Navigator implements NavigatorID; +Navigator implements NavigatorLanguage; Navigator implements NavigatorOnLine; Navigator implements NavigatorContentUtils; Navigator implements NavigatorStorageUtils; +Navigator implements NavigatorPlugins; -[NoInterfaceObject] +[NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorID { + readonly attribute DOMString appCodeName; // constant "Mozilla" readonly attribute DOMString appName; readonly attribute DOMString appVersion; readonly attribute DOMString platform; + readonly attribute DOMString product; // constant "Gecko" + boolean taintEnabled(); // constant false readonly attribute DOMString userAgent; + readonly attribute DOMString vendorSub; +}; + +[NoInterfaceObject, Exposed=(Window,Worker)] +interface NavigatorLanguage { + readonly attribute DOMString? language; + readonly attribute DOMString[] languages; }; [NoInterfaceObject] @@ -1616,162 +1725,93 @@ interface NavigatorContentUtils { [NoInterfaceObject] interface NavigatorStorageUtils { + readonly attribute boolean cookieEnabled; void yieldForStorageUpdates(); }; -interface External { - void AddSearchProvider(DOMString engineURL); - unsigned long IsSearchProviderInstalled(DOMString engineURL); -}; - -interface DataTransfer { - attribute DOMString dropEffect; - attribute DOMString effectAllowed; - - readonly attribute DataTransferItemList items; - - void setDragImage(Element image, long x, long y); - - /* old interface */ - readonly attribute DOMString[] types; - DOMString getData(DOMString format); - void setData(DOMString format, DOMString data); - void clearData(optional DOMString format); - readonly attribute FileList files; +[NoInterfaceObject] +interface NavigatorPlugins { + [SameObject] readonly attribute PluginArray plugins; + [SameObject] readonly attribute MimeTypeArray mimeTypes; + readonly attribute boolean javaEnabled; }; -interface DataTransferItemList { +interface PluginArray { + void refresh(optional boolean reload = false); readonly attribute unsigned long length; - getter DataTransferItem (unsigned long index); - deleter void (unsigned long index); - void clear(); - - DataTransferItem? add(DOMString data, DOMString type); - DataTransferItem? add(File data); -}; - -interface DataTransferItem { - readonly attribute DOMString kind; - readonly attribute DOMString type; - void getAsString(FunctionStringCallback? _callback); - - File? getAsFile(); -}; - -[Callback, NoInterfaceObject] -interface FunctionStringCallback { - void handleEvent(DOMString data); -}; - -[Constructor(DOMString type, optional DragEventInit eventInitDict)] -interface DragEvent : MouseEvent { - readonly attribute DataTransfer? dataTransfer; -}; - -dictionary DragEventInit : MouseEventInit { - DataTransfer? dataTransfer; -}; - -interface WorkerGlobalScope : EventTarget { - readonly attribute WorkerGlobalScope self; - readonly attribute WorkerLocation location; - - void close(); - attribute EventHandler onerror; - attribute EventHandler onoffline; - attribute EventHandler ononline; + getter Plugin? item(unsigned long index); + getter Plugin? namedItem(DOMString name); }; -WorkerGlobalScope implements WorkerUtils; -interface DedicatedWorkerGlobalScope : WorkerGlobalScope { - void postMessage(any message, optional sequence transfer); - attribute EventHandler onmessage; +interface MimeTypeArray { + readonly attribute unsigned long length; + getter MimeType? item(unsigned long index); + getter MimeType? namedItem(DOMString name); }; -interface SharedWorkerGlobalScope : WorkerGlobalScope { +interface Plugin { readonly attribute DOMString name; - readonly attribute ApplicationCache applicationCache; - attribute EventHandler onconnect; -}; - -[Constructor(DOMString type, optional ErrorEventInit eventInitDict)] -interface ErrorEvent : Event { - readonly attribute DOMString message; + readonly attribute DOMString description; readonly attribute DOMString filename; - readonly attribute unsigned long lineno; - readonly attribute unsigned long column; -}; - -dictionary ErrorEventInit : EventInit { - DOMString message; - DOMString filename; - unsigned long lineno; - unsigned long column; + readonly attribute unsigned long length; + getter MimeType? item(unsigned long index); + getter MimeType? namedItem(DOMString name); }; -[NoInterfaceObject] -interface AbstractWorker { - attribute EventHandler onerror; - +interface MimeType { + readonly attribute DOMString type; + readonly attribute DOMString description; + readonly attribute DOMString suffixes; // comma-separated + readonly attribute Plugin enabledPlugin; }; -[Constructor(DOMString scriptURL)] -interface Worker : EventTarget { - void terminate(); - - void postMessage(any message, optional sequence transfer); - attribute EventHandler onmessage; -}; -Worker implements AbstractWorker; - -[Constructor(DOMString scriptURL, optional DOMString name)] -interface SharedWorker : EventTarget { - readonly attribute MessagePort port; +interface External { + void AddSearchProvider(DOMString engineURL); + unsigned long IsSearchProviderInstalled(DOMString engineURL); }; -SharedWorker implements AbstractWorker; -[NoInterfaceObject] -interface WorkerUtils { - void importScripts(DOMString... urls); - readonly attribute WorkerNavigator navigator; +[Exposed=(Window,Worker)] +interface ImageBitmap { + readonly attribute unsigned long width; + readonly attribute unsigned long height; }; -WorkerUtils implements WindowTimers; -WorkerUtils implements WindowBase64; -interface WorkerNavigator {}; -WorkerNavigator implements NavigatorID; -WorkerNavigator implements NavigatorOnLine; +typedef (HTMLImageElement or + HTMLVideoElement or + HTMLCanvasElement or + Blob or + ImageData or + CanvasRenderingContext2D or + ImageBitmap) ImageBitmapSource; -interface WorkerLocation { - // URL decomposition IDL attributes - stringifier readonly attribute DOMString href; - readonly attribute DOMString protocol; - readonly attribute DOMString host; - readonly attribute DOMString hostname; - readonly attribute DOMString port; - readonly attribute DOMString pathname; - readonly attribute DOMString search; - readonly attribute DOMString hash; +[NoInterfaceObject, Exposed=(Window,Worker)] +interface ImageBitmapFactories { + Promise createImageBitmap(ImageBitmapSource image); + Promise createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh); }; +Window implements ImageBitmapFactories; +WorkerGlobalScope implements ImageBitmapFactories; -[Constructor(DOMString type, optional MessageEventInit eventInitDict)] +[Constructor(DOMString type, optional MessageEventInit eventInitDict), Exposed=(Window,Worker)] interface MessageEvent : Event { readonly attribute any data; readonly attribute DOMString origin; readonly attribute DOMString lastEventId; readonly attribute (WindowProxy or MessagePort)? source; readonly attribute MessagePort[]? ports; + + void initMessageEvent(DOMString typeArg, boolean canBubbleArg, boolean cancelableArg, any dataArg, DOMString originArg, DOMString lastEventIdArg, (WindowProxy or MessagePort) sourceArg, sequence? portsArg); }; dictionary MessageEventInit : EventInit { any data; DOMString origin; DOMString lastEventId; - WindowProxy? source; - MessagePort[]? ports; + (WindowProxy or MessagePort)? source; + sequence ports; }; -[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict)] +[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict), Exposed=(Window,Worker)] interface EventSource : EventTarget { readonly attribute DOMString url; readonly attribute boolean withCredentials; @@ -1783,9 +1823,9 @@ interface EventSource : EventTarget { readonly attribute unsigned short readyState; // networking - attribute EventHandler onopen; - attribute EventHandler onmessage; - attribute EventHandler onerror; + attribute EventHandler onopen; + attribute EventHandler onmessage; + attribute EventHandler onerror; void close(); }; @@ -1794,7 +1834,7 @@ dictionary EventSourceInit { }; enum BinaryType { "blob", "arraybuffer" }; -[Constructor(DOMString url, optional (DOMString or DOMString[]) protocols)] +[Constructor(DOMString url, optional (DOMString or DOMString[]) protocols), Exposed=(Window,Worker)] interface WebSocket : EventTarget { readonly attribute DOMString url; @@ -1807,23 +1847,23 @@ interface WebSocket : EventTarget { readonly attribute unsigned long bufferedAmount; // networking - attribute EventHandler onopen; - attribute EventHandler onerror; - attribute EventHandler onclose; + attribute EventHandler onopen; + attribute EventHandler onerror; + attribute EventHandler onclose; readonly attribute DOMString extensions; readonly attribute DOMString protocol; - void close([Clamp] optional unsigned short code, optional DOMString reason); + void close([Clamp] optional unsigned short code, optional USVString reason); // messaging - attribute EventHandler onmessage; - attribute BinaryType binaryType; - void send(DOMString data); + attribute EventHandler onmessage; + attribute BinaryType binaryType; + void send(USVString data); void send(Blob data); void send(ArrayBuffer data); void send(ArrayBufferView data); }; -[Constructor(DOMString type, optional CloseEventInit eventInitDict)] +[Constructor(DOMString type, optional CloseEventInit eventInitDict), Exposed=(Window,Worker)] interface CloseEvent : Event { readonly attribute boolean wasClean; readonly attribute unsigned short code; @@ -1836,26 +1876,110 @@ dictionary CloseEventInit : EventInit { DOMString reason; }; -[Constructor] +[Constructor, Exposed=(Window,Worker)] interface MessageChannel { readonly attribute MessagePort port1; readonly attribute MessagePort port2; }; +[Exposed=(Window,Worker)] interface MessagePort : EventTarget { void postMessage(any message, optional sequence transfer); void start(); void close(); // event handlers - attribute EventHandler onmessage; + attribute EventHandler onmessage; +}; +// MessagePort implements Transferable; + +[Constructor, Exposed=(Window,Worker)] +interface PortCollection { + void add(MessagePort port); + void remove(MessagePort port); + void clear(); + void iterate(PortCollectionCallback callback); +}; + +callback PortCollectionCallback = void (MessagePort port); + +[Constructor(DOMString channel), Exposed=(Window,Worker)] +interface BroadcastChannel : EventTarget { + readonly attribute DOMString name; + void postMessage(any message); + void close(); + attribute EventHandler onmessage; +}; + +[Exposed=Worker] +interface WorkerGlobalScope : EventTarget { + readonly attribute WorkerGlobalScope self; + readonly attribute WorkerLocation location; + + void close(); + attribute OnErrorEventHandler onerror; + attribute EventHandler onlanguagechange; + attribute EventHandler onoffline; + attribute EventHandler ononline; + + // also has additional members in a partial interface +}; + +[Global=(Worker,DedicatedWorker),Exposed=DedicatedWorker] +/*sealed*/ interface DedicatedWorkerGlobalScope : WorkerGlobalScope { + void postMessage(any message, optional sequence transfer); + attribute EventHandler onmessage; +}; + +[Global=(Worker,SharedWorker),Exposed=SharedWorker] +/*sealed*/ interface SharedWorkerGlobalScope : WorkerGlobalScope { + readonly attribute DOMString name; + readonly attribute ApplicationCache applicationCache; + attribute EventHandler onconnect; }; -MessagePort implements Transferable; + +[NoInterfaceObject, Exposed=(Window,Worker)] +interface AbstractWorker { + attribute EventHandler onerror; +}; + +[Constructor(DOMString scriptURL), Exposed=(Window,Worker)] +interface Worker : EventTarget { + void terminate(); + + void postMessage(any message, optional sequence transfer); + attribute EventHandler onmessage; +}; +Worker implements AbstractWorker; + +[Constructor(DOMString scriptURL, optional DOMString name), Exposed=(Window,Worker)] +interface SharedWorker : EventTarget { + readonly attribute MessagePort port; +}; +SharedWorker implements AbstractWorker; + +[Exposed=Worker] +partial interface WorkerGlobalScope { // not obsolete + void importScripts(DOMString... urls); + readonly attribute WorkerNavigator navigator; +}; +WorkerGlobalScope implements WindowTimers; +WorkerGlobalScope implements WindowBase64; + +[Exposed=Worker] +interface WorkerNavigator {}; +WorkerNavigator implements NavigatorID; +WorkerNavigator implements NavigatorLanguage; +WorkerNavigator implements NavigatorOnLine; + +[Exposed=Worker] +interface WorkerLocation { }; +WorkerLocation implements URLUtilsReadOnly; interface Storage { readonly attribute unsigned long length; DOMString? key(unsigned long index); - getter DOMString getItem(DOMString key); + getter DOMString? getItem(DOMString key); setter creator void setItem(DOMString key, DOMString value); deleter void removeItem(DOMString key); void clear(); @@ -1891,70 +2015,53 @@ dictionary StorageEventInit : EventInit { }; interface HTMLAppletElement : HTMLElement { - attribute DOMString align; - attribute DOMString alt; - attribute DOMString archive; - attribute DOMString code; - attribute DOMString codeBase; - attribute DOMString height; - attribute unsigned long hspace; - attribute DOMString name; - attribute DOMString _object; // the underscore is not part of the identifier - attribute unsigned long vspace; - attribute DOMString width; + attribute DOMString align; + attribute DOMString alt; + attribute DOMString archive; + attribute DOMString code; + attribute DOMString codeBase; + attribute DOMString height; + attribute unsigned long hspace; + attribute DOMString name; + attribute DOMString _object; // the underscore is not part of the identifier + attribute unsigned long vspace; + attribute DOMString width; }; interface HTMLMarqueeElement : HTMLElement { - attribute DOMString behavior; - attribute DOMString bgColor; - attribute DOMString direction; - attribute DOMString height; - attribute unsigned long hspace; - attribute long loop; - attribute unsigned long scrollAmount; - attribute unsigned long scrollDelay; - attribute boolean trueSpeed; - attribute unsigned long vspace; - attribute DOMString width; - - attribute EventHandler onbounce; - attribute EventHandler onfinish; - attribute EventHandler onstart; + attribute DOMString behavior; + attribute DOMString bgColor; + attribute DOMString direction; + attribute DOMString height; + attribute unsigned long hspace; + attribute long loop; + attribute unsigned long scrollAmount; + attribute unsigned long scrollDelay; + attribute boolean trueSpeed; + attribute unsigned long vspace; + attribute DOMString width; + + attribute EventHandler onbounce; + attribute EventHandler onfinish; + attribute EventHandler onstart; void start(); void stop(); }; interface HTMLFrameSetElement : HTMLElement { - attribute DOMString cols; - attribute DOMString rows; - attribute EventHandler onafterprint; - attribute EventHandler onbeforeprint; - attribute EventHandler onbeforeunload; - attribute EventHandler onblur; - attribute EventHandler onerror; - attribute EventHandler onfocus; - attribute EventHandler onhashchange; - attribute EventHandler onload; - attribute EventHandler onmessage; - attribute EventHandler onoffline; - attribute EventHandler ononline; - attribute EventHandler onpagehide; - attribute EventHandler onpageshow; - attribute EventHandler onpopstate; - attribute EventHandler onresize; - attribute EventHandler onscroll; - attribute EventHandler onstorage; - attribute EventHandler onunload; + attribute DOMString cols; + attribute DOMString rows; }; +HTMLFrameSetElement implements WindowEventHandlers; interface HTMLFrameElement : HTMLElement { - attribute DOMString name; - attribute DOMString scrolling; - attribute DOMString src; - attribute DOMString frameBorder; - attribute DOMString longDesc; - attribute boolean noResize; + attribute DOMString name; + attribute DOMString scrolling; + attribute DOMString src; + attribute DOMString frameBorder; + attribute DOMString longDesc; + attribute boolean noResize; readonly attribute Document? contentDocument; readonly attribute WindowProxy? contentWindow; @@ -1963,22 +2070,15 @@ interface HTMLFrameElement : HTMLElement { }; partial interface HTMLAnchorElement { - attribute DOMString coords; - attribute DOMString charset; - attribute DOMString name; - attribute DOMString rev; - attribute DOMString shape; + attribute DOMString coords; + attribute DOMString charset; + attribute DOMString name; + attribute DOMString rev; + attribute DOMString shape; }; partial interface HTMLAreaElement { - attribute boolean noHref; -}; - -interface HTMLBaseFontElement : HTMLElement { - attribute DOMString color; - attribute DOMString face; - attribute long size; - + attribute boolean noHref; }; partial interface HTMLBodyElement { @@ -1987,155 +2087,155 @@ partial interface HTMLBodyElement { [TreatNullAs=EmptyString] attribute DOMString vLink; [TreatNullAs=EmptyString] attribute DOMString aLink; [TreatNullAs=EmptyString] attribute DOMString bgColor; - attribute DOMString background; + attribute DOMString background; }; partial interface HTMLBRElement { - attribute DOMString clear; + attribute DOMString clear; }; partial interface HTMLTableCaptionElement { - attribute DOMString align; + attribute DOMString align; }; partial interface HTMLTableColElement { - attribute DOMString align; - attribute DOMString ch; - attribute DOMString chOff; - attribute DOMString vAlign; - attribute DOMString width; + attribute DOMString align; + attribute DOMString ch; + attribute DOMString chOff; + attribute DOMString vAlign; + attribute DOMString width; }; interface HTMLDirectoryElement : HTMLElement { - attribute boolean compact; + attribute boolean compact; }; partial interface HTMLDivElement { - attribute DOMString align; + attribute DOMString align; }; partial interface HTMLDListElement { - attribute boolean compact; + attribute boolean compact; }; partial interface HTMLEmbedElement { - attribute DOMString align; - attribute DOMString name; + attribute DOMString align; + attribute DOMString name; }; interface HTMLFontElement : HTMLElement { [TreatNullAs=EmptyString] attribute DOMString color; - attribute DOMString face; - attribute DOMString size; - + attribute DOMString face; + attribute DOMString size; }; partial interface HTMLHeadingElement { - attribute DOMString align; + attribute DOMString align; }; partial interface HTMLHRElement { - attribute DOMString align; - attribute DOMString color; - attribute boolean noShade; - attribute DOMString size; - attribute DOMString width; + attribute DOMString align; + attribute DOMString color; + attribute boolean noShade; + attribute DOMString size; + attribute DOMString width; }; partial interface HTMLHtmlElement { - attribute DOMString version; + attribute DOMString version; }; partial interface HTMLIFrameElement { - attribute DOMString align; - attribute DOMString scrolling; - attribute DOMString frameBorder; - attribute DOMString longDesc; + attribute DOMString align; + attribute DOMString scrolling; + attribute DOMString frameBorder; + attribute DOMString longDesc; [TreatNullAs=EmptyString] attribute DOMString marginHeight; [TreatNullAs=EmptyString] attribute DOMString marginWidth; }; partial interface HTMLImageElement { - attribute DOMString name; - attribute DOMString align; - attribute unsigned long hspace; - attribute unsigned long vspace; - attribute DOMString longDesc; + attribute DOMString name; + attribute DOMString lowsrc; + attribute DOMString align; + attribute unsigned long hspace; + attribute unsigned long vspace; + attribute DOMString longDesc; [TreatNullAs=EmptyString] attribute DOMString border; }; partial interface HTMLInputElement { - attribute DOMString align; - attribute DOMString useMap; + attribute DOMString align; + attribute DOMString useMap; }; partial interface HTMLLegendElement { - attribute DOMString align; + attribute DOMString align; }; partial interface HTMLLIElement { - attribute DOMString type; + attribute DOMString type; }; partial interface HTMLLinkElement { - attribute DOMString charset; - attribute DOMString rev; - attribute DOMString target; + attribute DOMString charset; + attribute DOMString rev; + attribute DOMString target; }; partial interface HTMLMenuElement { - attribute boolean compact; + attribute boolean compact; }; partial interface HTMLMetaElement { - attribute DOMString scheme; + attribute DOMString scheme; }; partial interface HTMLObjectElement { - attribute DOMString align; - attribute DOMString archive; - attribute DOMString code; - attribute boolean declare; - attribute unsigned long hspace; - attribute DOMString standby; - attribute unsigned long vspace; - attribute DOMString codeBase; - attribute DOMString codeType; + attribute DOMString align; + attribute DOMString archive; + attribute DOMString code; + attribute boolean declare; + attribute unsigned long hspace; + attribute DOMString standby; + attribute unsigned long vspace; + attribute DOMString codeBase; + attribute DOMString codeType; [TreatNullAs=EmptyString] attribute DOMString border; }; partial interface HTMLOListElement { - attribute boolean compact; + attribute boolean compact; }; partial interface HTMLParagraphElement { - attribute DOMString align; + attribute DOMString align; }; partial interface HTMLParamElement { - attribute DOMString type; - attribute DOMString valueType; + attribute DOMString type; + attribute DOMString valueType; }; partial interface HTMLPreElement { - attribute long width; + attribute long width; }; partial interface HTMLScriptElement { - attribute DOMString event; - attribute DOMString htmlFor; + attribute DOMString event; + attribute DOMString htmlFor; }; partial interface HTMLTableElement { - attribute DOMString align; - attribute DOMString border; - attribute DOMString frame; - attribute DOMString rules; - attribute DOMString summary; - attribute DOMString width; + attribute DOMString align; + attribute DOMString border; + attribute DOMString frame; + attribute DOMString rules; + attribute DOMString summary; + attribute DOMString width; [TreatNullAs=EmptyString] attribute DOMString bgColor; [TreatNullAs=EmptyString] attribute DOMString cellPadding; @@ -2143,39 +2243,42 @@ partial interface HTMLTableElement { }; partial interface HTMLTableSectionElement { - attribute DOMString align; - attribute DOMString ch; - attribute DOMString chOff; - attribute DOMString vAlign; + attribute DOMString align; + attribute DOMString ch; + attribute DOMString chOff; + attribute DOMString vAlign; }; partial interface HTMLTableCellElement { - attribute DOMString abbr; - attribute DOMString align; - attribute DOMString axis; - attribute DOMString height; - attribute DOMString width; + attribute DOMString align; + attribute DOMString axis; + attribute DOMString height; + attribute DOMString width; - attribute DOMString ch; - attribute DOMString chOff; - attribute boolean noWrap; - attribute DOMString vAlign; + attribute DOMString ch; + attribute DOMString chOff; + attribute boolean noWrap; + attribute DOMString vAlign; [TreatNullAs=EmptyString] attribute DOMString bgColor; }; +partial interface HTMLTableDataCellElement { + attribute DOMString abbr; +}; + partial interface HTMLTableRowElement { - attribute DOMString align; - attribute DOMString ch; - attribute DOMString chOff; - attribute DOMString vAlign; + attribute DOMString align; + attribute DOMString ch; + attribute DOMString chOff; + attribute DOMString vAlign; [TreatNullAs=EmptyString] attribute DOMString bgColor; }; partial interface HTMLUListElement { - attribute boolean compact; - attribute DOMString type; + attribute boolean compact; + attribute DOMString type; }; partial interface Document { @@ -2189,7 +2292,14 @@ partial interface Document { readonly attribute HTMLCollection applets; void clear(); + void captureEvents(); + void releaseEvents(); readonly attribute HTMLAllCollection all; }; +partial interface Window { + void captureEvents(); + void releaseEvents(); +}; + -- cgit v1.2.3 From 8bc392a91daf4cc1a27a8e6777af1a29ed24e3c4 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 22 Jul 2015 13:13:41 +0100 Subject: chnage binding AST to put methds inside class nodes --- src/nsgenbind-ast.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/nsgenbind-ast.h | 4 ++++ src/nsgenbind-parser.y | 47 ++++++++++++++++++++++++++++++++++++++--- src/nsgenbind.c | 20 +++++++++--------- 4 files changed, 115 insertions(+), 13 deletions(-) diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index 49477cf..1b5f53c 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -38,6 +38,63 @@ struct genbind_node { } r; }; +/* insert node(s) at beginning of a list */ +struct genbind_node * +genbind_node_prepend(struct genbind_node *list, struct genbind_node *inst) +{ + struct genbind_node *end = inst; + + if (inst == NULL) { + return list; /* no node to prepend - return existing list */ + } + + /* find end of inserted node list */ + while (end->l != NULL) { + end = end->l; + } + + end->l = list; + + return inst; +} + +/* prepend list to a nodes list + * + * inserts a list into the beginning of a nodes r list + * + * CAUTION: if the \a node element is not a node type the node will not be added + */ +struct genbind_node * +genbind_node_add(struct genbind_node *node, struct genbind_node *list) +{ + if (node == NULL) { + return list; + } + + /* this does not use genbind_node_getnode() as it cannot + * determine between an empty node and a node which is not a + * list type + */ + switch (node->type) { + case GENBIND_NODE_TYPE_BINDING: + case GENBIND_NODE_TYPE_CLASS: + case GENBIND_NODE_TYPE_PRIVATE: + case GENBIND_NODE_TYPE_INTERNAL: + case GENBIND_NODE_TYPE_PROPERTY: + case GENBIND_NODE_TYPE_FLAGS: + case GENBIND_NODE_TYPE_METHOD: + case GENBIND_NODE_TYPE_PARAMETER: + break; + + default: + /* not a node type */ + return list; + } + + node->r.node = genbind_node_prepend(node->r.node, list); + + return node; +} char *genbind_strapp(char *a, char *b) { diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index f6800fb..e7215b1 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -70,6 +70,10 @@ char *genbind_strapp(char *a, char *b); struct genbind_node *genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r); struct genbind_node *genbind_node_link(struct genbind_node *tgt, struct genbind_node *src); +struct genbind_node *genbind_node_prepend(struct genbind_node *list, struct genbind_node *inst); + +struct genbind_node *genbind_node_add(struct genbind_node *node, struct genbind_node *list); + /** * Dump the binding AST to file * diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index c8e5154..454fb56 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -128,7 +128,7 @@ Statements | Statements Statement { - $$ = genbind_node_link($2, $1); + $$ = *genbind_ast = genbind_node_prepend($2, $1); } | error ';' @@ -330,11 +330,52 @@ Method : MethodType MethodDeclarator CBlock { - $$ = genbind_new_node(GENBIND_NODE_TYPE_METHOD, NULL, + struct genbind_node *declarator; + struct genbind_node *method_node; + struct genbind_node *class_node; + char *class_name; + + declarator = $2; + + /* extract the class name from the declarator */ + class_name = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode( + genbind_node_find_type( + declarator, + NULL, + GENBIND_NODE_TYPE_CLASS)), + NULL, + GENBIND_NODE_TYPE_IDENT)); + + /* generate method node */ + method_node = genbind_new_node(GENBIND_NODE_TYPE_METHOD, NULL, genbind_new_node(GENBIND_NODE_TYPE_METHOD_TYPE, genbind_new_node(GENBIND_NODE_TYPE_CDATA, - $2, $3), + declarator, $3), (void *)$1)); + + + + class_node = genbind_node_find_type_ident(*genbind_ast, + NULL, + GENBIND_NODE_TYPE_CLASS, + class_name); + if (class_node == NULL) { + /* no existing class so manufacture one and attach method */ + $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + method_node, + class_name)); + + } else { + /* update the existing class */ + + /* link member node into class_node */ + genbind_node_add(class_node, method_node); + + $$ = NULL; /* updating so no need to add a new node */ + } } diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 3174fa0..8d83d13 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -20,6 +20,12 @@ struct options *options; +enum bindingtype_e { + BINDINGTYPE_UNKNOWN, + BINDINGTYPE_JSAPI_LIBDOM, + BINDINGTYPE_DUK_LIBDOM, +}; + static struct options* process_cmdline(int argc, char **argv) { int opt; @@ -98,12 +104,6 @@ static int generate_binding(struct genbind_node *binding_node, void *ctx) return res; } -enum bindingtype_e { - BINDINGTYPE_UNKNOWN, - BINDINGTYPE_JSAPI_LIBDOM, - BINDINGTYPE_DUK_LIBDOM, -}; - /** * get the type of binding */ @@ -146,7 +146,7 @@ static enum bindingtype_e genbind_get_type(struct genbind_node *node) int main(int argc, char **argv) { int res; - struct genbind_node *genbind_root; + struct genbind_node *genbind_root = NULL; enum bindingtype_e bindingtype; options = process_cmdline(argc, argv); @@ -154,17 +154,17 @@ int main(int argc, char **argv) return 1; /* bad commandline */ } - /* parse input and generate dependancy */ + /* parse binding */ res = genbind_parsefile(options->infilename, &genbind_root); if (res != 0) { fprintf(stderr, "Error: parse failed with code %d\n", res); return res; } - /* dump the AST */ + /* dump the binding AST */ genbind_dump_ast(genbind_root); - /* get bindingtype */ + /* get type of binding */ bindingtype = genbind_get_type(genbind_root); if (bindingtype == BINDINGTYPE_UNKNOWN) { return 3; -- cgit v1.2.3 From d36c21c4f53270f9ba8137bb1e84a7de45fea0f3 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 22 Jul 2015 22:12:05 +0100 Subject: Load the WebIDL files specified in the binding This loads the WebIDL specified in the bindings into an Abstract Syntax Tree (AST) and performs the mixin operations for implements. Additionally the specs now use a slightly extended IDL syntax. Instead of wholesale implementing the second edition of the IDL spec the parser has been updated to cope with iterator and Promise keywords as those are the only changes used in the dom and html specifications. A bug was also fixed in the lexer where negative int literals were not recognised. --- src/nsgenbind-ast.c | 33 ++++++++-------- src/nsgenbind.c | 57 ++++++++++++++++++++++++++- src/webidl-ast.c | 94 ++++++++++++++++++++++++++++++++++++++------- src/webidl-ast.h | 39 ++++++++++++++----- src/webidl-lexer.l | 7 +++- src/webidl-parser.y | 104 ++++++++++++++++++++++++++++++++++++++++++-------- test/data/idl/dom.idl | 8 ++-- 7 files changed, 283 insertions(+), 59 deletions(-) diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index 1b5f53c..c1acee1 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -20,6 +20,11 @@ #include "nsgenbind-ast.h" #include "options.h" +/** + * standard IO handle for parse trace logging. + */ +static FILE *genbind_parsetracef; + /* parser and lexer interface */ extern int nsgenbind_debug; extern int nsgenbind__flex_debug; @@ -448,23 +453,23 @@ static int genbind_ast_dump(FILE *dfile, struct genbind_node *node, int indent) /* exported interface documented in nsgenbind-ast.h */ int genbind_dump_ast(struct genbind_node *node) { - FILE *dumpf; + FILE *dumpf; - /* only dump AST to file if required */ - if (!options->debug) { - return 0; - } + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } - dumpf = genb_fopen("binding-ast", "w"); - if (dumpf == NULL) { - return 2; - } + dumpf = genb_fopen("binding-ast", "w"); + if (dumpf == NULL) { + return 2; + } - genbind_ast_dump(dumpf, node, 0); + genbind_ast_dump(dumpf, node, 0); - fclose(dumpf); + fclose(dumpf); - return 0; + return 0; } FILE *genbindopen(const char *filename) @@ -545,10 +550,6 @@ FILE *genbindopen(const char *filename) return genfile; } -/** - * standard IO handle for parse trace logging. - */ -static FILE *genbind_parsetracef; int genbind_parsefile(char *infilename, struct genbind_node **ast) { diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 8d83d13..914f58e 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -15,6 +15,7 @@ #include #include "nsgenbind-ast.h" +#include "webidl-ast.h" #include "jsapi-libdom.h" #include "options.h" @@ -104,6 +105,51 @@ static int generate_binding(struct genbind_node *binding_node, void *ctx) return res; } + +static int webidl_file_cb(struct genbind_node *node, void *ctx) +{ + struct webidl_node **webidl_ast = ctx; + char *filename; + + filename = genbind_node_gettext(node); + + if (options->verbose) { + printf("Opening IDL file \"%s\"\n", filename); + } + + return webidl_parsefile(filename, webidl_ast); +} + +static int genbind_load_idl(struct genbind_node *genbind, + struct webidl_node **webidl_out) +{ + int res; + struct genbind_node *binding_node; + + binding_node = genbind_node_find_type(genbind, NULL, + GENBIND_NODE_TYPE_BINDING); + + /* walk AST and load any web IDL files required */ + res = genbind_node_foreach_type( + genbind_node_getnode(binding_node), + GENBIND_NODE_TYPE_WEBIDL, + webidl_file_cb, + webidl_out); + if (res != 0) { + fprintf(stderr, "Error: failed reading Web IDL\n"); + return -1; + } + + /* implements are implemented as mixins so intercalate them */ + res = webidl_intercalate_implements(*webidl_out); + if (res != 0) { + fprintf(stderr, "Error: Failed to intercalate implements\n"); + return -1; + } + + return 0; +} + /** * get the type of binding */ @@ -147,6 +193,7 @@ int main(int argc, char **argv) { int res; struct genbind_node *genbind_root = NULL; + struct webidl_node *webidl_root = NULL; enum bindingtype_e bindingtype; options = process_cmdline(argc, argv); @@ -170,8 +217,16 @@ int main(int argc, char **argv) return 3; } + /* load the IDL files specified in the binding */ + res = genbind_load_idl(genbind_root, &webidl_root); + if (res != 0) { + return 4; + } + + /* debug dump of web idl AST */ + webidl_dump_ast(webidl_root); + #if 0 - genbind_load_idl(genbind_root); /* generate output for each binding */ res = genbind_node_foreach_type(genbind_root, diff --git a/src/webidl-ast.c b/src/webidl-ast.c index 945b5fa..6c24c41 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -11,10 +11,17 @@ #include #include #include +#include +#include "utils.h" #include "webidl-ast.h" #include "options.h" +/** + * standard IO handle for parse trace logging. + */ +static FILE *webidl_parsetracef; + extern int webidl_debug; extern int webidl__flex_debug; extern void webidl_restart(FILE*); @@ -386,13 +393,16 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) } - -/* exported interface defined in webidl-ast.h */ -int webidl_ast_dump(struct webidl_node *node, int indent) +/** + * Recursively dump the AST nodes increasing indent as appropriate + */ +static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent) { - const char *SPACES=" "; char *txt; + const char *SPACES=" "; + char *txt; while (node != NULL) { - printf("%.*s%s", indent, SPACES, webidl_node_type_to_str(node->type)); + fprintf(dumpf, "%.*s%s", indent, SPACES, + webidl_node_type_to_str(node->type)); txt = webidl_node_gettext(node); if (txt == NULL) { @@ -401,20 +411,43 @@ int webidl_ast_dump(struct webidl_node *node, int indent) next = webidl_node_getnode(node); if (next != NULL) { - printf("\n"); - webidl_ast_dump(next, indent + 2); + fprintf(dumpf, "\n"); + webidl_ast_dump(dumpf, next, indent + 2); } else { /* not txt or node has to be an int */ - printf(": %d\n", webidl_node_getint(node)); + fprintf(dumpf, ": %d\n", + webidl_node_getint(node)); } } else { - printf(": \"%s\"\n", txt); + fprintf(dumpf, ": \"%s\"\n", txt); } node = node->l; } return 0; } +/* exported interface documented in webidl-ast.h */ +int webidl_dump_ast(struct webidl_node *node) +{ + FILE *dumpf; + + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } + + dumpf = genb_fopen("webidl-ast", "w"); + if (dumpf == NULL) { + return 2; + } + + webidl_ast_dump(dumpf, node, 0); + + fclose(dumpf); + + return 0; +} + /* exported interface defined in webidl-ast.h */ static FILE *idlopen(const char *filename) { @@ -444,8 +477,8 @@ static FILE *idlopen(const char *filename) /* exported interface defined in webidl-ast.h */ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast) { - FILE *idlfile; + int ret; idlfile = idlopen(filename); if (!idlfile) { @@ -455,16 +488,51 @@ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast) return 2; } - if (options->debug) { + /* if debugging enabled enable parser tracing and send to file */ + if (options->debug) { + char *tracename; + int tracenamelen; webidl_debug = 1; webidl__flex_debug = 1; - } + + tracenamelen = SLEN("webidl--trace") + strlen(filename) + 1; + tracename = malloc(tracenamelen); + snprintf(tracename, tracenamelen,"webidl-%s-trace", filename); + webidl_parsetracef = genb_fopen(tracename, "w"); + free(tracename); + } else { + webidl_parsetracef = NULL; + } /* set flex to read from file */ webidl_restart(idlfile); /* parse the file */ - return webidl_parse(webidl_ast); + ret = webidl_parse(webidl_ast); + + /* close tracefile if open */ + if (webidl_parsetracef != NULL) { + fclose(webidl_parsetracef); + } + return ret; +} + +/* exported interface defined in webidl-ast.h */ +int webidl_fprintf(FILE *stream, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + + if (webidl_parsetracef == NULL) { + ret = vfprintf(stream, format, ap); + } else { + ret = vfprintf(webidl_parsetracef, format, ap); + } + va_end(ap); + + return ret; } /* unlink a child node from a parent */ diff --git a/src/webidl-ast.h b/src/webidl-ast.h index a494f4e..5d0cbc0 100644 --- a/src/webidl-ast.h +++ b/src/webidl-ast.h @@ -90,17 +90,25 @@ int webidl_node_getint(struct webidl_node *node); enum webidl_node_type webidl_node_gettype(struct webidl_node *node); /* node searches */ + +/** + * Iterate nodes children matching their type. + * + * For each child node where the type is matched the callback function is + * called with a context value. + */ int webidl_node_for_each_type(struct webidl_node *node, - enum webidl_node_type type, - webidl_callback_t *cb, + enum webidl_node_type type, + webidl_callback_t *cb, void *ctx); -int webidl_node_enumerate_type(struct webidl_node *node, enum webidl_node_type type); +int webidl_node_enumerate_type(struct webidl_node *node, + enum webidl_node_type type); struct webidl_node * webidl_node_find(struct webidl_node *node, - struct webidl_node *prev, - webidl_callback_t *cb, + struct webidl_node *prev, + webidl_callback_t *cb, void *ctx); struct webidl_node * @@ -114,13 +122,26 @@ webidl_node_find_type_ident(struct webidl_node *root_node, const char *ident); -/* debug dump */ -int webidl_ast_dump(struct webidl_node *node, int indent); -/** parse web idl file */ +/** + * parse web idl file into Abstract Syntax Tree + */ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast); -/** perform replacement of implements elements with copies of ast data */ +/** + * dump AST to file + */ +int webidl_dump_ast(struct webidl_node *node); + +/** + * perform replacement of implements elements with copies of ast data + */ int webidl_intercalate_implements(struct webidl_node *node); +/** + * formatted printf to allow webidl trace data to be written to file. + */ +int webidl_fprintf(FILE *stream, const char *format, ...); + + #endif diff --git a/src/webidl-lexer.l b/src/webidl-lexer.l index 74b9bb8..e49b813 100644 --- a/src/webidl-lexer.l +++ b/src/webidl-lexer.l @@ -86,7 +86,7 @@ lineend ([\n\r]|{LS}|{PS}) hexdigit [0-9A-Fa-f] hexint 0(x|X){hexdigit}+ -decimalint 0|([1-9][0-9]*) +decimalint 0|([\+\-]?[1-9][0-9]*) octalint (0[0-8]+) @@ -207,6 +207,11 @@ void return TOK_VOID; readonly return TOK_READONLY; +Promise return TOK_PROMISE; + +iterable return TOK_ITERABLE; + +legacyiterable return TOK_LEGACYITERABLE; {identifier} { /* A leading "_" is used to escape an identifier from diff --git a/src/webidl-parser.y b/src/webidl-parser.y index 9324212..9717b8c 100644 --- a/src/webidl-parser.y +++ b/src/webidl-parser.y @@ -9,6 +9,9 @@ * * Derived from the the grammar in apendix A of W3C WEB IDL * http://www.w3.org/TR/WebIDL/ + * + * WebIDL now has a second edition draft (mid 2015) that the dom and + * html specs are using. https://heycam.github.io/webidl */ #include @@ -17,11 +20,17 @@ #include #include -#include "webidl-ast.h" +#define YYFPRINTF webidl_fprintf +#define YY_LOCATION_PRINT(File, Loc) \ + webidl_fprintf(File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) #include "webidl-parser.h" #include "webidl-lexer.h" +#include "webidl-ast.h" + char *errtxt; static void @@ -77,6 +86,8 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %token TOK_INFINITY %token TOK_INHERIT %token TOK_INTERFACE +%token TOK_ITERABLE +%token TOK_LEGACYITERABLE %token TOK_LONG %token TOK_MODULE %token TOK_NAN @@ -88,6 +99,7 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %token TOK_OPTIONAL %token TOK_OR %token TOK_PARTIAL +%token TOK_PROMISE %token TOK_RAISES %token TOK_READONLY %token TOK_SETRAISES @@ -105,12 +117,12 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %token TOK_POUND_SIGN -%token TOK_IDENTIFIER -%token TOK_INT_LITERAL -%token TOK_FLOAT_LITERAL -%token TOK_STRING_LITERAL -%token TOK_OTHER_LITERAL -%token TOK_JAVADOC +%token TOK_IDENTIFIER +%token TOK_INT_LITERAL +%token TOK_FLOAT_LITERAL +%token TOK_STRING_LITERAL +%token TOK_OTHER_LITERAL +%token TOK_JAVADOC %type Inheritance @@ -153,6 +165,8 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %type ArgumentName %type ArgumentNameKeyword %type Ellipsis +%type Iterable +%type OptionalType %type Type %type ReturnType @@ -165,6 +179,7 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %type FloatType %type UnsignedIntegerType %type IntegerType +%type PromiseType %type TypeSuffix %type TypeSuffixStartingWithArray @@ -356,7 +371,7 @@ InterfaceMembers: if (ident_node == NULL) { /* something with no ident - possibly constructors? */ - /* @todo understand this abtter */ + /* @todo understand this better */ $$ = webidl_node_prepend($1, $3); @@ -389,11 +404,17 @@ InterfaceMembers: } ; - /* [10] */ + /* [10] + * SE[10] + * Second edition actually splits up AttributeOrOperation completely + * here we "just" add Iterable as thats what the specs use + */ InterfaceMember: Const | AttributeOrOperation + | + Iterable ; /* [11] */ @@ -474,18 +495,28 @@ Enum: } ; -/* [21] */ + /* Second edition changes enumeration rules to allow trailing comma */ + + /* SE[20] */ EnumValueList: - TOK_STRING_LITERAL EnumValues + TOK_STRING_LITERAL EnumValueListComma ; -/* [22] */ -EnumValues: + /* SE[21] */ +EnumValueListComma: + ',' EnumValueListString + | /* empty */ + ; + + /* SE[22] */ +EnumValueListString: + TOK_STRING_LITERAL EnumValueListComma | - ',' TOK_STRING_LITERAL EnumValues + /* empty */ ; + /* [23] - bug in w3c grammar? it doesnt list the equals as a terminal */ CallbackRest: TOK_IDENTIFIER '=' ReturnType '(' ArgumentList ')' ';' @@ -835,6 +866,32 @@ Ellipsis: } ; + /* SE[59] */ +Iterable: + TOK_ITERABLE '<' Type OptionalType '>' ';' + { + $$ = NULL; + } + | + TOK_LEGACYITERABLE '<' Type '>' ';' + { + $$ = NULL; + } + ; + + /* SE[60] */ +OptionalType: + /* empty */ + { + $$ = NULL; + } + | + ',' Type + { + $$ = NULL; + } + ; + /* [47] */ ExceptionMember: Const @@ -1301,13 +1358,22 @@ UnionMemberTypes: TOK_OR UnionMemberType UnionMemberTypes ; - /* [62] */ + /* [62] + * SE[78] + * Second edition adds several types + */ NonAnyType: PrimitiveType TypeSuffix { $$ = webidl_node_prepend($1, $2); } | + PromiseType TypeSuffix + { + /* second edition adds promise types */ + $$ = webidl_node_prepend($1, $2); + } + | TOK_STRING TypeSuffix { $$ = webidl_node_new(WEBIDL_NODE_TYPE_TYPE_BASE, $2, (void *)WEBIDL_TYPE_STRING); @@ -1442,6 +1508,14 @@ OptionalLong: } ; +/* SE[87] */ +PromiseType: + TOK_PROMISE '<' ReturnType '>' + { + $$ = NULL; + } + ; + /* [70] */ TypeSuffix: /* empty */ diff --git a/test/data/idl/dom.idl b/test/data/idl/dom.idl index 6a4a95e..1c9e75b 100644 --- a/test/data/idl/dom.idl +++ b/test/data/idl/dom.idl @@ -107,10 +107,10 @@ DocumentType implements ChildNode; Element implements ChildNode; CharacterData implements ChildNode; -class Elements extends Array { - Element? query(DOMString relativeSelectors); - Elements queryAll(DOMString relativeSelectors); -}; +//class Elements extends Array { +// Element? query(DOMString relativeSelectors); +// Elements queryAll(DOMString relativeSelectors); +//}; [Exposed=Window] interface NodeList { -- cgit v1.2.3 From 6406dae8c4da597da888345cf145f366b8297d7c Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 24 Jul 2015 00:01:51 +0100 Subject: Build interface map allowing for correct dependency generation This constructs an ordered list of all interfaces in their dependency order. The topological sort ordering is derived from the interfaces inheritance. The resulting table allows the generation phase to easily map interfaces to classes defined in the binding with a useful ordering. Additionally it was noticed that the uievent IDL was missing so that has now been added and allows for a much more complete graph of interfaces to be constructed. --- README | 24 +++ src/Makefile | 2 +- src/interface-map.c | 292 +++++++++++++++++++++++++++++++ src/interface-map.h | 43 +++++ src/jsapi-libdom-infmap.c | 348 ------------------------------------- src/nsgenbind-ast.h | 2 +- src/nsgenbind.c | 13 +- test/data/bindings/browser-duk.bnd | 1 + test/data/idl/uievents.idl | 185 ++++++++++++++++++++ 9 files changed, 559 insertions(+), 351 deletions(-) create mode 100644 src/interface-map.c create mode 100644 src/interface-map.h delete mode 100644 src/jsapi-libdom-infmap.c create mode 100644 test/data/idl/uievents.idl diff --git a/README b/README index e260642..039bd6a 100644 --- a/README +++ b/README @@ -37,6 +37,30 @@ The tool requires a binding file as input and an output directory in which to place its output. +Debug output +------------ + +as well as the generated source the tool will output seevral debugging +files with the -D switch in use. + +interface.dot + + The interfaces IDL dot file contains all the interfaces and their + relationship. graphviz can be used to convert this into a visual + representation which is sometimes useful to help in debugging + missing or incorrect IDL inheritance. + + Processing the dot file with graphviz can produce very large files + so care must be taken with options. Some examples that produce + adequate output: + + # classical tree + dot -O -Tsvg interface.dot + + # radial output + twopi -Granksep=10.0 -Gnodesep=1.0 -Groot=0009 -O -Tsvg interface.dot + + Web IDL ------- diff --git a/src/Makefile b/src/Makefile index 3e5b8af..b7b142a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ 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 +DIR_SOURCES := nsgenbind.c utils.c webidl-ast.c nsgenbind-ast.c interface-map.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/interface-map.c b/src/interface-map.c new file mode 100644 index 0000000..aef697e --- /dev/null +++ b/src/interface-map.c @@ -0,0 +1,292 @@ +/* interface mapping + * + * This file is part of nsgenbind. + * Published under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2015 Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "utils.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "interface-map.h" + +/** count the number of nodes of a given type on an interface */ +static int +enumerate_interface_type(struct webidl_node *interface_node, + enum webidl_node_type node_type) +{ + int count = 0; + struct webidl_node *members_node; + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_LIST); + while (members_node != NULL) { + count += webidl_node_enumerate_type( + webidl_node_getnode(members_node), + node_type); + + members_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + members_node, + WEBIDL_NODE_TYPE_LIST); + } + + return count; +} + +/* find index of inherited node if it is one of those listed in the + * binding also maintain refcounts + */ +static void +compute_inherit_refcount(struct interface_map_entry *entries, int entryc) +{ + int idx; + int inf; + + for (idx = 0; idx < entryc; idx++ ) { + entries[idx].inherit_idx = -1; + for (inf = 0; inf < entryc; inf++ ) { + /* cannot inherit from self and name must match */ + if ((inf != idx) && + (entries[idx].inherit_name != NULL ) && + (strcmp(entries[idx].inherit_name, + entries[inf].name) == 0)) { + entries[idx].inherit_idx = inf; + entries[inf].refcount++; + break; + } + } + } +} + +/** Topoligical sort based on the refcount + * + * do not need to consider loops as constructed graph is a acyclic + * + * alloc a second copy of the map + * repeat until all entries copied: + * walk source mapping until first entry with zero refcount + * put the entry at the end of the output map + * reduce refcount on inherit index if !=-1 + * remove entry from source map + */ +static struct interface_map_entry * +interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) +{ + struct interface_map_entry *dstinf; + int idx; + int inf; + + dstinf = calloc(infc, sizeof(struct interface_map_entry)); + if (dstinf == NULL) { + return NULL; + } + + for (idx = infc - 1; idx >= 0; idx--) { + /* walk source map until first valid entry with zero refcount */ + inf = 0; + while ((inf < infc) && + ((srcinf[inf].name == NULL) || + (srcinf[inf].refcount > 0))) { + inf++; + } + if (inf == infc) { + free(dstinf); + return NULL; + } + + /* copy entry to the end of the output map */ + dstinf[idx].name = srcinf[inf].name; + dstinf[idx].node = srcinf[inf].node; + dstinf[idx].inherit_name = srcinf[inf].inherit_name; + dstinf[idx].operations = srcinf[inf].operations; + dstinf[idx].attributes = srcinf[inf].attributes; + dstinf[idx].class = srcinf[inf].class; + + /* reduce refcount on inherit index if !=-1 */ + if (srcinf[inf].inherit_idx != -1) { + srcinf[srcinf[inf].inherit_idx].refcount--; + } + + /* remove entry from source map */ + srcinf[inf].name = NULL; + } + + return dstinf; +} + +int interface_map_new(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map **index_out) +{ + int interfacec; + struct interface_map_entry *entries; + struct interface_map_entry *sorted_entries; + struct interface_map_entry *ecur; + struct webidl_node *node; + struct interface_map *index; + + interfacec = webidl_node_enumerate_type(webidl, + WEBIDL_NODE_TYPE_INTERFACE); + + if (options->verbose) { + printf("Indexing %d interfaces\n", interfacec); + } + + entries = calloc(interfacec, sizeof(struct interface_map_entry)); + if (entries == NULL) { + return -1; + } + + /* for each interface populate an entry in the index */ + ecur = entries; + node = webidl_node_find_type(webidl, NULL, WEBIDL_NODE_TYPE_INTERFACE); + while (node != NULL) { + + /* fill index entry */ + ecur->node = node; + + /* name of interface */ + ecur->name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(node), + NULL, + GENBIND_NODE_TYPE_IDENT)); + + /* name of the inherited interface (if any) */ + ecur->inherit_name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); + + + /* enumerate the number of operations */ + ecur->operations = enumerate_interface_type(node, + WEBIDL_NODE_TYPE_OPERATION); + + /* enumerate the number of attributes */ + ecur->attributes = enumerate_interface_type(node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + + /* matching class from binding */ + ecur->class = genbind_node_find_type_ident(genbind, + NULL, GENBIND_NODE_TYPE_CLASS, ecur->name); + + /* move to next interface */ + node = webidl_node_find_type(webidl, node, + WEBIDL_NODE_TYPE_INTERFACE); + ecur++; + } + + /* compute inheritance and refcounts on map */ + compute_inherit_refcount(entries, interfacec); + + /* sort interfaces to ensure correct ordering */ + sorted_entries = interface_topoligical_sort(entries, interfacec); + free(entries); + if (sorted_entries == NULL) { + return -1; + } + + /* compute inheritance and refcounts on sorted map */ + compute_inherit_refcount(sorted_entries, interfacec); + + index = malloc(sizeof(struct interface_map)); + index->entryc = interfacec; + index->entries = sorted_entries; + + *index_out = index; + + return 0; +} + +int interface_map_dump(struct interface_map *index) +{ + FILE *dumpf; + int eidx; + struct interface_map_entry *ecur; + const char *inherit_name; + + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } + + dumpf = genb_fopen("interface-index", "w"); + if (dumpf == NULL) { + return 2; + } + + ecur = index->entries; + for (eidx = 0; eidx < index->entryc; eidx++) { + inherit_name = ecur->inherit_name; + if (inherit_name == NULL) { + inherit_name = ""; + } + fprintf(dumpf, "%d %s %s i:%d a:%d %p\n", eidx, ecur->name, + inherit_name, ecur->operations, ecur->attributes, + ecur->class); + ecur++; + } + + fclose(dumpf); + + return 0; +} + +int interface_map_dumpdot(struct interface_map *index) +{ + FILE *dumpf; + int eidx; + struct interface_map_entry *ecur; + + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } + + dumpf = genb_fopen("interface.dot", "w"); + if (dumpf == NULL) { + return 2; + } + + fprintf(dumpf, "digraph interfaces {\n"); + + ecur = index->entries; + for (eidx = 0; eidx < index->entryc; eidx++) { + if (ecur->class != NULL) { + /* interfaces bound to a class are shown in blue */ + fprintf(dumpf, "%04d [label=\"%s\" fontcolor=\"blue\"];\n", eidx, ecur->name); + } else { + fprintf(dumpf, "%04d [label=\"%s\"];\n", eidx, ecur->name); + } + ecur++; + } + + ecur = index->entries; + for (eidx = 0; eidx < index->entryc; eidx++) { + if (index->entries[eidx].inherit_idx != -1) { + fprintf(dumpf, "%04d -> %04d;\n", + eidx, index->entries[eidx].inherit_idx); + } + } + + fprintf(dumpf, "}\n"); + + fclose(dumpf); + + return 0; +} diff --git a/src/interface-map.h b/src/interface-map.h new file mode 100644 index 0000000..c9dd654 --- /dev/null +++ b/src/interface-map.h @@ -0,0 +1,43 @@ +/* Interface mapping + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2012 Vincent Sanders + */ + +#ifndef nsgenbind_interface_map_h +#define nsgenbind_interface_map_h + +struct genbind_node; +struct webidl_node; + +struct interface_map_entry { + const char *name; /** interface name */ + struct webidl_node *node; /**< AST interface node */ + const char *inherit_name; /**< Name of interface inhertited from */ + int operations; /**< number of operations on interface */ + int attributes; /**< number of attributes on interface */ + int inherit_idx; /**< index into map of inherited interface or -1 for + * not in map + */ + int refcount; /**< number of interfacess in map that refer to this + * interface + */ + struct genbind_node *class; /**< class from binding (if any) */ +}; + +struct interface_map { + int entryc; /**< count of interfaces */ + struct interface_map_entry *entries; +}; + +int interface_map_new(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map **index_out); + +int interface_map_dump(struct interface_map *index); + +int interface_map_dumpdot(struct interface_map *index); + +#endif diff --git a/src/jsapi-libdom-infmap.c b/src/jsapi-libdom-infmap.c deleted file mode 100644 index 09fce1e..0000000 --- a/src/jsapi-libdom-infmap.c +++ /dev/null @@ -1,348 +0,0 @@ -/* interface map builder - * - * This file is part of nsgenbind. - * Published under the MIT License, - * http://www.opensource.org/licenses/mit-license.php - * Copyright 2014 Vincent Sanders - */ - -#include -#include -#include -#include -#include -#include - -#include "options.h" -#include "nsgenbind-ast.h" -#include "webidl-ast.h" -#include "jsapi-libdom.h" - -/** count the number of methods or properties for an interface */ -static int -enumerate_interface_own(struct webidl_node *interface_node, - enum webidl_node_type node_type) -{ - int count = 0; - struct webidl_node *members_node; - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - NULL, - WEBIDL_NODE_TYPE_LIST); - while (members_node != NULL) { - count += webidl_node_enumerate_type( - webidl_node_getnode(members_node), - node_type); - - members_node = webidl_node_find_type( - webidl_node_getnode(interface_node), - members_node, - WEBIDL_NODE_TYPE_LIST); - } - - return count; -} - -static int -fill_binding_interface(struct webidl_node *webidl_ast, - struct binding_interface *interface) -{ - /* get web IDL node for interface */ - interface->widl_node = webidl_node_find_type_ident( - webidl_ast, - WEBIDL_NODE_TYPE_INTERFACE, - interface->name); - if (interface->widl_node == NULL) { - return -1; - } - - /* enumerate the number of functions */ - interface->own_functions = enumerate_interface_own( - interface->widl_node, - WEBIDL_NODE_TYPE_OPERATION); - - /* enumerate the number of properties */ - interface->own_properties = enumerate_interface_own( - interface->widl_node, - WEBIDL_NODE_TYPE_ATTRIBUTE); - - /* extract the name of the inherited interface (if any) */ - interface->inherit_name = webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(interface->widl_node), - NULL, - WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); - - return 0; -} - -/* find index of inherited node if it is one of those listed in the - * binding also maintain refcounts - */ -static void -compute_inherit_refcount(struct binding_interface *interfaces, - int interfacec) -{ - int idx; - int inf; - - for (idx = 0; idx < interfacec; idx++ ) { - interfaces[idx].inherit_idx = -1; - for (inf = 0; inf < interfacec; inf++ ) { - /* cannot inherit from self and name must match */ - if ((inf != idx) && - (interfaces[idx].inherit_name != NULL ) && - (strcmp(interfaces[idx].inherit_name, - interfaces[inf].name) == 0)) { - interfaces[idx].inherit_idx = inf; - interfaces[inf].refcount++; - break; - } - } - } -} - -/** Topoligical sort based on the refcount - * - * do not need to consider loops as constructed graph is a acyclic - * - * alloc a second copy of the map - * repeat until all entries copied: - * walk source mapping until first entry with zero refcount - * put the entry at the end of the output map - * reduce refcount on inherit index if !=-1 - * remove entry from source map - */ -static struct binding_interface * -interface_topoligical_sort(struct binding_interface *srcinf, int infc) -{ - struct binding_interface *dstinf; - int idx; - int inf; - - dstinf = calloc(infc, sizeof(struct binding_interface)); - if (dstinf == NULL) { - return NULL; - } - - for (idx = infc - 1; idx >= 0; idx--) { - /* walk source map until first valid entry with zero refcount */ - inf = 0; - while ((inf < infc) && - ((srcinf[inf].name == NULL) || - (srcinf[inf].refcount > 0))) { - inf++; - } - if (inf == infc) { - free(dstinf); - return NULL; - } - - /* copy entry to the end of the output map */ - dstinf[idx].name = srcinf[inf].name; - dstinf[idx].node = srcinf[inf].node; - dstinf[idx].widl_node = srcinf[inf].widl_node; - dstinf[idx].inherit_name = srcinf[inf].inherit_name; - dstinf[idx].own_properties = srcinf[inf].own_properties; - dstinf[idx].own_functions = srcinf[inf].own_functions; - - /* reduce refcount on inherit index if !=-1 */ - if (srcinf[inf].inherit_idx != -1) { - srcinf[srcinf[inf].inherit_idx].refcount--; - } - - /* remove entry from source map */ - srcinf[inf].name = NULL; - } - - return dstinf; -} - -/* exported interface documented in jsapi-libdom.h */ -int build_interface_map(struct genbind_node *binding_node, - struct webidl_node *webidl_ast, - int *interfacec_out, - struct binding_interface **interfaces_out) -{ - int interfacec; - int inf; /* interface loop counter */ - int idx; /* map index counter */ - struct binding_interface *interfaces; - struct genbind_node *node = NULL; - struct binding_interface *reinterfaces; - - /* count number of interfaces listed in binding */ - interfacec = genbind_node_enumerate_type( - genbind_node_getnode(binding_node), - GENBIND_NODE_TYPE_BINDING_INTERFACE); - - if (interfacec == 0) { - return -1; - } - if (options->verbose) { - printf("Binding has %d interfaces\n", interfacec); - } - - interfaces = calloc(interfacec, sizeof(struct binding_interface)); - if (interfaces == NULL) { - return -1; - } - - /* fill in map with binding node data */ - idx = 0; - node = genbind_node_find_type(genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); - while (node != NULL) { - - /* binding node */ - interfaces[idx].node = node; - - /* get interface name */ - interfaces[idx].name = genbind_node_gettext( - genbind_node_find_type(genbind_node_getnode(node), - NULL, - GENBIND_NODE_TYPE_IDENT)); - if (interfaces[idx].name == NULL) { - free(interfaces); - return -1; - } - - /* get interface info from webidl */ - if (fill_binding_interface(webidl_ast, interfaces + idx) == -1) { - free(interfaces); - return -1; - } - - interfaces[idx].refcount = 0; - - /* ensure it is not a duplicate */ - for (inf = 0; inf < idx; inf++) { - if (strcmp(interfaces[inf].name, interfaces[idx].name) == 0) { - break; - } - } - if (inf != idx) { - WARN(WARNING_DUPLICATED, - "interface %s duplicated in binding", - interfaces[idx].name); - } else { - idx++; - } - - /* next node */ - node = genbind_node_find_type( - genbind_node_getnode(binding_node), - node, - GENBIND_NODE_TYPE_BINDING_INTERFACE); - } - - /* update count which may have changed if there were duplicates */ - interfacec = idx; - - /* compute inheritance and refcounts on map */ - compute_inherit_refcount(interfaces, interfacec); - - /* the map must be augmented with all the interfaces not in - * the binding but in the dependancy chain - */ - for (idx = 0; idx < interfacec; idx++ ) { - if ((interfaces[idx].inherit_idx == -1) && - (interfaces[idx].inherit_name != NULL)) { - /* interface inherits but not currently in map */ - - /* grow map */ - reinterfaces = realloc(interfaces, - (interfacec + 1) * sizeof(struct binding_interface)); - if (reinterfaces == NULL) { - fprintf(stderr,"Unable to grow interface map\n"); - free(interfaces); - return -1; - } - interfaces = reinterfaces; - - /* setup all fields in new interface */ - - /* this interface is not in the binding and - * will not be exported - */ - interfaces[interfacec].node = NULL; - - interfaces[interfacec].name = interfaces[idx].inherit_name; - - if (fill_binding_interface(webidl_ast, - interfaces + interfacec) == -1) { - fprintf(stderr, - "Interface %s inherits from %s which is not in the WebIDL\n", - interfaces[idx].name, - interfaces[idx].inherit_name); - free(interfaces); - return -1; - } - - interfaces[interfacec].inherit_idx = -1; - interfaces[interfacec].refcount = 0; - - /* update dependancy info and refcount */ - for (inf = 0; inf < interfacec; inf++) { - if (strcmp(interfaces[inf].inherit_name, - interfaces[interfacec].name) == 0) { - interfaces[inf].inherit_idx = interfacec; - interfaces[interfacec].refcount++; - } - } - - /* update interface count in map */ - interfacec++; - - } - } - - /* sort interfaces to ensure correct ordering */ - reinterfaces = interface_topoligical_sort(interfaces, interfacec); - free(interfaces); - if (reinterfaces == NULL) { - return -1; - } - interfaces = reinterfaces; - - /* compute inheritance and refcounts on sorted map */ - compute_inherit_refcount(interfaces, interfacec); - - /* setup output index values */ - inf = 0; - for (idx = 0; idx < interfacec; idx++ ) { - if (interfaces[idx].node == NULL) { - interfaces[idx].output_idx = -1; - } else { - interfaces[idx].output_idx = inf; - inf++; - } - } - - /* show the interface map */ - if (options->verbose) { - for (idx = 0; idx < interfacec; idx++ ) { - printf("interface num:%d\n" - " name:%s node:%p widl:%p\n" - " inherit:%s inherit idx:%d refcount:%d\n" - " own functions:%d own properties:%d output idx:%d\n", - idx, - interfaces[idx].name, - interfaces[idx].node, - interfaces[idx].widl_node, - interfaces[idx].inherit_name, - interfaces[idx].inherit_idx, - interfaces[idx].refcount, - interfaces[idx].own_functions, - interfaces[idx].own_properties, - interfaces[idx].output_idx); - } - } - - *interfacec_out = interfacec; - *interfaces_out = interfaces; - - return 0; -} diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index e7215b1..9c564b9 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -130,7 +130,7 @@ genbind_node_enumerate_type(struct genbind_node *node, enum genbind_node_type type); /** Depth first left hand search returning nodes of the specified type - * and a ident child node with matching text + * with an ident child node with matching text * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 914f58e..18db196 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -14,10 +14,11 @@ #include #include +#include "options.h" #include "nsgenbind-ast.h" #include "webidl-ast.h" #include "jsapi-libdom.h" -#include "options.h" +#include "interface-map.h" struct options *options; @@ -194,6 +195,7 @@ int main(int argc, char **argv) int res; struct genbind_node *genbind_root = NULL; struct webidl_node *webidl_root = NULL; + struct interface_map *interface_map = NULL; enum bindingtype_e bindingtype; options = process_cmdline(argc, argv); @@ -226,6 +228,15 @@ int main(int argc, char **argv) /* debug dump of web idl AST */ webidl_dump_ast(webidl_root); + /* generate index of interfaces in idl sorted by inheritance */ + res = interface_map_new(genbind_root, webidl_root, &interface_map); + if (res != 0) { + return 5; + } + + /* dump the interface mapping */ + interface_map_dump(interface_map); + interface_map_dumpdot(interface_map); #if 0 /* generate output for each binding */ diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd index c32f6a3..4e06d23 100644 --- a/test/data/bindings/browser-duk.bnd +++ b/test/data/bindings/browser-duk.bnd @@ -11,6 +11,7 @@ binding duk_libdom { webidl "dom.idl"; webidl "html.idl"; + webidl "uievents.idl"; webidl "console.idl"; preface %{ diff --git a/test/data/idl/uievents.idl b/test/data/idl/uievents.idl new file mode 100644 index 0000000..3f339f3 --- /dev/null +++ b/test/data/idl/uievents.idl @@ -0,0 +1,185 @@ +// Retrived from +// Thu Jul 23 21:40:07 BST 2015 + + +[Constructor(DOMString type, optional UIEventInit eventInitDict)] +interface UIEvent : Event { + readonly attribute Window? view; + readonly attribute long detail; +}; + +dictionary UIEventInit : EventInit { + Window? view = null; + long detail = 0; +}; + +[Constructor(DOMString typeArg, optional FocusEventInit focusEventInitDict)] +interface FocusEvent : UIEvent { + readonly attribute EventTarget? relatedTarget; +}; + +dictionary FocusEventInit : UIEventInit { + EventTarget? relatedTarget = null; +}; + +[Constructor(DOMString typeArg, optional MouseEventInit mouseEventInitDict)] +interface MouseEvent : UIEvent { + readonly attribute long screenX; + readonly attribute long screenY; + readonly attribute long clientX; + readonly attribute long clientY; + readonly attribute boolean ctrlKey; + readonly attribute boolean shiftKey; + readonly attribute boolean altKey; + readonly attribute boolean metaKey; + readonly attribute short button; + readonly attribute EventTarget? relatedTarget; + // Introduced in this specification + readonly attribute unsigned short buttons; + boolean getModifierState (DOMString keyArg); +}; + +dictionary MouseEventInit : EventModifierInit { + long screenX = 0; + long screenY = 0; + long clientX = 0; + long clientY = 0; + short button = 0; + unsigned short buttons = 0; + EventTarget? relatedTarget = null; +}; + +dictionary EventModifierInit : UIEventInit { + boolean ctrlKey = false; + boolean shiftKey = false; + boolean altKey = false; + boolean metaKey = false; + boolean modifierAltGraph = false; + boolean modifierCapsLock = false; + boolean modifierFn = false; + boolean modifierFnLock = false; + boolean modifierHyper = false; + boolean modifierNumLock = false; + boolean modifierOS = false; + boolean modifierScrollLock = false; + boolean modifierSuper = false; + boolean modifierSymbol = false; + boolean modifierSymbolLock = false; +}; + +[Constructor(DOMString typeArg, optional WheelEventInit wheelEventInitDict)] +interface WheelEvent : MouseEvent { + // DeltaModeCode + const unsigned long DOM_DELTA_PIXEL = 0x00; + const unsigned long DOM_DELTA_LINE = 0x01; + const unsigned long DOM_DELTA_PAGE = 0x02; + readonly attribute double deltaX; + readonly attribute double deltaY; + readonly attribute double deltaZ; + readonly attribute unsigned long deltaMode; +}; + +dictionary WheelEventInit : MouseEventInit { + double deltaX = 0.0; + double deltaY = 0.0; + double deltaZ = 0.0; + unsigned long deltaMode = 0; +}; + +[Constructor(DOMString typeArg, optional KeyboardEventInit keyboardEventInitDict)] +interface KeyboardEvent : UIEvent { + // KeyLocationCode + const unsigned long DOM_KEY_LOCATION_STANDARD = 0x00; + const unsigned long DOM_KEY_LOCATION_LEFT = 0x01; + const unsigned long DOM_KEY_LOCATION_RIGHT = 0x02; + const unsigned long DOM_KEY_LOCATION_NUMPAD = 0x03; + readonly attribute DOMString key; + readonly attribute DOMString code; + readonly attribute unsigned long location; + readonly attribute boolean ctrlKey; + readonly attribute boolean shiftKey; + readonly attribute boolean altKey; + readonly attribute boolean metaKey; + readonly attribute boolean repeat; + readonly attribute boolean isComposing; + boolean getModifierState (DOMString keyArg); +}; + +dictionary KeyboardEventInit : EventModifierInit { + DOMString key = ""; + DOMString code = ""; + unsigned long location = 0; + boolean repeat = false; + boolean isComposing = false; +}; + +[Constructor(DOMString typeArg, optional CompositionEventInit compositionEventInitDict)] +interface CompositionEvent : UIEvent { + readonly attribute DOMString data; +}; + +dictionary CompositionEventInit : UIEventInit { + DOMString data = ""; +}; + +partial interface CustomEvent { + // Originally introduced (and deprecated) in this specification + void initCustomEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, any detailArg); +}; + +partial interface UIEvent { + // Deprecated in this specification + void initUIEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg); +}; + +partial interface FocusEvent { + // Originally introduced (and deprecated) in this specification + void initFocusEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, EventTarget? relatedTargetArg); +}; + +partial interface MouseEvent { + // Deprecated in this specification + void initMouseEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, boolean ctrlKeyArg, boolean altKeyArg, boolean shiftKeyArg, boolean metaKeyArg, short buttonArg, EventTarget? relatedTargetArg); +}; + +partial interface WheelEvent { + // Originally introduced (and deprecated) in this specification + void initWheelEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, short buttonArg, EventTarget? relatedTargetArg, DOMString modifiersListArg, double deltaXArg, double deltaYArg, double deltaZArg, unsigned long deltaMode); +}; + +partial interface KeyboardEvent { + // Originally introduced (and deprecated) in this specification + void initKeyboardEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, DOMString keyArg, unsigned long locationArg, DOMString modifiersListArg, boolean repeat, DOMString locale); +}; + +partial interface CompositionEvent { + // Originally introduced (and deprecated) in this specification + void initCompositionEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, DOMString dataArg, DOMString locale); +}; + +partial interface KeyboardEvent { + // The following support legacy user agents + readonly attribute unsigned long charCode; + readonly attribute unsigned long keyCode; + readonly attribute unsigned long which; +}; + +partial dictionary KeyboardEventInit { + unsigned long charCode = 0; + unsigned long keyCode = 0; + unsigned long which = 0; +}; + +interface MutationEvent : Event { + // attrChangeType + const unsigned short MODIFICATION = 1; + const unsigned short ADDITION = 2; + const unsigned short REMOVAL = 3; + readonly attribute Node? relatedNode; + readonly attribute DOMString prevValue; + readonly attribute DOMString newValue; + readonly attribute DOMString attrName; + readonly attribute unsigned short attrChange; + void initMutationEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Node? relatedNodeArg, DOMString prevValueArg, DOMString newValueArg, DOMString attrNameArg, unsigned short attrChangeArg); +}; + -- cgit v1.2.3 From 13be4238314d1a9903b037ab749074575ef0d1eb Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 25 Jul 2015 21:59:19 +0100 Subject: initial duktape libdom generator This generator creates all the output files and generates the finalisers for every class. --- src/Makefile | 3 +- src/duk-libdom.c | 268 ++++++++++++++++++++++++++++++ src/duk-libdom.h | 16 ++ src/interface-map.c | 13 ++ src/interface-map.h | 32 +++- src/nsgenbind.c | 52 ++---- src/options.h | 4 - test/data/bindings/HTMLUnknownElement.bnd | 17 ++ test/data/bindings/browser-duk.bnd | 12 ++ 9 files changed, 366 insertions(+), 51 deletions(-) create mode 100644 src/duk-libdom.c create mode 100644 src/duk-libdom.h create mode 100644 test/data/bindings/HTMLUnknownElement.bnd diff --git a/src/Makefile b/src/Makefile index b7b142a..8b034fe 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,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 interface-map.c +DIR_SOURCES := nsgenbind.c utils.c webidl-ast.c nsgenbind-ast.c \ + interface-map.c duk-libdom.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.c b/src/duk-libdom.c new file mode 100644 index 0000000..4d8ecf5 --- /dev/null +++ b/src/duk-libdom.c @@ -0,0 +1,268 @@ +/* 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "utils.h" +#include "nsgenbind-ast.h" +#include "webidl-ast.h" +#include "interface-map.h" +#include "duk-libdom.h" + +#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"\ +" */" + +/** + * Generate a C class name for the interface. + * + * The IDL interface names are camelcase and not similar to libdom naming so it + * is necessary to convert them to a libdom compatible class name. This + * implementation is simple ASCII capable only and cannot cope with multibyte + * codepoints. + * + * The algorithm is: + * - copy characters to output lowering their case + * - if the previous character in the input name was uppercase and the current + * one is lowercase insert an underscore before the *previous* character. + */ +static char *gen_class_name(struct interface_map_entry *interfacee) +{ + const char *inc; + char *outc; + char *name; + int wasupper; + + /* enpty strings are a bad idea */ + if ((interfacee->name == NULL) || (interfacee->name[0] == 0)) { + return NULL; + } + + /* allocate result buffer as twice the input length as thats the + * absolute worst case. + */ + name = calloc(2, strlen(interfacee->name)); + + outc = name; + inc = interfacee->name; + wasupper = 0; + + /* first character handled separately as inserting a leading underscore + * is undesirable + */ + *outc++ = tolower(*inc++); + /* copy input to output */ + while (*inc != 0) { + /* ugly hack as html IDL is always prefixed uppercase and needs + * an underscore there + */ + if ((inc == (interfacee->name + 4)) && + (interfacee->name[0] == 'H') && + (interfacee->name[1] == 'T') && + (interfacee->name[2] == 'M') && + (interfacee->name[3] == 'L') && + (islower(inc[1]) == 0)) { + *outc++ = '_'; + } + if ((islower(*inc) != 0) && (wasupper != 0)) { + *outc = *(outc - 1); + *(outc - 1) = '_'; + outc++; + wasupper = 0; + } else { + wasupper = isupper(*inc); + } + *outc++ = tolower(*inc++); + } + return name; +} + +/** + * output character data of node of given type. + * + * used for pre/pro/epi/post sections + */ +static int +output_cdata(FILE* outf, + struct genbind_node *node, + enum genbind_node_type nodetype) +{ + char *cdata; + cdata = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode(node), + NULL, nodetype)); + if (cdata != NULL) { + fprintf(outf, "%s\n", cdata); + } + 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; + + /* finaliser definition */ + fprintf(outf, + "void dukky_%s___fini(duk_context *ctx, %s_private_t *priv)\n", + 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" ); + } + + /* 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_cdata(outf, fini_node, GENBIND_NODE_TYPE_CDATA); + + /* if this interface inherits ensure we call its finaliser */ + if (inherite != NULL) { + fprintf(outf, + "\tdukky_%s___fini(ctx, &priv->parent);\n", + inherite->class_name); + } + fprintf(outf, "}\n"); + + return 0; +} + + +/** + * generate a source file to implement an interface using duk and libdom. + */ +static int output_interface(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map *interface_map, + struct interface_map_entry *interfacee) +{ + FILE *ifacef; + int ifacenamelen; + struct genbind_node *binding_node; + struct interface_map_entry *inherite; + + interfacee->class_name = gen_class_name(interfacee); + + /* generate source filename */ + ifacenamelen = strlen(interfacee->class_name) + 4; + interfacee->filename = malloc(ifacenamelen); + snprintf(interfacee->filename, ifacenamelen, + "%s.c", interfacee->class_name); + + /* open output file */ + ifacef = genb_fopen(interfacee->filename, "w"); + if (ifacef == NULL) { + return -1; + } + + /* 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); + + /* class preface */ + output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE); + + /* binding prologue */ + output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PROLOGUE); + + /* class prologue */ + output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PROLOGUE); + + /* initialisor */ + //output_interface_init(); + + /* finaliser */ + output_interface_fini(ifacef, interfacee, inherite); + + /* constructor */ + /* destructor */ + + /* class epilogue */ + output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE); + + /* binding epilogue */ + output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_EPILOGUE); + + /* class postface */ + output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_POSTFACE); + + /* binding postface */ + output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_POSTFACE); + + fclose(ifacef); + + return 0; +} + +int duk_libdom_output(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map *interface_map) +{ + int idx; + int res = 0; + + /* generate interfaces */ + for (idx = 0; idx < interface_map->entryc; idx++) { + res = output_interface(genbind, webidl, interface_map, + &interface_map->entries[idx]); + if (res != 0) { + break; + } + } + + /* generate header */ + /** \todo implement header */ + + /* generate makefile fragment */ + /** \todo implement makefile generation */ + + return res; +} diff --git a/src/duk-libdom.h b/src/duk-libdom.h new file mode 100644 index 0000000..8e86d74 --- /dev/null +++ b/src/duk-libdom.h @@ -0,0 +1,16 @@ +/* DukTape binding generation + * + * This file is part of nsgenbind. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2015 Vincent Sanders + */ + +#ifndef nsgenbind_duk_libdom_h +#define nsgenbind_duk_libdom_h + +int duk_libdom_output(struct genbind_node *genbind, + struct webidl_node *webidl, + struct interface_map *interface_map); + +#endif diff --git a/src/interface-map.c b/src/interface-map.c index aef697e..44ece42 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -290,3 +290,16 @@ int interface_map_dumpdot(struct interface_map *index) return 0; } + +struct interface_map_entry * +interface_map_inherit_entry(struct interface_map *map, + struct interface_map_entry *entry) +{ + struct interface_map_entry *res = NULL; + + if ((entry != NULL) && + (entry->inherit_idx != -1)) { + res = &map->entries[entry->inherit_idx]; + } + return res; +} diff --git a/src/interface-map.h b/src/interface-map.h index c9dd654..8a6ac05 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -25,19 +25,39 @@ struct interface_map_entry { * interface */ struct genbind_node *class; /**< class from binding (if any) */ + + /* The variables are created and used by the output generation but + * rtaher than have another allocation and pointer the data they are + * just inline here. + */ + + char *filename; /**< filename used for output */ + + char *class_name; /**< the interface name converted to output + * appropriate value. e.g. generators targetting c + * might lowercase the name or add underscores + * instead of caps + */ }; struct interface_map { - int entryc; /**< count of interfaces */ - struct interface_map_entry *entries; + int entryc; /**< count of interfaces */ + struct interface_map_entry *entries; }; int interface_map_new(struct genbind_node *genbind, - struct webidl_node *webidl, - struct interface_map **index_out); + struct webidl_node *webidl, + struct interface_map **index_out); -int interface_map_dump(struct interface_map *index); +int interface_map_dump(struct interface_map *map); -int interface_map_dumpdot(struct interface_map *index); +int interface_map_dumpdot(struct interface_map *map); + +/** + * interface map parent entry + * + * \return inherit entry or NULL if there is not one + */ +struct interface_map_entry *interface_map_inherit_entry(struct interface_map *map, struct interface_map_entry *entry); #endif diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 18db196..b3191ba 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -17,8 +17,9 @@ #include "options.h" #include "nsgenbind-ast.h" #include "webidl-ast.h" -#include "jsapi-libdom.h" #include "interface-map.h" +#include "jsapi-libdom.h" +#include "duk-libdom.h" struct options *options; @@ -85,28 +86,6 @@ static struct options* process_cmdline(int argc, char **argv) } -static int generate_binding(struct genbind_node *binding_node, void *ctx) -{ - struct genbind_node *genbind_root = ctx; - char *type; - int res = 10; - - type = genbind_node_gettext( - genbind_node_find_type( - genbind_node_getnode(binding_node), - NULL, - GENBIND_NODE_TYPE_TYPE)); - - if (strcmp(type, "jsapi_libdom") == 0) { - res = jsapi_libdom_output(options, genbind_root, binding_node); - } else { - fprintf(stderr, "Error: unsupported binding type \"%s\"\n", type); - } - - return res; -} - - static int webidl_file_cb(struct genbind_node *node, void *ctx) { struct webidl_node **webidl_ast = ctx; @@ -237,24 +216,17 @@ int main(int argc, char **argv) /* dump the interface mapping */ interface_map_dump(interface_map); interface_map_dumpdot(interface_map); -#if 0 - /* generate output for each binding */ - res = genbind_node_foreach_type(genbind_root, - GENBIND_NODE_TYPE_BINDING, - generate_binding, - genbind_root); - if (res != 0) { - fprintf(stderr, "Error: output failed with code %d\n", res); - if (options->outfilename != NULL) { - unlink(options->outfilename); - } - if (options->hdrfilename != NULL) { - unlink(options->hdrfilename); - } - return res; + /* generate binding */ + switch (bindingtype) { + case BINDINGTYPE_DUK_LIBDOM: + res = duk_libdom_output(genbind_root, webidl_root, interface_map); + break; + + default: + fprintf(stderr, "Unable to generate binding of this type\n"); + res = 7; } -#endif - return 0; + return res; } diff --git a/src/options.h b/src/options.h index 68a4bc1..85f107e 100644 --- a/src/options.h +++ b/src/options.h @@ -13,10 +13,6 @@ struct options { char *infilename; /**< binding source */ char *outdirname; /**< output directory */ -FILE *hdrfilehandle; -char *hdrfilename; -char *outfilename; -FILE *outfilehandle; char *idlpath; /**< path to IDL files */ bool verbose; /**< verbose processing */ diff --git a/test/data/bindings/HTMLUnknownElement.bnd b/test/data/bindings/HTMLUnknownElement.bnd new file mode 100644 index 0000000..376a823 --- /dev/null +++ b/test/data/bindings/HTMLUnknownElement.bnd @@ -0,0 +1,17 @@ +class HTMLUnknownElement { + preface %{ +/* class pre */ + %}; + + prologue %{ +/* class pro */ + %}; + + epilogue %{ +/* class epi */ + %}; + + postface %{ +/* class post */ + %}; +} diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd index 4e06d23..273eae9 100644 --- a/test/data/bindings/browser-duk.bnd +++ b/test/data/bindings/browser-duk.bnd @@ -15,18 +15,30 @@ binding duk_libdom { webidl "console.idl"; preface %{ +/* DukTape JavaScript bindings for NetSurf browser + * + * Copyright 2015 Vincent Sanders + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * Released under the terms of the MIT License, + * http://www.opensource.org/licenses/mit-license + */ %}; prologue %{ +/* binding prologue */ %}; epilogue %{ +/* binding epilogue */ %}; postface %{ +/* binding postface */ %}; } +#include "HTMLUnknownElement.bnd" + class Node { private "dom_node *" node; -- cgit v1.2.3 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 --- README | 229 +++++++++++++++++++-- src/duk-libdom.c | 326 +++++++++++++++++++++++++++--- src/nsgenbind-parser.y | 124 +++++++----- test/data/bindings/HTMLUnknownElement.bnd | 2 + test/data/bindings/browser-duk.bnd | 113 +++++++++-- 5 files changed, 691 insertions(+), 103 deletions(-) diff --git a/README b/README index 039bd6a..eb42c83 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ -genjsbind +nsgenbind ========= -This is a tool to generate javascript to dom bindings from w3c webidl +This is a tool to generate JavaScript to DOM bindings from w3c webidl files and a binding configuration file. building @@ -16,7 +16,7 @@ nsgenbind [-v] [-g] [-D] [-W] [-I idlpath] inputfile outputdir -v The verbose switch makes the tool verbose about what operations it is -performing instead of teh default of only reporting errors. +performing instead of the default of only reporting errors. -g The generated code will be augmented with runtime debug logging so it @@ -40,15 +40,15 @@ which to place its output. Debug output ------------ -as well as the generated source the tool will output seevral debugging -files with the -D switch in use. +In addition to the generated source the tool will output several + debugging files with the -D switch in use. interface.dot The interfaces IDL dot file contains all the interfaces and their relationship. graphviz can be used to convert this into a visual representation which is sometimes useful to help in debugging - missing or incorrect IDL inheritance. + missing or incorrect interface inheritance. Processing the dot file with graphviz can produce very large files so care must be taken with options. Some examples that produce @@ -65,17 +65,17 @@ Web IDL ------- The IDL is specified in a w3c document[1] but the second edition is in -draft[2] and covers many of the features actually used in the whatwg -dom and html spec. + draft[2] and covers many of the features actually used in the whatwg + dom and HTML spec. The principal usage of the IDL is to define the interface between -scripts and a browsers internal state. For example the DOM[3] and -HTML[4] specs contain all the IDL for acessing the DOM and interacting -with a web browser (this not strictly true as there are several -interfaces simply not in the standards such as console). + scripts and a browsers internal state. For example the DOM[3] and + HTML[4] specs contain all the IDL for accessing the DOM and interacting + with a web browser (this not strictly true as there are several + interfaces simply not in the standards such as console). The IDL uses some slightly strange names than other object orientated -systems. + systems. IDL | JS | OOP | Notes -----------+------------------+----------------+---------------------------- @@ -88,6 +88,209 @@ systems. attribute | property | property | Variables set per instance -----------+------------------+----------------+---------------------------- + +Binding file +------------ + +The binding file controls how the code generator constructs its +output. It is deliberately similar to c++ in syntax and uses OOP +nomenclature to describe the annotations (class, method, etc. instead +of interface, operation, etc.) + +The binding file consists of three types of element: + + binding + + The binding element has an identifier controlling which type of + output is produced (currently duk_libdom and jsapi_libdom). + + The binding block may contain one or more directives which + control overall generation behaviour: + + webidl + + This takes a quoted string which identifies a WebIDL file to + process. There may be many of these directives as required + but without at least one the binding is not very useful as + it will generate no output. + + preface + + This takes a cdata block. There may only be one of these per + binding, subsequent directives will be ignored. + + The preface is emitted in every generated source file before + any other output and generally is used for copyright + comments and similar. It is immediately followed by the + binding tools preamble comments. + + prologue + + This takes a cdata block. There may only be one of these per + binding, subsequent directives will be ignored. + + The prologue is emitted in every generated source file after + the class preface has been generated. It is often used for + include directives required across all modules. + + epilogue + + This takes a cdata block. There may only be one of these per + binding, subsequent directives will be ignored. + + The epilogue is emitted after the generated code and the + class epilogue + + postface + + This takes a cdata block. There may only be one of these per + binding, subsequent directives will be ignored. + + The postface is emitted as the very last element of the + generated source files. + + + class + + The class controls the generation of source for an IDL interface + private member variables are declared here and header and + footer elements specific to this class. + + private + + variables added to the private structure for the class. + + preface + + This takes a cdata block. There may only be one of these per + class, subsequent directives will be ignored. + + The preface is emitted in every generated source file after + the binding preface and tool preamble. + + prologue + + This takes a cdata block. There may only be one of these per + class, subsequent directives will be ignored. + + The prologue is emitted in every generated source file after + the binding prologue has been generated. + + epilogue + + This takes a cdata block. There may only be one of these per + class, subsequent directives will be ignored. + + The epilogue is emitted after the generated code and before + the binding epilogue + + postface + + This takes a cdata block. There may only be one of these per + class, subsequent directives will be ignored. + + The postface is emitted after the binding epilogue. + + + methods + + The methods allow a binding to provide code to be inserted in + the output and to control the class initializer and finalizer + (note not the constructor/destructor) + + All these are in the syntax of: + + methodtype declarator ( parameters ) + + They may optionally be followed by a cdata block which will be + added to the appropriate method in the output. A semicolon may + be used instead of the cdata block but this is not obviously + useful except in the case of the init type. + + methods and getters/setters for properties must specify both + class and name using the c++ style double colon separated + identifiers i.e. class::identifier + + Note: the class names must match the IDL interface names in the + binding but they will almost certainly have to be translated + into more suitable class names for generated output. + + init + + The declarator for this method type need only identify the + class (an identifier may be provided but will be ignored). + + TODO: should it become necessary to defeat the automated + generation of an initializer altogether the identifier can + be checked and if set to the class name (like a + constructor) output body simply becomes a verbatim copy of + the cdata block. + + The parameter list may be empty or contain type/identifier + tuples. If there is a parent interface it will be called + with the parameters necessary for its initializer, hence the + entire ancestry will be initialised. + + The parameters passed to the parent are identified by + matching the identifier with the parents initializer + parameter identifier, if the type does not match a type + cast is inserted. + + It is sometimes desirable for the parent initializer + identifier to be different from the childs identifier. In + this case the identifier may have an alias added by having + a double colon followed by a second identifier. + + For example consider the case below where HTMLElement + inherits from Element which inherits from Node. + + init Node("struct dom_node *" node); + init Element("struct dom_element *" element::node); + init HTMLElement("struct dom_html_element *" html_element::element); + + The three initializers have parameters with different + identifiers but specify the identifier as it appears in + their parents parameter list. This allows for differing + parameter ordering and identifier naming while allowing the + automated enforcement of correct initializer calling + chains. + + + fini + + The declarator for this method type need only identify the + class (an identifier may be provided but will be ignored). + + The cdata block is output. + + The parent finalizer is called (finalizers have no parameters + so do not need the complexity of initializers. + + method + + The declarator for this method type must contain both the + class and the identifier. + + The cdata block is output. + + getter + + The declarator for this method type must contain both the + class and the identifier. + + The cdata block is output. + + setter + + The declarator for this method type must contain both the + class and the identifier. + + The cdata block is output. + + +References +---------- + [1] http://www.w3.org/TR/WebIDL/ [2] https://heycam.github.io/webidl/ [3] https://dom.spec.whatwg.org/ 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, diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index 454fb56..456decb 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -32,6 +32,65 @@ static void nsgenbind_error(YYLTYPE *locp, errtxt = strdup(str); } +static struct genbind_node * +add_method(struct genbind_node **genbind_ast, + long methodtype, + struct genbind_node *declarator, + char *cdata) +{ + struct genbind_node *res_node; + struct genbind_node *method_node; + struct genbind_node *class_node; + struct genbind_node *cdata_node; + char *class_name; + + /* extract the class name from the declarator */ + class_name = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode( + genbind_node_find_type( + declarator, + NULL, + GENBIND_NODE_TYPE_CLASS)), + NULL, + GENBIND_NODE_TYPE_IDENT)); + + if (cdata == NULL) { + cdata_node = declarator; + } else { + cdata_node = genbind_new_node(GENBIND_NODE_TYPE_CDATA, + declarator, + cdata); + } + + /* generate method node */ + method_node = genbind_new_node(GENBIND_NODE_TYPE_METHOD, + NULL, + genbind_new_node(GENBIND_NODE_TYPE_METHOD_TYPE, + cdata_node, + (void *)methodtype)); + + class_node = genbind_node_find_type_ident(*genbind_ast, + NULL, + GENBIND_NODE_TYPE_CLASS, + class_name); + if (class_node == NULL) { + /* no existing class so manufacture one and attach method */ + res_node = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + method_node, + class_name)); + + } else { + /* update the existing class */ + + /* link member node into class_node */ + genbind_node_add(class_node, method_node); + + res_node = NULL; /* updating so no need to add a new node */ + } + return res_node; +} %} @@ -199,6 +258,17 @@ TypeIdent $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, genbind_new_node(GENBIND_NODE_TYPE_TYPE, NULL, $1), $2); } + | + TOK_STRING_LITERAL TOK_IDENTIFIER TOK_DBLCOLON TOK_IDENTIFIER + { + $$ = genbind_new_node(GENBIND_NODE_TYPE_IDENT, + genbind_new_node(GENBIND_NODE_TYPE_IDENT, + genbind_new_node(GENBIND_NODE_TYPE_TYPE, + NULL, + $1), + $2), + $4); + } ; Preface @@ -330,54 +400,14 @@ Method : MethodType MethodDeclarator CBlock { - struct genbind_node *declarator; - struct genbind_node *method_node; - struct genbind_node *class_node; - char *class_name; - - declarator = $2; - - /* extract the class name from the declarator */ - class_name = genbind_node_gettext( - genbind_node_find_type( - genbind_node_getnode( - genbind_node_find_type( - declarator, - NULL, - GENBIND_NODE_TYPE_CLASS)), - NULL, - GENBIND_NODE_TYPE_IDENT)); - - /* generate method node */ - method_node = genbind_new_node(GENBIND_NODE_TYPE_METHOD, NULL, - genbind_new_node(GENBIND_NODE_TYPE_METHOD_TYPE, - genbind_new_node(GENBIND_NODE_TYPE_CDATA, - declarator, $3), - (void *)$1)); - - - - class_node = genbind_node_find_type_ident(*genbind_ast, - NULL, - GENBIND_NODE_TYPE_CLASS, - class_name); - if (class_node == NULL) { - /* no existing class so manufacture one and attach method */ - $$ = genbind_new_node(GENBIND_NODE_TYPE_CLASS, NULL, - genbind_new_node(GENBIND_NODE_TYPE_IDENT, - method_node, - class_name)); - - } else { - /* update the existing class */ - - /* link member node into class_node */ - genbind_node_add(class_node, method_node); - - $$ = NULL; /* updating so no need to add a new node */ - } + $$ = add_method(genbind_ast, $1, $2, $3); } - + | + MethodType MethodDeclarator ';' + { + $$ = add_method(genbind_ast, $1, $2, NULL); + } + ; Class : diff --git a/test/data/bindings/HTMLUnknownElement.bnd b/test/data/bindings/HTMLUnknownElement.bnd index 376a823..faabaec 100644 --- a/test/data/bindings/HTMLUnknownElement.bnd +++ b/test/data/bindings/HTMLUnknownElement.bnd @@ -15,3 +15,5 @@ class HTMLUnknownElement { /* class post */ %}; } + +init HTMLUnknownElement("struct dom_html_element *" html_unknown_element::html_element); diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd index 273eae9..392f652 100644 --- a/test/data/bindings/browser-duk.bnd +++ b/test/data/bindings/browser-duk.bnd @@ -39,31 +39,112 @@ binding duk_libdom { #include "HTMLUnknownElement.bnd" +/* specialisations of html_element */ +init HTMLFontElement("struct dom_html_element *" html_font_element::html_element); +init HTMLDirectoryElement("struct dom_html_element *" html_directory_element::html_element); +init HTMLFrameElement("struct dom_html_element *" html_frame_element::html_element); +init HTMLFrameSetElement("struct dom_html_element *" html_frame_set_element::html_element); +init HTMLMarqueeElement("struct dom_html_element *" html_marquee_element::html_element); +init HTMLAppletElement("struct dom_html_element *" html_applet_element::html_element); +init HTMLCanvasElement("struct dom_html_element *" html_canvas_element::html_element); +init HTMLTemplateElement("struct dom_html_element *" html_template_element::html_element); +init HTMLScriptElement("struct dom_html_element *" html_script_element::html_element); +init HTMLDialogElement("struct dom_html_element *" html_dialog_element::html_element); +init HTMLMenuItemElement("struct dom_html_element *" html_menu_item_element::html_element); +init HTMLMenuElement("struct dom_html_element *" html_menu_element::html_element); +init HTMLDetailsElement("struct dom_html_element *" html_details_element::html_element); +init HTMLLegendElement("struct dom_html_element *" html_legend_element::html_element); +init HTMLFieldSetElement("struct dom_html_element *" html_field_set_element::html_element); +init HTMLMeterElement("struct dom_html_element *" html_meter_element::html_element); +init HTMLProgressElement("struct dom_html_element *" html_progress_element::html_element); +init HTMLOutputElement("struct dom_html_element *" html_output_element::html_element); +init HTMLKeygenElement("struct dom_html_element *" html_keygen_element::html_element); +init HTMLTextAreaElement("struct dom_html_element *" html_text_area_element::html_element); +init HTMLOptionElement("struct dom_html_element *" html_option_element::html_element); +init HTMLOptGroupElement("struct dom_html_element *" html_opt_group_element::html_element); +init HTMLDataListElement("struct dom_html_element *" html_data_list_element::html_element); +init HTMLSelectElement("struct dom_html_element *" html_select_element::html_element); +init HTMLButtonElement("struct dom_html_element *" html_button_element::html_element); +init HTMLInputElement("struct dom_html_element *" html_input_element::html_element); +init HTMLLabelElement("struct dom_html_element *" html_label_element::html_element); +init HTMLFormElement("struct dom_html_element *" html_form_element::html_element); +init HTMLTableCellElement("struct dom_html_element *" html_table_cell_element::html_element); +init HTMLTableRowElement("struct dom_html_element *" html_table_row_element::html_element); +init HTMLTableSectionElement("struct dom_html_element *" html_table_section_element::html_element); +init HTMLTableColElement("struct dom_html_element *" html_table_col_element::html_element); +init HTMLTableCaptionElement("struct dom_html_element *" html_table_caption_element::html_element); +init HTMLTableElement("struct dom_html_element *" html_table_element::html_element); +init HTMLAreaElement("struct dom_html_element *" html_area_element::html_element); +init HTMLMapElement("struct dom_html_element *" html_map_element::html_element); +init HTMLMediaElement("struct dom_html_element *" html_media_element::html_element); +init HTMLTrackElement("struct dom_html_element *" html_track_element::html_element); +init HTMLParamElement("struct dom_html_element *" html_param_element::html_element); +init HTMLObjectElement("struct dom_html_element *" html_object_element::html_element); +init HTMLEmbedElement("struct dom_html_element *" html_embed_element::html_element); +init HTMLIFrameElement("struct dom_html_element *" html_i_frame_element::html_element); +init HTMLImageElement("struct dom_html_element *" html_image_element::html_element); +init HTMLSourceElement("struct dom_html_element *" html_source_element::html_element); +init HTMLPictureElement("struct dom_html_element *" html_picture_element::html_element); +init HTMLModElement("struct dom_html_element *" html_mod_element::html_element); +init HTMLBRElement("struct dom_html_element *" html_br_element::html_element); +init HTMLSpanElement("struct dom_html_element *" html_span_element::html_element); +init HTMLTimeElement("struct dom_html_element *" html_time_element::html_element); +init HTMLDataElement("struct dom_html_element *" html_data_element::html_element); +init HTMLAnchorElement("struct dom_html_element *" html_anchor_element::html_element); +init HTMLDivElement("struct dom_html_element *" html_div_element::html_element); +init HTMLDListElement("struct dom_html_element *" html_d_list_element::html_element); +init HTMLLIElement("struct dom_html_element *" html_li_element::html_element); +init HTMLUListElement("struct dom_html_element *" html_u_list_element::html_element); +init HTMLOListElement("struct dom_html_element *" html_o_list_element::html_element); +init HTMLQuoteElement("struct dom_html_element *" html_quote_element::html_element); +init HTMLPreElement("struct dom_html_element *" html_pre_element::html_element); +init HTMLHRElement("struct dom_html_element *" html_hr_element::html_element); +init HTMLParagraphElement("struct dom_html_element *" html_paragraph_element::html_element); +init HTMLHeadingElement("struct dom_html_element *" html_heading_element::html_element); +init HTMLBodyElement("struct dom_html_element *" html_body_element::html_element); +init HTMLStyleElement("struct dom_html_element *" html_style_element::html_element); +init HTMLMetaElement("struct dom_html_element *" html_meta_element::html_element); +init HTMLLinkElement("struct dom_html_element *" html_link_element::html_element); +init HTMLBaseElement("struct dom_html_element *" html_base_element::html_element); +init HTMLTitleElement("struct dom_html_element *" html_title_element::html_element); +init HTMLHeadElement("struct dom_html_element *" html_head_element::html_element); +init HTMLHtmlElement("struct dom_html_element *" html_html_element::html_element); + +/* specialisations of HTMLTableCellElement */ +init HTMLTableHeaderCellElement("struct dom_html_element *" html_table_header_cell_element::html_table_cell_element); +init HTMLTableDataCellElement("struct dom_html_element *" html_table_data_cell_element::html_table_cell_element); + +/* specialisations of html_media_element */ +init HTMLAudioElement("struct dom_html_element *" html_audio_element::html_media_element); +init HTMLVideoElement("struct dom_html_element *" html_video_element::html_media_element); + +init HTMLElement("struct dom_html_element *" html_element::element); + +init Text("struct dom_node_text *" text::character_data); +init Comment("struct dom_node_comment *" comment::character_data); +init ProcessingInstruction("struct dom_node_text *" text::character_data); + +init XMLDocument("struct dom_document *" document); + +init Element("struct dom_element *" element::node); +init CharacterData("struct dom_node_character_data *" character_data::node); +init DocumentFragment("struct dom_document *" document::node); +init DocumentType("struct dom_document *" document::node); +init Document("struct dom_document *" document::node); + class Node { private "dom_node *" node; - - preface %{ - %}; - - prologue %{ - %}; - - epilogue %{ - %}; - - postface %{ - %}; } -init Node("dom_node *" node) +init Node("struct dom_node *" node) %{ - private->node = node; - dom_node_ref(node); + priv->node = node; + dom_node_ref(node); %} fini Node() %{ - dom_node_unref(private->node); + dom_node_unref(priv->node); %} method Node::AppendChild() -- cgit v1.2.3 From d67501b49bb147ac8784618906c024906ae25cbc Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 27 Jul 2015 22:30:20 +0100 Subject: Add prototype generation --- src/duk-libdom.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/interface-map.h | 3 ++ 2 files changed, 119 insertions(+), 7 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index ee45eaf..b372df7 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -186,9 +186,11 @@ static int output_ducky_safe_get_private(FILE* outf, char *class_name, int idx) static int output_interface_constructor(FILE* outf, struct interface_map_entry *interfacee) { + int init_argc; + /* constructor definition */ fprintf(outf, - "duk_ret_t %s_%s___constructor(duk_context *ctx)\n", + "static duk_ret_t %s_%s___constructor(duk_context *ctx)\n", DLPFX, interfacee->class_name); fprintf(outf,"{\n"); @@ -196,8 +198,15 @@ output_interface_constructor(FILE* outf, struct interface_map_entry *interfacee) /* generate call to initialisor */ fprintf(outf, - "\t%s_%s___init(ctx, priv, duk_get_pointer(ctx, 1));\n", + "\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"); @@ -215,7 +224,7 @@ output_interface_destructor(FILE* outf, struct interface_map_entry *interfacee) { /* destructor definition */ fprintf(outf, - "duk_ret_t %s_%s___destructor(duk_context *ctx)\n", + "static duk_ret_t %s_%s___destructor(duk_context *ctx)\n", DLPFX, interfacee->class_name); fprintf(outf,"{\n"); @@ -351,11 +360,15 @@ output_interface_init(FILE* 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); @@ -402,8 +415,8 @@ output_interface_fini(FILE* outf, /* finaliser definition */ fprintf(outf, - "void dukky_%s___fini(duk_context *ctx, %s_private_t *priv)\n", - interfacee->class_name, interfacee->class_name); + "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 */ @@ -418,14 +431,107 @@ output_interface_fini(FILE* outf, /* if this interface inherits ensure we call its finaliser */ if (inherite != NULL) { fprintf(outf, - "\tdukky_%s___fini(ctx, &priv->parent);\n", - inherite->class_name); + "\t%s_%s___fini(ctx, &priv->parent);\n", + DLPFX, inherite->class_name); } fprintf(outf, "}\n\n"); return 0; } +/** + * generate code that gets a prototype by name + */ +static int output_get_prototype(FILE* outf, const char *interface_name) +{ + char *proto_name; + int pnamelen; + + /* duplicate the interface name in upper case */ + pnamelen = strlen(interface_name) + 1; /* allow for null byte */ + proto_name = malloc(pnamelen); + for ( ; pnamelen >= 0; pnamelen--) { + proto_name[pnamelen] = toupper(interface_name[pnamelen]); + } + + fprintf(outf,"\tduk_get_global_string(ctx, PROTO_MAGIC);\n"); + fprintf(outf,"\tduk_get_prop_string(ctx, -1, PROTO_NAME(%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, INIT_MAGIC);\n"); + fprintf(outf, "\tduk_pop(ctx);\n\n"); + + return 0; +} + +/** + * generate the interface prototype creator + */ +static int +output_interface_prototype(FILE* outf, + struct interface_map_entry *interfacee, + struct interface_map_entry *inherite) +{ + /* prototype definition */ + fprintf(outf, + "duk_ret_t %s_%s___proto(duk_context *ctx)\n", + DLPFX, interfacee->class_name); + 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 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 source file to implement an interface using duk and libdom. @@ -494,6 +600,9 @@ static int output_interface(struct genbind_node *genbind, /* destructor */ output_interface_destructor(ifacef, interfacee); + /* prototype */ + output_interface_prototype(ifacef, interfacee, inherite); + fprintf(ifacef, "\n"); /* class epilogue */ diff --git a/src/interface-map.h b/src/interface-map.h index 8a6ac05..7373580 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -38,6 +38,9 @@ struct interface_map_entry { * might lowercase the name or add underscores * instead of caps */ + int class_init_argc; /**< The number of parameters on the class + * initializer. + */ }; struct interface_map { -- cgit v1.2.3 From 3f0d06f529fb5efaeb4edd89e61b3421951b8bf2 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 28 Jul 2015 14:17:47 +0100 Subject: Generate class methods from interface operations --- src/duk-libdom.c | 275 ++++++++++++++++++++++++++++++++++++- test/data/bindings/browser-duk.bnd | 12 +- 2 files changed, 282 insertions(+), 5 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index b372df7..d1af70c 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -131,6 +131,34 @@ find_class_method(struct genbind_node *node, return res_node; } +/** + * find method by type on class with a specific ident + */ +static struct genbind_node * +find_class_method_ident(struct genbind_node *node, + struct genbind_node *prev, + enum genbind_node_type nodetype, + char *ident) +{ + struct genbind_node *res_node; + char *method_ident; + + res_node = find_class_method(node, prev, nodetype); + while (res_node != NULL) { + method_ident = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode(res_node), + NULL, + GENBIND_NODE_TYPE_IDENT)); + if ((method_ident != NULL) && strcmp(ident, method_ident) == 0) { + break; + } + + res_node = find_class_method(node, res_node, nodetype); + } + return res_node; +} + /** * output character data of node of given type. * @@ -158,6 +186,7 @@ output_cdata(FILE* outf, */ static int output_duckky_create_private(FILE* outf, char *class_name) { + fprintf(outf, "\t/* create private data and attach to instance */"); fprintf(outf, "\t%s_private_t *priv = calloc(1, sizeof(*priv));\n", class_name); fprintf(outf, "\tif (priv == NULL) return 0;\n"); @@ -453,11 +482,11 @@ static int output_get_prototype(FILE* outf, const char *interface_name) for ( ; pnamelen >= 0; pnamelen--) { proto_name[pnamelen] = toupper(interface_name[pnamelen]); } - - fprintf(outf,"\tduk_get_global_string(ctx, PROTO_MAGIC);\n"); - fprintf(outf,"\tduk_get_prop_string(ctx, -1, PROTO_NAME(%s));\n", + fprintf(outf, "\t/* get prototype */\n"); + fprintf(outf, "\tduk_get_global_string(ctx, PROTO_MAGIC);\n"); + fprintf(outf, "\tduk_get_prop_string(ctx, -1, PROTO_NAME(%s));\n", proto_name); - fprintf(outf,"\tduk_replace(ctx, -2);\n"); + fprintf(outf, "\tduk_replace(ctx, -2);\n"); free(proto_name); @@ -495,6 +524,135 @@ output_set_constructor(FILE* outf, char *class_name, int idx, int argc) return 0; } +/** + * generate code that adds a method in a prototype + */ +static int +output_add_method(FILE* outf, char *class_name, char *method, int argc) +{ + //#define DUKKY_ADD_METHOD(klass,meth,nargs) + 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, ", + DLPFX, class_name, method); + if (argc == -1) { + fprintf(outf, "DUK_VARARGS);\n"); + + } else { + fprintf(outf, "%d);\n", argc); + } + fprintf(outf, "\tDUKKY_DUMP_STACK(ctx);\n"); + 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; +} + +/** + * 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 + */ +static int +output_prototype_method(FILE* outf, + struct interface_map_entry *interfacee, + struct webidl_node *op_node) +{ + char *op_name; + int op_argc; + + op_name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(op_node), + NULL, + WEBIDL_NODE_TYPE_IDENT)); + + op_argc = count_operation_arguments(op_node); + + output_add_method(outf, interfacee->class_name, op_name, op_argc); + + return 0; + +} + +/** + * generate prototype method definitions + */ +static int +output_prototype_methods(FILE *outf, struct interface_map_entry *interfacee) +{ + int res; + struct webidl_node *list_node; + struct webidl_node *op_node; /* operation on list node */ + + /* iterate each list node within the interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(interfacee->node), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (list_node != NULL) { + /* iterate through operations in a list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_OPERATION); + + while (op_node != NULL) { + res = output_prototype_method(outf, interfacee, op_node); + if (res != 0) { + return res; + } + + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_OPERATION); + } + + + list_node = webidl_node_find_type( + webidl_node_getnode(interfacee->node), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + return 0; + +} + /** * generate the interface prototype creator */ @@ -517,6 +675,9 @@ output_interface_prototype(FILE* outf, fprintf(outf, "\tduk_set_prototype(ctx, 0);\n\n"); } + /* generate setting of methods */ + output_prototype_methods(outf, interfacee); + /* generate setting of destructor */ output_set_destructor(outf, interfacee->class_name, 0); @@ -533,6 +694,107 @@ output_interface_prototype(FILE* outf, 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, PRIVATE_MAGIC);\n"); + fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n"); + fprintf(outf, "\tduk_pop_2(ctx);\n"); + fprintf(outf, "\tif (priv == NULL) return 0; /* can do? No can do. */\n\n"); + return 0; +} + +/** + * generate a single class method for an interface operation + */ +static int +output_interface_operation(FILE* outf, + struct interface_map_entry *interfacee, + struct webidl_node *op_node) +{ + char *op_name; + struct genbind_node *method_node; + + op_name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(op_node), + NULL, + WEBIDL_NODE_TYPE_IDENT)); + + method_node = find_class_method_ident(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_METHOD, + op_name); + + /* method definition */ + fprintf(outf, + "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", + DLPFX, interfacee->class_name, op_name); + fprintf(outf,"{\n"); + + output_get_method_private(outf, interfacee->class_name); + + output_cdata(outf, method_node, GENBIND_NODE_TYPE_CDATA); + + 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 interface_map_entry *interfacee) +{ + int res; + struct webidl_node *list_node; + struct webidl_node *op_node; /* operation on list node */ + + /* iterate each list node within the interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(interfacee->node), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (list_node != NULL) { + /* iterate through operations in a list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_OPERATION); + + while (op_node != NULL) { + res = output_interface_operation(outf, interfacee, op_node); + if (res != 0) { + return res; + } + + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_OPERATION); + } + + + list_node = webidl_node_find_type( + webidl_node_getnode(interfacee->node), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + return 0; +} + /** * generate a source file to implement an interface using duk and libdom. */ @@ -600,6 +862,11 @@ static int output_interface(struct genbind_node *genbind, /* destructor */ output_interface_destructor(ifacef, interfacee); + /* operations */ + output_interface_operations(ifacef, interfacee); + + /* attributes */ + /* prototype */ output_interface_prototype(ifacef, interfacee, inherite); diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd index 392f652..0ddfa02 100644 --- a/test/data/bindings/browser-duk.bnd +++ b/test/data/bindings/browser-duk.bnd @@ -147,8 +147,18 @@ fini Node() dom_node_unref(priv->node); %} -method Node::AppendChild() +method Node::appendChild() %{ + if (!dukky_instanceof(ctx, PROTO_NAME(NODE))) return 0; + + DUKKY_SAFE_GET_ANOTHER(other,node,0); + + dom_exception err; + dom_node *spare; + + err = dom_node_append_child(priv->node, other->node, &spare); + if (err != DOM_NO_ERR) return 0; + dom_node_unref(spare); %} getter Node::aprop() -- cgit v1.2.3 From cb23f1f911523752db095781d0d5fa3e334f1aa5 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 29 Jul 2015 00:08:08 +0100 Subject: Add property generation and add it to prototype construction --- src/duk-libdom.c | 235 +++++++++++++++++++++----------- src/interface-map.c | 266 +++++++++++++++++++++++++++++++++---- src/interface-map.h | 23 +++- src/nsgenbind-ast.c | 63 +++++++++ src/nsgenbind-ast.h | 52 +++++++- src/webidl-ast.c | 14 +- src/webidl-ast.h | 5 +- src/webidl-parser.y | 2 +- test/data/bindings/browser-duk.bnd | 17 ++- 9 files changed, 556 insertions(+), 121 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index d1af70c..f7a1a5f 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -97,68 +97,6 @@ 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; -} - -/** - * find method by type on class with a specific ident - */ -static struct genbind_node * -find_class_method_ident(struct genbind_node *node, - struct genbind_node *prev, - enum genbind_node_type nodetype, - char *ident) -{ - struct genbind_node *res_node; - char *method_ident; - - res_node = find_class_method(node, prev, nodetype); - while (res_node != NULL) { - method_ident = genbind_node_gettext( - genbind_node_find_type( - genbind_node_getnode(res_node), - NULL, - GENBIND_NODE_TYPE_IDENT)); - if ((method_ident != NULL) && strcmp(ident, method_ident) == 0) { - break; - } - - res_node = find_class_method(node, res_node, nodetype); - } - return res_node; -} - /** * output character data of node of given type. * @@ -291,14 +229,14 @@ output_interface_inherit_init(FILE* outf, } /* find the initialisor method on the class (if any) */ - init_node = find_class_method(interfacee->class, - NULL, - GENBIND_METHOD_TYPE_INIT); + init_node = genbind_node_find_method(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_INIT); - inh_init_node = find_class_method(inherite->class, - NULL, - GENBIND_METHOD_TYPE_INIT); + inh_init_node = genbind_node_find_method(inherite->class, + NULL, + GENBIND_METHOD_TYPE_INIT); @@ -380,9 +318,9 @@ output_interface_init(FILE* outf, int res; /* find the initialisor method on the class (if any) */ - init_node = find_class_method(interfacee->class, - NULL, - GENBIND_METHOD_TYPE_INIT); + init_node = genbind_node_find_method(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_INIT); /* initialisor definition */ fprintf(outf, @@ -438,9 +376,9 @@ output_interface_fini(FILE* outf, struct genbind_node *fini_node; /* find the finaliser method on the class (if any) */ - fini_node = find_class_method(interfacee->class, - NULL, - GENBIND_METHOD_TYPE_FINI); + fini_node = genbind_node_find_method(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_FINI); /* finaliser definition */ fprintf(outf, @@ -530,7 +468,6 @@ output_set_constructor(FILE* outf, char *class_name, int idx, int argc) static int output_add_method(FILE* outf, char *class_name, char *method, int argc) { - //#define DUKKY_ADD_METHOD(klass,meth,nargs) fprintf(outf, "\t/* Add a method */\n"); fprintf(outf, "\tduk_dup(ctx, 0);\n"); fprintf(outf, "\tduk_push_string(ctx, %s);\n", method); @@ -653,6 +590,79 @@ output_prototype_methods(FILE *outf, struct interface_map_entry *interfacee) } +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); + fprintf(outf, "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\n"); + fprintf(outf, "\t DUK_DEFPROP_HAVE_SETTER |\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; +} + +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); + fprintf(outf, + "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\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; +} + +static int +output_prototype_attribute(FILE *outf, + struct interface_map_entry *interfacee, + struct interface_map_attribute_entry *attributee) +{ + if (attributee->modifier == WEBIDL_TYPE_MODIFIER_READONLY) { + return output_populate_ro_property(outf, + interfacee->class_name, + attributee->name); + } else { + return output_populate_rw_property(outf, + interfacee->class_name, + attributee->name); + } +} + +/** + * generate prototype attribute definitions + */ +static int +output_prototype_attributes(FILE *outf, struct interface_map_entry *interfacee) +{ + int attrc; + + for (attrc = 0; attrc < interfacee->attributec; attrc++) { + output_prototype_attribute(outf, + interfacee, + interfacee->attributev + attrc); + } + + return 0; + +} + /** * generate the interface prototype creator */ @@ -678,6 +688,9 @@ output_interface_prototype(FILE* outf, /* generate setting of methods */ output_prototype_methods(outf, interfacee); + /* generate setting of attributes */ + output_prototype_attributes(outf, interfacee); + /* generate setting of destructor */ output_set_destructor(outf, interfacee->class_name, 0); @@ -727,10 +740,10 @@ output_interface_operation(FILE* outf, NULL, WEBIDL_NODE_TYPE_IDENT)); - method_node = find_class_method_ident(interfacee->class, - NULL, - GENBIND_METHOD_TYPE_METHOD, - op_name); + method_node = genbind_node_find_method_ident(interfacee->class, + NULL, + GENBIND_METHOD_TYPE_METHOD, + op_name); /* method definition */ fprintf(outf, @@ -747,7 +760,6 @@ output_interface_operation(FILE* outf, fprintf(outf, "}\n\n"); return 0; - } /** @@ -795,6 +807,68 @@ output_interface_operations(FILE* outf, struct interface_map_entry *interfacee) return 0; } +/** + * Generate class property getter/setter for a single attribute + */ +static int +output_interface_attribute(FILE* outf, + struct interface_map_entry *interfacee, + struct interface_map_attribute_entry *atributee) +{ + /* 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); + + output_cdata(outf, atributee->getter, GENBIND_NODE_TYPE_CDATA); + + 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); + + output_cdata(outf, atributee->setter, GENBIND_NODE_TYPE_CDATA); + + 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 interface_map_entry *interfacee) +{ + int attrc; + + for (attrc = 0; attrc < interfacee->attributec; attrc++) { + output_interface_attribute(outf, + interfacee, + interfacee->attributev + attrc); + } + + return 0; +} + /** * generate a source file to implement an interface using duk and libdom. */ @@ -866,6 +940,7 @@ static int output_interface(struct genbind_node *genbind, output_interface_operations(ifacef, interfacee); /* attributes */ + output_interface_attributes(ifacef, interfacee); /* prototype */ output_interface_prototype(ifacef, interfacee, inherite); diff --git a/src/interface-map.c b/src/interface-map.c index 44ece42..6a77b6a 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -110,8 +110,10 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) dstinf[idx].name = srcinf[inf].name; dstinf[idx].node = srcinf[inf].node; dstinf[idx].inherit_name = srcinf[inf].inherit_name; - dstinf[idx].operations = srcinf[inf].operations; - dstinf[idx].attributes = srcinf[inf].attributes; + dstinf[idx].operationc = srcinf[inf].operationc; + dstinf[idx].operationv = srcinf[inf].operationv; + dstinf[idx].attributec = srcinf[inf].attributec; + dstinf[idx].attributev = srcinf[inf].attributev; dstinf[idx].class = srcinf[inf].class; /* reduce refcount on inherit index if !=-1 */ @@ -126,6 +128,180 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) return dstinf; } +static int +operation_map_new(struct webidl_node *interface, + struct genbind_node *class, + int *operationc_out, + struct interface_map_operation_entry **operationv_out) +{ + struct webidl_node *list_node; + struct webidl_node *op_node; /* attribute node */ + struct interface_map_operation_entry *cure; /* current entry */ + struct interface_map_operation_entry *operationv; + int operationc; + + /* enumerate operationss */ + operationc = enumerate_interface_type(interface, + WEBIDL_NODE_TYPE_OPERATION); + *operationc_out = operationc; + + if (operationc < 1) { + *operationv_out = NULL; /* no operations so empty map */ + return 0; + } + + operationv = calloc(operationc, + sizeof(struct interface_map_operation_entry)); + if (operationv == NULL) { + return -1; + }; + cure = operationv; + + /* iterate each list node within the interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(interface), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (list_node != NULL) { + /* iterate through operations on list */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_OPERATION); + + while (op_node != NULL) { + cure->node = op_node; + + cure->name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(op_node), + NULL, + WEBIDL_NODE_TYPE_IDENT)); + + cure->method = genbind_node_find_method_ident( + class, + NULL, + GENBIND_METHOD_TYPE_METHOD, + cure->name); + + cure++; + + /* move to next operation */ + op_node = webidl_node_find_type( + webidl_node_getnode(list_node), + op_node, + WEBIDL_NODE_TYPE_OPERATION); + } + + list_node = webidl_node_find_type( + webidl_node_getnode(interface), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + *operationv_out = operationv; /* resulting operations map */ + + return 0; +} + +static int +attribute_map_new(struct webidl_node *interface, + struct genbind_node *class, + int *attributec_out, + struct interface_map_attribute_entry **attributev_out) +{ + struct webidl_node *list_node; + struct webidl_node *at_node; /* attribute node */ + struct interface_map_attribute_entry *cure; /* current entry */ + struct interface_map_attribute_entry *attributev; + int attributec; + + /* enumerate attributes */ + attributec = enumerate_interface_type(interface, + WEBIDL_NODE_TYPE_ATTRIBUTE); + *attributec_out = attributec; + + if (attributec < 1) { + *attributev_out = NULL; /* no attributes so empty map */ + return 0; + } + + attributev = calloc(attributec, + sizeof(struct interface_map_attribute_entry)); + if (attributev == NULL) { + return -1; + }; + cure = attributev; + + /* iterate each list node within the interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(interface), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (list_node != NULL) { + /* iterate through attributes on list */ + at_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_ATTRIBUTE); + + while (at_node != NULL) { + enum webidl_type_modifier *modifier; + + cure->node = at_node; + + cure->name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(at_node), + NULL, + WEBIDL_NODE_TYPE_IDENT)); + + cure->getter = genbind_node_find_method_ident( + class, + NULL, + GENBIND_METHOD_TYPE_GETTER, + cure->name); + + /* check fo readonly attributes */ + modifier = (enum webidl_type_modifier *)webidl_node_getint( + webidl_node_find_type( + webidl_node_getnode(at_node), + NULL, + WEBIDL_NODE_TYPE_MODIFIER)); + if ((modifier != NULL) && + (*modifier == WEBIDL_TYPE_MODIFIER_READONLY)) { + cure->modifier = WEBIDL_TYPE_MODIFIER_READONLY; + } else { + cure->modifier = WEBIDL_TYPE_MODIFIER_NONE; + cure->setter = genbind_node_find_method_ident( + class, + NULL, + GENBIND_METHOD_TYPE_SETTER, + cure->name); + } + + cure++; + + /* move to next attribute */ + at_node = webidl_node_find_type( + webidl_node_getnode(list_node), + at_node, + WEBIDL_NODE_TYPE_ATTRIBUTE); + } + + list_node = webidl_node_find_type( + webidl_node_getnode(interface), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + *attributev_out = attributev; /* resulting attributes map */ + + return 0; +} + int interface_map_new(struct genbind_node *genbind, struct webidl_node *webidl, struct interface_map **index_out) @@ -162,7 +338,7 @@ int interface_map_new(struct genbind_node *genbind, webidl_node_find_type( webidl_node_getnode(node), NULL, - GENBIND_NODE_TYPE_IDENT)); + WEBIDL_NODE_TYPE_IDENT)); /* name of the inherited interface (if any) */ ecur->inherit_name = webidl_node_gettext( @@ -171,20 +347,22 @@ int interface_map_new(struct genbind_node *genbind, NULL, WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); - - /* enumerate the number of operations */ - ecur->operations = enumerate_interface_type(node, - WEBIDL_NODE_TYPE_OPERATION); - - /* enumerate the number of attributes */ - ecur->attributes = enumerate_interface_type(node, - WEBIDL_NODE_TYPE_ATTRIBUTE); - - /* matching class from binding */ ecur->class = genbind_node_find_type_ident(genbind, NULL, GENBIND_NODE_TYPE_CLASS, ecur->name); + /* enumerate and map the interface operations */ + operation_map_new(node, + ecur->class, + &ecur->operationc, + &ecur->operationv); + + /* enumerate and map the interface attributes */ + attribute_map_new(node, + ecur->class, + &ecur->attributec, + &ecur->attributev); + /* move to next interface */ node = webidl_node_find_type(webidl, node, WEBIDL_NODE_TYPE_INTERFACE); @@ -218,27 +396,68 @@ int interface_map_dump(struct interface_map *index) FILE *dumpf; int eidx; struct interface_map_entry *ecur; - const char *inherit_name; /* only dump AST to file if required */ if (!options->debug) { return 0; } - dumpf = genb_fopen("interface-index", "w"); + dumpf = genb_fopen("interface-map", "w"); if (dumpf == NULL) { return 2; } ecur = index->entries; for (eidx = 0; eidx < index->entryc; eidx++) { - inherit_name = ecur->inherit_name; - if (inherit_name == NULL) { - inherit_name = ""; - } - fprintf(dumpf, "%d %s %s i:%d a:%d %p\n", eidx, ecur->name, - inherit_name, ecur->operations, ecur->attributes, - ecur->class); + fprintf(dumpf, "%d %s\n", eidx, ecur->name); + if (ecur->inherit_name != NULL) { + fprintf(dumpf, " inherit:%s\n", ecur->inherit_name); + } + if (ecur->class != NULL) { + fprintf(dumpf, " class:%p\n", ecur->class); + } + if (ecur->operationc > 0) { + int opc = ecur->operationc; + struct interface_map_operation_entry *ope; + + fprintf(dumpf, " %d operations\n", + ecur->operationc); + + ope = ecur->operationv; + while (ope != NULL) { + fprintf(dumpf, " %s %p\n", + ope->name, ope->method); + ope++; + opc--; + if (opc == 0) { + break; + } + } + + } + if (ecur->attributec > 0) { + int attrc = ecur->attributec; + struct interface_map_attribute_entry *attre; + + fprintf(dumpf, " %d attributes\n", attrc); + + attre = ecur->attributev; + while (attre != NULL) { + fprintf(dumpf, " %s %p", + attre->name, + attre->getter); + if (attre->modifier == WEBIDL_TYPE_MODIFIER_NONE) { + fprintf(dumpf, " %p\n", attre->setter); + } else { + fprintf(dumpf, "\n"); + } + attre++; + attrc--; + if (attrc == 0) { + break; + } + } + } ecur++; } @@ -269,7 +488,8 @@ int interface_map_dumpdot(struct interface_map *index) for (eidx = 0; eidx < index->entryc; eidx++) { if (ecur->class != NULL) { /* interfaces bound to a class are shown in blue */ - fprintf(dumpf, "%04d [label=\"%s\" fontcolor=\"blue\"];\n", eidx, ecur->name); + fprintf(dumpf, "%04d [label=\"%s\" fontcolor=\"blue\"];\n", + eidx, ecur->name); } else { fprintf(dumpf, "%04d [label=\"%s\"];\n", eidx, ecur->name); } diff --git a/src/interface-map.h b/src/interface-map.h index 7373580..9d66dfb 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -12,12 +12,31 @@ struct genbind_node; struct webidl_node; +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) */ +}; + +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 interface_map_entry { const char *name; /** interface name */ struct webidl_node *node; /**< AST interface node */ const char *inherit_name; /**< Name of interface inhertited from */ - int operations; /**< number of operations on interface */ - int attributes; /**< number of attributes on interface */ + + int operationc; /**< number of operations on interface */ + struct interface_map_operation_entry *operationv; + + int attributec; /**< number of attributes on interface */ + struct interface_map_attribute_entry *attributev; + int inherit_idx; /**< index into map of inherited interface or -1 for * not in map */ diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index c1acee1..28326aa 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -288,6 +288,69 @@ genbind_node_find_type_type(struct genbind_node *node, return found_node; } + +/* exported interface documented in nsgenbind-ast.h */ +struct genbind_node * +genbind_node_find_method(struct genbind_node *node, + struct genbind_node *prev, + enum genbind_method_type methodtype) +{ + 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_method_type *type; + + type_node = genbind_node_find_type( + genbind_node_getnode(res_node), + NULL, GENBIND_NODE_TYPE_METHOD_TYPE); + + type = (enum genbind_method_type *)genbind_node_getint(type_node); + if (*type == methodtype) { + break; + } + + res_node = genbind_node_find_type( + genbind_node_getnode(node), + res_node, GENBIND_NODE_TYPE_METHOD); + } + + return res_node; +} + + +/* exported interface documented in nsgenbind-ast.h */ +struct genbind_node * +genbind_node_find_method_ident(struct genbind_node *node, + struct genbind_node *prev, + enum genbind_method_type nodetype, + const char *ident) +{ + struct genbind_node *res_node; + char *method_ident; + + res_node = genbind_node_find_method(node, prev, nodetype); + while (res_node != NULL) { + method_ident = genbind_node_gettext( + genbind_node_find_type( + genbind_node_getnode(res_node), + NULL, + GENBIND_NODE_TYPE_IDENT)); + if ((method_ident != NULL) && + strcmp(ident, method_ident) == 0) { + break; + } + + res_node = genbind_node_find_method(node, res_node, nodetype); + } + return res_node; +} + + +/* exported interface documented in nsgenbind-ast.h */ int genbind_cmp_node_type(struct genbind_node *node, void *ctx) { if (node->type == (enum genbind_node_type)ctx) diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index 9c564b9..0b0fcfd 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -101,7 +101,8 @@ genbind_node_find(struct genbind_node *node, genbind_callback_t *cb, void *ctx); -/** Depth first left hand search returning nodes of the specified type +/** + * Depth first left hand search returning nodes of the specified type * * @param node The node to start the search from * @param prev The node at which to stop the search, either NULL to @@ -115,7 +116,8 @@ genbind_node_find_type(struct genbind_node *node, struct genbind_node *prev, enum genbind_node_type nodetype); -/** count how many nodes of a specified type. +/** + * count how many nodes of a specified type. * * Enumerate how many nodes of the specified type there are by * performing a depth first search for nodes of the given type and @@ -129,7 +131,9 @@ int genbind_node_enumerate_type(struct genbind_node *node, enum genbind_node_type type); -/** Depth first left hand search returning nodes of the specified type + +/** + * Depth first left hand search returning nodes of the specified type * with an ident child node with matching text * * @param node The node to start the search from @@ -145,7 +149,9 @@ genbind_node_find_type_ident(struct genbind_node *node, enum genbind_node_type nodetype, const char *ident); -/** Returning node of the specified type with a GENBIND_NODE_TYPE_TYPE + +/** + * Returning node of the specified type with a GENBIND_NODE_TYPE_TYPE * subnode with matching text. * * This is a conveniance wrapper around nested calls to @@ -167,7 +173,43 @@ genbind_node_find_type_type(struct genbind_node *node, enum genbind_node_type nodetype, const char *type_text); -/** Iterate all nodes of a certian type from a node with a callback. + +/** + * Find a method node of a given method type + * + * \param node A node of type GENBIND_NODE_TYPE_CLASS to search for methods. + * \param prev The node at which to stop the search, either NULL to + * search the full tree depth (initial search) or the result + * of a previous search to continue. + * \param methodtype The type of method to find. + * \return A node of type GENBIND_NODE_TYPE_METHOD on success or NULL on faliure + */ +struct genbind_node * +genbind_node_find_method(struct genbind_node *node, + struct genbind_node *prev, + enum genbind_method_type methodtype); + + +/** + * Find a method node of a given method type and identifier + * + * \param node A node of type GENBIND_NODE_TYPE_CLASS to search for methods. + * \param prev The node at which to stop the search, either NULL to + * search the full tree depth (initial search) or the result + * of a previous search to continue. + * \param methodtype The type of method to find. + * \param ident The identifier to search for + * \return A node of type GENBIND_NODE_TYPE_METHOD on success or NULL on faliure + */ +struct genbind_node * +genbind_node_find_method_ident(struct genbind_node *node, + struct genbind_node *prev, + enum genbind_method_type methodtype, + const char *ident); + + +/** + * Iterate all nodes of a certian type from a node with a callback. * * Depth first search for nodes of the given type calling the callback * with context. diff --git a/src/webidl-ast.c b/src/webidl-ast.c index 6c24c41..75f969b 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -277,7 +277,7 @@ char *webidl_node_gettext(struct webidl_node *node) } /* exported interface defined in webidl-ast.h */ -int +int * webidl_node_getint(struct webidl_node *node) { if (node != NULL) { @@ -285,14 +285,13 @@ webidl_node_getint(struct webidl_node *node) case WEBIDL_NODE_TYPE_MODIFIER: case WEBIDL_NODE_TYPE_TYPE_BASE: case WEBIDL_NODE_TYPE_LITERAL_INT: - return node->r.number; + return &node->r.number; default: break; } } - return -1; - + return NULL; } /* exported interface defined in webidl-ast.h */ @@ -400,6 +399,7 @@ static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent) { const char *SPACES=" "; char *txt; + int *value; while (node != NULL) { fprintf(dumpf, "%.*s%s", indent, SPACES, webidl_node_type_to_str(node->type)); @@ -415,8 +415,10 @@ static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent) webidl_ast_dump(dumpf, next, indent + 2); } else { /* not txt or node has to be an int */ - fprintf(dumpf, ": %d\n", - webidl_node_getint(node)); + value = webidl_node_getint(node); + if (value != NULL) { + fprintf(dumpf, ": %d\n", *value); + } } } else { fprintf(dumpf, ": \"%s\"\n", txt); diff --git a/src/webidl-ast.h b/src/webidl-ast.h index 5d0cbc0..38968f3 100644 --- a/src/webidl-ast.h +++ b/src/webidl-ast.h @@ -62,9 +62,10 @@ enum webidl_type { }; enum webidl_type_modifier { + WEBIDL_TYPE_MODIFIER_NONE, WEBIDL_TYPE_MODIFIER_UNSIGNED, WEBIDL_TYPE_MODIFIER_UNRESTRICTED, - WEBIDL_TYPE_READONLY, + WEBIDL_TYPE_MODIFIER_READONLY, }; struct webidl_node; @@ -86,7 +87,7 @@ struct webidl_node *webidl_node_add(struct webidl_node *node, struct webidl_node /* node contents acessors */ char *webidl_node_gettext(struct webidl_node *node); struct webidl_node *webidl_node_getnode(struct webidl_node *node); -int webidl_node_getint(struct webidl_node *node); +int *webidl_node_getint(struct webidl_node *node); enum webidl_node_type webidl_node_gettype(struct webidl_node *node); /* node searches */ diff --git a/src/webidl-parser.y b/src/webidl-parser.y index 9717b8c..a48f3fd 100644 --- a/src/webidl-parser.y +++ b/src/webidl-parser.y @@ -689,7 +689,7 @@ Attribute: /* deal with readonly modifier */ if ($2) { - attribute = webidl_node_new(WEBIDL_NODE_TYPE_MODIFIER, attribute, (void *)WEBIDL_TYPE_READONLY); + attribute = webidl_node_new(WEBIDL_NODE_TYPE_MODIFIER, attribute, (void *)WEBIDL_TYPE_MODIFIER_READONLY); } $$ = webidl_node_new(WEBIDL_NODE_TYPE_ATTRIBUTE, NULL, attribute); diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd index 0ddfa02..513ad99 100644 --- a/test/data/bindings/browser-duk.bnd +++ b/test/data/bindings/browser-duk.bnd @@ -161,10 +161,23 @@ method Node::appendChild() dom_node_unref(spare); %} -getter Node::aprop() +getter Node::textContent() %{ + dom_exception exc; + dom_string *content; + + exc = dom_node_get_text_content(priv->node, &content); + if (exc != DOM_NO_ERR) { + return 0; + } + + if (content != NULL) { + duk_push_lstring(ctx, dom_string_data(content), dom_string_length(content)); + dom_string_unref(content); + return 1; + } %} -setter Node::aprop() +setter Node::textContent() %{ %} -- cgit v1.2.3 From 0c5f196017056b257c4c5a28338f90ada379310a Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 29 Jul 2015 16:22:36 +0100 Subject: Generate constant values on the class prototype --- src/duk-libdom.c | 51 +++++++++++++++++++++++++++++ src/interface-map.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/interface-map.h | 13 ++++++++ 3 files changed, 156 insertions(+) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index f7a1a5f..00f1bbc 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -663,6 +663,54 @@ output_prototype_attributes(FILE *outf, struct interface_map_entry *interfacee) } +/** + * 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 interface_map_entry *interfacee, + struct interface_map_constant_entry *constante) +{ + int *value; + + value = webidl_node_getint( + webidl_node_find_type( + webidl_node_getnode(constante->node), + NULL, + WEBIDL_NODE_TYPE_LITERAL_INT)); + + + fprintf(outf, "\tduk_dup(ctx, 0);\n"); + fprintf(outf, "\tduk_push_string(ctx, \"%s\");\n", constante->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 prototype constant definitions + */ +static int +output_prototype_constants(FILE *outf, struct interface_map_entry *interfacee) +{ + int attrc; + + for (attrc = 0; attrc < interfacee->constantc; attrc++) { + output_prototype_constant(outf, + interfacee, + interfacee->constantv + attrc); + } + + return 0; + +} + /** * generate the interface prototype creator */ @@ -691,6 +739,9 @@ output_interface_prototype(FILE* outf, /* generate setting of attributes */ output_prototype_attributes(outf, interfacee); + /* generate setting of constants */ + output_prototype_constants(outf, interfacee); + /* generate setting of destructor */ output_set_destructor(outf, interfacee->class_name, 0); diff --git a/src/interface-map.c b/src/interface-map.c index 6a77b6a..2ac1871 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -114,6 +114,8 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) dstinf[idx].operationv = srcinf[inf].operationv; dstinf[idx].attributec = srcinf[inf].attributec; dstinf[idx].attributev = srcinf[inf].attributev; + dstinf[idx].constantc = srcinf[inf].constantc; + dstinf[idx].constantv = srcinf[inf].constantv; dstinf[idx].class = srcinf[inf].class; /* reduce refcount on inherit index if !=-1 */ @@ -302,6 +304,78 @@ attribute_map_new(struct webidl_node *interface, return 0; } +static int +constant_map_new(struct webidl_node *interface, + int *constantc_out, + struct interface_map_constant_entry **constantv_out) +{ + struct webidl_node *list_node; + struct webidl_node *constant_node; /* constant node */ + struct interface_map_constant_entry *cure; /* current entry */ + struct interface_map_constant_entry *constantv; + int constantc; + + /* enumerate constants */ + constantc = enumerate_interface_type(interface, + WEBIDL_NODE_TYPE_CONST); + + if (constantc < 1) { + *constantc_out = 0; + *constantv_out = NULL; /* no constants so empty map */ + return 0; + } + + *constantc_out = constantc; + + constantv = calloc(constantc, + sizeof(struct interface_map_constant_entry)); + if (constantv == NULL) { + return -1; + }; + cure = constantv; + + /* iterate each list node within the interface */ + list_node = webidl_node_find_type( + webidl_node_getnode(interface), + NULL, + WEBIDL_NODE_TYPE_LIST); + + while (list_node != NULL) { + /* iterate through constants on list */ + constant_node = webidl_node_find_type( + webidl_node_getnode(list_node), + NULL, + WEBIDL_NODE_TYPE_CONST); + + while (constant_node != NULL) { + cure->node = constant_node; + + cure->name = webidl_node_gettext( + webidl_node_find_type( + webidl_node_getnode(constant_node), + NULL, + WEBIDL_NODE_TYPE_IDENT)); + + cure++; + + /* move to next constant */ + constant_node = webidl_node_find_type( + webidl_node_getnode(list_node), + constant_node, + WEBIDL_NODE_TYPE_CONST); + } + + list_node = webidl_node_find_type( + webidl_node_getnode(interface), + list_node, + WEBIDL_NODE_TYPE_LIST); + } + + *constantv_out = constantv; /* resulting constants map */ + + return 0; +} + int interface_map_new(struct genbind_node *genbind, struct webidl_node *webidl, struct interface_map **index_out) @@ -363,6 +437,11 @@ int interface_map_new(struct genbind_node *genbind, &ecur->attributec, &ecur->attributev); + /* enumerate and map the interface constants */ + constant_map_new(node, + &ecur->constantc, + &ecur->constantv); + /* move to next interface */ node = webidl_node_find_type(webidl, node, WEBIDL_NODE_TYPE_INTERFACE); @@ -458,6 +537,19 @@ int interface_map_dump(struct interface_map *index) } } } + if (ecur->constantc > 0) { + int idx; + + fprintf(dumpf, " %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", + cone->name); + } + } ecur++; } diff --git a/src/interface-map.h b/src/interface-map.h index 9d66dfb..8ce6c01 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -12,12 +12,14 @@ struct genbind_node; struct webidl_node; +/** 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) */ }; +/** map entry for attributes on an interface */ struct interface_map_attribute_entry { const char *name; /** attribute name */ struct webidl_node *node; /**< AST attribute node */ @@ -26,6 +28,13 @@ struct interface_map_attribute_entry { struct genbind_node *setter; /**< getter from binding (if any) */ }; +/** map entry for constants on an interface */ +struct interface_map_constant_entry { + const char *name; /** attribute name */ + struct webidl_node *node; /**< AST constant node */ +}; + +/** map entry for an interface */ struct interface_map_entry { const char *name; /** interface name */ struct webidl_node *node; /**< AST interface node */ @@ -37,6 +46,9 @@ struct interface_map_entry { int attributec; /**< number of attributes on interface */ struct interface_map_attribute_entry *attributev; + int constantc; /**< number of constants on interface */ + struct interface_map_constant_entry *constantv; + int inherit_idx; /**< index into map of inherited interface or -1 for * not in map */ @@ -62,6 +74,7 @@ struct interface_map_entry { */ }; +/** WebIDL interface map */ struct interface_map { int entryc; /**< count of interfaces */ struct interface_map_entry *entries; -- cgit v1.2.3 From 2976a0e461da9777b23851eb37e285cbf1b8d6b1 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 30 Jul 2015 13:33:43 +0100 Subject: Add generation of private header and cause class files to include it --- src/duk-libdom.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++-------- src/utils.c | 16 +++++++-- src/utils.h | 11 +++++++ 3 files changed, 110 insertions(+), 16 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 00f1bbc..e277eec 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -124,7 +124,7 @@ output_cdata(FILE* outf, */ static int output_duckky_create_private(FILE* outf, char *class_name) { - fprintf(outf, "\t/* create private data and attach to instance */"); + 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"); @@ -660,7 +660,6 @@ output_prototype_attributes(FILE *outf, struct interface_map_entry *interfacee) } return 0; - } /** @@ -671,8 +670,7 @@ output_prototype_attributes(FILE *outf, struct interface_map_entry *interfacee) */ static int output_prototype_constant(FILE *outf, - struct interface_map_entry *interfacee, - struct interface_map_constant_entry *constante) + struct interface_map_constant_entry *constante) { int *value; @@ -702,13 +700,10 @@ output_prototype_constants(FILE *outf, struct interface_map_entry *interfacee) int attrc; for (attrc = 0; attrc < interfacee->constantc; attrc++) { - output_prototype_constant(outf, - interfacee, - interfacee->constantv + attrc); + output_prototype_constant(outf, interfacee->constantv + attrc); } return 0; - } /** @@ -920,11 +915,20 @@ output_interface_attributes(FILE* outf, return 0; } +static int output_private_include(FILE* outf) +{ + char *fpath; + fpath = genb_fpath("private.h"); + + fprintf(outf, "\n#include \"%s\"\n", fpath); + + return 0; +} + /** * generate a source file to implement an interface using duk and libdom. */ static int output_interface(struct genbind_node *genbind, - struct webidl_node *webidl, struct interface_map *interface_map, struct interface_map_entry *interfacee) { @@ -958,8 +962,9 @@ static int output_interface(struct genbind_node *genbind, /* binding preface */ output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PREFACE); - /* nsgenbind preamble */ + /* tool preface */ fprintf(ifacef, "\n%s\n", NSGENBIND_PREAMBLE); + output_private_include(ifacef); /* class preface */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE); @@ -1016,6 +1021,63 @@ op_error: return res; } +/** generate private header */ +static int +output_private_header(struct interface_map *interface_map) +{ + int idx; + FILE *privf; + + /* open output file */ + privf = genb_fopen("private.h", "w"); + if (privf == NULL) { + return -1; + } + + for (idx = 0; idx < interface_map->entryc; idx++) { + struct interface_map_entry *interfacee; + struct interface_map_entry *inherite; + struct genbind_node *priv_node; + + interfacee = interface_map->entries + idx; + + /* find parent interface entry */ + inherite = interface_map_inherit_entry(interface_map, + interfacee); + + fprintf(privf, "typedef struct {\n"); + if (inherite != NULL) { + fprintf(privf, "\t%s_private_t parent;\n", + inherite->class_name); + } + + /* for each private variable on the class output it here. */ + priv_node = genbind_node_find_type( + genbind_node_getnode(interfacee->class), + NULL, + GENBIND_NODE_TYPE_PRIVATE); + while (priv_node != NULL) { + fprintf(privf, "\t"); + output_cdata(privf, priv_node, GENBIND_NODE_TYPE_TYPE); + output_cdata(privf, priv_node, GENBIND_NODE_TYPE_IDENT); + fprintf(privf, ";\n"); + + priv_node = genbind_node_find_type( + genbind_node_getnode(interfacee->class), + priv_node, + GENBIND_NODE_TYPE_PRIVATE); + } + + fprintf(privf, "} %s_private_t;\n\n", interfacee->class_name); + + } + + + fclose(privf); + + return 0; +} + int duk_libdom_output(struct genbind_node *genbind, struct webidl_node *webidl, struct interface_map *interface_map) @@ -1025,18 +1087,27 @@ int duk_libdom_output(struct genbind_node *genbind, /* generate interfaces */ for (idx = 0; idx < interface_map->entryc; idx++) { - res = output_interface(genbind, webidl, interface_map, - &interface_map->entries[idx]); + res = output_interface(genbind, + interface_map, + interface_map->entries + idx); if (res != 0) { - break; + goto output_err; } } - /* generate header */ + /* generate private header */ + res = output_private_header(interface_map); + if (res != 0) { + goto output_err; + } + + + /* generate prototype header */ /** \todo implement header */ /* generate makefile fragment */ /** \todo implement makefile generation */ +output_err: return res; } diff --git a/src/utils.c b/src/utils.c index 7bab058..9e50a93 100644 --- a/src/utils.c +++ b/src/utils.c @@ -7,16 +7,27 @@ #include "options.h" #include "utils.h" -FILE *genb_fopen(const char *fname, const char *mode) +/* exported function documented in utils.h */ +char *genb_fpath(const char *fname) { char *fpath; int fpathl; - FILE *filef; fpathl = strlen(options->outdirname) + strlen(fname) + 2; fpath = malloc(fpathl); snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname); + return fpath; +} + +/* exported function documented in utils.h */ +FILE *genb_fopen(const char *fname, const char *mode) +{ + char *fpath; + FILE *filef; + + fpath = genb_fpath(fname); + filef = fopen(fpath, mode); if (filef == NULL) { fprintf(stderr, "Error: unable to open file %s (%s)\n", @@ -29,6 +40,7 @@ FILE *genb_fopen(const char *fname, const char *mode) return filef; } + #ifdef NEED_STRNDUP char *strndup(const char *s, size_t n) diff --git a/src/utils.h b/src/utils.h index 98a4c6b..b37d755 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,6 +9,17 @@ #ifndef nsgenbind_utils_h #define nsgenbind_utils_h +/** + * get a pathname with the output prefix prepended + * + * \param fname leaf filename. + * \return full prefixed path to file caller must free + */ +char *genb_fpath(const char *fname); + +/** + * Open file allowing for output path prefix + */ FILE *genb_fopen(const char *fname, const char *mode); #ifdef _WIN32 -- cgit v1.2.3 From 1fcab4d37de137bbc346e6ed82d92ed97f2024cf Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 30 Jul 2015 16:15:39 +0100 Subject: Generate prototype header and include it from each class source --- src/duk-libdom.c | 110 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 90 insertions(+), 20 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index e277eec..173d22f 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -309,20 +309,12 @@ output_interface_inherit_init(FILE* outf, } static int -output_interface_init(FILE* outf, - struct interface_map_entry *interfacee, - struct interface_map_entry *inherite) +output_interface_init_declaration(FILE* outf, + struct interface_map_entry *interfacee, + struct genbind_node *init_node) { - struct genbind_node *init_node; struct genbind_node *param_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 */ fprintf(outf, "void %s_%s___init(duk_context *ctx, %s_private_t *priv", DLPFX, interfacee->class_name, interfacee->class_name); @@ -345,7 +337,28 @@ output_interface_init(FILE* outf, param_node, GENBIND_NODE_TYPE_METHOD); } - fprintf(outf,")\n{\n"); + fprintf(outf,")"); + + return 0; +} + +static int +output_interface_init(FILE* outf, + struct interface_map_entry *interfacee, + struct interface_map_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); @@ -915,12 +928,22 @@ output_interface_attributes(FILE* outf, return 0; } -static int output_private_include(FILE* outf) +/** + * generate preface block for nsgenbind + */ +static int output_tool_preface(FILE* outf) { char *fpath; + + fprintf(outf, "\n%s\n\n", NSGENBIND_PREAMBLE); + fpath = genb_fpath("private.h"); + fprintf(outf, "#include \"%s\"\n", fpath); + free(fpath); - fprintf(outf, "\n#include \"%s\"\n", fpath); + fpath = genb_fpath("prototype.h"); + fprintf(outf, "#include \"%s\"\n", fpath); + free(fpath); return 0; } @@ -963,8 +986,7 @@ static int output_interface(struct genbind_node *genbind, output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PREFACE); /* tool preface */ - fprintf(ifacef, "\n%s\n", NSGENBIND_PREAMBLE); - output_private_include(ifacef); + output_tool_preface(ifacef); /* class preface */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE); @@ -1021,7 +1043,9 @@ op_error: return res; } -/** generate private header */ +/** + * generate private header + */ static int output_private_header(struct interface_map *interface_map) { @@ -1072,12 +1096,56 @@ output_private_header(struct interface_map *interface_map) } - fclose(privf); return 0; } +/** + * generate protottype header + */ +static int +output_prototype_header(struct interface_map *interface_map) +{ + int idx; + FILE *protof; + + /* open output file */ + protof = genb_fopen("prototype.h", "w"); + if (protof == NULL) { + return -1; + } + + for (idx = 0; idx < interface_map->entryc; idx++) { + struct interface_map_entry *interfacee; + struct genbind_node *init_node; + + interfacee = interface_map->entries + idx; + + /* prototype declaration */ + fprintf(protof, "duk_ret_t %s_%s___proto(duk_context *ctx);\n", + DLPFX, interfacee->class_name); + + /* finaliser declaration */ + fprintf(protof, + "void %s_%s___fini(duk_context *ctx, %s_private_t *priv);\n", + DLPFX, interfacee->class_name, interfacee->class_name); + + /* 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(protof, interfacee, init_node); + fprintf(protof, ";\n\n"); + } + + fclose(protof); + + return 0; +} + int duk_libdom_output(struct genbind_node *genbind, struct webidl_node *webidl, struct interface_map *interface_map) @@ -1101,9 +1169,11 @@ int duk_libdom_output(struct genbind_node *genbind, goto output_err; } - /* generate prototype header */ - /** \todo implement header */ + res = output_prototype_header(interface_map); + if (res != 0) { + goto output_err; + } /* generate makefile fragment */ /** \todo implement makefile generation */ -- cgit v1.2.3 From 4b723a410bc1a3355d401b95ac390f377b5d77b8 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 30 Jul 2015 17:28:06 +0100 Subject: Clean up code generation functions --- src/duk-libdom.c | 407 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 221 insertions(+), 186 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 173d22f..a883f7c 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -33,6 +33,207 @@ " * 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, PRIVATE_MAGIC)\n\n"); + + 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, PRIVATE_MAGIC);\n",idx); + 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 code that gets a prototype by name + */ +static int output_get_prototype(FILE* outf, const char *interface_name) +{ + char *proto_name; + int pnamelen; + + /* duplicate the interface name in upper case */ + pnamelen = strlen(interface_name) + 1; /* allow for null byte */ + proto_name = malloc(pnamelen); + for ( ; pnamelen >= 0; pnamelen--) { + proto_name[pnamelen] = toupper(interface_name[pnamelen]); + } + fprintf(outf, "\t/* get prototype */\n"); + fprintf(outf, "\tduk_get_global_string(ctx, PROTO_MAGIC);\n"); + fprintf(outf, "\tduk_get_prop_string(ctx, -1, PROTO_NAME(%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, INIT_MAGIC);\n"); + 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, char *class_name, char *method, int argc) +{ + 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, ", + 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"); + 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); + fprintf(outf, "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\n"); + fprintf(outf, "\t DUK_DEFPROP_HAVE_SETTER |\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 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); + fprintf(outf, + "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\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 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, PRIVATE_MAGIC);\n"); + fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n"); + fprintf(outf, "\tduk_pop_2(ctx);\n"); + fprintf(outf, "\tif (priv == NULL) return 0; /* can do? No can do. */\n\n"); + return 0; +} + /** * Generate a C class name for the interface. * @@ -118,35 +319,6 @@ output_cdata(FILE* outf, return 0; } -/** - * Output code to create a private structure - * - */ -static int output_duckky_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, 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 */ @@ -161,7 +333,7 @@ output_interface_constructor(FILE* outf, struct interface_map_entry *interfacee) DLPFX, interfacee->class_name); fprintf(outf,"{\n"); - output_duckky_create_private(outf, interfacee->class_name); + output_create_private(outf, interfacee->class_name); /* generate call to initialisor */ fprintf(outf, @@ -195,7 +367,7 @@ output_interface_destructor(FILE* outf, struct interface_map_entry *interfacee) DLPFX, interfacee->class_name); fprintf(outf,"{\n"); - output_ducky_safe_get_private(outf, interfacee->class_name, 0); + output_safe_get_private(outf, interfacee->class_name, 0); /* generate call to finaliser */ fprintf(outf, @@ -419,89 +591,6 @@ output_interface_fini(FILE* outf, return 0; } -/** - * generate code that gets a prototype by name - */ -static int output_get_prototype(FILE* outf, const char *interface_name) -{ - char *proto_name; - int pnamelen; - - /* duplicate the interface name in upper case */ - pnamelen = strlen(interface_name) + 1; /* allow for null byte */ - proto_name = malloc(pnamelen); - for ( ; pnamelen >= 0; pnamelen--) { - proto_name[pnamelen] = toupper(interface_name[pnamelen]); - } - fprintf(outf, "\t/* get prototype */\n"); - fprintf(outf, "\tduk_get_global_string(ctx, PROTO_MAGIC);\n"); - fprintf(outf, "\tduk_get_prop_string(ctx, -1, PROTO_NAME(%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, INIT_MAGIC);\n"); - fprintf(outf, "\tduk_pop(ctx);\n\n"); - - return 0; -} - -/** - * generate code that adds a method in a prototype - */ -static int -output_add_method(FILE* outf, char *class_name, char *method, int argc) -{ - 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, ", - DLPFX, class_name, method); - if (argc == -1) { - fprintf(outf, "DUK_VARARGS);\n"); - - } else { - fprintf(outf, "%d);\n", argc); - } - fprintf(outf, "\tDUKKY_DUMP_STACK(ctx);\n"); - 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; -} /** * count the number of arguments to an operation @@ -554,7 +643,6 @@ output_prototype_method(FILE* outf, output_add_method(outf, interfacee->class_name, op_name, op_argc); return 0; - } /** @@ -600,47 +688,8 @@ output_prototype_methods(FILE *outf, struct interface_map_entry *interfacee) } return 0; - } -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); - fprintf(outf, "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\n"); - fprintf(outf, "\t DUK_DEFPROP_HAVE_SETTER |\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; -} - -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); - fprintf(outf, - "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\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; -} static int output_prototype_attribute(FILE *outf, @@ -651,11 +700,10 @@ output_prototype_attribute(FILE *outf, return output_populate_ro_property(outf, interfacee->class_name, attributee->name); - } else { - return output_populate_rw_property(outf, - interfacee->class_name, - attributee->name); } + return output_populate_rw_property(outf, + interfacee->class_name, + attributee->name); } /** @@ -665,14 +713,17 @@ static int output_prototype_attributes(FILE *outf, struct interface_map_entry *interfacee) { int attrc; + int res = 0; for (attrc = 0; attrc < interfacee->attributec; attrc++) { - output_prototype_attribute(outf, - interfacee, - interfacee->attributev + attrc); + res = output_prototype_attribute(outf,interfacee, + interfacee->attributev + attrc); + if (res != 0) { + break; + } } - return 0; + return res; } /** @@ -693,14 +744,8 @@ output_prototype_constant(FILE *outf, NULL, WEBIDL_NODE_TYPE_LITERAL_INT)); + output_prototype_constant_int(outf, constante->name, *value); - fprintf(outf, "\tduk_dup(ctx, 0);\n"); - fprintf(outf, "\tduk_push_string(ctx, \"%s\");\n", constante->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; } @@ -711,12 +756,17 @@ static int output_prototype_constants(FILE *outf, struct interface_map_entry *interfacee) { int attrc; + int res = 0; for (attrc = 0; attrc < interfacee->constantc; attrc++) { - output_prototype_constant(outf, interfacee->constantv + attrc); + res = output_prototype_constant(outf, + interfacee->constantv + attrc); + if (res != 0) { + break; + } } - return 0; + return res; } /** @@ -766,21 +816,6 @@ output_interface_prototype(FILE* outf, 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, PRIVATE_MAGIC);\n"); - fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n"); - fprintf(outf, "\tduk_pop_2(ctx);\n"); - fprintf(outf, "\tif (priv == NULL) return 0; /* can do? No can do. */\n\n"); - return 0; -} /** * generate a single class method for an interface operation -- cgit v1.2.3 From 02ebfefd0fc3d81b59cc15f34033210a6344f430 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 31 Jul 2015 21:49:45 +0100 Subject: Generate makefile fragment and add header guards --- src/duk-libdom.c | 119 +++++++++++++++++++++++++++++++++++++++++++--------- src/duk-libdom.h | 4 +- src/interface-map.c | 21 ++++++---- src/interface-map.h | 13 +++++- src/nsgenbind.c | 4 +- 5 files changed, 126 insertions(+), 35 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index a883f7c..49f100a 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -968,12 +968,20 @@ output_interface_attributes(FILE* outf, */ static int output_tool_preface(FILE* outf) { - char *fpath; + fprintf(outf, "\n%s\n", NSGENBIND_PREAMBLE); - fprintf(outf, "\n%s\n\n", NSGENBIND_PREAMBLE); + return 0; +} + +/** + * generate preface block for nsgenbind + */ +static int output_tool_prologue(FILE* outf) +{ + char *fpath; fpath = genb_fpath("private.h"); - fprintf(outf, "#include \"%s\"\n", fpath); + fprintf(outf, "\n#include \"%s\"\n", fpath); free(fpath); fpath = genb_fpath("prototype.h"); @@ -986,13 +994,11 @@ static int output_tool_preface(FILE* outf) /** * generate a source file to implement an interface using duk and libdom. */ -static int output_interface(struct genbind_node *genbind, - struct interface_map *interface_map, +static int output_interface(struct interface_map *interface_map, struct interface_map_entry *interfacee) { FILE *ifacef; int ifacenamelen; - struct genbind_node *binding_node; struct interface_map_entry *inherite; int res = 0; @@ -1014,11 +1020,10 @@ static int output_interface(struct genbind_node *genbind, /* find parent interface entry */ inherite = interface_map_inherit_entry(interface_map, interfacee); - binding_node = genbind_node_find_type(genbind, NULL, - GENBIND_NODE_TYPE_BINDING); - /* binding preface */ - output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PREFACE); + output_cdata(ifacef, + interface_map->binding_node, + GENBIND_NODE_TYPE_PREFACE); /* tool preface */ output_tool_preface(ifacef); @@ -1027,7 +1032,11 @@ static int output_interface(struct genbind_node *genbind, output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE); /* binding prologue */ - output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_PROLOGUE); + output_cdata(ifacef, + interface_map->binding_node, + GENBIND_NODE_TYPE_PROLOGUE); + + output_tool_prologue(ifacef); /* class prologue */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PROLOGUE); @@ -1064,13 +1073,17 @@ static int output_interface(struct genbind_node *genbind, output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_EPILOGUE); /* binding epilogue */ - output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_EPILOGUE); + output_cdata(ifacef, + interface_map->binding_node, + GENBIND_NODE_TYPE_EPILOGUE); /* class postface */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_POSTFACE); /* binding postface */ - output_cdata(ifacef, binding_node, GENBIND_NODE_TYPE_POSTFACE); + output_cdata(ifacef, + interface_map->binding_node, + GENBIND_NODE_TYPE_POSTFACE); op_error: fclose(ifacef); @@ -1093,6 +1106,18 @@ output_private_header(struct interface_map *interface_map) return -1; } + /* binding preface */ + output_cdata(privf, + interface_map->binding_node, + GENBIND_NODE_TYPE_PREFACE); + + /* tool preface */ + output_tool_preface(privf); + + /* header guard */ + fprintf(privf, "\n#ifndef duk_libdom_private_h\n"); + fprintf(privf, "#define duk_libdom_private_h\n\n"); + for (idx = 0; idx < interface_map->entryc; idx++) { struct interface_map_entry *interfacee; struct interface_map_entry *inherite; @@ -1131,6 +1156,13 @@ output_private_header(struct interface_map *interface_map) } + /* binding postface */ + output_cdata(privf, + interface_map->binding_node, + GENBIND_NODE_TYPE_POSTFACE); + + fprintf(privf, "\n#endif\n"); + fclose(privf); return 0; @@ -1151,6 +1183,18 @@ output_prototype_header(struct interface_map *interface_map) return -1; } + /* binding preface */ + output_cdata(protof, + interface_map->binding_node, + GENBIND_NODE_TYPE_PREFACE); + + /* tool preface */ + output_tool_preface(protof); + + /* header guard */ + fprintf(protof, "\n#ifndef duk_libdom_prototype_h\n"); + fprintf(protof, "#define duk_libdom_prototype_h\n\n"); + for (idx = 0; idx < interface_map->entryc; idx++) { struct interface_map_entry *interfacee; struct genbind_node *init_node; @@ -1176,22 +1220,58 @@ output_prototype_header(struct interface_map *interface_map) fprintf(protof, ";\n\n"); } + /* binding postface */ + output_cdata(protof, + interface_map->binding_node, + GENBIND_NODE_TYPE_POSTFACE); + + fprintf(protof, "\n#endif\n"); + fclose(protof); return 0; } -int duk_libdom_output(struct genbind_node *genbind, - struct webidl_node *webidl, - struct interface_map *interface_map) +/** + * generate protottype header + */ +static int +output_makefile(struct interface_map *interface_map) +{ + int idx; + FILE *makef; + + /* open output file */ + makef = genb_fopen("Makefile", "w"); + if (makef == NULL) { + return -1; + } + + fprintf(makef, "# duk libdom makefile fragment\n\n"); + + fprintf(makef, "NSGENBIND_SOURCES:="); + for (idx = 0; idx < interface_map->entryc; idx++) { + struct interface_map_entry *interfacee; + + interfacee = interface_map->entries + idx; + + fprintf(makef, "%s ", interfacee->filename); + } + fprintf(makef, "\nNSGENBIND_PREFIX:=%s\n", options->outdirname); + + fclose(makef); + + return 0; +} + +int duk_libdom_output(struct interface_map *interface_map) { int idx; int res = 0; /* generate interfaces */ for (idx = 0; idx < interface_map->entryc; idx++) { - res = output_interface(genbind, - interface_map, + res = output_interface(interface_map, interface_map->entries + idx); if (res != 0) { goto output_err; @@ -1211,7 +1291,8 @@ int duk_libdom_output(struct genbind_node *genbind, } /* generate makefile fragment */ - /** \todo implement makefile generation */ + res = output_makefile(interface_map); + output_err: return res; diff --git a/src/duk-libdom.h b/src/duk-libdom.h index 8e86d74..e1dd2c4 100644 --- a/src/duk-libdom.h +++ b/src/duk-libdom.h @@ -9,8 +9,6 @@ #ifndef nsgenbind_duk_libdom_h #define nsgenbind_duk_libdom_h -int duk_libdom_output(struct genbind_node *genbind, - struct webidl_node *webidl, - struct interface_map *interface_map); +int duk_libdom_output(struct interface_map *interface_map); #endif diff --git a/src/interface-map.c b/src/interface-map.c index 2ac1871..13d6106 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -378,20 +378,20 @@ constant_map_new(struct webidl_node *interface, int interface_map_new(struct genbind_node *genbind, struct webidl_node *webidl, - struct interface_map **index_out) + struct interface_map **map_out) { int interfacec; struct interface_map_entry *entries; struct interface_map_entry *sorted_entries; struct interface_map_entry *ecur; struct webidl_node *node; - struct interface_map *index; + struct interface_map *map; interfacec = webidl_node_enumerate_type(webidl, WEBIDL_NODE_TYPE_INTERFACE); if (options->verbose) { - printf("Indexing %d interfaces\n", interfacec); + printf("Maping %d interfaces\n", interfacec); } entries = calloc(interfacec, sizeof(struct interface_map_entry)); @@ -399,12 +399,12 @@ int interface_map_new(struct genbind_node *genbind, return -1; } - /* for each interface populate an entry in the index */ + /* for each interface populate an entry in the map */ ecur = entries; node = webidl_node_find_type(webidl, NULL, WEBIDL_NODE_TYPE_INTERFACE); while (node != NULL) { - /* fill index entry */ + /* fill map entry */ ecur->node = node; /* name of interface */ @@ -461,11 +461,14 @@ int interface_map_new(struct genbind_node *genbind, /* compute inheritance and refcounts on sorted map */ compute_inherit_refcount(sorted_entries, interfacec); - index = malloc(sizeof(struct interface_map)); - index->entryc = interfacec; - index->entries = sorted_entries; + map = malloc(sizeof(struct interface_map)); + map->entryc = interfacec; + map->entries = sorted_entries; + map->webidl = webidl; + map->binding_node = genbind_node_find_type(genbind, NULL, + GENBIND_NODE_TYPE_BINDING); - *index_out = index; + *map_out = map; return 0; } diff --git a/src/interface-map.h b/src/interface-map.h index 8ce6c01..e44380a 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -77,12 +77,21 @@ struct interface_map_entry { /** WebIDL interface map */ struct interface_map { int entryc; /**< count of interfaces */ - struct interface_map_entry *entries; + struct interface_map_entry *entries; /**< interface entries */ + + /** The AST node of the binding information */ + struct genbind_node *binding_node; + + /** Root AST node of the webIDL */ + struct webidl_node *webidl; }; +/** + * Create a new interface map + */ int interface_map_new(struct genbind_node *genbind, struct webidl_node *webidl, - struct interface_map **index_out); + struct interface_map **map_out); int interface_map_dump(struct interface_map *map); diff --git a/src/nsgenbind.c b/src/nsgenbind.c index b3191ba..65feedd 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -207,7 +207,7 @@ int main(int argc, char **argv) /* debug dump of web idl AST */ webidl_dump_ast(webidl_root); - /* generate index of interfaces in idl sorted by inheritance */ + /* generate map of WebIDL interfaces sorted by inheritance */ res = interface_map_new(genbind_root, webidl_root, &interface_map); if (res != 0) { return 5; @@ -220,7 +220,7 @@ int main(int argc, char **argv) /* generate binding */ switch (bindingtype) { case BINDINGTYPE_DUK_LIBDOM: - res = duk_libdom_output(genbind_root, webidl_root, interface_map); + res = duk_libdom_output(interface_map); break; default: -- cgit v1.2.3 From cb2089531d4165786772c5cef17d28dc1a8e28d6 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 31 Jul 2015 22:32:12 +0100 Subject: ensure nothing is generated for interfaces marked with NoInterfaceObject --- src/duk-libdom.c | 26 +++++++++++++++++++++++++- src/interface-map.c | 34 +++++++++++++++++++++++++--------- src/interface-map.h | 17 +++++++++++------ 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 49f100a..590afa2 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -1002,7 +1002,12 @@ static int output_interface(struct interface_map *interface_map, struct interface_map_entry *inherite; int res = 0; - /* compute clas name */ + /* do not generate class for interfaces marked no output */ + if (interfacee->noobject) { + return 0; + } + + /* compute class name */ interfacee->class_name = gen_class_name(interfacee); /* generate source filename */ @@ -1125,6 +1130,13 @@ output_private_header(struct interface_map *interface_map) interfacee = interface_map->entries + idx; + /* do not generate private structs for interfaces marked no + * output + */ + if (interfacee->noobject) { + continue; + } + /* find parent interface entry */ inherite = interface_map_inherit_entry(interface_map, interfacee); @@ -1201,6 +1213,13 @@ output_prototype_header(struct interface_map *interface_map) interfacee = interface_map->entries + idx; + /* do not generate prototype declarations for interfaces marked + * no output + */ + if (interfacee->noobject) { + continue; + } + /* prototype declaration */ fprintf(protof, "duk_ret_t %s_%s___proto(duk_context *ctx);\n", DLPFX, interfacee->class_name); @@ -1255,6 +1274,11 @@ output_makefile(struct interface_map *interface_map) interfacee = interface_map->entries + idx; + /* no source for interfaces marked no output */ + if (interfacee->noobject) { + continue; + } + fprintf(makef, "%s ", interfacee->filename); } fprintf(makef, "\nNSGENBIND_PREFIX:=%s\n", options->outdirname); diff --git a/src/interface-map.c b/src/interface-map.c index 13d6106..467c0ed 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -110,6 +110,7 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) dstinf[idx].name = srcinf[inf].name; dstinf[idx].node = srcinf[inf].node; dstinf[idx].inherit_name = srcinf[inf].inherit_name; + dstinf[idx].noobject = srcinf[inf].noobject; dstinf[idx].operationc = srcinf[inf].operationc; dstinf[idx].operationv = srcinf[inf].operationv; dstinf[idx].attributec = srcinf[inf].attributec; @@ -391,7 +392,7 @@ int interface_map_new(struct genbind_node *genbind, WEBIDL_NODE_TYPE_INTERFACE); if (options->verbose) { - printf("Maping %d interfaces\n", interfacec); + printf("Mapping %d interfaces\n", interfacec); } entries = calloc(interfacec, sizeof(struct interface_map_entry)); @@ -421,6 +422,17 @@ int interface_map_new(struct genbind_node *genbind, NULL, WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); + if (webidl_node_find_type_ident( + webidl_node_getnode(node), + WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE, + "NoInterfaceObject") != NULL) { + /** \todo we should ensure inherit is unset as this + * cannot form part of an inheritance chain if it is + * not generating an output class + */ + ecur->noobject = true; + } + /* matching class from binding */ ecur->class = genbind_node_find_type_ident(genbind, NULL, GENBIND_NODE_TYPE_CLASS, ecur->name); @@ -579,16 +591,20 @@ int interface_map_dumpdot(struct interface_map *index) fprintf(dumpf, "digraph interfaces {\n"); + fprintf(dumpf, "node [shape=box]\n"); + ecur = index->entries; for (eidx = 0; eidx < index->entryc; eidx++) { - if (ecur->class != NULL) { - /* interfaces bound to a class are shown in blue */ - fprintf(dumpf, "%04d [label=\"%s\" fontcolor=\"blue\"];\n", - eidx, ecur->name); - } else { - fprintf(dumpf, "%04d [label=\"%s\"];\n", eidx, ecur->name); - } - ecur++; + fprintf(dumpf, "%04d [label=\"%s\"", eidx, ecur->name); + if (ecur->noobject == true) { + /* noobject interfaces in red */ + fprintf(dumpf, "fontcolor=\"red\""); + } else if (ecur->class != NULL) { + /* interfaces bound to a class are shown in blue */ + fprintf(dumpf, "fontcolor=\"blue\""); + } + fprintf(dumpf, "];\n"); + ecur++; } ecur = index->entries; diff --git a/src/interface-map.h b/src/interface-map.h index e44380a..e07aa19 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -39,6 +39,16 @@ struct interface_map_entry { const char *name; /** interface name */ struct webidl_node *node; /**< AST interface node */ const char *inherit_name; /**< Name of interface inhertited from */ + int inherit_idx; /**< index into map of inherited interface or -1 for + * not in map + */ + int refcount; /**< number of interfacess in map that refer to this + * interface + */ + bool noobject; /**< flag indicating if no interface object should eb + * generated. This allows for interfaces which do not + * generate code. For implements (mixin) interfaces + */ int operationc; /**< number of operations on interface */ struct interface_map_operation_entry *operationv; @@ -49,12 +59,7 @@ struct interface_map_entry { int constantc; /**< number of constants on interface */ struct interface_map_constant_entry *constantv; - int inherit_idx; /**< index into map of inherited interface or -1 for - * not in map - */ - int refcount; /**< number of interfacess in map that refer to this - * interface - */ + struct genbind_node *class; /**< class from binding (if any) */ /* The variables are created and used by the output generation but -- cgit v1.2.3 From 6fb336e6587d550bf4a8355e65923efb0bf14cab Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 1 Aug 2015 22:42:11 +0100 Subject: generate binding header and source These allow a closed set of functions used by the automatic bindings and gives an external interface allowing all the generated prototypes to be created in the correct order --- src/duk-libdom.c | 426 +++++++++++++++++++++++++++++++++++++++++++--------- src/interface-map.c | 14 ++ src/interface-map.h | 3 + 3 files changed, 371 insertions(+), 72 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 590afa2..4dbc8e2 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -25,6 +25,8 @@ /** prefix for all generated functions */ #define DLPFX "duckky" +#define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_" + #define NSGENBIND_PREAMBLE \ "/* Generated by nsgenbind\n" \ " *\n" \ @@ -62,24 +64,42 @@ static int output_safe_get_private(FILE* outf, char *class_name, int idx) return 0; } + /** - * generate code that gets a prototype by name + * generate a duktape prototype name */ -static int output_get_prototype(FILE* outf, const char *interface_name) +static char *get_prototype_name(const char *interface_name) { char *proto_name; int pnamelen; + int pfxlen; /* duplicate the interface name in upper case */ - pnamelen = strlen(interface_name) + 1; /* allow for null byte */ - proto_name = malloc(pnamelen); - for ( ; pnamelen >= 0; pnamelen--) { - proto_name[pnamelen] = toupper(interface_name[pnamelen]); + 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, PROTO_MAGIC);\n"); - fprintf(outf, "\tduk_get_prop_string(ctx, -1, PROTO_NAME(%s));\n", - proto_name); + fprintf(outf, + "\tduk_get_global_string(ctx, \"%sPROTOTYPES\");\n", MAGICPFX); + fprintf(outf, + "\tduk_get_prop_string(ctx, -1, \"%s\");\n", proto_name); fprintf(outf, "\tduk_replace(ctx, -2);\n"); free(proto_name); @@ -234,6 +254,16 @@ output_get_method_private(FILE* outf, char *class_name) return 0; } +/** + * generate preface block for nsgenbind + */ +static int output_tool_preface(FILE* outf) +{ + fprintf(outf, "\n%s\n", NSGENBIND_PREAMBLE); + + return 0; +} + /** * Generate a C class name for the interface. * @@ -319,6 +349,53 @@ output_cdata(FILE* outf, return 0; } +static FILE *open_header(struct interface_map *interface_map, const char *name) +{ + FILE *hdrf; + char *fname; + int fnamel; + + fnamel = strlen(name) + 4; + fname = malloc(fnamel); + snprintf(fname, fnamel, "%s.h", name); + + /* open output file */ + hdrf = genb_fopen(fname, "w"); + free(fname); + if (hdrf == NULL) { + return NULL; + } + + /* binding preface */ + output_cdata(hdrf, + interface_map->binding_node, + GENBIND_NODE_TYPE_PREFACE); + + /* tool preface */ + output_tool_preface(hdrf); + + /* header guard */ + fprintf(hdrf, "\n#ifndef %s_%s_h\n", DLPFX, name); + fprintf(hdrf, "#define %s_%s_h\n\n", DLPFX, name); + + return hdrf; +} + +static int close_header(struct interface_map *interface_map, FILE *hdrf) +{ + fprintf(hdrf, "\n#endif\n"); + + /* binding postface */ + output_cdata(hdrf, + interface_map->binding_node, + GENBIND_NODE_TYPE_POSTFACE); + + fclose(hdrf); + + return 0; +} + + /** * generate the interface constructor */ @@ -963,15 +1040,6 @@ output_interface_attributes(FILE* outf, return 0; } -/** - * generate preface block for nsgenbind - */ -static int output_tool_preface(FILE* outf) -{ - fprintf(outf, "\n%s\n", NSGENBIND_PREAMBLE); - - return 0; -} /** * generate preface block for nsgenbind @@ -980,10 +1048,14 @@ static int output_tool_prologue(FILE* outf) { char *fpath; - fpath = genb_fpath("private.h"); + 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); @@ -1105,23 +1177,8 @@ output_private_header(struct interface_map *interface_map) int idx; FILE *privf; - /* open output file */ - privf = genb_fopen("private.h", "w"); - if (privf == NULL) { - return -1; - } - - /* binding preface */ - output_cdata(privf, - interface_map->binding_node, - GENBIND_NODE_TYPE_PREFACE); - - /* tool preface */ - output_tool_preface(privf); - - /* header guard */ - fprintf(privf, "\n#ifndef duk_libdom_private_h\n"); - fprintf(privf, "#define duk_libdom_private_h\n\n"); + /* open header */ + privf = open_header(interface_map, "private"); for (idx = 0; idx < interface_map->entryc; idx++) { struct interface_map_entry *interfacee; @@ -1168,20 +1225,13 @@ output_private_header(struct interface_map *interface_map) } - /* binding postface */ - output_cdata(privf, - interface_map->binding_node, - GENBIND_NODE_TYPE_POSTFACE); - - fprintf(privf, "\n#endif\n"); - - fclose(privf); + close_header(interface_map, privf); return 0; } /** - * generate protottype header + * generate prototype header */ static int output_prototype_header(struct interface_map *interface_map) @@ -1189,23 +1239,8 @@ output_prototype_header(struct interface_map *interface_map) int idx; FILE *protof; - /* open output file */ - protof = genb_fopen("prototype.h", "w"); - if (protof == NULL) { - return -1; - } - - /* binding preface */ - output_cdata(protof, - interface_map->binding_node, - GENBIND_NODE_TYPE_PREFACE); - - /* tool preface */ - output_tool_preface(protof); - - /* header guard */ - fprintf(protof, "\n#ifndef duk_libdom_prototype_h\n"); - fprintf(protof, "#define duk_libdom_prototype_h\n\n"); + /* open header */ + protof = open_header(interface_map, "prototype"); for (idx = 0; idx < interface_map->entryc; idx++) { struct interface_map_entry *interfacee; @@ -1224,6 +1259,13 @@ output_prototype_header(struct interface_map *interface_map) fprintf(protof, "duk_ret_t %s_%s___proto(duk_context *ctx);\n", DLPFX, interfacee->class_name); + /** \todo if the interface has no references (no other + * interface inherits from it) there is no reason to export + * the initalisor/finaliser as no other class + * constructor/destructor should call them. Additionally the + * init/fini definition should be made static. + */ + /* finaliser declaration */ fprintf(protof, "void %s_%s___fini(duk_context *ctx, %s_private_t *priv);\n", @@ -1239,20 +1281,13 @@ output_prototype_header(struct interface_map *interface_map) fprintf(protof, ";\n\n"); } - /* binding postface */ - output_cdata(protof, - interface_map->binding_node, - GENBIND_NODE_TYPE_POSTFACE); - - fprintf(protof, "\n#endif\n"); - - fclose(protof); + close_header(interface_map, protof); return 0; } /** - * generate protottype header + * generate makefile fragment */ static int output_makefile(struct interface_map *interface_map) @@ -1268,7 +1303,7 @@ output_makefile(struct interface_map *interface_map) fprintf(makef, "# duk libdom makefile fragment\n\n"); - fprintf(makef, "NSGENBIND_SOURCES:="); + fprintf(makef, "NSGENBIND_SOURCES:=binding.c "); for (idx = 0; idx < interface_map->entryc; idx++) { struct interface_map_entry *interfacee; @@ -1288,6 +1323,241 @@ output_makefile(struct interface_map *interface_map) return 0; } + +/** + * generate binding header + * + * The binding header contains all the duk-libdom specific binding interface + * macros and definitions. + * + * the create prototypes interface is used to cause all the prototype creation + * functions for all generated classes to be called in the correct order with + * the primary global (if any) generated last. + */ +static int +output_binding_header(struct interface_map *interface_map) +{ + FILE *bindf; + + /* open header */ + bindf = open_header(interface_map, "binding"); + + fprintf(bindf, + "#define _MAGIC(S) (\"%s\" S)\n" + "#define MAGIC(S) _MAGIC(#S)\n" + "#define PROTO_MAGIC MAGIC(PROTOTYPES)\n" + "#define PRIVATE_MAGIC MAGIC(PRIVATE)\n" + "#define INIT_MAGIC MAGIC(INIT)\n" + "#define NODE_MAGIC MAGIC(NODE_MAP)\n" + "#define _PROTO_NAME(K) _MAGIC(\"PROTOTYPE_\" K)\n" + "#define PROTO_NAME(K) _PROTO_NAME(#K)\n" + "#define _PROP_NAME(K,V) _MAGIC(K \"_PROPERTY_\" V)\n" + "#define PROP_NAME(K,V) _PROP_NAME(#K,#V)\n" + "\n", + MAGICPFX); + + fprintf(bindf, + "duk_bool_t %s_instanceof(duk_context *ctx, const char *klass);\n", + DLPFX); + + fprintf(bindf, + "duk_ret_t %s_create_prototypes(duk_context *ctx);\n", DLPFX); + + close_header(interface_map, bindf); + + return 0; +} + + +/** + * generate binding source + * + * The binding header contains all the duk-libdom specific binding + * implementations. + */ +static int +output_binding_src(struct interface_map *interface_map) +{ + int idx; + FILE *bindf; + struct interface_map_entry *pglobale = NULL; + char *proto_name; + + /* open output file */ + bindf = genb_fopen("binding.c", "w"); + if (bindf == NULL) { + return -1; + } + + /* binding preface */ + output_cdata(bindf, + interface_map->binding_node, + GENBIND_NODE_TYPE_PREFACE); + + /* tool preface */ + output_tool_preface(bindf); + + /* binding prologue */ + output_cdata(bindf, + interface_map->binding_node, + GENBIND_NODE_TYPE_PROLOGUE); + + output_tool_prologue(bindf); + + fprintf(bindf, "\n"); + + /* instance of helper */ + fprintf(bindf, + "duk_bool_t\n" + "%s_instanceof(duk_context *ctx, const char *klass)\n", + DLPFX); + fprintf(bindf, + "{\n" + "\t/* ... ??? */\n" + "\tif (!duk_check_type(ctx, -1, DUK_TYPE_OBJECT)) {\n" + "\t\treturn false;\n" + "\t}\n" + "\t/* ... obj */\n" + "\tduk_get_global_string(ctx, \"%sPROTOTYPES\");\n" + "\t/* ... obj protos */\n" + "\tduk_get_prop_string(ctx, -1, klass);\n" + "\t/* ... obj protos goalproto */\n" + "\tduk_get_prototype(ctx, -3);\n" + "\t/* ... obj protos goalproto proto? */\n" + "\twhile (!duk_is_undefined(ctx, -1)) {\n" + "\t\tif (duk_strict_equals(ctx, -1, -2)) {\n" + "\t\t\tduk_pop_3(ctx);\n" + "\t\t\treturn true;\n" + "\t\t}\n" + "\t\tduk_get_prototype(ctx, -1);\n" + "\t\t/* ... obj protos goalproto proto proto? */\n" + "\t\tduk_replace(ctx, -2);\n" + "\t\t/* ... obj protos goalproto proto? */\n" + "\t}\n" + "\tduk_pop_3(ctx);\n" + "\t/* ... obj */\n" + "\treturn false;\n" + "}\n" + "\n", + MAGICPFX); + + /* prototype creation helper function */ + fprintf(bindf, + "static duk_ret_t\n" + "%s_to_string(duk_context *ctx)\n" + "{\n" + "\t/* */\n" + "\tduk_push_this(ctx);\n" + "\t/* this */\n" + "\tduk_get_prototype(ctx, -1);\n" + "\t/* this proto */\n" + "\tduk_get_prop_string(ctx, -1, \"%sklass_name\");\n" + "\t/* this proto classname */\n" + "\tduk_push_string(ctx, \"[object \");\n" + "\t/* this proto classname str */\n" + "\tduk_insert(ctx, -2);\n" + "\t/* this proto str classname */\n" + "\tduk_push_string(ctx, \"]\");\n" + "\t/* this proto str classname str */\n" + "\tduk_concat(ctx, 3);\n" + "\t/* this proto str */\n" + "\treturn 1;\n" + "}\n" + "\n", + DLPFX, + MAGICPFX); + + fprintf(bindf, + "static duk_ret_t %s_create_prototype(duk_context *ctx,\n", + DLPFX); + fprintf(bindf, + "\t\t\t\t\tduk_safe_call_function genproto,\n" + "\t\t\t\t\tconst char *proto_name,\n" + "\t\t\t\t\tconst char *klass_name)\n" + "{\n" + "\tduk_int_t ret;\n" + "\tduk_push_object(ctx);\n" + "\tif ((ret = duk_safe_call(ctx, genproto, 1, 1)) != DUK_EXEC_SUCCESS) {\n" + "\t\tduk_pop(ctx);\n" + "\t\tLOG(\"Failed to register prototype for %%s\", proto_name + 2);\n" + "\t\treturn ret;\n" + "\t}\n" + "\t/* top of stack is the ready prototype, inject it */\n" + "\tduk_push_string(ctx, klass_name);\n" + "\tduk_put_prop_string(ctx, -2, \"%sklass_name\");\n" + "\tduk_push_c_function(ctx, %s_to_string, 0);\n" + "\tduk_put_prop_string(ctx, -2, \"toString\");\n" + "\tduk_push_string(ctx, \"toString\");\n" + "\tduk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_ENUMERABLE);\n" + "\tduk_put_global_string(ctx, proto_name);\n" + "\treturn DUK_ERR_NONE;\n" + "}\n\n", + MAGICPFX, + DLPFX); + + /* generate prototype creation */ + fprintf(bindf, + "duk_ret_t %s_create_prototypes(duk_context *ctx)\n", DLPFX); + + fprintf(bindf, "{\n"); + + for (idx = 0; idx < interface_map->entryc; idx++) { + struct interface_map_entry *interfacee; + + interfacee = interface_map->entries + idx; + + /* do not generate prototype calls for interfaces marked + * no output + */ + if (interfacee->noobject) { + continue; + } + + if (interfacee->primary_global) { + pglobale = interfacee; + continue; + } + + proto_name = get_prototype_name(interfacee->name); + + fprintf(bindf, + "\t%s_create_prototype(ctx, %s_%s___proto, \"%s\", \"%s\");\n", + DLPFX, + DLPFX, + interfacee->class_name, + proto_name, + interfacee->name); + + free(proto_name); + } + + if (pglobale != NULL) { + fprintf(bindf, "\n\t/* Global object prototype is last */\n"); + + proto_name = get_prototype_name(pglobale->name); + fprintf(bindf, + "\t%s_create_prototype(ctx, %s_%s___proto, \"%s\", \"%s\");\n", + DLPFX, + DLPFX, + pglobale->class_name, + proto_name, + pglobale->name); + free(proto_name); + } + + fprintf(bindf, "\n\treturn DUK_ERR_NONE;\n"); + + fprintf(bindf, "}\n"); + + /* binding postface */ + output_cdata(bindf, + interface_map->binding_node, + GENBIND_NODE_TYPE_POSTFACE); + + fclose(bindf); + return 0; +} + int duk_libdom_output(struct interface_map *interface_map) { int idx; @@ -1314,6 +1584,18 @@ int duk_libdom_output(struct interface_map *interface_map) goto output_err; } + /* generate binding header */ + res = output_binding_header(interface_map); + if (res != 0) { + goto output_err; + } + + /* generate binding source */ + res = output_binding_src(interface_map); + if (res != 0) { + goto output_err; + } + /* generate makefile fragment */ res = output_makefile(interface_map); diff --git a/src/interface-map.c b/src/interface-map.c index 467c0ed..555156a 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -111,6 +111,7 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) dstinf[idx].node = srcinf[inf].node; dstinf[idx].inherit_name = srcinf[inf].inherit_name; dstinf[idx].noobject = srcinf[inf].noobject; + dstinf[idx].primary_global = srcinf[inf].primary_global; dstinf[idx].operationc = srcinf[inf].operationc; dstinf[idx].operationv = srcinf[inf].operationv; dstinf[idx].attributec = srcinf[inf].attributec; @@ -422,6 +423,7 @@ int interface_map_new(struct genbind_node *genbind, NULL, WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE)); + /* is the interface marked as not generating an object */ if (webidl_node_find_type_ident( webidl_node_getnode(node), WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE, @@ -433,6 +435,18 @@ int interface_map_new(struct genbind_node *genbind, ecur->noobject = true; } + /* is the interface marked as the primary global */ + if (webidl_node_find_type_ident( + webidl_node_getnode(node), + WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE, + "PrimaryGlobal") != NULL) { + /** \todo we should ensure nothing inherits *from* this + * class or all hell will break loose having two + * primary globals. + */ + ecur->primary_global = true; + } + /* matching class from binding */ ecur->class = genbind_node_find_type_ident(genbind, NULL, GENBIND_NODE_TYPE_CLASS, ecur->name); diff --git a/src/interface-map.h b/src/interface-map.h index e07aa19..c34eb4b 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -49,6 +49,9 @@ struct interface_map_entry { * generated. This allows for interfaces which do not * generate code. For implements (mixin) interfaces */ + bool primary_global; /**< flag indicating the interface is the primary + * global javascript object. + */ int operationc; /**< number of operations on interface */ struct interface_map_operation_entry *operationv; -- cgit v1.2.3 From cf89528fc6668e6d07b6e99db0069c9fe1f6e05d Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 2 Aug 2015 18:30:18 +0100 Subject: Update the webidl parser to cope with specials and overloaded methods --- src/duk-libdom.c | 201 ++++++++++++++++--------------------- src/interface-map.c | 63 +++++++++++- src/interface-map.h | 1 + src/webidl-ast.c | 9 +- src/webidl-ast.h | 14 ++- src/webidl-parser.y | 82 +++++++++++---- test/data/bindings/browser-duk.bnd | 5 +- 7 files changed, 230 insertions(+), 145 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 4dbc8e2..bc27dfc 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -23,7 +23,7 @@ #include "duk-libdom.h" /** prefix for all generated functions */ -#define DLPFX "duckky" +#define DLPFX "dukky" #define MAGICPFX "\\xFF\\xFFNETSURF_DUKTAPE_" @@ -46,7 +46,9 @@ static int output_create_private(FILE* outf, char *class_name) 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"); + fprintf(outf, + "\tduk_put_prop_string(ctx, 0, \"%sPRIVATE\");\n\n", + MAGICPFX); return 0; } @@ -57,7 +59,8 @@ static int output_create_private(FILE* outf, char *class_name) 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, PRIVATE_MAGIC);\n",idx); + fprintf(outf, "\tduk_get_prop_string(ctx, %d, \"%sPRIVATE\");\n", + idx, MAGICPFX); fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n"); fprintf(outf, "\tduk_pop(ctx);\n"); fprintf(outf, "\tif (priv == NULL) return 0;\n\n"); @@ -154,11 +157,14 @@ output_dump_stack(FILE* outf) * generate code that adds a method in a prototype */ static int -output_add_method(FILE* outf, char *class_name, char *method, int argc) +output_add_method(FILE* outf, + const char *class_name, + const char *method, + int argc) { 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_string(ctx, \"%s\");\n", method); fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s, ", DLPFX, class_name, method); if (argc == -1) { @@ -172,7 +178,7 @@ output_add_method(FILE* outf, char *class_name, char *method, int argc) 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"); + fprintf(outf, "\tduk_pop(ctx);\n\n"); return 0; } @@ -196,7 +202,7 @@ output_populate_rw_property(FILE* outf, const char *class_name, const char *prop fprintf(outf, "\t DUK_DEFPROP_HAVE_SETTER |\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"); + fprintf(outf, "\tduk_pop(ctx);\n\n"); return 0; } @@ -217,7 +223,7 @@ output_populate_ro_property(FILE* outf, const char *class_name, const char *prop "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\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"); + fprintf(outf, "\tduk_pop(ctx);\n\n"); return 0; } @@ -234,7 +240,7 @@ output_prototype_constant_int(FILE *outf, const char *constant_name, int 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"); + fprintf(outf, "\tduk_pop(ctx);\n\n"); return 0; } @@ -259,7 +265,7 @@ output_get_method_private(FILE* outf, char *class_name) */ static int output_tool_preface(FILE* outf) { - fprintf(outf, "\n%s\n", NSGENBIND_PREAMBLE); + fprintf(outf, "%s\n", NSGENBIND_PREAMBLE); return 0; } @@ -704,20 +710,30 @@ static int count_operation_arguments(struct webidl_node *node) static int output_prototype_method(FILE* outf, struct interface_map_entry *interfacee, - struct webidl_node *op_node) + struct interface_map_operation_entry *operatione) { - char *op_name; int op_argc; - op_name = webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(op_node), - NULL, - WEBIDL_NODE_TYPE_IDENT)); + if (operatione->overloadc > 1) { + /* only generate a method for the first occourance of an + * overloaded method + */ + return 0; + } - op_argc = count_operation_arguments(op_node); + if (operatione->name != NULL) { + /* normal method of prototype */ + op_argc = count_operation_arguments(operatione->node); - output_add_method(outf, interfacee->class_name, op_name, op_argc); + output_add_method(outf, + interfacee->class_name, + operatione->name, + op_argc); + } else { + /* special method on prototype */ + fprintf(outf, + "\t/* Special method on prototype - UNIMPLEMENTED */\n\n"); + } return 0; } @@ -728,43 +744,19 @@ output_prototype_method(FILE* outf, static int output_prototype_methods(FILE *outf, struct interface_map_entry *interfacee) { - int res; - struct webidl_node *list_node; - struct webidl_node *op_node; /* operation on list node */ - - /* iterate each list node within the interface */ - list_node = webidl_node_find_type( - webidl_node_getnode(interfacee->node), - NULL, - WEBIDL_NODE_TYPE_LIST); - - while (list_node != NULL) { - /* iterate through operations in a list */ - op_node = webidl_node_find_type( - webidl_node_getnode(list_node), - NULL, - WEBIDL_NODE_TYPE_OPERATION); - - while (op_node != NULL) { - res = output_prototype_method(outf, interfacee, op_node); - if (res != 0) { - return res; - } + int opc; + int res = 0; - op_node = webidl_node_find_type( - webidl_node_getnode(list_node), - op_node, - WEBIDL_NODE_TYPE_OPERATION); + for (opc = 0; opc < interfacee->operationc; opc++) { + res = output_prototype_method(outf, + interfacee, + interfacee->operationv + opc); + if (res != 0) { + break; } - - - list_node = webidl_node_find_type( - webidl_node_getnode(interfacee->node), - list_node, - WEBIDL_NODE_TYPE_LIST); } - return 0; + return res; } @@ -900,35 +892,34 @@ output_interface_prototype(FILE* outf, static int output_interface_operation(FILE* outf, struct interface_map_entry *interfacee, - struct webidl_node *op_node) + struct interface_map_operation_entry *operatione) { - char *op_name; - struct genbind_node *method_node; - - op_name = webidl_node_gettext( - webidl_node_find_type( - webidl_node_getnode(op_node), - NULL, - WEBIDL_NODE_TYPE_IDENT)); - - method_node = genbind_node_find_method_ident(interfacee->class, - NULL, - GENBIND_METHOD_TYPE_METHOD, - op_name); + if (operatione->overloadc > 1) { + /* only generate a method for the first occourance of an + * overloaded method + */ + return 0; + } - /* method definition */ - fprintf(outf, - "static duk_ret_t %s_%s_%s(duk_context *ctx)\n", - DLPFX, interfacee->class_name, op_name); - fprintf(outf,"{\n"); + if (operatione->name != NULL) { + /* normal method definition */ + 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); + output_get_method_private(outf, interfacee->class_name); - output_cdata(outf, method_node, GENBIND_NODE_TYPE_CDATA); + output_cdata(outf, operatione->method, GENBIND_NODE_TYPE_CDATA); - fprintf(outf,"\treturn 0;\n"); + fprintf(outf,"\treturn 0;\n"); - fprintf(outf, "}\n\n"); + fprintf(outf, "}\n\n"); + } else { + /* special method definition */ + fprintf(outf, + "/* Special method definition - UNIMPLEMENTED */\n\n"); + } return 0; } @@ -939,43 +930,19 @@ output_interface_operation(FILE* outf, static int output_interface_operations(FILE* outf, struct interface_map_entry *interfacee) { - int res; - struct webidl_node *list_node; - struct webidl_node *op_node; /* operation on list node */ - - /* iterate each list node within the interface */ - list_node = webidl_node_find_type( - webidl_node_getnode(interfacee->node), - NULL, - WEBIDL_NODE_TYPE_LIST); - - while (list_node != NULL) { - /* iterate through operations in a list */ - op_node = webidl_node_find_type( - webidl_node_getnode(list_node), - NULL, - WEBIDL_NODE_TYPE_OPERATION); - - while (op_node != NULL) { - res = output_interface_operation(outf, interfacee, op_node); - if (res != 0) { - return res; - } + int opc; + int res = 0; - op_node = webidl_node_find_type( - webidl_node_getnode(list_node), - op_node, - WEBIDL_NODE_TYPE_OPERATION); + for (opc = 0; opc < interfacee->operationc; opc++) { + res = output_interface_operation(outf, + interfacee, + interfacee->operationv + opc); + if (res != 0) { + break; } - - - list_node = webidl_node_find_type( - webidl_node_getnode(interfacee->node), - list_node, - WEBIDL_NODE_TYPE_LIST); } - return 0; + return res; } /** @@ -1097,24 +1064,25 @@ static int output_interface(struct interface_map *interface_map, /* find parent interface entry */ inherite = interface_map_inherit_entry(interface_map, interfacee); + /* tool preface */ + output_tool_preface(ifacef); + /* binding preface */ output_cdata(ifacef, interface_map->binding_node, GENBIND_NODE_TYPE_PREFACE); - /* tool preface */ - output_tool_preface(ifacef); - /* class preface */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PREFACE); + /* tool prologue */ + output_tool_prologue(ifacef); + /* binding prologue */ output_cdata(ifacef, interface_map->binding_node, GENBIND_NODE_TYPE_PROLOGUE); - output_tool_prologue(ifacef); - /* class prologue */ output_cdata(ifacef, interfacee->class, GENBIND_NODE_TYPE_PROLOGUE); @@ -1389,20 +1357,21 @@ output_binding_src(struct interface_map *interface_map) return -1; } + /* tool preface */ + output_tool_preface(bindf); + /* binding preface */ output_cdata(bindf, interface_map->binding_node, GENBIND_NODE_TYPE_PREFACE); - /* tool preface */ - output_tool_preface(bindf); + output_tool_prologue(bindf); /* binding prologue */ output_cdata(bindf, interface_map->binding_node, GENBIND_NODE_TYPE_PROLOGUE); - output_tool_prologue(bindf); fprintf(bindf, "\n"); diff --git a/src/interface-map.c b/src/interface-map.c index 555156a..29e9ec0 100644 --- a/src/interface-map.c +++ b/src/interface-map.c @@ -132,6 +132,33 @@ interface_topoligical_sort(struct interface_map_entry *srcinf, int infc) return dstinf; } +static int +count_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++; + } else { + if ((cure->name != NULL) && + (name != NULL) && + (strcmp(cure->name, name) == 0)) { + res++; + } + } + } + + return res; +} + static int operation_map_new(struct webidl_node *interface, struct genbind_node *class, @@ -143,14 +170,16 @@ 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 */ operationc = enumerate_interface_type(interface, WEBIDL_NODE_TYPE_OPERATION); - *operationc_out = operationc; if (operationc < 1) { - *operationv_out = NULL; /* no operations so empty map */ + /* no operations so empty map */ + *operationc_out = 0; + *operationv_out = NULL; return 0; } @@ -189,6 +218,10 @@ operation_map_new(struct webidl_node *interface, GENBIND_METHOD_TYPE_METHOD, cure->name); + cure->overloadc = count_operation_name(operationv, + operationc, + cure->name); + cure++; /* move to next operation */ @@ -204,6 +237,21 @@ 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 */ return 0; @@ -533,8 +581,15 @@ int interface_map_dump(struct interface_map *index) ope = ecur->operationv; while (ope != NULL) { - fprintf(dumpf, " %s %p\n", - ope->name, ope->method); + fprintf(dumpf, + " %s\n", + ope->name); + fprintf(dumpf, + " method:%p\n", + ope->method); + fprintf(dumpf, + " overload:%d\n", + ope->overloadc); ope++; opc--; if (opc == 0) { diff --git a/src/interface-map.h b/src/interface-map.h index c34eb4b..04d9df1 100644 --- a/src/interface-map.h +++ b/src/interface-map.h @@ -17,6 +17,7 @@ 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 */ }; /** map entry for attributes on an interface */ diff --git a/src/webidl-ast.c b/src/webidl-ast.c index 75f969b..0e90767 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -285,6 +285,7 @@ webidl_node_getint(struct webidl_node *node) case WEBIDL_NODE_TYPE_MODIFIER: case WEBIDL_NODE_TYPE_TYPE_BASE: case WEBIDL_NODE_TYPE_LITERAL_INT: + case WEBIDL_NODE_TYPE_SPECIAL: return &node->r.number; default: @@ -386,6 +387,9 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: return "Extended Attribute"; + case WEBIDL_NODE_TYPE_SPECIAL: + return "Special"; + default: return "Unknown"; } @@ -414,10 +418,13 @@ static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent) fprintf(dumpf, "\n"); webidl_ast_dump(dumpf, next, indent + 2); } else { - /* not txt or node has to be an int */ + /* not txt or node try an int */ value = webidl_node_getint(node); if (value != NULL) { fprintf(dumpf, ": %d\n", *value); + } else { + /* no value */ + fprintf(dumpf, "\n"); } } } else { diff --git a/src/webidl-ast.h b/src/webidl-ast.h index 38968f3..c17a54b 100644 --- a/src/webidl-ast.h +++ b/src/webidl-ast.h @@ -27,7 +27,8 @@ enum webidl_node_type { WEBIDL_NODE_TYPE_OPERATION, WEBIDL_NODE_TYPE_CONST, - WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT, + WEBIDL_NODE_TYPE_SPECIAL, + WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT, WEBIDL_NODE_TYPE_ARGUMENT, WEBIDL_NODE_TYPE_ELLIPSIS, WEBIDL_NODE_TYPE_TYPE, @@ -68,6 +69,15 @@ enum webidl_type_modifier { WEBIDL_TYPE_MODIFIER_READONLY, }; +/* the type of special node */ +enum webidl_type_special { + WEBIDL_TYPE_SPECIAL_GETTER, + WEBIDL_TYPE_SPECIAL_SETTER, + WEBIDL_TYPE_SPECIAL_CREATOR, + WEBIDL_TYPE_SPECIAL_DELETER, + WEBIDL_TYPE_SPECIAL_LEGACYCALLER, +}; + struct webidl_node; /** callback for search and iteration routines */ @@ -114,7 +124,7 @@ webidl_node_find(struct webidl_node *node, struct webidl_node * webidl_node_find_type(struct webidl_node *node, - struct webidl_node *prev, + struct webidl_node *prev, enum webidl_node_type type); struct webidl_node * diff --git a/src/webidl-parser.y b/src/webidl-parser.y index a48f3fd..953388e 100644 --- a/src/webidl-parser.y +++ b/src/webidl-parser.y @@ -155,6 +155,9 @@ webidl_error(YYLTYPE *locp, struct webidl_node **winbind_ast, const char *str) %type Const %type Operation +%type SpecialOperation +%type Specials +%type Special %type OperationRest %type OptionalIdentifier @@ -723,55 +726,94 @@ ReadOnly: } ; - /* [35] */ + /* SE[47] */ Operation: - Qualifiers OperationRest + ReturnType OperationRest { - /* @todo fix qualifiers */ - $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPERATION, NULL, $2); + /* put return type on the operation */ + $2 = webidl_node_prepend($1, $2); + + $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPERATION, NULL, $2); + } + | + SpecialOperation + { + $$ = webidl_node_new(WEBIDL_NODE_TYPE_OPERATION, NULL, $1); } ; - /* [36] */ -Qualifiers: - TOK_STATIC - | - Specials + /* SE[48] */ +SpecialOperation: + Special Specials ReturnType OperationRest + { + /* put return type on the operation */ + $$ = webidl_node_prepend($4, $3); + + /* specials */ + $$ = webidl_node_prepend($$, $2); + + /* special */ + $$ = webidl_node_prepend($$, $1); + } ; - /* [37] */ + /* SE[49] */ Specials: /* empty */ + { + $$ = NULL; + } | Special Specials + { + $$ = webidl_node_prepend($2, $1); + } ; - /* [38] */ + /* SE[50] */ Special: TOK_GETTER + { + $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL, + NULL, (void *)WEBIDL_TYPE_SPECIAL_GETTER); + } | TOK_SETTER + { + $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL, + NULL, (void *)WEBIDL_TYPE_SPECIAL_SETTER); + } | TOK_CREATOR + { + /* second edition removed this special but teh + specifications still use it! + */ + $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL, + NULL, (void *)WEBIDL_TYPE_SPECIAL_CREATOR); + } | TOK_DELETER + { + $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL, + NULL, (void *)WEBIDL_TYPE_SPECIAL_DELETER); + } | TOK_LEGACYCALLER + { + $$ = webidl_node_new(WEBIDL_NODE_TYPE_SPECIAL, + NULL, (void *)WEBIDL_TYPE_SPECIAL_LEGACYCALLER); + } ; - /* [39] */ + /* SE[51] */ OperationRest: - ReturnType OptionalIdentifier '(' ArgumentList ')' ';' + OptionalIdentifier '(' ArgumentList ')' ';' { - struct webidl_node *arglist; - - /* put return type in argument list */ - arglist = webidl_node_prepend($4, $1); - /* argument list */ - $$ = webidl_node_new(WEBIDL_NODE_TYPE_LIST, NULL, arglist); + $$ = webidl_node_new(WEBIDL_NODE_TYPE_LIST, NULL, $3); - $$ = webidl_node_prepend($$, $2); /* identifier */ + $$ = webidl_node_prepend($1, $$); /* identifier */ } ; diff --git a/test/data/bindings/browser-duk.bnd b/test/data/bindings/browser-duk.bnd index 513ad99..d0c2c41 100644 --- a/test/data/bindings/browser-duk.bnd +++ b/test/data/bindings/browser-duk.bnd @@ -14,7 +14,8 @@ binding duk_libdom { webidl "uievents.idl"; webidl "console.idl"; - preface %{ + preface +%{ /* DukTape JavaScript bindings for NetSurf browser * * Copyright 2015 Vincent Sanders @@ -22,7 +23,7 @@ binding duk_libdom { * Released under the terms of the MIT License, * http://www.opensource.org/licenses/mit-license */ - %}; +%}; prologue %{ /* binding prologue */ -- cgit v1.2.3 From 780d7c53a8479b62fe8d90e16a3045187e347cc7 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 2 Aug 2015 21:44:04 +0100 Subject: generates files with temporary name and only overwites on change --- src/duk-libdom.c | 35 ++++++++----- src/utils.c | 149 ++++++++++++++++++++++++++++++++++++++++++++----------- src/utils.h | 14 ++++++ 3 files changed, 158 insertions(+), 40 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index bc27dfc..3e2fbe4 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -366,7 +366,7 @@ static FILE *open_header(struct interface_map *interface_map, const char *name) snprintf(fname, fnamel, "%s.h", name); /* open output file */ - hdrf = genb_fopen(fname, "w"); + hdrf = genb_fopen_tmp(fname); free(fname); if (hdrf == NULL) { return NULL; @@ -387,8 +387,17 @@ static FILE *open_header(struct interface_map *interface_map, const char *name) return hdrf; } -static int close_header(struct interface_map *interface_map, FILE *hdrf) +static int close_header(struct interface_map *interface_map, + FILE *hdrf, + const char *name) { + char *fname; + int fnamel; + + fnamel = strlen(name) + 4; + fname = malloc(fnamel); + snprintf(fname, fnamel, "%s.h", name); + fprintf(hdrf, "\n#endif\n"); /* binding postface */ @@ -396,7 +405,8 @@ static int close_header(struct interface_map *interface_map, FILE *hdrf) interface_map->binding_node, GENBIND_NODE_TYPE_POSTFACE); - fclose(hdrf); + genb_fclose_tmp(hdrf, fname); + free(fname); return 0; } @@ -1056,7 +1066,7 @@ static int output_interface(struct interface_map *interface_map, "%s.c", interfacee->class_name); /* open output file */ - ifacef = genb_fopen(interfacee->filename, "w"); + ifacef = genb_fopen_tmp(interfacee->filename); if (ifacef == NULL) { return -1; } @@ -1131,7 +1141,7 @@ static int output_interface(struct interface_map *interface_map, GENBIND_NODE_TYPE_POSTFACE); op_error: - fclose(ifacef); + genb_fclose_tmp(ifacef, interfacee->filename); return res; } @@ -1193,7 +1203,7 @@ output_private_header(struct interface_map *interface_map) } - close_header(interface_map, privf); + close_header(interface_map, privf, "private"); return 0; } @@ -1249,7 +1259,7 @@ output_prototype_header(struct interface_map *interface_map) fprintf(protof, ";\n\n"); } - close_header(interface_map, protof); + close_header(interface_map, protof, "prototype"); return 0; } @@ -1264,7 +1274,7 @@ output_makefile(struct interface_map *interface_map) FILE *makef; /* open output file */ - makef = genb_fopen("Makefile", "w"); + makef = genb_fopen_tmp("Makefile"); if (makef == NULL) { return -1; } @@ -1286,7 +1296,7 @@ output_makefile(struct interface_map *interface_map) } fprintf(makef, "\nNSGENBIND_PREFIX:=%s\n", options->outdirname); - fclose(makef); + genb_fclose_tmp(makef, "Makefile"); return 0; } @@ -1331,7 +1341,7 @@ output_binding_header(struct interface_map *interface_map) fprintf(bindf, "duk_ret_t %s_create_prototypes(duk_context *ctx);\n", DLPFX); - close_header(interface_map, bindf); + close_header(interface_map, bindf, "binding"); return 0; } @@ -1352,7 +1362,7 @@ output_binding_src(struct interface_map *interface_map) char *proto_name; /* open output file */ - bindf = genb_fopen("binding.c", "w"); + bindf = genb_fopen_tmp("binding.c"); if (bindf == NULL) { return -1; } @@ -1523,7 +1533,8 @@ output_binding_src(struct interface_map *interface_map) interface_map->binding_node, GENBIND_NODE_TYPE_POSTFACE); - fclose(bindf); + genb_fclose_tmp(bindf, "binding.c"); + return 0; } diff --git a/src/utils.c b/src/utils.c index 9e50a93..1e8ec23 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,3 +1,11 @@ +/* utility functions + * + * This file is part of nsgenbind. + * Published under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2015 Vincent Sanders + */ + #include #include #include @@ -10,34 +18,120 @@ /* exported function documented in utils.h */ char *genb_fpath(const char *fname) { - char *fpath; - int fpathl; + char *fpath; + int fpathl; + + fpathl = strlen(options->outdirname) + strlen(fname) + 2; + fpath = malloc(fpathl); + snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname); + + return fpath; +} + +static char *genb_fpath_tmp(const char *fname) +{ + char *fpath; + int fpathl; - fpathl = strlen(options->outdirname) + strlen(fname) + 2; - fpath = malloc(fpathl); - snprintf(fpath, fpathl, "%s/%s", options->outdirname, fname); + fpathl = strlen(options->outdirname) + strlen(fname) + 3; + fpath = malloc(fpathl); + snprintf(fpath, fpathl, "%s/%s~", options->outdirname, fname); - return fpath; + return fpath; } /* exported function documented in utils.h */ FILE *genb_fopen(const char *fname, const char *mode) { - char *fpath; - FILE *filef; + char *fpath; + FILE *filef; + + fpath = genb_fpath(fname); + + filef = fopen(fpath, mode); + if (filef == NULL) { + fprintf(stderr, "Error: unable to open file %s (%s)\n", + fpath, strerror(errno)); + free(fpath); + return NULL; + } + free(fpath); + + return filef; +} + +/* exported function documented in utils.h */ +FILE *genb_fopen_tmp(const char *fname) +{ + char *fpath; + FILE *filef; + + fpath = genb_fpath_tmp(fname); + + filef = fopen(fpath, "w+"); + if (filef == NULL) { + fprintf(stderr, "Error: unable to open file %s (%s)\n", + fpath, strerror(errno)); + free(fpath); + return NULL; + } + free(fpath); - fpath = genb_fpath(fname); + return filef; +} - filef = fopen(fpath, mode); - if (filef == NULL) { - fprintf(stderr, "Error: unable to open file %s (%s)\n", - fpath, strerror(errno)); +int genb_fclose_tmp(FILE *filef_tmp, const char *fname) +{ + char *fpath; + char *tpath; + FILE *filef; + char tbuf[1024]; + char fbuf[1024]; + size_t trd; + size_t frd; + + fpath = genb_fpath(fname); + tpath = genb_fpath_tmp(fname); + + filef = fopen(fpath, "r"); + if (filef == NULL) { + /* unable to open target file for comparison */ + + fclose(filef_tmp); /* close tmpfile */ + + remove(fpath); + rename(tpath, fpath); + } else { + rewind(filef_tmp); + + frd = fread(fbuf, 1, 1024, filef); + while (frd != 0) { + trd = fread(tbuf, 1, frd, filef_tmp); + if ((trd != frd) || + (memcmp(tbuf, fbuf, trd) != 0)) { + /* file doesnt match */ + fclose(filef_tmp); + + remove(fpath); + rename(tpath, fpath); + + goto close_done; + } + + frd = fread(fbuf, 1, 1024, filef); + } + + /* was the same kill temporary file */ + fclose(filef_tmp); + fclose(filef); + remove(tpath); + } + +close_done: free(fpath); - return NULL; - } - free(fpath); + free(tpath); - return filef; + return 0; } @@ -45,20 +139,19 @@ FILE *genb_fopen(const char *fname, const char *mode) char *strndup(const char *s, size_t n) { - size_t len; - char *s2; + size_t len; + char *s2; - for (len = 0; len != n && s[len]; len++) - continue; + for (len = 0; len != n && s[len]; len++) + continue; - s2 = malloc(len + 1); - if (!s2) - return 0; + s2 = malloc(len + 1); + if (!s2) + return 0; - memcpy(s2, s, len); - s2[len] = 0; - return s2; + memcpy(s2, s, len); + s2[len] = 0; + return s2; } #endif - diff --git a/src/utils.h b/src/utils.h index b37d755..508d1c1 100644 --- a/src/utils.h +++ b/src/utils.h @@ -22,6 +22,20 @@ char *genb_fpath(const char *fname); */ FILE *genb_fopen(const char *fname, const char *mode); +/** + * Open file allowing for output path prefix + * + * file is opened for reading/writing with a temporary suffix allowing for the + * matching close call to check the output is different before touching the + * target file. + */ +FILE *genb_fopen_tmp(const char *fname); + +/** + * Close file opened with genb_fopen + */ +int genb_fclose_tmp(FILE *filef, const char *fname); + #ifdef _WIN32 #define NEED_STRNDUP 1 char *strndup(const char *s, size_t n); -- cgit v1.2.3 From dd684cd17564664ca9c51f0b95d0bbd3cbadddf2 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 2 Aug 2015 22:59:08 +0100 Subject: Fix initialiser parameter list The initialiser parameter list parsing was missing creation of a parameter node in the AST and the parameter iterator was looking for a method node instead of a paramter node. --- src/duk-libdom.c | 8 +++++--- src/nsgenbind-parser.y | 6 +++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 3e2fbe4..2361448 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -135,7 +135,8 @@ output_set_constructor(FILE* outf, char *class_name, int idx, int argc) 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, INIT_MAGIC);\n"); + fprintf(outf, "\tduk_put_prop_string(ctx, -2, \"%sINIT\");\n", + MAGICPFX); fprintf(outf, "\tduk_pop(ctx);\n\n"); return 0; @@ -253,7 +254,8 @@ 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, PRIVATE_MAGIC);\n"); + fprintf(outf, "\tduk_get_prop_string(ctx, -1, \"%sPRIVATE\");\n", + MAGICPFX); fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n"); fprintf(outf, "\tduk_pop_2(ctx);\n"); fprintf(outf, "\tif (priv == NULL) return 0; /* can do? No can do. */\n\n"); @@ -599,7 +601,7 @@ output_interface_init_declaration(FILE* outf, param_node = genbind_node_find_type( genbind_node_getnode(init_node), - param_node, GENBIND_NODE_TYPE_METHOD); + param_node, GENBIND_NODE_TYPE_PARAMETER); } fprintf(outf,")"); diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index 456decb..0f30dfc 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -350,7 +350,11 @@ ParameterList | ParameterList ',' TypeIdent { - $$ = genbind_node_link($3, $1); + $$ = genbind_node_prepend($1, + genbind_new_node( + GENBIND_NODE_TYPE_PARAMETER, + NULL, + $3)); } ; -- cgit v1.2.3 From 6862f9c5c94bf8f668227f4bce200006ff2c7d17 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 3 Aug 2015 00:06:51 +0100 Subject: When constructing the interface map ensure method type search code does not strcmp null --- src/nsgenbind-ast.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c index 28326aa..4f0654a 100644 --- a/src/nsgenbind-ast.c +++ b/src/nsgenbind-ast.c @@ -339,7 +339,9 @@ genbind_node_find_method_ident(struct genbind_node *node, genbind_node_getnode(res_node), NULL, GENBIND_NODE_TYPE_IDENT)); - if ((method_ident != NULL) && + + if ((ident != NULL) && + (method_ident != NULL) && strcmp(ident, method_ident) == 0) { break; } -- cgit v1.2.3 From a3224e5daea03c4dbf28a2d6a5c0ddb3ece1ed0a Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 4 Aug 2015 10:29:01 +0100 Subject: Update README with info on generated output --- README | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/README b/README index eb42c83..a6efd38 100644 --- a/README +++ b/README @@ -288,6 +288,62 @@ The binding file consists of three types of element: The cdata block is output. +Generated source +---------------- + +duk_libdom + + This binding type generates several files as output: + - binding.c + support function source + + - binding.h + header to declare the support functions and magic constant + + - prototype.h + header which declares all the prototype builder, initialiser + and finalizer functions. + + - private.h + Which defines all the private structures for all classes + + - C source file per class + These are the main output of the tool and are structured to + give the binding author control of the output while + automatically generating as much code as possible. + + The files are generated in sections: + tool preface + binding preface + class preface + tool prologue + binding prologue + class prologue + initialiser + finalizer + constructor + destructor + methods + getters and setters + prototype + class epilogue + binding epilogue + tool epilogue + class postface + binding postface + tool postface + + The preface, prologue, epilogue and postface are all + verbaitum output from the binding and class elements in the + binding. All the other sections are generated code augmented + and controlled by the binding. + + Method generation produces a method with appropriate + signature added to the prototype. Any verbatum cdata from + the binding is added after the code that automatically + populates a private pointer of the appropriate type + (named priv). + References ---------- -- cgit v1.2.3 From 5af5647471a44f489f14a415f10b7b8e34344581 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 4 Aug 2015 10:30:01 +0100 Subject: The Read-only properties generator was using the wrong number of parameters. --- src/duk-libdom.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 2361448..6966f02 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -193,16 +193,15 @@ output_populate_rw_property(FILE* outf, const char *class_name, const char *prop 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", + 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", + 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 DUK_DEFPROP_HAVE_SETTER |\n"); - fprintf(outf, "\t DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n"); - fprintf(outf, "\t DUK_DEFPROP_HAVE_CONFIGURABLE);\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; @@ -217,13 +216,12 @@ output_populate_ro_property(FILE* outf, const char *class_name, const char *prop 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", + fprintf(outf, "\tduk_push_c_function(ctx, %s_%s_%s_getter, 0);\n", DLPFX, class_name, property); - fprintf(outf, - "\tduk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |\n"); - fprintf(outf, "\t DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |\n"); - fprintf(outf, "\t DUK_DEFPROP_HAVE_CONFIGURABLE);\n"); + 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; @@ -258,7 +256,13 @@ output_get_method_private(FILE* outf, char *class_name) MAGICPFX); fprintf(outf, "\tpriv = duk_get_pointer(ctx, -1);\n"); fprintf(outf, "\tduk_pop_2(ctx);\n"); - fprintf(outf, "\tif (priv == NULL) return 0; /* can do? No can do. */\n\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; } -- cgit v1.2.3 From 619dbd53bc4624e3a4e9bb291e61ed358272d009 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 5 Aug 2015 22:27:25 +0100 Subject: change method and property generators default block generation If the binding implementation of a method or property is empty then generate a default implementation (currently simply a return statement) otherwise the binding implementation must be complete including a return statement. --- src/duk-libdom.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 6966f02..31ec0a1 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -343,7 +343,12 @@ static char *gen_class_name(struct interface_map_entry *interfacee) /** * output character data of node of given type. * - * used for pre/pro/epi/post sections + * 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, @@ -351,14 +356,17 @@ output_cdata(FILE* outf, 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 0; + return res; } static FILE *open_header(struct interface_map *interface_map, const char *name) @@ -919,6 +927,9 @@ output_interface_operation(FILE* outf, if (operatione->name != NULL) { /* 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); @@ -926,9 +937,14 @@ output_interface_operation(FILE* outf, output_get_method_private(outf, interfacee->class_name); - output_cdata(outf, operatione->method, GENBIND_NODE_TYPE_CDATA); + cdatac = output_cdata(outf, + operatione->method, + GENBIND_NODE_TYPE_CDATA); - fprintf(outf,"\treturn 0;\n"); + if (cdatac == 0) { + /* no implementation so generate default */ + fprintf(outf,"\treturn 0;\n"); + } fprintf(outf, "}\n\n"); } else { @@ -969,6 +985,8 @@ output_interface_attribute(FILE* outf, struct interface_map_entry *interfacee, struct interface_map_attribute_entry *atributee) { + int cdatac; + /* getter definition */ fprintf(outf, "static duk_ret_t %s_%s_%s_getter(duk_context *ctx)\n", @@ -977,9 +995,12 @@ output_interface_attribute(FILE* outf, output_get_method_private(outf, interfacee->class_name); - output_cdata(outf, atributee->getter, GENBIND_NODE_TYPE_CDATA); + cdatac = output_cdata(outf, atributee->getter, GENBIND_NODE_TYPE_CDATA); - fprintf(outf,"\treturn 0;\n"); + if (cdatac == 0) { + /* no implementation so generate default */ + fprintf(outf,"\treturn 0;\n"); + } fprintf(outf, "}\n\n"); @@ -996,9 +1017,13 @@ output_interface_attribute(FILE* outf, output_get_method_private(outf, interfacee->class_name); - output_cdata(outf, atributee->setter, GENBIND_NODE_TYPE_CDATA); + cdatac = output_cdata(outf, atributee->setter, GENBIND_NODE_TYPE_CDATA); + + if (cdatac == 0) { + /* no implementation so generate default */ + fprintf(outf,"\treturn 0;\n"); + } - fprintf(outf,"\treturn 0;\n"); fprintf(outf, "}\n\n"); -- cgit v1.2.3 From dca5aa6db8f0dbcae283aee21605d8d1a85d7f94 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 5 Aug 2015 22:58:05 +0100 Subject: Add ptototype method type to binding This allows additional cdata to be added to the generated prototype constructor. --- src/duk-libdom.c | 15 +++++++++++++-- src/nsgenbind-ast.h | 11 ++++++----- src/nsgenbind-lexer.l | 2 ++ src/nsgenbind-parser.y | 6 ++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index 31ec0a1..b01ac4e 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -870,12 +870,23 @@ output_interface_prototype(FILE* outf, struct interface_map_entry *interfacee, struct interface_map_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", + 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, diff --git a/src/nsgenbind-ast.h b/src/nsgenbind-ast.h index 0b0fcfd..2a384b2 100644 --- a/src/nsgenbind-ast.h +++ b/src/nsgenbind-ast.h @@ -45,11 +45,12 @@ enum genbind_type_modifier { /* binding method types */ enum genbind_method_type { - GENBIND_METHOD_TYPE_INIT = 0, - GENBIND_METHOD_TYPE_FINI = 1, /**< */ - GENBIND_METHOD_TYPE_METHOD = 2, /**< */ - GENBIND_METHOD_TYPE_GETTER = 3, /**< */ - GENBIND_METHOD_TYPE_SETTER = 4, /**< */ + GENBIND_METHOD_TYPE_INIT = 0, /**< binding method is initialiser */ + GENBIND_METHOD_TYPE_FINI, /**< binding method is finalizer */ + GENBIND_METHOD_TYPE_METHOD, /**< binding method is a method */ + GENBIND_METHOD_TYPE_GETTER, /**< binding method is a getter */ + GENBIND_METHOD_TYPE_SETTER, /**< binding method is a setter */ + GENBIND_METHOD_TYPE_PROTOTYPE, /**< binding method is a prototype */ }; struct genbind_node; diff --git a/src/nsgenbind-lexer.l b/src/nsgenbind-lexer.l index f7b6528..d092195 100644 --- a/src/nsgenbind-lexer.l +++ b/src/nsgenbind-lexer.l @@ -135,6 +135,8 @@ getter return TOK_GETTER; setter return TOK_SETTER; +prototype return TOK_PROTOTYPE; + /* other terminals */ {dblcolon} return TOK_DBLCOLON; diff --git a/src/nsgenbind-parser.y b/src/nsgenbind-parser.y index 0f30dfc..1462b39 100644 --- a/src/nsgenbind-parser.y +++ b/src/nsgenbind-parser.y @@ -131,6 +131,7 @@ add_method(struct genbind_node **genbind_ast, %token TOK_METHOD %token TOK_GETTER %token TOK_SETTER +%token TOK_PROTOTYPE %token TOK_DBLCOLON @@ -339,6 +340,11 @@ MethodType { $$ = GENBIND_METHOD_TYPE_SETTER; } + | + TOK_PROTOTYPE + { + $$ = GENBIND_METHOD_TYPE_PROTOTYPE; + } ; ParameterList -- cgit v1.2.3 From e78ea8b28064181d9081e7ff0143830c4ec37d7f Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 6 Aug 2015 15:34:43 +0100 Subject: Enable warnings to be enabled and generated for unimplemented elements --- src/duk-libdom.c | 11 +++++++++++ src/nsgenbind.c | 18 ++++++++++++++++-- src/options.h | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/duk-libdom.c b/src/duk-libdom.c index b01ac4e..a2d65af 100644 --- a/src/duk-libdom.c +++ b/src/duk-libdom.c @@ -954,6 +954,9 @@ output_interface_operation(FILE* outf, if (cdatac == 0) { /* no implementation so generate default */ + WARN(WARNING_UNIMPLEMENTED, + "Unimplemented: method %s::%s();", + interfacee->name, operatione->name); fprintf(outf,"\treturn 0;\n"); } @@ -1009,6 +1012,10 @@ output_interface_attribute(FILE* outf, 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"); } @@ -1031,6 +1038,10 @@ output_interface_attribute(FILE* outf, 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"); } diff --git a/src/nsgenbind.c b/src/nsgenbind.c index 65feedd..173f23d 100644 --- a/src/nsgenbind.c +++ b/src/nsgenbind.c @@ -58,7 +58,22 @@ static struct options* process_cmdline(int argc, char **argv) break; case 'W': - options->warnings = 1; /* warning flags */ + if ((optarg == NULL) || + (strcmp(optarg, "all") == 0)) { + /* all warnings */ + options->warnings |= WARNING_ALL; + } else if (strcmp(optarg, "unimplemented") == 0) { + options->warnings |= WARNING_UNIMPLEMENTED; + } else if (strcmp(optarg, "duplicated") == 0) { + options->warnings |= WARNING_DUPLICATED; + } else { + fprintf(stderr, + "Unknown warning option \"%s\" valid options are: all, unimplemented\n", + optarg); + free(options); + return NULL; + + } break; default: /* '?' */ @@ -67,7 +82,6 @@ static struct options* process_cmdline(int argc, char **argv) argv[0]); free(options); return NULL; - } } diff --git a/src/options.h b/src/options.h index 85f107e..02674b7 100644 --- a/src/options.h +++ b/src/options.h @@ -32,7 +32,7 @@ enum opt_warnings { #define WARN(flags, msg, args...) do { \ if ((options->warnings & flags) != 0) { \ - fprintf(stderr, "%s: warning:"msg"\n", __func__, ## args); \ + fprintf(stderr, "%s: warning: "msg"\n", __func__, ## args); \ } \ } while(0) -- cgit v1.2.3 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 From 89f5a327b82d0f15c2988d918c8f9f57a156da36 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sun, 9 Aug 2015 11:22:27 +0100 Subject: Stop parallel runs of genbind temporary files conflicting. --- src/utils.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 1e8ec23..0952744 100644 --- a/src/utils.c +++ b/src/utils.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "options.h" #include "utils.h" @@ -35,7 +37,7 @@ static char *genb_fpath_tmp(const char *fname) fpathl = strlen(options->outdirname) + strlen(fname) + 3; fpath = malloc(fpathl); - snprintf(fpath, fpathl, "%s/%s~", options->outdirname, fname); + snprintf(fpath, fpathl, "%s/%s.%d", options->outdirname, fname, getpid()); return fpath; } @@ -111,6 +113,7 @@ int genb_fclose_tmp(FILE *filef_tmp, const char *fname) (memcmp(tbuf, fbuf, trd) != 0)) { /* file doesnt match */ fclose(filef_tmp); + fclose(filef); remove(fpath); rename(tpath, fpath); -- cgit v1.2.3