• 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. Public_configs from a breadth-first traversal of the dependency\n"
201     "      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, public_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     "  Typically this will be called once in the master build config script\n"
493     "  to set up the filter for the current platform. Subsequent calls will\n"
494     "  overwrite the previous values.\n"
495     "\n"
496     "  If you want to bypass the filter and add a file even if it might\n"
497     "  be filtered out, call set_sources_assignment_filter([]) to clear the\n"
498     "  list of filters. This will apply until the current scope exits\n"
499     "\n"
500     "How to use patterns\n"
501     "\n"
502     "  File patterns are VERY limited regular expressions. They must match\n"
503     "  the entire input string to be counted as a match. In regular\n"
504     "  expression parlance, there is an implicit \"^...$\" surrounding your\n"
505     "  input. If you want to match a substring, you need to use wildcards at\n"
506     "  the beginning and end.\n"
507     "\n"
508     "  There are only two special tokens understood by the pattern matcher.\n"
509     "  Everything else is a literal.\n"
510     "\n"
511     "   * Matches zero or more of any character. It does not depend on the\n"
512     "     preceding character (in regular expression parlance it is\n"
513     "     equivalent to \".*\").\n"
514     "\n"
515     "  \\b Matches a path boundary. This will match the beginning or end of\n"
516     "     a string, or a slash.\n"
517     "\n"
518     "Pattern examples\n"
519     "\n"
520     "  \"*asdf*\"\n"
521     "      Matches a string containing \"asdf\" anywhere.\n"
522     "\n"
523     "  \"asdf\"\n"
524     "      Matches only the exact string \"asdf\".\n"
525     "\n"
526     "  \"*.cc\"\n"
527     "      Matches strings ending in the literal \".cc\".\n"
528     "\n"
529     "  \"\\bwin/*\"\n"
530     "      Matches \"win/foo\" and \"foo/win/bar.cc\" but not \"iwin/foo\".\n"
531     "\n"
532     "Sources assignment example\n"
533     "\n"
534     "  # Filter out all _win files.\n"
535     "  set_sources_assignment_filter([ \"*_win.cc\", \"*_win.h\" ])\n"
536     "  sources = [ \"a.cc\", \"b_win.cc\" ]\n"
537     "  print(sources)\n"
538     "  # Will print [ \"a.cc\" ]. b_win one was filtered out.\n";
539 
RunSetSourcesAssignmentFilter(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,Err * err)540 Value RunSetSourcesAssignmentFilter(Scope* scope,
541                                     const FunctionCallNode* function,
542                                     const std::vector<Value>& args,
543                                     Err* err) {
544   if (args.size() != 1) {
545     *err = Err(function, "set_sources_assignment_filter takes one argument.");
546   } else {
547     scoped_ptr<PatternList> f(new PatternList);
548     f->SetFromValue(args[0], err);
549     if (!err->has_error())
550       scope->set_sources_assignment_filter(f.Pass());
551   }
552   return Value();
553 }
554 
555 // print -----------------------------------------------------------------------
556 
557 const char kPrint[] = "print";
558 const char kPrint_HelpShort[] =
559     "print: Prints to the console.";
560 const char kPrint_Help[] =
561     "print: Prints to the console.\n"
562     "\n"
563     "  Prints all arguments to the console separated by spaces. A newline is\n"
564     "  automatically appended to the end.\n"
565     "\n"
566     "  This function is intended for debugging. Note that build files are run\n"
567     "  in parallel so you may get interleaved prints. A buildfile may also\n"
568     "  be executed more than once in parallel in the context of different\n"
569     "  toolchains so the prints from one file may be duplicated or\n"
570     "  interleaved with itself.\n"
571     "\n"
572     "Examples:\n"
573     "  print(\"Hello world\")\n"
574     "\n"
575     "  print(sources, deps)\n";
576 
RunPrint(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,Err * err)577 Value RunPrint(Scope* scope,
578                const FunctionCallNode* function,
579                const std::vector<Value>& args,
580                Err* err) {
581   std::string output;
582   for (size_t i = 0; i < args.size(); i++) {
583     if (i != 0)
584       output.push_back(' ');
585     output.append(args[i].ToString(false));
586   }
587   output.push_back('\n');
588 
589   const BuildSettings::PrintCallback& cb =
590       scope->settings()->build_settings()->print_callback();
591   if (cb.is_null())
592     printf("%s", output.c_str());
593   else
594     cb.Run(output);
595 
596   return Value();
597 }
598 
599 // -----------------------------------------------------------------------------
600 
FunctionInfo()601 FunctionInfo::FunctionInfo()
602     : self_evaluating_args_runner(NULL),
603       generic_block_runner(NULL),
604       executed_block_runner(NULL),
605       no_block_runner(NULL),
606       help_short(NULL),
607       help(NULL),
608       is_target(false) {
609 }
610 
FunctionInfo(SelfEvaluatingArgsFunction seaf,const char * in_help_short,const char * in_help,bool in_is_target)611 FunctionInfo::FunctionInfo(SelfEvaluatingArgsFunction seaf,
612                            const char* in_help_short,
613                            const char* in_help,
614                            bool in_is_target)
615     : self_evaluating_args_runner(seaf),
616       generic_block_runner(NULL),
617       executed_block_runner(NULL),
618       no_block_runner(NULL),
619       help_short(in_help_short),
620       help(in_help),
621       is_target(in_is_target) {
622 }
623 
FunctionInfo(GenericBlockFunction gbf,const char * in_help_short,const char * in_help,bool in_is_target)624 FunctionInfo::FunctionInfo(GenericBlockFunction gbf,
625                            const char* in_help_short,
626                            const char* in_help,
627                            bool in_is_target)
628     : self_evaluating_args_runner(NULL),
629       generic_block_runner(gbf),
630       executed_block_runner(NULL),
631       no_block_runner(NULL),
632       help_short(in_help_short),
633       help(in_help),
634       is_target(in_is_target) {
635 }
636 
FunctionInfo(ExecutedBlockFunction ebf,const char * in_help_short,const char * in_help,bool in_is_target)637 FunctionInfo::FunctionInfo(ExecutedBlockFunction ebf,
638                            const char* in_help_short,
639                            const char* in_help,
640                            bool in_is_target)
641     : self_evaluating_args_runner(NULL),
642       generic_block_runner(NULL),
643       executed_block_runner(ebf),
644       no_block_runner(NULL),
645       help_short(in_help_short),
646       help(in_help),
647       is_target(in_is_target) {
648 }
649 
FunctionInfo(NoBlockFunction nbf,const char * in_help_short,const char * in_help,bool in_is_target)650 FunctionInfo::FunctionInfo(NoBlockFunction nbf,
651                            const char* in_help_short,
652                            const char* in_help,
653                            bool in_is_target)
654     : self_evaluating_args_runner(NULL),
655       generic_block_runner(NULL),
656       executed_block_runner(NULL),
657       no_block_runner(nbf),
658       help_short(in_help_short),
659       help(in_help),
660       is_target(in_is_target) {
661 }
662 
663 // Setup the function map via a static initializer. We use this because it
664 // avoids race conditions without having to do some global setup function or
665 // locking-heavy singleton checks at runtime. In practice, we always need this
666 // before we can do anything interesting, so it's OK to wait for the
667 // initializer.
668 struct FunctionInfoInitializer {
669   FunctionInfoMap map;
670 
FunctionInfoInitializerfunctions::FunctionInfoInitializer671   FunctionInfoInitializer() {
672     #define INSERT_FUNCTION(command, is_target) \
673         map[k##command] = FunctionInfo(&Run##command, \
674                                        k##command##_HelpShort, \
675                                        k##command##_Help, \
676                                        is_target);
677 
678     INSERT_FUNCTION(Action, true)
679     INSERT_FUNCTION(ActionForEach, true)
680     INSERT_FUNCTION(Copy, true)
681     INSERT_FUNCTION(Executable, true)
682     INSERT_FUNCTION(Group, true)
683     INSERT_FUNCTION(SharedLibrary, true)
684     INSERT_FUNCTION(SourceSet, true)
685     INSERT_FUNCTION(StaticLibrary, true)
686 
687     INSERT_FUNCTION(Assert, false)
688     INSERT_FUNCTION(Config, false)
689     INSERT_FUNCTION(DeclareArgs, false)
690     INSERT_FUNCTION(Defined, false)
691     INSERT_FUNCTION(ExecScript, false)
692     INSERT_FUNCTION(ForEach, false)
693     INSERT_FUNCTION(GetEnv, false)
694     INSERT_FUNCTION(GetLabelInfo, false)
695     INSERT_FUNCTION(GetPathInfo, false)
696     INSERT_FUNCTION(GetTargetOutputs, false)
697     INSERT_FUNCTION(Import, false)
698     INSERT_FUNCTION(Print, false)
699     INSERT_FUNCTION(ProcessFileTemplate, false)
700     INSERT_FUNCTION(ReadFile, false)
701     INSERT_FUNCTION(RebasePath, false)
702     INSERT_FUNCTION(SetDefaults, false)
703     INSERT_FUNCTION(SetDefaultToolchain, false)
704     INSERT_FUNCTION(SetSourcesAssignmentFilter, false)
705     INSERT_FUNCTION(Template, false)
706     INSERT_FUNCTION(Tool, false)
707     INSERT_FUNCTION(Toolchain, false)
708     INSERT_FUNCTION(ToolchainArgs, false)
709     INSERT_FUNCTION(WriteFile, false)
710 
711     #undef INSERT_FUNCTION
712   }
713 };
714 const FunctionInfoInitializer function_info;
715 
GetFunctions()716 const FunctionInfoMap& GetFunctions() {
717   return function_info.map;
718 }
719 
RunFunction(Scope * scope,const FunctionCallNode * function,const ListNode * args_list,BlockNode * block,Err * err)720 Value RunFunction(Scope* scope,
721                   const FunctionCallNode* function,
722                   const ListNode* args_list,
723                   BlockNode* block,
724                   Err* err) {
725   const Token& name = function->function();
726 
727   const FunctionInfoMap& function_map = GetFunctions();
728   FunctionInfoMap::const_iterator found_function =
729       function_map.find(name.value());
730   if (found_function == function_map.end()) {
731     // No built-in function matching this, check for a template.
732     const Template* templ =
733         scope->GetTemplate(function->function().value().as_string());
734     if (templ) {
735       Value args = args_list->Execute(scope, err);
736       if (err->has_error())
737         return Value();
738       return templ->Invoke(scope, function, args.list_value(), block, err);
739     }
740 
741     *err = Err(name, "Unknown function.");
742     return Value();
743   }
744 
745   if (found_function->second.self_evaluating_args_runner) {
746     return found_function->second.self_evaluating_args_runner(
747         scope, function, args_list, err);
748   }
749 
750   // All other function types take a pre-executed set of args.
751   Value args = args_list->Execute(scope, err);
752   if (err->has_error())
753     return Value();
754 
755   if (found_function->second.generic_block_runner) {
756     if (!block) {
757       FillNeedsBlockError(function, err);
758       return Value();
759     }
760     return found_function->second.generic_block_runner(
761         scope, function, args.list_value(), block, err);
762   }
763 
764   if (found_function->second.executed_block_runner) {
765     if (!block) {
766       FillNeedsBlockError(function, err);
767       return Value();
768     }
769 
770     Scope block_scope(scope);
771     block->ExecuteBlockInScope(&block_scope, err);
772     if (err->has_error())
773       return Value();
774 
775     Value result = found_function->second.executed_block_runner(
776         function, args.list_value(), &block_scope, err);
777     if (err->has_error())
778       return Value();
779 
780     if (!block_scope.CheckForUnusedVars(err))
781       return Value();
782     return result;
783   }
784 
785   // Otherwise it's a no-block function.
786   return found_function->second.no_block_runner(scope, function,
787                                                 args.list_value(), err);
788 }
789 
790 }  // namespace functions
791