| Index: tools/gn/scope.cc
|
| diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
|
| index 86f82beb804c87fcc17dc6def47d77ce77e5b17c..78612f2c64b555c241cd11979231f8e8494f4220 100644
|
| --- a/tools/gn/scope.cc
|
| +++ b/tools/gn/scope.cc
|
| @@ -7,6 +7,7 @@
|
| #include "base/logging.h"
|
| #include "base/stl_util.h"
|
| #include "tools/gn/parse_tree.h"
|
| +#include "tools/gn/template.h"
|
|
|
| namespace {
|
|
|
| @@ -41,6 +42,7 @@ Scope::Scope(const Scope* parent)
|
| Scope::~Scope() {
|
| STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
|
| target_defaults_.end());
|
| + STLDeleteContainerPairSecondPointers(templates_.begin(), templates_.end());
|
| }
|
|
|
| const Value* Scope::GetValue(const base::StringPiece& ident,
|
| @@ -119,14 +121,14 @@ Value* Scope::SetValue(const base::StringPiece& ident,
|
| return &r.value;
|
| }
|
|
|
| -bool Scope::AddTemplate(const std::string& name, const FunctionCallNode* decl) {
|
| +bool Scope::AddTemplate(const std::string& name, scoped_ptr<Template> templ) {
|
| if (GetTemplate(name))
|
| return false;
|
| - templates_[name] = decl;
|
| + templates_[name] = templ.release();
|
| return true;
|
| }
|
|
|
| -const FunctionCallNode* Scope::GetTemplate(const std::string& name) const {
|
| +const Template* Scope::GetTemplate(const std::string& name) const {
|
| TemplateMap::const_iterator found = templates_.find(name);
|
| if (found != templates_.end())
|
| return found->second;
|
| @@ -191,24 +193,28 @@ void Scope::GetCurrentScopeValues(KeyValueMap* output) const {
|
| }
|
|
|
| bool Scope::NonRecursiveMergeTo(Scope* dest,
|
| + bool clobber_existing,
|
| 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& new_value = i->second.value;
|
| - const Value* existing_value = dest->GetValue(i->first);
|
| - if (existing_value && new_value != *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 unless the values are identical."));
|
| - return false;
|
| + if (!clobber_existing) {
|
| + const Value* existing_value = dest->GetValue(i->first);
|
| + if (existing_value && new_value != *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 unless the values are identical."));
|
| + return false;
|
| + }
|
| }
|
| dest->values_[i->first] = i->second;
|
| }
|
| @@ -216,34 +222,42 @@ bool Scope::NonRecursiveMergeTo(Scope* dest,
|
| // 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;
|
| + if (!clobber_existing) {
|
| + 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;
|
| + // Be careful to delete any pointer we're about to clobber.
|
| + Scope** dest_scope = &dest->target_defaults_[i->first];
|
| + if (*dest_scope)
|
| + delete *dest_scope;
|
| + *dest_scope = new Scope(settings_);
|
| + i->second->NonRecursiveMergeTo(*dest_scope, clobber_existing, node_for_err,
|
| + "<SHOULDN'T HAPPEN>", err);
|
| }
|
|
|
| // 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;
|
| + if (!clobber_existing) {
|
| + 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\nwould clobber the one in your current scope.");
|
| + return false;
|
| + }
|
| }
|
| dest->sources_assignment_filter_.reset(
|
| new PatternList(*sources_assignment_filter_));
|
| @@ -252,25 +266,56 @@ bool Scope::NonRecursiveMergeTo(Scope* dest,
|
| // 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;
|
| + if (!clobber_existing) {
|
| + const Template* 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->GetDefinitionRange(), "defined here.",
|
| + "Which would clobber the one in your current scope"));
|
| + err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
|
| + "defined here.",
|
| + "Executing " + desc_string + " should not conflict with anything "
|
| + "in the current\nscope."));
|
| + return false;
|
| + }
|
| }
|
| - dest->templates_.insert(*i);
|
| +
|
| + // Be careful to delete any pointer we're about to clobber.
|
| + const Template** dest_template = &dest->templates_[i->first];
|
| + if (*dest_template)
|
| + delete *dest_template;
|
| + *dest_template = i->second;
|
| }
|
|
|
| return true;
|
| }
|
|
|
| +scoped_ptr<Scope> Scope::MakeClosure() const {
|
| + scoped_ptr<Scope> result;
|
| + if (const_containing_) {
|
| + // We reached the top of the mutable scope stack. The result scope just
|
| + // references the const scope (which will never change).
|
| + result.reset(new Scope(const_containing_));
|
| + } else if (mutable_containing_) {
|
| + // There are more nested mutable scopes. Recursively go up the stack to
|
| + // get the closure.
|
| + result = mutable_containing_->MakeClosure();
|
| + } else {
|
| + // This is a standalone scope, just copy it.
|
| + result.reset(new Scope(settings_));
|
| + }
|
| +
|
| + // Add in our variables and we're done.
|
| + Err err;
|
| + NonRecursiveMergeTo(result.get(), true, NULL, "<SHOULDN'T HAPPEN>", &err);
|
| + DCHECK(!err.has_error());
|
| + return result.Pass();
|
| +}
|
| +
|
| Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
|
| if (GetTargetDefaults(target_type))
|
| return NULL;
|
|
|