//===--- Scope.h - Declarations for scope RAII objects ----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the Scope and FullExpr RAII objects.
//
//===----------------------------------------------------------------------===//

#ifndef SCOPE_H
#define SCOPE_H

#include "SILGenFunction.h"
#include "swift/SIL/SILDebugScope.h"
#include "Cleanup.h"

namespace swift {
namespace Lowering {

/// A Scope is a RAII object recording that a scope (e.g. a brace
/// statement) has been entered.
class LLVM_LIBRARY_VISIBILITY Scope {
  CleanupManager &Cleanups;
  CleanupsDepth Depth;
  CleanupsDepth SavedInnermostScope;
  CleanupLocation Loc;

  void popImpl() {
    Cleanups.Stack.checkIterator(Depth);
    Cleanups.Stack.checkIterator(Cleanups.InnermostScope);
    assert(Cleanups.InnermostScope == Depth && "popping scopes out of order");

    Cleanups.InnermostScope = SavedInnermostScope;
    Cleanups.endScope(Depth, Loc);
    Cleanups.Stack.checkIterator(Cleanups.InnermostScope);
    Cleanups.popTopDeadCleanups(Cleanups.InnermostScope);
  }

public:
  explicit Scope(CleanupManager &Cleanups, CleanupLocation L)
    : Cleanups(Cleanups), Depth(Cleanups.getCleanupsDepth()),
      SavedInnermostScope(Cleanups.InnermostScope),
      Loc(L) {
    assert(Depth.isValid());
    Cleanups.Stack.checkIterator(Cleanups.InnermostScope);
    Cleanups.InnermostScope = Depth;
  }

  void pop() {
    assert(Depth.isValid() && "popping a scope twice!");
    popImpl();
    Depth = CleanupsDepth::invalid();
  }
  
  ~Scope() {
    if (Depth.isValid()) popImpl();
  }
};

/// A FullExpr is a RAII object recording that a full-expression has
/// been entered.  A full-expression is essentially a very small scope
/// for the temporaries in an expression, with the added complexity
/// that (eventually, very likely) we have to deal with expressions
/// that are only conditionally evaluated.
class LLVM_LIBRARY_VISIBILITY FullExpr : private Scope {
public:
  explicit FullExpr(CleanupManager &Cleanups, CleanupLocation Loc)
    : Scope(Cleanups, Loc) {}
  using Scope::pop;
};

/// A LexicalScope is a Scope that is also exposed to the debug info.
class LLVM_LIBRARY_VISIBILITY LexicalScope : private Scope {
  SILGenFunction& SGF;
public:
  explicit LexicalScope(CleanupManager &Cleanups,
                        SILGenFunction& SGF,
                        CleanupLocation Loc)
    : Scope(Cleanups, Loc), SGF(SGF) {
    SGF.enterDebugScope(Loc);
  }
  using Scope::pop;

  ~LexicalScope() {
    SGF.leaveDebugScope();
  }
};


} // end namespace Lowering
} // end namespace swift

#endif
