Blame src/environment.cpp

Packit bfcc33
#include "sass.hpp"
Packit bfcc33
#include "ast.hpp"
Packit bfcc33
#include "environment.hpp"
Packit bfcc33
Packit bfcc33
namespace Sass {
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  Environment<T>::Environment(bool is_shadow)
Packit bfcc33
  : local_frame_(environment_map<std::string, T>()),
Packit bfcc33
    parent_(0), is_shadow_(false)
Packit bfcc33
  { }
Packit bfcc33
  template <typename T>
Packit bfcc33
  Environment<T>::Environment(Environment<T>* env, bool is_shadow)
Packit bfcc33
  : local_frame_(environment_map<std::string, T>()),
Packit bfcc33
    parent_(env), is_shadow_(is_shadow)
Packit bfcc33
  { }
Packit bfcc33
  template <typename T>
Packit bfcc33
  Environment<T>::Environment(Environment<T>& env, bool is_shadow)
Packit bfcc33
  : local_frame_(environment_map<std::string, T>()),
Packit bfcc33
    parent_(&env), is_shadow_(is_shadow)
Packit bfcc33
  { }
Packit bfcc33
Packit bfcc33
  // link parent to create a stack
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::link(Environment& env) { parent_ = &env; }
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::link(Environment* env) { parent_ = env; }
Packit bfcc33
Packit bfcc33
  // this is used to find the global frame
Packit bfcc33
  // which is the second last on the stack
Packit bfcc33
  template <typename T>
Packit bfcc33
  bool Environment<T>::is_lexical() const
Packit bfcc33
  {
Packit bfcc33
    return !! parent_ && parent_->parent_;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  // only match the real root scope
Packit bfcc33
  // there is still a parent around
Packit bfcc33
  // not sure what it is actually use for
Packit bfcc33
  // I guess we store functions etc. there
Packit bfcc33
  template <typename T>
Packit bfcc33
  bool Environment<T>::is_global() const
Packit bfcc33
  {
Packit bfcc33
    return parent_ && ! parent_->parent_;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  environment_map<std::string, T>& Environment<T>::local_frame() {
Packit bfcc33
    return local_frame_;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  bool Environment<T>::has_local(const std::string& key) const
Packit bfcc33
  { return local_frame_.find(key) != local_frame_.end(); }
Packit bfcc33
Packit bfcc33
  template <typename T> EnvResult
Packit bfcc33
  Environment<T>::find_local(const std::string& key)
Packit bfcc33
  {
Packit bfcc33
    auto end = local_frame_.end();
Packit bfcc33
    auto it = local_frame_.find(key);
Packit bfcc33
    return EnvResult(it, it != end);
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  T& Environment<T>::get_local(const std::string& key)
Packit bfcc33
  { return local_frame_[key]; }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::set_local(const std::string& key, const T& val)
Packit bfcc33
  {
Packit bfcc33
    local_frame_[key] = val;
Packit bfcc33
  }
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::set_local(const std::string& key, T&& val)
Packit bfcc33
  {
Packit bfcc33
    local_frame_[key] = val;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::del_local(const std::string& key)
Packit bfcc33
  { local_frame_.erase(key); }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  Environment<T>* Environment<T>::global_env()
Packit bfcc33
  {
Packit bfcc33
    Environment* cur = this;
Packit bfcc33
    while (cur->is_lexical()) {
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    return cur;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  bool Environment<T>::has_global(const std::string& key)
Packit bfcc33
  { return global_env()->has(key); }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  T& Environment<T>::get_global(const std::string& key)
Packit bfcc33
  { return (*global_env())[key]; }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::set_global(const std::string& key, const T& val)
Packit bfcc33
  {
Packit bfcc33
    global_env()->local_frame_[key] = val;
Packit bfcc33
  }
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::set_global(const std::string& key, T&& val)
Packit bfcc33
  {
Packit bfcc33
    global_env()->local_frame_[key] = val;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::del_global(const std::string& key)
Packit bfcc33
  { global_env()->local_frame_.erase(key); }
Packit bfcc33
Packit bfcc33
  template <typename T>
Packit bfcc33
  Environment<T>* Environment<T>::lexical_env(const std::string& key)
Packit bfcc33
  {
Packit bfcc33
    Environment* cur = this;
Packit bfcc33
    while (cur) {
Packit bfcc33
      if (cur->has_local(key)) {
Packit bfcc33
        return cur;
Packit bfcc33
      }
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    return this;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  // see if we have a lexical variable
Packit bfcc33
  // move down the stack but stop before we
Packit bfcc33
  // reach the global frame (is not included)
Packit bfcc33
  template <typename T>
Packit bfcc33
  bool Environment<T>::has_lexical(const std::string& key) const
Packit bfcc33
  {
Packit bfcc33
    auto cur = this;
Packit bfcc33
    while (cur->is_lexical()) {
Packit bfcc33
      if (cur->has_local(key)) return true;
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    return false;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  // see if we have a lexical we could update
Packit bfcc33
  // either update already existing lexical value
Packit bfcc33
  // or if flag is set, we create one if no lexical found
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::set_lexical(const std::string& key, const T& val)
Packit bfcc33
  {
Packit bfcc33
    Environment<T>* cur = this;
Packit bfcc33
    bool shadow = false;
Packit bfcc33
    while ((cur && cur->is_lexical()) || shadow) {
Packit bfcc33
      EnvResult rv(cur->find_local(key));
Packit bfcc33
      if (rv.found) {
Packit bfcc33
        rv.it->second = val;
Packit bfcc33
        return;
Packit bfcc33
      }
Packit bfcc33
      shadow = cur->is_shadow();
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    set_local(key, val);
Packit bfcc33
  }
Packit bfcc33
  // this one moves the value
Packit bfcc33
  template <typename T>
Packit bfcc33
  void Environment<T>::set_lexical(const std::string& key, T&& val)
Packit bfcc33
  {
Packit bfcc33
    Environment<T>* cur = this;
Packit bfcc33
    bool shadow = false;
Packit bfcc33
    while ((cur && cur->is_lexical()) || shadow) {
Packit bfcc33
      EnvResult rv(cur->find_local(key));
Packit bfcc33
      if (rv.found) {
Packit bfcc33
        rv.it->second = val;
Packit bfcc33
        return;
Packit bfcc33
      }
Packit bfcc33
      shadow = cur->is_shadow();
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    set_local(key, val);
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  // look on the full stack for key
Packit bfcc33
  // include all scopes available
Packit bfcc33
  template <typename T>
Packit bfcc33
  bool Environment<T>::has(const std::string& key) const
Packit bfcc33
  {
Packit bfcc33
    auto cur = this;
Packit bfcc33
    while (cur) {
Packit bfcc33
      if (cur->has_local(key)) {
Packit bfcc33
        return true;
Packit bfcc33
      }
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    return false;
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  // look on the full stack for key
Packit bfcc33
  // include all scopes available
Packit bfcc33
  template <typename T> EnvResult
Packit bfcc33
  Environment<T>::find(const std::string& key)
Packit bfcc33
  {
Packit bfcc33
    auto cur = this;
Packit bfcc33
    while (true) {
Packit bfcc33
      EnvResult rv(cur->find_local(key));
Packit bfcc33
      if (rv.found) return rv;
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
      if (!cur) return rv;
Packit bfcc33
    }
Packit bfcc33
  };
Packit bfcc33
Packit bfcc33
  // use array access for getter and setter functions
Packit bfcc33
  template <typename T>
Packit bfcc33
  T& Environment<T>::operator[](const std::string& key)
Packit bfcc33
  {
Packit bfcc33
    auto cur = this;
Packit bfcc33
    while (cur) {
Packit bfcc33
      if (cur->has_local(key)) {
Packit bfcc33
        return cur->get_local(key);
Packit bfcc33
      }
Packit bfcc33
      cur = cur->parent_;
Packit bfcc33
    }
Packit bfcc33
    return get_local(key);
Packit bfcc33
  }
Packit bfcc33
Packit bfcc33
  #ifdef DEBUG
Packit bfcc33
  template <typename T>
Packit bfcc33
  size_t Environment<T>::print(std::string prefix)
Packit bfcc33
  {
Packit bfcc33
    size_t indent = 0;
Packit bfcc33
    if (parent_) indent = parent_->print(prefix) + 1;
Packit bfcc33
    std::cerr << prefix << std::string(indent, ' ') << "== " << this << std::endl;
Packit bfcc33
    for (typename environment_map<std::string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
Packit bfcc33
      if (!ends_with(i->first, "[f]") && !ends_with(i->first, "[f]4") && !ends_with(i->first, "[f]2")) {
Packit bfcc33
        std::cerr << prefix << std::string(indent, ' ') << i->first << " " << i->second;
Packit bfcc33
        if (Value_Ptr val = Cast<Value>(i->second))
Packit bfcc33
        { std::cerr << " : " << val->to_string(); }
Packit bfcc33
        std::cerr << std::endl;
Packit bfcc33
      }
Packit bfcc33
    }
Packit bfcc33
    return indent ;
Packit bfcc33
  }
Packit bfcc33
  #endif
Packit bfcc33
Packit bfcc33
  // compile implementation for AST_Node
Packit bfcc33
  template class Environment<AST_Node_Obj>;
Packit bfcc33
Packit bfcc33
}
Packit bfcc33