| Index: tools/gn/functions.cc
|
| diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
|
| index 8d146b2f7201a581c7b6b966c84783c650d012be..43cdcd36cf4f5ea6f09d393fed312300f4a21fe0 100644
|
| --- a/tools/gn/functions.cc
|
| +++ b/tools/gn/functions.cc
|
| @@ -16,46 +16,10 @@
|
| #include "tools/gn/scheduler.h"
|
| #include "tools/gn/scope.h"
|
| #include "tools/gn/settings.h"
|
| +#include "tools/gn/template.h"
|
| #include "tools/gn/token.h"
|
| #include "tools/gn/value.h"
|
|
|
| -namespace {
|
| -
|
| -// This is called when a template is invoked. When we see a template
|
| -// declaration, that funciton is RunTemplate.
|
| -Value RunTemplateInvocation(Scope* scope,
|
| - const FunctionCallNode* invocation,
|
| - const std::vector<Value>& args,
|
| - BlockNode* block,
|
| - const FunctionCallNode* rule,
|
| - Err* err) {
|
| - if (!EnsureNotProcessingImport(invocation, scope, err))
|
| - return Value();
|
| -
|
| - Scope block_scope(scope);
|
| - if (!FillTargetBlockScope(scope, invocation,
|
| - invocation->function().value().as_string(),
|
| - block, args, &block_scope, err))
|
| - return Value();
|
| -
|
| - // Run the block for the rule invocation.
|
| - block->ExecuteBlockInScope(&block_scope, err);
|
| - if (err->has_error())
|
| - return Value();
|
| -
|
| - // Now run the rule itself with that block as the current scope.
|
| - rule->block()->ExecuteBlockInScope(&block_scope, err);
|
| - if (err->has_error())
|
| - return Value();
|
| -
|
| - block_scope.CheckForUnusedVars(err);
|
| - return Value();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// ----------------------------------------------------------------------------
|
| -
|
| bool EnsureNotProcessingImport(const ParseNode* node,
|
| const Scope* scope,
|
| Err* err) {
|
| @@ -97,7 +61,7 @@ bool FillTargetBlockScope(const Scope* scope,
|
| // the block in.
|
| const Scope* default_scope = scope->GetTargetDefaults(target_type);
|
| if (default_scope) {
|
| - if (!default_scope->NonRecursiveMergeTo(block_scope, function,
|
| + if (!default_scope->NonRecursiveMergeTo(block_scope, false, function,
|
| "target defaults", err))
|
| return false;
|
| }
|
| @@ -331,16 +295,29 @@ const char kDefined_Help[] =
|
| " Returns true if the given argument is defined. This is most useful in\n"
|
| " templates to assert that the caller set things up properly.\n"
|
| "\n"
|
| + " You can pass an identifier:\n"
|
| + " defined(foo)\n"
|
| + " which will return true or false depending on whether foo is defined in\n"
|
| + " the current scope.\n"
|
| + "\n"
|
| + " You can also check a named scope:\n"
|
| + " defined(foo.bar)\n"
|
| + " which returns true if both foo is defined and bar is defined on the\n"
|
| + " named scope foo. It will throw an error if foo is defined but is not\n"
|
| + " a scope.\n"
|
| + "\n"
|
| "Example:\n"
|
| "\n"
|
| " template(\"mytemplate\") {\n"
|
| " # To help users call this template properly...\n"
|
| - " assert(defined(sources), \"Sources must be defined\")\n"
|
| + " assert(defined(invoker.sources), \"Sources must be defined\")\n"
|
| "\n"
|
| " # If we want to accept an optional \"values\" argument, we don't\n"
|
| " # want to dereference something that may not be defined.\n"
|
| - " if (!defined(outputs)) {\n"
|
| - " outputs = []\n"
|
| + " if (defined(invoker.values)) {\n"
|
| + " values = invoker.values\n"
|
| + " } else {\n"
|
| + " values = \"some default value\"\n"
|
| " }\n"
|
| " }\n";
|
|
|
| @@ -349,17 +326,42 @@ Value RunDefined(Scope* scope,
|
| const ListNode* args_list,
|
| Err* err) {
|
| const std::vector<const ParseNode*>& args_vector = args_list->contents();
|
| - const IdentifierNode* identifier = NULL;
|
| - if (args_vector.size() != 1 ||
|
| - !(identifier = args_vector[0]->AsIdentifier())) {
|
| - *err = Err(function, "Bad argument to defined().",
|
| - "defined() takes one argument which should be an identifier.");
|
| + if (args_vector.size() != 1) {
|
| + *err = Err(function, "Wrong number of arguments to defined().",
|
| + "Expecting exactly one.");
|
| return Value();
|
| }
|
|
|
| - if (scope->GetValue(identifier->value().value()))
|
| - return Value(function, true);
|
| - return Value(function, false);
|
| + const IdentifierNode* identifier = args_vector[0]->AsIdentifier();
|
| + if (identifier) {
|
| + // Passed an identifier "defined(foo)".
|
| + if (scope->GetValue(identifier->value().value()))
|
| + return Value(function, true);
|
| + return Value(function, false);
|
| + }
|
| +
|
| + const AccessorNode* accessor = args_vector[0]->AsAccessor();
|
| + if (accessor) {
|
| + // Passed an accessor "defined(foo.bar)".
|
| + if (accessor->member()) {
|
| + // The base of the accessor must be a scope if it's defined.
|
| + const Value* base = scope->GetValue(accessor->base().value());
|
| + if (!base)
|
| + return Value(function, false);
|
| + if (!base->VerifyTypeIs(Value::SCOPE, err))
|
| + return Value();
|
| +
|
| + // Check the member inside the scope to see if its defined.
|
| + if (base->scope_value()->GetValue(accessor->member()->value().value()))
|
| + return Value(function, true);
|
| + return Value(function, false);
|
| + }
|
| + }
|
| +
|
| + // Argument is invalid.
|
| + *err = Err(function, "Bad thing passed to defined().",
|
| + "It should be of the form defined(foo) or defined(foo.bar).");
|
| + return Value();
|
| }
|
|
|
| // getenv ----------------------------------------------------------------------
|
| @@ -625,14 +627,13 @@ Value RunFunction(Scope* scope,
|
| function_map.find(name.value());
|
| if (found_function == function_map.end()) {
|
| // No built-in function matching this, check for a template.
|
| - const FunctionCallNode* rule =
|
| + const Template* templ =
|
| scope->GetTemplate(function->function().value().as_string());
|
| - if (rule) {
|
| + if (templ) {
|
| Value args = args_list->Execute(scope, err);
|
| if (err->has_error())
|
| return Value();
|
| - return RunTemplateInvocation(scope, function, args.list_value(), block,
|
| - rule, err);
|
| + return templ->Invoke(scope, function, args.list_value(), block, err);
|
| }
|
|
|
| *err = Err(name, "Unknown function.");
|
|
|