Home | History | Annotate | Download | only in gn
      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.
     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 
     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 
     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 
     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 
    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 
    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 
    134 const Label& ToolchainLabelForScope(const Scope* scope) {
    135   return scope->settings()->toolchain_label();
    136 }
    137 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    536   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 
    573 const FunctionInfoMap& GetFunctions() {
    574   return function_info.map;
    575 }
    576 
    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