Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Unified Diff: tools/gn/scope.cc

Issue 21114002: Add initial prototype for the GN meta-buildsystem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add owners and readme Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/gn/scope.h ('k') | tools/gn/scope_per_file_provider.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/gn/scope.cc
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
new file mode 100644
index 0000000000000000000000000000000000000000..72664d7cc425c9d5a815cf3d0c916bb69de7aff3
--- /dev/null
+++ b/tools/gn/scope.cc
@@ -0,0 +1,372 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/scope.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "tools/gn/parse_tree.h"
+
+namespace {
+
+// FLags set in the mode_flags_ of a scope. If a bit is set, it applies
+// recursively to all dependent scopes.
+const unsigned kProcessingBuildConfigFlag = 1;
+const unsigned kProcessingDefaultBuildConfigFlag = 2;
+const unsigned kProcessingImportFlag = 4;
+
+} // namespace
+
+Scope::Scope(const Settings* settings)
+ : const_containing_(NULL),
+ mutable_containing_(NULL),
+ settings_(settings),
+ mode_flags_(0) {
+}
+
+Scope::Scope(Scope* parent)
+ : const_containing_(NULL),
+ mutable_containing_(parent),
+ settings_(parent->settings()),
+ mode_flags_(0) {
+}
+
+Scope::Scope(const Scope* parent)
+ : const_containing_(parent),
+ mutable_containing_(NULL),
+ settings_(parent->settings()),
+ mode_flags_(0) {
+}
+
+Scope::~Scope() {
+ STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
+ target_defaults_.end());
+}
+
+const Value* Scope::GetValue(const base::StringPiece& ident,
+ bool counts_as_used) {
+ // First check for programatically-provided values.
+ for (ProviderSet::const_iterator i = programmatic_providers_.begin();
+ i != programmatic_providers_.end(); ++i) {
+ const Value* v = (*i)->GetProgrammaticValue(ident);
+ if (v)
+ return v;
+ }
+
+ RecordMap::iterator found = values_.find(ident);
+ if (found != values_.end()) {
+ if (counts_as_used)
+ found->second.used = true;
+ return &found->second.value;
+ }
+
+ // Search in the parent scope.
+ if (const_containing_)
+ return const_containing_->GetValue(ident);
+ if (mutable_containing_)
+ return mutable_containing_->GetValue(ident, counts_as_used);
+ return NULL;
+}
+
+Value* Scope::GetValueForcedToCurrentScope(const base::StringPiece& ident,
+ const ParseNode* set_node) {
+ RecordMap::iterator found = values_.find(ident);
+ if (found != values_.end())
+ return &found->second.value; // Already have in the current scope.
+
+ // Search in the parent scope.
+ if (containing()) {
+ const Value* in_containing = containing()->GetValue(ident);
+ if (in_containing) {
+ // Promote to current scope.
+ return SetValue(ident, *in_containing, set_node);
+ }
+ }
+ return NULL;
+}
+
+const Value* Scope::GetValue(const base::StringPiece& ident) const {
+ RecordMap::const_iterator found = values_.find(ident);
+ if (found != values_.end())
+ return &found->second.value;
+ if (containing())
+ return containing()->GetValue(ident);
+ return NULL;
+}
+
+Value* Scope::SetValue(const base::StringPiece& ident,
+ const Value& v,
+ const ParseNode* set_node) {
+ Record& r = values_[ident]; // Clears any existing value.
+ r.value = v;
+ r.value.set_origin(set_node);
+ return &r.value;
+}
+
+bool Scope::AddTemplate(const std::string& name, const FunctionCallNode* decl) {
+ if (GetTemplate(name))
+ return false;
+ templates_[name] = decl;
+ return true;
+}
+
+const FunctionCallNode* Scope::GetTemplate(const std::string& name) const {
+ TemplateMap::const_iterator found = templates_.find(name);
+ if (found != templates_.end())
+ return found->second;
+ if (containing())
+ return containing()->GetTemplate(name);
+ return NULL;
+}
+
+void Scope::MarkUsed(const base::StringPiece& ident) {
+ RecordMap::iterator found = values_.find(ident);
+ if (found == values_.end()) {
+ NOTREACHED();
+ return;
+ }
+ found->second.used = true;
+}
+
+void Scope::MarkUnused(const base::StringPiece& ident) {
+ RecordMap::iterator found = values_.find(ident);
+ if (found == values_.end()) {
+ NOTREACHED();
+ return;
+ }
+ found->second.used = false;
+}
+
+bool Scope::IsSetButUnused(const base::StringPiece& ident) const {
+ RecordMap::const_iterator found = values_.find(ident);
+ if (found != values_.end()) {
+ if (!found->second.used) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Scope::CheckForUnusedVars(Err* err) const {
+ for (RecordMap::const_iterator i = values_.begin();
+ i != values_.end(); ++i) {
+ if (!i->second.used) {
+ std::string help = "You set the variable \"" + i->first.as_string() +
+ "\" here and it was unused before it went\nout of scope.";
+
+ const BinaryOpNode* binary = i->second.value.origin()->AsBinaryOp();
+ if (binary) {
+ // Make a nicer error message for normal var sets.
+ *err = Err(binary->left()->GetRange(), "Assignment had no effect.",
+ help);
+ } else {
+ // This will happen for internally-generated variables.
+ *err = Err(i->second.value.origin(), "Assignment had no effect.", help);
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+void Scope::GetCurrentScopeValues(KeyValueVector* output) const {
+ output->reserve(values_.size());
+ for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) {
+ output->push_back(std::make_pair(i->first, i->second.value));
+ }
+}
+
+bool Scope::NonRecursiveMergeTo(Scope* dest,
+ const ParseNode* node_for_err,
+ const char* desc_for_err,
+ Err* err) const {
+ // Values.
+ for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) {
+ const Value* existing_value = dest->GetValue(i->first);
+ if (existing_value) {
+ // Value present in both the source and the dest.
+ std::string desc_string(desc_for_err);
+ *err = Err(node_for_err, "Value collision.",
+ "This " + desc_string + " contains \"" + i->first.as_string() + "\"");
+ err->AppendSubErr(Err(i->second.value, "defined here.",
+ "Which would clobber the one in your current scope"));
+ err->AppendSubErr(Err(*existing_value, "defined here.",
+ "Executing " + desc_string + " should not conflict with anything "
+ "in the current\nscope."));
+ return false;
+ }
+ dest->values_[i->first] = i->second;
+ }
+
+ // Target defaults are owning pointers.
+ for (NamedScopeMap::const_iterator i = target_defaults_.begin();
+ i != target_defaults_.end(); ++i) {
+ if (dest->GetTargetDefaults(i->first)) {
+ // TODO(brettw) it would be nice to know the origin of a
+ // set_target_defaults so we can give locations for the colliding target
+ // defaults.
+ std::string desc_string(desc_for_err);
+ *err = Err(node_for_err, "Target defaults collision.",
+ "This " + desc_string + " contains target defaults for\n"
+ "\"" + i->first + "\" which would clobber one for the\n"
+ "same target type in your current scope. It's unfortunate that I'm "
+ "too stupid\nto tell you the location of where the target defaults "
+ "were set. Usually\nthis happens in the BUILDCONFIG.gn file.");
+ return false;
+ }
+
+ Scope* s = new Scope(settings_);
+ i->second->NonRecursiveMergeTo(s, node_for_err, "<SHOULDN'T HAPPEN>", err);
+ dest->target_defaults_[i->first] = s;
+ }
+
+ // Sources assignment filter.
+ if (sources_assignment_filter_) {
+ if (dest->GetSourcesAssignmentFilter()) {
+ // Sources assignment filter present in both the source and the dest.
+ std::string desc_string(desc_for_err);
+ *err = Err(node_for_err, "Assignment filter collision.",
+ "The " + desc_string + " contains a sources_assignment_filter which\n"
+ "would clobber the one in your current scope.");
+ return false;
+ }
+ dest->sources_assignment_filter_.reset(
+ new PatternList(*sources_assignment_filter_));
+ }
+
+ // Templates.
+ for (TemplateMap::const_iterator i = templates_.begin();
+ i != templates_.end(); ++i) {
+ const FunctionCallNode* existing_template = dest->GetTemplate(i->first);
+ if (existing_template) {
+ // Rule present in both the source and the dest.
+ std::string desc_string(desc_for_err);
+ *err = Err(node_for_err, "Template collision.",
+ "This " + desc_string + " contains a template \"" + i->first + "\"");
+ err->AppendSubErr(Err(i->second->function(), "defined here.",
+ "Which would clobber the one in your current scope"));
+ err->AppendSubErr(Err(existing_template->function(), "defined here.",
+ "Executing " + desc_string + " should not conflict with anything "
+ "in the current\nscope."));
+ return false;
+ }
+ dest->templates_.insert(*i);
+ }
+
+ return true;
+}
+
+Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
+ if (GetTargetDefaults(target_type))
+ return NULL;
+
+ Scope** dest = &target_defaults_[target_type];
+ if (*dest) {
+ NOTREACHED(); // Already set.
+ return *dest;
+ }
+ *dest = new Scope(settings_);
+ return *dest;
+}
+
+const Scope* Scope::GetTargetDefaults(const std::string& target_type) const {
+ NamedScopeMap::const_iterator found = target_defaults_.find(target_type);
+ if (found != target_defaults_.end())
+ return found->second;
+ if (containing())
+ return containing()->GetTargetDefaults(target_type);
+ return NULL;
+}
+
+const PatternList* Scope::GetSourcesAssignmentFilter() const {
+ if (sources_assignment_filter_)
+ return sources_assignment_filter_.get();
+ if (containing())
+ return containing()->GetSourcesAssignmentFilter();
+ return NULL;
+}
+
+void Scope::SetProcessingBuildConfig() {
+ DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0);
+ mode_flags_ |= kProcessingBuildConfigFlag;
+}
+
+void Scope::ClearProcessingBuildConfig() {
+ DCHECK(mode_flags_ & kProcessingBuildConfigFlag);
+ mode_flags_ &= ~(kProcessingBuildConfigFlag);
+}
+
+bool Scope::IsProcessingBuildConfig() const {
+ if (mode_flags_ & kProcessingBuildConfigFlag)
+ return true;
+ if (containing())
+ return containing()->IsProcessingBuildConfig();
+ return false;
+}
+
+void Scope::SetProcessingDefaultBuildConfig() {
+ DCHECK((mode_flags_ & kProcessingDefaultBuildConfigFlag) == 0);
+ mode_flags_ |= kProcessingDefaultBuildConfigFlag;
+}
+
+void Scope::ClearProcessingDefaultBuildConfig() {
+ DCHECK(mode_flags_ & kProcessingDefaultBuildConfigFlag);
+ mode_flags_ &= ~(kProcessingDefaultBuildConfigFlag);
+}
+
+bool Scope::IsProcessingDefaultBuildConfig() const {
+ if (mode_flags_ & kProcessingDefaultBuildConfigFlag)
+ return true;
+ if (containing())
+ return containing()->IsProcessingDefaultBuildConfig();
+ return false;
+}
+
+void Scope::SetProcessingImport() {
+ DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
+ mode_flags_ |= kProcessingImportFlag;
+}
+
+void Scope::ClearProcessingImport() {
+ DCHECK(mode_flags_ & kProcessingImportFlag);
+ mode_flags_ &= ~(kProcessingImportFlag);
+}
+
+bool Scope::IsProcessingImport() const {
+ if (mode_flags_ & kProcessingImportFlag)
+ return true;
+ if (containing())
+ return containing()->IsProcessingImport();
+ return false;
+}
+
+void Scope::SetProperty(const void* key, void* value) {
+ if (!value) {
+ DCHECK(properties_.find(key) != properties_.end());
+ properties_.erase(key);
+ } else {
+ properties_[key] = value;
+ }
+}
+
+void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const {
+ PropertyMap::const_iterator found = properties_.find(key);
+ if (found != properties_.end()) {
+ if (found_on_scope)
+ *found_on_scope = this;
+ return found->second;
+ }
+ if (containing())
+ return containing()->GetProperty(key, found_on_scope);
+ return NULL;
+}
+
+void Scope::AddProvider(ProgrammaticProvider* p) {
+ programmatic_providers_.insert(p);
+}
+
+void Scope::RemoveProvider(ProgrammaticProvider* p) {
+ DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
+ programmatic_providers_.erase(p);
+}
« no previous file with comments | « tools/gn/scope.h ('k') | tools/gn/scope_per_file_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698