summaryrefslogtreecommitdiff
path: root/src/jsapi-libdom-new.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsapi-libdom-new.c')
-rw-r--r--src/jsapi-libdom-new.c395
1 files changed, 395 insertions, 0 deletions
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 <vince@netsurf-browser.org>
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#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;
+}