gnu.jel.OPcondtnl Maven / Gradle / Ivy
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* $Id: OPcondtnl.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 conditional.
*/
public class OPcondtnl extends OP {
/**
* Creates conditional operator.
* On entry the paramOPs should contain .
* @param paramOPs stack holding the operands
*/
public OPcondtnl(Stack paramOPs)
throws CompilationException {
chi=new OP[3];
for (int i=2;i>=0;i--)
chi[i]=(OP)paramOPs.pop();
int type2ID=chi[2].resID;
Class type2=chi[2].resType;
int type1ID=chi[1].resID;
Class type1=chi[1].resType;
int argID=chi[0].resID;
if (unwrapType[argID]!=0) // first argument must be boolean
throw new CompilationException(23,null);
if (argID!=0) { // unwrap
paramOPs.push(chi[0]);
chi[0]=new OPunary(paramOPs,0,null,false);
};
// determine the result type according to JLS 15.24
resID=-1;
if ((type1ID>=8) && (type2ID>=8)) {
// references
if (isWidening(type1ID, type1, type2ID, type2)) {
resID=type2ID;
resType=type2;
} else if (isWidening(type2ID, type2, type1ID, type1)) {
resID=type1ID;
resType=type1;
};
// otherwise both must unwrap to primitives, which is checked next
};
if (resID<0) {
// if reference conversion did not work
int type1IDunwrp;
int type2IDunwrp;
if ((resID=type1IDunwrp=unwrapType[type1ID])!=
(type2IDunwrp=unwrapType[type2ID])) {
if (((type1IDunwrp==1) && (type2IDunwrp==3)) ||
((type1IDunwrp==3) && (type2IDunwrp==1)))
resID=3;
else {
if ((type1IDunwrp>=8) || (type2IDunwrp>=8) ||
((resID=OPbinary.promotions[type1IDunwrp][type2IDunwrp])<0)) {
Object[] paramsExc={type1,type2};
throw new CompilationException(24,paramsExc);
};
};
};
resType=specialTypes[resID]; // here it's always the primitive
};
// convert types
if ((type1ID!=resID) || ((resID==8) && (type1!=null) &&
(type1!=resType))) {
paramOPs.push(chi[1]);
chi[1]=new OPunary(paramOPs,resID,resType,false);
};
if ((type2ID!=resID) || ((resID==8) && (type2!=null) &&
(type2!=resType))) {
paramOPs.push(chi[2]);
chi[2]=new OPunary(paramOPs,resID,resType,false);
};
};
public void compile(ClassFile cf) {
chi[0].compile(cf);
if (chi[1]!=null) {
// in the case condition was impossible to evaluate at compile-time
cf.code(0xE4); // start "true" branch
chi[1].compile(cf);
cf.code(0xE5); // finish "true" branch / start "false" branch
chi[2].compile(cf);
cf.code(0xE6); // finish "false" branch
};
};
public Object eval() throws Exception {
boolean cond;
try {
cond=((Boolean)chi[0].eval()).booleanValue();
} catch (Exception e) {
try {
chi[1]=new OPload(chi[1],chi[1].eval());
} catch (Exception exc) {
};
try {
chi[2]=new OPload(chi[2],chi[2].eval());
} catch (Exception exc) {
};
throw e;
};
OP rop=cond?chi[1]:chi[2];
try {
return rop.eval();
} catch (Exception e) {
// if can't eval, but know the condition
chi[0]=rop;
chi[1]=null;
chi[2]=null;
throw e;
}
};
};