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