All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gnu.jel.OPunary Maven / Gradle / Ivy

There is a newer version: 0.8.1
Show newest version
/* -*- 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