| Index: tools/gn/input_conversion.cc
|
| diff --git a/tools/gn/input_conversion.cc b/tools/gn/input_conversion.cc
|
| index 246b4c9d5fb9e4f8c7deec96e31ef80fa42d4beb..e66000b5ebbedcfb4c0c0bfa94c8ce8eafb68fc8 100644
|
| --- a/tools/gn/input_conversion.cc
|
| +++ b/tools/gn/input_conversion.cc
|
| @@ -12,6 +12,7 @@
|
| #include "tools/gn/label.h"
|
| #include "tools/gn/parse_tree.h"
|
| #include "tools/gn/parser.h"
|
| +#include "tools/gn/scheduler.h"
|
| #include "tools/gn/scope.h"
|
| #include "tools/gn/settings.h"
|
| #include "tools/gn/tokenizer.h"
|
| @@ -47,36 +48,56 @@ Err MakeParseErr(const std::string& input,
|
| return result;
|
| }
|
|
|
| +enum ValueOrScope {
|
| + PARSE_VALUE, // Treat the input as an expression.
|
| + PARSE_SCOPE, // Treat the input as code and return the resulting scope.
|
| +};
|
| +
|
| // Sets the origin of the value and any nested values with the given node.
|
| -Value ParseString(const std::string& input,
|
| - const ParseNode* origin,
|
| - Err* err) {
|
| - SourceFile empty_source_for_most_vexing_parse;
|
| - InputFile input_file(empty_source_for_most_vexing_parse);
|
| - input_file.SetContents(input);
|
| -
|
| - std::vector<Token> tokens = Tokenizer::Tokenize(&input_file, err);
|
| +Value ParseValueOrScope(const std::string& input,
|
| + ValueOrScope what,
|
| + const ParseNode* origin,
|
| + Err* err) {
|
| + // The memory for these will be kept around by the input file manager
|
| + // so the origin parse nodes for the values will be preserved.
|
| + InputFile* input_file;
|
| + std::vector<Token>* tokens;
|
| + scoped_ptr<ParseNode>* parse_root_ptr;
|
| + g_scheduler->input_file_manager()->AddDynamicInput(
|
| + &input_file, &tokens, &parse_root_ptr);
|
| +
|
| + input_file->SetContents(input);
|
| + input_file->set_friendly_name("Script input"); // TODO(brettw) make nicer.
|
| +
|
| + *tokens = Tokenizer::Tokenize(input_file, err);
|
| if (err->has_error()) {
|
| *err = MakeParseErr(input, origin, *err);
|
| return Value();
|
| }
|
|
|
| - scoped_ptr<ParseNode> expression = Parser::ParseExpression(tokens, err);
|
| + // Parse the file according to what we're looking for.
|
| + if (what == PARSE_VALUE)
|
| + *parse_root_ptr = Parser::ParseExpression(*tokens, err);
|
| + else
|
| + *parse_root_ptr = Parser::Parse(*tokens, err); // Will return a Block.
|
| if (err->has_error()) {
|
| *err = MakeParseErr(input, origin, *err);
|
| return Value();
|
| }
|
| + ParseNode* parse_root = parse_root_ptr->get(); // For nicer syntax below.
|
|
|
| // It's valid for the result to be a null pointer, this just means that the
|
| // script returned nothing.
|
| - if (!expression)
|
| + if (!parse_root)
|
| return Value();
|
|
|
| - // The result should either be a list or a literal, anything else is
|
| - // invalid.
|
| - if (!expression->AsList() && !expression->AsLiteral()) {
|
| - *err = MakeParseErr(input, origin, Err());
|
| - return Value();
|
| + // When parsing as a value, the result should either be a list or a literal,
|
| + // anything else is invalid.
|
| + if (what == PARSE_VALUE) {
|
| + if (!parse_root->AsList() && !parse_root->AsLiteral()) {
|
| + *err = MakeParseErr(input, origin, Err());
|
| + return Value();
|
| + }
|
| }
|
|
|
| BuildSettings build_settings;
|
| @@ -84,23 +105,31 @@ Value ParseString(const std::string& input,
|
| Scope scope(&settings);
|
|
|
| Err nested_err;
|
| - Value result = expression->Execute(&scope, &nested_err);
|
| + Value result = parse_root->Execute(&scope, &nested_err);
|
| if (nested_err.has_error()) {
|
| *err = MakeParseErr(input, origin, nested_err);
|
| return Value();
|
| }
|
|
|
| - // The returned value will have references to the temporary parse nodes we
|
| - // made on the stack. If the values are used in an error message in the
|
| - // future, this will crash. Reset the origin of all values to be our
|
| - // containing origin.
|
| - result.RecursivelySetOrigin(origin);
|
| + // When we want the result as a scope, the result is actually the scope
|
| + // we made, rather than the result of running the code (which will be
|
| + // empty).
|
| + if (what == PARSE_SCOPE) {
|
| + DCHECK(result.type() == Value::NONE);
|
| + // Convert the scope to a dictionary. We have to return the result, and
|
| + // a scope value does not own its scope.
|
| + result = Value(origin, Value::DICT);
|
| + std::vector<base::StringPiece> keys;
|
| + scope.GetCurrentScopeKeys(&keys);
|
| + for (size_t i = 0; i < keys.size(); i++) {
|
| + result.dict_value()[keys[i].as_string()] =
|
| + *scope.GetValue(keys[i], false);
|
| + }
|
| + }
|
| return result;
|
| }
|
|
|
| -Value ParseList(const std::string& input,
|
| - const ParseNode* origin,
|
| - Err* err) {
|
| +Value ParseList(const std::string& input, const ParseNode* origin, Err* err) {
|
| Value ret(origin, Value::LIST);
|
| std::vector<std::string> as_lines;
|
| base::SplitString(input, '\n', &as_lines);
|
| @@ -141,11 +170,13 @@ Value DoConvertInputToValue(const std::string& input,
|
| }
|
|
|
| if (input_conversion == "value")
|
| - return ParseString(input, origin, err);
|
| + return ParseValueOrScope(input, PARSE_VALUE, origin, err);
|
| if (input_conversion == "string")
|
| return Value(origin, input);
|
| if (input_conversion == "list lines")
|
| return ParseList(input, origin, err);
|
| + if (input_conversion == "scope")
|
| + return ParseValueOrScope(input, PARSE_SCOPE, origin, err);
|
|
|
| *err = Err(original_input_conversion, "Not a valid input_conversion.",
|
| "Have you considered a career in retail?");
|
| @@ -172,6 +203,19 @@ extern const char kInputConversion_Help[] =
|
| " After splitting, each individual line will be trimmed of\n"
|
| " whitespace on both ends.\n"
|
| "\n"
|
| + " \"scope\"\n"
|
| + " Execute the block as GN code and return a scope with the\n"
|
| + " resulting values in it. If the input was:\n"
|
| + " a = [ \"hello.cc\", \"world.cc\" ]\n"
|
| + " b = 26\n"
|
| + " and you read the result into a variable named \"val\", then you\n"
|
| + " could access contents the \".\" operator on \"val\":\n"
|
| + " sources = val.a\n"
|
| + " some_count = val.b\n"
|
| + "\n"
|
| + " \"string\"\n"
|
| + " Return the file contents into a single string.\n"
|
| + "\n"
|
| " \"value\"\n"
|
| " Parse the input as if it was a literal rvalue in a buildfile.\n"
|
| " Examples of typical program output using this mode:\n"
|
| @@ -184,9 +228,6 @@ extern const char kInputConversion_Help[] =
|
| " Note that if the input is empty, the result will be a null value\n"
|
| " which will produce an error if assigned to a variable.\n"
|
| "\n"
|
| - " \"string\"\n"
|
| - " Return the file contents into a single string.\n"
|
| - "\n"
|
| " \"trim ...\"\n"
|
| " Prefixing any of the other transformations with the word \"trim\"\n"
|
| " will result in whitespace being trimmed from the beginning and end\n"
|
|
|