// Copyright 2015 Google Inc. All rights reserved // // 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. // +build ignore #include "var.h" #include "eval.h" #include "expr.h" #include "log.h" unordered_map<const Var*, string> Var::diagnostic_messages_; const char* GetOriginStr(VarOrigin origin) { switch (origin) { case VarOrigin::UNDEFINED: return "undefined"; case VarOrigin::DEFAULT: return "default"; case VarOrigin::ENVIRONMENT: return "environment"; case VarOrigin::ENVIRONMENT_OVERRIDE: return "environment override"; case VarOrigin::FILE: return "file"; case VarOrigin::COMMAND_LINE: return "command line"; case VarOrigin::OVERRIDE: return "override"; case VarOrigin::AUTOMATIC: return "automatic"; } CHECK(false); return "*** broken origin ***"; } Var::Var() : Var(VarOrigin::UNDEFINED) {} Var::Var(VarOrigin origin) : origin_(origin), readonly_(false), deprecated_(false), obsolete_(false) {} Var::~Var() { diagnostic_messages_.erase(this); } void Var::AppendVar(Evaluator*, Value*) { CHECK(false); } void Var::SetDeprecated(const StringPiece& msg) { deprecated_ = true; diagnostic_messages_[this] = msg.as_string(); } void Var::SetObsolete(const StringPiece& msg) { obsolete_ = true; diagnostic_messages_[this] = msg.as_string(); } void Var::Used(Evaluator* ev, const Symbol& sym) const { if (obsolete_) { ev->Error(StringPrintf("*** %s is obsolete%s.", sym.c_str(), diagnostic_message_text())); } else if (deprecated_) { WARN_LOC(ev->loc(), "%s has been deprecated%s.", sym.c_str(), diagnostic_message_text()); } } const char* Var::diagnostic_message_text() const { auto it = diagnostic_messages_.find(this); return it == diagnostic_messages_.end() ? "" : it->second.c_str(); } const string& Var::DeprecatedMessage() const { static const string empty_string; auto it = diagnostic_messages_.find(this); return it == diagnostic_messages_.end() ? empty_string : it->second; } Var* Var::Undefined() { static Var* undefined_var; if (!undefined_var) { undefined_var = new UndefinedVar(); } return undefined_var; } SimpleVar::SimpleVar(VarOrigin origin) : Var(origin) {} SimpleVar::SimpleVar(const string& v, VarOrigin origin) : Var(origin), v_(v) {} SimpleVar::SimpleVar(VarOrigin origin, Evaluator* ev, Value* v) : Var(origin) { v->Eval(ev, &v_); } void SimpleVar::Eval(Evaluator* ev, string* s) const { ev->CheckStack(); *s += v_; } void SimpleVar::AppendVar(Evaluator* ev, Value* v) { string buf; v->Eval(ev, &buf); v_.push_back(' '); v_ += buf; } StringPiece SimpleVar::String() const { return v_; } string SimpleVar::DebugString() const { return v_; } RecursiveVar::RecursiveVar(Value* v, VarOrigin origin, StringPiece orig) : Var(origin), v_(v), orig_(orig) {} void RecursiveVar::Eval(Evaluator* ev, string* s) const { ev->CheckStack(); v_->Eval(ev, s); } void RecursiveVar::AppendVar(Evaluator* ev, Value* v) { ev->CheckStack(); v_ = Value::NewExpr(v_, Value::NewLiteral(" "), v); } StringPiece RecursiveVar::String() const { return orig_; } string RecursiveVar::DebugString() const { return Value::DebugString(v_); } UndefinedVar::UndefinedVar() {} void UndefinedVar::Eval(Evaluator*, string*) const { // Nothing to do. } StringPiece UndefinedVar::String() const { return StringPiece(""); } string UndefinedVar::DebugString() const { return "*undefined*"; } Vars::~Vars() { for (auto p : *this) { delete p.second; } } void Vars::add_used_env_vars(Symbol v) { used_env_vars_.insert(v); } Var* Vars::Lookup(Symbol name) const { auto found = find(name); if (found == end()) return Var::Undefined(); Var* v = found->second; if (v->Origin() == VarOrigin::ENVIRONMENT || v->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) { used_env_vars_.insert(name); } return v; } Var* Vars::Peek(Symbol name) const { auto found = find(name); return found == end() ? Var::Undefined() : found->second; } void Vars::Assign(Symbol name, Var* v, bool* readonly) { *readonly = false; auto p = emplace(name, v); if (!p.second) { Var* orig = p.first->second; if (orig->ReadOnly()) { *readonly = true; return; } if (orig->Origin() == VarOrigin::OVERRIDE || orig->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) { return; } if (orig->Origin() == VarOrigin::AUTOMATIC) { ERROR("overriding automatic variable is not implemented yet"); } if (orig->IsDefined()) delete p.first->second; p.first->second = v; } } SymbolSet Vars::used_env_vars_; ScopedVar::ScopedVar(Vars* vars, Symbol name, Var* var) : vars_(vars), orig_(NULL) { auto p = vars->emplace(name, var); iter_ = p.first; if (!p.second) { orig_ = iter_->second; iter_->second = var; } } ScopedVar::~ScopedVar() { if (orig_) { iter_->second = orig_; } else { vars_->erase(iter_); } }