/** * 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.reflect; 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.internal.ScriptRuntime.PrepareForTailCall; import static com.github.anba.es6draft.runtime.types.Null.NULL; import static com.github.anba.es6draft.runtime.types.PropertyDescriptor.FromPropertyDescriptor; import static com.github.anba.es6draft.runtime.types.PropertyDescriptor.ToPropertyDescriptor; import java.util.List; 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.CompatibilityExtension; import com.github.anba.es6draft.runtime.internal.Properties.Function; import com.github.anba.es6draft.runtime.internal.Properties.Optional; import com.github.anba.es6draft.runtime.internal.Properties.Prototype; import com.github.anba.es6draft.runtime.internal.Properties.TailCall; import com.github.anba.es6draft.runtime.internal.Properties.Value; import com.github.anba.es6draft.runtime.types.Callable; import com.github.anba.es6draft.runtime.types.Constructor; import com.github.anba.es6draft.runtime.types.Intrinsics; import com.github.anba.es6draft.runtime.types.Property; import com.github.anba.es6draft.runtime.types.PropertyDescriptor; import com.github.anba.es6draft.runtime.types.ScriptObject; import com.github.anba.es6draft.runtime.types.Type; import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject; /** * <h1>26 Reflection</h1> * <ul> * <li>26.1 The Reflect Object * </ul> */ public final class ReflectObject extends OrdinaryObject implements Initializable { /** * Constructs a new Reflect object. * * @param realm * the realm object */ public ReflectObject(Realm realm) { super(realm); } @Override public void initialize(Realm realm) { createProperties(realm, this, Properties.class); createProperties(realm, this, EnumerateProperty.class); createProperties(realm, this, RealmProperty.class); createProperties(realm, this, LoaderProperty.class); createProperties(realm, this, ParseProperty.class); } /** * 26.1 Properties of the Reflect Object */ public enum Properties { ; @Prototype public static final Intrinsics __proto__ = Intrinsics.ObjectPrototype; /** * 26.1.1 Reflect.apply ( target, thisArgument, argumentsList ) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param thisArgument * the this-binding for the [[Call]] invocation * @param argumentsList * the function arguments * @return the function call result */ @TailCall @Function(name = "apply", arity = 3) public static Object apply(ExecutionContext cx, Object thisValue, Object target, Object thisArgument, Object argumentsList) { /* step 1 */ if (!IsCallable(target)) { throw newTypeError(cx, Messages.Key.NotCallable); } /* steps 2-3 */ Object[] args = CreateListFromArrayLike(cx, argumentsList); /* steps 4-5 */ return PrepareForTailCall((Callable) target, thisArgument, args); } /** * 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] ) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param argumentsList * the function arguments * @param newTarget * the newTarget object * @return the new script object */ @Function(name = "construct", arity = 2) public static Object construct(ExecutionContext cx, Object thisValue, Object target, Object argumentsList, @Optional(Optional.Default.NONE) Object newTarget) { /* step 1 */ if (!IsConstructor(target)) { throw newTypeError(cx, Messages.Key.NotConstructor); } /* steps 2-3 */ if (newTarget == null) { // FIXME: spec issue - compare to undefined? // https://bugs.ecmascript.org/show_bug.cgi?id=4416 newTarget = target; } else if (!IsConstructor(newTarget)) { throw newTypeError(cx, Messages.Key.NotConstructor); } /* steps 4-5 */ Object[] args = CreateListFromArrayLike(cx, argumentsList); /* step 6 */ return ((Constructor) target).construct(cx, (Constructor) newTarget, args); } /** * 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param propertyKey * the property key * @param attributes * the property descriptor object * @return {@code true} on success */ @Function(name = "defineProperty", arity = 3) public static Object defineProperty(ExecutionContext cx, Object thisValue, Object target, Object propertyKey, Object attributes) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ Object key = ToPropertyKey(cx, propertyKey); /* steps 4-5 */ PropertyDescriptor desc = ToPropertyDescriptor(cx, attributes); /* step 6 */ return targetObject.defineOwnProperty(cx, key, desc); } /** * 26.1.4 Reflect.deleteProperty (target, propertyKey) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param propertyKey * the property key * @return {@code true} on success */ @Function(name = "deleteProperty", arity = 2) public static Object deleteProperty(ExecutionContext cx, Object thisValue, Object target, Object propertyKey) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ Object key = ToPropertyKey(cx, propertyKey); /* step 4 */ return targetObject.delete(cx, key); } /** * 26.1.6 Reflect.get (target, propertyKey [, receiver ]) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param propertyKey * the property key * @param receiver * the optional receiver object * @return the property value */ @Function(name = "get", arity = 2) public static Object get(ExecutionContext cx, Object thisValue, Object target, Object propertyKey, @Optional(Optional.Default.NONE) Object receiver) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ Object key = ToPropertyKey(cx, propertyKey); /* step 4 */ if (receiver == null) { receiver = target; } /* step 5 */ return targetObject.get(cx, key, receiver); } /** * 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param propertyKey * the property key * @return the property descriptor object */ @Function(name = "getOwnPropertyDescriptor", arity = 2) public static Object getOwnPropertyDescriptor(ExecutionContext cx, Object thisValue, Object target, Object propertyKey) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ Object key = ToPropertyKey(cx, propertyKey); /* steps 4-5 */ Property desc = targetObject.getOwnProperty(cx, key); /* step 6 */ return FromPropertyDescriptor(cx, desc); } /** * 26.1.8 Reflect.getPrototypeOf (target) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @return the prototype object */ @Function(name = "getPrototypeOf", arity = 1) public static Object getPrototypeOf(ExecutionContext cx, Object thisValue, Object target) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* step 2 */ ScriptObject proto = targetObject.getPrototypeOf(cx); return proto != null ? proto : NULL; } /** * 26.1.9 Reflect.has (target, propertyKey) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param propertyKey * the property key * @return {@code true} if the property was found */ @Function(name = "has", arity = 2) public static Object has(ExecutionContext cx, Object thisValue, Object target, Object propertyKey) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ Object key = ToPropertyKey(cx, propertyKey); /* step 4 */ return targetObject.hasProperty(cx, key); } /** * 26.1.10 Reflect.isExtensible (target) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @return {@code true} if the object is extensible */ @Function(name = "isExtensible", arity = 1) public static Object isExtensible(ExecutionContext cx, Object thisValue, Object target) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* step 2 */ return targetObject.isExtensible(cx); } /** * 26.1.11 Reflect.ownKeys (target) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @return the properties iterator object */ @Function(name = "ownKeys", arity = 1) public static Object ownKeys(ExecutionContext cx, Object thisValue, Object target) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ List<?> keys = targetObject.ownPropertyKeys(cx); /* step 4 */ return CreateArrayFromList(cx, keys); } /** * 26.1.12 Reflect.preventExtensions (target) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @return {@code true} on success */ @Function(name = "preventExtensions", arity = 1) public static Object preventExtensions(ExecutionContext cx, Object thisValue, Object target) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* step 2 */ return targetObject.preventExtensions(cx); } /** * 26.1.13 Reflect.set (target, propertyKey, V [, receiver ]) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param propertyKey * the property key * @param value * the new property value * @param receiver * the optional receiver object * @return {@code true} on success */ @Function(name = "set", arity = 3) public static Object set(ExecutionContext cx, Object thisValue, Object target, Object propertyKey, Object value, @Optional(Optional.Default.NONE) Object receiver) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* steps 2-3 */ Object key = ToPropertyKey(cx, propertyKey); /* step 4 */ if (receiver == null) { receiver = target; } /* step 5 */ return targetObject.set(cx, key, value, receiver); } /** * 26.1.14 Reflect.setPrototypeOf (target, proto) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @param proto * the new prototype object * @return {@code true} on success */ @Function(name = "setPrototypeOf", arity = 2) public static Object setPrototypeOf(ExecutionContext cx, Object thisValue, Object target, Object proto) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* step 2 */ if (!Type.isObjectOrNull(proto)) { throw newTypeError(cx, Messages.Key.NotObjectOrNull); } /* step 3 */ return targetObject.setPrototypeOf(cx, Type.objectValueOrNull(proto)); } } @CompatibilityExtension(CompatibilityOption.Enumerate) public enum EnumerateProperty { ; /** * 26.1.5 Reflect.enumerate (target) * * @param cx * the execution context * @param thisValue * the function this-value * @param target * the target object * @return the enumeration iterator object */ @Function(name = "enumerate", arity = 1) public static Object enumerate(ExecutionContext cx, Object thisValue, Object target) { /* step 1 */ if (!Type.isObject(target)) { throw newTypeError(cx, Messages.Key.NotObjectType); } ScriptObject targetObject = Type.objectValue(target); /* step 2 */ return targetObject.enumerate(cx); } } @CompatibilityExtension(CompatibilityOption.ReflectParse) public enum ParseProperty { ; /** * Reflect.parse(src[, options]) * * @param cx * the execution context * @param thisValue * the function this-value * @param src * the source string * @param options * the optional parse options * @return the parsed AST object */ @Function(name = "parse", arity = 1) public static Object parse(ExecutionContext cx, Object thisValue, Object src, Object options) { String source = ToFlatString(cx, src); ScriptObject opts; if (Type.isUndefinedOrNull(options)) { opts = null; } else if (!Type.isObject(options)) { throw newTypeError(cx, Messages.Key.NotObjectType); } else { opts = Type.objectValue(options); } return ReflectParser.parse(cx, source, opts); } } @CompatibilityExtension(CompatibilityOption.Realm) public enum RealmProperty { ; /** * Realm ( . . . ) */ @Value(name = "Realm") public static final Intrinsics Realm = Intrinsics.Realm; } @CompatibilityExtension(CompatibilityOption.Loader) public enum LoaderProperty { ; /** * Loader ( . . . ) */ @Value(name = "Loader") public static final Intrinsics Loader = Intrinsics.Loader; } }