/* * A method is an `operation', therefore a method decl is an `op dcl'. * I blame Elliot. */ static gboolean op_dcl(TreeState *state) { GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments; /* * Verify that e.g. non-scriptable methods in [scriptable] interfaces * are declared so. Do this in a separate verification pass? */ if (!verify_method_declaration(state->tree)) return FALSE; if (doc_comments != NULL) { write_indent(state->file); printlist(state->file, doc_comments); } xpidl_write_comment(state, 2); write_indent(state->file); if (!write_method_signature(state->tree, state->file, AS_DECL, NULL)) return FALSE; fputs(" = 0;\n\n", state->file); return TRUE; }
static gboolean attr_dcl(TreeState *state) { GSList *doc_comments; if (!verify_attribute_declaration(state->tree)) return FALSE; doc_comments = IDL_IDENT(IDL_LIST(IDL_ATTR_DCL (state->tree).simple_declarations).data).comments; if (doc_comments != NULL && comment_level >= 2) { write_indent(state->file); printlist(state->file, doc_comments); } /* * XXX lists of attributes with the same type, e.g. * attribute string foo, bar sil; * are legal IDL... but we don't do anything with 'em. */ if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) { XPIDL_WARNING((state->tree, IDL_WARNING1, "multiple attributes in a single declaration aren't " "currently supported by xpidl")); } xpidl_write_comment(state, 2); write_indent(state->file); write_indent(state->file); if (!write_attr_accessor(state->tree, state->file, TRUE, NULL)) return FALSE; fputs(": Longword; stdcall;\n", state->file); if (!IDL_ATTR_DCL(state->tree).f_readonly) { write_indent(state->file); write_indent(state->file); if (!write_attr_accessor(state->tree, state->file, FALSE, NULL)) return FALSE; fputs(": Longword; stdcall;\n", state->file); } /*fputc('\n', state->file);*/ return TRUE; }
static gboolean interface(TreeState *state) { IDL_tree iface = state->tree, iter, orig; char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str; char *classNameUpper = NULL; char *classNameImpl = NULL; char *cp; gboolean ok = TRUE; gboolean keepvtable; const char *iid; const char *name_space; struct nsID id; char iid_parsed[UUID_LENGTH]; GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments; if (!verify_interface_declaration(iface)) return FALSE; #define FAIL do {ok = FALSE; goto out;} while(0) fprintf(state->file, "\n/* starting interface: %s */\n", className); name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace"); if (name_space) { fprintf(state->file, "/* namespace: %s */\n", name_space); fprintf(state->file, "/* fully qualified name: %s.%s */\n", name_space,className); } iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid"); if (iid) { /* Redundant, but a better error than 'cannot parse.' */ if (strlen(iid) != 36) { IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid); FAIL; } /* * Parse uuid and then output resulting nsID to string, to validate * uuid and normalize resulting .h files. */ if (!xpidl_parse_iid(&id, iid)) { IDL_tree_error(state->tree, "cannot parse IID %s\n", iid); FAIL; } if (!xpidl_sprint_iid(&id, iid_parsed)) { IDL_tree_error(state->tree, "error formatting IID %s\n", iid); FAIL; } /* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */ fputs("#define ", state->file); write_classname_iid_define(state->file, className); fprintf(state->file, "_STR \"%s\"\n", iid_parsed); fputc('\n', state->file); /* #define NS_ISUPPORTS_IID { {0x00000000 .... 0x46 }} */ fprintf(state->file, "#define "); write_classname_iid_define(state->file, className); fprintf(state->file, " \\\n" " {0x%.8x, 0x%.4x, 0x%.4x, \\\n" " { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, " "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }}\n", id.m0, id.m1, id.m2, id.m3[0], id.m3[1], id.m3[2], id.m3[3], id.m3[4], id.m3[5], id.m3[6], id.m3[7]); fputc('\n', state->file); } else { IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n", className); FAIL; } if (doc_comments != NULL) printlist(state->file, doc_comments); /* * NS_NO_VTABLE is defined in nsISupportsUtils.h, and defined on windows * to __declspec(novtable) on windows. This optimization is safe * whenever the constructor calls no virtual methods. Writing in IDL * almost guarantees this, except for the case when a %{C++ block occurs in * the interface. We detect that case, and emit a macro call that disables * the optimization. */ keepvtable = FALSE; for (iter = IDL_INTERFACE(state->tree).body; iter != NULL; iter = IDL_LIST(iter).next) { IDL_tree data = IDL_LIST(iter).data; if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG) keepvtable = TRUE; } /* The interface declaration itself. */ fprintf(state->file, "class %s%s", (keepvtable ? "" : "NS_NO_VTABLE "), className); if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { fputs(" : ", state->file); if (IDL_LIST(iter).next != NULL) { IDL_tree_error(iter, "multiple inheritance is not supported by xpidl"); FAIL; } fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str); } fputs(" {\n" " public: \n\n", state->file); if (iid) { fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file); write_classname_iid_define(state->file, className); fputs(")\n\n", state->file); } orig = state->tree; /* It would be nice to remove this state-twiddling. */ state->tree = IDL_INTERFACE(iface).body; if (state->tree && !xpidl_process_node(state)) FAIL; fputs("};\n", state->file); fputc('\n', state->file); /* * #define NS_DECL_NSIFOO - create method prototypes that can be used in * class definitions that support this interface. * * Walk the tree explicitly to prototype a reworking of xpidl to get rid of * the callback mechanism. */ state->tree = orig; fputs("/* Use this macro when declaring classes that implement this " "interface. */\n", state->file); fputs("#define NS_DECL_", state->file); classNameUpper = xpidl_strdup(className); for (cp = classNameUpper; *cp != '\0'; cp++) *cp = toupper(*cp); fprintf(state->file, "%s \\\n", classNameUpper); if (IDL_INTERFACE(state->tree).body == NULL) { write_indent(state->file); fputs("/* no methods! */\n", state->file); } for (iter = IDL_INTERFACE(state->tree).body; iter != NULL; iter = IDL_LIST(iter).next) { IDL_tree data = IDL_LIST(iter).data; switch(IDL_NODE_TYPE(data)) { case IDLN_OP_DCL: write_indent(state->file); write_method_signature(data, state->file, AS_DECL, NULL); break; case IDLN_ATTR_DCL: write_indent(state->file); if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) FAIL; if (!IDL_ATTR_DCL(data).f_readonly) { fputs("; \\\n", state->file); /* Terminate the previous one. */ write_indent(state->file); if (!write_attr_accessor(data, state->file, FALSE, AS_DECL, NULL)) FAIL; /* '; \n' at end will clean up. */ } break; case IDLN_CONST_DCL: /* ignore it here; it doesn't contribute to the macro. */ continue; case IDLN_CODEFRAG: XPIDL_WARNING((iter, IDL_WARNING1, "%%{ .. %%} code fragment within interface " "ignored when generating NS_DECL_%s macro; " "if the code fragment contains method " "declarations, the macro probably isn't " "complete.", classNameUpper)); continue; default: IDL_tree_error(iter, "unexpected node type %d! " "Please file a bug against the xpidl component.", IDL_NODE_TYPE(data)); FAIL; } if (IDL_LIST(iter).next != NULL) { fprintf(state->file, "; \\\n"); } else { fprintf(state->file, "; \n"); } } fputc('\n', state->file); /* XXX abstract above and below into one function? */ /* * #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate * behavior from in implementation to another object. As generated by * idlc. */ fprintf(state->file, "/* Use this macro to declare functions that forward the " "behavior of this interface to another object. */\n" "#define NS_FORWARD_%s(_to) \\\n", classNameUpper); if (IDL_INTERFACE(state->tree).body == NULL) { write_indent(state->file); fputs("/* no methods! */\n", state->file); } for (iter = IDL_INTERFACE(state->tree).body; iter != NULL; iter = IDL_LIST(iter).next) { IDL_tree data = IDL_LIST(iter).data; switch(IDL_NODE_TYPE(data)) { case IDLN_OP_DCL: write_indent(state->file); write_method_signature(data, state->file, AS_DECL, NULL); fputs(" { return _to ", state->file); write_method_signature(data, state->file, AS_CALL, NULL); break; case IDLN_ATTR_DCL: write_indent(state->file); if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) FAIL; fputs(" { return _to ", state->file); if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL)) FAIL; if (!IDL_ATTR_DCL(data).f_readonly) { fputs("; } \\\n", state->file); /* Terminate the previous one. */ write_indent(state->file); if (!write_attr_accessor(data, state->file, FALSE, AS_DECL, NULL)) FAIL; fputs(" { return _to ", state->file); if (!write_attr_accessor(data, state->file, FALSE, AS_CALL, NULL)) FAIL; /* '; } \n' at end will clean up. */ } break; case IDLN_CONST_DCL: case IDLN_CODEFRAG: continue; default: FAIL; } if (IDL_LIST(iter).next != NULL) { fprintf(state->file, "; } \\\n"); } else { fprintf(state->file, "; } \n"); } } fputc('\n', state->file); /* XXX abstract above and below into one function? */ /* * #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate * behavior from in implementation to another object. As generated by * idlc. */ fprintf(state->file, "/* Use this macro to declare functions that forward the " "behavior of this interface to another object in a safe way. */\n" "#define NS_FORWARD_SAFE_%s(_to) \\\n", classNameUpper); if (IDL_INTERFACE(state->tree).body == NULL) { write_indent(state->file); fputs("/* no methods! */\n", state->file); } for (iter = IDL_INTERFACE(state->tree).body; iter != NULL; iter = IDL_LIST(iter).next) { IDL_tree data = IDL_LIST(iter).data; switch(IDL_NODE_TYPE(data)) { case IDLN_OP_DCL: write_indent(state->file); write_method_signature(data, state->file, AS_DECL, NULL); fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); write_method_signature(data, state->file, AS_CALL, NULL); break; case IDLN_ATTR_DCL: write_indent(state->file); if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) FAIL; fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL)) FAIL; if (!IDL_ATTR_DCL(data).f_readonly) { fputs("; } \\\n", state->file); /* Terminate the previous one. */ write_indent(state->file); if (!write_attr_accessor(data, state->file, FALSE, AS_DECL, NULL)) FAIL; fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); if (!write_attr_accessor(data, state->file, FALSE, AS_CALL, NULL)) FAIL; /* '; } \n' at end will clean up. */ } break; case IDLN_CONST_DCL: case IDLN_CODEFRAG: continue; default: FAIL; } if (IDL_LIST(iter).next != NULL) { fprintf(state->file, "; } \\\n"); } else { fprintf(state->file, "; } \n"); } } fputc('\n', state->file); /* * Build a sample implementation template. */ if (strlen(className) >= 3 && className[2] == 'I') { classNameImpl = xpidl_strdup(className); if (!classNameImpl) FAIL; memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2); } else { classNameImpl = xpidl_strdup("_MYCLASS_"); if (!classNameImpl) FAIL; } fputs("#if 0\n" "/* Use the code below as a template for the " "implementation class for this interface. */\n" "\n" "/* Header file */" "\n", state->file); fprintf(state->file, "class %s : public %s\n", classNameImpl, className); fputs("{\n" "public:\n", state->file); write_indent(state->file); fputs("NS_DECL_ISUPPORTS\n", state->file); write_indent(state->file); fprintf(state->file, "NS_DECL_%s\n", classNameUpper); fputs("\n", state->file); write_indent(state->file); fprintf(state->file, "%s();\n", classNameImpl); fputs("\n" "private:\n", state->file); write_indent(state->file); fprintf(state->file, "~%s();\n", classNameImpl); fputs("\n" "protected:\n", state->file); write_indent(state->file); fputs("/* additional members */\n", state->file); fputs("};\n\n", state->file); fputs("/* Implementation file */\n", state->file); fprintf(state->file, "NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className); fputs("\n", state->file); fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl); fputs("{\n", state->file); write_indent(state->file); fputs("/* member initializers and constructor code */\n", state->file); fputs("}\n\n", state->file); fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl); fputs("{\n", state->file); write_indent(state->file); fputs("/* destructor code */\n", state->file); fputs("}\n\n", state->file); for (iter = IDL_INTERFACE(state->tree).body; iter != NULL; iter = IDL_LIST(iter).next) { IDL_tree data = IDL_LIST(iter).data; switch(IDL_NODE_TYPE(data)) { case IDLN_OP_DCL: /* It would be nice to remove this state-twiddling. */ orig = state->tree; state->tree = data; xpidl_write_comment(state, 0); state->tree = orig; write_method_signature(data, state->file, AS_IMPL, classNameImpl); fputs("\n{\n", state->file); write_indent(state->file); write_indent(state->file); fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" "}\n" "\n", state->file); break; case IDLN_ATTR_DCL: /* It would be nice to remove this state-twiddling. */ orig = state->tree; state->tree = data; xpidl_write_comment(state, 0); state->tree = orig; if (!write_attr_accessor(data, state->file, TRUE, AS_IMPL, classNameImpl)) FAIL; fputs("\n{\n", state->file); write_indent(state->file); write_indent(state->file); fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" "}\n", state->file); if (!IDL_ATTR_DCL(data).f_readonly) { if (!write_attr_accessor(data, state->file, FALSE, AS_IMPL, classNameImpl)) FAIL; fputs("\n{\n", state->file); write_indent(state->file); write_indent(state->file); fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" "}\n", state->file); } fputs("\n", state->file); break; case IDLN_CONST_DCL: case IDLN_CODEFRAG: continue; default: FAIL; } } fputs("/* End of implementation class template. */\n" "#endif\n" "\n", state->file); #undef FAIL out: if (classNameUpper) free(classNameUpper); if (classNameImpl) free(classNameImpl); return ok; }
static gboolean attribute_declaration(TreeState *state) { gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly; char *attribute_name = ATTR_IDENT(state->tree).str; gboolean method_noscript = (IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript") != NULL); gboolean method_notxpcom = (IDL_tree_property_get(ATTR_PROPS(state->tree), "notxpcom") != NULL); #if 0 /* * Disabled here because I can't verify this check against possible * users of the java xpidl backend. */ if (!verify_attribute_declaration(state->tree)) return FALSE; #endif /* Comment */ fputc('\n', state->file); xpidl_write_comment(state, 4); #if 1 /* * Write access permission ("public") */ fputs(" public ", state->file); #else if (method_notxpcom || method_noscript) return TRUE; /* * Write access permission ("public" unless nonscriptable) */ fputs(" ", state->file); if (!method_noscript) { fputs("public ", state->file); } #endif /* * Write the proper Java return value for the get operation */ if (!xpcom_to_java_type(state, ATTR_TYPE_DECL(state->tree))) { return FALSE; } /* * Write the name of the accessor ("get") method. */ fprintf(state->file, " get%c%s();\n", toupper(attribute_name[0]), attribute_name + 1); if (!read_only) { #if 1 fputs(" public ", state->file); #else /* Nonscriptable methods become package-protected */ fputs(" ", state->file); if (!method_noscript) { fputs("public ", state->file); } #endif /* * Write attribute access method name and return type */ fprintf(state->file, "void set%c%s(", toupper(attribute_name[0]), attribute_name+1); /* * Write the proper Java type for the set operation */ if (!xpcom_to_java_type(state, ATTR_TYPE_DECL(state->tree))) { return FALSE; } /* * Write the name of the formal parameter. */ fprintf(state->file, " a%c%s);\n", toupper(attribute_name[0]), attribute_name + 1); } return TRUE; }
static gboolean constant_declaration(TreeState *state) { /* * The C++ header XPIDL module only allows for shorts and longs (ints) * to be constants, so we will follow the same convention */ struct _IDL_CONST_DCL *declaration = &IDL_CONST_DCL(state->tree); const char *name = IDL_IDENT(declaration->ident).str; IDL_tree real_type; gboolean success; gboolean isshort = FALSE; if (!verify_const_declaration(state->tree)) return FALSE; /* Could be a typedef; try to map it to the real type. */ real_type = find_underlying_type(declaration->const_type); real_type = real_type ? real_type : declaration->const_type; /* * Consts must be in an interface */ if (!IDL_NODE_UP(IDL_NODE_UP(state->tree)) || IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(state->tree))) != IDLN_INTERFACE) { XPIDL_WARNING((state->tree, IDL_WARNING1, "A constant \"%s\" was declared outside an interface." " It was ignored.", name)); return TRUE; } /* * Make sure this is a numeric short or long constant. */ success = (IDLN_TYPE_INTEGER == IDL_NODE_TYPE(real_type)); if (success) { /* * We aren't successful yet, we know it's an integer, but what *kind* * of integer? */ switch(IDL_TYPE_INTEGER(real_type).f_type) { case IDL_INTEGER_TYPE_SHORT: /* * We're OK */ isshort = TRUE; break; case IDL_INTEGER_TYPE_LONG: /* * We're OK */ break; default: /* * Whoops, it's some other kind of number */ success = FALSE; } } else { IDL_tree_error(state->tree, "const declaration \'%s\' must be of type short or long", name); return FALSE; } /* if (doc_comments != NULL) { fputs(" ", state->file); printlist(state->file, doc_comments); } */ if (success) { /* Since Java does not have any concept of 'unsigned short', we need * to check that the value is in the proper range. If not, promote * it to an 'int'. */ int value = (int) IDL_INTEGER(declaration->const_exp).value; if (isshort && (value < -32768 || value > 32767)) isshort = FALSE; fputc('\n', state->file); xpidl_write_comment(state, 4); /* write_comment(state); */ fprintf(state->file, " public static final %s %s = %d;\n", (isshort ? "short" : "int"), subscriptIdentifier(state, (char*) name), (int) IDL_INTEGER(declaration->const_exp).value); } else { XPIDL_WARNING((state->tree, IDL_WARNING1, "A constant \"%s\" was not of type short or long." " It was ignored.", name)); } return TRUE; }
static gboolean method_declaration(TreeState *state) { const char* array = NULL; struct _IDL_OP_DCL *method = &IDL_OP_DCL(state->tree); gboolean method_notxpcom = (IDL_tree_property_get(method->ident, "notxpcom") != NULL); gboolean method_noscript = (IDL_tree_property_get(method->ident, "noscript") != NULL); IDL_tree iterator = NULL; IDL_tree retval_param = NULL; char *method_name = g_strdup_printf("%c%s", tolower(IDL_IDENT(method->ident).str[0]), IDL_IDENT(method->ident).str + 1); if (!verify_method_declaration(state->tree)) return FALSE; fputc('\n', state->file); xpidl_write_comment(state, 4); #if 1 /* do not write non-xpcom methods */ if (method_notxpcom) { return TRUE; } /* * Write beginning of method declaration */ fputs(" public ", state->file); #else /* do not write nonscriptable methods */ if (method_notxpcom || method_noscript) { return TRUE; } /* * Write beginning of method declaration */ fputs(" ", state->file); if (!method_noscript) { /* Nonscriptable methods become package-protected */ fputs("public ", state->file); } #endif /* * Write return type * Unlike C++ headers, Java interfaces return the declared * return value; an exception indicates XPCOM method failure. */ if (method->op_type_spec) { state->tree = method->op_type_spec; if (!xpcom_to_java_type(state, method->op_type_spec)) { return FALSE; } } else { /* Check for retval attribute */ for (iterator = method->parameter_dcls; iterator != NULL; iterator = IDL_LIST(iterator).next) { IDL_tree original_tree = state->tree; state->tree = IDL_LIST(iterator).data; if (IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, "retval")) { retval_param = iterator; array = IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, "array"); /* * Put in type of parameter */ if (!xpcom_to_java_type(state, IDL_PARAM_DCL(state->tree).param_type_spec)) { return FALSE; } if (array) fputs("[]", state->file); } state->tree = original_tree; } if (retval_param == NULL) { fputs("void", state->file); } } /* * Write method name */ fprintf(state->file, " %s(", subscriptIdentifier(state, method_name)); /* * Write parameters */ for (iterator = method->parameter_dcls; iterator != NULL; iterator = IDL_LIST(iterator).next) { /* Skip "retval" */ if (iterator == retval_param) { continue; } if (iterator != method->parameter_dcls) { fputs(", ", state->file); } state->tree = IDL_LIST(iterator).data; if (!xpcom_to_java_param(state)) { return FALSE; } } fputs(")", state->file); /* XXX Disable this for now. How do we specify exceptions? if (method->raises_expr) { IDL_tree iter = method->raises_expr; IDL_tree dataNode = IDL_LIST(iter).data; fputs(" throws ", state->file); fputs(IDL_IDENT(dataNode).str, state->file); iter = IDL_LIST(iter).next; while (iter) { dataNode = IDL_LIST(iter).data; fprintf(state->file, ", %s", IDL_IDENT(dataNode).str); iter = IDL_LIST(iter).next; } } */ fputs(";\n", state->file); return TRUE; }