org.mozilla.javascript.NativeObject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino Show documentation
Show all versions of rhino Show documentation
Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically
embedded into Java applications to provide scripting to end users.
/* -*- 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.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.mozilla.javascript.ScriptRuntime.StringIdOrIndex;
/**
* This class implements the Object native object. See ECMA 15.2.
*
* @author Norris Boyd
*/
public class NativeObject extends IdScriptableObject implements Map {
private static final long serialVersionUID = -6345305608474346996L;
private static final Object OBJECT_TAG = "Object";
static void init(Scriptable scope, boolean sealed) {
NativeObject obj = new NativeObject();
obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
}
@Override
public String getClassName() {
return "Object";
}
@Override
public String toString() {
return ScriptRuntime.defaultObjectToString(this);
}
@Override
protected void fillConstructorProperties(IdFunctionObject ctor) {
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_getPrototypeOf, "getPrototypeOf", 1);
if (Context.getCurrentContext().version >= Context.VERSION_ES6) {
addIdFunctionProperty(
ctor, OBJECT_TAG, ConstructorId_setPrototypeOf, "setPrototypeOf", 2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_entries, "entries", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_fromEntries, "fromEntries", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_values, "values", 1);
}
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_keys, "keys", 1);
addIdFunctionProperty(
ctor, OBJECT_TAG, ConstructorId_getOwnPropertyNames, "getOwnPropertyNames", 1);
addIdFunctionProperty(
ctor, OBJECT_TAG, ConstructorId_getOwnPropertySymbols, "getOwnPropertySymbols", 1);
addIdFunctionProperty(
ctor,
OBJECT_TAG,
ConstructorId_getOwnPropertyDescriptor,
"getOwnPropertyDescriptor",
2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_defineProperty, "defineProperty", 3);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isExtensible, "isExtensible", 1);
addIdFunctionProperty(
ctor, OBJECT_TAG, ConstructorId_preventExtensions, "preventExtensions", 1);
addIdFunctionProperty(
ctor, OBJECT_TAG, ConstructorId_defineProperties, "defineProperties", 2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_create, "create", 2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isSealed, "isSealed", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isFrozen, "isFrozen", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_seal, "seal", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_freeze, "freeze", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_assign, "assign", 2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_is, "is", 2);
super.fillConstructorProperties(ctor);
}
@Override
protected void initPrototypeId(int id) {
String s;
int arity;
switch (id) {
case Id_constructor:
arity = 1;
s = "constructor";
break;
case Id_toString:
arity = 0;
s = "toString";
break;
case Id_toLocaleString:
arity = 0;
s = "toLocaleString";
break;
case Id_valueOf:
arity = 0;
s = "valueOf";
break;
case Id_hasOwnProperty:
arity = 1;
s = "hasOwnProperty";
break;
case Id_propertyIsEnumerable:
arity = 1;
s = "propertyIsEnumerable";
break;
case Id_isPrototypeOf:
arity = 1;
s = "isPrototypeOf";
break;
case Id_toSource:
arity = 0;
s = "toSource";
break;
case Id___defineGetter__:
arity = 2;
s = "__defineGetter__";
break;
case Id___defineSetter__:
arity = 2;
s = "__defineSetter__";
break;
case Id___lookupGetter__:
arity = 1;
s = "__lookupGetter__";
break;
case Id___lookupSetter__:
arity = 1;
s = "__lookupSetter__";
break;
default:
throw new IllegalArgumentException(String.valueOf(id));
}
initPrototypeMethod(OBJECT_TAG, id, s, arity);
}
@Override
public Object execIdCall(
IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
if (!f.hasTag(OBJECT_TAG)) {
return super.execIdCall(f, cx, scope, thisObj, args);
}
int id = f.methodId();
switch (id) {
case Id_constructor:
{
if (thisObj != null) {
// BaseFunction.construct will set up parent, proto
return f.construct(cx, scope, args);
}
if (args.length == 0 || args[0] == null || Undefined.isUndefined(args[0])) {
return new NativeObject();
}
return ScriptRuntime.toObject(cx, scope, args[0]);
}
case Id_toLocaleString:
{
if (thisObj == null) {
throw ScriptRuntime.notFunctionError(null);
}
Object toString = ScriptableObject.getProperty(thisObj, "toString");
if (!(toString instanceof Callable)) {
throw ScriptRuntime.notFunctionError(toString);
}
Callable fun = (Callable) toString;
return fun.call(cx, scope, thisObj, ScriptRuntime.emptyArgs);
}
case Id_toString:
{
if (cx.hasFeature(Context.FEATURE_TO_STRING_AS_SOURCE)) {
String s =
ScriptRuntime.defaultObjectToSource(
cx, scope,
thisObj, args);
int L = s.length();
if (L != 0 && s.charAt(0) == '(' && s.charAt(L - 1) == ')') {
// Strip () that surrounds toSource
s = s.substring(1, L - 1);
}
return s;
}
return ScriptRuntime.defaultObjectToString(thisObj);
}
case Id_valueOf:
if (cx.getLanguageVersion() >= Context.VERSION_1_8
&& (thisObj == null || Undefined.isUndefined(thisObj))) {
throw ScriptRuntime.typeErrorById(
"msg." + (thisObj == null ? "null" : "undef") + ".to.object");
}
return thisObj;
case Id_hasOwnProperty:
{
if (cx.getLanguageVersion() >= Context.VERSION_1_8
&& (thisObj == null || Undefined.isUndefined(thisObj))) {
throw ScriptRuntime.typeErrorById(
"msg." + (thisObj == null ? "null" : "undef") + ".to.object");
}
boolean result;
Object arg = args.length < 1 ? Undefined.instance : args[0];
if (arg instanceof Symbol) {
result = ensureSymbolScriptable(thisObj).has((Symbol) arg, thisObj);
} else {
StringIdOrIndex s = ScriptRuntime.toStringIdOrIndex(cx, arg);
if (s.stringId == null) {
result = thisObj.has(s.index, thisObj);
} else {
result = thisObj.has(s.stringId, thisObj);
}
}
return ScriptRuntime.wrapBoolean(result);
}
case Id_propertyIsEnumerable:
{
if (cx.getLanguageVersion() >= Context.VERSION_1_8
&& (thisObj == null || Undefined.isUndefined(thisObj))) {
throw ScriptRuntime.typeErrorById(
"msg." + (thisObj == null ? "null" : "undef") + ".to.object");
}
boolean result;
Object arg = args.length < 1 ? Undefined.instance : args[0];
if (arg instanceof Symbol) {
result = ((SymbolScriptable) thisObj).has((Symbol) arg, thisObj);
result = result && isEnumerable((Symbol) arg, thisObj);
} else {
StringIdOrIndex s = ScriptRuntime.toStringIdOrIndex(cx, arg);
// When checking if a property is enumerable, a missing property should
// return "false" instead of
// throwing an exception. See: https://github.com/mozilla/rhino/issues/415
try {
if (s.stringId == null) {
result = thisObj.has(s.index, thisObj);
result = result && isEnumerable(s.index, thisObj);
} else {
result = thisObj.has(s.stringId, thisObj);
result = result && isEnumerable(s.stringId, thisObj);
}
} catch (EvaluatorException ee) {
if (ee.getMessage()
.startsWith(
ScriptRuntime.getMessageById(
"msg.prop.not.found",
s.stringId == null
? Integer.toString(s.index)
: s.stringId))) {
result = false;
} else {
throw ee;
}
}
}
return ScriptRuntime.wrapBoolean(result);
}
case Id_isPrototypeOf:
{
if (cx.getLanguageVersion() >= Context.VERSION_1_8
&& (thisObj == null || Undefined.isUndefined(thisObj))) {
throw ScriptRuntime.typeErrorById(
"msg." + (thisObj == null ? "null" : "undef") + ".to.object");
}
boolean result = false;
if (args.length != 0 && args[0] instanceof Scriptable) {
Scriptable v = (Scriptable) args[0];
do {
v = v.getPrototype();
if (v == thisObj) {
result = true;
break;
}
} while (v != null);
}
return ScriptRuntime.wrapBoolean(result);
}
case Id_toSource:
return ScriptRuntime.defaultObjectToSource(cx, scope, thisObj, args);
case Id___defineGetter__:
case Id___defineSetter__:
{
if (args.length < 2 || !(args[1] instanceof Callable)) {
Object badArg = (args.length >= 2 ? args[1] : Undefined.instance);
throw ScriptRuntime.notFunctionError(badArg);
}
if (!(thisObj instanceof ScriptableObject)) {
throw Context.reportRuntimeErrorById(
"msg.extend.scriptable",
thisObj == null ? "null" : thisObj.getClass().getName(),
String.valueOf(args[0]));
}
ScriptableObject so = (ScriptableObject) thisObj;
StringIdOrIndex s = ScriptRuntime.toStringIdOrIndex(cx, args[0]);
int index = s.stringId != null ? 0 : s.index;
Callable getterOrSetter = (Callable) args[1];
boolean isSetter = (id == Id___defineSetter__);
so.setGetterOrSetter(s.stringId, index, getterOrSetter, isSetter);
if (so instanceof NativeArray) ((NativeArray) so).setDenseOnly(false);
}
return Undefined.instance;
case Id___lookupGetter__:
case Id___lookupSetter__:
{
if (args.length < 1 || !(thisObj instanceof ScriptableObject))
return Undefined.instance;
ScriptableObject so = (ScriptableObject) thisObj;
StringIdOrIndex s = ScriptRuntime.toStringIdOrIndex(cx, args[0]);
int index = s.stringId != null ? 0 : s.index;
boolean isSetter = (id == Id___lookupSetter__);
Object gs;
for (; ; ) {
gs = so.getGetterOrSetter(s.stringId, index, this, isSetter);
if (gs != null) {
break;
}
// If there is no getter or setter for the object itself,
// how about the prototype?
Scriptable v = so.getPrototype();
if (v == null) {
break;
}
if (v instanceof ScriptableObject) {
so = (ScriptableObject) v;
} else {
break;
}
}
if (gs != null) {
return gs;
}
}
return Undefined.instance;
case ConstructorId_getPrototypeOf:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
Scriptable obj = getCompatibleObject(cx, scope, arg);
return obj.getPrototype();
}
case ConstructorId_setPrototypeOf:
{
if (args.length < 2) {
throw ScriptRuntime.typeErrorById(
"msg.method.missing.parameter",
"Object.setPrototypeOf",
"2",
Integer.toString(args.length));
}
Scriptable proto = (args[1] == null) ? null : ensureScriptable(args[1]);
if (proto instanceof Symbol) {
throw ScriptRuntime.typeErrorById(
"msg.arg.not.object", ScriptRuntime.typeof(proto));
}
final Object arg0 = args[0];
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
ScriptRuntimeES6.requireObjectCoercible(cx, arg0, f);
}
if (!(arg0 instanceof ScriptableObject)) {
return arg0;
}
ScriptableObject obj = (ScriptableObject) arg0;
if (!obj.isExtensible()) {
throw ScriptRuntime.typeErrorById("msg.not.extensible");
}
// cycle detection
Scriptable prototypeProto = proto;
while (prototypeProto != null) {
if (prototypeProto == obj) {
throw ScriptRuntime.typeErrorById(
"msg.object.cyclic.prototype", obj.getClass().getSimpleName());
}
prototypeProto = prototypeProto.getPrototype();
}
obj.setPrototype(proto);
return obj;
}
case ConstructorId_keys:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
Scriptable obj = getCompatibleObject(cx, scope, arg);
Object[] ids = obj.getIds();
for (int i = 0; i < ids.length; i++) {
ids[i] = ScriptRuntime.toString(ids[i]);
}
return cx.newArray(scope, ids);
}
case ConstructorId_entries:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
Scriptable obj = getCompatibleObject(cx, scope, arg);
Object[] ids = obj.getIds();
int j = 0;
for (int i = 0; i < ids.length; i++) {
if (ids[i] instanceof Integer) {
int intId = (Integer) ids[i];
if (obj.has(intId, obj) && isEnumerable(intId, obj)) {
String stringId = ScriptRuntime.toString(ids[i]);
Object[] entry = new Object[] {stringId, obj.get(intId, obj)};
ids[j++] = cx.newArray(scope, entry);
}
} else {
String stringId = ScriptRuntime.toString(ids[i]);
if (obj.has(stringId, obj) && isEnumerable(stringId, obj)) {
Object[] entry = new Object[] {stringId, obj.get(stringId, obj)};
ids[j++] = cx.newArray(scope, entry);
}
}
}
if (j != ids.length) {
ids = Arrays.copyOf(ids, j);
}
return cx.newArray(scope, ids);
}
case ConstructorId_fromEntries:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
arg = getCompatibleObject(cx, scope, arg);
Scriptable obj = cx.newObject(scope);
ScriptRuntime.loadFromIterable(
cx,
scope,
arg,
(key, value) -> {
if (key instanceof Integer) {
obj.put((Integer) key, obj, value);
} else if (key instanceof Symbol
&& obj instanceof SymbolScriptable) {
((SymbolScriptable) obj).put((Symbol) key, obj, value);
} else {
obj.put(ScriptRuntime.toString(key), obj, value);
}
});
return obj;
}
case ConstructorId_values:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
Scriptable obj = getCompatibleObject(cx, scope, arg);
Object[] ids = obj.getIds();
int j = 0;
for (int i = 0; i < ids.length; i++) {
if (ids[i] instanceof Integer) {
int intId = (Integer) ids[i];
if (obj.has(intId, obj) && isEnumerable(intId, obj)) {
ids[j++] = obj.get(intId, obj);
}
} else {
String stringId = ScriptRuntime.toString(ids[i]);
// getter may remove keys
if (obj.has(stringId, obj) && isEnumerable(stringId, obj)) {
ids[j++] = obj.get(stringId, obj);
}
}
}
if (j != ids.length) {
ids = Arrays.copyOf(ids, j);
}
return cx.newArray(scope, ids);
}
case ConstructorId_getOwnPropertyNames:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
Scriptable s = getCompatibleObject(cx, scope, arg);
ScriptableObject obj = ensureScriptableObject(s);
Object[] ids = obj.getIds(true, false);
for (int i = 0; i < ids.length; i++) {
ids[i] = ScriptRuntime.toString(ids[i]);
}
return cx.newArray(scope, ids);
}
case ConstructorId_getOwnPropertySymbols:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
Scriptable s = getCompatibleObject(cx, scope, arg);
ScriptableObject obj = ensureScriptableObject(s);
Object[] ids = obj.getIds(true, true);
ArrayList
© 2015 - 2024 Weber Informatics LLC | Privacy Policy