/* 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 generate_property_tinyid(struct binding *binding, const char *interface); static int generate_property_spec(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, struct binding_interface *inf, const char *argname) { int ret = 0; if (binding->has_private) { ret = fprintf(binding->outfile, "\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, "\tJSLOG(\"jscontext:%%p jsobject:%%p private:%%p\", cx, obj, %s);\n", argname); } } else { if (options->dbglog) { ret += fprintf(binding->outfile, "\tJSLOG(\"jscontext:%%p jsobject:%%p\", cx, obj);\n"); } } return ret; } /* generate vars for property name getter */ static inline int output_property_name_get_vars(struct binding *binding, const char *argname) { /* get property name */ return fprintf(binding->outfile, "\tjsval %s_jsval;\n" "\tJSString *%s_jsstr = NULL;\n" "\tint %s_len = 0;\n" "\tchar *%s = NULL;\n", argname, argname, argname, argname); } /* generate vars for property tinyid getter */ static inline int output_property_tinyid_get_vars(struct binding *binding, const char *argname) { /* get property name */ return fprintf(binding->outfile, "\tjsval %s_jsval;\n" "\tint8_t %s = JSAPI_PROP_TINYID_END;\n", argname, argname); } /* generate property name getter */ static inline int output_property_name_get(struct binding *binding, const char *argname) { /* get property name */ return fprintf(binding->outfile, "\t /* obtain property name */\n" "\tJSAPI_PROP_IDVAL(cx, &%s_jsval);\n" "\t%s_jsstr = JS_ValueToString(cx, %s_jsval);\n" "\tif (%s_jsstr != NULL) {\n" "\t\tJSString_to_char(%s_jsstr, %s, %s_len);\n" "\t}\n\n", argname,argname,argname,argname,argname,argname,argname); } /* generate property name getter */ static inline int output_property_tinyid_get(struct binding *binding, const char *argname) { /* get property name */ return fprintf(binding->outfile, "\t /* obtain property tinyid */\n" "\tJSAPI_PROP_IDVAL(cx, &%s_jsval);\n" "\t%s = JSVAL_TO_INT(%s_jsval);\n\n", argname, argname, argname); } /******************************** tinyid ********************************/ static int webidl_property_tinyid_cb(struct webidl_node *node, void *ctx) { struct binding *binding = ctx; struct webidl_node *ident_node; const char *ident; ident_node = webidl_node_find_type(webidl_node_getnode(node), NULL, WEBIDL_NODE_TYPE_IDENT); ident = webidl_node_gettext(ident_node); if (ident == NULL) { /* properties must have an operator * http://www.w3.org/TR/WebIDL/#idl-attributes */ return -1; } fprintf(binding->outfile, "\tJSAPI_PROP_TINYID_%s,\n", ident); return 0; } static int generate_property_tinyid(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_tinyid_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_tinyid(binding, webidl_node_gettext(inherit_node)); } return res; } /* exported interface documented in jsapi-libdom.h */ int output_property_tinyid(struct binding *binding) { int res; fprintf(binding->outfile, "enum property_tinyid {\n"); res = generate_property_tinyid(binding, binding->interface); fprintf(binding->outfile, "\tJSAPI_PROP_TINYID_END,\n" "};\n\n"); return res; } /******************************** specifier ********************************/ /* search binding for property sharing modifier */ static enum genbind_type_modifier get_binding_shared_modifier(struct binding *binding, const char *type, const char *ident) { 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, NULL, GENBIND_NODE_TYPE_BINDING_PROPERTY, ident); /* look for a node matching the type */ if (shared_node == NULL) { shared_node = genbind_node_find_type_ident(binding->binding_list, NULL, GENBIND_NODE_TYPE_BINDING_PROPERTY, type); } if (shared_node != NULL) { /* no explicit shared status */ shared_mod_node = genbind_node_find_type(genbind_node_getnode(shared_node), NULL, GENBIND_NODE_TYPE_MODIFIER); shared_modifier = (enum genbind_type_modifier *)genbind_node_getint(shared_mod_node); if (shared_modifier != NULL) { return *shared_modifier; } } return GENBIND_TYPE_NONE; } /* obtain the value for a key/value type extended attribute */ static char * get_keyval_extended_attribute(struct webidl_node *node, const char *attribute) { struct webidl_node *ext_node; struct webidl_node *ident_node; char *value; ext_node = webidl_node_find_type_ident(webidl_node_getnode(node), WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE, attribute); if (ext_node == NULL) { return NULL; /* no matching extended attribute at all */ } /* should be extended atrribute name node */ ident_node = webidl_node_find_type(webidl_node_getnode(ext_node), NULL, WEBIDL_NODE_TYPE_IDENT); if (ident_node == NULL) { /* not the attribute name already matched - bail * somethings broken */ return NULL; } value = webidl_node_gettext(ident_node); if (strcmp(attribute, value) != 0) { /* not the attribute name already matched - bail * somethings broken */ return NULL; } /* should be an = sign for key/value pair */ ident_node = webidl_node_find_type(webidl_node_getnode(ext_node), ident_node, WEBIDL_NODE_TYPE_IDENT); if (ident_node == NULL) { /* no additional attribute - not key/value then */ return NULL; } value = webidl_node_gettext(ident_node); if (strcmp("=", value) != 0) { /* not a key/value pair then */ return NULL; } /* value */ ident_node = webidl_node_find_type(webidl_node_getnode(ext_node), ident_node, WEBIDL_NODE_TYPE_IDENT); if (ident_node == NULL) { /* no value */ return NULL; } value = webidl_node_gettext(ident_node); return value; } static bool property_is_ro(struct webidl_node *node) { struct webidl_node *modifier_node; modifier_node = webidl_node_find_type(webidl_node_getnode(node), NULL, WEBIDL_NODE_TYPE_MODIFIER); if (webidl_node_getint(modifier_node) == WEBIDL_TYPE_READONLY) { return true; } return false; } static int webidl_property_spec(struct binding *binding, struct binding_interface *inf, struct webidl_node *node) { 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, WEBIDL_NODE_TYPE_IDENT); ident = webidl_node_gettext(ident_node); if (ident == NULL) { /* properties must have an operator * http://www.w3.org/TR/WebIDL/#idl-attributes */ return -1; } /* get type name */ type_node = webidl_node_find_type(webidl_node_getnode(node), NULL, WEBIDL_NODE_TYPE_TYPE); ident_node = webidl_node_find_type(webidl_node_getnode(type_node), NULL, WEBIDL_NODE_TYPE_IDENT); type = webidl_node_gettext(ident_node); /* generate JSAPI_PS macro entry */ /* if there is a putforwards the property requires a setter */ if ((property_is_ro(node)) && (get_keyval_extended_attribute(node, "PutForwards") == NULL)) { ro = true; } /* generate property shared status */ switch (get_binding_shared_modifier(binding, type, ident)) { default: case GENBIND_TYPE_NONE: /* shared property without type handler * * js doesnt provide storage and setter/getter must * perform all GC management. */ 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, "\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, "\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, "\tJSAPI_PS_ID_%s(%s, %s, 0, %s),\n", ro?"RO":"RW", inf->name, ident, type); break; } return 0; } /* 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; } /* generate property specifier */ fprintf(binding->outfile, "static JSPropertySpec JSClass_%s_properties[] = {\n", binding->interfaces[inf].name); /* 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_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); } 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; } /******************************** body ********************************/ static int output_return(struct binding *binding, const char *ident, struct webidl_node *node) { struct webidl_node *type_node = NULL; struct webidl_node *type_base = NULL; struct webidl_node *type_nullable = 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); type_nullable = webidl_node_find_type(webidl_node_getnode(type_node), NULL, WEBIDL_NODE_TYPE_TYPE_NULLABLE); switch (webidl_arg_type) { case WEBIDL_TYPE_USER: /* User type are represented with jsobject */ fprintf(binding->outfile, "\tJSAPI_PROP_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(%s));\n", ident); break; case WEBIDL_TYPE_BOOL: /* JSBool */ fprintf(binding->outfile, "\tJSAPI_PROP_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_PROP_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(%s));\n", ident); break; case WEBIDL_TYPE_SHORT: /* int16_t */ fprintf(binding->outfile, "\tJSAPI_PROP_SET_RVAL(cx, vp, INT_TO_JSVAL(%s));\n", ident); break; case WEBIDL_TYPE_LONGLONG: WARN(WARNING_UNIMPLEMENTED, "Unhandled type WEBIDL_TYPE_LONGLONG"); break; case WEBIDL_TYPE_LONG: /* int32_t */ fprintf(binding->outfile, "\tJSAPI_PROP_SET_RVAL(cx, vp, INT_TO_JSVAL(%s));\n", ident); break; case WEBIDL_TYPE_STRING: /* JSString * */ if (type_nullable == NULL) { /* entry is not nullable ensure it is set to a string */ fprintf(binding->outfile, "\tif (%s == NULL) {\n" "\t\t%s = JS_NewStringCopyN(cx, NULL, 0);\n" "\t}\n", ident, ident); } fprintf(binding->outfile, "\tJSAPI_PROP_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_PROP_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 *type_node = NULL; struct webidl_node *type_base = NULL; struct webidl_node *type_name = NULL; struct webidl_node *type_mod = 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_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: /* int16_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, "\tuint16_t %s = 0;\n", ident); } else { fprintf(binding->outfile, "\tint16_t %s = 0;\n", ident); } 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; } static int output_property_placeholder(struct binding *binding, struct binding_interface *inf, struct webidl_node* oplist, const char *ident) { oplist=oplist; WARN(WARNING_UNIMPLEMENTED, "property %s.%s has no implementation\n", inf->name, ident); if (options->dbglog) { fprintf(binding->outfile, "\tJSLOG(\"property %s.%s has no implementation\");\n", 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_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, inf, "private"); property_node = genbind_node_find_type_ident(binding->gb_ast, NULL, GENBIND_NODE_TYPE_GETTER, ident); if (property_node != NULL) { /* binding source block */ output_code_block(binding, genbind_node_getnode(property_node)); } else { /* examine internal variables and see if they are gettable */ struct genbind_node *binding_node; struct genbind_node *internal_node = NULL; binding_node = genbind_node_find_type(binding->gb_ast, NULL, GENBIND_NODE_TYPE_BINDING); if (binding_node != NULL) { internal_node = genbind_node_find_type_ident(genbind_node_getnode(binding_node), NULL, GENBIND_NODE_TYPE_BINDING_INTERNAL, ident); } if (internal_node != NULL) { /** @todo fetching from internal entries ought to be type sensitive */ fprintf(binding->outfile, "\tjsret = private->%s;\n", ident); } else { output_property_placeholder(binding, inf, node, ident); } } output_return(binding, "jsret", node); fprintf(binding->outfile, "\treturn JS_TRUE;\n" "}\n\n"); return 0; } static int output_property_setter(struct binding *binding, struct binding_interface *inf, struct webidl_node *node, const char *property_ident) { struct genbind_node *property_node; char *putforwards; putforwards = get_keyval_extended_attribute(node, "PutForwards"); if (putforwards != NULL) { /* generate a putforwards setter */ fprintf(binding->outfile, "/* PutForwards setter */\n" "static JSBool JSAPI_PROP_SET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", 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", property_ident, putforwards); fprintf(binding->outfile, "\treturn JS_FALSE; /* disallow the asignment */\n" "}\n\n"); return 0; } if (property_is_ro(node)) { /* readonly so a set function is not required */ return 0; } property_node = genbind_node_find_type_ident(binding->gb_ast, NULL, GENBIND_NODE_TYPE_SETTER, property_ident); fprintf(binding->outfile, "static JSBool JSAPI_PROP_SET(%s, %s, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", inf->name, property_ident); 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, inf, node, property_ident); } fprintf(binding->outfile, " return JS_FALSE; /* disallow the asignment by default */\n" "}\n\n"); return 0; } /** * generate atribute (property) body. */ static int webidl_property_body(struct binding *binding, struct binding_interface *inf, struct webidl_node *node) { struct webidl_node *ident_node; const char *ident; struct webidl_node *type_node; const char *type = NULL; int ret; enum genbind_type_modifier shared_mod; ident_node = webidl_node_find_type(webidl_node_getnode(node), NULL, WEBIDL_NODE_TYPE_IDENT); ident = webidl_node_gettext(ident_node); if (ident == NULL) { /* properties must have an operator * http://www.w3.org/TR/WebIDL/#idl-attributes */ return -1; } /* get type name */ type_node = webidl_node_find_type(webidl_node_getnode(node), NULL, WEBIDL_NODE_TYPE_TYPE); ident_node = webidl_node_find_type(webidl_node_getnode(type_node), NULL, WEBIDL_NODE_TYPE_IDENT); type = webidl_node_gettext(ident_node); /* find shared modifiers */ shared_mod = get_binding_shared_modifier(binding, type, ident); /* only generate individual getters/setters if there is not a * type handler */ if ((shared_mod & GENBIND_TYPE_TYPE) == 0) { ret = output_property_setter(binding, inf, node, ident); if (ret == 0) { /* property getter */ ret = output_property_getter(binding, inf, node, ident); } } return ret; } /* setter for type handler */ static int output_property_type_setter(struct binding *binding, struct binding_interface *inf, struct genbind_node *node, const char *type) { struct genbind_node *property_node; node = node;/* currently unused */ fprintf(binding->outfile, "static JSBool\n" "JSAPI_STRICTPROP(%s_set, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", type); /* property name vars */ output_property_tinyid_get_vars(binding, "tinyid"); /* context data */ output_private_get(binding, inf, "private"); /* property name */ output_property_tinyid_get(binding, "tinyid"); /* output binding code block */ property_node = genbind_node_find_type_ident(binding->gb_ast, NULL, GENBIND_NODE_TYPE_SETTER, type); if (property_node != NULL) { /* binding source block */ output_code_block(binding, genbind_node_getnode(property_node)); } fprintf(binding->outfile, "\treturn JS_TRUE;\n" "}\n\n"); return 0; } /* getter for type handlers */ 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 */ fprintf(binding->outfile, "static JSBool JSAPI_PROP(%s_get, JSContext *cx, JSObject *obj, jsval *vp)\n" "{\n", type); /* property tinyid vars */ output_property_tinyid_get_vars(binding, "tinyid"); /* context data */ output_private_get(binding, inf, "private"); /* property tinyid */ output_property_tinyid_get(binding, "tinyid"); /* output binding code block */ property_node = genbind_node_find_type_ident(binding->gb_ast, NULL, GENBIND_NODE_TYPE_GETTER, type); if (property_node != NULL) { /* binding source block */ output_code_block(binding, genbind_node_getnode(property_node)); } fprintf(binding->outfile, " return JS_TRUE;\n" "}\n\n"); return 0; } /* callback to emit property handlers for whole types */ static int typehandler_property_cb(struct genbind_node *node, void *ctx) { struct binding *binding = ctx; struct genbind_node *ident_node; const char *type; 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, GENBIND_NODE_TYPE_MODIFIER); 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), NULL, GENBIND_NODE_TYPE_IDENT); type = genbind_node_gettext(ident_node); if (type != NULL) { ret = output_property_type_setter(binding, inf, node, type); if (ret == 0) { /* property getter */ ret = output_property_type_getter(binding, inf, node, type); } } } return ret; } /** * 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; /* check if the interface has any properties with type handlers */ if (!inf->has_type_properties) { return 0; } 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; }