1d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// found in the LICENSE file.
4d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/input_conversion.h"
6d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
7d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/string_split.h"
8d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/string_util.h"
9d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/build_settings.h"
10d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/err.h"
11d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/input_file.h"
12d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/label.h"
13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/parse_tree.h"
14d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/parser.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "tools/gn/scheduler.h"
16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/scope.h"
17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/settings.h"
18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/tokenizer.h"
19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/value.h"
20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
21d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace {
22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochenum ValueOrScope {
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PARSE_VALUE,  // Treat the input as an expression.
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PARSE_SCOPE,  // Treat the input as code and return the resulting scope.
26c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch};
27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Sets the origin of the value and any nested values with the given node.
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochValue ParseValueOrScope(const Settings* settings,
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        const std::string& input,
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        ValueOrScope what,
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        const ParseNode* origin,
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        Err* err) {
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // The memory for these will be kept around by the input file manager
35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // so the origin parse nodes for the values will be preserved.
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  InputFile* input_file;
37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<Token>* tokens;
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<ParseNode>* parse_root_ptr;
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  g_scheduler->input_file_manager()->AddDynamicInput(
40a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      SourceFile(), &input_file, &tokens, &parse_root_ptr);
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  input_file->SetContents(input);
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (origin) {
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // This description will be the blame for any error messages caused by
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // script parsing or if a value is blamed. It will say
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // "Error at <...>:line:char" so here we try to make a string for <...>
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // that reads well in this context.
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    input_file->set_friendly_name(
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "dynamically parsed input that " +
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        origin->GetRange().begin().Describe(true) +
51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        " loaded ");
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  } else {
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    input_file->set_friendly_name("dynamic input");
54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  *tokens = Tokenizer::Tokenize(input_file, err);
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (err->has_error())
58d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Parse the file according to what we're looking for.
61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (what == PARSE_VALUE)
62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *parse_root_ptr = Parser::ParseExpression(*tokens, err);
63c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  else
64c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *parse_root_ptr = Parser::Parse(*tokens, err);  // Will return a Block.
65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (err->has_error())
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return Value();
67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ParseNode* parse_root = parse_root_ptr->get();  // For nicer syntax below.
68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // It's valid for the result to be a null pointer, this just means that the
70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // script returned nothing.
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!parse_root)
72d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
73d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // When parsing as a value, the result should either be a list or a literal,
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // anything else is invalid.
76c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (what == PARSE_VALUE) {
77c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!parse_root->AsList() && !parse_root->AsLiteral())
78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return Value();
79d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
80d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<Scope> scope(new Scope(settings));
82d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  Value result = parse_root->Execute(scope.get(), err);
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (err->has_error())
85d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
86d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
87c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // When we want the result as a scope, the result is actually the scope
88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // we made, rather than the result of running the block (which will be empty).
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (what == PARSE_SCOPE) {
90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK(result.type() == Value::NONE);
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    result = Value(origin, scope.Pass());
92c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
93d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return result;
94d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
95d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
96c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochValue ParseList(const std::string& input, const ParseNode* origin, Err* err) {
97d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  Value ret(origin, Value::LIST);
98d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::vector<std::string> as_lines;
99d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  base::SplitString(input, '\n', &as_lines);
100d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Trim one empty line from the end since the last line might end in a
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // newline. If the user wants more trimming, they'll specify "trim" in the
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // input conversion options.
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!as_lines.empty() && as_lines[as_lines.size() - 1].empty())
105d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    as_lines.resize(as_lines.size() - 1);
106d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
107d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ret.list_value().reserve(as_lines.size());
108d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < as_lines.size(); i++)
109d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    ret.list_value().push_back(Value(origin, as_lines[i]));
110d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return ret;
111d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
112d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Backend for ConvertInputToValue, this takes the extracted string for the
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// input conversion so we can recursively call ourselves to handle the optional
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// "trim" prefix. This original value is also kept for the purposes of throwing
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// errors.
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochValue DoConvertInputToValue(const Settings* settings,
118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            const std::string& input,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const ParseNode* origin,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const Value& original_input_conversion,
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            const std::string& input_conversion,
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            Err* err) {
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (input_conversion.empty())
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return Value();  // Empty string means discard the result.
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char kTrimPrefix[] = "trim ";
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (StartsWithASCII(input_conversion, kTrimPrefix, true)) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string trimmed;
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TrimWhitespaceASCII(input, base::TRIM_ALL, &trimmed);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Remove "trim" prefix from the input conversion and re-run.
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return DoConvertInputToValue(
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        settings, trimmed, origin, original_input_conversion,
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        input_conversion.substr(arraysize(kTrimPrefix) - 1), err);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (input_conversion == "value")
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return ParseValueOrScope(settings, input, PARSE_VALUE, origin, err);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (input_conversion == "string")
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return Value(origin, input);
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (input_conversion == "list lines")
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ParseList(input, origin, err);
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (input_conversion == "scope")
144c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return ParseValueOrScope(settings, input, PARSE_SCOPE, origin, err);
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *err = Err(original_input_conversion, "Not a valid input_conversion.",
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             "Have you considered a career in retail?");
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return Value();
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}  // namespace
152d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)extern const char kInputConversion_Help[] =
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "input_conversion: Specifies how to transform input to a variable.\n"
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "\n"
156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "  input_conversion is an argument to read_file and exec_script that\n"
157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "  specifies how the result of the read operation should be converted\n"
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "  into a variable.\n"
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "\n"
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  \"\" (the default)\n"
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      Discard the result and return None.\n"
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "\n"
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "  \"list lines\"\n"
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      Return the file contents as a list, with a string for each line.\n"
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      The newlines will not be present in the result. The last line may\n"
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      or may not end in a newline.\n"
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "\n"
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      After splitting, each individual line will be trimmed of\n"
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      whitespace on both ends.\n"
170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "\n"
171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "  \"scope\"\n"
172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "      Execute the block as GN code and return a scope with the\n"
173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "      resulting values in it. If the input was:\n"
174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "        a = [ \"hello.cc\", \"world.cc\" ]\n"
175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "        b = 26\n"
176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "      and you read the result into a variable named \"val\", then you\n"
177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "      could access contents the \".\" operator on \"val\":\n"
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "        sources = val.a\n"
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "        some_count = val.b\n"
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "\n"
181c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "  \"string\"\n"
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "      Return the file contents into a single string.\n"
183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "\n"
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "  \"value\"\n"
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      Parse the input as if it was a literal rvalue in a buildfile.\n"
186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      Examples of typical program output using this mode:\n"
187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "        [ \"foo\", \"bar\" ]     (result will be a list)\n"
188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      or\n"
189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "        \"foo bar\"            (result will be a string)\n"
190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      or\n"
191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "        5                    (result will be an integer)\n"
192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "\n"
193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      Note that if the input is empty, the result will be a null value\n"
194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "      which will produce an error if assigned to a variable.\n"
195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    "\n"
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  \"trim ...\"\n"
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      Prefixing any of the other transformations with the word \"trim\"\n"
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      will result in whitespace being trimmed from the beginning and end\n"
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      of the result before processing.\n"
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "\n"
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      Examples: \"trim string\" or \"trim list lines\"\n"
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "\n"
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      Note that \"trim value\" is useless because the value parser skips\n"
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      whitespace anyway.\n";
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
206c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochValue ConvertInputToValue(const Settings* settings,
207c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          const std::string& input,
208d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          const ParseNode* origin,
209d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          const Value& input_conversion_value,
210d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          Err* err) {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (input_conversion_value.type() == Value::NONE)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return Value();  // Allow null inputs to mean discard the result.
213d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!input_conversion_value.VerifyTypeIs(Value::STRING, err))
214d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return DoConvertInputToValue(settings, input, origin, input_conversion_value,
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               input_conversion_value.string_value(), err);
217d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
218