// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_AST_SCOPES_H_ #define V8_AST_SCOPES_H_ #include "src/ast/ast.h" #include "src/base/hashmap.h" #include "src/pending-compilation-error-handler.h" #include "src/zone.h" namespace v8 { namespace internal { class ParseInfo; // A hash map to support fast variable declaration and lookup. class VariableMap: public ZoneHashMap { public: explicit VariableMap(Zone* zone); virtual ~VariableMap(); Variable* Declare(Scope* scope, const AstRawString* name, VariableMode mode, Variable::Kind kind, InitializationFlag initialization_flag, MaybeAssignedFlag maybe_assigned_flag = kNotAssigned); Variable* Lookup(const AstRawString* name); Zone* zone() const { return zone_; } private: Zone* zone_; }; // The dynamic scope part holds hash maps for the variables that will // be looked up dynamically from within eval and with scopes. The objects // are allocated on-demand from Scope::NonLocal to avoid wasting memory // and setup time for scopes that don't need them. class DynamicScopePart : public ZoneObject { public: explicit DynamicScopePart(Zone* zone) { for (int i = 0; i < 3; i++) maps_[i] = new(zone->New(sizeof(VariableMap))) VariableMap(zone); } VariableMap* GetMap(VariableMode mode) { int index = mode - DYNAMIC; DCHECK(index >= 0 && index < 3); return maps_[index]; } private: VariableMap *maps_[3]; }; // Sloppy block-scoped function declarations to var-bind class SloppyBlockFunctionMap : public ZoneHashMap { public: explicit SloppyBlockFunctionMap(Zone* zone); virtual ~SloppyBlockFunctionMap(); void Declare(const AstRawString* name, SloppyBlockFunctionStatement* statement); typedef ZoneVector<SloppyBlockFunctionStatement*> Vector; private: Zone* zone_; }; // Global invariants after AST construction: Each reference (i.e. identifier) // to a JavaScript variable (including global properties) is represented by a // VariableProxy node. Immediately after AST construction and before variable // allocation, most VariableProxy nodes are "unresolved", i.e. not bound to a // corresponding variable (though some are bound during parse time). Variable // allocation binds each unresolved VariableProxy to one Variable and assigns // a location. Note that many VariableProxy nodes may refer to the same Java- // Script variable. class Scope: public ZoneObject { public: // --------------------------------------------------------------------------- // Construction Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type, AstValueFactory* value_factory, FunctionKind function_kind = kNormalFunction); // Compute top scope and allocate variables. For lazy compilation the top // scope only contains the single lazily compiled function, so this // doesn't re-allocate variables repeatedly. static bool Analyze(ParseInfo* info); static Scope* DeserializeScopeChain(Isolate* isolate, Zone* zone, Context* context, Scope* script_scope); // The scope name is only used for printing/debugging. void SetScopeName(const AstRawString* scope_name) { scope_name_ = scope_name; } void Initialize(); // Checks if the block scope is redundant, i.e. it does not contain any // block scoped declarations. In that case it is removed from the scope // tree and its children are reparented. Scope* FinalizeBlockScope(); // Inserts outer_scope into this scope's scope chain (and removes this // from the current outer_scope_'s inner_scopes_). // Assumes outer_scope_ is non-null. void ReplaceOuterScope(Scope* outer_scope); // Propagates any eagerly-gathered scope usage flags (such as calls_eval()) // to the passed-in scope. void PropagateUsageFlagsToScope(Scope* other); Zone* zone() const { return zone_; } // --------------------------------------------------------------------------- // Declarations // Lookup a variable in this scope. Returns the variable or NULL if not found. Variable* LookupLocal(const AstRawString* name); // This lookup corresponds to a lookup in the "intermediate" scope sitting // between this scope and the outer scope. (ECMA-262, 3rd., requires that // the name of named function literal is kept in an intermediate scope // in between this scope and the next outer scope.) Variable* LookupFunctionVar(const AstRawString* name, AstNodeFactory* factory); // Lookup a variable in this scope or outer scopes. // Returns the variable or NULL if not found. Variable* Lookup(const AstRawString* name); // Declare the function variable for a function literal. This variable // is in an intermediate scope between this function scope and the the // outer scope. Only possible for function scopes; at most one variable. void DeclareFunctionVar(VariableDeclaration* declaration) { DCHECK(is_function_scope()); // Handle implicit declaration of the function name in named function // expressions before other declarations. decls_.InsertAt(0, declaration, zone()); function_ = declaration; } // Declare a parameter in this scope. When there are duplicated // parameters the rightmost one 'wins'. However, the implementation // expects all parameters to be declared and from left to right. Variable* DeclareParameter( const AstRawString* name, VariableMode mode, bool is_optional, bool is_rest, bool* is_duplicate); // Declare a local variable in this scope. If the variable has been // declared before, the previously declared variable is returned. Variable* DeclareLocal(const AstRawString* name, VariableMode mode, InitializationFlag init_flag, Variable::Kind kind, MaybeAssignedFlag maybe_assigned_flag = kNotAssigned); // Declare an implicit global variable in this scope which must be a // script scope. The variable was introduced (possibly from an inner // scope) by a reference to an unresolved variable with no intervening // with statements or eval calls. Variable* DeclareDynamicGlobal(const AstRawString* name); // Create a new unresolved variable. VariableProxy* NewUnresolved(AstNodeFactory* factory, const AstRawString* name, Variable::Kind kind = Variable::NORMAL, int start_position = RelocInfo::kNoPosition, int end_position = RelocInfo::kNoPosition) { // Note that we must not share the unresolved variables with // the same name because they may be removed selectively via // RemoveUnresolved(). DCHECK(!already_resolved()); VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_position, end_position); unresolved_.Add(proxy, zone_); return proxy; } void AddUnresolved(VariableProxy* proxy) { DCHECK(!already_resolved()); DCHECK(!proxy->is_resolved()); unresolved_.Add(proxy, zone_); } // Remove a unresolved variable. During parsing, an unresolved variable // may have been added optimistically, but then only the variable name // was used (typically for labels). If the variable was not declared, the // addition introduced a new unresolved variable which may end up being // allocated globally as a "ghost" variable. RemoveUnresolved removes // such a variable again if it was added; otherwise this is a no-op. bool RemoveUnresolved(VariableProxy* var); // Creates a new temporary variable in this scope's TemporaryScope. The // name is only used for printing and cannot be used to find the variable. // In particular, the only way to get hold of the temporary is by keeping the // Variable* around. The name should not clash with a legitimate variable // names. Variable* NewTemporary(const AstRawString* name); // Remove a temporary variable. This is for adjusting the scope of // temporaries used when desugaring parameter initializers. // Returns the index at which it was found in this scope, or -1 if // it was not found. int RemoveTemporary(Variable* var); // Adds a temporary variable in this scope's TemporaryScope. This is for // adjusting the scope of temporaries used when desugaring parameter // initializers. void AddTemporary(Variable* var) { // Temporaries are only placed in ClosureScopes. DCHECK_EQ(ClosureScope(), this); temps_.Add(var, zone()); } // Adds the specific declaration node to the list of declarations in // this scope. The declarations are processed as part of entering // the scope; see codegen.cc:ProcessDeclarations. void AddDeclaration(Declaration* declaration); // --------------------------------------------------------------------------- // Illegal redeclaration support. // Check if the scope has conflicting var // declarations, i.e. a var declaration that has been hoisted from a nested // scope over a let binding of the same name. Declaration* CheckConflictingVarDeclarations(); // --------------------------------------------------------------------------- // Scope-specific info. // Inform the scope that the corresponding code contains an eval call. void RecordEvalCall() { scope_calls_eval_ = true; } // Inform the scope that the corresponding code uses "arguments". void RecordArgumentsUsage() { scope_uses_arguments_ = true; } // Inform the scope that the corresponding code uses "super". void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; } // Set the language mode flag (unless disabled by a global flag). void SetLanguageMode(LanguageMode language_mode) { DCHECK(!is_module_scope() || is_strict(language_mode)); language_mode_ = language_mode; } // Set the ASM module flag. void SetAsmModule() { asm_module_ = true; } // Inform the scope that the scope may execute declarations nonlinearly. // Currently, the only nonlinear scope is a switch statement. The name is // more general in case something else comes up with similar control flow, // for example the ability to break out of something which does not have // its own lexical scope. // The bit does not need to be stored on the ScopeInfo because none of // the three compilers will perform hole check elimination on a variable // located in VariableLocation::CONTEXT. So, direct eval and closures // will not expose holes. void SetNonlinear() { scope_nonlinear_ = true; } // Position in the source where this scope begins and ends. // // * For the scope of a with statement // with (obj) stmt // start position: start position of first token of 'stmt' // end position: end position of last token of 'stmt' // * For the scope of a block // { stmts } // start position: start position of '{' // end position: end position of '}' // * For the scope of a function literal or decalaration // function fun(a,b) { stmts } // start position: start position of '(' // end position: end position of '}' // * For the scope of a catch block // try { stms } catch(e) { stmts } // start position: start position of '(' // end position: end position of ')' // * For the scope of a for-statement // for (let x ...) stmt // start position: start position of '(' // end position: end position of last token of 'stmt' // * For the scope of a switch statement // switch (tag) { cases } // start position: start position of '{' // end position: end position of '}' int start_position() const { return start_position_; } void set_start_position(int statement_pos) { start_position_ = statement_pos; } int end_position() const { return end_position_; } void set_end_position(int statement_pos) { end_position_ = statement_pos; } // Scopes created for desugaring are hidden. I.e. not visible to the debugger. bool is_hidden() const { return is_hidden_; } void set_is_hidden() { is_hidden_ = true; } // In some cases we want to force context allocation for a whole scope. void ForceContextAllocation() { DCHECK(!already_resolved()); force_context_allocation_ = true; } bool has_forced_context_allocation() const { return force_context_allocation_; } // --------------------------------------------------------------------------- // Predicates. // Specific scope types. bool is_eval_scope() const { return scope_type_ == EVAL_SCOPE; } bool is_function_scope() const { return scope_type_ == FUNCTION_SCOPE; } bool is_module_scope() const { return scope_type_ == MODULE_SCOPE; } bool is_script_scope() const { return scope_type_ == SCRIPT_SCOPE; } bool is_catch_scope() const { return scope_type_ == CATCH_SCOPE; } bool is_block_scope() const { return scope_type_ == BLOCK_SCOPE; } bool is_with_scope() const { return scope_type_ == WITH_SCOPE; } bool is_arrow_scope() const { return is_function_scope() && IsArrowFunction(function_kind_); } bool is_declaration_scope() const { return is_declaration_scope_; } void set_is_declaration_scope() { is_declaration_scope_ = true; } // Information about which scopes calls eval. bool calls_eval() const { return scope_calls_eval_; } bool calls_sloppy_eval() const { return scope_calls_eval_ && is_sloppy(language_mode_); } bool outer_scope_calls_sloppy_eval() const { return outer_scope_calls_sloppy_eval_; } bool asm_module() const { return asm_module_; } bool asm_function() const { return asm_function_; } // Is this scope inside a with statement. bool inside_with() const { return scope_inside_with_; } // Does this scope access "arguments". bool uses_arguments() const { return scope_uses_arguments_; } // Does this scope access "super" property (super.foo). bool uses_super_property() const { return scope_uses_super_property_; } // Does this scope have the potential to execute declarations non-linearly? bool is_nonlinear() const { return scope_nonlinear_; } // Whether this needs to be represented by a runtime context. bool NeedsContext() const { // Catch and module scopes always have heap slots. DCHECK(!is_catch_scope() || num_heap_slots() > 0); DCHECK(!is_module_scope() || num_heap_slots() > 0); return is_with_scope() || num_heap_slots() > 0; } bool NeedsHomeObject() const { return scope_uses_super_property_ || ((scope_calls_eval_ || inner_scope_calls_eval_) && (IsConciseMethod(function_kind()) || IsAccessorFunction(function_kind()) || IsClassConstructor(function_kind()))); } // --------------------------------------------------------------------------- // Accessors. // The type of this scope. ScopeType scope_type() const { return scope_type_; } FunctionKind function_kind() const { return function_kind_; } // The language mode of this scope. LanguageMode language_mode() const { return language_mode_; } // The variable corresponding to the 'this' value. Variable* receiver() { DCHECK(has_this_declaration()); DCHECK_NOT_NULL(receiver_); return receiver_; } // TODO(wingo): Add a GLOBAL_SCOPE scope type which will lexically allocate // "this" (and no other variable) on the native context. Script scopes then // will not have a "this" declaration. bool has_this_declaration() const { return (is_function_scope() && !is_arrow_scope()) || is_module_scope(); } // The variable corresponding to the 'new.target' value. Variable* new_target_var() { return new_target_; } // The variable holding the function literal for named function // literals, or NULL. Only valid for function scopes. VariableDeclaration* function() const { DCHECK(is_function_scope()); return function_; } // Parameters. The left-most parameter has index 0. // Only valid for function scopes. Variable* parameter(int index) const { DCHECK(is_function_scope()); return params_[index]; } // Returns the default function arity excluding default or rest parameters. int default_function_length() const { return arity_; } // Returns the number of formal parameters, up to but not including the // rest parameter index (if the function has rest parameters), i.e. it // says 2 for // // function foo(a, b) { ... } // // and // // function foo(a, b, ...c) { ... } // // but for // // function foo(a, b, c = 1) { ... } // // we return 3 here. int num_parameters() const { return has_rest_parameter() ? params_.length() - 1 : params_.length(); } // A function can have at most one rest parameter. Returns Variable* or NULL. Variable* rest_parameter(int* index) const { *index = rest_index_; if (rest_index_ < 0) return NULL; return rest_parameter_; } bool has_rest_parameter() const { return rest_index_ >= 0; } bool has_simple_parameters() const { return has_simple_parameters_; } // TODO(caitp): manage this state in a better way. PreParser must be able to // communicate that the scope is non-simple, without allocating any parameters // as the Parser does. This is necessary to ensure that TC39's proposed early // error can be reported consistently regardless of whether lazily parsed or // not. void SetHasNonSimpleParameters() { DCHECK(is_function_scope()); has_simple_parameters_ = false; } // Retrieve `IsSimpleParameterList` of current or outer function. bool HasSimpleParameters() { Scope* scope = ClosureScope(); return !scope->is_function_scope() || scope->has_simple_parameters(); } // The local variable 'arguments' if we need to allocate it; NULL otherwise. Variable* arguments() const { DCHECK(!is_arrow_scope() || arguments_ == nullptr); return arguments_; } Variable* this_function_var() const { // This is only used in derived constructors atm. DCHECK(this_function_ == nullptr || (is_function_scope() && (IsClassConstructor(function_kind()) || IsConciseMethod(function_kind()) || IsAccessorFunction(function_kind())))); return this_function_; } // Declarations list. ZoneList<Declaration*>* declarations() { return &decls_; } // Inner scope list. ZoneList<Scope*>* inner_scopes() { return &inner_scopes_; } // The scope immediately surrounding this scope, or NULL. Scope* outer_scope() const { return outer_scope_; } // The ModuleDescriptor for this scope; only for module scopes. ModuleDescriptor* module() const { return module_descriptor_; } // --------------------------------------------------------------------------- // Variable allocation. // Collect stack and context allocated local variables in this scope. Note // that the function variable - if present - is not collected and should be // handled separately. void CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals, ZoneList<Variable*>* context_globals); // Current number of var or const locals. int num_var_or_const() { return num_var_or_const_; } // Result of variable allocation. int num_stack_slots() const { return num_stack_slots_; } int num_heap_slots() const { return num_heap_slots_; } int num_global_slots() const { return num_global_slots_; } int StackLocalCount() const; int ContextLocalCount() const; int ContextGlobalCount() const; // Make sure this scope and all outer scopes are eagerly compiled. void ForceEagerCompilation() { force_eager_compilation_ = true; } // Determine if we can parse a function literal in this scope lazily. bool AllowsLazyParsing() const; // Determine if we can use lazy compilation for this scope. bool AllowsLazyCompilation() const; // Determine if we can use lazy compilation for this scope without a context. bool AllowsLazyCompilationWithoutContext() const; // True if the outer context of this scope is always the native context. bool HasTrivialOuterContext() const; // The number of contexts between this and scope; zero if this == scope. int ContextChainLength(Scope* scope); // The maximum number of nested contexts required for this scope and any inner // scopes. int MaxNestedContextChainLength(); // Find the first function, script, eval or (declaration) block scope. This is // the scope where var declarations will be hoisted to in the implementation. Scope* DeclarationScope(); // Find the first non-block declaration scope. This should be either a script, // function, or eval scope. Same as DeclarationScope(), but skips // declaration "block" scopes. Used for differentiating associated // function objects (i.e., the scope for which a function prologue allocates // a context) or declaring temporaries. Scope* ClosureScope(); // Find the first (non-arrow) function or script scope. This is where // 'this' is bound, and what determines the function kind. Scope* ReceiverScope(); Handle<ScopeInfo> GetScopeInfo(Isolate* isolate); Handle<StringSet> CollectNonLocals(Handle<StringSet> non_locals); // --------------------------------------------------------------------------- // Strict mode support. bool IsDeclared(const AstRawString* name) { // During formal parameter list parsing the scope only contains // two variables inserted at initialization: "this" and "arguments". // "this" is an invalid parameter name and "arguments" is invalid parameter // name in strict mode. Therefore looking up with the map which includes // "this" and "arguments" in addition to all formal parameters is safe. return variables_.Lookup(name) != NULL; } bool IsDeclaredParameter(const AstRawString* name) { // If IsSimpleParameterList is false, duplicate parameters are not allowed, // however `arguments` may be allowed if function is not strict code. Thus, // the assumptions explained above do not hold. return params_.Contains(variables_.Lookup(name)); } SloppyBlockFunctionMap* sloppy_block_function_map() { return &sloppy_block_function_map_; } // --------------------------------------------------------------------------- // Debugging. #ifdef DEBUG void Print(int n = 0); // n = indentation; n < 0 => don't print recursively // Check that the scope has positions assigned. void CheckScopePositions(); #endif // --------------------------------------------------------------------------- // Implementation. private: // Scope tree. Scope* outer_scope_; // the immediately enclosing outer scope, or NULL ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes // The scope type. ScopeType scope_type_; // If the scope is a function scope, this is the function kind. FunctionKind function_kind_; // Debugging support. const AstRawString* scope_name_; // The variables declared in this scope: // // All user-declared variables (incl. parameters). For script scopes // variables may be implicitly 'declared' by being used (possibly in // an inner scope) with no intervening with statements or eval calls. VariableMap variables_; // Compiler-allocated (user-invisible) temporaries. Due to the implementation // of RemoveTemporary(), may contain nulls, which must be skipped-over during // allocation and printing. ZoneList<Variable*> temps_; // Parameter list in source order. ZoneList<Variable*> params_; // Variables that must be looked up dynamically. DynamicScopePart* dynamics_; // Unresolved variables referred to from this scope. ZoneList<VariableProxy*> unresolved_; // Declarations. ZoneList<Declaration*> decls_; // Convenience variable. Variable* receiver_; // Function variable, if any; function scopes only. VariableDeclaration* function_; // new.target variable, function scopes only. Variable* new_target_; // Convenience variable; function scopes only. Variable* arguments_; // Convenience variable; Subclass constructor only Variable* this_function_; // Module descriptor; module scopes only. ModuleDescriptor* module_descriptor_; // Map of function names to lists of functions defined in sloppy blocks SloppyBlockFunctionMap sloppy_block_function_map_; // Scope-specific information computed during parsing. // // This scope is inside a 'with' of some outer scope. bool scope_inside_with_; // This scope or a nested catch scope or with scope contain an 'eval' call. At // the 'eval' call site this scope is the declaration scope. bool scope_calls_eval_; // This scope uses "arguments". bool scope_uses_arguments_; // This scope uses "super" property ('super.foo'). bool scope_uses_super_property_; // This scope contains an "use asm" annotation. bool asm_module_; // This scope's outer context is an asm module. bool asm_function_; // This scope's declarations might not be executed in order (e.g., switch). bool scope_nonlinear_; // The language mode of this scope. LanguageMode language_mode_; // Source positions. int start_position_; int end_position_; bool is_hidden_; // Computed via PropagateScopeInfo. bool outer_scope_calls_sloppy_eval_; bool inner_scope_calls_eval_; bool force_eager_compilation_; bool force_context_allocation_; // True if it doesn't need scope resolution (e.g., if the scope was // constructed based on a serialized scope info or a catch context). bool already_resolved_; // True if it holds 'var' declarations. bool is_declaration_scope_; // Computed as variables are declared. int num_var_or_const_; // Computed via AllocateVariables; function, block and catch scopes only. int num_stack_slots_; int num_heap_slots_; int num_global_slots_; // Info about the parameter list of a function. int arity_; bool has_simple_parameters_; Variable* rest_parameter_; int rest_index_; // Serialized scope info support. Handle<ScopeInfo> scope_info_; bool already_resolved() { return already_resolved_; } // Create a non-local variable with a given name. // These variables are looked up dynamically at runtime. Variable* NonLocal(const AstRawString* name, VariableMode mode); // Variable resolution. // Possible results of a recursive variable lookup telling if and how a // variable is bound. These are returned in the output parameter *binding_kind // of the LookupRecursive function. enum BindingKind { // The variable reference could be statically resolved to a variable binding // which is returned. There is no 'with' statement between the reference and // the binding and no scope between the reference scope (inclusive) and // binding scope (exclusive) makes a sloppy 'eval' call. BOUND, // The variable reference could be statically resolved to a variable binding // which is returned. There is no 'with' statement between the reference and // the binding, but some scope between the reference scope (inclusive) and // binding scope (exclusive) makes a sloppy 'eval' call, that might // possibly introduce variable bindings shadowing the found one. Thus the // found variable binding is just a guess. BOUND_EVAL_SHADOWED, // The variable reference could not be statically resolved to any binding // and thus should be considered referencing a global variable. NULL is // returned. The variable reference is not inside any 'with' statement and // no scope between the reference scope (inclusive) and script scope // (exclusive) makes a sloppy 'eval' call. UNBOUND, // The variable reference could not be statically resolved to any binding // NULL is returned. The variable reference is not inside any 'with' // statement, but some scope between the reference scope (inclusive) and // script scope (exclusive) makes a sloppy 'eval' call, that might // possibly introduce a variable binding. Thus the reference should be // considered referencing a global variable unless it is shadowed by an // 'eval' introduced binding. UNBOUND_EVAL_SHADOWED, // The variable could not be statically resolved and needs to be looked up // dynamically. NULL is returned. There are two possible reasons: // * A 'with' statement has been encountered and there is no variable // binding for the name between the variable reference and the 'with'. // The variable potentially references a property of the 'with' object. // * The code is being executed as part of a call to 'eval' and the calling // context chain contains either a variable binding for the name or it // contains a 'with' context. DYNAMIC_LOOKUP }; // Lookup a variable reference given by name recursively starting with this // scope. If the code is executed because of a call to 'eval', the context // parameter should be set to the calling context of 'eval'. Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind, AstNodeFactory* factory); MUST_USE_RESULT bool ResolveVariable(ParseInfo* info, VariableProxy* proxy, AstNodeFactory* factory); MUST_USE_RESULT bool ResolveVariablesRecursively(ParseInfo* info, AstNodeFactory* factory); // Scope analysis. void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval); bool HasTrivialContext() const; // Predicates. bool MustAllocate(Variable* var); bool MustAllocateInContext(Variable* var); bool HasArgumentsParameter(Isolate* isolate); // Variable allocation. void AllocateStackSlot(Variable* var); void AllocateHeapSlot(Variable* var); void AllocateParameterLocals(Isolate* isolate); void AllocateNonParameterLocal(Isolate* isolate, Variable* var); void AllocateDeclaredGlobal(Isolate* isolate, Variable* var); void AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate); void AllocateVariablesRecursively(Isolate* isolate); void AllocateParameter(Variable* var, int index); void AllocateReceiver(); // Resolve and fill in the allocation information for all variables // in this scopes. Must be called *after* all scopes have been // processed (parsed) to ensure that unresolved variables can be // resolved properly. // // In the case of code compiled and run using 'eval', the context // parameter is the context in which eval was called. In all other // cases the context parameter is an empty handle. MUST_USE_RESULT bool AllocateVariables(ParseInfo* info, AstNodeFactory* factory); // Construct a scope based on the scope info. Scope(Zone* zone, Scope* inner_scope, ScopeType type, Handle<ScopeInfo> scope_info, AstValueFactory* value_factory); // Construct a catch scope with a binding for the name. Scope(Zone* zone, Scope* inner_scope, const AstRawString* catch_variable_name, AstValueFactory* value_factory); void AddInnerScope(Scope* inner_scope) { if (inner_scope != NULL) { inner_scopes_.Add(inner_scope, zone_); inner_scope->outer_scope_ = this; } } void RemoveInnerScope(Scope* inner_scope) { DCHECK_NOT_NULL(inner_scope); for (int i = 0; i < inner_scopes_.length(); i++) { if (inner_scopes_[i] == inner_scope) { inner_scopes_.Remove(i); break; } } } void SetDefaults(ScopeType type, Scope* outer_scope, Handle<ScopeInfo> scope_info, FunctionKind function_kind = kNormalFunction); AstValueFactory* ast_value_factory_; Zone* zone_; PendingCompilationErrorHandler pending_error_handler_; }; } // namespace internal } // namespace v8 #endif // V8_AST_SCOPES_H_