/*
* Copyright (c) 2011, IETR/INSA of Rennes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.ir.util;
import static java.math.BigInteger.ONE;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import net.sf.orcc.OrccRuntimeException;
import net.sf.orcc.ir.ExprBool;
import net.sf.orcc.ir.ExprFloat;
import net.sf.orcc.ir.ExprInt;
import net.sf.orcc.ir.ExprList;
import net.sf.orcc.ir.ExprString;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.IrFactory;
import net.sf.orcc.ir.OpBinary;
import net.sf.orcc.ir.OpUnary;
import net.sf.orcc.ir.Type;
import net.sf.orcc.ir.TypeList;
/**
* This class defines many static utility methods to deal with values.
*
* @author Matthieu Wipliez
*
*/
public class ValueUtil {
/**
* Returns a new integer equal to the sum of the two operands, or
* <code>null</code> if the two operands are not both floats or integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object add(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).add((BigDecimal) val2);
} else if (isFloat(val1) && isInt(val2)) {
return ((BigDecimal) val1).add(new BigDecimal((BigInteger) val2));
} else if (isInt(val1) && isFloat(val2)) {
return new BigDecimal((BigInteger) val1).add((BigDecimal) val2);
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).add((BigInteger) val2);
} else if (isString(val1) || isString(val2)) {
return val1.toString() + val2.toString();
}
throw new OrccRuntimeException("type mismatch in add");
}
/**
* Returns a new integer equal to the bitwise and of the two operands, or
* <code>null</code> if the two operands are not both integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object and(Object val1, Object val2) {
if (isBool(val1) && isBool(val2)) {
return ((Boolean) val1) & ((Boolean) val2);
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).and((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in and");
}
/**
* Returns the value of <code>val1</code> <code>op</code> <code>val2</code>.
* Returns <code>null</code> if the value of the expression cannot be
* computed.
*
* @param val1
* an expression
* @param op
* a binary operator
* @param val2
* another expression
* @return the value of <code>val1</code> <code>op</code> <code>val2</code>
*/
public static Object compute(Object val1, OpBinary op, Object val2) {
switch (op) {
case BITAND:
return ValueUtil.and(val1, val2);
case BITOR:
return ValueUtil.or(val1, val2);
case BITXOR:
return ValueUtil.xor(val1, val2);
case DIV:
return ValueUtil.divide(val1, val2);
case DIV_INT:
return ValueUtil.divide(val1, val2);
case EQ:
return ValueUtil.equals(val1, val2);
case EXP:
return ValueUtil.pow(val1, val2);
case GE:
return ValueUtil.ge(val1, val2);
case GT:
return ValueUtil.gt(val1, val2);
case LOGIC_AND:
return ValueUtil.logicAnd(val1, val2);
case LE:
return ValueUtil.le(val1, val2);
case LOGIC_OR:
return ValueUtil.logicOr(val1, val2);
case LT:
return ValueUtil.lt(val1, val2);
case MINUS:
return ValueUtil.subtract(val1, val2);
case MOD:
return ValueUtil.mod(val1, val2);
case NE:
return ValueUtil.notEquals(val1, val2);
case PLUS:
return ValueUtil.add(val1, val2);
case SHIFT_LEFT:
return ValueUtil.shiftLeft(val1, val2);
case SHIFT_RIGHT:
return ValueUtil.shiftRight(val1, val2);
case TIMES:
return ValueUtil.multiply(val1, val2);
default:
return null;
}
}
/**
* Returns the value of <code>op</code> <code>value</code>. Returns
* <code>null</code> if the value of the expression cannot be computed.
*
* @param op
* a unary operator
* @param value
* an expression
* @return the value of <code>op</code> <code>value</code>
*/
public static Object compute(OpUnary op, Object value) {
switch (op) {
case BITNOT:
return ValueUtil.not(value);
case LOGIC_NOT:
return ValueUtil.logicNot(value);
case MINUS:
return ValueUtil.negate(value);
case NUM_ELTS:
return ValueUtil.length(value);
default:
return null;
}
}
/**
* Creates a new array whose elements have the given type, and with the
* given number of dimensions.
*
* @param type
* type of elements
* @param dimensions
* number of elements for each dimension
* @return an array
*/
public static Object createArray(Type type, int... dimensions) {
if (type.isBool()) {
return Array.newInstance(Boolean.TYPE, dimensions);
} else if (type.isFloat()) {
return Array.newInstance(Float.TYPE, dimensions);
} else if (type.isInt() || type.isUint()) {
int size = type.getSizeInBits();
if (size <= 8) {
return Array.newInstance(Byte.TYPE, dimensions);
} else if (size <= 16) {
return Array.newInstance(Short.TYPE, dimensions);
} else if (size <= 32) {
return Array.newInstance(Integer.TYPE, dimensions);
} else if (size <= 64) {
return Array.newInstance(Long.TYPE, dimensions);
} else {
return Array.newInstance(BigInteger.class, dimensions);
}
} else if (type.isString()) {
return Array.newInstance(String.class, dimensions);
} else {
throw new IllegalArgumentException("expected scalar type");
}
}
/**
* Creates a new array that matches the given type.
*
* @param type
* a type of list
* @return an array
*/
public static Object createArray(TypeList type) {
List<Integer> listDimensions = type.getDimensions();
int[] dimensions = new int[listDimensions.size()];
for (int i = 0; i < dimensions.length; i++) {
dimensions[i] = listDimensions.get(i);
}
Type eltType = type.getInnermostType();
return createArray(eltType, dimensions);
}
/**
* Returns a new integer equal to the division of the two operands, or
* <code>null</code> if the two operands are not both floats or integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object divide(Object val1, Object val2) {
if (isFloat(val1)) {
double doubleVal1 = ((BigDecimal) val1).doubleValue();
if (isFloat(val2)) {
return new BigDecimal(doubleVal1
/ ((BigDecimal) val2).doubleValue());
} else if (isInt(val2)) {
return new BigDecimal(doubleVal1
/ ((BigInteger) val2).intValue());
}
}
if (isFloat(val2)) {
double doubleVal2 = ((BigDecimal) val2).doubleValue();
if (isFloat(val1)) {
return new BigDecimal(((BigDecimal) val1).doubleValue()
/ doubleVal2);
} else if (isInt(val1)) {
return new BigDecimal(((BigInteger) val1).intValue()
/ doubleVal2);
}
}
if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).divide((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in divide");
}
/**
* If the two operands have the same type, returns a new boolean that is the
* result of their comparison; if they do not have the same type, returns
* <code>null</code>.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean or <code>null</code> in case of type mismatch
*/
public static Object equals(Object val1, Object val2) {
if (isBool(val1) && isBool(val2) || isFloat(val1) && isFloat(val2)
|| isInt(val1) && isInt(val2) || isString(val1)
&& isString(val2)) {
return val1.equals(val2);
} else if (isString(val1) && isInt(val2) || isInt(val1)
&& isString(val2)) {
if (getIntValue(val1) == getIntValue(val2)) {
return true;
} else {
return false;
}
}
throw new OrccRuntimeException("type mismatch in equals");
}
/**
* Returns a new boolean that is <code>true</code> if val1 is greater than
* or equal to val2, or <code>null</code> if the two operands are not both
* of the same type.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean value or <code>null</code>
*/
public static Object ge(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).compareTo((BigDecimal) val2) >= 0;
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).compareTo((BigInteger) val2) >= 0;
}
throw new OrccRuntimeException("type mismatch in ge");
}
/**
* Returns the value in the given array, at the given indexes, knowing the
* type of the elements of the array.
*
* @param type
* @param array
* @param indexes
* @return
*/
public static Object get(Type type, Object array, Object... indexes) {
if (array == null) {
return null;
}
int numIndexes = indexes.length;
for (int i = 0; i < numIndexes - 1; i++) {
int index = getIntValue(indexes[i]);
array = Array.get(array, index);
}
int index = getIntValue(indexes[numIndexes - 1]);
Object value = Array.get(array, index);
if (type.isBool() && isBool(value) || type.isString()
&& isString(value)) {
return value;
} else if (type.isFloat()) {
return BigDecimal.valueOf((Float) value);
} else if (type.isInt()) {
int size = type.getSizeInBits();
long longVal;
if (size <= 8) {
longVal = (Byte) value;
} else if (size <= 16) {
longVal = (Short) value;
} else if (size <= 32) {
longVal = (Integer) value;
} else if (size <= 64) {
longVal = (Long) value;
} else {
return value;
}
return BigInteger.valueOf(longVal);
} else if (type.isUint()) {
int size = type.getSizeInBits();
long longVal;
if (size <= 8) {
longVal = ((Byte) value) & 0xFF;
} else if (size <= 16) {
longVal = ((Short) value) & 0xFFFF;
} else if (size <= 32) {
longVal = ((Integer) value) & 0xFFFFFFFFL;
} else if (size <= 64) {
BigInteger bigInt = BigInteger.valueOf((Long) value);
return bigInt.and(ONE.shiftLeft(64).subtract(ONE));
} else {
return value;
}
return BigInteger.valueOf(longVal);
}
throw new OrccRuntimeException("unexpected type in set");
}
/**
* Returns the IR Expression that matches the given runtime value. Value is
* expected to be one of Boolean, BigDecimal, BigInteger, String, or Array.
*
* @param value
* a runtime value
* @return an IR expression
*/
public static Expression getExpression(Object value) {
if (isBool(value)) {
return IrFactory.eINSTANCE.createExprBool((Boolean) value);
} else if (isFloat(value)) {
return IrFactory.eINSTANCE.createExprFloat((BigDecimal) value);
} else if (isInt(value)) {
return IrFactory.eINSTANCE.createExprInt((BigInteger) value);
} else if (isString(value)) {
return IrFactory.eINSTANCE.createExprString((String) value);
} else if (isList(value)) {
ExprList list = IrFactory.eINSTANCE.createExprList();
int length = Array.getLength(value);
for (int i = 0; i < length; i++) {
list.getValue().add(getExpression(Array.get(value, i)));
}
return list;
} else {
return null;
}
}
private static int getIntValue(Object value) {
if (value instanceof Integer) {
return (Integer) value;
} else if (isInt(value)) {
return ((BigInteger) value).intValue();
} else if (isString(value)) {
return (Integer.parseInt((String) value));
}
throw new OrccRuntimeException("type mismatch in getIntValue");
}
/**
* Returns the IR Type of the given runtime value. Value is expected to be
* one of Boolean, BigDecimal, BigInteger, String, or Array.
*
* @param value
* a runtime value
* @return an IR type
*/
public static Type getType(Object value) {
if (isBool(value)) {
return IrFactory.eINSTANCE.createTypeBool();
} else if (isFloat(value)) {
return IrFactory.eINSTANCE.createTypeFloat();
} else if (isInt(value)) {
return IrFactory.eINSTANCE.createTypeIntOrUint((BigInteger) value);
} else if (isString(value)) {
return IrFactory.eINSTANCE.createTypeString();
} else if (isList(value)) {
int size = Array.getLength(value);
Type type = null;
if (size > 0) {
type = getType(Array.get(value, 0));
for (int i = 0; i < size; i++) {
Type t2 = getType(Array.get(value, i));
type = TypeUtil.getLub(type, t2);
}
}
return IrFactory.eINSTANCE.createTypeList(size, type);
} else {
return null;
}
}
/**
* Returns the value of the given expression.
*
* @param expr
* an expression
* @return the value of the given expression
*/
public static Object getValue(Expression expr) {
if (expr != null) {
if (expr.isExprBool()) {
return ((ExprBool) expr).isValue();
} else if (expr.isExprFloat()) {
return ((ExprFloat) expr).getValue();
} else if (expr.isExprInt()) {
return ((ExprInt) expr).getValue();
} else if (expr.isExprString()) {
return ((ExprString) expr).getValue();
} else if (expr.isExprList()) {
throw new OrccRuntimeException(
"list type not supported yet in getValue");
}
}
return null;
}
/**
* Returns a new boolean that is <code>true</code> if val1 is greater than
* val2, or <code>null</code> if the two operands are not both of the same
* type.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean value or <code>null</code>
*/
public static Object gt(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).compareTo((BigDecimal) val2) > 0;
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).compareTo((BigInteger) val2) > 0;
}
throw new OrccRuntimeException("type mismatch in gt");
}
/**
* Returns <code>true</code> if value is a boolean.
*
* @param value
* a value
* @return <code>true</code> if value is a boolean
*/
public static boolean isBool(Object value) {
return value instanceof Boolean;
}
/**
* Returns <code>true</code> if value is a float.
*
* @param value
* a value
* @return <code>true</code> if value is a float
*/
public static boolean isFloat(Object value) {
return value instanceof BigDecimal;
}
/**
* Returns <code>true</code> if value is an integer.
*
* @param value
* a value
* @return <code>true</code> if value is an integer
*/
public static boolean isInt(Object value) {
return value instanceof BigInteger;
}
/**
* Returns <code>true</code> if value is a list.
*
* @param value
* a value
* @return <code>true</code> if value is a list
*/
public static boolean isList(Object value) {
return (value != null && value.getClass().isArray());
}
/**
* Returns <code>true</code> if the given expression is a power of two.
*
* @param expr
* an expression
* @return true if the expression is a power of two
*/
public static boolean isPowerOfTwo(Expression expr) {
int n;
try {
n = new ExpressionEvaluator().evaluateAsInteger(expr);
} catch (Exception e) {
return false;
}
return isPowerOfTwo(n);
}
/**
* Returns <code>true</code> if the given integer is a power of two.
*
* @param n
* an integer
* @return <code>true</code> if the given integer is a power of two
*/
public static boolean isPowerOfTwo(int n) {
return (n > 0) && (n & (n - 1)) == 0;
}
/**
* Returns <code>true</code> if value is a String.
*
* @param value
* a value
* @return <code>true</code> if value is a String
*/
public static boolean isString(Object value) {
return value instanceof String;
}
/**
* Returns <code>true</code> if value is a boolean and is <code>true</code>
*
* @param value
* a value
* @return <code>true</code> if value is a boolean and is <code>true</code>
*/
public static boolean isTrue(Object value) {
return isBool(value) && (Boolean) value;
}
/**
* Returns a new boolean that is <code>true</code> if val1 is less than or
* equal to val2, or <code>null</code> if the two operands are not both of
* the same type.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean value or <code>null</code>
*/
public static Object le(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).compareTo((BigDecimal) val2) <= 0;
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).compareTo((BigInteger) val2) <= 0;
}
throw new OrccRuntimeException("type mismatch in le");
}
/**
* If value is an array, returns its number of elements.
*
* @param value
* @return
*/
public static int length(Object value) {
if (isList(value)) {
return Array.getLength(value);
}
return 0;
}
/**
* Returns a new boolean that is <code>true</code> if both val1 and val2 are
* true, or <code>null</code> if the two operands are not both of the same
* type.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean value or <code>null</code>
*/
public static Object logicAnd(Object val1, Object val2) {
if (isBool(val1) && isBool(val2)) {
return ((Boolean) val1) && ((Boolean) val2);
}
throw new OrccRuntimeException("type mismatch in logicAnd");
}
/**
* Returns a new boolean that is <code>!value</code> if value is a boolean,
* or <code>null</code> otherwise
*
* @param value
* an object
* @return a boolean value or <code>null</code>
*/
public static Object logicNot(Object value) {
if (isBool(value)) {
return !((Boolean) value);
}
throw new OrccRuntimeException("type mismatch in logicNot");
}
/**
* Returns a new boolean that is <code>true</code> if either val1 or val2 is
* true, or <code>null</code> if the two operands are not both of the same
* type.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean value or <code>null</code>
*/
public static Object logicOr(Object val1, Object val2) {
if (isBool(val1) && isBool(val2)) {
return ((Boolean) val1) || ((Boolean) val2);
}
throw new OrccRuntimeException("type mismatch in logicOr");
}
/**
* Returns a new boolean that is <code>true</code> if val1 is less than
* val2, or <code>null</code> if the two operands are not both of the same
* type.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean value or <code>null</code>
*/
public static Object lt(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).compareTo((BigDecimal) val2) < 0;
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).compareTo((BigInteger) val2) < 0;
}
throw new OrccRuntimeException("type mismatch in lt");
}
/**
* Returns a new integer equal to the modulo of the two operands, or
* <code>null</code> if the two operands are not both integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object mod(Object val1, Object val2) {
if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).mod((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in mod");
}
/**
* Returns a new integer equal to the product of the two operands, or
* <code>null</code> if the two operands are not both floats or integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object multiply(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).multiply((BigDecimal) val2);
} else if (isFloat(val1) && isInt(val2)) {
return ((BigDecimal) val1).multiply(new BigDecimal(
(BigInteger) val2));
} else if (isInt(val1) && isFloat(val2)) {
return new BigDecimal((BigInteger) val1)
.multiply((BigDecimal) val2);
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).multiply((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in multiply");
}
/**
* Returns a new integer equal to <code>-value</code>, or <code>null</code>
* if value is not a float or an integer.
*
* @param value
* an object
* @return a float or integer value or <code>null</code>
*/
public static Object negate(Object value) {
if (isFloat(value)) {
return ((BigDecimal) value).negate();
} else if (isInt(value)) {
return ((BigInteger) value).negate();
}
throw new OrccRuntimeException("type mismatch in negate");
}
/**
* Returns a new integer equal to <code>~value</code>, or <code>null</code>
* if value is not an integer.
*
* @param value
* an object
* @return an integer value or <code>null</code>
*/
public static Object not(Object value) {
if (isInt(value)) {
return ((BigInteger) value).not();
}
throw new OrccRuntimeException("type mismatch in not");
}
/**
* If the two operands have the same type, returns a new boolean that is the
* result of their comparison; if they do not have the same type, returns
* <code>null</code>.
*
* @param val1
* an object
* @param val2
* an object
* @return a boolean or <code>null</code> in case of type mismatch
*/
public static Object notEquals(Object val1, Object val2) {
Object result = equals(val1, val2);
if (isBool(result)) {
return !((Boolean) result);
}
throw new OrccRuntimeException("type mismatch in notEquals");
}
/**
* Returns a new integer equal to the bitwise or of the two operands, or
* <code>null</code> if the two operands are not both integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object or(Object val1, Object val2) {
if (isBool(val1) && isBool(val2)) {
return ((Boolean) val1) | ((Boolean) val2);
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).or((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in or");
}
/**
* Returns a new integer equal to the first operand left shifted by the
* right operand, or <code>null</code> if the two operands are not both
* integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object pow(Object val1, Object val2) {
if (isInt(val1) && isInt(val2)) {
int exponent = ((BigInteger) val2).intValue();
return ((BigInteger) val1).pow(exponent);
}
throw new OrccRuntimeException("type mismatch in pow");
}
/**
* Writes the given value in the given array at the given indexes.
*
* @param type
* type of the innermost elements of the array.
* @param array
* an array object
* @param value
* a value
* @param indexes
* indexes
*/
public static void set(Type type, Object array, Object value,
Object... indexes) {
if (array == null || value == null) {
return;
}
int numIndexes = indexes.length;
for (int i = 0; i < numIndexes - 1; i++) {
int index = getIntValue(indexes[i]);
array = Array.get(array, index);
}
int index = getIntValue(indexes[numIndexes - 1]);
Object valueToSet;
if (type.isBool() && isBool(value) || type.isString()
&& isString(value)) {
valueToSet = value;
} else if (type.isFloat() && isFloat(value)) {
BigDecimal floatVal = (BigDecimal) value;
valueToSet = floatVal.floatValue();
} else if ((type.isInt() || type.isUint()) && isInt(value)) {
BigInteger intVal = (BigInteger) value;
int size = type.getSizeInBits();
if (size <= 8) {
valueToSet = intVal.byteValue();
} else if (size <= 16) {
valueToSet = intVal.shortValue();
} else if (size <= 32) {
valueToSet = intVal.intValue();
} else if (size <= 64) {
valueToSet = intVal.longValue();
} else {
valueToSet = value;
}
} else {
throw new OrccRuntimeException("unexpected type in set");
}
Array.set(array, index, valueToSet);
}
/**
* Returns a new integer equal to the first operand left shifted by the
* right operand, or <code>null</code> if the two operands are not both
* integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object shiftLeft(Object val1, Object val2) {
if (isInt(val1) && isInt(val2)) {
int n = ((BigInteger) val2).intValue();
return ((BigInteger) val1).shiftLeft(n);
}
throw new OrccRuntimeException("type mismatch in shiftLeft");
}
/**
* Returns a new integer equal to the first operand right shifted by the
* right operand, or <code>null</code> if the two operands are not both
* integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object shiftRight(Object val1, Object val2) {
if (isInt(val1) && isInt(val2)) {
int n = ((BigInteger) val2).intValue();
return ((BigInteger) val1).shiftRight(n);
}
throw new OrccRuntimeException("type mismatch in shiftRight");
}
/**
* Returns a new integer equal to the difference of the two operands, or
* <code>null</code> if the two operands are not both floats or integers.
*
* @param val1
* an object
* @param val2
* an object
* @return a float or integer value or <code>null</code>
*/
public static Object subtract(Object val1, Object val2) {
if (isFloat(val1) && isFloat(val2)) {
return ((BigDecimal) val1).subtract((BigDecimal) val2);
} else if (isFloat(val1) && isInt(val2)) {
return ((BigDecimal) val1).subtract(new BigDecimal(
(BigInteger) val2));
} else if (isInt(val1) && isFloat(val2)) {
return new BigDecimal((BigInteger) val1)
.subtract((BigDecimal) val2);
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).subtract((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in subtract");
}
/**
* Returns a new integer equal to the bitwise xor of the two operands, or
* <code>null</code> if the two operands are not both integers.
*
* @param val1
* an object
* @param val2
* an object
* @return an integer value or <code>null</code>
*/
public static Object xor(Object val1, Object val2) {
if (isBool(val1) && isBool(val2)) {
return ((Boolean) val1) ^ ((Boolean) val2);
} else if (isInt(val1) && isInt(val2)) {
return ((BigInteger) val1).xor((BigInteger) val2);
}
throw new OrccRuntimeException("type mismatch in xor");
}
}