/**
* 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.internal.Errors.newReferenceError;
import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.types.Constructor;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.builtins.FunctionObject;
/**
* <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.3 Function Environment Records
* </ul>
*/
public final class FunctionEnvironmentRecord extends DeclarativeEnvironmentRecord {
private final FunctionObject functionObject;
private final Constructor newTarget;
private final ScriptObject homeObject;
private Object thisValue;
private ThisBindingStatus thisBindingStatus;
public enum ThisBindingStatus {
Lexical, Initialized, Uninitialized
}
public FunctionEnvironmentRecord(ExecutionContext cx, FunctionObject functionObject, Constructor newTarget,
Object thisValue) {
super(cx, false);
this.functionObject = functionObject;
this.newTarget = newTarget;
this.homeObject = functionObject.getHomeObject();
this.thisValue = thisValue;
this.thisBindingStatus = thisValue != null ? ThisBindingStatus.Initialized : ThisBindingStatus.Lexical;
}
public FunctionEnvironmentRecord(ExecutionContext cx, FunctionObject functionObject, Constructor newTarget) {
super(cx, false);
this.functionObject = functionObject;
this.newTarget = newTarget;
this.homeObject = functionObject.getHomeObject();
this.thisValue = UNDEFINED;
this.thisBindingStatus = ThisBindingStatus.Uninitialized;
}
@Override
public String toString() {
return String
.format("%s:{%n\tfunctionObject=%s,%n\tnewTarget=%s,%n\thomeObject=%s,%n\tthisValue=%s,%n\tthisBindingStatus=%s,%n\tbindings=%s%n}",
getClass().getSimpleName(), functionObject, newTarget, homeObject,
thisValue, thisBindingStatus, bindingsToString());
}
/**
* Returns the {@code FunctionObject} field.
*
* @return the {@code FunctionObject} field
*/
public FunctionObject getFunctionObject() {
return functionObject;
}
/**
* Returns the {@code newTarget} field.
*
* @return the {@code newTarget} field
*/
public Constructor getNewTarget() {
return newTarget;
}
/**
* Returns the {@code thisBindingStatus} field.
*
* @return the {@code thisBindingStatus} field
*/
public ThisBindingStatus getThisBindingStatus() {
return thisBindingStatus;
}
/**
* 8.1.1.3.1 BindThisValue(V)
*
* @param cx
* the execution context
* @param thisValue
* the function {@code this} value
*/
public void bindThisValue(ExecutionContext cx, ScriptObject thisValue) {
/* step 1 (not applicable) */
/* step 2 */
assert thisBindingStatus != ThisBindingStatus.Lexical;
/* step 3 */
if (thisBindingStatus == ThisBindingStatus.Initialized) {
throw newReferenceError(cx, Messages.Key.InitializedThis);
}
/* step 4 */
this.thisValue = thisValue;
/* step 5 */
this.thisBindingStatus = ThisBindingStatus.Initialized;
/* step 5 (not applicable) */
}
/**
* 8.1.1.3.2 HasThisBinding ()
*/
@Override
public boolean hasThisBinding() {
/* steps 1-2 */
return thisValue != null;
}
/**
* 8.1.1.3.3 HasSuperBinding ()
*/
@Override
public boolean hasSuperBinding() {
/* steps 1-3 */
return thisValue != null && homeObject != null;
}
/**
* 8.1.1.3.4 GetThisBinding ()
*
* @param cx
* the execution context
*/
@Override
public Object getThisBinding(ExecutionContext cx) {
/* step 1 (not applicable) */
/* step 2 */
assert thisBindingStatus != ThisBindingStatus.Lexical;
/* step 3 */
if (thisBindingStatus == ThisBindingStatus.Uninitialized) {
throw newReferenceError(cx, Messages.Key.UninitializedThis);
}
/* step 4 */
return thisValue;
}
/**
* 8.1.1.3.5 GetSuperBase ()
*
* @param cx
* the execution context
* @return the prototype of the home object or {@code null} if no super binding was set
*/
public ScriptObject getSuperBase(ExecutionContext cx) {
/* step 1 (not applicable) */
/* step 2 */
ScriptObject home = homeObject;
/* step 3 */
if (home == null) {
return null;
}
/* step 4 (not applicable) */
/* step 5 */
return home.getPrototypeOf(cx);
}
}