/*
 * $Id: CompiledExpression.java,v 1.5 2000/02/11 22:08:18 metlov Exp $
 *
 * This file is part of the Java Expressions Library (JEL).
 *   For more information about JEL visit :
 *    http://galaxy.fzu.cz/JEL/
 *
 * (c) 1998 -- 2000 by Konstantin Metlov(metlov@fzu.cz);
 *
 * JEL is Distributed under the terms of GNU General Public License.
 *    This code comes with ABSOLUTELY NO WARRANTY.
 *  For license details see COPYING file in this directory.
 */

package gnu.jel;

import gnu.jel.debug.Debug;

/**
 * The superclass of every compiled expression.
 * <P>You can not get the instance of this class (because it is abstract) 
 * but every JEL compiled expression is subclass of it. Some functions in
 * this class are overridden by the result of compilation.
 * <P> Most methods of this class accept a reference to the array of objects. 
 * This reference is the pointer to the dynamic object library. As You, 
 * probably, read : JEL allows to call virtual methods of Java classes. But,
 * virtual methods require the reference to the object (<TT>this</TT>) to be
 * passed along with parameters. That is, the array <TT>dl</TT> (dynamic 
 * library) should contain references to objects of all classes, whose 
 * virtual methods were put into the Library of callable functions. The objects
 * in the <TT>dl</TT> array should be instances of corresponding classes
 * in the array,
 * passed as a second argument of <TT>gnu.jel.Library</TT> constructor.
 *  <P> There are two ways of evaluation of compiled expressions. These methods
 * vary in the performance achieved.
 * <P> The <I>first method</I> (simplest one) is based on the call to the
 * <TT> evaluate</TT> method, which will
 * return an object even if the result of computation was the primitive type.
 * The primitive types will be converted to the corresponding reflection 
 * objects. There is certain overhead, associated with object creation, it 
 * takes CPU cycles and also produces load on the garbage collector later..
 * <P>For massive (thousand times) evaluations of functions, producing 
 * results of primitive Java types , the <I>second 
 * method</I> can be more suitable. It is based on : first, determining the 
 * type of the result, and, then, subsequent call to the
 * <U>proper</U> evaluateXXX method.
 * <P> The type of the resulting expression can be determined by call to the
 * getType() method. It will return an integer number, indentifying the type,
 * <U>proper</U> method can be determined, based on the following table:
 * <PRE>
 * getType()   |  method to call
 * ------------+----------------------
 * 0           | evaluate_boolean(...)
 * 1           | evaluate_byte(...)
 * 2           | evaluate_char(...)
 * 3           | evaluate_short(...)
 * 4           | evaluate_int(...)
 * 5           | evaluate_long(...)
 * 6           | evaluate_float(...)
 * 7           | evaluate_double(...)
 * &gt;7          | evaluate()         <- means result is Object or void (null)
 * -----------------------------------
 * </PRE>
 * <P> Note: If You call wrong evaluateXXX() method -- zero
 * will be returned, and warning will be printed to stderr (in debug version 
 * of JEL only).
 * <P> There is the possibility to enforce resulting type of the expression at
 * compile time. Use it to avoid unnecesary type checks.
 * @see gnu.jel.Library
 */
public abstract class CompiledExpression {
  
  /**
   * Returns type of the expression result.
   * <P> The type is encoded in integer. Following table could help
   * in determining what it is :
   * getType()   |  method to call
   * ------------+-----------------
   * 0           | boolean
   * 1           | byte
   * 2           | char
   * 3           | short
   * 4           | int
   * 5           | long
   * 6           | float
   * 7           | double
   * 8           | Object
   * 9           | void
   * </PRE>
   * <P> The reason not to introduce the family of, say, TYPE_XXX constants
   * is to save space... well there are many things connected with these
   * particular numbers in codegenerator that it could be a pain to change 
   * the meaning of those numbers. This is not needed also because these 
   * are ALL Java 1.X primitive types.
   * @return the type of the expression, encoded in integer.
   */
  public abstract int getType();
  
  /**
   * Evaluates the expression, representing result as an object.
   * <P> If the result of evaluation is Java primitive type it gets wrapped
   * into corresponding reflection object , i.e. 
   * <TT>int</TT> -> <TT>java.lang.Integer</TT>,
   * <TT>boolean</TT> -> <TT>java.lang.Boolean</TT>,...
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public Object evaluate(Object[] dl) throws Throwable {
    int type=getType();
    Object res=null;
    switch (type) {
    case 0: res=new Boolean(evaluate_boolean(dl)); break;
    case 1: res=new Byte(evaluate_byte(dl)); break;
    case 2: res=new Character(evaluate_char(dl)); break;
    case 3: res=new Short(evaluate_short(dl)); break;
    case 4: res=new Integer(evaluate_int(dl)); break;
    case 5: res=new Long(evaluate_long(dl)); break;
    case 6: res=new Float(evaluate_float(dl)); break;
    case 7: res=new Double(evaluate_double(dl)); break;
    default:
      if (Debug.enabled)
	Debug.assert(false,"WrongTypeReturned from "+
		     "CompiledExpression.getType().");
    };
    return res;
  };

  /**
   * Evaluates the expression whose result has type <TT>boolean</TT>.
   * <P> If the type of the result is not a <TT>boolean</TT> this function 
   * returns always <TT>false</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public boolean evaluate_boolean(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return false;
  };

  /**
   * Evaluates the expression whose result has type <TT>byte</TT>.
   * <P> If the type of the result is not a <TT>byte</TT> this function returns
   * always <TT>0</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public byte evaluate_byte(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return 0;
  };

  /**
   * Evaluates the expression whose result has type <TT>short</TT>.
   * <P>If the type of the result is not a <TT>short</TT> this function returns
   * always <TT>0</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public short evaluate_short(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return 0;
  };

  /**
   * Evaluates the expression whose result has type <TT>char</TT>.
   * <P>If the type of the result is not a <TT>char</TT> this function returns
   * always <TT>'?'</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public char evaluate_char(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return '?';
  };

  /**
   * Evaluates the expression whose result has type <TT>int</TT>.
   * <P>If the type of the result is not a <TT>int</TT> this function returns
   * always <TT>0</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public int evaluate_int(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return 0;
  };

  /**
   * Evaluates the expression whose result has type <TT>long</TT>.
   * <P>If the type of the result is not a <TT>long</TT> this function returns
   * always <TT>0</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public long evaluate_long(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return 0L;
  };

  /**
   * Evaluates the expression whose result has type <TT>float</TT>.
   * <P>If the type of the result is not a <TT>float</TT> this function returns
   * always <TT>0.0</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public float evaluate_float(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return 0.0F;
  };

  /**
   * Evaluates the expression whose result has type <TT>double</TT>.
   * <P>If the type of the result is not a <TT>double</TT> this function 
   * returns always <TT>0.0</TT>, debug version will print warning to stderr.
   * @param dl Array of the instance references to the objects in dynamic
   *  library. See description of this class above for more details.
   * @return the result fo computation.
   * @exception Throwable if any runtime error have occured (i.e. division
   *          by 0)
   * @see gnu.jel.Evaluator#compile
   * @see gnu.jel.Library
   */
  public double evaluate_double(Object[] dl) throws Throwable {
    if (Debug.enabled)
      Debug.println("Wrong evaluateXXXX() method called,"+
		    " check value of getType().");
    return 0.0D;
  };

};






