OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/functions.h" | 5 #include "tools/gn/functions.h" |
6 | 6 |
7 #include <iostream> | 7 #include <iostream> |
8 | 8 |
9 #include "base/environment.h" | 9 #include "base/environment.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 #include "tools/gn/config.h" | 11 #include "tools/gn/config.h" |
12 #include "tools/gn/config_values_generator.h" | 12 #include "tools/gn/config_values_generator.h" |
13 #include "tools/gn/err.h" | 13 #include "tools/gn/err.h" |
14 #include "tools/gn/input_file.h" | 14 #include "tools/gn/input_file.h" |
15 #include "tools/gn/parse_tree.h" | 15 #include "tools/gn/parse_tree.h" |
16 #include "tools/gn/scheduler.h" | 16 #include "tools/gn/scheduler.h" |
17 #include "tools/gn/scope.h" | 17 #include "tools/gn/scope.h" |
18 #include "tools/gn/settings.h" | 18 #include "tools/gn/settings.h" |
| 19 #include "tools/gn/template.h" |
19 #include "tools/gn/token.h" | 20 #include "tools/gn/token.h" |
20 #include "tools/gn/value.h" | 21 #include "tools/gn/value.h" |
21 | 22 |
22 namespace { | |
23 | |
24 // This is called when a template is invoked. When we see a template | |
25 // declaration, that funciton is RunTemplate. | |
26 Value RunTemplateInvocation(Scope* scope, | |
27 const FunctionCallNode* invocation, | |
28 const std::vector<Value>& args, | |
29 BlockNode* block, | |
30 const FunctionCallNode* rule, | |
31 Err* err) { | |
32 if (!EnsureNotProcessingImport(invocation, scope, err)) | |
33 return Value(); | |
34 | |
35 Scope block_scope(scope); | |
36 if (!FillTargetBlockScope(scope, invocation, | |
37 invocation->function().value().as_string(), | |
38 block, args, &block_scope, err)) | |
39 return Value(); | |
40 | |
41 // Run the block for the rule invocation. | |
42 block->ExecuteBlockInScope(&block_scope, err); | |
43 if (err->has_error()) | |
44 return Value(); | |
45 | |
46 // Now run the rule itself with that block as the current scope. | |
47 rule->block()->ExecuteBlockInScope(&block_scope, err); | |
48 if (err->has_error()) | |
49 return Value(); | |
50 | |
51 block_scope.CheckForUnusedVars(err); | |
52 return Value(); | |
53 } | |
54 | |
55 } // namespace | |
56 | |
57 // ---------------------------------------------------------------------------- | |
58 | |
59 bool EnsureNotProcessingImport(const ParseNode* node, | 23 bool EnsureNotProcessingImport(const ParseNode* node, |
60 const Scope* scope, | 24 const Scope* scope, |
61 Err* err) { | 25 Err* err) { |
62 if (scope->IsProcessingImport()) { | 26 if (scope->IsProcessingImport()) { |
63 *err = Err(node, "Not valid from an import.", | 27 *err = Err(node, "Not valid from an import.", |
64 "Imports are for defining defaults, variables, and rules. The\n" | 28 "Imports are for defining defaults, variables, and rules. The\n" |
65 "appropriate place for this kind of thing is really in a normal\n" | 29 "appropriate place for this kind of thing is really in a normal\n" |
66 "BUILD file."); | 30 "BUILD file."); |
67 return false; | 31 return false; |
68 } | 32 } |
(...skipping 21 matching lines...) Expand all Loading... |
90 Err* err) { | 54 Err* err) { |
91 if (!block) { | 55 if (!block) { |
92 FillNeedsBlockError(function, err); | 56 FillNeedsBlockError(function, err); |
93 return false; | 57 return false; |
94 } | 58 } |
95 | 59 |
96 // Copy the target defaults, if any, into the scope we're going to execute | 60 // Copy the target defaults, if any, into the scope we're going to execute |
97 // the block in. | 61 // the block in. |
98 const Scope* default_scope = scope->GetTargetDefaults(target_type); | 62 const Scope* default_scope = scope->GetTargetDefaults(target_type); |
99 if (default_scope) { | 63 if (default_scope) { |
100 if (!default_scope->NonRecursiveMergeTo(block_scope, function, | 64 if (!default_scope->NonRecursiveMergeTo(block_scope, false, function, |
101 "target defaults", err)) | 65 "target defaults", err)) |
102 return false; | 66 return false; |
103 } | 67 } |
104 | 68 |
105 // The name is the single argument to the target function. | 69 // The name is the single argument to the target function. |
106 if (!EnsureSingleStringArg(function, args, err)) | 70 if (!EnsureSingleStringArg(function, args, err)) |
107 return false; | 71 return false; |
108 | 72 |
109 // Set the target name variable to the current target, and mark it used | 73 // Set the target name variable to the current target, and mark it used |
110 // because we don't want to issue an error if the script ignores it. | 74 // because we don't want to issue an error if the script ignores it. |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 | 288 |
325 // defined --------------------------------------------------------------------- | 289 // defined --------------------------------------------------------------------- |
326 | 290 |
327 const char kDefined[] = "defined"; | 291 const char kDefined[] = "defined"; |
328 const char kDefined_Help[] = | 292 const char kDefined_Help[] = |
329 "defined: Returns whether an identifier is defined.\n" | 293 "defined: Returns whether an identifier is defined.\n" |
330 "\n" | 294 "\n" |
331 " Returns true if the given argument is defined. This is most useful in\n" | 295 " Returns true if the given argument is defined. This is most useful in\n" |
332 " templates to assert that the caller set things up properly.\n" | 296 " templates to assert that the caller set things up properly.\n" |
333 "\n" | 297 "\n" |
| 298 " You can pass an identifier:\n" |
| 299 " defined(foo)\n" |
| 300 " which will return true or false depending on whether foo is defined in\n" |
| 301 " the current scope.\n" |
| 302 "\n" |
| 303 " You can also check a named scope:\n" |
| 304 " defined(foo.bar)\n" |
| 305 " which returns true if both foo is defined and bar is defined on the\n" |
| 306 " named scope foo. It will throw an error if foo is defined but is not\n" |
| 307 " a scope.\n" |
| 308 "\n" |
334 "Example:\n" | 309 "Example:\n" |
335 "\n" | 310 "\n" |
336 " template(\"mytemplate\") {\n" | 311 " template(\"mytemplate\") {\n" |
337 " # To help users call this template properly...\n" | 312 " # To help users call this template properly...\n" |
338 " assert(defined(sources), \"Sources must be defined\")\n" | 313 " assert(defined(invoker.sources), \"Sources must be defined\")\n" |
339 "\n" | 314 "\n" |
340 " # If we want to accept an optional \"values\" argument, we don't\n" | 315 " # If we want to accept an optional \"values\" argument, we don't\n" |
341 " # want to dereference something that may not be defined.\n" | 316 " # want to dereference something that may not be defined.\n" |
342 " if (!defined(outputs)) {\n" | 317 " if (defined(invoker.values)) {\n" |
343 " outputs = []\n" | 318 " values = invoker.values\n" |
| 319 " } else {\n" |
| 320 " values = \"some default value\"\n" |
344 " }\n" | 321 " }\n" |
345 " }\n"; | 322 " }\n"; |
346 | 323 |
347 Value RunDefined(Scope* scope, | 324 Value RunDefined(Scope* scope, |
348 const FunctionCallNode* function, | 325 const FunctionCallNode* function, |
349 const ListNode* args_list, | 326 const ListNode* args_list, |
350 Err* err) { | 327 Err* err) { |
351 const std::vector<const ParseNode*>& args_vector = args_list->contents(); | 328 const std::vector<const ParseNode*>& args_vector = args_list->contents(); |
352 const IdentifierNode* identifier = NULL; | 329 if (args_vector.size() != 1) { |
353 if (args_vector.size() != 1 || | 330 *err = Err(function, "Wrong number of arguments to defined().", |
354 !(identifier = args_vector[0]->AsIdentifier())) { | 331 "Expecting exactly one."); |
355 *err = Err(function, "Bad argument to defined().", | |
356 "defined() takes one argument which should be an identifier."); | |
357 return Value(); | 332 return Value(); |
358 } | 333 } |
359 | 334 |
360 if (scope->GetValue(identifier->value().value())) | 335 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); |
361 return Value(function, true); | 336 if (identifier) { |
362 return Value(function, false); | 337 // Passed an identifier "defined(foo)". |
| 338 if (scope->GetValue(identifier->value().value())) |
| 339 return Value(function, true); |
| 340 return Value(function, false); |
| 341 } |
| 342 |
| 343 const AccessorNode* accessor = args_vector[0]->AsAccessor(); |
| 344 if (accessor) { |
| 345 // Passed an accessor "defined(foo.bar)". |
| 346 if (accessor->member()) { |
| 347 // The base of the accessor must be a scope if it's defined. |
| 348 const Value* base = scope->GetValue(accessor->base().value()); |
| 349 if (!base) |
| 350 return Value(function, false); |
| 351 if (!base->VerifyTypeIs(Value::SCOPE, err)) |
| 352 return Value(); |
| 353 |
| 354 // Check the member inside the scope to see if its defined. |
| 355 if (base->scope_value()->GetValue(accessor->member()->value().value())) |
| 356 return Value(function, true); |
| 357 return Value(function, false); |
| 358 } |
| 359 } |
| 360 |
| 361 // Argument is invalid. |
| 362 *err = Err(function, "Bad thing passed to defined().", |
| 363 "It should be of the form defined(foo) or defined(foo.bar)."); |
| 364 return Value(); |
363 } | 365 } |
364 | 366 |
365 // getenv ---------------------------------------------------------------------- | 367 // getenv ---------------------------------------------------------------------- |
366 | 368 |
367 const char kGetEnv[] = "getenv"; | 369 const char kGetEnv[] = "getenv"; |
368 const char kGetEnv_Help[] = | 370 const char kGetEnv_Help[] = |
369 "getenv: Get an environment variable.\n" | 371 "getenv: Get an environment variable.\n" |
370 "\n" | 372 "\n" |
371 " value = getenv(env_var_name)\n" | 373 " value = getenv(env_var_name)\n" |
372 "\n" | 374 "\n" |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 const ListNode* args_list, | 620 const ListNode* args_list, |
619 BlockNode* block, | 621 BlockNode* block, |
620 Err* err) { | 622 Err* err) { |
621 const Token& name = function->function(); | 623 const Token& name = function->function(); |
622 | 624 |
623 const FunctionInfoMap& function_map = GetFunctions(); | 625 const FunctionInfoMap& function_map = GetFunctions(); |
624 FunctionInfoMap::const_iterator found_function = | 626 FunctionInfoMap::const_iterator found_function = |
625 function_map.find(name.value()); | 627 function_map.find(name.value()); |
626 if (found_function == function_map.end()) { | 628 if (found_function == function_map.end()) { |
627 // No built-in function matching this, check for a template. | 629 // No built-in function matching this, check for a template. |
628 const FunctionCallNode* rule = | 630 const Template* templ = |
629 scope->GetTemplate(function->function().value().as_string()); | 631 scope->GetTemplate(function->function().value().as_string()); |
630 if (rule) { | 632 if (templ) { |
631 Value args = args_list->Execute(scope, err); | 633 Value args = args_list->Execute(scope, err); |
632 if (err->has_error()) | 634 if (err->has_error()) |
633 return Value(); | 635 return Value(); |
634 return RunTemplateInvocation(scope, function, args.list_value(), block, | 636 return templ->Invoke(scope, function, args.list_value(), block, err); |
635 rule, err); | |
636 } | 637 } |
637 | 638 |
638 *err = Err(name, "Unknown function."); | 639 *err = Err(name, "Unknown function."); |
639 return Value(); | 640 return Value(); |
640 } | 641 } |
641 | 642 |
642 if (found_function->second.self_evaluating_args_runner) { | 643 if (found_function->second.self_evaluating_args_runner) { |
643 return found_function->second.self_evaluating_args_runner( | 644 return found_function->second.self_evaluating_args_runner( |
644 scope, function, args_list, err); | 645 scope, function, args_list, err); |
645 } | 646 } |
(...skipping 25 matching lines...) Expand all Loading... |
671 return found_function->second.executed_block_runner( | 672 return found_function->second.executed_block_runner( |
672 function, args.list_value(), &block_scope, err); | 673 function, args.list_value(), &block_scope, err); |
673 } | 674 } |
674 | 675 |
675 // Otherwise it's a no-block function. | 676 // Otherwise it's a no-block function. |
676 return found_function->second.no_block_runner(scope, function, | 677 return found_function->second.no_block_runner(scope, function, |
677 args.list_value(), err); | 678 args.list_value(), err); |
678 } | 679 } |
679 | 680 |
680 } // namespace functions | 681 } // namespace functions |
OLD | NEW |