gnu.jel.OPunary Maven / Gradle / Ivy
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* $Id: OPunary.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 unary operation.
*/
public class OPunary extends OP {
/** code of this operation */
public int code;
private int uwrpCode=0; // what to code to unwrap the object
private int implCode=0;
private int uwrpsTo=-1;
// The full list of codes is :
// 0 -- negation (applicable to anything except boolean)
// 1 -- bitwise not (applicable to all integral types)
// 2 -- logical not (applicable to booleans only)
// 3 -- return
// 4 -- convert to boolean
// 5 -- convert to byte
// 6 -- convert to char
// 7 -- convert to short
// 8 -- convert to int
// 9 -- convert to long
// 10 -- convert to float
// 11 -- convert to double
// 12 -- convert to object (in this case the cls parameter gives class)
// 13 -- convert to void (throw from stack)
// 14 -- convert string to temporary string buffer (TSB)
// 15 -- convert temporary string buffer (TSB) to string
/** unary promotions of base types */
protected final static byte[] unary_prmtns;
private final static int[][] una;
private final static String[] opNames;
static {
unary_prmtns=(byte[])TableKeeper.getTable("unary_prmtns");
una=(int[][])TableKeeper.getTable("una");
opNames=(String[])TableKeeper.getTable("opNames");
if (Debug.enabled)
Debug.check((opNames.length==una.length));
};
/**
* Constructs a new unary operation.
* Codes are following:
*
* 0 -- negation (applicable to anything except boolean)
* 1 -- bitwise not (applicable to all integral types)
* 2 -- logical not (applicable to booleans only)
* 3 -- return the type in stack
*
* @param paramOPs stack holding the operands
* @param code operation code
*/
public OPunary(Stack paramOPs, int code)
throws CompilationException {
if (Debug.enabled)
Debug.check((code>=0) && (code<=3));
this.code=code;
chi=new OP[1];
chi[0]=(OP)paramOPs.pop();
int opID=chi[0].resID;
Class opType=chi[0].resType;
if (code==3) { // return
// everything can be returned no checks/unwraps needed
resID=(opID>9?8:opID); // computes base type
resType=opType;
implCode=una[code][resID];
} else {
// unwrap object if can
int unwrpID=unwrapType[opID];
if (unwrpID!=opID) {
uwrpCode=((opID-12+11)<<8)+0x00FE;
uwrpsTo=unwrpID;
};
if ((implCode=una[code][unwrpID])==0xFF) {
// operation is not defined on types
Object[] paramsExc={opNames[code],opType};
throw new CompilationException(28,paramsExc);
};
resID=unary_prmtns[unwrpID];
resType=specialTypes[resID];
};
};
/**
* Creates conversion operation to the given class.
* @param paramOPs stack holding the operands
* @param targetID ID of primitive type to convert to.
* @param targetClass the class to convert to, in case cldID=8
* @param allownarrowing if narrowing conversions are allowed.
*/
public OPunary(Stack paramOPs, int targetID, Class targetClass,
boolean allownarrowing) throws CompilationException {
if (Debug.enabled) {
// check for proper target type was identification
Debug.check(((targetID==8)^(targetClass==null)) ||
((targetID!=8)&&
(specialTypes[targetID].isAssignableFrom(targetClass)))
);
if (targetID==8) {
Debug.check(typeID(targetClass)==targetID,
"The type was improperly identified for OPunary conv.");
};
};
// set the result type
resID=targetID;
resType=(targetClass!=null?targetClass:specialTypes[targetID]);
chi=new OP[1];
chi[0]=(OP)paramOPs.pop();
Class currClass=chi[0].resType;
int currID=chi[0].resID;
int unwrappedCurrID=unwrapType[currID];
// there are folowing cases:
// unwrappable object to primitive
// string-like to string
// string or string-like to TSB
// TSB to string
// primitive to primitive
// object to object
// error (object -> primitive, primitive->object)
code=4+resID;
if ((resID>=8) && (resID!=10) && (currID!=10) &&
(!((currID==28) && ((resID==10) || (resID==11))))) {
// object to object
code=4+8;
unwrappedCurrID=8;
} else {
// unwrappable object to primitive
// string or string-like to TSB
// TSB to string
// primitive to primitive
if (unwrappedCurrID!=currID) {
uwrpCode=((currID-12+11)<<8)+0x00FE;
uwrpsTo=unwrappedCurrID;
};
};
if ((implCode=una[code][unwrappedCurrID])==0xFF) {
//Debug.println("code="+code);
// can't convert at all
Object[] paramsExc={currClass,resType};
throw new CompilationException(21,paramsExc);
};
if (!(allownarrowing ||
isWidening(currID,currClass,resID,resType))) {
// can't do narrowing conversions automatically
Object[] paramsExc={currClass,resType};
throw new CompilationException(22,paramsExc);
};
};
public void compile(ClassFile cf) {
if (code==2) cf.code(0xFB); // equivalent to cf.labels_block();
if (code==14) {
cf.code(0x0001FE591DFDBBL); // ANY => TSB
// | new
//
// | dup
// | invokespecial StringBuffer()
cf.noteStk(-1,10); // pushes ref to TSB
};
chi[0].compile(cf);
cf.code(uwrpCode); // unwrap object if needed
if (uwrpsTo>=0)
cf.noteStk(chi[0].resID,uwrpsTo); // note the unwrapping on stack
cf.code(implCode);
if (code==12) // code CP index for conversion to reference
cf.writeShort(cf.getIndex(resType,9));
// get rid of this switch is the task for the NEXT major update
switch(code) {
case 2: // logical inversion does not change stack
case 4: // conversion to boolean does not change stack as well
// if it was a jump, jump is preserved
break;
case 3:
case 13:
cf.noteStk(resID,-1); // return and (void) throw one word, add nothing
break;
case 14:
cf.noteStk(11,-1);
break;
case 1: // bitwise not may have excess item on stack
cf.noteStk(-1,resID);
cf.noteStk(resID,-1);
default: // other ops throw one word replace it by another
cf.noteStk(uwrpsTo>=0?uwrpsTo:chi[0].resID,resID);
};
};
public Object eval() throws Exception {
Object operand=chi[0].eval();
int operand_resID=chi[0].resID;
if ((code==3) ||
(code==13) ||
(code==12)) { // do not evaluate, just replace operand
chi[0]=new OPload(chi[0],operand);
throw new Exception(); // bail out
};
if (code==2) { // logical not
if (((Boolean)operand).booleanValue())
operand=Boolean.FALSE;
else
operand=Boolean.TRUE;
} else if (code<2) {
Number val=widen(operand,operand_resID);
switch(code) {
case 0: // negation
if (operand_resID>5)
val=new Double(-val.doubleValue());
else
val=new Long(-val.longValue());
break;
case 1: // bitwise complement
val=new Long(~val.longValue());
break;
default:
if (Debug.enabled)
Debug.check(code>=0,"Wrong unary opcode.");
};
operand=narrow(val,resID);
} else {
// conversion operations
if (code==14) { // ANY->TSB
operand=new StringBuffer(String.valueOf(operand));
} else if (code==15) { // TSB->STR
operand=operand.toString();
} else {
operand=narrow(widen(operand,operand_resID),resID);
};
};
return operand;
};
};
© 2015 - 2024 Weber Informatics LLC | Privacy Policy