/** * 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 com.github.anba.es6draft.runtime.internal.Messages; import com.github.anba.es6draft.runtime.types.Constructor; import com.github.anba.es6draft.runtime.types.Reference; 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> * <ul> * <li>8.1.2 Lexical Environment Operations * </ul> */ public final class LexicalEnvironment<RECORD extends EnvironmentRecord> { private final ExecutionContext cx; private final LexicalEnvironment<?> outer; private final RECORD envRec; private LexicalEnvironment(ExecutionContext cx, RECORD envRec) { assert envRec instanceof GlobalEnvironmentRecord; this.cx = cx; this.outer = null; this.envRec = envRec; } /** * Creates a new lexical environment. * * @param outer * the outer lexical environment * @param envRec * the environment record */ public LexicalEnvironment(LexicalEnvironment<?> outer, RECORD envRec) { this.cx = outer.cx; this.outer = outer; this.envRec = envRec; } @Override public String toString() { return String.format("%s: {envRec=%s}", getClass().getSimpleName(), envRec); } public RECORD getEnvRec() { return envRec; } public LexicalEnvironment<?> getOuter() { return outer; } /** * Returns a clone of the declarative {@link LexicalEnvironment}. * <p> * [Called from generated code] * * @param e * the source lexical environment * @return the cloned lexical environment */ public static LexicalEnvironment<DeclarativeEnvironmentRecord> cloneDeclarativeEnvironment( LexicalEnvironment<DeclarativeEnvironmentRecord> e) { DeclarativeEnvironmentRecord envRec = new DeclarativeEnvironmentRecord(e.envRec); return new LexicalEnvironment<>(e.outer, envRec); } /** * Retrieves the binding value of the first {@link EnvironmentRecord} which has a binding for * {@code name}. If no such binding exists a ReferenceError is thrown. * * @param lex * the lexical environment * @param name * the identifier name * @param strict * the strict mode flag * @return the resolved identifier value */ static Object getIdentifierValueOrThrow(LexicalEnvironment<?> lex, String name, boolean strict) { for (LexicalEnvironment<?> env = lex; env != null; env = env.outer) { Object value = env.envRec.getBindingValueOrNull(name, strict); if (value != null) { return value; } } throw newReferenceError(lex.cx, Messages.Key.UnresolvableReference, name); } /** * 8.1.2.1 GetIdentifierReference (lex, name, strict) * * @param lex * the lexical environment * @param name * the identifier name * @param strict * the strict mode flag * @return the resolved identifier reference */ public static Reference<?, String> getIdentifierReference(LexicalEnvironment<?> lex, String name, boolean strict) { /* steps 2-6 */ for (LexicalEnvironment<?> env = lex; env != null; env = env.outer) { Reference<? extends EnvironmentRecord, String> ref = env.envRec.getReferenceOrNull(name, strict); if (ref != null) { return ref; } } /* step 1 */ return new Reference.UnresolvableReference(name, strict); } /** * 8.1.2.2 NewDeclarativeEnvironment (E) * * @param e * the outer lexical environment * @return the new declarative environment */ public static LexicalEnvironment<DeclarativeEnvironmentRecord> newDeclarativeEnvironment(LexicalEnvironment<?> e) { /* step 2 */ DeclarativeEnvironmentRecord envRec = new DeclarativeEnvironmentRecord(e.cx, false); /* steps 1, 3-4 */ LexicalEnvironment<DeclarativeEnvironmentRecord> env = new LexicalEnvironment<>(e, envRec); /* step 5 */ return env; } /** * 8.1.2.2 NewDeclarativeEnvironment (E) * * @param e * the outer lexical environment * @return the new declarative environment */ public static LexicalEnvironment<DeclarativeEnvironmentRecord> newCatchDeclarativeEnvironment( LexicalEnvironment<?> e) { /* step 2 */ DeclarativeEnvironmentRecord envRec = new DeclarativeEnvironmentRecord(e.cx, true); /* steps 1, 3-4 */ LexicalEnvironment<DeclarativeEnvironmentRecord> env = new LexicalEnvironment<>(e, envRec); /* step 5 */ return env; } /** * 8.1.2.3 NewObjectEnvironment (O, E) * * @param o * the script object * @param e * the outer lexical environment * @return the new object environment */ public static LexicalEnvironment<ObjectEnvironmentRecord> newObjectEnvironment(ScriptObject o, LexicalEnvironment<?> e) { return newObjectEnvironment(o, e, false); } /** * 8.1.2.3 NewObjectEnvironment (O, E) * * @param o * the script object * @param e * the outer lexical environment * @param withEnvironment * the withEnvironment flag * @return the new object environment */ public static LexicalEnvironment<ObjectEnvironmentRecord> newObjectEnvironment(ScriptObject o, LexicalEnvironment<?> e, boolean withEnvironment) { /* step 2 */ ObjectEnvironmentRecord envRec = new ObjectEnvironmentRecord(e.cx, o, withEnvironment); /* steps 1, 3-4 */ LexicalEnvironment<ObjectEnvironmentRecord> env = new LexicalEnvironment<>(e, envRec); /* step 5 */ return env; } /** * 8.1.2.4 NewFunctionEnvironment ( F, newTarget ) * * @param f * the function object * @param newTarget * the newTarget constructor object or {@code null} * @param thisValue * the function this-binding or {@code null} * @return the new function environment */ public static LexicalEnvironment<FunctionEnvironmentRecord> newFunctionEnvironment(FunctionObject f, Constructor newTarget, Object thisValue) { /* steps 1-2 (not applicable) */ LexicalEnvironment<?> e = f.getEnvironment(); /* steps 4-10 */ FunctionEnvironmentRecord envRec = new FunctionEnvironmentRecord(e.cx, f, newTarget, thisValue); /* steps 3, 11-12 */ LexicalEnvironment<FunctionEnvironmentRecord> env = new LexicalEnvironment<>(e, envRec); /* step 13 */ return env; } /** * 8.1.2.4 NewFunctionEnvironment ( F, newTarget ) * * @param f * the function object * @param newTarget * the newTarget constructor object * @return the new function environment */ public static LexicalEnvironment<FunctionEnvironmentRecord> newFunctionEnvironment(FunctionObject f, Constructor newTarget) { /* steps 1-2 (not applicable) */ LexicalEnvironment<?> e = f.getEnvironment(); /* steps 4-10 */ FunctionEnvironmentRecord envRec = new FunctionEnvironmentRecord(e.cx, f, newTarget); /* steps 3, 11-12 */ LexicalEnvironment<FunctionEnvironmentRecord> env = new LexicalEnvironment<>(e, envRec); /* step 13 */ return env; } /** * 8.1.2.5 NewGlobalEnvironment ( G, thisValue ) * * @param cx * the default execution context * @param g * the global object * @param thisValue * the global this value * @return the new global environment */ public static LexicalEnvironment<GlobalEnvironmentRecord> newGlobalEnvironment(ExecutionContext cx, ScriptObject g, ScriptObject thisValue) { /* steps 2-7 */ GlobalEnvironmentRecord globalRec = new GlobalEnvironmentRecord(cx, g, thisValue); /* steps 1, 8-9 */ LexicalEnvironment<GlobalEnvironmentRecord> env = new LexicalEnvironment<>(cx, globalRec); /* step 10 */ return env; } /** * 8.1.2.6 NewModuleEnvironment (E) * * @param e * the outer lexical environment * @return the new module environment */ public static LexicalEnvironment<ModuleEnvironmentRecord> newModuleEnvironment(LexicalEnvironment<?> e) { /* step 2 */ ModuleEnvironmentRecord envRec = new ModuleEnvironmentRecord(e.cx); /* steps 1, 3-4 */ LexicalEnvironment<ModuleEnvironmentRecord> env = new LexicalEnvironment<>(e, envRec); /* step 5 */ return env; } }