gnu.jel.OP Maven / Gradle / Ivy
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* $Id: OP.java 490 2006-10-01 16:08:04Z metlov $
*
* This file is part of the Java Expressions Library (JEL).
* For more information about JEL visit :
* http://kinetic.ac.donetsk.ua/JEL/
*
* (c) 1998 -- 2007 by Konstantin Metlov([email protected]);
*
* 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;
import java.util.Stack;
/**
* A tree node, representing an operation.
*/
public abstract class OP {
/** Holds references to children of this node */
public OP[] chi=null;
/** Holds type ID of the result of this OP */
public int resID;
/** Holds type of the result of this OP */
public Class resType;
/**
* Called to evaluate this node and all its sub-nodes.
* Upon success this node is to be replaced by the constant node
* holding the returned object.
* @return an object to which this node evaluates
* @exception if can't evaluate, in this case the sub-nodes
*/
public abstract Object eval() throws Exception;
/**
* Called to generate the code implementing this OP.
* @param cf class file with a new open method to write the code into.
*/
public abstract void compile(ClassFile cf);
//======================================================
// Utility methods for dealing with types, etc...
//======================================================
/**
* Classes of the special types by ID.
*
The frequently used types (those on which many operations are
* defined) are identified by an integer number. The advantage is
* the possibility to have almost completely table driven code generator.
*
So, the special types are only special in the fact that except
* of the reference to their class object they are also identified by an
* integer number.
*/
public final static Class[] specialTypes; // defined in gnu.jel.TablesKeeper
/**
* Unwraps the type ID.
*
That is all special types which are references are translated into 8.
*/
public final static byte[] unwrapType;
static {
specialTypes=(Class[])TableKeeper.getTable("specialTypes");
unwrapType=(byte[]) TableKeeper.getTable("unwrapType");
};
/**
* Identifies the primitive type of the given class.
* @param c class to identify.
* @return id of the corresponding primitive type.
*/
public static final int typeID(Class c) {
final int NUM_SPECIAL_PRIMITIVE_TYPES=10;
// ^^^ it is the number of primitive types out of special ones
if (c==null) return 8;
if (c.isPrimitive()) {
int i;
for(i=0;(it2 is widening.
* @param id1 type ID to convert from
* @param c1 class to convert from (used if id1==8)
* @param id2 type ID to convert to
* @param c2 class to convert to (used if id2==8)
* @return true if the given conversion is widening (can be done
* automatically)
*/
public static boolean isWidening(int id1, Class c1, int id2, Class c2) {
if ((id2<=11) && (id2!=8)) {
// converting into primitive
id1=unwrapType[id1];
if (Debug.enabled)
Debug.check(id1> id1)) >0;
};
// converting into object
if (id1>=8) {
// converting object into object
if (c1==c2) return true; // for nulls also
if (c1==null) return true; // "null" can be widened to any reference
if (c2==null) return false; // assignment to "null" is narrowing
return c2.isAssignableFrom(c1); // can assign references
};
// primitive into object is certainly not widening
return false;
};
/**
* Used to find out if the conversion t1->t2 is widening.
* @param c1 class to convert from (used if id1==8)
* @param c2 class to convert to (used if id2==8)
* @return true if the given conversion is widening (can be done
* automatically)
*/
public static boolean isWidening(Class c1, Class c2) {
return isWidening(typeID(c1),c1,typeID(c2),c2);
};
/**
* Makes widest possible representation of a value of Java primitive type.
* @param o reflection object, containing value to represent.
* @param clsID ID of a type of this reflection object (to save lookup).
* @return Number, representing the given value.
*/
protected static Number widen(Object o, int clsID) {
switch (clsID) {
case 0: // Z
if (((Boolean)o).booleanValue())
return new Long(1L);
else
return new Long(0L);
case 1: // B
return (Number)o;
case 2: // C
return new Long((long)((Character)o).charValue());
case 3: // S
case 4: // I
case 5: // J
case 6: // F
case 7: // D
return (Number)o;
default:
if (Debug.enabled)
Debug.println("Attempt to widen wrong primitive ("+clsID+").");
return new Long(0L);
}
};
/**
* Narrows the value back to desired primitiva type.
* @param val reflection object, containing value to narrow.
* @param clsID ID of a type to narrow the given object into.
* @return narrowed reflection object.
*/
protected static Object narrow(Number val, int clsID) {
switch (clsID) {
case 0: // Z
if (val.longValue()!=0) return Boolean.TRUE; else return Boolean.FALSE;
case 1: // B
return new Byte(val.byteValue());
case 2: // C
return new Character((char)val.longValue());
case 3: // S
return new Short(val.shortValue());
case 4: // I
return new Integer(val.intValue());
case 5: // J
return new Long(val.longValue());
case 6:
return new Float(val.floatValue());
case 7:
return new Double(val.doubleValue());
default:
if (Debug.enabled)
Debug.println("Attempt to narrow wrong primitive ("+clsID+").");
return null;
}
};
};