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