Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (102)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (322)
Collections:
Other Resources:
Rhino JavaScript Java Library Source Code
Rhino JavaScript Java Library is an open-source implementation of JavaScript
written entirely in Java.
Rhino JavaScript Java Library Source Code files are provided in binary package (rhino-1.7.14.zip).
You can also browse the source code below:
✍: FYIcenter.com
⏎ org/mozilla/javascript/ScriptRuntime.java
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.function.BiConsumer;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.v8dtoa.DoubleConversion;
import org.mozilla.javascript.v8dtoa.FastDtoa;
import org.mozilla.javascript.xml.XMLLib;
import org.mozilla.javascript.xml.XMLObject;
/**
* This is the class that implements the runtime.
*
* @author Norris Boyd
*/
public class ScriptRuntime {
/** No instances should be created. */
protected ScriptRuntime() {}
/**
* Returns representation of the [[ThrowTypeError]] object. See ECMA 5 spec, 13.2.3
*
* @deprecated {@link #typeErrorThrower(Context)}
*/
@Deprecated
public static BaseFunction typeErrorThrower() {
return typeErrorThrower(Context.getCurrentContext());
}
/** Returns representation of the [[ThrowTypeError]] object. See ECMA 5 spec, 13.2.3 */
public static BaseFunction typeErrorThrower(Context cx) {
if (cx.typeErrorThrower == null) {
BaseFunction thrower =
new BaseFunction() {
private static final long serialVersionUID = -5891740962154902286L;
@Override
public Object call(
Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
throw typeErrorById("msg.op.not.allowed");
}
@Override
public int getLength() {
return 0;
}
};
ScriptRuntime.setFunctionProtoAndParent(thrower, cx.topCallScope);
thrower.preventExtensions();
cx.typeErrorThrower = thrower;
}
return cx.typeErrorThrower;
}
static class NoSuchMethodShim implements Callable {
String methodName;
Callable noSuchMethodMethod;
NoSuchMethodShim(Callable noSuchMethodMethod, String methodName) {
this.noSuchMethodMethod = noSuchMethodMethod;
this.methodName = methodName;
}
/**
* Perform the call.
*
* @param cx the current Context for this thread
* @param scope the scope to use to resolve properties.
* @param thisObj the JavaScript <code>this</code> object
* @param args the array of arguments
* @return the result of the call
*/
@Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
Object[] nestedArgs = new Object[2];
nestedArgs[0] = methodName;
nestedArgs[1] = newArrayLiteral(args, null, cx, scope);
return noSuchMethodMethod.call(cx, scope, thisObj, nestedArgs);
}
}
/*
* There's such a huge space (and some time) waste for the Foo.class
* syntax: the compiler sticks in a test of a static field in the
* enclosing class for null and the code for creating the class value.
* It has to do this since the reference has to get pushed off until
* execution time (i.e. can't force an early load), but for the
* 'standard' classes - especially those in java.lang, we can trust
* that they won't cause problems by being loaded early.
*/
public static final Class<?> BooleanClass = Kit.classOrNull("java.lang.Boolean"),
ByteClass = Kit.classOrNull("java.lang.Byte"),
CharacterClass = Kit.classOrNull("java.lang.Character"),
ClassClass = Kit.classOrNull("java.lang.Class"),
DoubleClass = Kit.classOrNull("java.lang.Double"),
FloatClass = Kit.classOrNull("java.lang.Float"),
IntegerClass = Kit.classOrNull("java.lang.Integer"),
LongClass = Kit.classOrNull("java.lang.Long"),
NumberClass = Kit.classOrNull("java.lang.Number"),
ObjectClass = Kit.classOrNull("java.lang.Object"),
ShortClass = Kit.classOrNull("java.lang.Short"),
StringClass = Kit.classOrNull("java.lang.String"),
DateClass = Kit.classOrNull("java.util.Date"),
BigIntegerClass = Kit.classOrNull("java.math.BigInteger");
public static final Class<?> ContextClass = Kit.classOrNull("org.mozilla.javascript.Context"),
ContextFactoryClass = Kit.classOrNull("org.mozilla.javascript.ContextFactory"),
FunctionClass = Kit.classOrNull("org.mozilla.javascript.Function"),
ScriptableObjectClass = Kit.classOrNull("org.mozilla.javascript.ScriptableObject");
public static final Class<Scriptable> ScriptableClass = Scriptable.class;
private static final Object LIBRARY_SCOPE_KEY = "LIBRARY_SCOPE";
public static boolean isRhinoRuntimeType(Class<?> cl) {
if (cl.isPrimitive()) {
return (cl != Character.TYPE);
}
return (cl == StringClass
|| cl == BooleanClass
|| NumberClass.isAssignableFrom(cl)
|| ScriptableClass.isAssignableFrom(cl));
}
public static ScriptableObject initSafeStandardObjects(
Context cx, ScriptableObject scope, boolean sealed) {
if (scope == null) {
scope = new NativeObject();
} else if (scope instanceof TopLevel) {
((TopLevel) scope).clearCache();
}
scope.associateValue(LIBRARY_SCOPE_KEY, scope);
(new ClassCache()).associate(scope);
BaseFunction.init(scope, sealed);
NativeObject.init(scope, sealed);
Scriptable objectProto = ScriptableObject.getObjectPrototype(scope);
// Function.prototype.__proto__ should be Object.prototype
Scriptable functionProto = ScriptableObject.getClassPrototype(scope, "Function");
functionProto.setPrototype(objectProto);
// Set the prototype of the object passed in if need be
if (scope.getPrototype() == null) scope.setPrototype(objectProto);
// must precede NativeGlobal since it's needed therein
NativeError.init(scope, sealed);
NativeGlobal.init(cx, scope, sealed);
NativeArray.init(scope, sealed);
if (cx.getOptimizationLevel() > 0) {
// When optimizing, attempt to fulfill all requests for new Array(N)
// with a higher threshold before switching to a sparse
// representation
NativeArray.setMaximumInitialCapacity(200000);
}
NativeString.init(scope, sealed);
NativeBoolean.init(scope, sealed);
NativeNumber.init(scope, sealed);
NativeDate.init(scope, sealed);
NativeMath.init(scope, sealed);
NativeJSON.init(scope, sealed);
NativeWith.init(scope, sealed);
NativeCall.init(scope, sealed);
NativeScript.init(scope, sealed);
NativeIterator.init(cx, scope, sealed); // Also initializes NativeGenerator & ES6Generator
NativeArrayIterator.init(scope, sealed);
NativeStringIterator.init(scope, sealed);
NativeJavaObject.init(scope, sealed);
NativeJavaMap.init(scope, sealed);
boolean withXml =
cx.hasFeature(Context.FEATURE_E4X) && cx.getE4xImplementationFactory() != null;
// define lazy-loaded properties using their class name
new LazilyLoadedCtor(
scope, "RegExp", "org.mozilla.javascript.regexp.NativeRegExp", sealed, true);
new LazilyLoadedCtor(
scope, "Continuation", "org.mozilla.javascript.NativeContinuation", sealed, true);
if (withXml) {
String xmlImpl = cx.getE4xImplementationFactory().getImplementationClassName();
new LazilyLoadedCtor(scope, "XML", xmlImpl, sealed, true);
new LazilyLoadedCtor(scope, "XMLList", xmlImpl, sealed, true);
new LazilyLoadedCtor(scope, "Namespace", xmlImpl, sealed, true);
new LazilyLoadedCtor(scope, "QName", xmlImpl, sealed, true);
}
if (((cx.getLanguageVersion() >= Context.VERSION_1_8)
&& cx.hasFeature(Context.FEATURE_V8_EXTENSIONS))
|| (cx.getLanguageVersion() >= Context.VERSION_ES6)) {
new LazilyLoadedCtor(
scope,
"ArrayBuffer",
"org.mozilla.javascript.typedarrays.NativeArrayBuffer",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Int8Array",
"org.mozilla.javascript.typedarrays.NativeInt8Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Uint8Array",
"org.mozilla.javascript.typedarrays.NativeUint8Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Uint8ClampedArray",
"org.mozilla.javascript.typedarrays.NativeUint8ClampedArray",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Int16Array",
"org.mozilla.javascript.typedarrays.NativeInt16Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Uint16Array",
"org.mozilla.javascript.typedarrays.NativeUint16Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Int32Array",
"org.mozilla.javascript.typedarrays.NativeInt32Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Uint32Array",
"org.mozilla.javascript.typedarrays.NativeUint32Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Float32Array",
"org.mozilla.javascript.typedarrays.NativeFloat32Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"Float64Array",
"org.mozilla.javascript.typedarrays.NativeFloat64Array",
sealed,
true);
new LazilyLoadedCtor(
scope,
"DataView",
"org.mozilla.javascript.typedarrays.NativeDataView",
sealed,
true);
}
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
NativeSymbol.init(cx, scope, sealed);
NativeCollectionIterator.init(scope, NativeSet.ITERATOR_TAG, sealed);
NativeCollectionIterator.init(scope, NativeMap.ITERATOR_TAG, sealed);
NativeMap.init(cx, scope, sealed);
NativePromise.init(cx, scope, sealed);
NativeSet.init(cx, scope, sealed);
NativeWeakMap.init(scope, sealed);
NativeWeakSet.init(scope, sealed);
NativeBigInt.init(scope, sealed);
}
if (scope instanceof TopLevel) {
((TopLevel) scope).cacheBuiltins(scope, sealed);
}
return scope;
}
public static ScriptableObject initStandardObjects(
Context cx, ScriptableObject scope, boolean sealed) {
ScriptableObject s = initSafeStandardObjects(cx, scope, sealed);
new LazilyLoadedCtor(
s, "Packages", "org.mozilla.javascript.NativeJavaTopPackage", sealed, true);
new LazilyLoadedCtor(
s, "getClass", "org.mozilla.javascript.NativeJavaTopPackage", sealed, true);
new LazilyLoadedCtor(s, "JavaAdapter", "org.mozilla.javascript.JavaAdapter", sealed, true);
new LazilyLoadedCtor(
s, "JavaImporter", "org.mozilla.javascript.ImporterTopLevel", sealed, true);
for (String packageName : getTopPackageNames()) {
new LazilyLoadedCtor(
s, packageName, "org.mozilla.javascript.NativeJavaTopPackage", sealed, true);
}
return s;
}
static String[] getTopPackageNames() {
// Include "android" top package if running on Android
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new String[] {"java", "javax", "org", "com", "edu", "net", "android"}
: new String[] {"java", "javax", "org", "com", "edu", "net"};
}
public static ScriptableObject getLibraryScopeOrNull(Scriptable scope) {
ScriptableObject libScope;
libScope = (ScriptableObject) ScriptableObject.getTopScopeValue(scope, LIBRARY_SCOPE_KEY);
return libScope;
}
// It is public so NativeRegExp can access it.
public static boolean isJSLineTerminator(int c) {
// Optimization for faster check for eol character:
// they do not have 0xDFD0 bits set
if ((c & 0xDFD0) != 0) {
return false;
}
return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
}
public static boolean isJSWhitespaceOrLineTerminator(int c) {
return (isStrWhiteSpaceChar(c) || isJSLineTerminator(c));
}
/**
* Indicates if the character is a Str whitespace char according to ECMA spec: StrWhiteSpaceChar
* ::: <TAB> <SP> <NBSP> <FF> <VT> <CR> <LF> <LS> <PS> <USP> <BOM>
*/
static boolean isStrWhiteSpaceChar(int c) {
switch (c) {
case ' ': // <SP>
case '\n': // <LF>
case '\r': // <CR>
case '\t': // <TAB>
case '\u00A0': // <NBSP>
case '\u000C': // <FF>
case '\u000B': // <VT>
case '\u2028': // <LS>
case '\u2029': // <PS>
case '\uFEFF': // <BOM>
return true;
default:
return Character.getType(c) == Character.SPACE_SEPARATOR;
}
}
public static Boolean wrapBoolean(boolean b) {
return Boolean.valueOf(b);
}
public static Integer wrapInt(int i) {
return Integer.valueOf(i);
}
public static Number wrapNumber(double x) {
if (Double.isNaN(x)) {
return ScriptRuntime.NaNobj;
}
return Double.valueOf(x);
}
/**
* Convert the value to a boolean.
*
* <p>See ECMA 9.2.
*/
public static boolean toBoolean(Object val) {
for (; ; ) {
if (val instanceof Boolean) return ((Boolean) val).booleanValue();
if (val == null || Undefined.isUndefined(val)) return false;
if (val instanceof CharSequence) return ((CharSequence) val).length() != 0;
if (val instanceof BigInteger) {
return !((BigInteger) val).equals(BigInteger.ZERO);
}
if (val instanceof Number) {
double d = ((Number) val).doubleValue();
return (!Double.isNaN(d) && d != 0.0);
}
if (val instanceof Scriptable) {
if (val instanceof ScriptableObject
&& ((ScriptableObject) val).avoidObjectDetection()) {
return false;
}
if (Context.getContext().isVersionECMA1()) {
// pure ECMA
return true;
}
// ECMA extension
val = ((Scriptable) val).getDefaultValue(BooleanClass);
if ((val instanceof Scriptable) && !isSymbol(val))
throw errorWithClassName("msg.primitive.expected", val);
continue;
}
warnAboutNonJSObject(val);
return true;
}
}
/**
* Convert the value to a number.
*
* <p>See ECMA 9.3.
*/
public static double toNumber(Object val) {
for (; ; ) {
if (val instanceof BigInteger) {
throw typeErrorById("msg.cant.convert.to.number", "BigInt");
}
if (val instanceof Number) return ((Number) val).doubleValue();
if (val == null) return +0.0;
if (Undefined.isUndefined(val)) return NaN;
if (val instanceof String) return toNumber((String) val);
if (val instanceof CharSequence) return toNumber(val.toString());
if (val instanceof Boolean) return ((Boolean) val).booleanValue() ? 1 : +0.0;
if (val instanceof Symbol) throw typeErrorById("msg.not.a.number");
if (val instanceof Scriptable) {
val = ((Scriptable) val).getDefaultValue(NumberClass);
if ((val instanceof Scriptable) && !isSymbol(val))
throw errorWithClassName("msg.primitive.expected", val);
continue;
}
warnAboutNonJSObject(val);
return NaN;
}
}
public static double toNumber(Object[] args, int index) {
return (index < args.length) ? toNumber(args[index]) : NaN;
}
public static final double NaN = Double.NaN;
public static final Double NaNobj = Double.valueOf(NaN);
// Preserve backward-compatibility with historical value of this.
public static final double negativeZero = Double.longBitsToDouble(0x8000000000000000L);
public static final Double zeroObj = Double.valueOf(0.0);
public static final Double negativeZeroObj = Double.valueOf(-0.0);
static double stringPrefixToNumber(String s, int start, int radix) {
return stringToNumber(s, start, s.length() - 1, radix, true);
}
static double stringToNumber(String s, int start, int end, int radix) {
return stringToNumber(s, start, end, radix, false);
}
/*
* Helper function for toNumber, parseInt, and TokenStream.getToken.
*/
private static double stringToNumber(
String source, int sourceStart, int sourceEnd, int radix, boolean isPrefix) {
char digitMax = '9';
char lowerCaseBound = 'a';
char upperCaseBound = 'A';
if (radix < 10) {
digitMax = (char) ('0' + radix - 1);
}
if (radix > 10) {
lowerCaseBound = (char) ('a' + radix - 10);
upperCaseBound = (char) ('A' + radix - 10);
}
int end;
double sum = 0.0;
for (end = sourceStart; end <= sourceEnd; end++) {
char c = source.charAt(end);
int newDigit;
if ('0' <= c && c <= digitMax) newDigit = c - '0';
else if ('a' <= c && c < lowerCaseBound) newDigit = c - 'a' + 10;
else if ('A' <= c && c < upperCaseBound) newDigit = c - 'A' + 10;
else if (!isPrefix) return NaN; // isn't a prefix but found unexpected char
else break; // unexpected char
sum = sum * radix + newDigit;
}
if (sourceStart == end) { // stopped right at the beginning
return NaN;
}
if (sum > NativeNumber.MAX_SAFE_INTEGER) {
if (radix == 10) {
/* If we're accumulating a decimal number and the number
* is >= 2^53, then the result from the repeated multiply-add
* above may be inaccurate. Call Java to get the correct
* answer.
*/
try {
return Double.parseDouble(source.substring(sourceStart, end));
} catch (NumberFormatException nfe) {
return NaN;
}
} else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) {
/* The number may also be inaccurate for one of these bases.
* This happens if the addition in value*radix + digit causes
* a round-down to an even least significant mantissa bit
* when the first dropped bit is a one. If any of the
* following digits in the number (which haven't been added
* in yet) are nonzero then the correct action would have
* been to round up instead of down. An example of this
* occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
int bitShiftInChar = 1;
int digit = 0;
final int SKIP_LEADING_ZEROS = 0;
final int FIRST_EXACT_53_BITS = 1;
final int AFTER_BIT_53 = 2;
final int ZEROS_AFTER_54 = 3;
final int MIXED_AFTER_54 = 4;
int state = SKIP_LEADING_ZEROS;
int exactBitsLimit = 53;
double factor = 0.0;
boolean bit53 = false;
// bit54 is the 54th bit (the first dropped from the mantissa)
boolean bit54 = false;
int pos = sourceStart;
for (; ; ) {
if (bitShiftInChar == 1) {
if (pos == end) break;
digit = source.charAt(pos++);
if ('0' <= digit && digit <= '9') digit -= '0';
else if ('a' <= digit && digit <= 'z') digit -= 'a' - 10;
else digit -= 'A' - 10;
bitShiftInChar = radix;
}
bitShiftInChar >>= 1;
boolean bit = (digit & bitShiftInChar) != 0;
switch (state) {
case SKIP_LEADING_ZEROS:
if (bit) {
--exactBitsLimit;
sum = 1.0;
state = FIRST_EXACT_53_BITS;
}
break;
case FIRST_EXACT_53_BITS:
sum *= 2.0;
if (bit) sum += 1.0;
--exactBitsLimit;
if (exactBitsLimit == 0) {
bit53 = bit;
state = AFTER_BIT_53;
}
break;
case AFTER_BIT_53:
bit54 = bit;
factor = 2.0;
state = ZEROS_AFTER_54;
break;
case ZEROS_AFTER_54:
if (bit) {
state = MIXED_AFTER_54;
}
// fallthrough
case MIXED_AFTER_54:
factor *= 2;
break;
}
}
switch (state) {
case SKIP_LEADING_ZEROS:
sum = 0.0;
break;
case FIRST_EXACT_53_BITS:
case AFTER_BIT_53:
// do nothing
break;
case ZEROS_AFTER_54:
// x1.1 -> x1 + 1 (round up)
// x0.1 -> x0 (round down)
if (bit54 & bit53) sum += 1.0;
sum *= factor;
break;
case MIXED_AFTER_54:
// x.100...1.. -> x + 1 (round up)
// x.0anything -> x (round down)
if (bit54) sum += 1.0;
sum *= factor;
break;
}
}
/* We don't worry about inaccurate numbers for any other base. */
}
return sum;
}
/**
* ToNumber applied to the String type
*
* <p>See the #sec-tonumber-applied-to-the-string-type section of ECMA
*/
public static double toNumber(String s) {
final int len = s.length();
// Skip whitespace at the start
int start = 0;
char startChar;
for (; ; ) {
if (start == len) {
// empty or contains only whitespace
return +0.0;
}
startChar = s.charAt(start);
if (!ScriptRuntime.isStrWhiteSpaceChar(startChar)) {
// found first non-whitespace character
break;
}
start++;
}
// Skip whitespace at the end
int end = len - 1;
char endChar;
while (ScriptRuntime.isStrWhiteSpaceChar(endChar = s.charAt(end))) {
end--;
}
// Do not break scripts relying on old non-compliant conversion
// (see bug #368)
// 1. makes ToNumber parse only a valid prefix in hex literals (similar to 'parseInt()')
// ToNumber('0x10 something') => 16
// 2. allows plus and minus signs for hexadecimal numbers
// ToNumber('-0x10') => -16
// 3. disables support for binary ('0b10') and octal ('0o13') literals
// ToNumber('0b1') => NaN
// ToNumber('0o5') => NaN
final Context cx = Context.getCurrentContext();
final boolean oldParsingMode = cx == null || cx.getLanguageVersion() < Context.VERSION_ES6;
// Handle non-base10 numbers
if (startChar == '0') {
if (start + 2 <= end) {
final char radixC = s.charAt(start + 1);
int radix = -1;
if (radixC == 'x' || radixC == 'X') {
radix = 16;
} else if (!oldParsingMode && (radixC == 'o' || radixC == 'O')) {
radix = 8;
} else if (!oldParsingMode && (radixC == 'b' || radixC == 'B')) {
radix = 2;
}
if (radix != -1) {
if (oldParsingMode) {
return stringPrefixToNumber(s, start + 2, radix);
}
return stringToNumber(s, start + 2, end, radix);
}
}
} else if (oldParsingMode && (startChar == '+' || startChar == '-')) {
// If in old parsing mode, check for a signed hexadecimal number
if (start + 3 <= end && s.charAt(start + 1) == '0') {
final char radixC = s.charAt(start + 2);
if (radixC == 'x' || radixC == 'X') {
double val = stringPrefixToNumber(s, start + 3, 16);
return startChar == '-' ? -val : val;
}
}
}
if (endChar == 'y') {
// check for "Infinity"
if (startChar == '+' || startChar == '-') {
start++;
}
if (start + 7 == end && s.regionMatches(start, "Infinity", 0, 8)) {
return startChar == '-' ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
}
return NaN;
}
// A base10, non-infinity number:
// just try a normal floating point conversion
String sub = s.substring(start, end + 1);
// Quick test to check string contains only valid characters because
// Double.parseDouble() can be slow and accept input we want to reject
for (int i = sub.length() - 1; i >= 0; i--) {
char c = sub.charAt(i);
if (('0' <= c && c <= '9') || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-')
continue;
return NaN;
}
try {
return Double.parseDouble(sub);
} catch (NumberFormatException ex) {
return NaN;
}
}
/** Convert the value to a BigInt. */
public static BigInteger toBigInt(Object val) {
for (; ; ) {
if (val instanceof BigInteger) {
return (BigInteger) val;
}
if (val instanceof BigDecimal) {
return ((BigDecimal) val).toBigInteger();
}
if (val instanceof Number) {
if (val instanceof Long) {
return BigInteger.valueOf(((Long) val));
} else {
double d = ((Number) val).doubleValue();
if (Double.isNaN(d) || Double.isInfinite(d)) {
throw rangeErrorById(
"msg.cant.convert.to.bigint.isnt.integer", toString(val));
}
BigDecimal bd = new BigDecimal(d, MathContext.UNLIMITED);
try {
return bd.toBigIntegerExact();
} catch (ArithmeticException e) {
throw rangeErrorById(
"msg.cant.convert.to.bigint.isnt.integer", toString(val));
}
}
}
if (val == null || Undefined.isUndefined(val)) {
throw typeErrorById("msg.cant.convert.to.bigint", toString(val));
}
if (val instanceof String) {
return toBigInt((String) val);
}
if (val instanceof CharSequence) {
return toBigInt(val.toString());
}
if (val instanceof Boolean) {
return ((Boolean) val).booleanValue() ? BigInteger.ONE : BigInteger.ZERO;
}
if (val instanceof Symbol) {
throw typeErrorById("msg.cant.convert.to.bigint", toString(val));
}
if (val instanceof Scriptable) {
val = ((Scriptable) val).getDefaultValue(BigIntegerClass);
if ((val instanceof Scriptable) && !isSymbol(val)) {
throw errorWithClassName("msg.primitive.expected", val);
}
continue;
}
warnAboutNonJSObject(val);
return BigInteger.ZERO;
}
}
/** ToBigInt applied to the String type */
public static BigInteger toBigInt(String s) {
final int len = s.length();
// Skip whitespace at the start
int start = 0;
char startChar;
for (; ; ) {
if (start == len) {
// empty or contains only whitespace
return BigInteger.ZERO;
}
startChar = s.charAt(start);
if (!ScriptRuntime.isStrWhiteSpaceChar(startChar)) {
// found first non-whitespace character
break;
}
start++;
}
// Skip whitespace at the end
int end = len - 1;
while (ScriptRuntime.isStrWhiteSpaceChar(s.charAt(end))) {
end--;
}
// Handle non-base10 numbers
if (startChar == '0') {
if (start + 2 <= end) {
final char radixC = s.charAt(start + 1);
int radix = -1;
if (radixC == 'x' || radixC == 'X') {
radix = 16;
} else if (radixC == 'o' || radixC == 'O') {
radix = 8;
} else if (radixC == 'b' || radixC == 'B') {
radix = 2;
}
if (radix != -1) {
try {
return new BigInteger(s.substring(start + 2, end + 1), radix);
} catch (NumberFormatException ex) {
throw syntaxErrorById("msg.bigint.bad.form");
}
}
}
}
// A base10, non-infinity bigint:
// just try a normal biginteger conversion
String sub = s.substring(start, end + 1);
for (int i = sub.length() - 1; i >= 0; i--) {
char c = sub.charAt(i);
if (i == 0 && (c == '+' || c == '-')) {
continue;
}
if ('0' <= c && c <= '9') {
continue;
}
throw syntaxErrorById("msg.bigint.bad.form");
}
try {
return new BigInteger(sub);
} catch (NumberFormatException ex) {
throw syntaxErrorById("msg.bigint.bad.form");
}
}
/**
* Convert the value to a Numeric (Number or BigInt).
*
* <p>toNumber does not allow java.math.BigInteger. toNumeric allows java.math.BigInteger.
*
* <p>See ECMA 7.1.3 (v11.0).
*/
public static Number toNumeric(Object val) {
if (val instanceof Number) {
return (Number) val;
}
return toNumber(val);
}
public static int toIndex(Object val) {
if (Undefined.isUndefined(val)) {
return 0;
}
double integerIndex = toInteger(val);
if (integerIndex < 0) {
throw rangeError("index out of range");
}
// ToLength
double index = Math.min(integerIndex, NativeNumber.MAX_SAFE_INTEGER);
if (integerIndex != index) {
throw rangeError("index out of range");
}
return (int) index;
}
/**
* Helper function for builtin objects that use the varargs form. ECMA function formal arguments
* are undefined if not supplied; this function pads the argument array out to the expected
* length, if necessary.
*/
public static Object[] padArguments(Object[] args, int count) {
if (count < args.length) return args;
Object[] result = new Object[count];
System.arraycopy(args, 0, result, 0, args.length);
if (args.length < count) {
Arrays.fill(result, args.length, count, Undefined.instance);
}
return result;
}
public static String escapeString(String s) {
return escapeString(s, '"');
}
/**
* For escaping strings printed by object and array literals; not quite the same as 'escape.'
*/
public static String escapeString(String s, char escapeQuote) {
if (!(escapeQuote == '"' || escapeQuote == '\'')) Kit.codeBug();
StringBuilder sb = null;
for (int i = 0, L = s.length(); i != L; ++i) {
int c = s.charAt(i);
if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') {
// an ordinary print character (like C isprint()) and not "
// or \ .
if (sb != null) {
sb.append((char) c);
}
continue;
}
if (sb == null) {
sb = new StringBuilder(L + 3);
sb.append(s);
sb.setLength(i);
}
int escape = -1;
switch (c) {
case '\b':
escape = 'b';
break;
case '\f':
escape = 'f';
break;
case '\n':
escape = 'n';
break;
case '\r':
escape = 'r';
break;
case '\t':
escape = 't';
break;
case 0xb:
escape = 'v';
break; // Java lacks \v.
case ' ':
escape = ' ';
break;
case '\\':
escape = '\\';
break;
}
if (escape >= 0) {
// an \escaped sort of character
sb.append('\\');
sb.append((char) escape);
} else if (c == escapeQuote) {
sb.append('\\');
sb.append(escapeQuote);
} else {
int hexSize;
if (c < 256) {
// 2-digit hex
sb.append("\\x");
hexSize = 2;
} else {
// Unicode.
sb.append("\\u");
hexSize = 4;
}
// append hexadecimal form of c left-padded with 0
for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
int digit = 0xf & (c >> shift);
int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit;
sb.append((char) hc);
}
}
}
return (sb == null) ? s : sb.toString();
}
static boolean isValidIdentifierName(String s, Context cx, boolean isStrict) {
int L = s.length();
if (L == 0) return false;
if (!Character.isJavaIdentifierStart(s.charAt(0))) return false;
for (int i = 1; i != L; ++i) {
if (!Character.isJavaIdentifierPart(s.charAt(i))) return false;
}
return !TokenStream.isKeyword(s, cx.getLanguageVersion(), isStrict);
}
public static CharSequence toCharSequence(Object val) {
if (val instanceof NativeString) {
return ((NativeString) val).toCharSequence();
}
return val instanceof CharSequence ? (CharSequence) val : toString(val);
}
/**
* Convert the value to a string.
*
* <p>See ECMA 9.8.
*/
public static String toString(Object val) {
for (; ; ) {
if (val == null) {
return "null";
}
if (Undefined.isUndefined(val)) {
return "undefined";
}
if (val instanceof String) {
return (String) val;
}
if (val instanceof CharSequence) {
return val.toString();
}
if (val instanceof BigInteger) {
return val.toString();
}
if (val instanceof Number) {
// XXX should we just teach NativeNumber.stringValue()
// about Numbers?
return numberToString(((Number) val).doubleValue(), 10);
}
if (val instanceof Symbol) {
throw typeErrorById("msg.not.a.string");
}
if (val instanceof Scriptable) {
val = ((Scriptable) val).getDefaultValue(StringClass);
if ((val instanceof Scriptable) && !isSymbol(val)) {
throw errorWithClassName("msg.primitive.expected", val);
}
continue;
}
return val.toString();
}
}
static String defaultObjectToString(Scriptable obj) {
if (obj == null) return "[object Null]";
if (Undefined.isUndefined(obj)) return "[object Undefined]";
return "[object " + obj.getClassName() + ']';
}
public static String toString(Object[] args, int index) {
return (index < args.length) ? toString(args[index]) : "undefined";
}
/** Optimized version of toString(Object) for numbers. */
public static String toString(double val) {
return numberToString(val, 10);
}
public static String numberToString(double d, int base) {
if ((base < 2) || (base > 36)) {
throw Context.reportRuntimeErrorById("msg.bad.radix", Integer.toString(base));
}
if (Double.isNaN(d)) return "NaN";
if (d == Double.POSITIVE_INFINITY) return "Infinity";
if (d == Double.NEGATIVE_INFINITY) return "-Infinity";
if (d == 0.0) return "0";
if (base != 10) {
return DToA.JS_dtobasestr(base, d);
}
// V8 FastDtoa can't convert all numbers, so try it first but
// fall back to old DToA in case it fails
String result = FastDtoa.numberToString(d);
if (result != null) {
return result;
}
StringBuilder buffer = new StringBuilder();
DToA.JS_dtostr(buffer, DToA.DTOSTR_STANDARD, 0, d);
return buffer.toString();
}
public static String bigIntToString(BigInteger n, int base) {
if ((base < 2) || (base > 36)) {
throw rangeErrorById("msg.bad.radix", Integer.toString(base));
}
return n.toString(base);
}
static String uneval(Context cx, Scriptable scope, Object value) {
if (value == null) {
return "null";
}
if (Undefined.isUndefined(value)) {
return "undefined";
}
if (value instanceof CharSequence) {
String escaped = escapeString(value.toString());
StringBuilder sb = new StringBuilder(escaped.length() + 2);
sb.append('\"');
sb.append(escaped);
sb.append('\"');
return sb.toString();
}
if (value instanceof Number) {
double d = ((Number) value).doubleValue();
if (d == 0 && 1 / d < 0) {
return "-0";
}
return toString(d);
}
if (value instanceof Boolean) {
return toString(value);
}
if (value instanceof Scriptable) {
Scriptable obj = (Scriptable) value;
// Wrapped Java objects won't have "toSource" and will report
// errors for get()s of nonexistent name, so use has() first
if (ScriptableObject.hasProperty(obj, "toSource")) {
Object v = ScriptableObject.getProperty(obj, "toSource");
if (v instanceof Function) {
Function f = (Function) v;
return toString(f.call(cx, scope, obj, emptyArgs));
}
}
return toString(value);
}
warnAboutNonJSObject(value);
return value.toString();
}
static String defaultObjectToSource(
Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
boolean toplevel, iterating;
if (cx.iterating == null) {
toplevel = true;
iterating = false;
cx.iterating = new ObjToIntMap(31);
} else {
toplevel = false;
iterating = cx.iterating.has(thisObj);
}
StringBuilder result = new StringBuilder(128);
if (toplevel) {
result.append("(");
}
result.append('{');
// Make sure cx.iterating is set to null when done
// so we don't leak memory
try {
if (!iterating) {
cx.iterating.intern(thisObj); // stop recursion.
Object[] ids = thisObj.getIds();
for (int i = 0; i < ids.length; i++) {
Object id = ids[i];
Object value;
if (id instanceof Integer) {
int intId = ((Integer) id).intValue();
value = thisObj.get(intId, thisObj);
if (value == Scriptable.NOT_FOUND) continue; // a property has been removed
if (i > 0) result.append(", ");
result.append(intId);
} else {
String strId = (String) id;
value = thisObj.get(strId, thisObj);
if (value == Scriptable.NOT_FOUND) continue; // a property has been removed
if (i > 0) result.append(", ");
if (ScriptRuntime.isValidIdentifierName(strId, cx, cx.isStrictMode())) {
result.append(strId);
} else {
result.append('\'');
result.append(ScriptRuntime.escapeString(strId, '\''));
result.append('\'');
}
}
result.append(':');
result.append(ScriptRuntime.uneval(cx, scope, value));
}
}
} finally {
if (toplevel) {
cx.iterating = null;
}
}
result.append('}');
if (toplevel) {
result.append(')');
}
return result.toString();
}
public static Scriptable toObject(Scriptable scope, Object val) {
if (val instanceof Scriptable) {
return (Scriptable) val;
}
return toObject(Context.getContext(), scope, val);
}
/**
* <strong>Warning</strong>: This doesn't allow to resolve primitive prototype properly when
* many top scopes are involved
*
* @deprecated Use {@link #toObjectOrNull(Context, Object, Scriptable)} instead
*/
@Deprecated
public static Scriptable toObjectOrNull(Context cx, Object obj) {
if (obj instanceof Scriptable) {
return (Scriptable) obj;
} else if (obj != null && !Undefined.isUndefined(obj)) {
return toObject(cx, getTopCallScope(cx), obj);
}
return null;
}
/** @param scope the scope that should be used to resolve primitive prototype */
public static Scriptable toObjectOrNull(Context cx, Object obj, Scriptable scope) {
if (obj instanceof Scriptable) {
return (Scriptable) obj;
} else if (obj != null && !Undefined.isUndefined(obj)) {
return toObject(cx, scope, obj);
}
return null;
}
/** @deprecated Use {@link #toObject(Scriptable, Object)} instead. */
@Deprecated
public static Scriptable toObject(Scriptable scope, Object val, Class<?> staticClass) {
if (val instanceof Scriptable) {
return (Scriptable) val;
}
return toObject(Context.getContext(), scope, val);
}
/**
* Convert the value to an object.
*
* <p>See ECMA 9.9.
*/
public static Scriptable toObject(Context cx, Scriptable scope, Object val) {
if (val == null) {
throw typeErrorById("msg.null.to.object");
}
if (Undefined.isUndefined(val)) {
throw typeErrorById("msg.undef.to.object");
}
if (isSymbol(val)) {
NativeSymbol result = new NativeSymbol((NativeSymbol) val);
setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.Symbol);
return result;
}
if (val instanceof Scriptable) {
return (Scriptable) val;
}
if (val instanceof CharSequence) {
// FIXME we want to avoid toString() here, especially for concat()
NativeString result = new NativeString((CharSequence) val);
setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.String);
return result;
}
if (cx.getLanguageVersion() >= Context.VERSION_ES6 && val instanceof BigInteger) {
NativeBigInt result = new NativeBigInt(((BigInteger) val));
setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.BigInt);
return result;
}
if (val instanceof Number) {
NativeNumber result = new NativeNumber(((Number) val).doubleValue());
setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.Number);
return result;
}
if (val instanceof Boolean) {
NativeBoolean result = new NativeBoolean(((Boolean) val).booleanValue());
setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.Boolean);
return result;
}
// Extension: Wrap as a LiveConnect object.
Object wrapped = cx.getWrapFactory().wrap(cx, scope, val, null);
if (wrapped instanceof Scriptable) return (Scriptable) wrapped;
throw errorWithClassName("msg.invalid.type", val);
}
/** @deprecated Use {@link #toObject(Context, Scriptable, Object)} instead. */
@Deprecated
public static Scriptable toObject(
Context cx, Scriptable scope, Object val, Class<?> staticClass) {
return toObject(cx, scope, val);
}
/** @deprecated The method is only present for compatibility. */
@Deprecated
public static Object call(
Context cx, Object fun, Object thisArg, Object[] args, Scriptable scope) {
if (!(fun instanceof Function)) {
throw notFunctionError(toString(fun));
}
Function function = (Function) fun;
Scriptable thisObj = toObjectOrNull(cx, thisArg, scope);
if (thisObj == null) {
throw undefCallError(null, "function");
}
return function.call(cx, scope, thisObj, args);
}
public static Scriptable newObject(
Context cx, Scriptable scope, String constructorName, Object[] args) {
scope = ScriptableObject.getTopLevelScope(scope);
Function ctor = getExistingCtor(cx, scope, constructorName);
if (args == null) {
args = ScriptRuntime.emptyArgs;
}
return ctor.construct(cx, scope, args);
}
public static Scriptable newBuiltinObject(
Context cx, Scriptable scope, TopLevel.Builtins type, Object[] args) {
scope = ScriptableObject.getTopLevelScope(scope);
Function ctor = TopLevel.getBuiltinCtor(cx, scope, type);
if (args == null) {
args = ScriptRuntime.emptyArgs;
}
return ctor.construct(cx, scope, args);
}
static Scriptable newNativeError(
Context cx, Scriptable scope, TopLevel.NativeErrors type, Object[] args) {
scope = ScriptableObject.getTopLevelScope(scope);
Function ctor = TopLevel.getNativeErrorCtor(cx, scope, type);
if (args == null) {
args = ScriptRuntime.emptyArgs;
}
return ctor.construct(cx, scope, args);
}
/** See ECMA 9.4. */
public static double toInteger(Object val) {
return toInteger(toNumber(val));
}
// convenience method
public static double toInteger(double d) {
// if it's NaN
if (Double.isNaN(d)) return +0.0;
if ((d == 0.0) || Double.isInfinite(d)) return d;
if (d > 0.0) return Math.floor(d);
return Math.ceil(d);
}
public static double toInteger(Object[] args, int index) {
return (index < args.length) ? toInteger(args[index]) : +0.0;
}
public static long toLength(Object[] args, int index) {
double len = toInteger(args, index);
if (len <= +0.0) {
return 0;
}
return (long) Math.min(len, NativeNumber.MAX_SAFE_INTEGER);
}
/** See ECMA 9.5. */
public static int toInt32(Object val) {
// short circuit for common integer values
if (val instanceof Integer) return ((Integer) val).intValue();
return toInt32(toNumber(val));
}
public static int toInt32(Object[] args, int index) {
return (index < args.length) ? toInt32(args[index]) : 0;
}
public static int toInt32(double d) {
return DoubleConversion.doubleToInt32(d);
}
/**
* See ECMA 9.6.
*
* @return long value representing 32 bits unsigned integer
*/
public static long toUint32(double d) {
return DoubleConversion.doubleToInt32(d) & 0xffffffffL;
}
public static long toUint32(Object val) {
return toUint32(toNumber(val));
}
/** See ECMA 9.7. */
public static char toUint16(Object val) {
double d = toNumber(val);
return (char) DoubleConversion.doubleToInt32(d);
}
// XXX: this is until setDefaultNamespace will learn how to store NS
// properly and separates namespace form Scriptable.get etc.
private static final String DEFAULT_NS_TAG = "__default_namespace__";
public static Object setDefaultNamespace(Object namespace, Context cx) {
Scriptable scope = cx.currentActivationCall;
if (scope == null) {
scope = getTopCallScope(cx);
}
XMLLib xmlLib = currentXMLLib(cx);
Object ns = xmlLib.toDefaultXmlNamespace(cx, namespace);
// XXX : this should be in separated namesapce from Scriptable.get/put
if (!scope.has(DEFAULT_NS_TAG, scope)) {
// XXX: this is racy of cause
ScriptableObject.defineProperty(
scope,
DEFAULT_NS_TAG,
ns,
ScriptableObject.PERMANENT | ScriptableObject.DONTENUM);
} else {
scope.put(DEFAULT_NS_TAG, scope, ns);
}
return Undefined.instance;
}
public static Object searchDefaultNamespace(Context cx) {
Scriptable scope = cx.currentActivationCall;
if (scope == null) {
scope = getTopCallScope(cx);
}
Object nsObject;
for (; ; ) {
Scriptable parent = scope.getParentScope();
if (parent == null) {
nsObject = ScriptableObject.getProperty(scope, DEFAULT_NS_TAG);
if (nsObject == Scriptable.NOT_FOUND) {
return null;
}
break;
}
nsObject = scope.get(DEFAULT_NS_TAG, scope);
if (nsObject != Scriptable.NOT_FOUND) {
break;
}
scope = parent;
}
return nsObject;
}
public static Object getTopLevelProp(Scriptable scope, String id) {
scope = ScriptableObject.getTopLevelScope(scope);
return ScriptableObject.getProperty(scope, id);
}
static Function getExistingCtor(Context cx, Scriptable scope, String constructorName) {
Object ctorVal = ScriptableObject.getProperty(scope, constructorName);
if (ctorVal instanceof Function) {
return (Function) ctorVal;
}
if (ctorVal == Scriptable.NOT_FOUND) {
throw Context.reportRuntimeErrorById("msg.ctor.not.found", constructorName);
}
throw Context.reportRuntimeErrorById("msg.not.ctor", constructorName);
}
/**
* Return -1L if str is not an index, or the index value as lower 32 bits of the result. Note
* that the result needs to be cast to an int in order to produce the actual index, which may be
* negative.
*/
public static long indexFromString(String str) {
// The length of the decimal string representation of
// Integer.MAX_VALUE, 2147483647
final int MAX_VALUE_LENGTH = 10;
int len = str.length();
if (len > 0) {
int i = 0;
boolean negate = false;
int c = str.charAt(0);
if (c == '-') {
if (len > 1) {
c = str.charAt(1);
if (c == '0') return -1L; // "-0" is not an index
i = 1;
negate = true;
}
}
c -= '0';
if (0 <= c && c <= 9 && len <= (negate ? MAX_VALUE_LENGTH + 1 : MAX_VALUE_LENGTH)) {
// Use negative numbers to accumulate index to handle
// Integer.MIN_VALUE that is greater by 1 in absolute value
// then Integer.MAX_VALUE
int index = -c;
int oldIndex = 0;
i++;
if (index != 0) {
// Note that 00, 01, 000 etc. are not indexes
while (i != len && 0 <= (c = str.charAt(i) - '0') && c <= 9) {
oldIndex = index;
index = 10 * index - c;
i++;
}
}
// Make sure all characters were consumed and that it couldn't
// have overflowed.
if (i == len
&& (oldIndex > (Integer.MIN_VALUE / 10)
|| (oldIndex == (Integer.MIN_VALUE / 10)
&& c
<= (negate
? -(Integer.MIN_VALUE % 10)
: (Integer.MAX_VALUE % 10))))) {
return 0xFFFFFFFFL & (negate ? index : -index);
}
}
}
return -1L;
}
/** If str is a decimal presentation of Uint32 value, return it as long. Othewise return -1L; */
public static long testUint32String(String str) {
// The length of the decimal string representation of
// UINT32_MAX_VALUE, 4294967296
final int MAX_VALUE_LENGTH = 10;
int len = str.length();
if (1 <= len && len <= MAX_VALUE_LENGTH) {
int c = str.charAt(0);
c -= '0';
if (c == 0) {
// Note that 00,01 etc. are not valid Uint32 presentations
return (len == 1) ? 0L : -1L;
}
if (1 <= c && c <= 9) {
long v = c;
for (int i = 1; i != len; ++i) {
c = str.charAt(i) - '0';
if (!(0 <= c && c <= 9)) {
return -1;
}
v = 10 * v + c;
}
// Check for overflow
if ((v >>> 32) == 0) {
return v;
}
}
}
return -1;
}
/** If s represents index, then return index value wrapped as Integer and othewise return s. */
static Object getIndexObject(String s) {
long indexTest = indexFromString(s);
if (indexTest >= 0) {
return Integer.valueOf((int) indexTest);
}
return s;
}
/**
* If d is exact int value, return its value wrapped as Integer and othewise return d converted
* to String.
*/
static Object getIndexObject(double d) {
int i = (int) d;
if (i == d) {
return Integer.valueOf(i);
}
return toString(d);
}
/**
* Helper to return a string or an integer. Always use a null check on s.stringId to determine
* if the result is string or integer.
*
* @see ScriptRuntime#toStringIdOrIndex(Context, Object)
*/
static final class StringIdOrIndex {
final String stringId;
final int index;
StringIdOrIndex(String stringId) {
this.stringId = stringId;
this.index = -1;
}
StringIdOrIndex(int index) {
this.stringId = null;
this.index = index;
}
}
/**
* If toString(id) is a decimal presentation of int32 value, then id is index. In this case
* return null and make the index available as ScriptRuntime.lastIndexResult(cx). Otherwise
* return toString(id).
*/
static StringIdOrIndex toStringIdOrIndex(Context cx, Object id) {
if (id instanceof Number) {
double d = ((Number) id).doubleValue();
int index = (int) d;
if (index == d) {
return new StringIdOrIndex(index);
}
return new StringIdOrIndex(toString(id));
}
String s;
if (id instanceof String) {
s = (String) id;
} else {
s = toString(id);
}
long indexTest = indexFromString(s);
if (indexTest >= 0) {
return new StringIdOrIndex((int) indexTest);
}
return new StringIdOrIndex(s);
}
/**
* Call obj.[[Get]](id)
*
* @deprecated Use {@link #getObjectElem(Object, Object, Context, Scriptable)} instead
*/
@Deprecated
public static Object getObjectElem(Object obj, Object elem, Context cx) {
return getObjectElem(obj, elem, cx, getTopCallScope(cx));
}
/** Call obj.[[Get]](id) */
public static Object getObjectElem(Object obj, Object elem, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefReadError(obj, elem);
}
return getObjectElem(sobj, elem, cx);
}
public static Object getObjectElem(Scriptable obj, Object elem, Context cx) {
Object result;
if (obj instanceof XMLObject) {
result = ((XMLObject) obj).get(cx, elem);
} else if (isSymbol(elem)) {
result = ScriptableObject.getProperty(obj, (Symbol) elem);
} else {
StringIdOrIndex s = toStringIdOrIndex(cx, elem);
if (s.stringId == null) {
int index = s.index;
result = ScriptableObject.getProperty(obj, index);
} else {
result = ScriptableObject.getProperty(obj, s.stringId);
}
}
if (result == Scriptable.NOT_FOUND) {
result = Undefined.instance;
}
return result;
}
/**
* Version of getObjectElem when elem is a valid JS identifier name.
*
* @deprecated Use {@link #getObjectProp(Object, String, Context, Scriptable)} instead
*/
@Deprecated
public static Object getObjectProp(Object obj, String property, Context cx) {
return getObjectProp(obj, property, cx, getTopCallScope(cx));
}
/**
* Version of getObjectElem when elem is a valid JS identifier name.
*
* @param scope the scope that should be used to resolve primitive prototype
*/
public static Object getObjectProp(Object obj, String property, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefReadError(obj, property);
}
return getObjectProp(sobj, property, cx);
}
public static Object getObjectProp(Scriptable obj, String property, Context cx) {
Object result = ScriptableObject.getProperty(obj, property);
if (result == Scriptable.NOT_FOUND) {
if (cx.hasFeature(Context.FEATURE_STRICT_MODE)) {
Context.reportWarning(
ScriptRuntime.getMessageById("msg.ref.undefined.prop", property));
}
result = Undefined.instance;
}
return result;
}
/** @deprecated Use {@link #getObjectPropNoWarn(Object, String, Context, Scriptable)} instead */
@Deprecated
public static Object getObjectPropNoWarn(Object obj, String property, Context cx) {
return getObjectPropNoWarn(obj, property, cx, getTopCallScope(cx));
}
public static Object getObjectPropNoWarn(
Object obj, String property, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefReadError(obj, property);
}
Object result = ScriptableObject.getProperty(sobj, property);
if (result == Scriptable.NOT_FOUND) {
return Undefined.instance;
}
return result;
}
/**
* A cheaper and less general version of the above for well-known argument types.
*
* @deprecated Use {@link #getObjectIndex(Object, double, Context, Scriptable)} instead
*/
@Deprecated
public static Object getObjectIndex(Object obj, double dblIndex, Context cx) {
return getObjectIndex(obj, dblIndex, cx, getTopCallScope(cx));
}
/** A cheaper and less general version of the above for well-known argument types. */
public static Object getObjectIndex(Object obj, double dblIndex, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefReadError(obj, toString(dblIndex));
}
int index = (int) dblIndex;
if (index == dblIndex) {
return getObjectIndex(sobj, index, cx);
}
String s = toString(dblIndex);
return getObjectProp(sobj, s, cx);
}
public static Object getObjectIndex(Scriptable obj, int index, Context cx) {
Object result = ScriptableObject.getProperty(obj, index);
if (result == Scriptable.NOT_FOUND) {
result = Undefined.instance;
}
return result;
}
/**
* Call obj.[[Put]](id, value)
*
* @deprecated Use {@link #setObjectElem(Object, Object, Object, Context, Scriptable)} instead
*/
@Deprecated
public static Object setObjectElem(Object obj, Object elem, Object value, Context cx) {
return setObjectElem(obj, elem, value, cx, getTopCallScope(cx));
}
/** Call obj.[[Put]](id, value) */
public static Object setObjectElem(
Object obj, Object elem, Object value, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefWriteError(obj, elem, value);
}
return setObjectElem(sobj, elem, value, cx);
}
public static Object setObjectElem(Scriptable obj, Object elem, Object value, Context cx) {
if (obj instanceof XMLObject) {
((XMLObject) obj).put(cx, elem, value);
} else if (isSymbol(elem)) {
ScriptableObject.putProperty(obj, (Symbol) elem, value);
} else {
StringIdOrIndex s = toStringIdOrIndex(cx, elem);
if (s.stringId == null) {
ScriptableObject.putProperty(obj, s.index, value);
} else {
ScriptableObject.putProperty(obj, s.stringId, value);
}
}
return value;
}
/**
* Version of setObjectElem when elem is a valid JS identifier name.
*
* @deprecated Use {@link #setObjectProp(Object, String, Object, Context, Scriptable)} instead
*/
@Deprecated
public static Object setObjectProp(Object obj, String property, Object value, Context cx) {
return setObjectProp(obj, property, value, cx, getTopCallScope(cx));
}
/** Version of setObjectElem when elem is a valid JS identifier name. */
public static Object setObjectProp(
Object obj, String property, Object value, Context cx, Scriptable scope) {
if (!(obj instanceof Scriptable)
&& cx.isStrictMode()
&& cx.getLanguageVersion() >= Context.VERSION_1_8) {
throw undefWriteError(obj, property, value);
}
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefWriteError(obj, property, value);
}
return setObjectProp(sobj, property, value, cx);
}
public static Object setObjectProp(Scriptable obj, String property, Object value, Context cx) {
ScriptableObject.putProperty(obj, property, value);
return value;
}
/**
* A cheaper and less general version of the above for well-known argument types.
*
* @deprecated Use {@link #setObjectIndex(Object, double, Object, Context, Scriptable)} instead
*/
@Deprecated
public static Object setObjectIndex(Object obj, double dblIndex, Object value, Context cx) {
return setObjectIndex(obj, dblIndex, value, cx, getTopCallScope(cx));
}
/** A cheaper and less general version of the above for well-known argument types. */
public static Object setObjectIndex(
Object obj, double dblIndex, Object value, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw undefWriteError(obj, String.valueOf(dblIndex), value);
}
int index = (int) dblIndex;
if (index == dblIndex) {
return setObjectIndex(sobj, index, value, cx);
}
String s = toString(dblIndex);
return setObjectProp(sobj, s, value, cx);
}
public static Object setObjectIndex(Scriptable obj, int index, Object value, Context cx) {
ScriptableObject.putProperty(obj, index, value);
return value;
}
public static boolean deleteObjectElem(Scriptable target, Object elem, Context cx) {
if (isSymbol(elem)) {
SymbolScriptable so = ScriptableObject.ensureSymbolScriptable(target);
Symbol s = (Symbol) elem;
so.delete(s);
return !so.has(s, target);
}
StringIdOrIndex s = toStringIdOrIndex(cx, elem);
if (s.stringId == null) {
target.delete(s.index);
return !target.has(s.index, target);
}
target.delete(s.stringId);
return !target.has(s.stringId, target);
}
public static boolean hasObjectElem(Scriptable target, Object elem, Context cx) {
boolean result;
if (isSymbol(elem)) {
result = ScriptableObject.hasProperty(target, (Symbol) elem);
} else {
StringIdOrIndex s = toStringIdOrIndex(cx, elem);
if (s.stringId == null) {
result = ScriptableObject.hasProperty(target, s.index);
} else {
result = ScriptableObject.hasProperty(target, s.stringId);
}
}
return result;
}
public static Object refGet(Ref ref, Context cx) {
return ref.get(cx);
}
/** @deprecated Use {@link #refSet(Ref, Object, Context, Scriptable)} instead */
@Deprecated
public static Object refSet(Ref ref, Object value, Context cx) {
return refSet(ref, value, cx, getTopCallScope(cx));
}
public static Object refSet(Ref ref, Object value, Context cx, Scriptable scope) {
return ref.set(cx, scope, value);
}
public static Object refDel(Ref ref, Context cx) {
return wrapBoolean(ref.delete(cx));
}
static boolean isSpecialProperty(String s) {
return s.equals("__proto__") || s.equals("__parent__");
}
/** @deprecated Use {@link #specialRef(Object, String, Context, Scriptable)} instead */
@Deprecated
public static Ref specialRef(Object obj, String specialProperty, Context cx) {
return specialRef(obj, specialProperty, cx, getTopCallScope(cx));
}
public static Ref specialRef(Object obj, String specialProperty, Context cx, Scriptable scope) {
return SpecialRef.createSpecial(cx, scope, obj, specialProperty);
}
/** @deprecated Use {@link #delete(Object, Object, Context, Scriptable, boolean)} instead */
@Deprecated
public static Object delete(Object obj, Object id, Context cx) {
return delete(obj, id, cx, false);
}
/**
* The delete operator
*
* <p>See ECMA 11.4.1
*
* <p>In ECMA 0.19, the description of the delete operator (11.4.1) assumes that the [[Delete]]
* method returns a value. However, the definition of the [[Delete]] operator (8.6.2.5) does not
* define a return value. Here we assume that the [[Delete]] method doesn't return a value.
*
* @deprecated Use {@link #delete(Object, Object, Context, Scriptable, boolean)} instead
*/
@Deprecated
public static Object delete(Object obj, Object id, Context cx, boolean isName) {
return delete(obj, id, cx, getTopCallScope(cx), isName);
}
/**
* The delete operator
*
* <p>See ECMA 11.4.1
*
* <p>In ECMA 0.19, the description of the delete operator (11.4.1) assumes that the [[Delete]]
* method returns a value. However, the definition of the [[Delete]] operator (8.6.2.5) does not
* define a return value. Here we assume that the [[Delete]] method doesn't return a value.
*/
public static Object delete(
Object obj, Object id, Context cx, Scriptable scope, boolean isName) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
if (isName) {
return Boolean.TRUE;
}
throw undefDeleteError(obj, id);
}
boolean result = deleteObjectElem(sobj, id, cx);
return wrapBoolean(result);
}
/** Looks up a name in the scope chain and returns its value. */
public static Object name(Context cx, Scriptable scope, String name) {
Scriptable parent = scope.getParentScope();
if (parent == null) {
Object result = topScopeName(cx, scope, name);
if (result == Scriptable.NOT_FOUND) {
throw notFoundError(scope, name);
}
return result;
}
return nameOrFunction(cx, scope, parent, name, false);
}
private static Object nameOrFunction(
Context cx,
Scriptable scope,
Scriptable parentScope,
String name,
boolean asFunctionCall) {
Object result;
Scriptable thisObj = scope; // It is used only if asFunctionCall==true.
XMLObject firstXMLObject = null;
for (; ; ) {
if (scope instanceof NativeWith) {
Scriptable withObj = scope.getPrototype();
if (withObj instanceof XMLObject) {
XMLObject xmlObj = (XMLObject) withObj;
if (xmlObj.has(name, xmlObj)) {
// function this should be the target object of with
thisObj = xmlObj;
result = xmlObj.get(name, xmlObj);
break;
}
if (firstXMLObject == null) {
firstXMLObject = xmlObj;
}
} else {
result = ScriptableObject.getProperty(withObj, name);
if (result != Scriptable.NOT_FOUND) {
// function this should be the target object of with
thisObj = withObj;
break;
}
}
} else if (scope instanceof NativeCall) {
// NativeCall does not prototype chain and Scriptable.get
// can be called directly.
result = scope.get(name, scope);
if (result != Scriptable.NOT_FOUND) {
if (asFunctionCall) {
// ECMA 262 requires that this for nested funtions
// should be top scope
thisObj = ScriptableObject.getTopLevelScope(parentScope);
}
break;
}
} else {
// Can happen if Rhino embedding decided that nested
// scopes are useful for what ever reasons.
result = ScriptableObject.getProperty(scope, name);
if (result != Scriptable.NOT_FOUND) {
thisObj = scope;
break;
}
}
scope = parentScope;
parentScope = parentScope.getParentScope();
if (parentScope == null) {
result = topScopeName(cx, scope, name);
if (result == Scriptable.NOT_FOUND) {
if (firstXMLObject == null || asFunctionCall) {
throw notFoundError(scope, name);
}
// The name was not found, but we did find an XML
// object in the scope chain and we are looking for name,
// not function. The result should be an empty XMLList
// in name context.
result = firstXMLObject.get(name, firstXMLObject);
}
// For top scope thisObj for functions is always scope itself.
thisObj = scope;
break;
}
}
if (asFunctionCall) {
if (!(result instanceof Callable)) {
throw notFunctionError(result, name);
}
storeScriptable(cx, thisObj);
}
return result;
}
private static Object topScopeName(Context cx, Scriptable scope, String name) {
if (cx.useDynamicScope) {
scope = checkDynamicScope(cx.topCallScope, scope);
}
return ScriptableObject.getProperty(scope, name);
}
/**
* Returns the object in the scope chain that has a given property.
*
* <p>The order of evaluation of an assignment expression involves evaluating the lhs to a
* reference, evaluating the rhs, and then modifying the reference with the rhs value. This
* method is used to 'bind' the given name to an object containing that property so that the
* side effects of evaluating the rhs do not affect which property is modified. Typically used
* in conjunction with setName.
*
* <p>See ECMA 10.1.4
*/
public static Scriptable bind(Context cx, Scriptable scope, String id) {
Scriptable firstXMLObject = null;
Scriptable parent = scope.getParentScope();
childScopesChecks:
if (parent != null) {
// Check for possibly nested "with" scopes first
while (scope instanceof NativeWith) {
Scriptable withObj = scope.getPrototype();
if (withObj instanceof XMLObject) {
XMLObject xmlObject = (XMLObject) withObj;
if (xmlObject.has(cx, id)) {
return xmlObject;
}
if (firstXMLObject == null) {
firstXMLObject = xmlObject;
}
} else {
if (ScriptableObject.hasProperty(withObj, id)) {
return withObj;
}
}
scope = parent;
parent = parent.getParentScope();
if (parent == null) {
break childScopesChecks;
}
}
for (; ; ) {
if (ScriptableObject.hasProperty(scope, id)) {
return scope;
}
scope = parent;
parent = parent.getParentScope();
if (parent == null) {
break childScopesChecks;
}
}
}
// scope here is top scope
if (cx.useDynamicScope) {
scope = checkDynamicScope(cx.topCallScope, scope);
}
if (ScriptableObject.hasProperty(scope, id)) {
return scope;
}
// Nothing was found, but since XML objects always bind
// return one if found
return firstXMLObject;
}
public static Object setName(
Scriptable bound, Object value, Context cx, Scriptable scope, String id) {
if (bound != null) {
// TODO: we used to special-case XMLObject here, but putProperty
// seems to work for E4X and it's better to optimize the common case
ScriptableObject.putProperty(bound, id, value);
} else {
// "newname = 7;", where 'newname' has not yet
// been defined, creates a new property in the
// top scope unless strict mode is specified.
if (cx.hasFeature(Context.FEATURE_STRICT_MODE)
|| cx.hasFeature(Context.FEATURE_STRICT_VARS)) {
Context.reportWarning(ScriptRuntime.getMessageById("msg.assn.create.strict", id));
}
// Find the top scope by walking up the scope chain.
bound = ScriptableObject.getTopLevelScope(scope);
if (cx.useDynamicScope) {
bound = checkDynamicScope(cx.topCallScope, bound);
}
bound.put(id, bound, value);
}
return value;
}
public static Object strictSetName(
Scriptable bound, Object value, Context cx, Scriptable scope, String id) {
if (bound != null) {
// TODO: The LeftHandSide also may not be a reference to a
// data property with the attribute value {[[Writable]]:false},
// to an accessor property with the attribute value
// {[[Put]]:undefined}, nor to a non-existent property of an
// object whose [[Extensible]] internal property has the value
// false. In these cases a TypeError exception is thrown (11.13.1).
// TODO: we used to special-case XMLObject here, but putProperty
// seems to work for E4X and we should optimize the common case
ScriptableObject.putProperty(bound, id, value);
return value;
}
// See ES5 8.7.2
String msg = "Assignment to undefined \"" + id + "\" in strict mode";
throw constructError("ReferenceError", msg);
}
public static Object setConst(Scriptable bound, Object value, Context cx, String id) {
if (bound instanceof XMLObject) {
bound.put(id, bound, value);
} else {
ScriptableObject.putConstProperty(bound, id, value);
}
return value;
}
/**
* This is the enumeration needed by the for..in statement.
*
* <p>See ECMA 12.6.3.
*
* <p>IdEnumeration maintains a ObjToIntMap to make sure a given id is enumerated only once
* across multiple objects in a prototype chain.
*
* <p>XXX - ECMA delete doesn't hide properties in the prototype, but js/ref does. This means
* that the js/ref for..in can avoid maintaining a hash table and instead perform lookups to see
* if a given property has already been enumerated.
*/
private static class IdEnumeration implements Serializable {
private static final long serialVersionUID = 1L;
Scriptable obj;
Object[] ids;
ObjToIntMap used;
Object currentId;
int index;
int enumType; /* one of ENUM_INIT_KEYS, ENUM_INIT_VALUES,
ENUM_INIT_ARRAY, ENUMERATE_VALUES_IN_ORDER */
// if true, integer ids will be returned as numbers rather than strings
boolean enumNumbers;
Scriptable iterator;
}
public static Scriptable toIterator(
Context cx, Scriptable scope, Scriptable obj, boolean keyOnly) {
if (ScriptableObject.hasProperty(obj, NativeIterator.ITERATOR_PROPERTY_NAME)) {
Object v = ScriptableObject.getProperty(obj, NativeIterator.ITERATOR_PROPERTY_NAME);
if (!(v instanceof Callable)) {
throw typeErrorById("msg.invalid.iterator");
}
Callable f = (Callable) v;
Object[] args = new Object[] {keyOnly ? Boolean.TRUE : Boolean.FALSE};
v = f.call(cx, scope, obj, args);
if (!(v instanceof Scriptable)) {
throw typeErrorById("msg.iterator.primitive");
}
return (Scriptable) v;
}
return null;
}
/**
* For backwards compatibility with generated class files
*
* @deprecated Use {@link #enumInit(Object, Context, Scriptable, int)} instead
*/
@Deprecated
public static Object enumInit(Object value, Context cx, boolean enumValues) {
return enumInit(value, cx, enumValues ? ENUMERATE_VALUES : ENUMERATE_KEYS);
}
public static final int ENUMERATE_KEYS = 0;
public static final int ENUMERATE_VALUES = 1;
public static final int ENUMERATE_ARRAY = 2;
public static final int ENUMERATE_KEYS_NO_ITERATOR = 3;
public static final int ENUMERATE_VALUES_NO_ITERATOR = 4;
public static final int ENUMERATE_ARRAY_NO_ITERATOR = 5;
public static final int ENUMERATE_VALUES_IN_ORDER = 6;
/** @deprecated Use {@link #enumInit(Object, Context, Scriptable, int)} instead */
@Deprecated
public static Object enumInit(Object value, Context cx, int enumType) {
return enumInit(value, cx, getTopCallScope(cx), enumType);
}
public static Object enumInit(Object value, Context cx, Scriptable scope, int enumType) {
IdEnumeration x = new IdEnumeration();
x.obj = toObjectOrNull(cx, value, scope);
// "for of" loop
if (enumType == ENUMERATE_VALUES_IN_ORDER) {
x.enumType = enumType;
x.iterator = null;
return enumInitInOrder(cx, x);
}
if (x.obj == null) {
// null or undefined do not cause errors but rather lead to empty
// "for in" loop
return x;
}
x.enumType = enumType;
x.iterator = null;
if (enumType != ENUMERATE_KEYS_NO_ITERATOR
&& enumType != ENUMERATE_VALUES_NO_ITERATOR
&& enumType != ENUMERATE_ARRAY_NO_ITERATOR) {
x.iterator =
toIterator(
cx,
x.obj.getParentScope(),
x.obj,
enumType == ScriptRuntime.ENUMERATE_KEYS);
}
if (x.iterator == null) {
// enumInit should read all initial ids before returning
// or "for (a.i in a)" would wrongly enumerate i in a as well
enumChangeObject(x);
}
return x;
}
private static Object enumInitInOrder(Context cx, IdEnumeration x) {
if (!(x.obj instanceof SymbolScriptable)
|| !ScriptableObject.hasProperty(x.obj, SymbolKey.ITERATOR)) {
throw typeErrorById("msg.not.iterable", toString(x.obj));
}
Object iterator = ScriptableObject.getProperty(x.obj, SymbolKey.ITERATOR);
if (!(iterator instanceof Callable)) {
throw typeErrorById("msg.not.iterable", toString(x.obj));
}
Callable f = (Callable) iterator;
Scriptable scope = x.obj.getParentScope();
Object[] args = new Object[] {};
Object v = f.call(cx, scope, x.obj, args);
if (!(v instanceof Scriptable)) {
throw typeErrorById("msg.not.iterable", toString(x.obj));
}
x.iterator = (Scriptable) v;
return x;
}
public static void setEnumNumbers(Object enumObj, boolean enumNumbers) {
((IdEnumeration) enumObj).enumNumbers = enumNumbers;
}
public static Boolean enumNext(Object enumObj) {
IdEnumeration x = (IdEnumeration) enumObj;
if (x.iterator != null) {
if (x.enumType == ENUMERATE_VALUES_IN_ORDER) {
return enumNextInOrder(x);
}
Object v = ScriptableObject.getProperty(x.iterator, "next");
if (!(v instanceof Callable)) return Boolean.FALSE;
Callable f = (Callable) v;
Context cx = Context.getContext();
try {
x.currentId = f.call(cx, x.iterator.getParentScope(), x.iterator, emptyArgs);
return Boolean.TRUE;
} catch (JavaScriptException e) {
if (e.getValue() instanceof NativeIterator.StopIteration) {
return Boolean.FALSE;
}
throw e;
}
}
for (; ; ) {
if (x.obj == null) {
return Boolean.FALSE;
}
if (x.index == x.ids.length) {
x.obj = x.obj.getPrototype();
enumChangeObject(x);
continue;
}
Object id = x.ids[x.index++];
if (x.used != null && x.used.has(id)) {
continue;
}
if (id instanceof Symbol) {
continue;
} else if (id instanceof String) {
String strId = (String) id;
if (!x.obj.has(strId, x.obj)) continue; // must have been deleted
x.currentId = strId;
} else {
int intId = ((Number) id).intValue();
if (!x.obj.has(intId, x.obj)) continue; // must have been deleted
x.currentId =
x.enumNumbers ? (Object) (Integer.valueOf(intId)) : String.valueOf(intId);
}
return Boolean.TRUE;
}
}
private static Boolean enumNextInOrder(IdEnumeration enumObj) {
Object v = ScriptableObject.getProperty(enumObj.iterator, ES6Iterator.NEXT_METHOD);
if (!(v instanceof Callable)) {
throw notFunctionError(enumObj.iterator, ES6Iterator.NEXT_METHOD);
}
Callable f = (Callable) v;
Context cx = Context.getContext();
Scriptable scope = enumObj.iterator.getParentScope();
Object r = f.call(cx, scope, enumObj.iterator, emptyArgs);
Scriptable iteratorResult = toObject(cx, scope, r);
Object done = ScriptableObject.getProperty(iteratorResult, ES6Iterator.DONE_PROPERTY);
if (done != Scriptable.NOT_FOUND && toBoolean(done)) {
return Boolean.FALSE;
}
enumObj.currentId =
ScriptableObject.getProperty(iteratorResult, ES6Iterator.VALUE_PROPERTY);
return Boolean.TRUE;
}
public static Object enumId(Object enumObj, Context cx) {
IdEnumeration x = (IdEnumeration) enumObj;
if (x.iterator != null) {
return x.currentId;
}
switch (x.enumType) {
case ENUMERATE_KEYS:
case ENUMERATE_KEYS_NO_ITERATOR:
return x.currentId;
case ENUMERATE_VALUES:
case ENUMERATE_VALUES_NO_ITERATOR:
return enumValue(enumObj, cx);
case ENUMERATE_ARRAY:
case ENUMERATE_ARRAY_NO_ITERATOR:
Object[] elements = {x.currentId, enumValue(enumObj, cx)};
return cx.newArray(ScriptableObject.getTopLevelScope(x.obj), elements);
default:
throw Kit.codeBug();
}
}
public static Object enumValue(Object enumObj, Context cx) {
IdEnumeration x = (IdEnumeration) enumObj;
Object result;
if (isSymbol(x.currentId)) {
SymbolScriptable so = ScriptableObject.ensureSymbolScriptable(x.obj);
result = so.get((Symbol) x.currentId, x.obj);
} else {
StringIdOrIndex s = toStringIdOrIndex(cx, x.currentId);
if (s.stringId == null) {
result = x.obj.get(s.index, x.obj);
} else {
result = x.obj.get(s.stringId, x.obj);
}
}
return result;
}
private static void enumChangeObject(IdEnumeration x) {
Object[] ids = null;
while (x.obj != null) {
ids = x.obj.getIds();
if (ids.length != 0) {
break;
}
x.obj = x.obj.getPrototype();
}
if (x.obj != null && x.ids != null) {
Object[] previous = x.ids;
int L = previous.length;
if (x.used == null) {
x.used = new ObjToIntMap(L);
}
for (int i = 0; i != L; ++i) {
x.used.intern(previous[i]);
}
}
x.ids = ids;
x.index = 0;
}
/**
* This is used to handle all the special cases that are required when invoking
* Object.fromEntries or constructing a NativeMap or NativeWeakMap from an iterable.
*
* @param cx the current context
* @param scope the current scope
* @param arg1 the iterable object.
* @param setter the setter to set the value
* @return true, if arg1 was iterable.
*/
public static boolean loadFromIterable(
Context cx, Scriptable scope, Object arg1, BiConsumer<Object, Object> setter) {
if ((arg1 == null) || Undefined.isUndefined(arg1)) return false;
// Call the "[Symbol.iterator]" property as a function.
final Object ito = ScriptRuntime.callIterator(arg1, cx, scope);
if (Undefined.isUndefined(ito)) {
// Per spec, ignore if the iterator is undefined
return false;
}
// Finally, run through all the iterated values and add them!
try (IteratorLikeIterable it = new IteratorLikeIterable(cx, scope, ito)) {
for (Object val : it) {
Scriptable sVal = ScriptableObject.ensureScriptable(val);
if (sVal instanceof Symbol) {
throw ScriptRuntime.typeErrorById(
"msg.arg.not.object", ScriptRuntime.typeof(sVal));
}
Object finalKey = sVal.get(0, sVal);
if (finalKey == Scriptable.NOT_FOUND) {
finalKey = Undefined.instance;
}
Object finalVal = sVal.get(1, sVal);
if (finalVal == Scriptable.NOT_FOUND) {
finalVal = Undefined.instance;
}
setter.accept(finalKey, finalVal);
}
}
return true;
}
/**
* Prepare for calling name(...): return function corresponding to name and make current top
* scope available as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. The
* caller must call ScriptRuntime.lastStoredScriptable() immediately after calling this method.
*/
public static Callable getNameFunctionAndThis(String name, Context cx, Scriptable scope) {
Scriptable parent = scope.getParentScope();
if (parent == null) {
Object result = topScopeName(cx, scope, name);
if (!(result instanceof Callable)) {
if (result == Scriptable.NOT_FOUND) {
throw notFoundError(scope, name);
}
throw notFunctionError(result, name);
}
// Top scope is not NativeWith or NativeCall => thisObj == scope
Scriptable thisObj = scope;
storeScriptable(cx, thisObj);
return (Callable) result;
}
// name will call storeScriptable(cx, thisObj);
return (Callable) nameOrFunction(cx, scope, parent, name, true);
}
/**
* Prepare for calling obj[id](...): return function corresponding to obj[id] and make obj
* properly converted to Scriptable available as ScriptRuntime.lastStoredScriptable() for
* consumption as thisObj. The caller must call ScriptRuntime.lastStoredScriptable() immediately
* after calling this method.
*
* @deprecated Use {@link #getElemFunctionAndThis(Object, Object, Context, Scriptable)} instead
*/
@Deprecated
public static Callable getElemFunctionAndThis(Object obj, Object elem, Context cx) {
return getElemFunctionAndThis(obj, elem, cx, getTopCallScope(cx));
}
/**
* Prepare for calling obj[id](...): return function corresponding to obj[id] and make obj
* properly converted to Scriptable available as ScriptRuntime.lastStoredScriptable() for
* consumption as thisObj. The caller must call ScriptRuntime.lastStoredScriptable() immediately
* after calling this method.
*/
public static Callable getElemFunctionAndThis(
Object obj, Object elem, Context cx, Scriptable scope) {
Scriptable thisObj;
Object value;
if (isSymbol(elem)) {
thisObj = toObjectOrNull(cx, obj, scope);
if (thisObj == null) {
throw undefCallError(obj, String.valueOf(elem));
}
value = ScriptableObject.getProperty(thisObj, (Symbol) elem);
} else {
StringIdOrIndex s = toStringIdOrIndex(cx, elem);
if (s.stringId != null) {
return getPropFunctionAndThis(obj, s.stringId, cx, scope);
}
thisObj = toObjectOrNull(cx, obj, scope);
if (thisObj == null) {
throw undefCallError(obj, String.valueOf(elem));
}
value = ScriptableObject.getProperty(thisObj, s.index);
}
if (!(value instanceof Callable)) {
throw notFunctionError(value, elem);
}
storeScriptable(cx, thisObj);
return (Callable) value;
}
/**
* Prepare for calling obj.property(...): return function corresponding to obj.property and make
* obj properly converted to Scriptable available as ScriptRuntime.lastStoredScriptable() for
* consumption as thisObj. The caller must call ScriptRuntime.lastStoredScriptable() immediately
* after calling this method. Warning: this doesn't allow to resolve primitive prototype
* properly when many top scopes are involved.
*
* @deprecated Use {@link #getPropFunctionAndThis(Object, String, Context, Scriptable)} instead
*/
@Deprecated
public static Callable getPropFunctionAndThis(Object obj, String property, Context cx) {
return getPropFunctionAndThis(obj, property, cx, getTopCallScope(cx));
}
/**
* Prepare for calling obj.property(...): return function corresponding to obj.property and make
* obj properly converted to Scriptable available as ScriptRuntime.lastStoredScriptable() for
* consumption as thisObj. The caller must call ScriptRuntime.lastStoredScriptable() immediately
* after calling this method.
*/
public static Callable getPropFunctionAndThis(
Object obj, String property, Context cx, Scriptable scope) {
Scriptable thisObj = toObjectOrNull(cx, obj, scope);
return getPropFunctionAndThisHelper(obj, property, cx, thisObj);
}
private static Callable getPropFunctionAndThisHelper(
Object obj, String property, Context cx, Scriptable thisObj) {
if (thisObj == null) {
throw undefCallError(obj, property);
}
Object value = ScriptableObject.getProperty(thisObj, property);
if (!(value instanceof Callable)) {
Object noSuchMethod = ScriptableObject.getProperty(thisObj, "__noSuchMethod__");
if (noSuchMethod instanceof Callable)
value = new NoSuchMethodShim((Callable) noSuchMethod, property);
}
if (!(value instanceof Callable)) {
throw notFunctionError(thisObj, value, property);
}
storeScriptable(cx, thisObj);
return (Callable) value;
}
/**
* Prepare for calling <expression>(...): return function corresponding to
* <expression> and make parent scope of the function available as
* ScriptRuntime.lastStoredScriptable() for consumption as thisObj. The caller must call
* ScriptRuntime.lastStoredScriptable() immediately after calling this method.
*/
public static Callable getValueFunctionAndThis(Object value, Context cx) {
if (!(value instanceof Callable)) {
throw notFunctionError(value);
}
Callable f = (Callable) value;
Scriptable thisObj = null;
if (f instanceof Scriptable) {
thisObj = ((Scriptable) f).getParentScope();
}
if (thisObj == null) {
if (cx.topCallScope == null) throw new IllegalStateException();
thisObj = cx.topCallScope;
}
if (thisObj.getParentScope() != null) {
if (thisObj instanceof NativeWith) {
// functions defined inside with should have with target
// as their thisObj
} else if (thisObj instanceof NativeCall) {
// nested functions should have top scope as their thisObj
thisObj = ScriptableObject.getTopLevelScope(thisObj);
}
}
storeScriptable(cx, thisObj);
return f;
}
/**
* Given an object, get the "Symbol.iterator" element, throw a TypeError if it is not present,
* then call the result, (throwing a TypeError if the result is not a function), and return that
* result, whatever it is.
*/
public static Object callIterator(Object obj, Context cx, Scriptable scope) {
final Callable getIterator =
ScriptRuntime.getElemFunctionAndThis(obj, SymbolKey.ITERATOR, cx, scope);
final Scriptable iterable = ScriptRuntime.lastStoredScriptable(cx);
return getIterator.call(cx, scope, iterable, ScriptRuntime.emptyArgs);
}
/**
* Given an iterator result, return true if and only if there is a "done" property that's true.
*/
public static boolean isIteratorDone(Context cx, Object result) {
if (!(result instanceof Scriptable)) {
return false;
}
final Object prop = getObjectProp((Scriptable) result, ES6Iterator.DONE_PROPERTY, cx);
return toBoolean(prop);
}
/**
* Perform function call in reference context. Should always return value that can be passed to
* {@link #refGet(Ref, Context)} or {@link #refSet(Ref, Object, Context)} arbitrary number of
* times. The args array reference should not be stored in any object that is can be
* GC-reachable after this method returns. If this is necessary, store args.clone(), not args
* array itself.
*/
public static Ref callRef(Callable function, Scriptable thisObj, Object[] args, Context cx) {
if (function instanceof RefCallable) {
RefCallable rfunction = (RefCallable) function;
Ref ref = rfunction.refCall(cx, thisObj, args);
if (ref == null) {
throw new IllegalStateException(
rfunction.getClass().getName() + ".refCall() returned null");
}
return ref;
}
// No runtime support for now
String msg = getMessageById("msg.no.ref.from.function", toString(function));
throw constructError("ReferenceError", msg);
}
/**
* Operator new.
*
* <p>See ECMA 11.2.2
*/
public static Scriptable newObject(Object fun, Context cx, Scriptable scope, Object[] args) {
if (!(fun instanceof Function)) {
throw notFunctionError(fun);
}
Function function = (Function) fun;
return function.construct(cx, scope, args);
}
public static Object callSpecial(
Context cx,
Callable fun,
Scriptable thisObj,
Object[] args,
Scriptable scope,
Scriptable callerThis,
int callType,
String filename,
int lineNumber) {
if (callType == Node.SPECIALCALL_EVAL) {
if (thisObj.getParentScope() == null && NativeGlobal.isEvalFunction(fun)) {
return evalSpecial(cx, scope, callerThis, args, filename, lineNumber);
}
} else if (callType == Node.SPECIALCALL_WITH) {
if (NativeWith.isWithFunction(fun)) {
throw Context.reportRuntimeErrorById("msg.only.from.new", "With");
}
} else {
throw Kit.codeBug();
}
return fun.call(cx, scope, thisObj, args);
}
public static Object newSpecial(
Context cx, Object fun, Object[] args, Scriptable scope, int callType) {
if (callType == Node.SPECIALCALL_EVAL) {
if (NativeGlobal.isEvalFunction(fun)) {
throw typeErrorById("msg.not.ctor", "eval");
}
} else if (callType == Node.SPECIALCALL_WITH) {
if (NativeWith.isWithFunction(fun)) {
return NativeWith.newWithSpecial(cx, scope, args);
}
} else {
throw Kit.codeBug();
}
return newObject(fun, cx, scope, args);
}
/**
* Function.prototype.apply and Function.prototype.call
*
* <p>See Ecma 15.3.4.[34]
*/
public static Object applyOrCall(
boolean isApply, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
int L = args.length;
Callable function = getCallable(thisObj);
Scriptable callThis = null;
if (L != 0) {
if (cx.hasFeature(Context.FEATURE_OLD_UNDEF_NULL_THIS)) {
callThis = toObjectOrNull(cx, args[0], scope);
} else {
callThis =
args[0] == Undefined.instance
? Undefined.SCRIPTABLE_UNDEFINED
: toObjectOrNull(cx, args[0], scope);
}
}
if (callThis == null && cx.hasFeature(Context.FEATURE_OLD_UNDEF_NULL_THIS)) {
callThis =
getTopCallScope(
cx); // This covers the case of args[0] == (null|undefined) as well.
}
Object[] callArgs;
if (isApply) {
// Follow Ecma 15.3.4.3
callArgs = L <= 1 ? ScriptRuntime.emptyArgs : getApplyArguments(cx, args[1]);
} else {
// Follow Ecma 15.3.4.4
if (L <= 1) {
callArgs = ScriptRuntime.emptyArgs;
} else {
callArgs = new Object[L - 1];
System.arraycopy(args, 1, callArgs, 0, L - 1);
}
}
return function.call(cx, scope, callThis, callArgs);
}
/** @return true if the passed in Scriptable looks like an array */
private static boolean isArrayLike(Scriptable obj) {
return obj != null
&& (obj instanceof NativeArray
|| obj instanceof Arguments
|| ScriptableObject.hasProperty(obj, "length"));
}
static Object[] getApplyArguments(Context cx, Object arg1) {
if (arg1 == null || Undefined.isUndefined(arg1)) {
return ScriptRuntime.emptyArgs;
} else if (arg1 instanceof Scriptable && isArrayLike((Scriptable) arg1)) {
return cx.getElements((Scriptable) arg1);
} else if (arg1 instanceof ScriptableObject) {
return ScriptRuntime.emptyArgs;
} else {
throw ScriptRuntime.typeErrorById("msg.arg.isnt.array");
}
}
static Callable getCallable(Scriptable thisObj) {
Callable function;
if (thisObj instanceof Callable) {
function = (Callable) thisObj;
} else if (thisObj == null) {
throw ScriptRuntime.notFunctionError(null, null);
} else {
Object value = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);
if (!(value instanceof Callable)) {
throw ScriptRuntime.notFunctionError(value, thisObj);
}
function = (Callable) value;
}
return function;
}
/**
* The eval function property of the global object.
*
* <p>See ECMA 15.1.2.1
*/
public static Object evalSpecial(
Context cx,
Scriptable scope,
Object thisArg,
Object[] args,
String filename,
int lineNumber) {
if (args.length < 1) return Undefined.instance;
Object x = args[0];
if (!(x instanceof CharSequence)) {
if (cx.hasFeature(Context.FEATURE_STRICT_MODE)
|| cx.hasFeature(Context.FEATURE_STRICT_EVAL)) {
throw Context.reportRuntimeErrorById("msg.eval.nonstring.strict");
}
String message = ScriptRuntime.getMessageById("msg.eval.nonstring");
Context.reportWarning(message);
return x;
}
if (filename == null) {
int[] linep = new int[1];
filename = Context.getSourcePositionFromStack(linep);
if (filename != null) {
lineNumber = linep[0];
} else {
filename = "";
}
}
String sourceName = ScriptRuntime.makeUrlForGeneratedScript(true, filename, lineNumber);
ErrorReporter reporter;
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
Evaluator evaluator = Context.createInterpreter();
if (evaluator == null) {
throw new JavaScriptException("Interpreter not present", filename, lineNumber);
}
// Compile with explicit interpreter instance to force interpreter
// mode.
Script script = cx.compileString(x.toString(), evaluator, reporter, sourceName, 1, null);
evaluator.setEvalScriptFlag(script);
Callable c = (Callable) script;
return c.call(cx, scope, (Scriptable) thisArg, ScriptRuntime.emptyArgs);
}
/** The typeof operator */
public static String typeof(Object value) {
if (value == null) return "object";
if (value == Undefined.instance) return "undefined";
if (value instanceof Delegator) return typeof(((Delegator) value).getDelegee());
if (value instanceof ScriptableObject) return ((ScriptableObject) value).getTypeOf();
if (value instanceof Scriptable) return (value instanceof Callable) ? "function" : "object";
if (value instanceof CharSequence) return "string";
if (value instanceof BigInteger) return "bigint";
if (value instanceof Number) return "number";
if (value instanceof Boolean) return "boolean";
throw errorWithClassName("msg.invalid.type", value);
}
/** The typeof operator that correctly handles the undefined case */
public static String typeofName(Scriptable scope, String id) {
Context cx = Context.getContext();
Scriptable val = bind(cx, scope, id);
if (val == null) return "undefined";
return typeof(getObjectProp(val, id, cx));
}
public static boolean isObject(Object value) {
if (value == null) {
return false;
}
if (Undefined.isUndefined(value)) {
return false;
}
if (value instanceof ScriptableObject) {
String type = ((ScriptableObject) value).getTypeOf();
return "object".equals(type) || "function".equals(type);
}
if (value instanceof Scriptable) {
return (!(value instanceof Callable));
}
return false;
}
// neg:
// implement the '-' operator inline in the caller
// as "-toNumber(val)"
// not:
// implement the '!' operator inline in the caller
// as "!toBoolean(val)"
// bitnot:
// implement the '~' operator inline in the caller
// as "~toInt32(val)"
public static Object add(Object val1, Object val2, Context cx) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return ((BigInteger) val1).add((BigInteger) val2);
}
if ((val1 instanceof Number && val2 instanceof BigInteger)
|| (val1 instanceof BigInteger && val2 instanceof Number)) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
}
if (val1 instanceof Number && val2 instanceof Number) {
return wrapNumber(((Number) val1).doubleValue() + ((Number) val2).doubleValue());
}
if (val1 instanceof CharSequence && val2 instanceof CharSequence) {
// If we let this happen later, then the "getDefaultValue" logic
// undoes many optimizations
return new ConsString((CharSequence) val1, (CharSequence) val2);
}
if (val1 instanceof XMLObject) {
Object test = ((XMLObject) val1).addValues(cx, true, val2);
if (test != Scriptable.NOT_FOUND) {
return test;
}
}
if (val2 instanceof XMLObject) {
Object test = ((XMLObject) val2).addValues(cx, false, val1);
if (test != Scriptable.NOT_FOUND) {
return test;
}
}
if ((val1 instanceof Symbol) || (val2 instanceof Symbol)) {
throw typeErrorById("msg.not.a.number");
}
if (val1 instanceof Scriptable) val1 = ((Scriptable) val1).getDefaultValue(null);
if (val2 instanceof Scriptable) val2 = ((Scriptable) val2).getDefaultValue(null);
if (!(val1 instanceof CharSequence) && !(val2 instanceof CharSequence)) {
Number num1 = val1 instanceof Number ? (Number) val1 : toNumeric(val1);
Number num2 = val2 instanceof Number ? (Number) val2 : toNumeric(val2);
if (num1 instanceof BigInteger && num2 instanceof BigInteger) {
return ((BigInteger) num1).add((BigInteger) num2);
}
if (num1 instanceof BigInteger || num2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
}
return num1.doubleValue() + num2.doubleValue();
}
return new ConsString(toCharSequence(val1), toCharSequence(val2));
}
/**
* https://262.ecma-international.org/11.0/#sec-addition-operator-plus 5. Let lprim be ?
* ToPrimitive(lval). 7. If Type(lprim) is String or Type(rprim) is String, then a. Let lstr be
* ? ToString(lprim).
*
* <p>Should call toPrimitive before toCharSequence
*
* @deprecated Use {@link #add(Object, Object, Context)} instead
*/
@Deprecated
public static CharSequence add(CharSequence val1, Object val2) {
return new ConsString(val1, toCharSequence(val2));
}
/**
* https://262.ecma-international.org/11.0/#sec-addition-operator-plus 6. Let rprim be ?
* ToPrimitive(rval). 7. If Type(lprim) is String or Type(rprim) is String, then b. Let rstr be
* ? ToString(rprim).
*
* <p>Should call toPrimitive before toCharSequence
*
* @deprecated Use {@link #add(Object, Object, Context)} instead
*/
@Deprecated
public static CharSequence add(Object val1, CharSequence val2) {
return new ConsString(toCharSequence(val1), val2);
}
public static Number subtract(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return ((BigInteger) val1).subtract((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
return val1.doubleValue() - val2.doubleValue();
}
}
public static Number multiply(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return ((BigInteger) val1).multiply((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
return val1.doubleValue() * val2.doubleValue();
}
}
public static Number divide(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
if (val2.equals(BigInteger.ZERO)) {
throw ScriptRuntime.rangeErrorById("msg.division.zero");
}
return ((BigInteger) val1).divide((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
return val1.doubleValue() / val2.doubleValue();
}
}
public static Number remainder(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
if (val2.equals(BigInteger.ZERO)) {
throw ScriptRuntime.rangeErrorById("msg.division.zero");
}
return ((BigInteger) val1).remainder((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
return val1.doubleValue() % val2.doubleValue();
}
}
public static Number exponentiate(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
if (((BigInteger) val2).signum() == -1) {
throw ScriptRuntime.rangeErrorById("msg.bigint.negative.exponent");
}
try {
int intVal2 = ((BigInteger) val2).intValueExact();
return ((BigInteger) val1).pow(intVal2);
} catch (ArithmeticException e) {
// This is outside the scope of the ECMA262 specification.
throw ScriptRuntime.rangeErrorById("msg.bigint.out.of.range.arithmetic");
}
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
return Math.pow(val1.doubleValue(), val2.doubleValue());
}
}
public static Number bitwiseAND(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return ((BigInteger) val1).and((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
int result = toInt32(val1.doubleValue()) & toInt32(val2.doubleValue());
return Double.valueOf(result);
}
}
public static Number bitwiseOR(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return ((BigInteger) val1).or((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
int result = toInt32(val1.doubleValue()) | toInt32(val2.doubleValue());
return Double.valueOf(result);
}
}
public static Number bitwiseXOR(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return ((BigInteger) val1).xor((BigInteger) val2);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
int result = toInt32(val1.doubleValue()) ^ toInt32(val2.doubleValue());
return Double.valueOf(result);
}
}
public static Number leftShift(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
try {
int intVal2 = ((BigInteger) val2).intValueExact();
return ((BigInteger) val1).shiftLeft(intVal2);
} catch (ArithmeticException e) {
// This is outside the scope of the ECMA262 specification.
throw ScriptRuntime.rangeErrorById("msg.bigint.out.of.range.arithmetic");
}
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
int result = toInt32(val1.doubleValue()) << toInt32(val2.doubleValue());
return Double.valueOf(result);
}
}
public static Number signedRightShift(Number val1, Number val2) {
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
try {
int intVal2 = ((BigInteger) val2).intValueExact();
return ((BigInteger) val1).shiftRight(intVal2);
} catch (ArithmeticException e) {
// This is outside the scope of the ECMA262 specification.
throw ScriptRuntime.rangeErrorById("msg.bigint.out.of.range.arithmetic");
}
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
throw ScriptRuntime.typeErrorById("msg.cant.convert.to.number", "BigInt");
} else {
int result = toInt32(val1.doubleValue()) >> toInt32(val2.doubleValue());
return Double.valueOf(result);
}
}
public static Number bitwiseNOT(Number val) {
if (val instanceof BigInteger) {
return ((BigInteger) val).not();
} else {
int result = ~toInt32(val.doubleValue());
return Double.valueOf(result);
}
}
/**
* The method is only present for compatibility.
*
* @deprecated Use {@link #nameIncrDecr(Scriptable, String, Context, int)} instead
*/
@Deprecated
public static Object nameIncrDecr(Scriptable scopeChain, String id, int incrDecrMask) {
return nameIncrDecr(scopeChain, id, Context.getContext(), incrDecrMask);
}
public static Object nameIncrDecr(
Scriptable scopeChain, String id, Context cx, int incrDecrMask) {
Scriptable target;
Object value;
search:
{
do {
if (cx.useDynamicScope && scopeChain.getParentScope() == null) {
scopeChain = checkDynamicScope(cx.topCallScope, scopeChain);
}
target = scopeChain;
do {
if (target instanceof NativeWith
&& target.getPrototype() instanceof XMLObject) {
break;
}
value = target.get(id, scopeChain);
if (value != Scriptable.NOT_FOUND) {
break search;
}
target = target.getPrototype();
} while (target != null);
scopeChain = scopeChain.getParentScope();
} while (scopeChain != null);
throw notFoundError(null, id);
}
return doScriptableIncrDecr(target, id, scopeChain, value, incrDecrMask);
}
/** @deprecated Use {@link #propIncrDecr(Object, String, Context, Scriptable, int)} instead */
@Deprecated
public static Object propIncrDecr(Object obj, String id, Context cx, int incrDecrMask) {
return propIncrDecr(obj, id, cx, getTopCallScope(cx), incrDecrMask);
}
public static Object propIncrDecr(
Object obj, String id, Context cx, Scriptable scope, int incrDecrMask) {
Scriptable start = toObjectOrNull(cx, obj, scope);
if (start == null) {
throw undefReadError(obj, id);
}
Scriptable target = start;
Object value;
search:
{
do {
value = target.get(id, start);
if (value != Scriptable.NOT_FOUND) {
break search;
}
target = target.getPrototype();
} while (target != null);
start.put(id, start, NaNobj);
return NaNobj;
}
return doScriptableIncrDecr(target, id, start, value, incrDecrMask);
}
private static Object doScriptableIncrDecr(
Scriptable target,
String id,
Scriptable protoChainStart,
Object value,
int incrDecrMask) {
final boolean post = (incrDecrMask & Node.POST_FLAG) != 0;
Number number;
if (value instanceof Number) {
number = (Number) value;
} else {
number = toNumeric(value);
}
Number result;
if (number instanceof BigInteger) {
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
result = ((BigInteger) number).add(BigInteger.ONE);
} else {
result = ((BigInteger) number).subtract(BigInteger.ONE);
}
} else {
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
result = number.doubleValue() + 1.0;
} else {
result = number.doubleValue() - 1.0;
}
}
target.put(id, protoChainStart, result);
if (post) {
return number;
}
return result;
}
/** @deprecated Use {@link #elemIncrDecr(Object, Object, Context, Scriptable, int)} instead */
@Deprecated
public static Object elemIncrDecr(Object obj, Object index, Context cx, int incrDecrMask) {
return elemIncrDecr(obj, index, cx, getTopCallScope(cx), incrDecrMask);
}
public static Object elemIncrDecr(
Object obj, Object index, Context cx, Scriptable scope, int incrDecrMask) {
Object value = getObjectElem(obj, index, cx, scope);
final boolean post = (incrDecrMask & Node.POST_FLAG) != 0;
Number number;
if (value instanceof Number) {
number = (Number) value;
} else {
number = toNumeric(value);
}
Number result;
if (number instanceof BigInteger) {
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
result = ((BigInteger) number).add(BigInteger.ONE);
} else {
result = ((BigInteger) number).subtract(BigInteger.ONE);
}
} else {
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
result = number.doubleValue() + 1.0;
} else {
result = number.doubleValue() - 1.0;
}
}
setObjectElem(obj, index, result, cx, scope);
if (post) {
return number;
}
return result;
}
/** @deprecated Use {@link #refIncrDecr(Ref, Context, Scriptable, int)} instead */
@Deprecated
public static Object refIncrDecr(Ref ref, Context cx, int incrDecrMask) {
return refIncrDecr(ref, cx, getTopCallScope(cx), incrDecrMask);
}
public static Object refIncrDecr(Ref ref, Context cx, Scriptable scope, int incrDecrMask) {
Object value = ref.get(cx);
boolean post = ((incrDecrMask & Node.POST_FLAG) != 0);
Number number;
if (value instanceof Number) {
number = (Number) value;
} else {
number = toNumeric(value);
}
Number result;
if (number instanceof BigInteger) {
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
result = ((BigInteger) number).add(BigInteger.ONE);
} else {
result = ((BigInteger) number).subtract(BigInteger.ONE);
}
} else {
if ((incrDecrMask & Node.DECR_FLAG) == 0) {
result = number.doubleValue() + 1.0;
} else {
result = number.doubleValue() - 1.0;
}
}
ref.set(cx, scope, result);
if (post) {
return number;
}
return result;
}
public static Number negate(Number val) {
if (val instanceof BigInteger) {
return ((BigInteger) val).negate();
}
return -val.doubleValue();
}
public static Object toPrimitive(Object val) {
return toPrimitive(val, null);
}
public static Object toPrimitive(Object val, Class<?> typeHint) {
if (!(val instanceof Scriptable)) {
return val;
}
Scriptable s = (Scriptable) val;
Object result = s.getDefaultValue(typeHint);
if ((result instanceof Scriptable) && !isSymbol(result))
throw typeErrorById("msg.bad.default.value");
return result;
}
/**
* Equality
*
* <p>See ECMA 11.9
*/
public static boolean eq(Object x, Object y) {
if (x == null || Undefined.isUndefined(x)) {
if (y == null || Undefined.isUndefined(y)) {
return true;
}
if (y instanceof ScriptableObject) {
Object test = ((ScriptableObject) y).equivalentValues(x);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
return false;
} else if (x instanceof BigInteger) {
return eqBigInt((BigInteger) x, y);
} else if (x instanceof Number) {
return eqNumber(((Number) x).doubleValue(), y);
} else if (x == y) {
return true;
} else if (x instanceof CharSequence) {
return eqString((CharSequence) x, y);
} else if (x instanceof Boolean) {
boolean b = ((Boolean) x).booleanValue();
if (y instanceof Boolean) {
return b == ((Boolean) y).booleanValue();
}
if (y instanceof ScriptableObject) {
Object test = ((ScriptableObject) y).equivalentValues(x);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
return eqNumber(b ? 1.0 : 0.0, y);
} else if (x instanceof Scriptable) {
if (x instanceof Delegator) {
x = ((Delegator) x).getDelegee();
if (y instanceof Delegator) {
return eq(x, ((Delegator) y).getDelegee());
}
if (x == y) {
return true;
}
}
if (y instanceof Delegator && ((Delegator) y).getDelegee() == x) {
return true;
}
if (y instanceof Scriptable) {
if (x instanceof ScriptableObject) {
Object test = ((ScriptableObject) x).equivalentValues(y);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
if (y instanceof ScriptableObject) {
Object test = ((ScriptableObject) y).equivalentValues(x);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
if (x instanceof Wrapper && y instanceof Wrapper) {
// See bug 413838. Effectively an extension to ECMA for
// the LiveConnect case.
Object unwrappedX = ((Wrapper) x).unwrap();
Object unwrappedY = ((Wrapper) y).unwrap();
return unwrappedX == unwrappedY
|| (isPrimitive(unwrappedX)
&& isPrimitive(unwrappedY)
&& eq(unwrappedX, unwrappedY));
}
return false;
} else if (y instanceof Boolean) {
if (x instanceof ScriptableObject) {
Object test = ((ScriptableObject) x).equivalentValues(y);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
double d = ((Boolean) y).booleanValue() ? 1.0 : 0.0;
return eqNumber(d, x);
} else if (y instanceof BigInteger) {
return eqBigInt((BigInteger) y, x);
} else if (y instanceof Number) {
return eqNumber(((Number) y).doubleValue(), x);
} else if (y instanceof CharSequence) {
return eqString((CharSequence) y, x);
}
// covers the case when y == Undefined.instance as well
return false;
} else {
warnAboutNonJSObject(x);
return x == y;
}
}
/*
* Implement "SameValue" as in ECMA 7.2.9. This is not the same as "eq" because it handles
* signed zeroes and NaNs differently.
*/
public static boolean same(Object x, Object y) {
if (!typeof(x).equals(typeof(y))) {
return false;
}
if (x instanceof Number) {
if (isNaN(x) && isNaN(y)) {
return true;
}
return x.equals(y);
}
return eq(x, y);
}
/** Implement "SameValueZero" from ECMA 7.2.9 */
public static boolean sameZero(Object x, Object y) {
if (!typeof(x).equals(typeof(y))) {
return false;
}
if (x instanceof BigInteger) {
return x.equals(y);
}
if (x instanceof Number) {
if (isNaN(x) && isNaN(y)) {
return true;
}
final double dx = ((Number) x).doubleValue();
if (y instanceof Number) {
final double dy = ((Number) y).doubleValue();
if (((dx == negativeZero) && (dy == 0.0)) || ((dx == 0.0) && dy == negativeZero)) {
return true;
}
}
return eqNumber(dx, y);
}
return eq(x, y);
}
public static boolean isNaN(Object n) {
if (n instanceof Double) {
return ((Double) n).isNaN();
}
if (n instanceof Float) {
return ((Float) n).isNaN();
}
return false;
}
public static boolean isPrimitive(Object obj) {
return obj == null
|| Undefined.isUndefined(obj)
|| (obj instanceof Number)
|| (obj instanceof String)
|| (obj instanceof Boolean);
}
static boolean eqNumber(double x, Object y) {
for (; ; ) {
if (y == null || Undefined.isUndefined(y)) {
return false;
} else if (y instanceof BigInteger) {
return eqBigInt((BigInteger) y, x);
} else if (y instanceof Number) {
return x == ((Number) y).doubleValue();
} else if (y instanceof CharSequence) {
return x == toNumber(y);
} else if (y instanceof Boolean) {
return x == (((Boolean) y).booleanValue() ? 1.0 : +0.0);
} else if (isSymbol(y)) {
return false;
} else if (y instanceof Scriptable) {
if (y instanceof ScriptableObject) {
Object xval = wrapNumber(x);
Object test = ((ScriptableObject) y).equivalentValues(xval);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
y = toPrimitive(y);
} else {
warnAboutNonJSObject(y);
return false;
}
}
}
static boolean eqBigInt(BigInteger x, Object y) {
for (; ; ) {
if (y == null || Undefined.isUndefined(y)) {
return false;
} else if (y instanceof BigInteger) {
return x.equals(y);
} else if (y instanceof Number) {
return eqBigInt(x, ((Number) y).doubleValue());
} else if (y instanceof CharSequence) {
BigInteger biy;
try {
biy = toBigInt(y);
} catch (EcmaError e) {
return false;
}
return x.equals(biy);
} else if (y instanceof Boolean) {
BigInteger biy = ((Boolean) y).booleanValue() ? BigInteger.ONE : BigInteger.ZERO;
return x.equals(biy);
} else if (isSymbol(y)) {
return false;
} else if (y instanceof Scriptable) {
if (y instanceof ScriptableObject) {
Object test = ((ScriptableObject) y).equivalentValues(x);
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
y = toPrimitive(y);
} else {
warnAboutNonJSObject(y);
return false;
}
}
}
private static boolean eqBigInt(BigInteger x, double y) {
if (Double.isNaN(y) || Double.isInfinite(y)) {
return false;
}
double d = Math.ceil(y);
if (d != y) {
return false;
}
BigDecimal bdx = new BigDecimal(x);
BigDecimal bdy = new BigDecimal(d, MathContext.UNLIMITED);
return bdx.compareTo(bdy) == 0;
}
private static boolean eqString(CharSequence x, Object y) {
for (; ; ) {
if (y == null || Undefined.isUndefined(y)) {
return false;
} else if (y instanceof CharSequence) {
CharSequence c = (CharSequence) y;
return x.length() == c.length() && x.toString().equals(c.toString());
} else if (y instanceof BigInteger) {
BigInteger bix;
try {
bix = toBigInt(x);
} catch (EcmaError e) {
return false;
}
return bix.equals(y);
} else if (y instanceof Number) {
return toNumber(x.toString()) == ((Number) y).doubleValue();
} else if (y instanceof Boolean) {
return toNumber(x.toString()) == (((Boolean) y).booleanValue() ? 1.0 : 0.0);
} else if (isSymbol(y)) {
return false;
} else if (y instanceof Scriptable) {
if (y instanceof ScriptableObject) {
Object test = ((ScriptableObject) y).equivalentValues(x.toString());
if (test != Scriptable.NOT_FOUND) {
return ((Boolean) test).booleanValue();
}
}
y = toPrimitive(y);
continue;
} else {
warnAboutNonJSObject(y);
return false;
}
}
}
public static boolean shallowEq(Object x, Object y) {
if (x == y) {
if (!(x instanceof Number)) {
return true;
}
// NaN check
double d = ((Number) x).doubleValue();
return !Double.isNaN(d);
}
if (x == null || x == Undefined.instance || x == Undefined.SCRIPTABLE_UNDEFINED) {
if ((x == Undefined.instance && y == Undefined.SCRIPTABLE_UNDEFINED)
|| (x == Undefined.SCRIPTABLE_UNDEFINED && y == Undefined.instance))
return true;
return false;
} else if (x instanceof BigInteger) {
if (y instanceof BigInteger) {
return x.equals(y);
}
} else if (x instanceof Number && !(x instanceof BigInteger)) {
if (y instanceof Number && !(y instanceof BigInteger)) {
return ((Number) x).doubleValue() == ((Number) y).doubleValue();
}
} else if (x instanceof CharSequence) {
if (y instanceof CharSequence) {
return x.toString().equals(y.toString());
}
} else if (x instanceof Boolean) {
if (y instanceof Boolean) {
return x.equals(y);
}
} else if (x instanceof Scriptable) {
if (x instanceof Wrapper && y instanceof Wrapper) {
return ((Wrapper) x).unwrap() == ((Wrapper) y).unwrap();
}
if (x instanceof Delegator) {
x = ((Delegator) x).getDelegee();
if (y instanceof Delegator) {
return shallowEq(x, ((Delegator) y).getDelegee());
}
if (x == y) {
return true;
}
}
if (y instanceof Delegator && ((Delegator) y).getDelegee() == x) {
return true;
}
} else {
warnAboutNonJSObject(x);
return x == y;
}
return false;
}
/**
* The instanceof operator.
*
* @return a instanceof b
*/
public static boolean instanceOf(Object a, Object b, Context cx) {
// Check RHS is an object
if (!(b instanceof Scriptable)) {
throw typeErrorById("msg.instanceof.not.object");
}
// for primitive values on LHS, return false
if (!(a instanceof Scriptable)) return false;
return ((Scriptable) b).hasInstance((Scriptable) a);
}
/**
* Delegates to
*
* @return true iff rhs appears in lhs' proto chain
*/
public static boolean jsDelegatesTo(Scriptable lhs, Scriptable rhs) {
Scriptable proto = lhs.getPrototype();
while (proto != null) {
if (proto.equals(rhs)) return true;
proto = proto.getPrototype();
}
return false;
}
/**
* The in operator.
*
* <p>This is a new JS 1.3 language feature. The in operator mirrors the operation of the for ..
* in construct, and tests whether the rhs has the property given by the lhs. It is different
* from the for .. in construct in that: <br>
* - it doesn't perform ToObject on the right hand side <br>
* - it returns true for DontEnum properties.
*
* @param a the left hand operand
* @param b the right hand operand
* @return true if property name or element number a is a property of b
*/
public static boolean in(Object a, Object b, Context cx) {
if (!(b instanceof Scriptable)) {
throw typeErrorById("msg.in.not.object");
}
return hasObjectElem((Scriptable) b, a, cx);
}
public static boolean compare(Object val1, Object val2, int op) {
assert op == Token.GE || op == Token.LE || op == Token.GT || op == Token.LT;
if (val1 instanceof Number && val2 instanceof Number) {
return compare((Number) val1, (Number) val2, op);
} else {
if ((val1 instanceof Symbol) || (val2 instanceof Symbol)) {
throw typeErrorById("msg.compare.symbol");
}
if (val1 instanceof Scriptable) {
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
}
if (val2 instanceof Scriptable) {
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
}
if (val1 instanceof CharSequence && val2 instanceof CharSequence) {
return compareTo(val1.toString(), val2.toString(), op);
}
return compare(toNumeric(val1), toNumeric(val2), op);
}
}
public static boolean compare(Number val1, Number val2, int op) {
assert op == Token.GE || op == Token.LE || op == Token.GT || op == Token.LT;
if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
return compareTo((BigInteger) val1, (BigInteger) val2, op);
} else if (val1 instanceof BigInteger || val2 instanceof BigInteger) {
BigDecimal bd1;
if (val1 instanceof BigInteger) {
bd1 = new BigDecimal((BigInteger) val1);
} else {
double d = val1.doubleValue();
if (Double.isNaN(d)) {
return false;
} else if (d == Double.POSITIVE_INFINITY) {
return op == Token.GE || op == Token.GT;
} else if (d == Double.NEGATIVE_INFINITY) {
return op == Token.LE || op == Token.LT;
}
bd1 = new BigDecimal(d, MathContext.UNLIMITED);
}
BigDecimal bd2;
if (val2 instanceof BigInteger) {
bd2 = new BigDecimal((BigInteger) val2);
} else {
double d = val2.doubleValue();
if (Double.isNaN(d)) {
return false;
} else if (d == Double.POSITIVE_INFINITY) {
return op == Token.LE || op == Token.LT;
} else if (d == Double.NEGATIVE_INFINITY) {
return op == Token.GE || op == Token.GT;
}
bd2 = new BigDecimal(d, MathContext.UNLIMITED);
}
return compareTo(bd1, bd2, op);
}
return compareTo(val1.doubleValue(), val2.doubleValue(), op);
}
private static <T> boolean compareTo(Comparable<T> val1, T val2, int op) {
switch (op) {
case Token.GE:
return val1.compareTo(val2) >= 0;
case Token.LE:
return val1.compareTo(val2) <= 0;
case Token.GT:
return val1.compareTo(val2) > 0;
case Token.LT:
return val1.compareTo(val2) < 0;
default:
throw Kit.codeBug();
}
}
private static <T> boolean compareTo(double d1, double d2, int op) {
switch (op) {
case Token.GE:
return d1 >= d2;
case Token.LE:
return d1 <= d2;
case Token.GT:
return d1 > d2;
case Token.LT:
return d1 < d2;
default:
throw Kit.codeBug();
}
}
// ------------------
// Statements
// ------------------
public static ScriptableObject getGlobal(Context cx) {
final String GLOBAL_CLASS = "org.mozilla.javascript.tools.shell.Global";
Class<?> globalClass = Kit.classOrNull(GLOBAL_CLASS);
if (globalClass != null) {
try {
Class<?>[] parm = {ScriptRuntime.ContextClass};
Constructor<?> globalClassCtor = globalClass.getConstructor(parm);
Object[] arg = {cx};
return (ScriptableObject) globalClassCtor.newInstance(arg);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
// fall through...
}
}
return new ImporterTopLevel(cx);
}
public static boolean hasTopCall(Context cx) {
return (cx.topCallScope != null);
}
public static Scriptable getTopCallScope(Context cx) {
Scriptable scope = cx.topCallScope;
if (scope == null) {
throw new IllegalStateException();
}
return scope;
}
/**
* @deprecated Use {@link #doTopCall(Callable, Context, Scriptable, Scriptable, Object[],
* boolean)} instead
*/
@Deprecated
public static Object doTopCall(
Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
return doTopCall(callable, cx, scope, thisObj, args, cx.isTopLevelStrict);
}
public static Object doTopCall(
Callable callable,
Context cx,
Scriptable scope,
Scriptable thisObj,
Object[] args,
boolean isTopLevelStrict) {
if (scope == null) throw new IllegalArgumentException();
if (cx.topCallScope != null) throw new IllegalStateException();
Object result;
cx.topCallScope = ScriptableObject.getTopLevelScope(scope);
cx.useDynamicScope = cx.hasFeature(Context.FEATURE_DYNAMIC_SCOPE);
boolean previousTopLevelStrict = cx.isTopLevelStrict;
cx.isTopLevelStrict = isTopLevelStrict;
ContextFactory f = cx.getFactory();
try {
result = f.doTopCall(callable, cx, scope, thisObj, args);
} finally {
cx.topCallScope = null;
// Cleanup cached references
cx.cachedXMLLib = null;
cx.isTopLevelStrict = previousTopLevelStrict;
if (cx.currentActivationCall != null) {
// Function should always call exitActivationFunction
// if it creates activation record
throw new IllegalStateException();
}
}
return result;
}
/**
* Return <code>possibleDynamicScope</code> if <code>staticTopScope</code> is present on its
* prototype chain and return <code>staticTopScope</code> otherwise. Should only be called when
* <code>staticTopScope</code> is top scope.
*/
static Scriptable checkDynamicScope(
Scriptable possibleDynamicScope, Scriptable staticTopScope) {
// Return cx.topCallScope if scope
if (possibleDynamicScope == staticTopScope) {
return possibleDynamicScope;
}
Scriptable proto = possibleDynamicScope;
for (; ; ) {
proto = proto.getPrototype();
if (proto == staticTopScope) {
return possibleDynamicScope;
}
if (proto == null) {
return staticTopScope;
}
}
}
public static void addInstructionCount(Context cx, int instructionsToAdd) {
cx.instructionCount += instructionsToAdd;
if (cx.instructionCount > cx.instructionThreshold) {
cx.observeInstructionCount(cx.instructionCount);
cx.instructionCount = 0;
}
}
public static void initScript(
NativeFunction funObj,
Scriptable thisObj,
Context cx,
Scriptable scope,
boolean evalScript) {
if (cx.topCallScope == null) throw new IllegalStateException();
int varCount = funObj.getParamAndVarCount();
if (varCount != 0) {
Scriptable varScope = scope;
// Never define any variables from var statements inside with
// object. See bug 38590.
while (varScope instanceof NativeWith) {
varScope = varScope.getParentScope();
}
for (int i = varCount; i-- != 0; ) {
String name = funObj.getParamOrVarName(i);
boolean isConst = funObj.getParamOrVarConst(i);
// Don't overwrite existing def if already defined in object
// or prototypes of object.
if (!ScriptableObject.hasProperty(scope, name)) {
if (isConst) {
ScriptableObject.defineConstProperty(varScope, name);
} else if (!evalScript) {
if (!(funObj instanceof InterpretedFunction)
|| ((InterpretedFunction) funObj).hasFunctionNamed(name)) {
// Global var definitions are supposed to be DONTDELETE
ScriptableObject.defineProperty(
varScope, name, Undefined.instance, ScriptableObject.PERMANENT);
}
} else {
varScope.put(name, varScope, Undefined.instance);
}
} else {
ScriptableObject.redefineProperty(scope, name, isConst);
}
}
}
}
/**
* @deprecated Use {@link #createFunctionActivation(NativeFunction, Scriptable, Object[],
* boolean)} instead
*/
@Deprecated
public static Scriptable createFunctionActivation(
NativeFunction funObj, Scriptable scope, Object[] args) {
return createFunctionActivation(funObj, scope, args, false);
}
public static Scriptable createFunctionActivation(
NativeFunction funObj, Scriptable scope, Object[] args, boolean isStrict) {
return new NativeCall(funObj, scope, args, false, isStrict);
}
public static Scriptable createArrowFunctionActivation(
NativeFunction funObj, Scriptable scope, Object[] args, boolean isStrict) {
return new NativeCall(funObj, scope, args, true, isStrict);
}
public static void enterActivationFunction(Context cx, Scriptable scope) {
if (cx.topCallScope == null) throw new IllegalStateException();
NativeCall call = (NativeCall) scope;
call.parentActivationCall = cx.currentActivationCall;
cx.currentActivationCall = call;
call.defineAttributesForArguments();
}
public static void exitActivationFunction(Context cx) {
NativeCall call = cx.currentActivationCall;
cx.currentActivationCall = call.parentActivationCall;
call.parentActivationCall = null;
}
static NativeCall findFunctionActivation(Context cx, Function f) {
NativeCall call = cx.currentActivationCall;
while (call != null) {
if (call.function == f) return call;
call = call.parentActivationCall;
}
return null;
}
public static Scriptable newCatchScope(
Throwable t,
Scriptable lastCatchScope,
String exceptionName,
Context cx,
Scriptable scope) {
Object obj;
boolean cacheObj;
getObj:
if (t instanceof JavaScriptException) {
cacheObj = false;
obj = ((JavaScriptException) t).getValue();
} else {
cacheObj = true;
// Create wrapper object unless it was associated with
// the previous scope object
if (lastCatchScope != null) {
NativeObject last = (NativeObject) lastCatchScope;
obj = last.getAssociatedValue(t);
if (obj == null) Kit.codeBug();
break getObj;
}
RhinoException re;
TopLevel.NativeErrors type;
String errorMsg;
Throwable javaException = null;
if (t instanceof EcmaError) {
EcmaError ee = (EcmaError) t;
re = ee;
type = TopLevel.NativeErrors.valueOf(ee.getName());
errorMsg = ee.getErrorMessage();
} else if (t instanceof WrappedException) {
WrappedException we = (WrappedException) t;
re = we;
javaException = we.getWrappedException();
if (!isVisible(cx, javaException)) {
type = TopLevel.NativeErrors.InternalError;
errorMsg = javaException.getMessage();
} else {
type = TopLevel.NativeErrors.JavaException;
errorMsg =
javaException.getClass().getName() + ": " + javaException.getMessage();
}
} else if (t instanceof EvaluatorException) {
// Pure evaluator exception, nor WrappedException instance
EvaluatorException ee = (EvaluatorException) t;
re = ee;
type = TopLevel.NativeErrors.InternalError;
errorMsg = ee.getMessage();
} else if (cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) {
// With FEATURE_ENHANCED_JAVA_ACCESS, scripts can catch
// all exception types
re = new WrappedException(t);
type = TopLevel.NativeErrors.JavaException;
errorMsg = t.toString();
} else {
// Script can catch only instances of JavaScriptException,
// EcmaError and EvaluatorException
throw Kit.codeBug();
}
String sourceUri = re.sourceName();
if (sourceUri == null) {
sourceUri = "";
}
int line = re.lineNumber();
Object args[];
if (line > 0) {
args = new Object[] {errorMsg, sourceUri, Integer.valueOf(line)};
} else {
args = new Object[] {errorMsg, sourceUri};
}
Scriptable errorObject = newNativeError(cx, scope, type, args);
// set exception in Error objects to enable non-ECMA "stack" property
if (errorObject instanceof NativeError) {
((NativeError) errorObject).setStackProvider(re);
}
if (javaException != null && isVisible(cx, javaException)) {
Object wrap = cx.getWrapFactory().wrap(cx, scope, javaException, null);
ScriptableObject.defineProperty(
errorObject,
"javaException",
wrap,
ScriptableObject.PERMANENT
| ScriptableObject.READONLY
| ScriptableObject.DONTENUM);
}
if (isVisible(cx, re)) {
Object wrap = cx.getWrapFactory().wrap(cx, scope, re, null);
ScriptableObject.defineProperty(
errorObject,
"rhinoException",
wrap,
ScriptableObject.PERMANENT
| ScriptableObject.READONLY
| ScriptableObject.DONTENUM);
}
obj = errorObject;
}
NativeObject catchScopeObject = new NativeObject();
// See ECMA 12.4
catchScopeObject.defineProperty(exceptionName, obj, ScriptableObject.PERMANENT);
if (isVisible(cx, t)) {
// Add special Rhino object __exception__ defined in the catch
// scope that can be used to retrieve the Java exception associated
// with the JavaScript exception (to get stack trace info, etc.)
catchScopeObject.defineProperty(
"__exception__",
Context.javaToJS(t, scope),
ScriptableObject.PERMANENT | ScriptableObject.DONTENUM);
}
if (cacheObj) {
catchScopeObject.associateValue(t, obj);
}
return catchScopeObject;
}
public static Scriptable wrapException(Throwable t, Scriptable scope, Context cx) {
RhinoException re;
String errorName;
String errorMsg;
Throwable javaException = null;
if (t instanceof EcmaError) {
EcmaError ee = (EcmaError) t;
re = ee;
errorName = ee.getName();
errorMsg = ee.getErrorMessage();
} else if (t instanceof WrappedException) {
WrappedException we = (WrappedException) t;
re = we;
javaException = we.getWrappedException();
errorName = "JavaException";
errorMsg = javaException.getClass().getName() + ": " + javaException.getMessage();
} else if (t instanceof EvaluatorException) {
// Pure evaluator exception, nor WrappedException instance
EvaluatorException ee = (EvaluatorException) t;
re = ee;
errorName = "InternalError";
errorMsg = ee.getMessage();
} else if (cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) {
// With FEATURE_ENHANCED_JAVA_ACCESS, scripts can catch
// all exception types
re = new WrappedException(t);
errorName = "JavaException";
errorMsg = t.toString();
} else {
// Script can catch only instances of JavaScriptException,
// EcmaError and EvaluatorException
throw Kit.codeBug();
}
String sourceUri = re.sourceName();
if (sourceUri == null) {
sourceUri = "";
}
int line = re.lineNumber();
Object args[];
if (line > 0) {
args = new Object[] {errorMsg, sourceUri, Integer.valueOf(line)};
} else {
args = new Object[] {errorMsg, sourceUri};
}
Scriptable errorObject = cx.newObject(scope, errorName, args);
ScriptableObject.putProperty(errorObject, "name", errorName);
// set exception in Error objects to enable non-ECMA "stack" property
if (errorObject instanceof NativeError) {
((NativeError) errorObject).setStackProvider(re);
}
if (javaException != null && isVisible(cx, javaException)) {
Object wrap = cx.getWrapFactory().wrap(cx, scope, javaException, null);
ScriptableObject.defineProperty(
errorObject,
"javaException",
wrap,
ScriptableObject.PERMANENT
| ScriptableObject.READONLY
| ScriptableObject.DONTENUM);
}
if (isVisible(cx, re)) {
Object wrap = cx.getWrapFactory().wrap(cx, scope, re, null);
ScriptableObject.defineProperty(
errorObject,
"rhinoException",
wrap,
ScriptableObject.PERMANENT
| ScriptableObject.READONLY
| ScriptableObject.DONTENUM);
}
return errorObject;
}
private static boolean isVisible(Context cx, Object obj) {
ClassShutter shutter = cx.getClassShutter();
return shutter == null || shutter.visibleToScripts(obj.getClass().getName());
}
public static Scriptable enterWith(Object obj, Context cx, Scriptable scope) {
Scriptable sobj = toObjectOrNull(cx, obj, scope);
if (sobj == null) {
throw typeErrorById("msg.undef.with", toString(obj));
}
if (sobj instanceof XMLObject) {
XMLObject xmlObject = (XMLObject) sobj;
return xmlObject.enterWith(scope);
}
return new NativeWith(scope, sobj);
}
public static Scriptable leaveWith(Scriptable scope) {
NativeWith nw = (NativeWith) scope;
return nw.getParentScope();
}
public static Scriptable enterDotQuery(Object value, Scriptable scope) {
if (!(value instanceof XMLObject)) {
throw notXmlError(value);
}
XMLObject object = (XMLObject) value;
return object.enterDotQuery(scope);
}
public static Object updateDotQuery(boolean value, Scriptable scope) {
// Return null to continue looping
NativeWith nw = (NativeWith) scope;
return nw.updateDotQuery(value);
}
public static Scriptable leaveDotQuery(Scriptable scope) {
NativeWith nw = (NativeWith) scope;
return nw.getParentScope();
}
public static void setFunctionProtoAndParent(BaseFunction fn, Scriptable scope) {
setFunctionProtoAndParent(fn, scope, false);
}
public static void setFunctionProtoAndParent(
BaseFunction fn, Scriptable scope, boolean es6GeneratorFunction) {
fn.setParentScope(scope);
if (es6GeneratorFunction) {
fn.setPrototype(ScriptableObject.getGeneratorFunctionPrototype(scope));
} else {
fn.setPrototype(ScriptableObject.getFunctionPrototype(scope));
}
}
public static void setObjectProtoAndParent(ScriptableObject object, Scriptable scope) {
// Compared with function it always sets the scope to top scope
scope = ScriptableObject.getTopLevelScope(scope);
object.setParentScope(scope);
Scriptable proto = ScriptableObject.getClassPrototype(scope, object.getClassName());
object.setPrototype(proto);
}
public static void setBuiltinProtoAndParent(
ScriptableObject object, Scriptable scope, TopLevel.Builtins type) {
scope = ScriptableObject.getTopLevelScope(scope);
object.setParentScope(scope);
object.setPrototype(TopLevel.getBuiltinPrototype(scope, type));
}
public static void initFunction(
Context cx, Scriptable scope, NativeFunction function, int type, boolean fromEvalCode) {
if (type == FunctionNode.FUNCTION_STATEMENT) {
String name = function.getFunctionName();
if (name != null && name.length() != 0) {
if (!fromEvalCode) {
// ECMA specifies that functions defined in global and
// function scope outside eval should have DONTDELETE set.
ScriptableObject.defineProperty(
scope, name, function, ScriptableObject.PERMANENT);
} else {
scope.put(name, scope, function);
}
}
} else if (type == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
String name = function.getFunctionName();
if (name != null && name.length() != 0) {
// Always put function expression statements into initial
// activation object ignoring the with statement to follow
// SpiderMonkey
while (scope instanceof NativeWith) {
scope = scope.getParentScope();
}
scope.put(name, scope, function);
}
} else {
throw Kit.codeBug();
}
}
public static Scriptable newArrayLiteral(
Object[] objects, int[] skipIndices, Context cx, Scriptable scope) {
final int SKIP_DENSITY = 2;
int count = objects.length;
int skipCount = 0;
if (skipIndices != null) {
skipCount = skipIndices.length;
}
int length = count + skipCount;
if (length > 1 && skipCount * SKIP_DENSITY < length) {
// If not too sparse, create whole array for constructor
Object[] sparse;
if (skipCount == 0) {
sparse = objects;
} else {
sparse = new Object[length];
int skip = 0;
for (int i = 0, j = 0; i != length; ++i) {
if (skip != skipCount && skipIndices[skip] == i) {
sparse[i] = Scriptable.NOT_FOUND;
++skip;
continue;
}
sparse[i] = objects[j];
++j;
}
}
return cx.newArray(scope, sparse);
}
Scriptable array = cx.newArray(scope, length);
int skip = 0;
for (int i = 0, j = 0; i != length; ++i) {
if (skip != skipCount && skipIndices[skip] == i) {
++skip;
continue;
}
array.put(i, array, objects[j]);
++j;
}
return array;
}
/**
* This method is here for backward compat with existing compiled code. It is called when an
* object literal is compiled. The next instance will be the version called from new code.
* <strong>This method only present for compatibility.</strong>
*
* @deprecated Use {@link #newObjectLiteral(Object[], Object[], int[], Context, Scriptable)}
* instead
*/
@Deprecated
public static Scriptable newObjectLiteral(
Object[] propertyIds, Object[] propertyValues, Context cx, Scriptable scope) {
// Passing null for getterSetters means no getters or setters
return newObjectLiteral(propertyIds, propertyValues, null, cx, scope);
}
public static Scriptable newObjectLiteral(
Object[] propertyIds,
Object[] propertyValues,
int[] getterSetters,
Context cx,
Scriptable scope) {
Scriptable object = cx.newObject(scope);
int end = propertyIds == null ? 0 : propertyIds.length;
for (int i = 0; i != end; ++i) {
Object id = propertyIds[i];
// -1 for property getter, 1 for property setter, 0 for a regular value property
int getterSetter = getterSetters == null ? 0 : getterSetters[i];
Object value = propertyValues[i];
if (getterSetter == 0) {
if (id instanceof Symbol) {
Symbol sym = (Symbol) id;
SymbolScriptable so = (SymbolScriptable) object;
so.put(sym, object, value);
} else if (id instanceof Integer) {
int index = ((Integer) id).intValue();
object.put(index, object, value);
} else {
String stringId = ScriptRuntime.toString(id);
if (isSpecialProperty(stringId)) {
Ref ref = specialRef(object, stringId, cx, scope);
ref.set(cx, scope, value);
} else {
object.put(stringId, object, value);
}
}
} else {
ScriptableObject so = (ScriptableObject) object;
Callable getterOrSetter = (Callable) value;
boolean isSetter = getterSetter == 1;
// XXX: Do we have to handle Symbol here.
// This will be required, when conputedprops are supported.
String key = id instanceof String ? (String) id : null;
int index = key == null ? ((Integer) id).intValue() : 0;
so.setGetterOrSetter(key, index, getterOrSetter, isSetter);
}
}
return object;
}
public static boolean isArrayObject(Object obj) {
return obj instanceof NativeArray || obj instanceof Arguments;
}
public static Object[] getArrayElements(Scriptable object) {
Context cx = Context.getContext();
long longLen = NativeArray.getLengthProperty(cx, object);
if (longLen > Integer.MAX_VALUE) {
// arrays beyond MAX_INT is not in Java in any case
throw new IllegalArgumentException();
}
int len = (int) longLen;
if (len == 0) {
return ScriptRuntime.emptyArgs;
}
Object[] result = new Object[len];
for (int i = 0; i < len; i++) {
Object elem = ScriptableObject.getProperty(object, i);
result[i] = (elem == Scriptable.NOT_FOUND) ? Undefined.instance : elem;
}
return result;
}
static void checkDeprecated(Context cx, String name) {
int version = cx.getLanguageVersion();
if (version >= Context.VERSION_1_4 || version == Context.VERSION_DEFAULT) {
String msg = getMessageById("msg.deprec.ctor", name);
if (version == Context.VERSION_DEFAULT) Context.reportWarning(msg);
else throw Context.reportRuntimeError(msg);
}
}
/** @deprecated Use {@link #getMessageById(String messageId, Object... args)} instead */
@Deprecated
public static String getMessage0(String messageId) {
return getMessage(messageId, null);
}
/** @deprecated Use {@link #getMessageById(String messageId, Object... args)} instead */
@Deprecated
public static String getMessage1(String messageId, Object arg1) {
Object[] arguments = {arg1};
return getMessage(messageId, arguments);
}
/** @deprecated Use {@link #getMessageById(String messageId, Object... args)} instead */
@Deprecated
public static String getMessage2(String messageId, Object arg1, Object arg2) {
Object[] arguments = {arg1, arg2};
return getMessage(messageId, arguments);
}
/** @deprecated Use {@link #getMessageById(String messageId, Object... args)} instead */
@Deprecated
public static String getMessage3(String messageId, Object arg1, Object arg2, Object arg3) {
Object[] arguments = {arg1, arg2, arg3};
return getMessage(messageId, arguments);
}
/** @deprecated Use {@link #getMessageById(String messageId, Object... args)} instead */
@Deprecated
public static String getMessage4(
String messageId, Object arg1, Object arg2, Object arg3, Object arg4) {
Object[] arguments = {arg1, arg2, arg3, arg4};
return getMessage(messageId, arguments);
}
/**
* This is an interface defining a message provider. Create your own implementation to override
* the default error message provider.
*
* @author Mike Harm
*/
public interface MessageProvider {
/**
* Returns a textual message identified by the given messageId, parameterized by the given
* arguments.
*
* @param messageId the identifier of the message
* @param arguments the arguments to fill into the message
*/
String getMessage(String messageId, Object[] arguments);
}
public static final MessageProvider messageProvider = new DefaultMessageProvider();
/** @deprecated Use {@link #getMessageById(String messageId, Object... args)} instead */
@Deprecated
public static String getMessage(String messageId, Object[] arguments) {
return messageProvider.getMessage(messageId, arguments);
}
public static String getMessageById(String messageId, Object... args) {
return messageProvider.getMessage(messageId, args);
}
/* OPT there's a noticable delay for the first error! Maybe it'd
* make sense to use a ListResourceBundle instead of a properties
* file to avoid (synchronized) text parsing.
*/
private static class DefaultMessageProvider implements MessageProvider {
@Override
public String getMessage(String messageId, Object[] arguments) {
final String defaultResource = "org.mozilla.javascript.resources.Messages";
Context cx = Context.getCurrentContext();
Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();
// ResourceBundle does caching.
ResourceBundle rb = ResourceBundle.getBundle(defaultResource, locale);
String formatString;
try {
formatString = rb.getString(messageId);
} catch (java.util.MissingResourceException mre) {
throw new RuntimeException(
"no message resource found for message property " + messageId);
}
/*
* It's OK to format the string, even if 'arguments' is null;
* we need to format it anyway, to make double ''s collapse to
* single 's.
*/
MessageFormat formatter = new MessageFormat(formatString);
return formatter.format(arguments);
}
}
public static EcmaError constructError(String error, String message) {
int[] linep = new int[1];
String filename = Context.getSourcePositionFromStack(linep);
return constructError(error, message, filename, linep[0], null, 0);
}
public static EcmaError constructError(String error, String message, int lineNumberDelta) {
int[] linep = new int[1];
String filename = Context.getSourcePositionFromStack(linep);
if (linep[0] != 0) {
linep[0] += lineNumberDelta;
}
return constructError(error, message, filename, linep[0], null, 0);
}
public static EcmaError constructError(
String error,
String message,
String sourceName,
int lineNumber,
String lineSource,
int columnNumber) {
return new EcmaError(error, message, sourceName, lineNumber, lineSource, columnNumber);
}
public static EcmaError rangeError(String message) {
return constructError("RangeError", message);
}
public static EcmaError rangeErrorById(String messageId, Object... args) {
String msg = getMessageById(messageId, args);
return rangeError(msg);
}
public static EcmaError typeError(String message) {
return constructError("TypeError", message);
}
public static EcmaError typeErrorById(String messageId, Object... args) {
String msg = getMessageById(messageId, args);
return typeError(msg);
}
/** @deprecated Use {@link #typeErrorById(String messageId, Object... args)} instead */
@Deprecated
public static EcmaError typeError0(String messageId) {
String msg = getMessage0(messageId);
return typeError(msg);
}
/** @deprecated Use {@link #typeErrorById(String messageId, Object... args)} instead */
@Deprecated
public static EcmaError typeError1(String messageId, Object arg1) {
String msg = getMessage1(messageId, arg1);
return typeError(msg);
}
/** @deprecated Use {@link #typeErrorById(String messageId, Object... args)} instead */
@Deprecated
public static EcmaError typeError2(String messageId, Object arg1, Object arg2) {
String msg = getMessage2(messageId, arg1, arg2);
return typeError(msg);
}
/** @deprecated Use {@link #typeErrorById(String messageId, Object... args)} instead */
@Deprecated
public static EcmaError typeError3(String messageId, String arg1, String arg2, String arg3) {
String msg = getMessage3(messageId, arg1, arg2, arg3);
return typeError(msg);
}
public static RuntimeException undefReadError(Object object, Object id) {
return typeErrorById("msg.undef.prop.read", toString(object), toString(id));
}
public static RuntimeException undefCallError(Object object, Object id) {
return typeErrorById("msg.undef.method.call", toString(object), toString(id));
}
public static RuntimeException undefWriteError(Object object, Object id, Object value) {
return typeErrorById(
"msg.undef.prop.write", toString(object), toString(id), toString(value));
}
private static RuntimeException undefDeleteError(Object object, Object id) {
throw typeErrorById("msg.undef.prop.delete", toString(object), toString(id));
}
public static RuntimeException notFoundError(Scriptable object, String property) {
// XXX: use object to improve the error message
String msg = getMessageById("msg.is.not.defined", property);
throw constructError("ReferenceError", msg);
}
public static RuntimeException notFunctionError(Object value) {
return notFunctionError(value, value);
}
public static RuntimeException notFunctionError(Object value, Object messageHelper) {
// Use value for better error reporting
String msg = (messageHelper == null) ? "null" : messageHelper.toString();
if (value == Scriptable.NOT_FOUND) {
return typeErrorById("msg.function.not.found", msg);
}
return typeErrorById("msg.isnt.function", msg, typeof(value));
}
public static RuntimeException notFunctionError(Object obj, Object value, String propertyName) {
// Use obj and value for better error reporting
String objString = toString(obj);
if (obj instanceof NativeFunction) {
// Omit function body in string representations of functions
int paren = objString.indexOf(')');
int curly = objString.indexOf('{', paren);
if (curly > -1) {
objString = objString.substring(0, curly + 1) + "...}";
}
}
if (value == Scriptable.NOT_FOUND) {
return typeErrorById("msg.function.not.found.in", propertyName, objString);
}
return typeErrorById("msg.isnt.function.in", propertyName, objString, typeof(value));
}
private static RuntimeException notXmlError(Object value) {
throw typeErrorById("msg.isnt.xml.object", toString(value));
}
public static EcmaError syntaxError(String message) {
return constructError("SyntaxError", message);
}
public static EcmaError syntaxErrorById(String messageId, Object... args) {
String msg = getMessageById(messageId, args);
return syntaxError(msg);
}
private static void warnAboutNonJSObject(Object nonJSObject) {
final String omitParam = ScriptRuntime.getMessageById("params.omit.non.js.object.warning");
if (!"true".equals(omitParam)) {
String message =
ScriptRuntime.getMessageById(
"msg.non.js.object.warning",
nonJSObject,
nonJSObject.getClass().getName());
Context.reportWarning(message);
// Just to be sure that it would be noticed
System.err.println(message);
}
}
public static RegExpProxy getRegExpProxy(Context cx) {
return cx.getRegExpProxy();
}
public static void setRegExpProxy(Context cx, RegExpProxy proxy) {
if (proxy == null) throw new IllegalArgumentException();
cx.regExpProxy = proxy;
}
public static RegExpProxy checkRegExpProxy(Context cx) {
RegExpProxy result = getRegExpProxy(cx);
if (result == null) {
throw Context.reportRuntimeErrorById("msg.no.regexp");
}
return result;
}
public static Scriptable wrapRegExp(Context cx, Scriptable scope, Object compiled) {
return cx.getRegExpProxy().wrapRegExp(cx, scope, compiled);
}
public static Scriptable getTemplateLiteralCallSite(
Context cx, Scriptable scope, Object[] strings, int index) {
Object callsite = strings[index];
if (callsite instanceof Scriptable) return (Scriptable) callsite;
assert callsite instanceof String[];
String[] vals = (String[]) callsite;
assert (vals.length & 1) == 0;
ScriptableObject siteObj = (ScriptableObject) cx.newArray(scope, vals.length >>> 1);
ScriptableObject rawObj = (ScriptableObject) cx.newArray(scope, vals.length >>> 1);
siteObj.put("raw", siteObj, rawObj);
siteObj.setAttributes("raw", ScriptableObject.DONTENUM);
for (int i = 0, n = vals.length; i < n; i += 2) {
int idx = i >>> 1;
siteObj.put(idx, siteObj, (vals[i] == null ? Undefined.instance : vals[i]));
rawObj.put(idx, rawObj, vals[i + 1]);
}
AbstractEcmaObjectOperations.setIntegrityLevel(
cx, rawObj, AbstractEcmaObjectOperations.INTEGRITY_LEVEL.FROZEN);
AbstractEcmaObjectOperations.setIntegrityLevel(
cx, siteObj, AbstractEcmaObjectOperations.INTEGRITY_LEVEL.FROZEN);
strings[index] = siteObj;
return siteObj;
}
private static XMLLib currentXMLLib(Context cx) {
// Scripts should be running to access this
if (cx.topCallScope == null) throw new IllegalStateException();
XMLLib xmlLib = cx.cachedXMLLib;
if (xmlLib == null) {
xmlLib = XMLLib.extractFromScope(cx.topCallScope);
if (xmlLib == null) throw new IllegalStateException();
cx.cachedXMLLib = xmlLib;
}
return xmlLib;
}
/**
* Escapes the reserved characters in a value of an attribute
*
* @param value Unescaped text
* @return The escaped text
*/
public static String escapeAttributeValue(Object value, Context cx) {
XMLLib xmlLib = currentXMLLib(cx);
return xmlLib.escapeAttributeValue(value);
}
/**
* Escapes the reserved characters in a value of a text node
*
* @param value Unescaped text
* @return The escaped text
*/
public static String escapeTextValue(Object value, Context cx) {
XMLLib xmlLib = currentXMLLib(cx);
return xmlLib.escapeTextValue(value);
}
public static Ref memberRef(Object obj, Object elem, Context cx, int memberTypeFlags) {
if (!(obj instanceof XMLObject)) {
throw notXmlError(obj);
}
XMLObject xmlObject = (XMLObject) obj;
return xmlObject.memberRef(cx, elem, memberTypeFlags);
}
public static Ref memberRef(
Object obj, Object namespace, Object elem, Context cx, int memberTypeFlags) {
if (!(obj instanceof XMLObject)) {
throw notXmlError(obj);
}
XMLObject xmlObject = (XMLObject) obj;
return xmlObject.memberRef(cx, namespace, elem, memberTypeFlags);
}
public static Ref nameRef(Object name, Context cx, Scriptable scope, int memberTypeFlags) {
XMLLib xmlLib = currentXMLLib(cx);
return xmlLib.nameRef(cx, name, scope, memberTypeFlags);
}
public static Ref nameRef(
Object namespace, Object name, Context cx, Scriptable scope, int memberTypeFlags) {
XMLLib xmlLib = currentXMLLib(cx);
return xmlLib.nameRef(cx, namespace, name, scope, memberTypeFlags);
}
public static void storeUint32Result(Context cx, long value) {
if ((value >>> 32) != 0) throw new IllegalArgumentException();
cx.scratchUint32 = value;
}
public static long lastUint32Result(Context cx) {
long value = cx.scratchUint32;
if ((value >>> 32) != 0) throw new IllegalStateException();
return value;
}
private static void storeScriptable(Context cx, Scriptable value) {
// The previously stored scratchScriptable should be consumed
if (cx.scratchScriptable != null) throw new IllegalStateException();
cx.scratchScriptable = value;
}
public static Scriptable lastStoredScriptable(Context cx) {
Scriptable result = cx.scratchScriptable;
cx.scratchScriptable = null;
return result;
}
static String makeUrlForGeneratedScript(
boolean isEval, String masterScriptUrl, int masterScriptLine) {
if (isEval) {
return masterScriptUrl + '#' + masterScriptLine + "(eval)";
}
return masterScriptUrl + '#' + masterScriptLine + "(Function)";
}
static boolean isGeneratedScript(String sourceUrl) {
// ALERT: this may clash with a valid URL containing (eval) or
// (Function)
return sourceUrl.indexOf("(eval)") >= 0 || sourceUrl.indexOf("(Function)") >= 0;
}
/**
* Not all "NativeSymbol" instances are actually symbols. So account for that here rather than
* just by using an "instanceof" check.
*/
static boolean isSymbol(Object obj) {
return (((obj instanceof NativeSymbol) && ((NativeSymbol) obj).isSymbol()))
|| (obj instanceof SymbolKey);
}
private static RuntimeException errorWithClassName(String msg, Object val) {
return Context.reportRuntimeErrorById(msg, val.getClass().getName());
}
/**
* Equivalent to executing "new Error(message, sourceFileName, sourceLineNo)" from JavaScript.
*
* @param cx the current context
* @param scope the current scope
* @param message the message
* @return a JavaScriptException you should throw
*/
public static JavaScriptException throwError(Context cx, Scriptable scope, String message) {
int[] linep = {0};
String filename = Context.getSourcePositionFromStack(linep);
final Scriptable error =
newBuiltinObject(
cx,
scope,
TopLevel.Builtins.Error,
new Object[] {message, filename, Integer.valueOf(linep[0])});
return new JavaScriptException(error, filename, linep[0]);
}
/**
* Equivalent to executing "new $constructorName(message, sourceFileName, sourceLineNo)" from
* JavaScript.
*
* @param cx the current context
* @param scope the current scope
* @param message the message
* @return a JavaScriptException you should throw
*/
public static JavaScriptException throwCustomError(
Context cx, Scriptable scope, String constructorName, String message) {
int[] linep = {0};
String filename = Context.getSourcePositionFromStack(linep);
final Scriptable error =
cx.newObject(
scope,
constructorName,
new Object[] {message, filename, Integer.valueOf(linep[0])});
return new JavaScriptException(error, filename, linep[0]);
}
public static final Object[] emptyArgs = new Object[0];
public static final String[] emptyStrings = new String[0];
}
⏎ org/mozilla/javascript/ScriptRuntime.java
Or download all of them as a single archive file:
File name: rhino-1.7.14-sources.jar File size: 1029165 bytes Release date: 2022-01-06 Download
⇒ Example code to Test rhino-runtime-1.7.14.jar
⇐ Download Rhino JavaScript Binary Package
2022-05-03, ≈192🔥, 1💬
Popular Posts:
How to download and install JDK (Java Development Kit) 6? If you want to write Java applications, yo...
How to read XML document with DTD validation from socket connections with the socket\DelayedInput.ja.. .
What Is commons-collections4-4.4 .jar?commons-collections4-4.4 .jaris the JAR file for Apache Common...
Guava is a suite of core and expanded libraries that include utility classes, google's collections, ...
JDK 8 jconsole.jar is the JAR file for JDK 8 JConsole, which is a graphical monitoring tool to monit...