| // Copyright 2020 The Tint Authors.  // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | #ifndef SRC_SCOPE_STACK_H_ | 
 | #define SRC_SCOPE_STACK_H_ | 
 |  | 
 | #include <unordered_map> | 
 | #include <vector> | 
 |  | 
 | #include "src/symbol.h" | 
 |  | 
 | namespace tint { | 
 |  | 
 | /// Used to store a stack of scope information. | 
 | /// The stack starts with a global scope which can not be popped. | 
 | template <class T> | 
 | class ScopeStack { | 
 |  public: | 
 |   /// Constructor | 
 |   ScopeStack() { | 
 |     // Push global bucket | 
 |     stack_.push_back({}); | 
 |   } | 
 |   /// Copy Constructor | 
 |   ScopeStack(const ScopeStack&) = default; | 
 |   ~ScopeStack() = default; | 
 |  | 
 |   /// Push a new scope on to the stack | 
 |   void push_scope() { stack_.push_back({}); } | 
 |  | 
 |   /// Pop the scope off the top of the stack | 
 |   void pop_scope() { | 
 |     if (stack_.size() > 1) { | 
 |       stack_.pop_back(); | 
 |     } | 
 |   } | 
 |  | 
 |   /// Set a global variable in the stack | 
 |   /// @param symbol the symbol of the variable | 
 |   /// @param val the value | 
 |   void set_global(const Symbol& symbol, T val) { stack_[0][symbol] = val; } | 
 |  | 
 |   /// Sets variable into the top most scope of the stack | 
 |   /// @param symbol the symbol of the variable | 
 |   /// @param val the value | 
 |   void set(const Symbol& symbol, T val) { stack_.back()[symbol] = val; } | 
 |  | 
 |   /// Checks for the given `symbol` in the stack | 
 |   /// @param symbol the symbol to look for | 
 |   /// @returns true if the stack contains `symbol` | 
 |   bool has(const Symbol& symbol) const { return get(symbol, nullptr); } | 
 |  | 
 |   /// Retrieves a given variable from the stack | 
 |   /// @param symbol the symbol to look for | 
 |   /// @param ret where to place the value | 
 |   /// @returns true if the symbol was successfully found, false otherwise | 
 |   bool get(const Symbol& symbol, T* ret) const { | 
 |     return get(symbol, ret, nullptr); | 
 |   } | 
 |  | 
 |   /// Retrieves a given variable from the stack | 
 |   /// @param symbol the symbol to look for | 
 |   /// @param ret where to place the value | 
 |   /// @param is_global set true if the symbol references a global variable | 
 |   /// otherwise unchanged | 
 |   /// @returns true if the symbol was successfully found, false otherwise | 
 |   bool get(const Symbol& symbol, T* ret, bool* is_global) const { | 
 |     for (auto iter = stack_.rbegin(); iter != stack_.rend(); ++iter) { | 
 |       auto& map = *iter; | 
 |       auto val = map.find(symbol); | 
 |  | 
 |       if (val != map.end()) { | 
 |         if (ret) { | 
 |           *ret = val->second; | 
 |         } | 
 |         if (is_global && iter == stack_.rend() - 1) { | 
 |           *is_global = true; | 
 |         } | 
 |         return true; | 
 |       } | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |  private: | 
 |   std::vector<std::unordered_map<Symbol, T>> stack_; | 
 | }; | 
 |  | 
 | }  // namespace tint | 
 |  | 
 | #endif  // SRC_SCOPE_STACK_H_ |