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