summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README229
-rw-r--r--src/duk-libdom.c326
-rw-r--r--src/nsgenbind-parser.y124
-rw-r--r--test/data/bindings/HTMLUnknownElement.bnd2
-rw-r--r--test/data/bindings/browser-duk.bnd113
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" \
@@ -95,6 +98,40 @@ static char *gen_class_name(struct interface_map_entry *interfacee)
}
/**
+ * 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.
*
* used for pre/pro/epi/post sections
@@ -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()