/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.objects; import static com.github.anba.es6draft.runtime.AbstractOperations.*; import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError; import static com.github.anba.es6draft.runtime.internal.Properties.createProperties; import static com.github.anba.es6draft.runtime.types.Null.NULL; import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.internal.CompatibilityOption; import com.github.anba.es6draft.runtime.internal.Initializable; import com.github.anba.es6draft.runtime.internal.Messages; import com.github.anba.es6draft.runtime.internal.Properties.Accessor; import com.github.anba.es6draft.runtime.internal.Properties.CompatibilityExtension; import com.github.anba.es6draft.runtime.internal.Properties.Function; import com.github.anba.es6draft.runtime.internal.Properties.Prototype; import com.github.anba.es6draft.runtime.internal.Properties.Value; import com.github.anba.es6draft.runtime.types.BuiltinSymbol; import com.github.anba.es6draft.runtime.types.Intrinsics; import com.github.anba.es6draft.runtime.types.Property; import com.github.anba.es6draft.runtime.types.ScriptObject; import com.github.anba.es6draft.runtime.types.Type; import com.github.anba.es6draft.runtime.types.builtins.ImmutablePrototypeObject; import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject; /** * <h1>19 Fundamental Objects</h1><br> * <h2>19.1 Object Objects</h2> * <ul> * <li>19.1.3 Properties of the Object Prototype Object * <li>19.1.4 Properties of Object Instances * </ul> */ public final class ObjectPrototype extends ImmutablePrototypeObject implements Initializable { /** * Constructs a new Object prototype object. * * @param realm * the realm object */ public ObjectPrototype(Realm realm) { super(realm, null); } @Override public void initialize(Realm realm) { createProperties(realm, this, Properties.class); createProperties(realm, this, AdditionalProperties.class); } public enum Properties { ; @Prototype public static final ScriptObject __proto__ = null; /** * 19.1.3.1 Object.prototype.constructor */ @Value(name = "constructor") public static final Intrinsics constructor = Intrinsics.Object; /** * 19.1.3.6 Object.prototype.toString ( ) * * @param cx * the execution context * @param thisValue * the function this-value * @return the string representation */ @Function(name = "toString", arity = 0) public static Object toString(ExecutionContext cx, Object thisValue) { /* step 1 */ if (Type.isUndefined(thisValue)) { return "[object Undefined]"; } /* step 2 */ if (Type.isNull(thisValue)) { return "[object Null]"; } /* step 3 */ ScriptObject o = ToObject(cx, thisValue); /* steps 4-5 */ boolean isArray = IsArray(cx, o); /* steps 6-15 (not applicable) */ /* steps 16-17 */ Object ttag = Get(cx, o, BuiltinSymbol.toStringTag.get()); /* step 18 */ String tag; if (!Type.isString(ttag)) { tag = isArray ? "Array" : o.className(); } else { tag = Type.stringValue(ttag).toString(); } /* step 19 */ return "[object " + tag + "]"; } /** * 19.1.3.5 Object.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ) * * @param cx * the execution context * @param thisValue * the function this-value * @return the locale specific string representation */ @Function(name = "toLocaleString", arity = 0) public static Object toLocaleString(ExecutionContext cx, Object thisValue) { /* steps 1-2 */ return Invoke(cx, thisValue, "toString"); } /** * 19.1.3.7 Object.prototype.valueOf ( ) * * @param cx * the execution context * @param thisValue * the function this-value * @return the object value */ @Function(name = "valueOf", arity = 0) public static Object valueOf(ExecutionContext cx, Object thisValue) { /* steps 1-2 */ return ToObject(cx, thisValue); } /** * 19.1.3.2 Object.prototype.hasOwnProperty (V) * * @param cx * the execution context * @param thisValue * the function this-value * @param v * the property key * @return {@code true} if the property is present */ @Function(name = "hasOwnProperty", arity = 1) public static Object hasOwnProperty(ExecutionContext cx, Object thisValue, Object v) { /* steps 1-2 */ Object p = ToPropertyKey(cx, v); /* steps 3-4 */ ScriptObject o = ToObject(cx, thisValue); /* step 5 */ return HasOwnProperty(cx, o, p); } /** * 19.1.3.3 Object.prototype.isPrototypeOf (V) * * @param cx * the execution context * @param thisValue * the function this-value * @param v * the script object * @return {@code true} if the this-value was found in the prototype chain of <var>v</var> */ @Function(name = "isPrototypeOf", arity = 1) public static Object isPrototypeOf(ExecutionContext cx, Object thisValue, Object v) { /* step 1 */ if (!Type.isObject(v)) { return false; } ScriptObject _v = Type.objectValue(v); /* steps 2-3 */ ScriptObject o = ToObject(cx, thisValue); /* step 4 */ for (;;) { _v = _v.getPrototypeOf(cx); if (_v == null) { return false; } if (o == _v) { return true; } } } /** * 19.1.3.4 Object.prototype.propertyIsEnumerable (V) * * @param cx * the execution context * @param thisValue * the function this-value * @param v * the property key * @return {@code true} if the property is enumerable */ @Function(name = "propertyIsEnumerable", arity = 1) public static Object propertyIsEnumerable(ExecutionContext cx, Object thisValue, Object v) { /* steps 1-2 */ Object p = ToPropertyKey(cx, v); /* steps 3-4 */ ScriptObject o = ToObject(cx, thisValue); /* steps 5-6 */ Property desc = o.getOwnProperty(cx, p); /* step 7 */ if (desc == null) { return false; } /* step 8 */ return desc.isEnumerable(); } } /** * B.2.2 Additional Properties of the Object.prototype Object */ @CompatibilityExtension(CompatibilityOption.ObjectPrototype) public enum AdditionalProperties { ; /** * B.2.2.1 Object.prototype.__proto__<br> * B.2.2.1.1 get Object.prototype.__proto__ * * @param cx * the execution context * @param thisValue * the function this-value * @return the prototype object */ @Accessor(name = "__proto__", type = Accessor.Type.Getter) public static Object getPrototype(ExecutionContext cx, Object thisValue) { /* steps 1-2 */ ScriptObject o = ToObject(cx, thisValue); /* step 3 */ ScriptObject p = o.getPrototypeOf(cx); return p != null ? p : NULL; } /** * B.2.2.1 Object.prototype.__proto__<br> * B.2.2.1.2 set Object.prototype.__proto__ * * @param cx * the execution context * @param thisValue * the function this-value * @param proto * the new prototype object * @return the prototype object */ @Accessor(name = "__proto__", type = Accessor.Type.Setter) public static Object setPrototype(ExecutionContext cx, Object thisValue, Object proto) { /* steps 1-2 */ Object o = RequireObjectCoercible(cx, thisValue); /* step 3 */ if (!Type.isObjectOrNull(proto)) { return UNDEFINED; } /* step 4 */ if (!Type.isObject(o)) { return UNDEFINED; } /* steps 5-6 */ ScriptObject obj = Type.objectValue(o); boolean status = obj.setPrototypeOf(cx, Type.objectValueOrNull(proto)); /* step 7 */ if (!status) { // provide better error messages for ordinary objects if (obj instanceof OrdinaryObject && !(obj instanceof ImmutablePrototypeObject)) { if (!obj.isExtensible(cx)) { throw newTypeError(cx, Messages.Key.NotExtensible); } throw newTypeError(cx, Messages.Key.CyclicProto); } throw newTypeError(cx, Messages.Key.ObjectSetPrototypeFailed); } /* step 8 */ return UNDEFINED; } } }