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