/*
 * 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;
}
Example #2
0
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;
    
}