Back to index

lightning-sunbird  0.9+nobinonly
xpidl_java.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Sun Microsystems, Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Michael Allen (michael.allen@sun.com)
00024  *   Frank Mitchell (frank.mitchell@sun.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /*
00041  * Generate Java interfaces from XPIDL.
00042  */
00043 
00044 #include "xpidl.h"
00045 #include <ctype.h>
00046 #include <glib.h>
00047 
00048 #ifdef XP_WIN
00049 #include <windef.h>
00050 #define PATH_MAX  MAX_PATH
00051 #elif defined(XP_OS2) && !defined(PATH_MAX)
00052 #include <os2.h>
00053 #define PATH_MAX  CCHMAXPATH
00054 #endif
00055 
00056 /* XXX Bug 331178 - nsIScriptSecurityManager inherits from non-scriptable
00057  * interface nsIXPCSecurityManager. To work around that, we write out a
00058  * Java interface for nsIXPCSecurityManager, but don't give it any methods.
00059  */
00060 #define CREATE_NSIXPCSECURITYMANAGER
00061 
00062 /* XXX Bug 324035 - XPIDL cannot tell whether a forward declared interface is
00063  * itself defined in an IDL file (in which case XPIDL will have also written
00064  * out a Java interface file) or if it is just defined in a C header (in which
00065  * case there will be an error when trying to compile the Java interfaces).
00066  * This workaround lists the infringing interfaces and writes out "nsISupports"
00067  * when encountering those types.
00068  */
00069 #define HANDLE_NON_IDL_IFACES
00070 
00071 /* XXX Bug 340009 - SWT depends on several [noscript] methods in order to
00072  * embed Mozilla in an SWT view.  This hack makes those methods available
00073  * to Java embedders.
00074  */
00075 #define OUTPUT_SWT_NOSCRIPT_METHODS
00076 
00077 /* XXX If an interface method throws an exception, how do we handle it? */
00078 /*#define HANDLE_EXCEPTIONS*/
00079 
00080 
00081 static char* subscriptIdentifier(TreeState *state, char *str);
00082 
00083 static char* javaKeywords[] = {
00084   "abstract", "default"  , "if"        , "private"     , "throw"       ,
00085   "boolean" , "do"       , "implements", "protected"   , "throws"      ,
00086   "break"   , "double"   , "import",     "public"      , "transient"   ,
00087   "byte"    , "else"     , "instanceof", "return"      , "try"         ,
00088   "case"    , "extends"  , "int"       , "short"       , "void"        ,
00089   "catch"   , "final"    , "interface" , "static"      , "volatile"    ,
00090   "char"    , "finally"  , "long"      , "super"       , "while"       ,
00091   "class"   , "float"    , "native"    , "switch"      ,
00092   "const"   , "for"      , "new"       , "synchronized",
00093   "continue", "goto"     , "package"   , "this"        ,
00094     /* added in Java 1.2 */
00095   "strictfp",
00096     /* added in Java 1.4 */
00097   "assert"  ,
00098     /* added in Java 5.0 */
00099   "enum"    ,
00100     /* Java constants */
00101   "true"    , "false"    , "null"      ,
00102     /* java.lang.Object methods                                           *
00103      *    - don't worry about "toString", since it does the same thing    *
00104      *      as Object's "toString"                                        */
00105   "clone"   , "equals"   , "finalize"  , "getClass"    , "hashCode"    ,
00106   "notify"  , "notifyAll", /*"toString"  ,*/ "wait"
00107 };
00108 
00109 #ifdef HANDLE_NON_IDL_IFACES
00110 static char* nonIDLIfaces[] = {
00111     "nsIPresShell",
00112     "nsIDocument",
00113     "nsIObjectFrame",
00114     "nsObjectFrame",
00115     "nsIFrame",
00116     "nsIContent",
00117     "nsILayoutHistoryState",
00118     "nsIMdbEnv",
00119     "nsIMdbTable",
00120     "nsIMdbRow",
00121     "nsIChannelSecurityInfo",
00122     "nsIUnicodeDecoder",
00123     "nsIUnicodeEncoder",
00124     "nsIServiceManagerObsolete",
00125     "nsIWordBreaker",
00126     "nsISecureEnv",
00127     "nsIScrollbarMediator",
00128     "nsIScriptContext",
00129     "nsIScriptGlobalObject",
00130     "nsIScriptElement",
00131     "nsIFrameSelection",
00132     "nsIWidget",
00133     "nsIMenuItem",
00134     "nsIMenuBar"
00135 };
00136 #define NONIDLS(state)      (((struct java_priv_data *)state->priv)->nonIDLIfaces)
00137 #endif
00138 
00139 #define TYPEDEFS(state)     (((struct java_priv_data *)state->priv)->typedefTable)
00140 #define PRIVDATA(state)     (((struct java_priv_data *)state->priv))
00141 #define KEYWORDS(state)     (((struct java_priv_data *)state->priv)->keywords)
00142 
00143 static void
00144 write_indent(FILE *outfile) {
00145     fputs("  ", outfile);
00146 }
00147 
00148 static gboolean
00149 write_classname_iid_define(FILE *file, const char *className)
00150 {
00151     const char *iidName;
00152     if (className[0] == 'n' && className[1] == 's') {
00153         /* backcompat naming styles */
00154         fputs("NS_", file);
00155         iidName = className + 2;
00156     } else {
00157         iidName = className;
00158     }
00159 
00160     while (*iidName) {
00161         fputc(toupper(*iidName++), file);
00162     }
00163 
00164     fputs("_IID", file);
00165     return TRUE;
00166 }
00167 
00168 static gboolean
00169 java_prolog(TreeState *state)
00170 {
00171     int len, i;
00172     state->priv = calloc(1, sizeof(struct java_priv_data));
00173     if (!state->priv)
00174         return FALSE;
00175 
00176     TYPEDEFS(state) = 0;
00177     TYPEDEFS(state) = g_hash_table_new(g_str_hash, g_str_equal);
00178     if (!TYPEDEFS(state)) {
00179         /* XXX report error */
00180         free(state->priv);
00181         return FALSE;
00182     }
00183 
00184     KEYWORDS(state) = 0;
00185     KEYWORDS(state) = g_hash_table_new(g_str_hash, g_str_equal);
00186     if (!KEYWORDS(state)) {
00187         g_hash_table_destroy(TYPEDEFS(state));
00188         free(state->priv);
00189         return FALSE;
00190     }
00191     len = sizeof(javaKeywords)/sizeof(*javaKeywords);
00192     for (i = 0; i < len; i++) {
00193         g_hash_table_insert(KEYWORDS(state),
00194                             javaKeywords[i],
00195                             javaKeywords[i]);
00196     }
00197 
00198 #ifdef HANDLE_NON_IDL_IFACES
00199     NONIDLS(state) = 0;
00200     NONIDLS(state) = g_hash_table_new(g_str_hash, g_str_equal);
00201     if (!NONIDLS(state)) {
00202         g_hash_table_destroy(TYPEDEFS(state));
00203         free(state->priv);
00204         return FALSE;
00205     }
00206     len = sizeof(nonIDLIfaces)/sizeof(*nonIDLIfaces);
00207     for (i = 0; i < len; i++) {
00208         g_hash_table_insert(NONIDLS(state),
00209                             nonIDLIfaces[i],
00210                             nonIDLIfaces[i]);
00211     }
00212 #endif
00213 
00214     return TRUE;
00215 }
00216 
00217 static gboolean 
00218 java_epilog(TreeState *state)
00219 {
00220     /* points to other elements of the tree, so just destroy the table */
00221     g_hash_table_destroy(TYPEDEFS(state));
00222     g_hash_table_destroy(KEYWORDS(state));
00223 #ifdef HANDLE_NON_IDL_IFACES
00224     g_hash_table_destroy(NONIDLS(state));
00225 #endif
00226 
00227     free(state->priv);
00228     state->priv = NULL;
00229     
00230     return TRUE;
00231 }
00232 
00233 static gboolean
00234 forward_declaration(TreeState *state) 
00235 {
00236     /*
00237      * Java doesn't need forward declarations unless the declared 
00238      * class resides in a different package.
00239      */
00240 #if 0
00241     IDL_tree iface = state->tree;
00242     const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
00243     const char *pkgName = "org.mozilla.xpcom";
00244     if (!className)
00245         return FALSE;
00246     /* XXX: Get package name and compare */
00247     fprintf(state->file, "import %s.%s;\n", pkgName, className);
00248 #endif
00249 
00250     return TRUE;
00251 }
00252 
00253 
00254 static gboolean
00255 interface_declaration(TreeState *state) 
00256 {
00257     char outname[PATH_MAX];
00258     char* p;
00259     IDL_tree interface = state->tree;
00260     IDL_tree iterator = NULL;
00261     char *interface_name = 
00262       subscriptIdentifier(state, IDL_IDENT(IDL_INTERFACE(interface).ident).str);
00263     const char *iid = NULL;
00264     char iid_parsed[UUID_LENGTH];
00265     GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(interface).ident).comments;
00266 
00267     if (!verify_interface_declaration(interface))
00268         return FALSE;
00269 
00270     /*
00271      * We only want to output scriptable interfaces
00272      */
00273     if (!IDL_tree_property_get(IDL_INTERFACE(interface).ident, "scriptable")) {
00274         /*
00275          * XXX SWT uses non-scriptable interface 'nsIAppShell' (bug 270892), so
00276          * include that one.
00277          */
00278         if (strcmp(interface_name, "nsIAppShell") != 0
00279 #ifdef CREATE_NSIXPCSECURITYMANAGER
00280             && strcmp(interface_name, "nsIXPCSecurityManager") != 0
00281 #endif
00282             )
00283             return TRUE;
00284     }
00285 
00286     /*
00287      * Each Java interface must be in its own file.
00288      */
00289     p = strrchr(state->filename, '/');
00290     if (p) {
00291         strncpy(outname, state->filename, p + 1 - state->filename);
00292         outname[p + 1 - state->filename] = '\0';
00293     }
00294     else {
00295         outname[0] = '\0';
00296     }
00297     strcat(outname, interface_name);
00298     strcat(outname, ".java");
00299 
00300     state->file = fopen(outname, "w");
00301     if (!state->file) {
00302         perror("error opening output file");
00303         return FALSE;
00304     }
00305 
00306     fprintf(state->file, "/*\n * DO NOT EDIT.  THIS FILE IS GENERATED FROM\n"
00307             " * %s.idl\n */\n", state->basename);
00308 
00309     /* package name (namespace) */
00310     fputs("\npackage org.mozilla.interfaces;\n\n", state->file);
00311 
00312 
00313     iid = IDL_tree_property_get(IDL_INTERFACE(interface).ident, "uuid");
00314     if (iid) {
00315         /*
00316          * Parse uuid and then output resulting nsID to string, to
00317          * validate uuid.
00318          */
00319         struct nsID id;
00320         if (!xpidl_parse_iid(&id, iid)) {
00321             IDL_tree_error(state->tree, "cannot parse IID %s\n", iid);
00322             return FALSE;
00323         }
00324         if (!xpidl_sprint_iid(&id, iid_parsed)) {
00325             IDL_tree_error(state->tree, "error formatting IID %s\n", iid);
00326             return FALSE;
00327         }
00328     } else {
00329         IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n", 
00330                        interface_name);
00331         return FALSE;
00332     }
00333 
00334     /*
00335      * Write any interface comments
00336      */
00337     if (doc_comments != NULL)
00338         printlist(state->file, doc_comments);
00339 
00340     /*
00341      * Write "public interface <foo>"
00342      */
00343     fprintf(state->file, "public interface %s", interface_name);
00344 
00345     /*
00346      * Check for inheritence, and iterator over the inherited names,
00347      * if any.
00348      */
00349 
00350     if ((iterator = IDL_INTERFACE(interface).inheritance_spec)) {
00351         fputs(" extends ", state->file);
00352 
00353         do {
00354             fprintf(state->file, "%s", 
00355                     IDL_IDENT(IDL_LIST(iterator).data).str);
00356         
00357             if (IDL_LIST(iterator).next) {
00358                 fputs(", ", state->file);
00359             }
00360         } while ((iterator = IDL_LIST(iterator).next));
00361     }
00362 
00363     fputs(" {\n\n", state->file);
00364 
00365     /*
00366      * Write interface constants for IID
00367      */
00368     if (iid) {
00369         /* String NS_ISUPPORTS_IID = "{00000000-0000-0000-c000-000000000046}";*/
00370         write_indent(state->file);
00371         fputs("String ", state->file);
00372         write_classname_iid_define(state->file, interface_name);
00373         fputs(" =\n", state->file);
00374         write_indent(state->file);
00375         write_indent(state->file);
00376         fprintf(state->file, "\"{%s}\";\n\n", iid_parsed);
00377     }
00378 
00379     /*
00380      * Advance the state of the tree, go on to process more
00381      */
00382     
00383     state->tree = IDL_INTERFACE(interface).body;
00384 
00385     if (state->tree && !xpidl_process_node(state)) {
00386         return FALSE;
00387     }
00388 
00389 
00390     fputs("}", state->file);
00391 
00392     fclose(state->file);
00393 
00394     return TRUE;
00395 }
00396 
00397 static gboolean
00398 process_list(TreeState *state)
00399 {
00400     IDL_tree iter;
00401     for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
00402         state->tree = IDL_LIST(iter).data;
00403         if (!xpidl_process_node(state))
00404             return FALSE;
00405     }
00406     return TRUE;
00407 }
00408 
00409 static gboolean 
00410 xpcom_to_java_type(TreeState *state, IDL_tree param) 
00411 {
00412     IDL_tree real_type, type;
00413     IDL_tree up;
00414 
00415     if (!state->tree) {
00416         fputs("Object", state->file);
00417         return TRUE;
00418     }
00419 
00420     /* Could be a typedef; try to map it to the real type */
00421     real_type = find_underlying_type(state->tree);
00422     type = real_type ? real_type : state->tree;
00423 
00424     switch(IDL_NODE_TYPE(type)) {
00425 
00426     case IDLN_TYPE_INTEGER: {
00427 
00428         switch(IDL_TYPE_INTEGER(type).f_type) {
00429 
00430         case IDL_INTEGER_TYPE_SHORT:
00431             if (IDL_TYPE_INTEGER(type).f_signed)
00432                 fputs("short", state->file);
00433             else
00434                 fputs("int", state->file);
00435             break;
00436 
00437         case IDL_INTEGER_TYPE_LONG:
00438             if (IDL_TYPE_INTEGER(type).f_signed)
00439                 fputs("int", state->file);
00440             else
00441                 fputs("long", state->file);
00442             break;
00443 
00444         case IDL_INTEGER_TYPE_LONGLONG:
00445             if (IDL_TYPE_INTEGER(type).f_signed)
00446                 fputs("long", state->file);
00447             else
00448                 fputs("double", state->file);
00449             break;
00450         
00451         default:
00452             g_error("   Unknown integer type: %d\n",
00453                     IDL_TYPE_INTEGER(type).f_type);
00454             return FALSE;
00455 
00456         }
00457 
00458         break;
00459     }
00460 
00461     case IDLN_TYPE_CHAR:
00462     case IDLN_TYPE_WIDE_CHAR:
00463         fputs("char", state->file);
00464         break;
00465 
00466     case IDLN_TYPE_WIDE_STRING:
00467     case IDLN_TYPE_STRING:
00468         fputs("String", state->file);
00469         break;
00470 
00471     case IDLN_TYPE_BOOLEAN:
00472         fputs("boolean", state->file);
00473         break;
00474 
00475     case IDLN_TYPE_OCTET:
00476         if (param && IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator, "array"))
00477             fputs("byte", state->file);
00478         else
00479             fputs("short", state->file);
00480         break;
00481 
00482     case IDLN_TYPE_FLOAT:
00483         switch(IDL_TYPE_FLOAT(type).f_type) {
00484 
00485         case IDL_FLOAT_TYPE_FLOAT:
00486             fputs("float", state->file);
00487             break;
00488 
00489         case IDL_FLOAT_TYPE_DOUBLE:
00490             fputs("double", state->file);
00491             break;
00492         
00493         default:
00494             g_error("    Unknown floating point typ: %d\n",
00495                     IDL_NODE_TYPE(type));
00496             break;
00497         }
00498         break;
00499 
00500 
00501     case IDLN_IDENT:
00502       if (!(up = IDL_NODE_UP(type))) {
00503           IDL_tree_error(state->tree,
00504                          "ERROR: orphan ident %s in param list\n",
00505                          IDL_IDENT(state->tree).str);
00506           return FALSE;
00507       }
00508       switch (IDL_NODE_TYPE(up)) {
00509         case IDLN_FORWARD_DCL:
00510         case IDLN_INTERFACE: {
00511           char *className;
00512           const char *iid_is;
00513 handle_iid_is:
00514           /* might get here via the goto, so re-check type */
00515           if (IDL_NODE_TYPE(up) == IDLN_INTERFACE)
00516               className = IDL_IDENT(IDL_INTERFACE(up).ident).str;
00517           else if (IDL_NODE_TYPE(up) == IDLN_FORWARD_DCL)
00518               className = IDL_IDENT(IDL_FORWARD_DCL(up).ident).str;
00519           else
00520               className = IDL_IDENT(IDL_NATIVE(up).ident).str;
00521 
00522           iid_is = NULL;
00523           if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) {
00524               IDL_tree simple = IDL_PARAM_DCL(state->tree).simple_declarator;
00525               iid_is = IDL_tree_property_get(simple, "iid_is");
00526           }
00527 
00528           if (iid_is) {
00529               fputs("nsISupports", state->file);
00530           } else {
00531               /*
00532                * In JavaXPCOM, we handle weak references internally; no need
00533                * for the |nsIWeakReference| interface.  So just return
00534                * |nsISupports|.
00535                */
00536               if (strcmp(className, "nsIWeakReference") == 0) {
00537                   fputs("nsISupports", state->file);
00538               } else {
00539 #ifdef HANDLE_NON_IDL_IFACES
00540                   char *nonidl = g_hash_table_lookup(NONIDLS(state), className);
00541                   if (nonidl) {
00542                       fputs("nsISupports", state->file);
00543                   } else
00544 #endif
00545                   {
00546                       fprintf(state->file, "%s", className);
00547                   }
00548               }
00549           }
00550           break;
00551         }
00552         case IDLN_NATIVE: {
00553             char *ident;
00554 
00555             /* jband - adding goto for iid_is when type is native */
00556             if (param) {
00557                 if (IDL_NODE_TYPE(param) == IDLN_PARAM_DCL &&
00558                     IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator,
00559                                           "iid_is"))
00560                 {
00561                     state->tree = param;
00562                     goto handle_iid_is;
00563                 }
00564             }
00565 
00566             ident = IDL_IDENT(type).str;
00567             if (IDL_tree_property_get(type, "nsid")) {
00568                 fputs("String", state->file);
00569             } else if (IDL_tree_property_get(type, "domstring")) {
00570                 fputs("String", state->file);
00571             } else if (IDL_tree_property_get(type, "astring")) {
00572                 fputs("String", state->file);
00573             } else if (IDL_tree_property_get(type, "utf8string")) {
00574                 fputs("String", state->file);
00575             } else if (IDL_tree_property_get(type, "cstring")) {
00576                 fputs("String", state->file);
00577             } else {
00578                 const char* user_type = IDL_NATIVE(IDL_NODE_UP(type)).user_type;
00579                 IDL_tree real_type = 
00580                     g_hash_table_lookup(TYPEDEFS(state), user_type);
00581 
00582                 if (real_type) {
00583                     gboolean rc;
00584                     IDL_tree orig_tree = state->tree;
00585 
00586                     state->tree = real_type;
00587                     rc = xpcom_to_java_type(state, param);
00588 
00589                     state->tree = orig_tree;
00590                     return rc;
00591                 } else {
00592                     if (strcmp(user_type, "PRInt8") == 0) {
00593                         fputs("byte", state->file);
00594                     } else if (strcmp(user_type, "PRInt16") == 0 ||
00595                                strcmp(user_type, "PRUint8") == 0) {
00596                         fputs("short", state->file);
00597                     } else if (strcmp(user_type, "PRInt32") == 0 ||
00598                                strcmp(user_type, "int") == 0 ||
00599                                strcmp(user_type, "PRUint16") == 0) {
00600                         fputs("int", state->file);
00601                     } else if (strcmp(user_type, "PRInt64") == 0 ||
00602                                strcmp(user_type, "PRUint32") == 0) {
00603                         fputs("long", state->file);
00604                     } else if (strcmp(user_type, "PRUint64") == 0) {
00605                         fputs("double", state->file);
00606                     } else if (strcmp(user_type, "PRBool") == 0) {
00607                         fputs("boolean", state->file);
00608                     } else if (strcmp(user_type, "char") == 0 ||
00609                                strcmp(user_type, "const char") == 0 ||
00610                                strcmp(user_type, "unsigned char") == 0) {
00611                         if (IDL_tree_property_get(type, "ptr")) {
00612                             fputs("byte[]", state->file);
00613                         } else {
00614                             fputs("char", state->file);
00615                         }
00616                     } else if (strcmp(user_type, "nsIID") == 0) {
00617                         fputs("String", state->file);
00618                     } else if (strcmp(user_type, "nsString") == 0 ||
00619                                strcmp(user_type, "nsAString") == 0 ||
00620                                strcmp(user_type, "nsACString") == 0) {
00621                         fputs("String", state->file);
00622                     } else {
00623                         fputs("long", state->file);
00624                     }
00625                 }
00626             }
00627             break;
00628           }
00629         default:
00630           if (IDL_NODE_TYPE(IDL_NODE_UP(up)) == IDLN_TYPE_DCL) {
00631               /* restart with the underlying type */
00632               gboolean rc;
00633               IDL_tree orig_tree = state->tree;
00634               state->tree = IDL_TYPE_DCL(IDL_NODE_UP(up)).type_spec;
00635               rc = xpcom_to_java_type(state, param);
00636               state->tree = orig_tree;
00637               return rc;
00638           }
00639           IDL_tree_error(state->tree,
00640                          "can't handle %s ident in param list\n",
00641                          "that type of"
00642                          );
00643           return FALSE;
00644       }
00645       break;
00646 
00647     default:
00648       IDL_tree_error(state->tree, "can't handle %s in param list\n",
00649 #ifdef DEBUG_shaver
00650                      /* XXX is this safe to use on Win now? */
00651                      IDL_NODE_TYPE_NAME(IDL_NODE_UP(type))
00652 #else
00653                   "that type"
00654 #endif
00655       );
00656       return FALSE;
00657     }
00658 
00659     return TRUE;
00660 
00661 }
00662 
00663 static gboolean
00664 xpcom_to_java_param(TreeState *state)
00665 {
00666     IDL_tree param = state->tree;
00667     state->tree = IDL_PARAM_DCL(param).param_type_spec;
00668 
00669     /*
00670      * Put in type of parameter
00671      */
00672 
00673     if (!xpcom_to_java_type(state, param)) {
00674         return FALSE;
00675     }
00676 
00677     /*
00678      * If the parameter is out or inout, make it a Java array of the
00679      * appropriate type
00680      */
00681 
00682     if (IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) {
00683         fputs("[]", state->file);
00684     }
00685 
00686     /*
00687      * If the parameter is an array make it a Java array
00688      */
00689     if (IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator, "array"))
00690         fputs("[]", state->file);
00691 
00692     /*
00693      * Put in name of parameter 
00694      */
00695     fputc(' ', state->file);
00696     fputs(subscriptIdentifier(state, 
00697                         IDL_IDENT(IDL_PARAM_DCL(param).simple_declarator).str), 
00698           state->file);
00699 
00700     return TRUE;
00701 }
00702 
00703 
00704 static gboolean
00705 type_declaration(TreeState *state) 
00706 {
00707     /*
00708      * Unlike C, Java has no type declaration directive.
00709      * Instead, we record the mapping, and look up the actual type
00710      * when needed.
00711      */
00712     IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
00713     IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
00714 
00715     /* XXX: check for illegal types */
00716 
00717     g_hash_table_insert(TYPEDEFS(state),
00718                         IDL_IDENT(IDL_LIST(dcls).data).str,
00719                         type);
00720 
00721     return TRUE;
00722 }
00723 
00724 #ifdef OUTPUT_SWT_NOSCRIPT_METHODS
00725 static gboolean
00726 print_noscript_method(TreeState *state)
00727 {
00728     IDL_tree iface = IDL_NODE_UP(IDL_NODE_UP(state->tree));
00729     char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
00730     if (strcmp(className, "nsIBaseWindow") == 0 ||
00731         strcmp(className, "nsIEmbeddingSiteWindow") == 0)
00732         return TRUE;
00733     return FALSE;
00734 }
00735 #endif
00736 
00737 static gboolean
00738 method_declaration(TreeState *state) 
00739 {
00740     const char* array = NULL;
00741     struct _IDL_OP_DCL *method = &IDL_OP_DCL(state->tree);
00742     gboolean method_notxpcom = 
00743         (IDL_tree_property_get(method->ident, "notxpcom") != NULL);
00744     gboolean method_noscript = 
00745         (IDL_tree_property_get(method->ident, "noscript") != NULL);
00746     IDL_tree iterator = NULL;
00747     IDL_tree retval_param = NULL;
00748     char *method_name =
00749                   g_strdup_printf("%c%s",
00750                                   tolower(IDL_IDENT(method->ident).str[0]),
00751                                   IDL_IDENT(method->ident).str + 1);
00752     GSList *doc_comments = IDL_IDENT(method->ident).comments;
00753 
00754     if (!verify_method_declaration(state->tree))
00755         return FALSE;
00756 
00757 #ifdef OUTPUT_SWT_NOSCRIPT_METHODS
00758     if (method_notxpcom)
00759         return TRUE;
00760     if (method_noscript && !print_noscript_method(state))
00761         return TRUE;
00762 #else
00763     /* do not write nonscriptable methods */
00764     if (method_notxpcom || method_noscript) {
00765         return TRUE;
00766     }
00767 #endif
00768 
00769 #ifdef CREATE_NSIXPCSECURITYMANAGER
00770     /* Since this interface is non-scriptable, we treat all of its methods
00771      * as if they were [noscript] */
00772     {
00773         IDL_tree iface = IDL_NODE_UP(IDL_NODE_UP(state->tree));
00774         char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
00775         if (strcmp(className, "nsIXPCSecurityManager") == 0)
00776             return TRUE;
00777     }
00778 #endif
00779 
00780     if (doc_comments != NULL) {
00781         write_indent(state->file);
00782         printlist(state->file, doc_comments);
00783     }
00784 
00785     /*
00786      * Write return type
00787      * Unlike C++ headers, Java interfaces return the declared 
00788      * return value; an exception indicates XPCOM method failure.
00789      */
00790     write_indent(state->file);
00791     if (method->op_type_spec) {
00792         state->tree = method->op_type_spec;
00793         if (!xpcom_to_java_type(state, NULL)) {
00794             return FALSE;
00795         }
00796     } else {
00797         /* Check for retval attribute */
00798         for (iterator = method->parameter_dcls; iterator != NULL; 
00799              iterator = IDL_LIST(iterator).next) {
00800 
00801             IDL_tree original_tree = state->tree;
00802             IDL_tree simple_decl;
00803 
00804             state->tree = IDL_LIST(iterator).data;
00805             simple_decl = IDL_PARAM_DCL(state->tree).simple_declarator;
00806 
00807             if (IDL_tree_property_get(simple_decl, "retval")) {
00808                 IDL_tree param;
00809 
00810                 retval_param = iterator;
00811                 array = IDL_tree_property_get(simple_decl, "array");
00812 
00813                 /*
00814                  * Put in type of parameter
00815                  */
00816                 param = state->tree;
00817                 state->tree = IDL_PARAM_DCL(state->tree).param_type_spec;
00818                 if (!xpcom_to_java_type(state, param)) {
00819                     return FALSE;
00820                 }
00821 
00822                 if (array) {
00823                     fputs("[]", state->file);
00824                 }
00825             }
00826 
00827             state->tree = original_tree;
00828         }
00829 
00830         if (retval_param == NULL) {
00831             fputs("void", state->file);
00832         }
00833     }
00834  
00835     /*
00836      * Write method name
00837      */
00838     fprintf(state->file, " %s(", subscriptIdentifier(state, method_name));
00839 
00840     /*
00841      * Write parameters
00842      */
00843     for (iterator = method->parameter_dcls; iterator != NULL; 
00844          iterator = IDL_LIST(iterator).next) {
00845 
00846         /* Skip "retval" */
00847         if (iterator == retval_param) {
00848             continue;
00849         }
00850 
00851         if (iterator != method->parameter_dcls) {
00852             fputs(", ", state->file);
00853         }
00854         
00855         state->tree = IDL_LIST(iterator).data;
00856 
00857         if (!xpcom_to_java_param(state)) {
00858             return FALSE;
00859         }
00860     }
00861 
00862     fputs(")", state->file);
00863 
00864 #ifdef HANDLE_EXCEPTIONS
00865     if (method->raises_expr) {
00866         IDL_tree iter = method->raises_expr;
00867         IDL_tree dataNode = IDL_LIST(iter).data;
00868 
00869         fputs(" throws ", state->file);
00870         fputs(IDL_IDENT(dataNode).str, state->file);
00871         iter = IDL_LIST(iter).next;
00872 
00873         while (iter) {
00874             dataNode = IDL_LIST(iter).data;
00875             fprintf(state->file, ", %s", IDL_IDENT(dataNode).str);
00876             iter = IDL_LIST(iter).next;
00877         }
00878     }
00879 #endif
00880 
00881     fputs(";\n\n", state->file);
00882 
00883     return TRUE;
00884 }
00885 
00886 
00887 static gboolean
00888 constant_declaration(TreeState *state)
00889 {
00890     struct _IDL_CONST_DCL *declaration = &IDL_CONST_DCL(state->tree);
00891     const char *name = IDL_IDENT(declaration->ident).str;
00892     GSList *doc_comments = IDL_IDENT(declaration->ident).comments;
00893     IDL_tree real_type;
00894 
00895     const char* format;
00896     const char* type_str;
00897     gboolean is_long;
00898 
00899     gboolean success;
00900 
00901     if (!verify_const_declaration(state->tree))
00902         return FALSE;
00903 
00904     /* Could be a typedef; try to map it to the real type. */
00905     real_type = find_underlying_type(declaration->const_type);
00906     real_type = real_type ? real_type : declaration->const_type;
00907 
00908     /* Consts must be in an interface */
00909     if (!IDL_NODE_UP(IDL_NODE_UP(state->tree)) ||
00910         IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(state->tree))) != 
00911         IDLN_INTERFACE) {
00912 
00913         XPIDL_WARNING((state->tree, IDL_WARNING1,
00914                        "A constant \"%s\" was declared outside an interface."
00915                        "  It was ignored.", name));
00916 
00917         return TRUE;
00918     }
00919 
00920     /*
00921      * The C++ header XPIDL module only allows for shorts and longs (ints)
00922      * to be constants, so we will follow the same convention
00923      */
00924 
00925     is_long = FALSE;
00926 
00927     success = (IDLN_TYPE_INTEGER == IDL_NODE_TYPE(real_type));
00928 
00929     if (success) {
00930         gboolean is_signed = IDL_TYPE_INTEGER(real_type).f_signed;
00931         format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "u";
00932 
00933         switch(IDL_TYPE_INTEGER(real_type).f_type) {
00934             case IDL_INTEGER_TYPE_SHORT:
00935                 if (is_signed)
00936                     type_str = "short";
00937                 else
00938                     type_str = "int";
00939                 break;
00940 
00941             case IDL_INTEGER_TYPE_LONG:
00942                 if (is_signed) {
00943                     type_str = "int";
00944                 } else {
00945                     type_str = "long";
00946                     is_long = TRUE;
00947                 }
00948                 break;
00949             
00950             default:
00951                 /* Whoops, it's some other kind of number */
00952                 success = FALSE;
00953                 break;
00954         }
00955     } else {
00956         IDL_tree_error(state->tree,
00957                        "const declaration \'%s\' must be of type short or long",
00958                        name);
00959         return FALSE;
00960     }
00961 
00962     if (!success) {
00963         XPIDL_WARNING((state->tree, IDL_WARNING1,
00964                        "A constant \"%s\" was not of type short or long."
00965                        "  It was ignored.", name));
00966         return FALSE;
00967     }
00968 
00969     if (doc_comments != NULL) {
00970         write_indent(state->file);
00971         printlist(state->file, doc_comments);
00972     }
00973 
00974     write_indent(state->file);
00975     fprintf(state->file, "%s %s = ", type_str,
00976             subscriptIdentifier(state, (char*) name));
00977     fprintf(state->file, format, IDL_INTEGER(declaration->const_exp).value);
00978     fprintf(state->file, "%s;\n\n", is_long ? "L" : "");
00979 
00980     return TRUE;
00981 
00982 }
00983 
00984 #define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data))
00985 #define ATTR_PROPS(tree) (IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data)
00986 #define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL((tree)).param_type_spec)
00987 
00988 
00989 static gboolean
00990 attribute_declaration(TreeState *state)
00991 {
00992     char *attribute_name;
00993     GSList *doc_comments;
00994     gboolean read_only;
00995 
00996     if (!verify_attribute_declaration(state->tree))
00997         return FALSE;
00998 
00999     attribute_name = ATTR_IDENT(state->tree).str;
01000     read_only = IDL_ATTR_DCL(state->tree).f_readonly;
01001 
01002 #ifdef OUTPUT_SWT_NOSCRIPT_METHODS
01003     if (IDL_tree_property_get(ATTR_PROPS(state->tree), "notxpcom"))
01004         return TRUE;
01005     if (IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript") &&
01006         !print_noscript_method(state))
01007         return TRUE;
01008 #else
01009     if (IDL_tree_property_get(ATTR_PROPS(state->tree), "notxpcom") ||
01010         IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript"))
01011         return TRUE;
01012 #endif
01013 
01014     doc_comments =
01015         IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
01016                            (state->tree).simple_declarations).data).comments;
01017     if (doc_comments != NULL) {
01018         write_indent(state->file);
01019         printlist(state->file, doc_comments);
01020     }
01021 
01022     /*
01023      * Write the proper Java return value for the get operation
01024      */
01025     write_indent(state->file);
01026     state->tree = ATTR_TYPE_DECL(state->tree);
01027     if (!xpcom_to_java_type(state, NULL)) {
01028         return FALSE;
01029     }
01030     
01031     /*
01032      * Write the name of the accessor ("get") method.
01033      */
01034     fprintf(state->file, " get%c%s();\n\n",
01035             toupper(attribute_name[0]), attribute_name + 1);
01036 
01037     if (!read_only) {
01038         if (doc_comments != NULL) {
01039             write_indent(state->file);
01040             printlist(state->file, doc_comments);
01041         }
01042 
01043         /*
01044          * Write attribute access method name and return type
01045          */
01046         write_indent(state->file);
01047         fprintf(state->file, "void set%c%s(",
01048                 toupper(attribute_name[0]), 
01049                 attribute_name+1);
01050         
01051         /*
01052          * Write the proper Java type for the set operation
01053          */
01054         if (!xpcom_to_java_type(state, NULL)) {
01055             return FALSE;
01056         }
01057 
01058         /*
01059          * Write the name of the formal parameter.
01060          */
01061         fprintf(state->file, " a%c%s);\n\n", toupper(attribute_name[0]),
01062                 attribute_name + 1);
01063     }
01064 
01065     return TRUE;
01066 }
01067 
01068 
01069 static gboolean
01070 enum_declaration(TreeState *state)
01071 {
01072     XPIDL_WARNING((state->tree, IDL_WARNING1,
01073                    "enums not supported, enum \'%s\' ignored",
01074                    IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str));
01075     return TRUE;
01076 }
01077 
01078 backend *
01079 xpidl_java_dispatch(void)
01080 {
01081     static backend result;
01082     static nodeHandler table[IDLN_LAST];
01083     static gboolean initialized = FALSE;
01084 
01085     result.emit_prolog = java_prolog;
01086     result.emit_epilog = java_epilog;
01087 
01088     if (!initialized) {
01089         table[IDLN_INTERFACE] = interface_declaration;
01090         table[IDLN_LIST] = process_list;
01091 
01092         table[IDLN_OP_DCL] = method_declaration;
01093         table[IDLN_ATTR_DCL] = attribute_declaration;
01094         table[IDLN_CONST_DCL] = constant_declaration;
01095 
01096         table[IDLN_TYPE_DCL] = type_declaration;
01097         table[IDLN_FORWARD_DCL] = forward_declaration;
01098 
01099         table[IDLN_TYPE_ENUM] = enum_declaration;
01100 
01101         initialized = TRUE;
01102     }
01103 
01104     result.dispatch_table = table;
01105     return &result;
01106 }
01107 
01108 char* subscriptIdentifier(TreeState *state, char *str)
01109 {
01110     char *sstr = NULL;
01111     char *keyword = g_hash_table_lookup(KEYWORDS(state), str);
01112     if (keyword) {
01113         sstr = g_strdup_printf("_%s", keyword);
01114         return sstr;
01115     }
01116     return str;
01117 }
01118