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/value_extractors.h"
      6 
      7 #include "tools/gn/build_settings.h"
      8 #include "tools/gn/err.h"
      9 #include "tools/gn/label.h"
     10 #include "tools/gn/source_dir.h"
     11 #include "tools/gn/source_file.h"
     12 #include "tools/gn/target.h"
     13 #include "tools/gn/value.h"
     14 
     15 namespace {
     16 
     17 // Sets the error and returns false on failure.
     18 template<typename T, class Converter>
     19 bool ListValueExtractor(const Value& value,
     20                         std::vector<T>* dest,
     21                         Err* err,
     22                         const Converter& converter) {
     23   if (!value.VerifyTypeIs(Value::LIST, err))
     24     return false;
     25   const std::vector<Value>& input_list = value.list_value();
     26   dest->resize(input_list.size());
     27   for (size_t i = 0; i < input_list.size(); i++) {
     28     if (!converter(input_list[i], &(*dest)[i], err))
     29       return false;
     30   }
     31   return true;
     32 }
     33 
     34 // Like the above version but extracts to a UniqueVector and sets the error if
     35 // there are duplicates.
     36 template<typename T, class Converter>
     37 bool ListValueUniqueExtractor(const Value& value,
     38                               UniqueVector<T>* dest,
     39                               Err* err,
     40                               const Converter& converter) {
     41   if (!value.VerifyTypeIs(Value::LIST, err))
     42     return false;
     43   const std::vector<Value>& input_list = value.list_value();
     44 
     45   for (size_t i = 0; i < input_list.size(); i++) {
     46     T new_one;
     47     if (!converter(input_list[i], &new_one, err))
     48       return false;
     49     if (!dest->push_back(new_one)) {
     50       // Already in the list, throw error.
     51       *err = Err(input_list[i], "Duplicate item in list");
     52       size_t previous_index = dest->IndexOf(new_one);
     53       err->AppendSubErr(Err(input_list[previous_index],
     54                             "This was the previous definition."));
     55       return false;
     56     }
     57   }
     58   return true;
     59 }
     60 
     61 // This extractor rejects files with system-absolute file paths. If we need
     62 // that in the future, we'll have to add some flag to control this.
     63 struct RelativeFileConverter {
     64   RelativeFileConverter(const BuildSettings* build_settings_in,
     65                         const SourceDir& current_dir_in)
     66       : build_settings(build_settings_in),
     67         current_dir(current_dir_in) {
     68   }
     69   bool operator()(const Value& v, SourceFile* out, Err* err) const {
     70     if (!v.VerifyTypeIs(Value::STRING, err))
     71       return false;
     72     *out = current_dir.ResolveRelativeFile(v.string_value(),
     73                                            build_settings->root_path_utf8());
     74     if (out->is_system_absolute()) {
     75       *err = Err(v, "System-absolute file path.",
     76           "You can't list a system-absolute file path here. Please include "
     77           "only files in\nthe source tree. Maybe you meant to begin with two "
     78           "slashes to indicate an\nabsolute path in the source tree?");
     79       return false;
     80     }
     81     return true;
     82   }
     83   const BuildSettings* build_settings;
     84   const SourceDir& current_dir;
     85 };
     86 
     87 struct RelativeDirConverter {
     88   RelativeDirConverter(const BuildSettings* build_settings_in,
     89                        const SourceDir& current_dir_in)
     90       : build_settings(build_settings_in),
     91         current_dir(current_dir_in) {
     92   }
     93   bool operator()(const Value& v, SourceDir* out, Err* err) const {
     94     if (!v.VerifyTypeIs(Value::STRING, err))
     95       return false;
     96     *out = current_dir.ResolveRelativeDir(v.string_value(),
     97                                           build_settings->root_path_utf8());
     98     return true;
     99   }
    100   const BuildSettings* build_settings;
    101   const SourceDir& current_dir;
    102 };
    103 
    104 // Fills in a label.
    105 template<typename T> struct LabelResolver {
    106   LabelResolver(const SourceDir& current_dir_in,
    107                 const Label& current_toolchain_in)
    108       : current_dir(current_dir_in),
    109         current_toolchain(current_toolchain_in) {}
    110   bool operator()(const Value& v, Label* out, Err* err) const {
    111     if (!v.VerifyTypeIs(Value::STRING, err))
    112       return false;
    113     *out = Label::Resolve(current_dir, current_toolchain, v, err);
    114     return !err->has_error();
    115   }
    116   const SourceDir& current_dir;
    117   const Label& current_toolchain;
    118 };
    119 
    120 // Fills the label part of a LabelPtrPair, leaving the pointer null.
    121 template<typename T> struct LabelPtrResolver {
    122   LabelPtrResolver(const SourceDir& current_dir_in,
    123                    const Label& current_toolchain_in)
    124       : current_dir(current_dir_in),
    125         current_toolchain(current_toolchain_in) {}
    126   bool operator()(const Value& v, LabelPtrPair<T>* out, Err* err) const {
    127     if (!v.VerifyTypeIs(Value::STRING, err))
    128       return false;
    129     out->label = Label::Resolve(current_dir, current_toolchain, v, err);
    130     out->origin = v.origin();
    131     return !err->has_error();
    132   }
    133   const SourceDir& current_dir;
    134   const Label& current_toolchain;
    135 };
    136 
    137 }  // namespace
    138 
    139 bool ExtractListOfStringValues(const Value& value,
    140                                std::vector<std::string>* dest,
    141                                Err* err) {
    142   if (!value.VerifyTypeIs(Value::LIST, err))
    143     return false;
    144   const std::vector<Value>& input_list = value.list_value();
    145   dest->reserve(input_list.size());
    146   for (size_t i = 0; i < input_list.size(); i++) {
    147     if (!input_list[i].VerifyTypeIs(Value::STRING, err))
    148       return false;
    149     dest->push_back(input_list[i].string_value());
    150   }
    151   return true;
    152 }
    153 
    154 bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
    155                                 const Value& value,
    156                                 const SourceDir& current_dir,
    157                                 std::vector<SourceFile>* files,
    158                                 Err* err) {
    159   return ListValueExtractor(value, files, err,
    160                             RelativeFileConverter(build_settings, current_dir));
    161 }
    162 
    163 bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
    164                                const Value& value,
    165                                const SourceDir& current_dir,
    166                                std::vector<SourceDir>* dest,
    167                                Err* err) {
    168   return ListValueExtractor(value, dest, err,
    169                             RelativeDirConverter(build_settings, current_dir));
    170 }
    171 
    172 bool ExtractListOfLabels(const Value& value,
    173                          const SourceDir& current_dir,
    174                          const Label& current_toolchain,
    175                          LabelTargetVector* dest,
    176                          Err* err) {
    177   return ListValueExtractor(value, dest, err,
    178                             LabelPtrResolver<Target>(current_dir,
    179                                                      current_toolchain));
    180 }
    181 
    182 bool ExtractListOfUniqueLabels(const Value& value,
    183                                const SourceDir& current_dir,
    184                                const Label& current_toolchain,
    185                                UniqueVector<Label>* dest,
    186                                Err* err) {
    187   return ListValueUniqueExtractor(value, dest, err,
    188                                   LabelResolver<Config>(current_dir,
    189                                                         current_toolchain));
    190 }
    191 
    192 bool ExtractListOfUniqueLabels(const Value& value,
    193                                const SourceDir& current_dir,
    194                                const Label& current_toolchain,
    195                                UniqueVector<LabelConfigPair>* dest,
    196                                Err* err) {
    197   return ListValueUniqueExtractor(value, dest, err,
    198                                   LabelPtrResolver<Config>(current_dir,
    199                                                            current_toolchain));
    200 }
    201 
    202 bool ExtractListOfUniqueLabels(const Value& value,
    203                                const SourceDir& current_dir,
    204                                const Label& current_toolchain,
    205                                UniqueVector<LabelTargetPair>* dest,
    206                                Err* err) {
    207   return ListValueUniqueExtractor(value, dest, err,
    208                                   LabelPtrResolver<Target>(current_dir,
    209                                                            current_toolchain));
    210 }
    211 
    212 bool ExtractRelativeFile(const BuildSettings* build_settings,
    213                          const Value& value,
    214                          const SourceDir& current_dir,
    215                          SourceFile* file,
    216                          Err* err) {
    217   RelativeFileConverter converter(build_settings, current_dir);
    218   return converter(value, file, err);
    219 }
    220