Add ICU message format support
[chromium-blink-merge.git] / tools / gn / functions.cc
blob0d86093105c345cf4d2eec6f31dd63ee4111e23c
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
3 // found in the LICENSE file.
5 #include "tools/gn/functions.h"
7 #include <iostream>
9 #include "base/environment.h"
10 #include "base/strings/string_util.h"
11 #include "tools/gn/config.h"
12 #include "tools/gn/config_values_generator.h"
13 #include "tools/gn/err.h"
14 #include "tools/gn/input_file.h"
15 #include "tools/gn/parse_tree.h"
16 #include "tools/gn/scheduler.h"
17 #include "tools/gn/scope.h"
18 #include "tools/gn/settings.h"
19 #include "tools/gn/template.h"
20 #include "tools/gn/token.h"
21 #include "tools/gn/value.h"
23 namespace {
25 // Some functions take a {} following them, and some don't. For the ones that
26 // don't, this is used to verify that the given block node is null and will
27 // set the error accordingly if it's not. Returns true if the block is null.
28 bool VerifyNoBlockForFunctionCall(const FunctionCallNode* function,
29 const BlockNode* block,
30 Err* err) {
31 if (!block)
32 return true;
34 *err = Err(block, "Unexpected '{'.",
35 "This function call doesn't take a {} block following it, and you\n"
36 "can't have a {} block that's not connected to something like an if\n"
37 "statement or a target declaration.");
38 err->AppendRange(function->function().range());
39 return false;
42 } // namespace
44 bool EnsureNotProcessingImport(const ParseNode* node,
45 const Scope* scope,
46 Err* err) {
47 if (scope->IsProcessingImport()) {
48 *err = Err(node, "Not valid from an import.",
49 "Imports are for defining defaults, variables, and rules. The\n"
50 "appropriate place for this kind of thing is really in a normal\n"
51 "BUILD file.");
52 return false;
54 return true;
57 bool EnsureNotProcessingBuildConfig(const ParseNode* node,
58 const Scope* scope,
59 Err* err) {
60 if (scope->IsProcessingBuildConfig()) {
61 *err = Err(node, "Not valid from the build config.",
62 "You can't do this kind of thing from the build config script, "
63 "silly!\nPut it in a regular BUILD file.");
64 return false;
66 return true;
69 bool FillTargetBlockScope(const Scope* scope,
70 const FunctionCallNode* function,
71 const std::string& target_type,
72 const BlockNode* block,
73 const std::vector<Value>& args,
74 Scope* block_scope,
75 Err* err) {
76 if (!block) {
77 FillNeedsBlockError(function, err);
78 return false;
81 // Copy the target defaults, if any, into the scope we're going to execute
82 // the block in.
83 const Scope* default_scope = scope->GetTargetDefaults(target_type);
84 if (default_scope) {
85 Scope::MergeOptions merge_options;
86 merge_options.skip_private_vars = true;
87 if (!default_scope->NonRecursiveMergeTo(block_scope, merge_options,
88 function, "target defaults", err))
89 return false;
92 // The name is the single argument to the target function.
93 if (!EnsureSingleStringArg(function, args, err))
94 return false;
96 // Set the target name variable to the current target, and mark it used
97 // because we don't want to issue an error if the script ignores it.
98 const base::StringPiece target_name("target_name");
99 block_scope->SetValue(target_name, Value(function, args[0].string_value()),
100 function);
101 block_scope->MarkUsed(target_name);
102 return true;
105 void FillNeedsBlockError(const FunctionCallNode* function, Err* err) {
106 *err = Err(function->function(), "This function call requires a block.",
107 "The block's \"{\" must be on the same line as the function "
108 "call's \")\".");
111 bool EnsureSingleStringArg(const FunctionCallNode* function,
112 const std::vector<Value>& args,
113 Err* err) {
114 if (args.size() != 1) {
115 *err = Err(function->function(), "Incorrect arguments.",
116 "This function requires a single string argument.");
117 return false;
119 return args[0].VerifyTypeIs(Value::STRING, err);
122 const Label& ToolchainLabelForScope(const Scope* scope) {
123 return scope->settings()->toolchain_label();
126 Label MakeLabelForScope(const Scope* scope,
127 const FunctionCallNode* function,
128 const std::string& name) {
129 const Label& toolchain_label = ToolchainLabelForScope(scope);
130 return Label(scope->GetSourceDir(), name, toolchain_label.dir(),
131 toolchain_label.name());
134 namespace functions {
136 // assert ----------------------------------------------------------------------
138 const char kAssert[] = "assert";
139 const char kAssert_HelpShort[] =
140 "assert: Assert an expression is true at generation time.";
141 const char kAssert_Help[] =
142 "assert: Assert an expression is true at generation time.\n"
143 "\n"
144 " assert(<condition> [, <error string>])\n"
145 "\n"
146 " If the condition is false, the build will fail with an error. If the\n"
147 " optional second argument is provided, that string will be printed\n"
148 " with the error message.\n"
149 "\n"
150 "Examples:\n"
151 " assert(is_win)\n"
152 " assert(defined(sources), \"Sources must be defined\")\n";
154 Value RunAssert(Scope* scope,
155 const FunctionCallNode* function,
156 const std::vector<Value>& args,
157 Err* err) {
158 if (args.size() != 1 && args.size() != 2) {
159 *err = Err(function->function(), "Wrong number of arguments.",
160 "assert() takes one or two argument, "
161 "were you expecting somethig else?");
162 } else if (args[0].type() != Value::BOOLEAN) {
163 *err = Err(function->function(), "Assertion value not a bool.");
164 } else if (!args[0].boolean_value()) {
165 if (args.size() == 2) {
166 // Optional string message.
167 if (args[1].type() != Value::STRING) {
168 *err = Err(function->function(), "Assertion failed.",
169 "<<<ERROR MESSAGE IS NOT A STRING>>>");
170 } else {
171 *err = Err(function->function(), "Assertion failed.",
172 args[1].string_value());
174 } else {
175 *err = Err(function->function(), "Assertion failed.");
178 if (args[0].origin()) {
179 // If you do "assert(foo)" we'd ideally like to show you where foo was
180 // set, and in this case the origin of the args will tell us that.
181 // However, if you do "assert(foo && bar)" the source of the value will
182 // be the assert like, which isn't so helpful.
184 // So we try to see if the args are from the same line or not. This will
185 // break if you do "assert(\nfoo && bar)" and we may show the second line
186 // as the source, oh well. The way around this is to check to see if the
187 // origin node is inside our function call block.
188 Location origin_location = args[0].origin()->GetRange().begin();
189 if (origin_location.file() != function->function().location().file() ||
190 origin_location.line_number() !=
191 function->function().location().line_number()) {
192 err->AppendSubErr(Err(args[0].origin()->GetRange(), "",
193 "This is where it was set."));
197 return Value();
200 // config ----------------------------------------------------------------------
202 const char kConfig[] = "config";
203 const char kConfig_HelpShort[] =
204 "config: Defines a configuration object.";
205 const char kConfig_Help[] =
206 "config: Defines a configuration object.\n"
207 "\n"
208 " Configuration objects can be applied to targets and specify sets of\n"
209 " compiler flags, includes, defines, etc. They provide a way to\n"
210 " conveniently group sets of this configuration information.\n"
211 "\n"
212 " A config is referenced by its label just like a target.\n"
213 "\n"
214 " The values in a config are additive only. If you want to remove a flag\n"
215 " you need to remove the corresponding config that sets it. The final\n"
216 " set of flags, defines, etc. for a target is generated in this order:\n"
217 "\n"
218 " 1. The values specified directly on the target (rather than using a\n"
219 " config.\n"
220 " 2. The configs specified in the target's \"configs\" list, in order.\n"
221 " 3. Public_configs from a breadth-first traversal of the dependency\n"
222 " tree in the order that the targets appear in \"deps\".\n"
223 " 4. All dependent configs from a breadth-first traversal of the\n"
224 " dependency tree in the order that the targets appear in \"deps\".\n"
225 "\n"
226 "Variables valid in a config definition:\n"
227 CONFIG_VALUES_VARS_HELP
228 "\n"
229 "Variables on a target used to apply configs:\n"
230 " all_dependent_configs, configs, public_configs,\n"
231 " forward_dependent_configs_from\n"
232 "\n"
233 "Example:\n"
234 " config(\"myconfig\") {\n"
235 " includes = [ \"include/common\" ]\n"
236 " defines = [ \"ENABLE_DOOM_MELON\" ]\n"
237 " }\n"
238 "\n"
239 " executable(\"mything\") {\n"
240 " configs = [ \":myconfig\" ]\n"
241 " }\n";
243 Value RunConfig(const FunctionCallNode* function,
244 const std::vector<Value>& args,
245 Scope* scope,
246 Err* err) {
247 if (!EnsureSingleStringArg(function, args, err) ||
248 !EnsureNotProcessingImport(function, scope, err))
249 return Value();
251 Label label(MakeLabelForScope(scope, function, args[0].string_value()));
253 if (g_scheduler->verbose_logging())
254 g_scheduler->Log("Defining config", label.GetUserVisibleName(true));
256 // Create the new config.
257 scoped_ptr<Config> config(new Config(scope->settings(), label));
258 config->set_defined_from(function);
259 if (!Visibility::FillItemVisibility(config.get(), scope, err))
260 return Value();
262 // Fill it.
263 const SourceDir& input_dir = scope->GetSourceDir();
264 ConfigValuesGenerator gen(&config->config_values(), scope, input_dir, err);
265 gen.Run();
266 if (err->has_error())
267 return Value();
269 // Save the generated item.
270 Scope::ItemVector* collector = scope->GetItemCollector();
271 if (!collector) {
272 *err = Err(function, "Can't define a config in this context.");
273 return Value();
275 collector->push_back(config.release());
277 return Value();
280 // declare_args ----------------------------------------------------------------
282 const char kDeclareArgs[] = "declare_args";
283 const char kDeclareArgs_HelpShort[] =
284 "declare_args: Declare build arguments.";
285 const char kDeclareArgs_Help[] =
286 "declare_args: Declare build arguments.\n"
287 "\n"
288 " Introduces the given arguments into the current scope. If they are\n"
289 " not specified on the command line or in a toolchain's arguments,\n"
290 " the default values given in the declare_args block will be used.\n"
291 " However, these defaults will not override command-line values.\n"
292 "\n"
293 " See also \"gn help buildargs\" for an overview.\n"
294 "\n"
295 "Example:\n"
296 " declare_args() {\n"
297 " enable_teleporter = true\n"
298 " enable_doom_melon = false\n"
299 " }\n"
300 "\n"
301 " If you want to override the (default disabled) Doom Melon:\n"
302 " gn --args=\"enable_doom_melon=true enable_teleporter=false\"\n"
303 " This also sets the teleporter, but it's already defaulted to on so\n"
304 " it will have no effect.\n";
306 Value RunDeclareArgs(Scope* scope,
307 const FunctionCallNode* function,
308 const std::vector<Value>& args,
309 BlockNode* block,
310 Err* err) {
311 Scope block_scope(scope);
312 block->Execute(&block_scope, err);
313 if (err->has_error())
314 return Value();
316 // Pass the values from our scope into the Args object for adding to the
317 // scope with the proper values (taking into account the defaults given in
318 // the block_scope, and arguments passed into the build).
319 Scope::KeyValueMap values;
320 block_scope.GetCurrentScopeValues(&values);
321 scope->settings()->build_settings()->build_args().DeclareArgs(
322 values, scope, err);
323 return Value();
326 // defined ---------------------------------------------------------------------
328 const char kDefined[] = "defined";
329 const char kDefined_HelpShort[] =
330 "defined: Returns whether an identifier is defined.";
331 const char kDefined_Help[] =
332 "defined: Returns whether an identifier is defined.\n"
333 "\n"
334 " Returns true if the given argument is defined. This is most useful in\n"
335 " templates to assert that the caller set things up properly.\n"
336 "\n"
337 " You can pass an identifier:\n"
338 " defined(foo)\n"
339 " which will return true or false depending on whether foo is defined in\n"
340 " the current scope.\n"
341 "\n"
342 " You can also check a named scope:\n"
343 " defined(foo.bar)\n"
344 " which will return true or false depending on whether bar is defined in\n"
345 " the named scope foo. It will throw an error if foo is not defined or\n"
346 " is not a scope.\n"
347 "\n"
348 "Example:\n"
349 "\n"
350 " template(\"mytemplate\") {\n"
351 " # To help users call this template properly...\n"
352 " assert(defined(invoker.sources), \"Sources must be defined\")\n"
353 "\n"
354 " # If we want to accept an optional \"values\" argument, we don't\n"
355 " # want to dereference something that may not be defined.\n"
356 " if (defined(invoker.values)) {\n"
357 " values = invoker.values\n"
358 " } else {\n"
359 " values = \"some default value\"\n"
360 " }\n"
361 " }\n";
363 Value RunDefined(Scope* scope,
364 const FunctionCallNode* function,
365 const ListNode* args_list,
366 Err* err) {
367 const std::vector<const ParseNode*>& args_vector = args_list->contents();
368 if (args_vector.size() != 1) {
369 *err = Err(function, "Wrong number of arguments to defined().",
370 "Expecting exactly one.");
371 return Value();
374 const IdentifierNode* identifier = args_vector[0]->AsIdentifier();
375 if (identifier) {
376 // Passed an identifier "defined(foo)".
377 if (scope->GetValue(identifier->value().value()))
378 return Value(function, true);
379 return Value(function, false);
382 const AccessorNode* accessor = args_vector[0]->AsAccessor();
383 if (accessor) {
384 // Passed an accessor "defined(foo.bar)".
385 if (accessor->member()) {
386 // The base of the accessor must be a scope if it's defined.
387 const Value* base = scope->GetValue(accessor->base().value());
388 if (!base) {
389 *err = Err(accessor, "Undefined identifier");
390 return Value();
392 if (!base->VerifyTypeIs(Value::SCOPE, err))
393 return Value();
395 // Check the member inside the scope to see if its defined.
396 if (base->scope_value()->GetValue(accessor->member()->value().value()))
397 return Value(function, true);
398 return Value(function, false);
402 // Argument is invalid.
403 *err = Err(function, "Bad thing passed to defined().",
404 "It should be of the form defined(foo) or defined(foo.bar).");
405 return Value();
408 // getenv ----------------------------------------------------------------------
410 const char kGetEnv[] = "getenv";
411 const char kGetEnv_HelpShort[] =
412 "getenv: Get an environment variable.";
413 const char kGetEnv_Help[] =
414 "getenv: Get an environment variable.\n"
415 "\n"
416 " value = getenv(env_var_name)\n"
417 "\n"
418 " Returns the value of the given enironment variable. If the value is\n"
419 " not found, it will try to look up the variable with the \"opposite\"\n"
420 " case (based on the case of the first letter of the variable), but\n"
421 " is otherwise case-sensitive.\n"
422 "\n"
423 " If the environment variable is not found, the empty string will be\n"
424 " returned. Note: it might be nice to extend this if we had the concept\n"
425 " of \"none\" in the language to indicate lookup failure.\n"
426 "\n"
427 "Example:\n"
428 "\n"
429 " home_dir = getenv(\"HOME\")\n";
431 Value RunGetEnv(Scope* scope,
432 const FunctionCallNode* function,
433 const std::vector<Value>& args,
434 Err* err) {
435 if (!EnsureSingleStringArg(function, args, err))
436 return Value();
438 scoped_ptr<base::Environment> env(base::Environment::Create());
440 std::string result;
441 if (!env->GetVar(args[0].string_value().c_str(), &result))
442 return Value(function, ""); // Not found, return empty string.
443 return Value(function, result);
446 // import ----------------------------------------------------------------------
448 const char kImport[] = "import";
449 const char kImport_HelpShort[] =
450 "import: Import a file into the current scope.";
451 const char kImport_Help[] =
452 "import: Import a file into the current scope.\n"
453 "\n"
454 " The import command loads the rules and variables resulting from\n"
455 " executing the given file into the current scope.\n"
456 "\n"
457 " By convention, imported files are named with a .gni extension.\n"
458 "\n"
459 " An import is different than a C++ \"include\". The imported file is\n"
460 " executed in a standalone environment from the caller of the import\n"
461 " command. The results of this execution are cached for other files that\n"
462 " import the same .gni file.\n"
463 "\n"
464 " Note that you can not import a BUILD.gn file that's otherwise used\n"
465 " in the build. Files must either be imported or implicitly loaded as\n"
466 " a result of deps rules, but not both.\n"
467 "\n"
468 " The imported file's scope will be merged with the scope at the point\n"
469 " import was called. If there is a conflict (both the current scope and\n"
470 " the imported file define some variable or rule with the same name but\n"
471 " different value), a runtime error will be thrown. Therefore, it's good\n"
472 " practice to minimize the stuff that an imported file defines.\n"
473 "\n"
474 " Variables and templates beginning with an underscore '_' are\n"
475 " considered private and will not be imported. Imported files can use\n"
476 " such variables for internal computation without affecting other files.\n"
477 "\n"
478 "Examples:\n"
479 "\n"
480 " import(\"//build/rules/idl_compilation_rule.gni\")\n"
481 "\n"
482 " # Looks in the current directory.\n"
483 " import(\"my_vars.gni\")\n";
485 Value RunImport(Scope* scope,
486 const FunctionCallNode* function,
487 const std::vector<Value>& args,
488 Err* err) {
489 if (!EnsureSingleStringArg(function, args, err))
490 return Value();
492 const SourceDir& input_dir = scope->GetSourceDir();
493 SourceFile import_file =
494 input_dir.ResolveRelativeFile(args[0], err,
495 scope->settings()->build_settings()->root_path_utf8());
496 if (!err->has_error()) {
497 scope->settings()->import_manager().DoImport(import_file, function,
498 scope, err);
500 return Value();
503 // set_sources_assignment_filter -----------------------------------------------
505 const char kSetSourcesAssignmentFilter[] = "set_sources_assignment_filter";
506 const char kSetSourcesAssignmentFilter_HelpShort[] =
507 "set_sources_assignment_filter: Set a pattern to filter source files.";
508 const char kSetSourcesAssignmentFilter_Help[] =
509 "set_sources_assignment_filter: Set a pattern to filter source files.\n"
510 "\n"
511 " The sources assignment filter is a list of patterns that remove files\n"
512 " from the list implicitly whenever the \"sources\" variable is\n"
513 " assigned to. This is intended to be used to globally filter out files\n"
514 " with platform-specific naming schemes when they don't apply, for\n"
515 " example, you may want to filter out all \"*_win.cc\" files on non-\n"
516 " Windows platforms.\n"
517 "\n"
518 " Typically this will be called once in the master build config script\n"
519 " to set up the filter for the current platform. Subsequent calls will\n"
520 " overwrite the previous values.\n"
521 "\n"
522 " If you want to bypass the filter and add a file even if it might\n"
523 " be filtered out, call set_sources_assignment_filter([]) to clear the\n"
524 " list of filters. This will apply until the current scope exits\n"
525 "\n"
526 "How to use patterns\n"
527 "\n"
528 " File patterns are VERY limited regular expressions. They must match\n"
529 " the entire input string to be counted as a match. In regular\n"
530 " expression parlance, there is an implicit \"^...$\" surrounding your\n"
531 " input. If you want to match a substring, you need to use wildcards at\n"
532 " the beginning and end.\n"
533 "\n"
534 " There are only two special tokens understood by the pattern matcher.\n"
535 " Everything else is a literal.\n"
536 "\n"
537 " * Matches zero or more of any character. It does not depend on the\n"
538 " preceding character (in regular expression parlance it is\n"
539 " equivalent to \".*\").\n"
540 "\n"
541 " \\b Matches a path boundary. This will match the beginning or end of\n"
542 " a string, or a slash.\n"
543 "\n"
544 "Pattern examples\n"
545 "\n"
546 " \"*asdf*\"\n"
547 " Matches a string containing \"asdf\" anywhere.\n"
548 "\n"
549 " \"asdf\"\n"
550 " Matches only the exact string \"asdf\".\n"
551 "\n"
552 " \"*.cc\"\n"
553 " Matches strings ending in the literal \".cc\".\n"
554 "\n"
555 " \"\\bwin/*\"\n"
556 " Matches \"win/foo\" and \"foo/win/bar.cc\" but not \"iwin/foo\".\n"
557 "\n"
558 "Sources assignment example\n"
559 "\n"
560 " # Filter out all _win files.\n"
561 " set_sources_assignment_filter([ \"*_win.cc\", \"*_win.h\" ])\n"
562 " sources = [ \"a.cc\", \"b_win.cc\" ]\n"
563 " print(sources)\n"
564 " # Will print [ \"a.cc\" ]. b_win one was filtered out.\n";
566 Value RunSetSourcesAssignmentFilter(Scope* scope,
567 const FunctionCallNode* function,
568 const std::vector<Value>& args,
569 Err* err) {
570 if (args.size() != 1) {
571 *err = Err(function, "set_sources_assignment_filter takes one argument.");
572 } else {
573 scoped_ptr<PatternList> f(new PatternList);
574 f->SetFromValue(args[0], err);
575 if (!err->has_error())
576 scope->set_sources_assignment_filter(f.Pass());
578 return Value();
581 // print -----------------------------------------------------------------------
583 const char kPrint[] = "print";
584 const char kPrint_HelpShort[] =
585 "print: Prints to the console.";
586 const char kPrint_Help[] =
587 "print: Prints to the console.\n"
588 "\n"
589 " Prints all arguments to the console separated by spaces. A newline is\n"
590 " automatically appended to the end.\n"
591 "\n"
592 " This function is intended for debugging. Note that build files are run\n"
593 " in parallel so you may get interleaved prints. A buildfile may also\n"
594 " be executed more than once in parallel in the context of different\n"
595 " toolchains so the prints from one file may be duplicated or\n"
596 " interleaved with itself.\n"
597 "\n"
598 "Examples:\n"
599 " print(\"Hello world\")\n"
600 "\n"
601 " print(sources, deps)\n";
603 Value RunPrint(Scope* scope,
604 const FunctionCallNode* function,
605 const std::vector<Value>& args,
606 Err* err) {
607 std::string output;
608 for (size_t i = 0; i < args.size(); i++) {
609 if (i != 0)
610 output.push_back(' ');
611 output.append(args[i].ToString(false));
613 output.push_back('\n');
615 const BuildSettings::PrintCallback& cb =
616 scope->settings()->build_settings()->print_callback();
617 if (cb.is_null())
618 printf("%s", output.c_str());
619 else
620 cb.Run(output);
622 return Value();
625 // -----------------------------------------------------------------------------
627 FunctionInfo::FunctionInfo()
628 : self_evaluating_args_runner(nullptr),
629 generic_block_runner(nullptr),
630 executed_block_runner(nullptr),
631 no_block_runner(nullptr),
632 help_short(nullptr),
633 help(nullptr),
634 is_target(false) {
637 FunctionInfo::FunctionInfo(SelfEvaluatingArgsFunction seaf,
638 const char* in_help_short,
639 const char* in_help,
640 bool in_is_target)
641 : self_evaluating_args_runner(seaf),
642 generic_block_runner(nullptr),
643 executed_block_runner(nullptr),
644 no_block_runner(nullptr),
645 help_short(in_help_short),
646 help(in_help),
647 is_target(in_is_target) {
650 FunctionInfo::FunctionInfo(GenericBlockFunction gbf,
651 const char* in_help_short,
652 const char* in_help,
653 bool in_is_target)
654 : self_evaluating_args_runner(nullptr),
655 generic_block_runner(gbf),
656 executed_block_runner(nullptr),
657 no_block_runner(nullptr),
658 help_short(in_help_short),
659 help(in_help),
660 is_target(in_is_target) {
663 FunctionInfo::FunctionInfo(ExecutedBlockFunction ebf,
664 const char* in_help_short,
665 const char* in_help,
666 bool in_is_target)
667 : self_evaluating_args_runner(nullptr),
668 generic_block_runner(nullptr),
669 executed_block_runner(ebf),
670 no_block_runner(nullptr),
671 help_short(in_help_short),
672 help(in_help),
673 is_target(in_is_target) {
676 FunctionInfo::FunctionInfo(NoBlockFunction nbf,
677 const char* in_help_short,
678 const char* in_help,
679 bool in_is_target)
680 : self_evaluating_args_runner(nullptr),
681 generic_block_runner(nullptr),
682 executed_block_runner(nullptr),
683 no_block_runner(nbf),
684 help_short(in_help_short),
685 help(in_help),
686 is_target(in_is_target) {
689 // Setup the function map via a static initializer. We use this because it
690 // avoids race conditions without having to do some global setup function or
691 // locking-heavy singleton checks at runtime. In practice, we always need this
692 // before we can do anything interesting, so it's OK to wait for the
693 // initializer.
694 struct FunctionInfoInitializer {
695 FunctionInfoMap map;
697 FunctionInfoInitializer() {
698 #define INSERT_FUNCTION(command, is_target) \
699 map[k##command] = FunctionInfo(&Run##command, \
700 k##command##_HelpShort, \
701 k##command##_Help, \
702 is_target);
704 INSERT_FUNCTION(Action, true)
705 INSERT_FUNCTION(ActionForEach, true)
706 INSERT_FUNCTION(Copy, true)
707 INSERT_FUNCTION(Executable, true)
708 INSERT_FUNCTION(Group, true)
709 INSERT_FUNCTION(SharedLibrary, true)
710 INSERT_FUNCTION(SourceSet, true)
711 INSERT_FUNCTION(StaticLibrary, true)
712 INSERT_FUNCTION(Target, true)
714 INSERT_FUNCTION(Assert, false)
715 INSERT_FUNCTION(Config, false)
716 INSERT_FUNCTION(DeclareArgs, false)
717 INSERT_FUNCTION(Defined, false)
718 INSERT_FUNCTION(ExecScript, false)
719 INSERT_FUNCTION(ForEach, false)
720 INSERT_FUNCTION(ForwardVariablesFrom, false)
721 INSERT_FUNCTION(GetEnv, false)
722 INSERT_FUNCTION(GetLabelInfo, false)
723 INSERT_FUNCTION(GetPathInfo, false)
724 INSERT_FUNCTION(GetTargetOutputs, false)
725 INSERT_FUNCTION(Import, false)
726 INSERT_FUNCTION(Print, false)
727 INSERT_FUNCTION(ProcessFileTemplate, false)
728 INSERT_FUNCTION(ReadFile, false)
729 INSERT_FUNCTION(RebasePath, false)
730 INSERT_FUNCTION(SetDefaults, false)
731 INSERT_FUNCTION(SetDefaultToolchain, false)
732 INSERT_FUNCTION(SetSourcesAssignmentFilter, false)
733 INSERT_FUNCTION(Template, false)
734 INSERT_FUNCTION(Tool, false)
735 INSERT_FUNCTION(Toolchain, false)
736 INSERT_FUNCTION(ToolchainArgs, false)
737 INSERT_FUNCTION(WriteFile, false)
739 #undef INSERT_FUNCTION
742 const FunctionInfoInitializer function_info;
744 const FunctionInfoMap& GetFunctions() {
745 return function_info.map;
748 Value RunFunction(Scope* scope,
749 const FunctionCallNode* function,
750 const ListNode* args_list,
751 BlockNode* block,
752 Err* err) {
753 const Token& name = function->function();
755 const FunctionInfoMap& function_map = GetFunctions();
756 FunctionInfoMap::const_iterator found_function =
757 function_map.find(name.value());
758 if (found_function == function_map.end()) {
759 // No built-in function matching this, check for a template.
760 const Template* templ =
761 scope->GetTemplate(function->function().value().as_string());
762 if (templ) {
763 Value args = args_list->Execute(scope, err);
764 if (err->has_error())
765 return Value();
766 return templ->Invoke(scope, function, args.list_value(), block, err);
769 *err = Err(name, "Unknown function.");
770 return Value();
773 if (found_function->second.self_evaluating_args_runner) {
774 // Self evaluating args functions are special weird built-ins like foreach.
775 // Rather than force them all to check that they have a block or no block
776 // and risk bugs for new additions, check a whitelist here.
777 if (found_function->second.self_evaluating_args_runner != &RunForEach) {
778 if (!VerifyNoBlockForFunctionCall(function, block, err))
779 return Value();
781 return found_function->second.self_evaluating_args_runner(
782 scope, function, args_list, err);
785 // All other function types take a pre-executed set of args.
786 Value args = args_list->Execute(scope, err);
787 if (err->has_error())
788 return Value();
790 if (found_function->second.generic_block_runner) {
791 if (!block) {
792 FillNeedsBlockError(function, err);
793 return Value();
795 return found_function->second.generic_block_runner(
796 scope, function, args.list_value(), block, err);
799 if (found_function->second.executed_block_runner) {
800 if (!block) {
801 FillNeedsBlockError(function, err);
802 return Value();
805 Scope block_scope(scope);
806 block->Execute(&block_scope, err);
807 if (err->has_error())
808 return Value();
810 Value result = found_function->second.executed_block_runner(
811 function, args.list_value(), &block_scope, err);
812 if (err->has_error())
813 return Value();
815 if (!block_scope.CheckForUnusedVars(err))
816 return Value();
817 return result;
820 // Otherwise it's a no-block function.
821 if (!VerifyNoBlockForFunctionCall(function, block, err))
822 return Value();
823 return found_function->second.no_block_runner(scope, function,
824 args.list_value(), err);
827 } // namespace functions