15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "tools/gn/substitution_pattern.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "tools/gn/build_settings.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "tools/gn/err.h"
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "tools/gn/filesystem_utils.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "tools/gn/value.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SubstitutionPattern::Subrange::Subrange()
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : type(SUBSTITUTION_LITERAL) {
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SubstitutionPattern::Subrange::Subrange(SubstitutionType t,
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                        const std::string& l)
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : type(t),
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      literal(l) {
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SubstitutionPattern::Subrange::~Subrange() {
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SubstitutionPattern::SubstitutionPattern() : origin_(NULL) {
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SubstitutionPattern::~SubstitutionPattern() {
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool SubstitutionPattern::Parse(const Value& value, Err* err) {
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!value.VerifyTypeIs(Value::STRING, err))
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return Parse(value.string_value(), value.origin(), err);
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool SubstitutionPattern::Parse(const std::string& str,
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                const ParseNode* origin,
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                Err* err) {
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(ranges_.empty());  // Should only be called once.
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t cur = 0;
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (true) {
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    size_t next = str.find("{{", cur);
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Pick up everything from the previous spot to here as a literal.
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (next == std::string::npos) {
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (cur != str.size())
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ranges_.push_back(Subrange(SUBSTITUTION_LITERAL, str.substr(cur)));
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else if (next > cur) {
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ranges_.push_back(
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          Subrange(SUBSTITUTION_LITERAL, str.substr(cur, next - cur)));
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Find which specific pattern this corresponds to.
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool found_match = false;
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for (size_t i = SUBSTITUTION_FIRST_PATTERN;
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         i < SUBSTITUTION_NUM_TYPES; i++) {
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const char* cur_pattern = kSubstitutionNames[i];
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      size_t cur_len = strlen(cur_pattern);
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (str.compare(next, cur_len, cur_pattern) == 0) {
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ranges_.push_back(Subrange(static_cast<SubstitutionType>(i)));
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        cur = next + cur_len;
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        found_match = true;
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Expect all occurrances of {{ to resolve to a pattern.
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!found_match) {
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Could make this error message more friendly if it comes up a lot. But
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // most people will not be writing substitution patterns and the code
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // to exactly indicate the error location is tricky.
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *err = Err(origin, "Unknown substitution pattern",
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          "Found a {{ at offset " +
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          base::SizeTToString(next) +
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          " and did not find a known substitution following it.");
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ranges_.clear();
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  origin_ = origin;
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Fill required types vector.
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SubstitutionBits bits;
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  FillRequiredTypes(&bits);
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bits.FillVector(&required_types_);
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciSubstitutionPattern SubstitutionPattern::MakeForTest(const char* str) {
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Err err;
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SubstitutionPattern pattern;
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(pattern.Parse(str, NULL, &err)) << err.message();
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return pattern;
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string SubstitutionPattern::AsString() const {
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string result;
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < ranges_.size(); i++) {
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (ranges_[i].type == SUBSTITUTION_LITERAL)
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result.append(ranges_[i].literal);
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result.append(kSubstitutionNames[ranges_[i].type]);
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return result;
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void SubstitutionPattern::FillRequiredTypes(SubstitutionBits* bits) const {
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < ranges_.size(); i++) {
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (ranges_[i].type != SUBSTITUTION_LITERAL)
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      bits->used[static_cast<size_t>(ranges_[i].type)] = true;
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool SubstitutionPattern::IsInOutputDir(const BuildSettings* build_settings,
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                        Err* err) const {
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (ranges_.empty()) {
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    *err = Err(origin_, "This is empty but I was expecting an output file.");
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (ranges_[0].type == SUBSTITUTION_LITERAL) {
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If the first thing is a literal, it must start with the output dir.
12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!EnsureStringIsInOutputDir(
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            build_settings->build_dir(),
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            ranges_[0].literal, origin_, err))
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return false;
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  } else {
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Otherwise, the first subrange must be a pattern that expands to
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // something in the output directory.
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!SubstitutionIsInOutputDir(ranges_[0].type)) {
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      *err = Err(origin_,
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          "File is not inside output directory.",
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          "The given file should be in the output directory. Normally you\n"
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          "would specify\n\"$target_out_dir/foo\" or "
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          "\"{{source_gen_dir}}/foo\".");
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return false;
14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
14603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
148