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