Logo Search packages:      
Sourcecode: babel version File versions  Download package

Method.java

// File:        Method.java
// Package:     gov.llnl.babel.symbols
// Revision:    @(#) $Id: Method.java 6212 2007-11-01 00:07:17Z epperly $
// Description: sidl method (modifiers, return type, name, args, and throws)
//
// Copyright (c) 2000-2003, The Regents of the University of Calfornia.
// Produced at the Lawrence Livermore National Laboratory.
// Written by the Components Team <components@llnl.gov>
// UCRL-CODE-2002-054
// All rights reserved.
// 
// This file is part of Babel. For more information, see
// http://www.llnl.gov/CASC/components/. Please read the COPYRIGHT file
// for Our Notice and the LICENSE file for the GNU Lesser General Public
// License.
// 
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License (as published by
// the Free Software Foundation) version 2.1 dated February 1999.
// 
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
// conditions of the GNU Lesser General Public License for more details.
// 
// You should have recieved a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package gov.llnl.babel.symbols;
import gov.llnl.babel.BabelConfiguration;
import gov.llnl.babel.Context;
import gov.llnl.babel.symbols.ASTNode; 
import gov.llnl.babel.symbols.Argument;
import gov.llnl.babel.symbols.Assertion;
import gov.llnl.babel.symbols.AssertionException;

import gov.llnl.babel.backend.CodeGenerationException;
import gov.llnl.babel.backend.IOR;
import gov.llnl.babel.backend.Utilities;
import gov.llnl.babel.backend.c.C;
import gov.llnl.babel.backend.fortran.Fortran;
import gov.llnl.babel.symbols.Comment;
import gov.llnl.babel.symbols.SymbolID;
import gov.llnl.babel.symbols.SymbolUtilities;
import gov.llnl.babel.symbols.Type;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * The <code>Method</code> class defines a SIDL method, including modifiers,
 * return type, name, arguments, and exceptions.  Methods may have one of
 * three definition modifiers: final, static, or abstract.  They may also
 * have one of two communication modifiers: local or oneway.  The return type
 * is either a type or null (which indicates void).  The method name is a
 * simple identifier string.  The optional arguments are an ordered collecton
 * or arguments.  The method may throw any number of exceptions.
 */
00070 public class Method extends ASTNode 
  implements Cloneable, Attributes, IMetadata {
  public static final int NORMAL   = 0; // communication/definition modifier
  public static final int ABSTRACT = 1; // definition modifier
  public static final int FINAL    = 2; // definition modifier
  public static final int STATIC   = 3; // definition modifier
  public static final int LOCAL    = 1; // communication modifier
  public static final int ONEWAY   = 2; // communication modifier
  public static final int NONBLOCKING = 3; // communication modifier (set by parser)
  public static final int NONBLOCKING_SEND = 4; // communication modifier (set by spawning a NONBLOCKING instance)
  public static final int NONBLOCKING_RECV = 5; // communication modifier (set by spawning a NONBLOCKING instance)

  public static final String[] s_def_mod = {
    "", "abstract", "final", "static",
  };

  public static final String[] s_comm_mod = {
    "", "local", "oneway", "nonblocking", "nonblocking_send", "nonblocking_recv",
  };

  private Map   d_attributes = new HashMap();
  private Metadata  d_metadata = new Metadata(new Date());
  private List d_arguments;
  private boolean   d_is_builtin;
  private Comment   d_comment;
  private String    d_short_name;      // for langs that support overloading
  private String    d_extension;       // short + extension = long name
  private String    d_long_name;       // keep for convenience
  private String    d_blocking_name;   // if NONBLOCKING_SEND or NONBLOCKING_RECV, this has the original name
  private Set   d_references;
  private Set   d_references_no_exceptions;  //subset of references, no exceptions
  private Set   d_basicarrays;     // basic array types references
  private Type      d_return_type;
  private Set   d_throws;
  private Set   d_explicit_throws;  // subset of d_throws
  private List d_preconditions;     // Local preconditions only
  private List d_postconditions;    // Local postconditions only
  private Set   d_rarray_indices; //All the rarray indices required in the arg list 
  private Map   d_rarray_index_map; //A Hashmap of rarray index names to
                                        //a collection of RarrayInfo objects.  And
                                        //RarrayInfo objects represents
                                        //what rarray uses the index, and where.
  private SplicerList d_splicers = null;  // Optional splicer blocks
  private Context d_context;

  /**
   * Create an empty <code>Method</code> object that will be built by
   * calls to other member functions.
   */
00119   public Method(Context context) {
    d_context = context;
    d_arguments              = new ArrayList();
    d_is_builtin             = false;  /* NOT built-in by default */
    d_comment                = null;
    d_short_name             = null;
    d_extension              = null;
    d_long_name              = null;
    d_references             = new HashSet();
    d_references_no_exceptions = new HashSet();
    d_basicarrays            = new HashSet();
    d_return_type            = null;
    d_throws                 = new TreeSet();
    d_explicit_throws        = new TreeSet();
    d_preconditions          = new ArrayList();
    d_postconditions         = new ArrayList();
    d_rarray_indices         = null;      
    d_splicers               = null;
  }

  /**
   * Return a shallow copy of this method object.  This method should
   * never fail since this method is cloneable.  Send in the clones.
   */
00143   public Method cloneMethod() {
    Method m = null;
    try {
      m = (Method) super.clone();
      m.d_attributes = new HashMap();
      m.d_attributes.putAll(d_attributes);
    } catch (CloneNotSupportedException ex) {
      throw new java.lang.InternalError(ex.getMessage());
    }
    return m;
  }

  private void copyAttributes(Attributes src, Attributes dest)
  {
    Iterator i = src.getAttributes().iterator();
    while(i.hasNext()) {
      String key = (String)i.next();
      dest.setAttribute(key, src.getAttribute(key));
    }
  }

  /**
   * Create the pre hook variant iff hooks are turned on.  Always filters
   * out the return value and the out args
   * 
   * @param withinout If false, all in and inout args are converted to in
   * args only.  If true, inouts remain inout.  out args are always removed.
   * @return new Method or null;
   * @see #spawnNonblockingRecv()
   */
00173   public Method spawnPreHook(boolean withinout) throws CodeGenerationException {
    Method m = new Method(d_context);
    m.d_is_builtin = true;

    // now largely copy everything... but there are important differences.
    m.d_comment = d_comment;
    m.d_attributes.putAll(d_attributes);
    
    m.d_blocking_name = d_long_name;
    m.d_short_name = d_short_name + IOR.GENERIC_PRE_SUFFIX;
    m.d_extension = d_extension;
    m.d_long_name = d_long_name + IOR.GENERIC_PRE_SUFFIX;
    // FIXME: May need to downselect later.
    m.d_references = new HashSet( d_references);
    m.d_references_no_exceptions = new HashSet( d_references_no_exceptions);
    // FIXME: May need to downselect later.
    m.d_basicarrays = new HashSet(d_basicarrays);

    m.d_throws = new TreeSet( d_throws);
    m.d_explicit_throws = new TreeSet(d_explicit_throws);
    
    /*
     * There is NO (good) reason to clone the method's contracts.
     */
    m.d_preconditions  = null;
    m.d_postconditions = null;
          
    m.d_rarray_indices = ((d_rarray_indices == null ) ? null : new HashSet(d_rarray_indices));
    m.d_rarray_index_map = ((d_rarray_index_map == null ) ? null : new HashMap(d_rarray_index_map));

    m.d_arguments = new ArrayList();
    m.d_arguments.addAll(d_arguments);

    /* 
     * now the key part... create a new arglist for the pre hook
     * that optionally converts all arguments to IN mode.  (To
     * avoid the developer changing the arguments inside the hook)
     */
    m.d_arguments = new ArrayList();
    for( Iterator i = d_arguments.iterator(); i.hasNext(); ) { 
      Argument arg = (Argument) i.next();
      if ( arg.getMode() != Argument.OUT ) { 
        Argument newarg = null;
        if(withinout) {
          newarg = new Argument(arg.getMode(), arg.getType(), arg.getFormalName() );
        } else {
          newarg = new Argument(Argument.IN, arg.getType(), arg.getFormalName() );
        }
        copyAttributes(arg, newarg);
        m.d_arguments.add(newarg);
      }
    }
    m.d_splicers = null;  /* Do not need clone of splicer block contents */
    m.d_return_type = new Type(Type.VOID);
    return m;
  }

  public Method spawnPreHook() throws CodeGenerationException {
    return spawnPreHook(false);
  }

  /**
   * Create the post hook variant iff hooks are turned on.  The return
   * argument is always converted to an in argument
   * 
   * 
   * @param useCReturn if true, uses the return name given in C.java.  If
   * false, uses the Fortran variant name
   * @param without If false, all out and inout args are converted to in
   * args only.  If true, inouts and outs remain such.
   * @return new Method or null;
   * @see #spawnNonblockingRecv()
   */
00246   public Method spawnPostHook(boolean useCReturn, boolean without) throws CodeGenerationException
  {
    Method m = new Method(d_context);
    m.d_is_builtin = true;

    // now largely copy everything... but there are important differences.
    m.d_comment = d_comment;
    m.d_attributes.putAll(d_attributes);
    
    m.d_blocking_name = d_long_name;
    m.d_short_name = d_short_name + IOR.GENERIC_POST_SUFFIX;
    m.d_extension = d_extension;
    m.d_long_name = d_long_name + IOR.GENERIC_POST_SUFFIX;
    // FIXME: May need to downselect later.
    m.d_references = new HashSet( d_references);
    m.d_references_no_exceptions = new HashSet( d_references_no_exceptions);
    // FIXME: May need to downselect later.
    m.d_basicarrays = new HashSet(d_basicarrays);
    

    m.d_throws = new TreeSet( d_throws);
    m.d_explicit_throws = new TreeSet( d_explicit_throws);

    /*
     * There is NO (good) reason to clone the method's contracts.
     */
    m.d_preconditions  = null;
    m.d_postconditions = null;
          
    m.d_rarray_indices = ((d_rarray_indices == null ) ? null : new HashSet(d_rarray_indices));
    m.d_rarray_index_map = ((d_rarray_index_map == null ) ? null : new HashMap(d_rarray_index_map));

    m.d_arguments = new ArrayList();
    m.d_arguments.addAll(d_arguments);

    /* 
     * now the key part... create a new arglist for the post hook
     * that optionally converts all arguments to IN mode. (To
     * avoid the developer changing the arguments inside the hook)
     */
    m.d_arguments = new ArrayList();
    for( Iterator i = d_arguments.iterator(); i.hasNext(); ) { 
      Argument arg = (Argument) i.next();
      Argument newarg = null;
      if(without) {
        newarg = new Argument(arg.getMode(), arg.getType(), arg.getFormalName() );
      } else {
        newarg = new Argument(Argument.IN, arg.getType(), arg.getFormalName() );
      }
      copyAttributes(arg, newarg);
      m.d_arguments.add(newarg);
    }
    Type t = d_return_type;
    if ( (t != null) && (t.getType() != Type.VOID) ) {
      Argument a;
      if (useCReturn) {
        a = new Argument(Argument.IN, t, C.FUNCTION_RESULT);
      } else {
        a = new Argument(Argument.IN, t, Fortran.s_return);
      }
      m.addArgument(a);
    }

    m.d_splicers = null;  /* Do not need clone of splicer block contents */
    m.d_return_type = new Type(Type.VOID);
    return m;
  }
  
  public Method spawnPostHook() throws CodeGenerationException {
    return spawnPostHook(true, false);
  }

  /**
   * Create the non-blocking send variant iff method is nonblocking
   * 
   * @return new Method or null;
   * @see #spawnNonblockingRecv()
   */
00324   public Method spawnNonblockingSend() throws CodeGenerationException {
    if ( getCommunicationModifier() != NONBLOCKING ) { 
      return null;
    }
    Method m = new Method(d_context);
    m.d_is_builtin = true;

    // now largely copy everything... but there are important differences.
    m.d_comment = d_comment;
    m.d_attributes.putAll(d_attributes);
    
    // change NONBLOCKING to NONBLOCKING_SEND
    m.setCommunicationModifier(NONBLOCKING_SEND);
    m.d_blocking_name = d_long_name;
    m.d_short_name = d_short_name + "_send";
    m.d_extension = d_extension;
    m.d_long_name = d_long_name + "_send";
    // FIXME: May need to downselect later.
    m.d_references = new HashSet ( d_references);
    m.d_references_no_exceptions = new HashSet( d_references_no_exceptions);
    // FIXME: May need to downselect later.
    m.d_basicarrays = new HashSet( d_basicarrays);
    
    // send will always return a local Ticket
    Symbol tmpsym = Utilities.lookupSymbol(d_context, "sidl.rmi.Ticket");
    m.d_return_type = new Type( tmpsym.getSymbolID(), d_context );  
    
    // send can return exceptions if the send fails
    // (not any exceptions from the recipient)
    TreeSet default_throws = new TreeSet();
    default_throws.add( Utilities.lookupSymbol(d_context, BabelConfiguration.getRuntimeException())
                        .getSymbolID());
    m.d_throws = default_throws;
    m.d_explicit_throws = new TreeSet();

    // FIXME: ask Tammy if this is right?
    m.d_preconditions = new ArrayList( d_preconditions);
    m.d_postconditions = new ArrayList( d_postconditions);
          
    m.d_rarray_indices = ((d_rarray_indices == null ) ? null : new HashSet(d_rarray_indices));
    m.d_rarray_index_map = ((d_rarray_index_map == null ) ? null : new HashMap(d_rarray_index_map));
        
    /* 
     * now the key part... create a new arglist for the send
     * this new arglist contains only the in and inout args
     * but they all appear simply as "in"
     */
    m.d_arguments = new ArrayList();
    for( Iterator i = d_arguments.iterator(); i.hasNext(); ) { 
      Argument arg = (Argument) i.next();
      if ( arg.getMode() != Argument.OUT ) { 
        Argument newarg = new Argument(Argument.IN, arg.getType(), arg.getFormalName() );
        copyAttributes(arg, newarg);
        m.d_arguments.add(newarg);
      }
    }
    m.d_splicers = null;  /* Do not need clone of splicer block contents */
    return m;
  }
  
  /**
   * Create the non-blocking recv variant iff method is nonblocking
   * 
   * @return new Method or null;
   * @see #spawnNonblockingSend()
   */
00390   public Method spawnNonblockingRecv() throws CodeGenerationException {
    if ( getCommunicationModifier() != NONBLOCKING ) { 
      return null;
    }
    Method m = new Method(d_context);
    m.d_is_builtin = true;

    m.d_attributes.putAll(d_attributes);

    // now largely copy everything... but there are important differences.
    m.d_comment = d_comment;
    m.setCommunicationModifier(NONBLOCKING_RECV); // change NONBLOCKING to NONBLOCKING_RECV
    m.d_blocking_name = d_long_name;

    m.d_short_name = d_short_name + "_recv";
    m.d_extension = d_extension;

    m.d_long_name = d_long_name + "_recv";
    m.d_references_no_exceptions = new HashSet( d_references_no_exceptions);

    m.d_basicarrays = new HashSet( d_basicarrays); // FIXME: May need to downselect later
    m.setReturnCopy(isReturnCopy());
    m.d_return_type = d_return_type;
    m.d_throws = new TreeSet( d_throws);
    m.d_explicit_throws = new TreeSet( d_explicit_throws);
    m.d_preconditions = new ArrayList( d_preconditions);        // FIXME: ask Tammy if this is right?
    m.d_postconditions = new ArrayList( d_postconditions); 
    m.d_rarray_indices = ((d_rarray_indices == null ) ? null : new HashSet(d_rarray_indices));
    m.d_rarray_index_map = ((d_rarray_index_map == null ) ? null : new HashMap(d_rarray_index_map));
        
    /* 
     * now the key part... create a new arglist for the send
     * this new arglist contains only the inout and out args
     * but they all appear simply as "out", the extends of any
     * inout rarray and the ticket from the corresponding send call are both
     * "in."
     */
    m.d_arguments = new ArrayList();
    Symbol ticketSymbol = Utilities.lookupSymbol(d_context, "sidl.rmi.Ticket");
    Type ticketType = new Type( ticketSymbol.getSymbolID(), d_context );
    Argument ticketArg = new Argument(Argument.IN, ticketType, "ticket");
    m.d_arguments.add(ticketArg);
      
    HashSet rarrayIndicies = new HashSet();
    if(m.hasRarray()) {
      for( Iterator i = d_arguments.iterator(); i.hasNext(); ) { 
        Argument arg = (Argument) i.next();
        if (arg.getType().isRarray()  && 
            arg.getMode() != Argument.IN ) {
          rarrayIndicies.addAll(arg.getType().getArrayIndices());
        }
      }
    }

    for( Iterator i = d_arguments.iterator(); i.hasNext(); ) { 
      Argument arg = (Argument) i.next();
      //Include out args and rarray index args
      if ( arg.getMode() != Argument.IN ||
           rarrayIndicies.contains(arg.getFormalName())) {
        m.d_arguments.add(arg);
      }          
    }

    m.d_splicers = null;  /* Do not need clone of splicer block contents */
    return m;
  }
  
  /**
   * Add another argument to the end of the list of method arguments.
   *
   * @param  arg  The argument to be appended to the object's argument list
   */
00462   public void addArgument(Argument arg) {
    checkFrozen();
    d_arguments.add(arg);
    addTypeReferences(arg.getType());
  }

  /**
   * Return the array of arguments in an <code>ArrayList</code>, where each
   * element is an <code>Argument</code>.
   */
00472   public List getArgumentList() {
    return getArgumentListWithOutIndices();
  }

  /**
   * Return the array of arguments in an <code>ArrayList</code> container.
   * This method returns only arguments that are not used as indices to 
   * an Rarray
   */
00481   public List getArgumentListWithOutIndices() {
    if(d_rarray_indices != null) {
      ArrayList ret = new ArrayList(Math.max(d_arguments.size() -
                                             d_rarray_indices.size(),0));
      for(Iterator a = d_arguments.iterator(); a.hasNext();) {
        Argument arg = (Argument) a.next();
        if (!d_rarray_indices.contains(arg.getFormalName())) {
          ret.add(arg);
        }
      }      
      return ret;
    } else {
      return d_arguments;
    }
  }

  /**
   * Return the array of arguments in an <code>ArrayList</code> container.
   * This returns all the arguments in the argument list, including those
   * that are indices to an Rarray.
   */
00502   public List getArgumentListWithIndices() {
    return protectList(d_arguments);
  }


  /**
   * add a required rarray index to the set of indices
   */ 
00510   public void addRarrayIndex(String s) {
    checkFrozen();
    if(d_rarray_indices == null)
      d_rarray_indices = new HashSet();
    d_rarray_indices.add(s);
  }

  /**
   * add a set of required rarray indices to the set of indices
   */ 
00520   public void addRarrayIndex(Collection new_indices) {
    checkFrozen();
    if(d_rarray_indices == null)
      d_rarray_indices = new HashSet();
    d_rarray_indices.addAll(new_indices);
  }
  
  /**
   * Return the set of rarray indices required in the arg list.  
   * (Returns null if there are no indices required)
   */
00531   public Set getRarrayIndices() {
    return protectSet(d_rarray_indices);
  } 

  /**
   * Returns true if this method has an rarray in it's signature
   */
00538   public boolean hasRarray() {
    return d_rarray_indices != null;
  }

  /**
   * Returns the number of rarray arguments in the method's argument list.
   */
00545   public int numRarray() {
    int result = 0;
    Iterator i = d_arguments.iterator();
    while (i.hasNext()) {
      if (((Argument)i.next()).getType().isRarray()) {
        ++result;
      }
    }
    return result;
  }

  /**
   * Return the <code>Type</code> of the argument with the specified formal 
   * name, if any; otherwise, return null.
   *
   * @param  name  The formal argument name whose type is to be returned.
   */
00562   public Type getArgumentType(String name) {
    Type t = null;
    for (Iterator i=d_arguments.iterator(); (i.hasNext() && (t == null)); ) {
      Argument arg = (Argument) i.next();
      if (arg.getFormalName().equals(name)) {
        t = arg.getType();
      }
    }
    return t;
  }

  /**
   * Return the mode of the argument with the specified formal name, if any; 
   * otherwise, return -1.
   *
   * @param  name  The formal argument name whose type is to be returned.
   */
00579   public int getArgumentMode(String name) {
    int m = -1;
    for (Iterator i=d_arguments.iterator(); (i.hasNext() && (m == -1)); ) {
      Argument arg = (Argument) i.next();
      if (arg.getFormalName().equals(name)) {
        m = arg.getMode();
      }
    }
    return m;
  }

  /**
   * Set the built-in attribute.
   *
   * @param  is_builtin  TRUE if the method is/should be built-in; otherwise,
   *                     false.
   */
00596   public void setBuiltIn(boolean is_builtin) {
    checkFrozen();
    d_is_builtin = is_builtin;
  }

  /**
   * Return the built-in attribute for the method.  
   */
00604   public boolean isBuiltIn() {
    return d_is_builtin;
  }

  /**
   * Set the comment for the method.  
   *
   * @param  comment  The comment associated with the method.  May be null.
   */
00613   public void setComment(Comment comment) {
    checkFrozen();
    d_comment = comment;
  }

  /**
   * Return the comment for the method.  This may be null if there is no
   * comment.
   */
00622   public Comment getComment() {
    return d_comment;
  }

  /**
   * Set the communication modifier for the method.  
   *
   * @param  modifier  The method's communication modifier.  Valid values
   *                   are NORMAL, LOCAL, and ONEWAY.
   */
00632   public void setCommunicationModifier(int modifier) {
    checkFrozen();
    for(int i = 0 ; i < s_comm_mod.length; ++i) {
      if (i == modifier) {
        if (s_comm_mod[i].length() > 0) {
          setAttribute(s_comm_mod[i]);
        }
      }
      else {
        if (hasAttribute(s_comm_mod[i])) {
          removeAttribute(s_comm_mod[i]);
        }
      }
    }
  }

  /**
   * Return the communication modifier for this method.  
   */
00651   public int getCommunicationModifier() {
    int i;
    for(i = s_comm_mod.length - 1; i > 0; --i) {
      if (hasAttribute(s_comm_mod[i])) return i;
    }
    return i;                   // defaults to 0 normal
  }

  /**
   * Return the communication modifier string for this method.  
   */
00662   public String getCommunicationModifierString() {
    return s_comm_mod[getCommunicationModifier()];
  }

  /**
   * Set the definition modifier for the method.
   *
   * @param  modifier  The method's definnition modifier.  Valid values are
   *                   NORMAL, ABSTRACT, FINAL, and STATIC.
   */
00672   public void setDefinitionModifier(int modifier) {
    checkFrozen();
    for(int i = 0; i < s_def_mod.length; ++i) {
      if (i == modifier) {
        if (s_def_mod[i].length() > 0) {
          setAttribute(s_def_mod[i]);
        }
      }
      else {
        if (hasAttribute(s_def_mod[i])) { 
          removeAttribute(s_def_mod[i]);
        }
      }
    }
  }

  /**
   * Return the definition modifier for the method.  
   */
00691   public int getDefinitionModifier() {
    int i;
    for(i = s_def_mod.length - 1; i > 0; --i){
      if (hasAttribute(s_def_mod[i])) return i;
    }
    return i;
  }

  /**
   * Return the explicit definition modifier string for the method based
   * on the type of extendable in which it belongs.  
   *
   * @param  is_interface  If TRUE, then the extendable is an interface so
   *                       do NOT include ABSTRACT since it is implicit.
   * @return the string associated with the explicit definition modifier
   */
00707   public String getDefinitionModifier(boolean is_interface) {
    String mod = null;
    if (  (!is_interface)
          || (getDefinitionModifier() == NORMAL) ) {
      mod = s_def_mod[getDefinitionModifier()];
    }
    return mod;
  }

  /**
   * Return TRUE if the method is abstract; otherwise, return FALSE.
   */
00719   public boolean isAbstract() {
    return getDefinitionModifier() == ABSTRACT;
  }

  /**
   * Return TRUE if the method is final; otherwise, return FALSE.
   */
00726   public boolean isFinal() {
    return getDefinitionModifier() == FINAL;
  }

  /**
   * Return TRUE if the method is static; otherwise, return FALSE.
   */
00733   public boolean isStatic() {
    return getDefinitionModifier() == STATIC;
  }

  /**
   * Return TRUE if and only if at least one argument of this method is an 
   * array with an ordering specification.  For example, calling this on 
   * methods without array arguments will return FALSE while calling it on 
   * something like <code>void doIt(in array&lt;int, 2, row-major&gt; x);</code>
   * will return TRUE.
   */
00744   public boolean hasArrayOrderSpec() {
    if (d_return_type.hasArrayOrderSpec()) return true;
    for(Iterator i = d_arguments.iterator(); i.hasNext(); ){
      if (((Argument)i.next()).hasArrayOrderSpec()) return true;
    }
    return false;
  }

  /**
   * Set the names of the method (a standard SIDL identifier).
   *
   * @param  shortName  The short name of the method
   * @param  extension  The method name extension used in combination
   *                    with the short name to uniquely identify this 
   *                    method
   */
00760   public void setMethodName(String shortName, String extension) {
    checkFrozen();
    d_short_name = shortName;
    d_extension  = extension;
    d_long_name  = shortName + extension;
  }

  /**
   * Set the names of the method (a standard SIDL identifier).  Use of
   * this method will result in the long and short name being identical.
   *
   * @param  shortName  The short name of the method
   */
00773   public void setMethodName(String shortName) {
    checkFrozen();
    setMethodName(shortName, "");
  }


  /**
   * This method is used for language bindings that support overloading.
   * For most methods it will return the short name, but if the method 
   * requires the long name for some reason determinable inside the method
   * class, the long name is returned.
   * For example, nonblocking send and receive always use the long method name.
   */
00786   public String getCorrectMethodName() {
    if(getCommunicationModifier() == NONBLOCKING_SEND ||
       getCommunicationModifier() == NONBLOCKING_RECV) {
      return getLongMethodName();
    } else {
      return getShortMethodName();
    }
  }

  /**
   * Return the short method name (a standard SIDL identifier).
   */
00798   public String getShortMethodName() {
    return d_short_name;
  }

  /**
   * Return the method name extension (a standard SIDL identifier).
   */
00805   public String getNameExtension() {
    return d_extension;
  }

  /**
   * Return the long method name (a standard SIDL identifier).
   */
00812   public String getLongMethodName() {
    return d_long_name;
  }

  /**
   * Return the nonblocking method name (if NONBLOCKING), else return long name
   */
00819   public String getBlockingMethodName() { 
    final int modifier = getCommunicationModifier();
    if (modifier == NONBLOCKING_SEND || 
        modifier == NONBLOCKING_RECV ) {  
      return d_blocking_name;
    } else { 
      return d_long_name;
    }
  }
  
  /**
   * Set the copy mode for the return type.  
   *
   * @param  copy  If TRUE then the return interface/class is to be copied 
   *               to the caller; otherwise, it is not.
   */
00835   public void setReturnCopy(boolean copy) {
    checkFrozen();
    if (copy) {
      d_attributes.put("copy", null);
    }
    else {
      d_attributes.remove("copy");
    }
  }

  /**
   * Return the copy mode for the return type.  
   */
00848   public boolean isReturnCopy() {
    return d_attributes.containsKey("copy");
  }

  /**
   * Set the return type for the method.  
   *
   * @param  type  The return type to be used.  Note that a void return
   *               type must be represented by a <code>Type.VOID</code>
   *               NOT a null Type reference.
   */
00859   public void setReturnType(Type type) {
    checkFrozen();
    d_return_type = type;
    addTypeReferences(type);
  }

  /**
   * Return the return type for the method or throw NullPointerException
   */
00868   public Type getReturnType() {
    d_return_type.getType(); // generates an exception if null
    return d_return_type;
  }

  /**
   * Add a symbol identifier to the list of explicit supported exceptions
   * for this method.  No error checking is performed to ensure that the
   * specified symbol is valid in the throws clause; such checking must be
   * performed by the parser. An explicit exception is one that is listed
   * in the SIDL file rather than the implicit runtime exception.
   *
   * @param  id  The symbol identifier to be added 
   */
00882   public void addThrows(SymbolID id) {
    checkFrozen();
    d_explicit_throws.add(id);
    addImplicitThrows(id);
  }

  /**
   * Add a symbol identifier to the list of exceptions thrown, but
   * do not treat it as an explicit throw.
   */
00892   public void addImplicitThrows(SymbolID id ) {
    checkFrozen();
    d_throws.add(id);
    d_references.add(id);
  }

  public boolean isImplicitException(SymbolID id) {
    return d_throws.contains(id) && !d_explicit_throws.contains(id);
  }

  public boolean hasExplicitExceptions() {
    return !d_explicit_throws.isEmpty();
  }

  /**
   * Return the <code>Set</code> of exceptions that may be thrown by this 
   * method.  Each element of the set is a <code>SymbolID</code>.
   */
00910   public Set getThrows() {
    return protectSet(d_throws);
  }

  /**
   * Return the <code>Set</code> of explicit exceptions that may be thrown
   * by this method. Each element of the set is a <code>SymbolID</code>.
   */
00918   public Set getExplicitThrows() {
    return protectSet(d_explicit_throws);
  }

  /**
   * Return the <code>Set</code> of implicit exceptions that may be thrown
   * by this method. Each element of the set is a <code>SymbolID</code>.
   */
00926   public Set getImplicitThrows() {
    TreeSet result = new TreeSet(d_throws);
    result.removeAll(d_explicit_throws);
    return result;
  }

  /**
   * Return the <code>Set</code> of symbols referred to by this method.  
   * Each element of the set is a <code>SymbolID</code>.
   */
00936   public Set getSymbolReferences() {
    return protectSet(d_references);
  }

  /**
   * Return the <code>Set</code> of symbols referred to by this method,
   * except for the exceptions it throws.
   * Each element of the set is a <code>SymbolID</code>.
   */
00945   public Set getSymbolReferencesWithoutExceptions() {
    return protectSet(d_references_no_exceptions);
  }


  /**
   * Return the <code>Set</code> of basic array references including
   * arrays of fundamental types such as double, int, etc.  Each element
   * of the set is a <code>SymbolID</code>.
   */
00955   public Set getBasicArrays() {
    return protectSet(d_basicarrays);
  }


  /**
   * Return the string corresponding to the return type for this method.  Note
   * the string may represent an abbreviated return type (i.e., a type
   * stripped of its package information).
   *
   * @param  parent_pkg  The string containing the parent package.  When not
   *                     null, it is used to strip the package from the return
   *                     string if it is in the specified package.
   * @return             the string containing the possibly abbreviated return
   *                     type.
   */
00971   public String getReturnType(String parent_pkg) {
    StringBuffer result = new StringBuffer();
    String rtype = d_return_type.getTypeString();
    if (parent_pkg != null) {
      result.append(SymbolUtilities.getSymbolName(rtype, parent_pkg));
    } else {
      result.append(rtype);
    }
    return result.toString();
  }

  private String customAttrStr()
  {
    StringBuffer result = new StringBuffer();
    if (getAttributes().size() > 0) {
      HashSet attrs = new HashSet(getAttributes());
      attrs.remove("copy");
      attrs.remove("static");
      attrs.remove("final");
      attrs.remove("abstract");
      attrs.remove("oneway");
      attrs.remove("local");
      attrs.remove("nonblocking");
      if (attrs.size() > 0) {
        Object[] sorted = attrs.toArray();
        Arrays.sort(sorted);
        result.append("%attrib{");
        for(int i = 0; i < sorted.length; ++i) {
          final String key = sorted[i].toString();
          final String value = getAttribute(key);
          result.append(' ').append(key);
          if (value != null) {
            result.append(" = \"").append(value).append('"');
          }
          if (i+1 < sorted.length) {
            result.append(',');
          }
        }
        result.append(" } ");
      }
    }
    return result.toString();
  }

  /**
   * Return the concatenation of the explicit definition modifier, copy,
   * return type, name and extension.
   *
   * @param  is_interface  TRUE if an interface and want the implicit 
   *                       definition modifier excluded from the result; 
   *                       otherwise, FALSE.
   * @param  parent_pkg    The string containing the parent package.  When not
   *                       null, it is used to strip the package from the return
   *                       string if it is in the specified package.
   * @return               the string containing the preface
   */
01027   public String getSignaturePreface(boolean is_interface, String parent_pkg) {
    StringBuffer preface = new StringBuffer();

    String dmod = getDefinitionModifier(is_interface);
    if (dmod != null) {
      preface.append(dmod + " ");
    }
    
    String cmod = getCommunicationModifierString();
    if (cmod != null) {
      preface.append(cmod + " ");
    }

    if (isReturnCopy()) {
      preface.append("copy ");
    }
    preface.append(customAttrStr());
    preface.append(getReturnType(parent_pkg));
    preface.append(" ");
    preface.append(d_short_name);
    if ((d_extension != null) && (d_extension != "")) {
      preface.append(" [");
      preface.append(d_extension);
      preface.append("] ");
    }
    return preface.toString();
  }


  /**
   * Return the signature of the method, including the definition modifier
   * based on the extendable type.  Also, optionally abbreviate type if in 
   * specified package.
   *
   * @param  is_interface  TRUE if interface and want the implicit definition
   *                       modifier excluded from the result; otherwise, FALSE
   * @param  parent_pkg    The string containing the parent package.  When not
   *                       null, it is used to strip the package from the return
   *                       string if it is in the specified package.
   * @return               The string containing the full signature.
   */
01068   public String getSignature(boolean is_interface, String parent_pkg) {
    StringBuffer signature = new StringBuffer();

    signature.append(getSignaturePreface(is_interface, parent_pkg));
    signature.append("(");
    for (Iterator a = d_arguments.iterator(); a.hasNext(); ) {
      signature.append(((Argument) a.next()).getArgumentString());
      if (a.hasNext()) {
        signature.append(", ");
      }
    }
    signature.append(") " + getCommunicationModifierString());

    if (!d_throws.isEmpty()) {
      signature.append(" throws ");
      for (Iterator t = d_throws.iterator(); t.hasNext(); ) {
        SymbolID sid = (SymbolID) t.next();
        String fname = sid.getFullName();
        if (parent_pkg != null) {
          signature.append(SymbolUtilities.getSymbolName(fname, parent_pkg));
        } else {
          signature.append(fname);
        }
        if (t.hasNext()) {
          signature.append(", ");
        }
      }
    }

    return signature.toString();
  }

  /**
   * Return the signature of the method.  The signature does not include
   * the attributes abstract, final, or static.  It also does not abbreviate
   * package names.
   */
01105   public String getSignature() {
    return getSignature(false, null);
  }

  /**
   * Return TRUE if the signature of the specified method matches that of
   * this method; otherwise, return FALSE.  For signatures to match, the 
   * methods must have the same return types and mode, the same names, the 
   * same arguments, and the same throws clauses.  They must also have the 
   * same communication modifiers.  The signature does not include modifiers 
   * static, abstract, or final.
   *
   * @param  m  The method whose signature is being compared with.
   */
01119   public boolean sameSignature(Method m) {
    return sameSignature(m, true);
  }

  /**
   * Return TRUE if the signature of the specified method matches that of
   * this method; otherwise, return FALSE.  For signatures to match, the 
   * methods must have the same return types and mode, the same names, the 
   * same arguments, and the same throws clauses.  They must also have the 
   * same communication modifiers.  The signature does not include modifiers 
   * static, abstract, or final.
   *
   * @param  m  The method whose signature is being compared with.
   * @param  compExt True if the comparision should compare method
   * extensions.  (False for from clauses)
   */
01135   public boolean sameSignature(Method m, boolean compExt) {
    /*
     * Check modifiers, method names, and return types
     */
    if (getCommunicationModifier() != m.getCommunicationModifier()) {
      return false;
    }
    if (!d_short_name.equals(m.d_short_name)) {
      return false;
    }
    if(compExt) {
      if (!d_extension.equals(m.d_extension)) {
        return false;
      }
    }
    if (isReturnCopy() != m.isReturnCopy()) {
      return false;
    }
    if (d_return_type == null) {
      if (m.d_return_type != null) {
        return false;
      }
    } else if (!d_return_type.equals(m.d_return_type)) {
      return false;
    }

    /*
     * Check that the two throws lists are the same
     */
    if (d_throws.size() != m.d_throws.size()) {
      return false;
    }
    for (Iterator i = d_throws.iterator(); i.hasNext(); ) {
      if (!m.d_throws.contains(i.next())) {
        return false;
      }
    }

    return sameArguments(m);
  }

  /**
   * Return TRUE if the base signature of the specified method matches
   * that of this method; otherwise, return FALSE.  For them to match, 
   * the methods must have the same short and the same arguments.
   *
   * @param  m  The method whose base signature is being compared.
   */
01183   public boolean sameBaseSignature(Method m) {
    /*
     * Check the names
     */
    if (!d_short_name.equals(m.d_short_name)) {
      return false;
    }

    return sameArguments(m);
  }

  /**
   * Return TRUE if the arguments of the specified method match those of
   * this method; otherwise, return FALSE.  Note that ordering counts!  
   * That is, the arguments are the same if the same types appear in the 
   * same order.
   *
   * @param  m  The method whose argument list is being compared.
   */
01202   private boolean sameArguments(Method m) {
    /*
     * Check that the arguments are the same
     */
    int size = d_arguments.size();
    if (size != m.d_arguments.size()) {
      return false;
    } else {
      for (int a = 0; a < size; a++) {
        if (!d_arguments.get(a).equals(m.d_arguments.get(a))) {
          return false;
        }
      }
    }

    return true;
  }

  /**
   * Return an the argument whose formal name matches the passed in string.
   * Return null if the string does not match anything.
   */
01224   public Argument getArgumentByName(String s) {
    for(Iterator a = d_arguments.iterator(); a.hasNext();) {
      Argument arg = (Argument) a.next();
      if(arg.getFormalName().compareTo(s) == 0)
        return arg;
    }
      
    return null;
  }

  /**
   * Add the symbol identifier of the specified type to the symbol reference
   * set ONLY if the specified type is an enumerated type, an interface, a 
   * class, or an array of these objects.
   *
   * @param  type  The symbol/type to be added
   */
01241   private void addTypeReferences(Type type) {
    if (type != null) {
      if (type.getType() == Type.SYMBOL) {
        d_references.add(type.getSymbolID());
        d_references_no_exceptions.add(type.getSymbolID());
      } else if (type.getType() == Type.ARRAY) {
        type = type.getArrayType();
        if (null != type) {
          addTypeReferences(type);
          if ((type.getType() >= Type.BOOLEAN) &&
              (type.getType() <= Type.STRING)) {
            Version v = new Version();
            v.appendVersionNumber(0);
            d_basicarrays.add(new SymbolID("sidl." + type.getTypeString(), v));
          }
        }
      }
    }
  }

  /**
   * Return TRUE if PURE clause appears in the assertions associated
   * with this method; otherwise, return FALSE.
   */
01265   public boolean hasPureAssertion() {
    boolean   found = false;
    List list  = getPostconditions();
    for (Iterator iter = list.iterator();
         iter.hasNext() && !found; ) {
      Assertion item = (Assertion) iter.next();
      if (item.hasPureClause()) {
        found = true;
      }
    }
    return found;
  }

  /**
   * Add the specified assertion to the proper assertion list for this method.
   *
   * @param   assertion  The assertion to be added.
   * @throws  gov.llnl.babel.symbols.AssertionException
   *                     The exception thrown if the assertion is not valid.
   */
01285   public void addAssertion(Assertion assertion) throws AssertionException 
  {
    checkFrozen();
    if ( assertion.isPrecondition() ) {
      d_preconditions.add(assertion);
    } else if ( assertion.isPostcondition() ) {
      d_postconditions.add(assertion);
    } else {
      throw new AssertionException("Method: " + d_long_name, "Cannot add a(n) "
                                   + "\"" + assertion.getTypeName() + "\" assertion to a "
                                   + "method\'s assertion list.");
    }
  }

  /**
   * Return the list of preconditions as an <code>ArrayList</code> of
   * <code>Assertion</code> elements.  
   */
01303   public List getPreconditions() {
    return protectList(d_preconditions);
  }

  /**
   * Return the list of postconditions as an <code>ArrayList</code> of
   * <code>Assertion</code> elements.
   */
01311   public List getPostconditions() {
    return protectList(d_postconditions);
  }

  /**
   * Return TRUE if the list of assertions has the specified reserved method 
   * assertion; FALSE otherwise.
   */
01319   public boolean hasReservedMethodAssertion(List list, int type) {
    boolean hasIt = false;
    for (Iterator iter = list.iterator(); iter.hasNext() && !hasIt; ) {
      Assertion item = (Assertion) iter.next();
      if (item.hasReservedMethod(type)) {
        hasIt = true;
      }
    }
    return hasIt;
  }

  /**
   * Return the number of array iteration macros in the assertions of the 
   * method of the specified return type.  Valid types are given in 
   * MethodCall.java as MACRO_RETURNS_* values.
   */
01335   public int getMaxArrayIterMacros(char type) {
    int num;
    Assertion as;
    int max = 0;

    Iterator i = d_preconditions.iterator();
    while (i.hasNext()) {
      as  = (Assertion)i.next();
      num = as.getNumArrayIterMacrosByType(type);
      if (num > max) {
        max = num;
      }
    }

    i = d_postconditions.iterator();
    while (i.hasNext()) {
      as  = (Assertion)i.next();
      num = as.getNumArrayIterMacrosByType(type);
      if (num > max) {
        max = num;
      }
    }

    return max;
  }

  /**
   * Return TRUE if the method has the specified reserved method assertion; 
   * FALSE otherwise.
   */
01365   public boolean hasReservedMethodAssertion(int type) {
    boolean hasIt = hasReservedMethodAssertion(d_preconditions, type);
    if (!hasIt) {
      hasIt = hasReservedMethodAssertion(d_postconditions, type);
    }
    return hasIt;
  }

  /**
   * Return TRUE if the list of assertions has the type of unreserved method 
   * assertion; FALSE otherwise.
   */
01377   public boolean hasUnreservedMethodAssertion(List list, boolean any) {
    boolean hasIt = false;
    for (Iterator iter = list.iterator(); iter.hasNext() && !hasIt; ) {
      Assertion item = (Assertion) iter.next();
      if (item.hasUnreservedMethod(any)) {
        hasIt = true;
      }
    }
    return hasIt;
  }

  /**
   * Return TRUE if the method has any unreserved method (when any is TRUE)
   * assertion or has an unreserved method assertion with a throws clause 
   * (if any is FALSE); otherwise, return FALSE.
   */
01393   public boolean hasUnreservedMethodAssertion(boolean any) {
    boolean hasIt = hasUnreservedMethodAssertion(d_preconditions, any);
    if (!hasIt) {
      hasIt = hasUnreservedMethodAssertion(d_postconditions, any);
    }
    return hasIt;
  }

  /**
   * This returns an array list of RarrayInfo objects that contains the info
   * for every rarray index used in this method.  
   */
01405   public Map getRarrayInfo() {
    if(d_rarray_index_map == null)
      createRarrayMap();
    return protectMap(d_rarray_index_map);
  }

  private void createRarrayMap() {
    d_rarray_index_map = new HashMap();
    Iterator i = d_arguments.iterator();
    while (i.hasNext()) {
      Argument a = (Argument)i.next();
      Type argType = a.getType();
      if (argType.isRarray()) {
        Iterator j = argType.getArrayIndexExprs().iterator();
        int position = 0;
        while (j.hasNext()) {
          AssertionExpression ae = (AssertionExpression)j.next();
          Set indices = (Set)ae.accept(new RarrayIndices(), new HashSet());
          Iterator k = indices.iterator();
          while (k.hasNext()) {
            String indexName = k.next().toString();
            Set indexSet = (Set) d_rarray_index_map.get(indexName);
            if (indexSet == null) {
              indexSet = new HashSet();
              d_rarray_index_map.put(indexName, indexSet);
            }
          
            Argument index_arg = null;
            for(Iterator a1 = d_arguments.iterator(); a1.hasNext();) {
              Argument arg = (Argument) a1.next();
              if(indexName.compareTo(arg.getFormalName()) == 0) {
                index_arg = arg;
                break;
              }
            }
            indexSet.add(new RarrayInfo(a, index_arg, position));
          }
          ++position;
        }
      }
    }
  }

  public int hashCode() {
    return d_long_name.hashCode() +
      d_short_name.hashCode() +
      getCommunicationModifier() +
      d_throws.hashCode() +
      d_arguments.hashCode() +
      (isReturnCopy() ? 1 : 0);
  }

  public boolean equals(Object o) {
    if (o instanceof Method) { 
      Method m = (Method)o;
      return (getCommunicationModifier() == m.getCommunicationModifier()) &&
        (isReturnCopy() == m.isReturnCopy()) &&
        d_arguments.equals(m.d_arguments) &&
        d_return_type.equals(m.d_return_type) &&
        d_long_name.equals(m.d_long_name) &&
        d_short_name.equals(m.d_short_name) &&
        d_throws.equals(m.d_throws) &&
        d_explicit_throws.equals(m.d_explicit_throws);
    } else { 
      return false;
    }
  }

  
01474   public class RarrayInfo {
    
    public final Argument rarray;
    public final Argument index;
    public final int dim;

    public RarrayInfo(Argument r, Argument i, int d) {
      rarray = r;
      index = i;
      dim = d;
    }
    
    public int hashCode() {
      return rarray.getFormalName().hashCode() + index.getFormalName().hashCode() + dim;
    }

    public boolean equals(Object o) {
      if ( o instanceof RarrayInfo ) { 
        RarrayInfo r = (RarrayInfo)o;
        return  ( r.rarray == rarray &&
                  r.index == index &&
                  r.dim == dim);
      } else { 
        return false;
      }
    }
  }

  public boolean hasAttribute(String key)
  {
    return d_attributes.containsKey(key);
  }

  public String getAttribute(String key)
  {
    if (hasAttribute(key)) {
      return (String)d_attributes.get(key);
    }
    throw new UnknownAttributeException("Method does not have attribute " + key);
  }

  public void setAttribute(String key)
  {
    checkFrozen();
    setAttribute(key, null);
  }

  public void setAttribute(String key, String value)
  {
    checkFrozen();
    d_attributes.put(key, value);
  }
  
  public void removeAttribute(String key) throws UnknownAttributeException
  {
    checkFrozen();
    if (hasAttribute(key)) {
      d_attributes.remove(key);
    }
    else {
      throw new UnknownAttributeException("Method does not have attribute " + key);
    }
  }
  
  public Set getAttributes()
  {
    return protectSet(d_attributes.keySet());
  }

01543   public Metadata getMetadata() {
    return d_metadata;
  }

01547   public void addMetadata(String keyword, String value)
  {
    checkFrozen();
    d_metadata.addMetadata(keyword, value);
  }

   /**
    * Add the specified contents to the splicer block identified by the
    * location and name.
    */
01557   public void addSplicerContents(String location, String name, String impl) {
    checkFrozen();
    if (d_splicers == null) {
      d_splicers = new SplicerList();
    }
    d_splicers.addSplicerContents(location, name, impl);
  }

  /**
   * Return splicer blocks for the specified location.
   */
01568   public ArrayList getSplicerBlocks(String location) {
    return (d_splicers != null) ? d_splicers.getSplicerBlocks(location) : null;
  }

  /**
   * Return splicer contents for the specified location and splicer name.
   */
01575   public ArrayList getSplicerContents(String location, String name) {
    return (d_splicers != null) ? d_splicers.getSplicerContents(location, name) 
                                : null;
  }

  public void freeze()
  {
    if (!d_frozen) {
      super.freeze();
      if (d_comment != null) d_comment.freeze();
      if (d_return_type != null) d_return_type.freeze();
      Iterator i = d_references.iterator();
      while (i.hasNext()) {
        SymbolID id = (SymbolID)i.next();
        id.freeze();
      }
      i = d_arguments.iterator();
      while (i.hasNext()) {
        Argument arg = (Argument)i.next();
        arg.freeze();
      }
      i = d_throws.iterator();
      while (i.hasNext()) {
        SymbolID id = (SymbolID)i.next();
        id.freeze();
      }
      d_attributes = protectMap(d_attributes);
      d_arguments = protectList(d_arguments);
      d_references = protectSet(d_references);
      d_references_no_exceptions = protectSet(d_references_no_exceptions);
      d_basicarrays = protectSet(d_basicarrays);
      d_throws = protectSet(d_throws);
      d_explicit_throws = protectSet(d_explicit_throws);
      d_preconditions = protectList(d_preconditions);
      d_postconditions = protectList(d_postconditions);
      d_rarray_indices = protectSet(d_rarray_indices);
      d_rarray_index_map = protectMap(d_rarray_index_map);
    }
  }
}

Generated by  Doxygen 1.6.0   Back to index