/**
* 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;
import static com.github.anba.es6draft.runtime.AbstractOperations.*;
import static com.github.anba.es6draft.runtime.internal.Errors.newReferenceError;
import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.types.BuiltinSymbol;
import com.github.anba.es6draft.runtime.types.PropertyDescriptor;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.Type;
/**
* <h1>8 Executable Code and Execution Contexts</h1><br>
* <h2>8.1 Lexical Environments</h2><br>
* <h3>8.1.1 Environment Records</h3>
* <ul>
* <li>8.1.1.2 Object Environment Records
* </ul>
*/
public final class ObjectEnvironmentRecord implements EnvironmentRecord {
private final ExecutionContext cx;
private final ScriptObject bindings;
private final boolean withEnvironment;
public ObjectEnvironmentRecord(ExecutionContext cx, ScriptObject bindings, boolean withEnvironment) {
this.cx = cx;
this.bindings = bindings;
this.withEnvironment = withEnvironment;
}
@Override
public String toString() {
return String.format("%s: {%n\twithEnvironment=%b,%n\tbindings=%n\t%s%n}", getClass().getSimpleName(),
withEnvironment, bindings);
}
@Override
public Set<String> bindingNames() {
HashSet<String> names = new HashSet<>();
for (Iterator<?> keys = bindings.enumerateKeys(cx); keys.hasNext();) {
Object key = keys.next();
Object propertyKey = ToPropertyKey(cx, key);
if (propertyKey instanceof String) {
names.add((String) propertyKey);
}
}
return names;
}
/**
* 8.1.1.2.1 HasBinding(N)
*/
@Override
public boolean hasBinding(String name) {
/* step 1 (omitted) */
/* step 2 */
ScriptObject bindings = this.bindings;
/* steps 3-4 */
boolean foundBinding = HasProperty(cx, bindings, name);
/* step 5 */
if (!foundBinding) {
return false;
}
/* step 6 */
if (!withEnvironment) {
return true;
}
/* steps 7-8 */
Object unscopables = Get(cx, bindings, BuiltinSymbol.unscopables.get());
/* step 9 */
if (Type.isObject(unscopables)) {
boolean blocked = ToBoolean(Get(cx, Type.objectValue(unscopables), name));
if (blocked) {
return false;
}
}
/* step 10 */
return true;
}
/**
* 8.1.1.2.2 CreateMutableBinding (N,D)
*/
@Override
public void createMutableBinding(String name, boolean deletable) {
/* steps 1-2 (omitted) */
/* steps 3-4 */
PropertyDescriptor desc = new PropertyDescriptor(UNDEFINED, true, true, deletable);
DefinePropertyOrThrow(cx, bindings, name, desc);
}
/**
* 8.1.1.2.3 CreateImmutableBinding (N, S)
*/
@Override
public void createImmutableBinding(String name, boolean strict) {
throw new IllegalStateException();
}
/**
* 8.1.1.2.4 InitializeBinding (N,V)
*/
@Override
public void initializeBinding(String name, Object value) {
assert value != null;
/* step 1 (omitted) */
/* steps 2-3 (not applicable) */
/* step 4 */
setMutableBinding(name, value, false);
}
/**
* 8.1.1.2.5 SetMutableBinding (N,V,S)
*/
@Override
public void setMutableBinding(String name, Object value, boolean strict) {
/* steps 1-2 (omitted) */
/* step 3 */
Set(cx, bindings, name, value, strict);
}
/**
* 8.1.1.2.6 GetBindingValue(N,S)
*/
@Override
public Object getBindingValue(String name, boolean strict) {
/* step 1 (omitted) */
/* step 2 */
ScriptObject bindings = this.bindings;
/* steps 3-4 */
boolean foundBinding = HasProperty(cx, bindings, name);
/* step 5 */
if (!foundBinding) {
if (!strict) {
return UNDEFINED;
}
throw newReferenceError(cx, Messages.Key.UnresolvableReference, name);
}
/* step 6 */
return Get(cx, bindings, name);
}
/**
* 8.1.1.2.7 DeleteBinding (N)
*/
@Override
public boolean deleteBinding(String name) {
/* steps 1-2 (omitted) */
/* step 3 */
return bindings.delete(cx, name);
}
/**
* 8.1.1.2.8 HasThisBinding ()
*/
@Override
public boolean hasThisBinding() {
/* step 1 */
return false;
}
/**
* -
*/
@Override
public Object getThisBinding(ExecutionContext cx) {
throw new IllegalStateException();
}
/**
* 8.1.1.2.9 HasSuperBinding ()
*/
@Override
public boolean hasSuperBinding() {
/* step 1 */
return false;
}
/**
* 8.1.1.2.10 WithBaseObject()
*/
@Override
public ScriptObject withBaseObject() {
/* step 1 (omitted) */
/* step 2 */
if (withEnvironment) {
return bindings;
}
/* step 3 */
return null;
}
}