| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.flex.abc.semantics; |
| |
| import org.apache.flex.abc.ABCConstants; |
| |
| import java.math.BigDecimal; |
| import java.math.MathContext; |
| |
| /** |
| * Provides helper functions for for various operations as specified by ECMA. |
| * |
| * @see <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMA 262 spec</a> |
| */ |
| public class ECMASupport |
| { |
| private static final long MASK_32_BIT_UINT = 0xffffffffL; |
| private static final double TWO_TO_THE_31ST = Math.pow(2, 31); |
| private static final double TWO_TO_THE_32ND = Math.pow(2, 32); |
| |
| /** |
| * The abstract operation ToInt32 converts its argument to one of 2^32 |
| * integer values in the range -2^31 through 2^31-1, inclusive. This |
| * abstract operation functions as follows: |
| * <ol> |
| * <li>Let {@code number} be the result of calling ToNumber on the input |
| * argument.</li> |
| * <li>If {@code number} is NaN, +0, -0, positive infinity, or negative |
| * infinity, return +0.</li> |
| * <li>Let {@code posInt} be {@code sign(number) * floor(abs(number))}.</li> |
| * <li>Let {@code int32bit} be {@code posInt modulo 2^ 32}; that is, a |
| * finite integer value k of Number type with positive sign and less than |
| * 2^32 in magnitude such that the mathematical difference of posInt and k |
| * is mathematically an integer multiple of 2^32.</li> |
| * <li>If {@code int32bit} is greater than or equal to 2^31, return |
| * {@code int32bit - 2^32}, otherwise return {@code int32bit}.</li> |
| * </ol> |
| * <em>NOTE Given the above definition of {@code ToInt32}:</em> |
| * <ul> |
| * <li>The ToInt32 abstract operation is idempotent: if applied to a result |
| * that it produced, the second application leaves that value unchanged.</li> |
| * <li>ToInt32(ToUint32(x)) is equal to ToInt32(x) for all values of x. (It |
| * is to preserve this latter property that positive infinity and negative |
| * infinity are mapped to +0.)</li> |
| * <li>ToInt32 maps -0 to +0.</li> |
| * </ul> |
| * |
| * @param number IEEE number. |
| * @return 32-bit integer. |
| */ |
| public static int toInt32(final double number) |
| { |
| final long int32bit = toUInt32(number); |
| if (int32bit >= TWO_TO_THE_31ST) |
| return (int)(int32bit - TWO_TO_THE_32ND); |
| else |
| return (int)int32bit; |
| } |
| |
| public static int toInt32(final Number number) |
| { |
| return toInt32(number.doubleValue()); |
| } |
| |
| public static int toInt32(final Object value) |
| { |
| return toInt32(toNumeric(value)); |
| } |
| |
| /** |
| * The abstract operation ToUInt32 converts its argument to one of 2^32 |
| * integer values in the range 0 through 2^32-1, inclusive. This abstract |
| * operation functions as follows: |
| * <ol> |
| * <li>Let {@code number} be the result of calling ToNumber on the input |
| * argument.</li> |
| * <li>If {@code number} is NaN, +0, -0, positive infinity, or negative |
| * infinity, return +0.</li> |
| * <li>Let {@code posInt} be {@code sign(number) x floor(abs(number))}.</li> |
| * <li>Let {@code int32bit} be {@code posInt modulo 2^ 32}; that is, a |
| * finite integer value k of Number type with positive sign and less than |
| * 2^32 in magnitude such that the mathematical difference of posInt and k |
| * is mathematically an integer multiple of 2^32.</li> |
| * <li>Return {@code int32bit}.</li> |
| * </ol> |
| * <em>NOTE Given the above definition of {@code ToInt32}:</em> |
| * <ul> |
| * <li>Step 5 is the only difference between {@link #toUInt32(double)} and |
| * {@link #toInt32(double)}.</li> |
| * <li>The ToUint32 abstract operation is idempotent: if applied to a result |
| * that it produced, the second application leaves that value unchanged.</li> |
| * <li>ToUint32 maps -0 to +0.</li> |
| * </ul> |
| * |
| * @param number IEEE number. |
| * @return 32-bit unsigned integer. |
| */ |
| public static long toUInt32(final double number) |
| { |
| final double posInt = toInteger(number); |
| final double int32bit = posInt % TWO_TO_THE_32ND; |
| return (long)int32bit & MASK_32_BIT_UINT; |
| } |
| |
| /** |
| * Version of toUInt32 that operates on Number |
| */ |
| public static long toUInt32(final Number value) |
| { |
| return toUInt32(value.doubleValue()); |
| } |
| |
| /** |
| * Version of toUInt32 that operates on Object |
| */ |
| public static long toUInt32(final Object value) |
| { |
| return toUInt32(toNumeric(value)); |
| } |
| |
| /** |
| * The abstract operation ToInteger converts its argument to an integral |
| * numeric value. This abstract operation functions as follows: |
| * <ol> |
| * <li>Let {@code number} be the result of calling ToNumber on the input |
| * argument.</li> |
| * <li>If {@code number} is NaN, return +0.</li> |
| * <li>If {@code number} is +0, -0, positive infinity, or negative infinity, |
| * return {@code number}.</li> |
| * <li>Return the result of computing |
| * {@code sign(number) x floor(abs(number))}.</li> |
| * </ol> |
| * |
| * @param number IEEE number. |
| * @return ECMA integer stored in a IEEE number. |
| */ |
| public static double toInteger(final double number) |
| { |
| if (isNan(number) || 0 == number || Double.isInfinite(number)) |
| return 0; |
| final double posInt = Math.signum(number) * Math.floor(Math.abs(number)); |
| return posInt; |
| } |
| |
| /** |
| * Converts "anything" to boolean using ECMA algorithm |
| * |
| * @param <T> - Number or String |
| */ |
| public static <T> boolean toBoolean(T value) |
| { |
| assert value != null : "to pass null use ABCConstants.NULL_VALUE"; |
| |
| if (value == ABCConstants.NULL_VALUE) // ECMA: null is always false |
| return false; |
| if (value == ABCConstants.UNDEFINED_VALUE) // ECMA: undefined is always false |
| return false; |
| if (value instanceof Number) |
| return toBoolean((Number)value); |
| if (value instanceof String) |
| return toBoolean((String)value); |
| if (value instanceof Boolean) |
| return (Boolean)value; |
| |
| return true; // ECMA: non-null object is true |
| } |
| |
| /** |
| * Converts a Number to boolean using ECMA algorithm The following rules |
| * apply: |
| * <ol> |
| * <li>If number is zero, return false</li> |
| * <li>If number is Nan, return false</li> |
| * <li>Otherwise, return true</li> |
| * </ol> |
| */ |
| |
| public static boolean toBoolean(Number value) |
| { |
| if(isNan(value.doubleValue()) ) |
| return false; |
| return value.doubleValue() != 0; // works for all number types, because even if there is |
| // rounding, != 0 will still be correct |
| } |
| |
| /** |
| * Converts a String to boolean using ECMA algorithm The following rules |
| * apply: |
| * <ol> |
| * <li>If value is empty, return false</li> |
| * <li>Otherwise, return true</li> |
| * </ol> |
| */ |
| public static boolean toBoolean(String value) |
| { |
| return !value.isEmpty(); |
| } |
| |
| /** |
| * Determines is a specific floating poing number is Nan |
| */ |
| public static boolean isNan(final double number) |
| { |
| return Double.isNaN(number); // Luckily ECMA uses the standard IEEE conventions for NaN |
| } |
| |
| /** |
| * The Left Shift Operator ( << ) performs a bitwise left shift operation on |
| * the left operand by the amount specified by the right operand. The |
| * production |
| * {@code ShiftExpression : ShiftExpression << AdditiveExpression} is |
| * evaluated as follows: |
| * <ol> |
| * <li>Let lref be the result of evaluating ShiftExpression.</li> |
| * <li>Let lval be GetValue(lref).</li> |
| * <li>Let rref be the result of evaluating AdditiveExpression.</li> |
| * <li>Let rval be GetValue(rref).</li> |
| * <li>Let lnum be ToInt32(lval).</li> |
| * <li>Let rnum be ToUint32(rval).</li> |
| * <li>Let shiftCount be the result of masking out all but the least |
| * significant 5 bits of rnum, that is, compute rnum & 0x1F.</li> |
| * <li>Return the result of left shifting lnum by shiftCount bits. The |
| * result is a signed 32-bit integer.</li> |
| * </ol> |
| * |
| * @param left Value of the left operand. |
| * @param right Value of the right operand. |
| * @return 32-bit signed integer. |
| */ |
| public static int leftShiftOperation(final Number left, final Number right) |
| { |
| final double lval = left.doubleValue(); |
| final double rval = right.doubleValue(); |
| final int lnum = toInt32(lval); |
| final long rnum = toUInt32(rval); |
| final long shiftCount = rnum & 0x1F; |
| return lnum << shiftCount; |
| } |
| |
| /** |
| * Performs a sign-filling bitwise right shift operation on the left operand |
| * by the amount specified by the right operand. The production |
| * {@code ShiftExpression : ShiftExpression >> AdditiveExpression} is |
| * evaluated as follows: |
| * <ol> |
| * <li>Let lref be the result of evaluating ShiftExpression.</li> |
| * <li>Let lval be GetValue(lref).</li> |
| * <li>Let rref be the result of evaluating AdditiveExpression.</li> |
| * <li>Let rval be GetValue(rref).</li> |
| * <li>Let lnum be ToInt32(lval).</li> |
| * <li>Let rnum be ToUint32(rval).</li> |
| * <li>Let shiftCount be the result of masking out all but the least |
| * significant 5 bits of rnum, that is, compute rnum & 0x1F.</li> |
| * <li>Return the result of performing a sign-extending right shift of lnum |
| * by shiftCount bits. The most significant bit is propagated. The result is |
| * a signed 32-bit integer.</li> |
| * </ol> |
| * |
| * @param left Value of the left operand. |
| * @param right Value of the right operand. |
| * @return 32-bit signed integer. |
| */ |
| public static int signedRightShiftOperation(final Number left, final Number right) |
| { |
| final double lval = left.doubleValue(); |
| final double rval = right.doubleValue(); |
| final int lnum = toInt32(lval); |
| final long rnum = toUInt32(rval); |
| final long shiftCount = rnum & 0x1F; |
| return lnum >> shiftCount; |
| } |
| |
| /** |
| * Performs a zero-filling bitwise right shift operation on the left operand |
| * by the amount specified by the right operand. The production |
| * {@code ShiftExpression : ShiftExpression >>> AdditiveExpression} is |
| * evaluated as follows: |
| * <ol> |
| * <li>Let lref be the result of evaluating ShiftExpression.</li> |
| * <li>Let lval be GetValue(lref).</li> |
| * <li>Let rref be the result of evaluating AdditiveExpression.</li> |
| * <li>Let rval be GetValue(rref).</li> |
| * <li>Let lnum be ToUInt32(lval).</li> |
| * <li>Let rnum be ToUint32(rval).</li> |
| * <li>Let shiftCount be the result of masking out all but the least |
| * significant 5 bits of rnum, that is, compute rnum & 0x1F.</li> |
| * <li>Return the result of performing a zero-filling right shift of lnum by |
| * shiftCount bits. Vacated bits are filled with zero. The result is an |
| * unsigned 32-bit integer.</li> |
| * </ol> |
| * |
| * @param left Value of the left operand. |
| * @param right Value of the right operand. |
| * @return 32-bit unsigned integer. |
| */ |
| public static long unsignedRightShiftOperation(final Number left, final Number right) |
| { |
| final double lval = left.doubleValue(); |
| final double rval = right.doubleValue(); |
| final long lnum = toUInt32(lval); |
| final long rnum = toUInt32(rval); |
| final long shiftCount = rnum & 0x1F; |
| return lnum >>> shiftCount; |
| } |
| |
| /** |
| * Performs the logical and (&&) operation on two objects. The production |
| * {@code LogicalANDExpression : LogicalANDExpression && BitwiseORExpression} |
| * is evaluated as follows: |
| * <ol> |
| * <li>Let lref be the result of evaluating LogicalANDExpression.</li> |
| * <li>lval be GetValue(lref).</li> |
| * <li>If ToBoolean(lval) is false, return lval.</li> |
| * <li>Let rref be the result of evaluating BitwiseORExpression.</li> |
| * <li>Return GetValue(rref). |
| * |
| * @param <T> is the numeric type of the operands, and the return type |
| * @param left Value of the left operand |
| * @param right Value of the right operand |
| */ |
| public static <T> T logicalAnd(T left, T right) |
| { |
| boolean b = toBoolean(left); |
| return b ? right : left; |
| } |
| |
| /** |
| * Performs the logical or (||) operation on two objects. is evaluated as |
| * follows: |
| * <ol> |
| * <li>Let lref be the result of evaluating LogicalANDExpression.</li> |
| * <li>lval be GetValue(lref).</li> |
| * <li>If ToBoolean(lval) is true, return lval.</li> |
| * <li>Let rref be the result of evaluating BitwiseORExpression.</li> |
| * <li>Return GetValue(rref). |
| * |
| * @param <T> is the numeric type of the operands, and the return type |
| * @param left Value of the left operand |
| * @param right Value of the right operand |
| */ |
| public static <T> T logicalOr(T left, T right) |
| { |
| boolean b = toBoolean(left); |
| return b ? left : right; |
| } |
| |
| /** |
| * Perform the logical not (!) operation on an object As per the ECMA spec |
| * this is done as follows |
| * <ol> |
| * <li>Let expr be the result of evaluating UnaryExpression</li> |
| * <li>Let oldValue be ToBoolean(GetValue(expr)).</li> |
| * <li>If oldValue is true, return false.</li> |
| * <li>Return true.</li> |
| * </ol> |
| * |
| * @param <T> is the numeric type of the operand |
| * @param e is the operand |
| */ |
| public static <T> boolean logicalNot(T e) |
| { |
| return !toBoolean(e); |
| } |
| |
| /** |
| * Implement the ECMA ToNumber (ECMA 262, 3rd Edition section 9.3) algorithm. This will convert any value |
| * into a numeric value.. |
| * |
| * @param value the value to convert |
| * @return the numeric representation of the value, as specified by the ToNumber algorithm |
| */ |
| public static <T> Number toNumeric(T value) |
| { |
| if( value == ABCConstants.UNDEFINED_VALUE ) |
| return Double.NaN; |
| if( value == ABCConstants.NULL_VALUE ) |
| return 0; |
| if( value instanceof Number ) |
| return (Number)value; |
| if( value instanceof Boolean ) |
| return toNumeric((Boolean) value); |
| if( value instanceof String ) |
| return toNumeric((String) value); |
| |
| return null; |
| } |
| |
| /** |
| * Implement ToNumber for boolean values - ECMA 262, 3rd edition section 9.3 |
| */ |
| private static int toNumeric (Boolean value) |
| { |
| return ((Boolean)value).booleanValue() ? 1 : 0; |
| } |
| |
| |
| /** |
| * trim according to ECMA - will get rid of escaped unicode characters |
| * that java's trim does not remove |
| * |
| * For use when converting Strings -> Number |
| */ |
| private static String numberTrim(String str) { |
| StringBuilder buf = new StringBuilder(); |
| for (int i=0; i<str.length(); i++) { |
| Character c = str.charAt(i); |
| if (Character.isWhitespace(c)) { |
| continue; |
| } |
| buf.append(c); |
| } |
| str = new String(buf); |
| buf = new StringBuilder(); |
| for (int i=str.length()-1; i>=0; i--) { |
| Character c = str.charAt(i); |
| if (Character.isWhitespace(c)) { |
| continue; |
| } |
| buf.append(c); |
| } |
| str = new String(buf.reverse()); |
| return str; |
| } |
| |
| /** |
| * Implement ToNumber for string values - ECMA 262, 3rd edition section 9.3.1 |
| */ |
| private static Number toNumeric(String str ) |
| { |
| double sign[] = new double[1]; |
| str = numberTrim(str); |
| str = numberSign(str, sign); |
| |
| double num; |
| if (str.equals("")) { |
| num = 0; |
| } |
| else |
| if (str.equals("Infinity")) { |
| if (sign[0] > 0) { |
| num = Double.POSITIVE_INFINITY; |
| } |
| else { |
| num = Double.NEGATIVE_INFINITY; |
| } |
| } |
| else |
| if (str.equals("NaN")) { |
| num = Double.NaN; |
| } |
| else if (str.startsWith("0x") || str.startsWith("0X")) { |
| try { |
| num = sign[0] * Long.valueOf(str.substring(2), 16); |
| } |
| catch (NumberFormatException e) { |
| num = Double.NaN; |
| } |
| } |
| else { |
| if (!Character.isDigit(str.charAt(str.length()-1)) && str.charAt(str.length()-1) != '.') { // localization? |
| num = Double.NaN; // "1f" "1F" "1d" "1D" are all NaN in AS3 |
| } |
| else { |
| try { |
| num = sign[0] * Double.valueOf(str); |
| } |
| catch (NumberFormatException e) { |
| num = Double.NaN; |
| } |
| } |
| } |
| return num; |
| } |
| |
| /** |
| * Helper method for converting strings to numbers - strips off any leaving '-' or '+' characters |
| * and determines what the sign of the number should be |
| */ |
| private static String numberSign(String str, double[] num) { |
| if(str.length() == 0) { |
| num[0] = +1; |
| } |
| else |
| if (str.equals("-") || str.equals("+")) { |
| num[0] = 0; // leave it alone, to produce NaN later |
| } |
| else |
| if(str.startsWith("-")) { |
| num[0] = -1; |
| str = str.substring(1); |
| } |
| else |
| if(str.startsWith("+")) { |
| num[0] = +1; |
| str = str.substring(1); |
| } |
| else { |
| num[0] = +1; |
| } |
| return str; |
| } |
| |
| /** |
| * Implement equality of numbers - see ECMA 262 3d Edition, section 11.9.3 |
| * @param l the left number |
| * @param r the right number |
| * @return true if the numbers are equal according to the ECMA spec |
| */ |
| public static boolean equals(Number l, Number r) |
| { |
| // NaN is not equal to anything, not even itself |
| double lDouble = l.doubleValue(); |
| if( Double.isNaN(lDouble) ) |
| return false; |
| |
| return lDouble == r.doubleValue(); |
| } |
| |
| /** |
| * Implement equality of strings - see ECMA 262 3d Edition, section 11.9.3 |
| * @param l the left string |
| * @param r the right string |
| * @return true if the strings are equal according to the ECMA spec |
| */ |
| public static boolean equals(String l, String r) |
| { |
| return l.equals(r); |
| } |
| |
| /** |
| * Implement equality of booleans - see ECMA 262 3d Edition, section 11.9.3 |
| * @param l the left boolean |
| * @param r the right boolean |
| * @return true if the booleans are equal according to the ECMA spec |
| */ |
| public static boolean equals(Boolean l, Boolean r) |
| { |
| return l.equals(r); |
| } |
| |
| /** |
| * Implement the Abstract Equality Comparison algorithm - see ECMA 262 3d Edition, section 11.9.3 |
| * @param l the left value |
| * @param r the right value |
| * @return true if the value are equal according to the ECMA spec |
| */ |
| public static boolean equals(Object l, Object r) |
| { |
| ECMAType leftType = getType(l); |
| ECMAType rightType = getType(r); |
| |
| if( leftType == rightType) |
| { |
| switch (leftType) |
| { |
| case Boolean: |
| return equals((Boolean)l, (Boolean)r); |
| case Number: |
| return equals((Number)l, (Number)r); |
| case String: |
| return equals((String)l, (String)r); |
| case Null: |
| return true; |
| case Undefined: |
| return true; |
| } |
| } |
| |
| if( l == r ) |
| return true; |
| |
| switch (leftType) |
| { |
| case Boolean: |
| return equals(toNumeric((Boolean)l), r); |
| case Number: |
| if( rightType == ECMAType.String ) |
| return equals((Number)l, toNumeric((String)r)); |
| break; |
| case String: |
| if( rightType == ECMAType.Number ) |
| return equals(toNumeric((String)l), (Number)r); |
| break; |
| case Null: |
| if( rightType == ECMAType.Undefined ) |
| return true; |
| break; |
| case Undefined: |
| if( rightType == ECMAType.Null ) |
| return true; |
| break; |
| } |
| |
| if( rightType == ECMAType.Boolean ) |
| return equals(l, toNumeric((Boolean)r)); |
| |
| |
| return false; |
| } |
| |
| /** |
| * Implement the strict equality comparison algorithm - see ECMA 262 3d Edition, section 11.9.6 |
| * |
| * Used for '===', '!==', etc. |
| * |
| * @param l the left value |
| * @param r the right value |
| * @return true if the values are equal according to the ECMA spec |
| */ |
| public static boolean strictEquals(Object l, Object r) |
| { |
| ECMAType leftType = getType(l); |
| ECMAType rightType = getType(r); |
| |
| if( leftType == rightType) |
| { |
| switch (leftType) |
| { |
| case Boolean: |
| return equals((Boolean)l, (Boolean)r); |
| case Number: |
| return equals((Number)l, (Number)r); |
| case String: |
| return equals((String)l, (String)r); |
| case Null: |
| return true; |
| case Undefined: |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Helper method for the comparison methods - return an enum representing the type |
| * of the value to avoid lots of if( instanceof ) checking. |
| */ |
| private static ECMAType getType(Object o) |
| { |
| if( o instanceof String ) |
| return ECMAType.String; |
| if( o instanceof Number ) |
| return ECMAType.Number; |
| if( o instanceof Boolean ) |
| return ECMAType.Boolean; |
| if( o == ABCConstants.NULL_VALUE ) |
| return ECMAType.Null; |
| if( o == ABCConstants.UNDEFINED_VALUE ) |
| return ECMAType.Undefined; |
| assert false : "unknown constant type"; |
| return null; |
| } |
| |
| /** |
| * Enum to represent the various ECMA types we may be folding |
| */ |
| private static enum ECMAType |
| { |
| Boolean, |
| Number, |
| String, |
| Null, |
| Undefined |
| } |
| |
| /** |
| * Implement the abstract relational comparison algorithm - see ECMA 262 3rd edition, section 11.8.5 |
| * |
| * less than, greater than, etc are implement in terms of this algorithm |
| * @param l the first value to compare |
| * @param r the second value to compare |
| * @return true, false, or java null (which means at least one operand was NaN) |
| */ |
| private static Boolean relationalCompare(Object l, Object r) |
| { |
| ECMAType lType = getType(l); |
| ECMAType rType = getType(r); |
| |
| if (lType == ECMAType.String && rType == ECMAType.String ) |
| return relationalCompare((String)l, (String)r); |
| |
| return relationalCompare(toNumeric(l), toNumeric(r)); |
| } |
| |
| /** |
| * Specialized relational compare method for String. |
| */ |
| private static Boolean relationalCompare(String l, String r) |
| { |
| if( l.compareTo(r) < 0 ) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Specialized relational compare method for Numbers. |
| */ |
| private static Boolean relationalCompare(Number l, Number r) |
| { |
| double lVal = l.doubleValue(); |
| double rVal = r.doubleValue(); |
| if( isNan(lVal) || isNan(rVal) ) |
| return null; |
| |
| return lVal < rVal; |
| } |
| |
| /** |
| * ECMA less-than operator - ECMA 262 3rd edition, section 11.8.1 |
| */ |
| public static boolean lessThan(Number l, Number r) |
| { |
| Boolean res = relationalCompare(l, r); |
| if( res == null ) |
| return false; |
| |
| return res; |
| } |
| |
| /** |
| * ECMA less-than operator - ECMA 262 3rd edition, section 11.8.1 |
| */ |
| public static boolean lessThan(Object l, Object r) |
| { |
| Boolean res = relationalCompare(l, r); |
| if( res == null ) |
| return false; |
| |
| return res; |
| } |
| |
| /** |
| * ECMA less-than-or-equal operator - ECMA 262 3rd edition, section 11.8.3 |
| */ |
| public static boolean lessThanEquals(Number l, Number r) |
| { |
| Boolean res = relationalCompare(r, l); |
| if( res == null || res == true ) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * ECMA less-than-or-equal operator - ECMA 262 3rd edition, section 11.8.3 |
| */ |
| public static boolean lessThanEquals(Object l, Object r) |
| { |
| Boolean res = relationalCompare(r, l); |
| if( res == null || res == true) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * ECMA greater-than - ECMA 262 3rd edition, section 11.8.2 |
| */ |
| public static boolean greaterThan(Number l, Number r) |
| { |
| Boolean res = relationalCompare(r, l); |
| if( res == null ) |
| return false; |
| |
| return res; |
| } |
| |
| /** |
| * ECMA greater-than - ECMA 262 3rd edition, section 11.8.2 |
| */ |
| public static boolean greaterThan(Object l, Object r) |
| { |
| Boolean res = relationalCompare(r, l); |
| if( res == null ) |
| return false; |
| |
| return res; |
| } |
| |
| /** |
| * ECMA greater-than-or-equal operator - ECMA 262 3rd edition, section 11.8.4 |
| */ |
| public static boolean greaterThanEquals(Number l, Number r) |
| { |
| Boolean res = relationalCompare(l, r); |
| if( res == null || res == true ) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * ECMA greater-than-or-equal operator - ECMA 262 3rd edition, section 11.8.4 |
| */ |
| public static boolean greaterThanEquals(Object l, Object r) |
| { |
| Boolean res = relationalCompare(l, r); |
| if( res == null || res == true) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * Implement the ECMA ToString algorithm - ECMA 262 3rd edition, section 9.8 |
| * @param o the value to convert to a String |
| * @return the String representation of the value |
| */ |
| public static String toString(Object o) |
| { |
| if( o instanceof String ) |
| return (String)o; |
| if( o instanceof Double ) |
| return toString((Double) o); |
| if( o instanceof Integer ) |
| return toString((Integer)o); |
| if( o instanceof Long ) |
| return toString((Long)o); |
| if( o instanceof Boolean ) |
| return toString((Boolean)o); |
| if( o == ABCConstants.NULL_VALUE ) |
| return "null"; |
| if( o == ABCConstants.UNDEFINED_VALUE ) |
| return "undefined"; |
| |
| return null; |
| } |
| |
| /** |
| * Implement the ECMA ToString algorithm - ECMA 262 3rd edition, section 9.8.1 |
| */ |
| public static String toString(Double d) |
| { |
| String str = ""; |
| if (d.isNaN() || d.isInfinite()) { |
| str = "" + d; |
| } |
| else { |
| // machinations for getting formatting to match AVM |
| BigDecimal bd = new BigDecimal(d.doubleValue()).round(MathContext.DECIMAL64).stripTrailingZeros(); |
| // BigDecimal bd = new BigDecimal(d.doubleValue()).round(new MathContext(15asc , RoundingMode.DOWN)).stripTrailingZeros(); |
| //out.println("dval="+dval+" bd="+bd+" scale="+bd.scale()+" prec="+bd.precision()); |
| if (bd.scale() < 0 && bd.scale() > -21) { |
| bd = bd.setScale(0); |
| } |
| str = "" + bd; |
| str = str.replaceFirst("E", "e"); |
| } |
| return str; |
| } |
| |
| /** |
| * Specialized toString for ints - ECMA 262 3rd edition, section 9.8.1 |
| */ |
| public static String toString(Integer i) |
| { |
| return "" + new BigDecimal(i); |
| } |
| |
| /** |
| * Specialized toString for uint's - ECMA 262 3rd edition, section 9.8.1 |
| */ |
| public static String toString(Long i) |
| { |
| return "" + new BigDecimal(i); |
| } |
| |
| /** |
| * Specialized toString for booleans - ECMA 262 3rd edition, section 9.8 |
| */ |
| public static String toString(Boolean b) |
| { |
| if( b.booleanValue() ) |
| return "true"; |
| return "false"; |
| } |
| |
| } |