text: // Copyright 2015 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_DEBUG_DEBUG_SCOPES_H_
  #define V8_DEBUG_DEBUG_SCOPES_H_
  
  #include "src/debug/debug-frames.h"
  #include "src/frames.h"
  
  namespace v8 {
  namespace internal {
  
  class ParseInfo;
  
  // Iterate over the actual scopes visible from a stack frame or from a closure.
  // The iteration proceeds from the innermost visible nested scope outwards.
  // All scopes are backed by an actual context except the local scope,
  // which is inserted "artificially" in the context chain.
  class ScopeIterator {
   public:
    enum ScopeType {
      ScopeTypeGlobal = 0,
      ScopeTypeLocal,
      ScopeTypeWith,
      ScopeTypeClosure,
      ScopeTypeCatch,
      ScopeTypeBlock,
      ScopeTypeScript,
      ScopeTypeEval,
      ScopeTypeModule
    };
  
    static const int kScopeDetailsTypeIndex = 0;
    static const int kScopeDetailsObjectIndex = 1;
    static const int kScopeDetailsNameIndex = 2;
    static const int kScopeDetailsStartPositionIndex = 3;
    static const int kScopeDetailsEndPositionIndex = 4;
    static const int kScopeDetailsFunctionIndex = 5;
    static const int kScopeDetailsSize = 6;
  
    enum Option { DEFAULT, IGNORE_NESTED_SCOPES, COLLECT_NON_LOCALS };
  
    ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
                  Option options = DEFAULT);
  
    ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
    ScopeIterator(Isolate* isolate, Handle<JSGeneratorObject> generator);
  
    MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails();
  
    // More scopes?
    bool Done() { return context_.is_null(); }
  
    // Move to the next scope.
    void Next();
  
    // Return the type of the current scope.
    ScopeType Type();
  
    // Return the JavaScript object with the content of the current scope.
    MaybeHandle<JSObject> ScopeObject();
  
    bool HasContext();
  
    // Set variable value and return true on success.
    bool SetVariableValue(Handle<String> variable_name, Handle<Object> new_value);
  
    Handle<ScopeInfo> CurrentScopeInfo();
  
    // Return the context for this scope. For the local context there might not
    // be an actual context.
    Handle<Context> CurrentContext();
  
    // Populate the set with collected non-local variable names.
    Handle<StringSet> GetNonLocals();
  
  #ifdef DEBUG
    // Debug print of the content of the current scope.
    void DebugPrint();
  #endif
  
   private:
    struct ExtendedScopeInfo {
      ExtendedScopeInfo(Handle<ScopeInfo> info, int start, int end)
          : scope_info(info), start_position(start), end_position(end) {}
      explicit ExtendedScopeInfo(Handle<ScopeInfo> info)
          : scope_info(info), start_position(-1), end_position(-1) {}
      Handle<ScopeInfo> scope_info;
      int start_position;
      int end_position;
      bool is_hidden() { return start_position == -1 && end_position == -1; }
    };
  
    Isolate* isolate_;
    FrameInspector* const frame_inspector_;
    Handle<Context> context_;
    List<ExtendedScopeInfo> nested_scope_chain_;
    Handle<StringSet> non_locals_;
    bool seen_script_scope_;
  
    inline JavaScriptFrame* GetFrame() {
      return frame_inspector_->GetArgumentsFrame();
    }
  
    inline Handle<JSFunction> GetFunction() {
      return frame_inspector_->GetFunction();
    }
  
    void RetrieveScopeChain(DeclarationScope* scope);
  
    void CollectNonLocals(ParseInfo* info, DeclarationScope* scope);
  
    void UnwrapEvaluationContext();
  
    MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScriptScope();
    MUST_USE_RESULT MaybeHandle<JSObject> MaterializeLocalScope();
    MUST_USE_RESULT MaybeHandle<JSObject> MaterializeModuleScope();
    Handle<JSObject> MaterializeClosure();
    Handle<JSObject> MaterializeCatchScope();
    Handle<JSObject> MaterializeInnerScope();
    Handle<JSObject> WithContextExtension();
  
    bool SetLocalVariableValue(Handle<String> variable_name,
                               Handle<Object> new_value);
    bool SetInnerScopeVariableValue(Handle<String> variable_name,
                                    Handle<Object> new_value);
    bool SetClosureVariableValue(Handle<String> variable_name,
                                 Handle<Object> new_value);
    bool SetScriptVariableValue(Handle<String> variable_name,
                                Handle<Object> new_value);
    bool SetCatchVariableValue(Handle<String> variable_name,
                               Handle<Object> new_value);
  
    // Helper functions.
    bool SetParameterValue(Handle<ScopeInfo> scope_info, JavaScriptFrame* frame,
                           Handle<String> parameter_name,
                           Handle<Object> new_value);
    bool SetStackVariableValue(Handle<ScopeInfo> scope_info,
                               Handle<String> variable_name,
                               Handle<Object> new_value);
    bool SetContextVariableValue(Handle<ScopeInfo> scope_info,
                                 Handle<Context> context,
                                 Handle<String> variable_name,
                                 Handle<Object> new_value);
  
    void CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
                                        Handle<Context> context,
                                        Handle<JSObject> scope_object);
    void CopyModuleVarsToScopeObject(Handle<ScopeInfo> scope_info,
                                     Handle<Context> context,
                                     Handle<JSObject> scope_object);
    void CopyContextExtensionToScopeObject(Handle<Context> context,
                                           Handle<JSObject> scope_object,
                                           KeyCollectionMode mode);
  
    // Get the chain of nested scopes within this scope for the source statement
    // position. The scopes will be added to the list from the outermost scope to
    // the innermost scope. Only nested block, catch or with scopes are tracked
    // and will be returned, but no inner function scopes.
    void GetNestedScopeChain(Isolate* isolate, Scope* scope,
                             int statement_position);
  
    DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
  };
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_DEBUG_DEBUG_SCOPES_H_
  