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 #endif
00052 
00053 static char* subscriptIdentifier(TreeState *state, char *str);
00054 
00055 /*
00056 struct java_priv_data {
00057     GHashTable *typedefTable;
00058 };
00059 */
00060 
00061 static char* javaKeywords[] = {
00062     "abstract", "default", "if"        , "private"     , "this"     ,
00063     "boolean" , "do"     , "implements", "protected"   , "throw"    ,
00064     "break"   , "double" , "import",     "public"      , "throws"   ,
00065     "byte"    , "else"   , "instanceof", "return"      , "transient",
00066     "case"    , "extends", "int"       , "short"       , "try"      ,
00067     "catch"   , "final"  , "interface" , "static"      , "void"     ,
00068     "char"    , "finally", "long"      , "strictfp"    , "volatile" ,
00069     "class"   , "float"  , "native"    , "super"       , "while"    ,
00070     "const"   , "for"    , "new"       , "switch"      , "assert"   ,
00071     "continue", "goto"   , "package"   , "synchronized",
00072     "clone"   ,  /* clone is a member function of java.lang.Object */
00073     "finalize"   /* finalize is a member function of java.lang.Object */};
00074 
00075 #define TYPEDEFS(state)     (((struct java_priv_data *)state->priv)->typedefTable)
00076 #define PRIVDATA(state)     (((struct java_priv_data *)state->priv))
00077 #define KEYWORDS(state)     (((struct java_priv_data *)state->priv)->keywords)
00078 
00079 static gboolean
00080 write_classname_iid_define(FILE *file, const char *className)
00081 {
00082     const char *iidName;
00083     if (className[0] == 'n' && className[1] == 's') {
00084         /* backcompat naming styles */
00085         fputs("NS_", file);
00086         iidName = className + 2;
00087     } else {
00088         iidName = className;
00089     }
00090 
00091     while (*iidName) {
00092         fputc(toupper(*iidName++), file);
00093     }
00094 
00095     fputs("_IID", file);
00096     return TRUE;
00097 }
00098 
00099 static gboolean
00100 java_prolog(TreeState *state)
00101 {
00102     int len, i;
00103     state->priv = calloc(1, sizeof(struct java_priv_data));
00104     if (!state->priv)
00105         return FALSE;
00106 
00107     TYPEDEFS(state) = 0;
00108     TYPEDEFS(state) = g_hash_table_new(g_str_hash, g_str_equal);
00109     if (!TYPEDEFS(state)) {
00110         /* XXX report error */
00111         free(state->priv);
00112         return FALSE;
00113     }
00114 
00115     KEYWORDS(state) = 0;
00116     KEYWORDS(state) = g_hash_table_new(g_str_hash, g_str_equal);
00117     if (!KEYWORDS(state)) {
00118         g_hash_table_destroy(TYPEDEFS(state));
00119         free(state->priv);
00120         return FALSE;
00121     }
00122     len = sizeof(javaKeywords)/sizeof(*javaKeywords);
00123     for (i = 0; i < len; i++) {
00124         g_hash_table_insert(KEYWORDS(state),
00125                             javaKeywords[i],
00126                             javaKeywords[i]);
00127     }
00128 
00129     return TRUE;
00130 }
00131 
00132 static gboolean 
00133 java_epilog(TreeState *state)
00134 {
00135     /* points to other elements of the tree, so just destroy the table */
00136     g_hash_table_destroy(TYPEDEFS(state));
00137     g_hash_table_destroy(KEYWORDS(state));
00138 
00139     free(state->priv);
00140     state->priv = NULL;
00141     
00142     return TRUE;
00143 }
00144 
00145 static gboolean
00146 forward_declaration(TreeState *state) 
00147 {
00148     /*
00149      * Java doesn't need forward declarations unless the declared 
00150      * class resides in a different package.
00151      */
00152 #if 0
00153     IDL_tree iface = state->tree;
00154     const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
00155     const char *pkgName = "org.mozilla.xpcom";
00156     if (!className)
00157         return FALSE;
00158     /* XXX: Get package name and compare */
00159     fprintf(state->file, "import %s.%s;\n", pkgName, className);
00160 #endif
00161 
00162     return TRUE;
00163 }
00164 
00165 
00166 static gboolean
00167 interface_declaration(TreeState *state) 
00168 {
00169     char outname[PATH_MAX];
00170     char* p;
00171     IDL_tree interface = state->tree;
00172     IDL_tree iterator = NULL;
00173     char *interface_name = 
00174         subscriptIdentifier(state, IDL_IDENT(IDL_INTERFACE(interface).ident).str);
00175     const char *iid = NULL;
00176     char iid_parsed[UUID_LENGTH];
00177 
00178     if (!verify_interface_declaration(interface))
00179         return FALSE;
00180 
00181     /*
00182      * Each interface decl is a single file
00183      */
00184     p = strrchr(state->filename, '/');
00185     if (p) {
00186       strncpy(outname, state->filename, p + 1 - state->filename);
00187       outname[p + 1 - state->filename] = '\0';
00188     }
00189     strcat(outname, interface_name);
00190     strcat(outname, ".java");
00191 
00192     state->file =  fopen(outname, "w");
00193     if (!state->file) {
00194         perror("error opening output file");
00195         return FALSE;
00196     }
00197 
00198     fputs("/*\n * ************* DO NOT EDIT THIS FILE ***********\n",
00199           state->file);
00200     
00201     fprintf(state->file, 
00202             " *\n * This file was automatically generated from %s.idl.\n", 
00203             state->basename);
00204     
00205     fputs(" */\n\n", state->file);
00206 
00207     if (state->package)
00208         fprintf(state->file, "\npackage %s;\n\n", state->package);
00209 
00210     if (!state->package || strcmp(state->package, "org.mozilla.xpcom") != 0)
00211         fputs("import org.mozilla.xpcom.*;\n", state->file);
00212 
00213     fputs("\n", state->file);
00214 
00215 #ifndef LIBIDL_MAJOR_VERSION
00216     iid = IDL_tree_property_get(interface, "uuid");
00217 #else
00218     iid = IDL_tree_property_get(IDL_INTERFACE(interface).ident, "uuid");
00219 #endif
00220     if (iid) {
00221         struct nsID id;
00222         /* Redundant, but a better error than 'cannot parse.' */
00223         if (strlen(iid) != 36) {
00224             IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid);
00225             return FALSE;
00226         }
00227 
00228         /*
00229          * Parse uuid and then output resulting nsID to string, to validate
00230          * uuid and normalize resulting .h files.
00231          */
00232         if (!xpidl_parse_iid(&id, iid)) {
00233             IDL_tree_error(state->tree, "cannot parse IID %s\n", iid);
00234             return FALSE;
00235         }
00236         if (!xpidl_sprint_iid(&id, iid_parsed)) {
00237             IDL_tree_error(state->tree, "error formatting IID %s\n", iid);
00238             return FALSE;
00239         }
00240     } else {
00241         IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n", 
00242                        interface_name);
00243         return FALSE;
00244     }
00245 
00246     /*
00247      * Write out JavaDoc comment
00248      */
00249 
00250     fprintf(state->file, "\n/**\n * Interface %s\n", interface_name);
00251     if (iid != NULL) {
00252         fprintf(state->file, " *\n * IID: 0x%s\n */\n\n", iid_parsed);
00253     } else {
00254         fputs(" */\n\n", state->file);
00255     }
00256 
00257     /*
00258      * Write "public interface <foo>"
00259      */
00260 
00261     fprintf(state->file, "public interface %s", interface_name);
00262 
00263     /*
00264      * Check for inheritence, and iterator over the inherited names,
00265      * if any.
00266      */
00267 
00268     if ((iterator = IDL_INTERFACE(interface).inheritance_spec)) {
00269         fputs(" extends ", state->file);
00270 
00271         do {
00272             fprintf(state->file, "%s", 
00273                     IDL_IDENT(IDL_LIST(iterator).data).str);
00274            
00275             if (IDL_LIST(iterator).next) {
00276                 fputs(", ", state->file);
00277             }
00278         } while ((iterator = IDL_LIST(iterator).next));
00279     }
00280 
00281     fputs("\n{\n", state->file);
00282     
00283     /*
00284      * Write interface constants for IID
00285      */
00286     if (iid) {
00287         /* public static final String NS_ISUPPORTS_IID = "00000000-0000-0000-c000-000000000046" */
00288         fputs("    public static final String ", state->file);
00289         write_classname_iid_define(state->file, interface_name);
00290         fprintf(state->file, " =\n        \"{%s}\";\n\n", iid_parsed);
00291     }
00292 
00293     /*
00294      * Advance the state of the tree, go on to process more
00295      */
00296     
00297     state->tree = IDL_INTERFACE(interface).body;
00298 
00299        PRIVDATA(state)->bCountingMethods = FALSE;
00300        PRIVDATA(state)->numMethods = 0;
00301 
00302     if (state->tree && !xpidl_process_node(state)) {
00303         return FALSE;
00304     }
00305 
00306 
00307     fputs("\n}\n", state->file);
00308 
00309     fprintf(state->file, "\n/*\n * end\n */\n");
00310     fclose(state->file);
00311 
00312     return TRUE;
00313 }
00314 
00315 static gboolean
00316 process_list(TreeState *state)
00317 {
00318     IDL_tree iter;
00319     for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
00320         state->tree = IDL_LIST(iter).data;
00321         if (!xpidl_process_node(state))
00322             return FALSE;
00323     }
00324     return TRUE;
00325 }
00326 
00327 static gboolean 
00328 xpcom_to_java_type(TreeState *state, IDL_tree type) 
00329 {
00330     IDL_tree real_type;
00331     IDL_tree up;
00332 
00333     if (!type) {
00334         fputs("Object", state->file);
00335         return TRUE;
00336     }
00337 
00338     /* Could be a typedef; try to map it to the real type */
00339     real_type = find_underlying_type(type);
00340     type = real_type ? real_type : type;
00341 
00342     switch(IDL_NODE_TYPE(type)) {
00343 
00344     case IDLN_TYPE_INTEGER: {
00345 
00346         switch(IDL_TYPE_INTEGER(type).f_type) {
00347 
00348         case IDL_INTEGER_TYPE_SHORT:
00349             fputs("short", state->file);
00350             break;
00351 
00352         case IDL_INTEGER_TYPE_LONG:
00353             fputs("int", state->file);
00354             break;
00355 
00356         case IDL_INTEGER_TYPE_LONGLONG:
00357             fputs("long", state->file);
00358             break;
00359            
00360         default:
00361             g_error("   Unknown integer type: %d\n",
00362                     IDL_TYPE_INTEGER(type).f_type);
00363             return FALSE;
00364 
00365         }
00366 
00367         break;
00368     }
00369 
00370     case IDLN_TYPE_CHAR:
00371     case IDLN_TYPE_WIDE_CHAR:
00372         fputs("char", state->file);
00373         break;
00374 
00375     case IDLN_TYPE_WIDE_STRING:
00376     case IDLN_TYPE_STRING:
00377         fputs("String", state->file);
00378         break;
00379 
00380     case IDLN_TYPE_BOOLEAN:
00381         fputs("boolean", state->file);
00382         break;
00383 
00384     case IDLN_TYPE_OCTET:
00385         fputs("byte", state->file);
00386         break;
00387 
00388     case IDLN_TYPE_FLOAT:
00389         switch(IDL_TYPE_FLOAT(type).f_type) {
00390 
00391         case IDL_FLOAT_TYPE_FLOAT:
00392             fputs("float", state->file);
00393             break;
00394 
00395         case IDL_FLOAT_TYPE_DOUBLE:
00396             fputs("double", state->file);
00397             break;
00398            
00399         default:
00400             g_error("    Unknown floating point typ: %d\n",
00401                     IDL_NODE_TYPE(type));
00402             break;
00403         }
00404         break;
00405 
00406 
00407     case IDLN_IDENT:
00408       if (!(up = IDL_NODE_UP(type))) {
00409           IDL_tree_error(state->tree,
00410                          "ERROR: orphan ident %s in param list\n",
00411                          IDL_IDENT(state->tree).str);
00412           return FALSE;
00413       }
00414       switch (IDL_NODE_TYPE(up)) {
00415         case IDLN_FORWARD_DCL:
00416         case IDLN_INTERFACE: {
00417           char *className;
00418           const char *iid_is;
00419 handle_iid_is:
00420           /* might get here via the goto, so re-check type */
00421           if (IDL_NODE_TYPE(up) == IDLN_INTERFACE)
00422               className = IDL_IDENT(IDL_INTERFACE(up).ident).str;
00423           else if (IDL_NODE_TYPE(up) == IDLN_FORWARD_DCL)
00424               className = IDL_IDENT(IDL_FORWARD_DCL(up).ident).str;
00425           else
00426               className = IDL_IDENT(IDL_NATIVE(up).ident).str;
00427           iid_is = NULL;
00428 
00429           if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) {
00430               iid_is =
00431                   IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
00432                                         "iid_is");
00433           }
00434           if (iid_is) {
00435               fputs("nsISupports", state->file);
00436           } else {
00437               /* XXX How do we want to handle this? If it's an IDLN_INTERFACE,
00438                *  then we can just output the name of the class, since the IDL
00439                *  files exist for those classes.  However, if it's an
00440                *  IDLN_FORWARD_DCL, some of those interfaces are not defined in
00441                *  IDL files, so we get an error when trying to compile the java
00442                *  files.  So, for now, we just output them as the base iface
00443                *  (nsISupports). 
00444                */
00445               if (IDL_NODE_TYPE(up) == IDLN_FORWARD_DCL)
00446                   fputs("nsISupports", state->file);
00447               else
00448                   fprintf(state->file, "%s", className);
00449           }
00450           break;
00451         }
00452         case IDLN_NATIVE: {
00453             char *ident;
00454 
00455             /* jband - adding goto for iid_is when type is native */
00456             if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL &&
00457                 IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
00458                                         "iid_is"))
00459             {
00460                 goto handle_iid_is;
00461 /*                fputs("nsISupports", state->file); */
00462                 break;
00463             }
00464 
00465             ident = IDL_IDENT(type).str;
00466             if (IDL_tree_property_get(type, "nsid")) {
00467                 fputs("String", state->file);
00468             } else if (IDL_tree_property_get(type, "domstring")) {
00469                 fputs("String", state->file);
00470             } else if (IDL_tree_property_get(type, "astring")) {
00471                 fputs("String", state->file);
00472             } else if (IDL_tree_property_get(type, "utf8string")) {
00473                 fputs("String", state->file);
00474             } else if (IDL_tree_property_get(type, "cstring")) {
00475                 fputs("String", state->file);
00476             } else {
00477                 const char* user_type = IDL_NATIVE(IDL_NODE_UP(type)).user_type;
00478                 IDL_tree real_type = 
00479                     g_hash_table_lookup(TYPEDEFS(state), user_type);
00480 
00481                 if (real_type) {
00482                     return xpcom_to_java_type(state, real_type);
00483                 } else {
00484                     if (strcmp(user_type, "PRInt8") == 0 ||
00485                         strcmp(user_type, "PRUint8") == 0) {
00486                         fputs("byte", state->file);
00487                     } else if (strcmp(user_type, "PRInt16") == 0 ||
00488                                strcmp(user_type, "PRUint16") == 0) {
00489                         fputs("short", state->file);
00490                     } else if (strcmp(user_type, "PRInt32") == 0 ||
00491                                strcmp(user_type, "PRUint32") == 0 ||
00492                                strcmp(user_type, "int") == 0) {
00493                         fputs("int", state->file);
00494                     } else if (strcmp(user_type, "PRInt64") == 0 ||
00495                                strcmp(user_type, "PRUint64") == 0) {
00496                         fputs("long", state->file);
00497                     } else if (strcmp(user_type, "PRBool") == 0) {
00498                         fputs("boolean", state->file);
00499                     } else if (strncmp(user_type, "char", 4) == 0 ||
00500                                strncmp(user_type, "const char", 10) == 0 ||
00501                                strncmp(user_type, "unsigned char", 13) == 0) {
00502                         if (IDL_tree_property_get(type, "ptr")) {
00503                             fputs("byte[]", state->file);
00504                         } else {
00505                             fputs("char", state->file);
00506                         }
00507                     } else if (strcmp(user_type, "nsIID") == 0) {
00508                         fputs("String", state->file);
00509                     } else if (strcmp(user_type, "nsString") == 0 ||
00510                                strcmp(user_type, "nsAString") == 0 ||
00511                                strcmp(user_type, "nsACString") == 0) {
00512                         fputs("String", state->file);
00513                     } else {
00514                         fputs("int", state->file);
00515                     }
00516                 }
00517             }
00518             break;
00519           }
00520         default:
00521           if (IDL_NODE_TYPE(IDL_NODE_UP(up)) == IDLN_TYPE_DCL) {
00522               /* restart with the underlying type */
00523               IDL_tree new_type;
00524               new_type = IDL_TYPE_DCL(IDL_NODE_UP(up)).type_spec;
00525               if (new_type) {
00526                   gboolean rc = xpcom_to_java_type(state, new_type);
00527                   return rc;
00528               } else {
00529                   /* do what we would do in recursion if !type */
00530                   fputs("Object", state->file);
00531                   return TRUE;
00532               }
00533           }
00534           IDL_tree_error(state->tree,
00535                          "can't handle %s ident in param list\n",
00536                          "that type of"
00537                          );
00538           return FALSE;
00539       }
00540       break;
00541 
00542     default:
00543       IDL_tree_error(state->tree, "can't handle %s in param list\n",
00544 #ifdef DEBUG_shaver
00545                      /* XXX is this safe to use on Win now? */
00546                      IDL_NODE_TYPE_NAME(IDL_NODE_UP(type))
00547 #else
00548                   "that type"
00549 #endif
00550       );
00551       return FALSE;
00552     }
00553 
00554     return TRUE;
00555 
00556 }
00557 
00558 static gboolean
00559 xpcom_to_java_param(TreeState *state) 
00560 {
00561     IDL_tree param = state->tree;
00562 
00563     /*
00564      * Put in type of parameter
00565      */
00566 
00567     if (!xpcom_to_java_type(state, IDL_PARAM_DCL(param).param_type_spec)) {
00568         return FALSE;
00569     }
00570 
00571     /*
00572      * If the parameter is out or inout, make it a Java array of the
00573      * appropriate type
00574      */
00575 
00576     if (IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) {
00577         fputs("[]", state->file);
00578     }
00579 
00580     /*
00581      * If the parameter is an array make it a Java array
00582      */
00583     if (IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator, "array"))
00584         fputs("[]", state->file);
00585 
00586     /*
00587      * Put in name of parameter 
00588      */
00589 
00590     fputc(' ', state->file);
00591 
00592     fputs(subscriptIdentifier(state, 
00593                               IDL_IDENT(IDL_PARAM_DCL(param).simple_declarator).str), 
00594           state->file);
00595 
00596     return TRUE;
00597 }
00598 
00599 
00600 static gboolean
00601 type_declaration(TreeState *state) 
00602 {
00603     /*
00604      * Unlike C, Java has no type declaration directive.
00605      * Instead, we record the mapping, and look up the actual type
00606      * when needed.
00607      */
00608     IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
00609     IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
00610 
00611     /* XXX: check for illegal types */
00612 
00613     g_hash_table_insert(TYPEDEFS(state),
00614                         IDL_IDENT(IDL_LIST(dcls).data).str,
00615                         type);
00616 
00617     return TRUE;
00618 }
00619 
00620 static gboolean
00621 method_declaration(TreeState *state) 
00622 {
00623     const char* array = NULL;
00624     struct _IDL_OP_DCL *method = &IDL_OP_DCL(state->tree);
00625     gboolean method_notxpcom = 
00626         (IDL_tree_property_get(method->ident, "notxpcom") != NULL);
00627     gboolean method_noscript = 
00628         (IDL_tree_property_get(method->ident, "noscript") != NULL);
00629     IDL_tree iterator = NULL;
00630     IDL_tree retval_param = NULL;
00631     char *method_name =
00632                   g_strdup_printf("%c%s",
00633                                   tolower(IDL_IDENT(method->ident).str[0]),
00634                                   IDL_IDENT(method->ident).str + 1);
00635 
00636     if (!verify_method_declaration(state->tree))
00637         return FALSE;
00638 
00639     fputc('\n', state->file);
00640     xpidl_write_comment(state, 4);
00641 
00642 #if 1
00643     /* do not write non-xpcom methods */
00644     if (method_notxpcom) {
00645         return TRUE;
00646     }
00647 
00648     /*
00649      * Write beginning of method declaration
00650      */
00651     fputs("    public ", state->file);
00652 #else
00653     /* do not write nonscriptable methods */
00654     if (method_notxpcom || method_noscript) {
00655         return TRUE;
00656     }
00657 
00658     /*
00659      * Write beginning of method declaration
00660      */
00661     fputs("    ", state->file);
00662     if (!method_noscript) {
00663         /* Nonscriptable methods become package-protected */
00664         fputs("public ", state->file);
00665     }
00666 #endif
00667 
00668     /*
00669      * Write return type
00670      * Unlike C++ headers, Java interfaces return the declared 
00671      * return value; an exception indicates XPCOM method failure.
00672      */
00673     if (method->op_type_spec) {
00674         state->tree = method->op_type_spec;
00675         if (!xpcom_to_java_type(state, method->op_type_spec)) {
00676             return FALSE;
00677         }
00678     } else {
00679         /* Check for retval attribute */
00680         for (iterator = method->parameter_dcls; iterator != NULL; 
00681              iterator = IDL_LIST(iterator).next) {
00682 
00683             IDL_tree original_tree = state->tree;
00684 
00685             state->tree = IDL_LIST(iterator).data;
00686 
00687             if (IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, 
00688                                       "retval")) {
00689                 retval_param = iterator;
00690 
00691                 array = 
00692                     IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
00693                                           "array");
00694 
00695                 /*
00696                  * Put in type of parameter
00697                  */
00698                 if (!xpcom_to_java_type(state,
00699                                         IDL_PARAM_DCL(state->tree).param_type_spec)) {
00700                     return FALSE;
00701                 }
00702                 if (array)
00703                     fputs("[]", state->file);
00704             }
00705 
00706             state->tree = original_tree;
00707         }
00708 
00709         if (retval_param == NULL) {
00710             fputs("void", state->file);
00711         }
00712     }
00713  
00714     /*
00715      * Write method name
00716      */
00717     fprintf(state->file, " %s(", subscriptIdentifier(state, method_name));
00718 
00719     /*
00720      * Write parameters
00721      */
00722     for (iterator = method->parameter_dcls; iterator != NULL; 
00723          iterator = IDL_LIST(iterator).next) {
00724 
00725         /* Skip "retval" */
00726         if (iterator == retval_param) {
00727             continue;
00728         }
00729 
00730         if (iterator != method->parameter_dcls) {
00731             fputs(", ", state->file);
00732         }
00733         
00734         state->tree = IDL_LIST(iterator).data;
00735 
00736         if (!xpcom_to_java_param(state)) {
00737             return FALSE;
00738         }
00739     }
00740 
00741     fputs(")", state->file);
00742 
00743     /* XXX
00744        Disable this for now.  How do we specify exceptions?
00745     if (method->raises_expr) {
00746         IDL_tree iter = method->raises_expr;
00747         IDL_tree dataNode = IDL_LIST(iter).data;
00748 
00749         fputs(" throws ", state->file);
00750         fputs(IDL_IDENT(dataNode).str, state->file);
00751         iter = IDL_LIST(iter).next;
00752 
00753         while (iter) {
00754             dataNode = IDL_LIST(iter).data;
00755             fprintf(state->file, ", %s", IDL_IDENT(dataNode).str);
00756             iter = IDL_LIST(iter).next;
00757         }
00758     }   */
00759 
00760     fputs(";\n", state->file);
00761 
00762     return TRUE;
00763     
00764 }
00765 
00766 
00767 static gboolean
00768 constant_declaration(TreeState *state)
00769 {
00770     /*
00771      * The C++ header XPIDL module only allows for shorts and longs (ints)
00772      * to be constants, so we will follow the same convention
00773      */
00774 
00775     struct _IDL_CONST_DCL *declaration = &IDL_CONST_DCL(state->tree);
00776     const char *name = IDL_IDENT(declaration->ident).str;
00777     IDL_tree real_type;
00778     
00779     gboolean success;
00780     gboolean isshort = FALSE;
00781 
00782     if (!verify_const_declaration(state->tree))
00783         return FALSE;
00784 
00785     /* Could be a typedef; try to map it to the real type. */
00786     real_type = find_underlying_type(declaration->const_type);
00787     real_type = real_type ? real_type : declaration->const_type;
00788 
00789     /*
00790      * Consts must be in an interface
00791      */
00792 
00793     if (!IDL_NODE_UP(IDL_NODE_UP(state->tree)) ||
00794         IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(state->tree))) != 
00795         IDLN_INTERFACE) {
00796 
00797         XPIDL_WARNING((state->tree, IDL_WARNING1,
00798                        "A constant \"%s\" was declared outside an interface."
00799                        "  It was ignored.", name));
00800 
00801         return TRUE;
00802     }
00803 
00804     /*
00805      * Make sure this is a numeric short or long constant.
00806      */
00807 
00808     success = (IDLN_TYPE_INTEGER == IDL_NODE_TYPE(real_type));
00809 
00810     if (success) {
00811         /*
00812          * We aren't successful yet, we know it's an integer, but what *kind*
00813          * of integer?
00814          */
00815 
00816         switch(IDL_TYPE_INTEGER(real_type).f_type) {
00817 
00818         case IDL_INTEGER_TYPE_SHORT:
00819             /*
00820              * We're OK
00821              */
00822             isshort = TRUE;
00823             break;
00824 
00825         case IDL_INTEGER_TYPE_LONG:
00826             /*
00827              * We're OK
00828              */            
00829             break;
00830             
00831         default:
00832             /*
00833              * Whoops, it's some other kind of number
00834              */            
00835             success = FALSE;
00836         }     
00837     } else {
00838             IDL_tree_error(state->tree,
00839                            "const declaration \'%s\' must be of type short or long",
00840                            name);
00841             return FALSE;
00842     }
00843 
00844 /*    if (doc_comments != NULL) {
00845         fputs("    ", state->file);
00846         printlist(state->file, doc_comments);
00847     }   */
00848 
00849     if (success) {
00850         /* Since Java does not have any concept of 'unsigned short', we need
00851          * to check that the value is in the proper range.  If not, promote
00852          * it to an 'int'. */
00853         int value = (int) IDL_INTEGER(declaration->const_exp).value;
00854         if (isshort && (value < -32768 || value > 32767))
00855             isshort = FALSE;
00856 
00857         fputc('\n', state->file);
00858         xpidl_write_comment(state, 4);
00859 /*        write_comment(state);     */
00860 
00861         fprintf(state->file, "    public static final %s %s = %d;\n",
00862                 (isshort ? "short" : "int"),
00863                 subscriptIdentifier(state, (char*) name),
00864                 (int) IDL_INTEGER(declaration->const_exp).value);
00865     } else {
00866         XPIDL_WARNING((state->tree, IDL_WARNING1,
00867                        "A constant \"%s\" was not of type short or long."
00868                        "  It was ignored.", name));     
00869     }
00870 
00871     return TRUE;
00872 
00873 }
00874 
00875 #define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data))
00876 #define ATTR_PROPS(tree) (IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data)
00877 #define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL((tree)).param_type_spec)
00878 
00879 
00880 static gboolean
00881 attribute_declaration(TreeState *state)
00882 {
00883     gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly;
00884     char *attribute_name = ATTR_IDENT(state->tree).str;
00885 
00886     gboolean method_noscript = 
00887         (IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript") != NULL);
00888 
00889     gboolean method_notxpcom = 
00890         (IDL_tree_property_get(ATTR_PROPS(state->tree), "notxpcom") != NULL);
00891 
00892 #if 0
00893     /*
00894      * Disabled here because I can't verify this check against possible
00895      * users of the java xpidl backend.
00896      */
00897     if (!verify_attribute_declaration(state->tree))
00898         return FALSE;
00899 #endif
00900 
00901     /* Comment */
00902     fputc('\n', state->file);
00903     xpidl_write_comment(state, 4);
00904 
00905 #if 1
00906     /*
00907      * Write access permission ("public")
00908      */
00909     fputs("    public ", state->file);
00910 #else
00911     if (method_notxpcom || method_noscript)
00912         return TRUE;
00913 
00914     /*
00915      * Write access permission ("public" unless nonscriptable)
00916      */
00917     fputs("    ", state->file);
00918     if (!method_noscript) {
00919         fputs("public ", state->file);
00920     }
00921 #endif
00922 
00923     /*
00924      * Write the proper Java return value for the get operation
00925      */
00926     if (!xpcom_to_java_type(state, ATTR_TYPE_DECL(state->tree))) {
00927         return FALSE;
00928     }
00929     
00930     /*
00931      * Write the name of the accessor ("get") method.
00932      */
00933     fprintf(state->file, " get%c%s();\n",
00934             toupper(attribute_name[0]), attribute_name + 1);
00935 
00936 
00937     if (!read_only) {
00938 #if 1
00939         fputs("    public ", state->file);
00940 #else
00941         /* Nonscriptable methods become package-protected */
00942         fputs("    ", state->file);
00943         if (!method_noscript) {
00944             fputs("public ", state->file);
00945         }
00946 #endif
00947 
00948         /*
00949          * Write attribute access method name and return type
00950          */
00951         fprintf(state->file, "void set%c%s(",
00952                 toupper(attribute_name[0]), 
00953                 attribute_name+1);
00954         
00955         /*
00956          * Write the proper Java type for the set operation
00957          */
00958         if (!xpcom_to_java_type(state, ATTR_TYPE_DECL(state->tree))) {
00959             return FALSE;
00960         }
00961 
00962         /*
00963          * Write the name of the formal parameter.
00964          */
00965         fprintf(state->file, " a%c%s);\n", toupper(attribute_name[0]), attribute_name + 1);
00966     }
00967 
00968     return TRUE;
00969 }
00970 
00971 
00972 static gboolean
00973 enum_declaration(TreeState *state)
00974 {
00975     XPIDL_WARNING((state->tree, IDL_WARNING1,
00976                    "enums not supported, enum \'%s\' ignored",
00977                    IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str));
00978     return TRUE;
00979 }
00980 
00981 backend *
00982 xpidl_java_dispatch(void)
00983 {
00984     static backend result;
00985     static nodeHandler table[IDLN_LAST];
00986     static gboolean initialized = FALSE;
00987 
00988     result.emit_prolog = java_prolog;
00989     result.emit_epilog = java_epilog;
00990 
00991     if (!initialized) {
00992         table[IDLN_INTERFACE] = interface_declaration;
00993         table[IDLN_LIST] = process_list;
00994 
00995         table[IDLN_OP_DCL] = method_declaration;
00996         table[IDLN_ATTR_DCL] = attribute_declaration;
00997         table[IDLN_CONST_DCL] = constant_declaration;
00998 
00999         table[IDLN_TYPE_DCL] = type_declaration;
01000         table[IDLN_FORWARD_DCL] = forward_declaration;
01001 
01002         table[IDLN_TYPE_ENUM] = enum_declaration;
01003 
01004         initialized = TRUE;
01005     }
01006 
01007     result.dispatch_table = table;
01008     return &result;
01009 }
01010 
01011 char* subscriptIdentifier(TreeState *state, char *str)
01012 {
01013     char *sstr = NULL;                                                  
01014     char *keyword = g_hash_table_lookup(KEYWORDS(state), str);
01015     if (keyword) {
01016         sstr = g_strdup_printf("%s_", keyword);
01017         return sstr;
01018     }
01019     return str;
01020 }
01021