| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "tools/gn/value_extractors.h" | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include "tools/gn/build_settings.h" | 
 | #include "tools/gn/err.h" | 
 | #include "tools/gn/label.h" | 
 | #include "tools/gn/source_dir.h" | 
 | #include "tools/gn/source_file.h" | 
 | #include "tools/gn/target.h" | 
 | #include "tools/gn/value.h" | 
 |  | 
 | namespace { | 
 |  | 
 | // Sets the error and returns false on failure. | 
 | template<typename T, class Converter> | 
 | bool ListValueExtractor(const Value& value, | 
 |                         std::vector<T>* dest, | 
 |                         Err* err, | 
 |                         const Converter& converter) { | 
 |   if (!value.VerifyTypeIs(Value::LIST, err)) | 
 |     return false; | 
 |   const std::vector<Value>& input_list = value.list_value(); | 
 |   dest->resize(input_list.size()); | 
 |   for (size_t i = 0; i < input_list.size(); i++) { | 
 |     if (!converter(input_list[i], &(*dest)[i], err)) | 
 |       return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | // Like the above version but extracts to a UniqueVector and sets the error if | 
 | // there are duplicates. | 
 | template<typename T, class Converter> | 
 | bool ListValueUniqueExtractor(const Value& value, | 
 |                               UniqueVector<T>* dest, | 
 |                               Err* err, | 
 |                               const Converter& converter) { | 
 |   if (!value.VerifyTypeIs(Value::LIST, err)) | 
 |     return false; | 
 |   const std::vector<Value>& input_list = value.list_value(); | 
 |  | 
 |   for (const auto& item : input_list) { | 
 |     T new_one; | 
 |     if (!converter(item, &new_one, err)) | 
 |       return false; | 
 |     if (!dest->push_back(new_one)) { | 
 |       // Already in the list, throw error. | 
 |       *err = Err(item, "Duplicate item in list"); | 
 |       size_t previous_index = dest->IndexOf(new_one); | 
 |       err->AppendSubErr(Err(input_list[previous_index], | 
 |                             "This was the previous definition.")); | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | struct RelativeFileConverter { | 
 |   RelativeFileConverter(const BuildSettings* build_settings_in, | 
 |                         const SourceDir& current_dir_in) | 
 |       : build_settings(build_settings_in), | 
 |         current_dir(current_dir_in) { | 
 |   } | 
 |   bool operator()(const Value& v, SourceFile* out, Err* err) const { | 
 |     *out = current_dir.ResolveRelativeFile(v, err, | 
 |                                            build_settings->root_path_utf8()); | 
 |     return !err->has_error(); | 
 |   } | 
 |   const BuildSettings* build_settings; | 
 |   const SourceDir& current_dir; | 
 | }; | 
 |  | 
 | struct LibFileConverter { | 
 |   LibFileConverter(const BuildSettings* build_settings_in, | 
 |                    const SourceDir& current_dir_in) | 
 |       : build_settings(build_settings_in), | 
 |         current_dir(current_dir_in) { | 
 |   } | 
 |   bool operator()(const Value& v, LibFile* out, Err* err) const { | 
 |     if (!v.VerifyTypeIs(Value::STRING, err)) | 
 |       return false; | 
 |     if (v.string_value().find('/') == std::string::npos) { | 
 |       *out = LibFile(v.string_value()); | 
 |     } else { | 
 |       *out = LibFile(current_dir.ResolveRelativeFile( | 
 |           v, err, build_settings->root_path_utf8())); | 
 |     } | 
 |     return !err->has_error(); | 
 |   } | 
 |   const BuildSettings* build_settings; | 
 |   const SourceDir& current_dir; | 
 | }; | 
 |  | 
 | struct RelativeDirConverter { | 
 |   RelativeDirConverter(const BuildSettings* build_settings_in, | 
 |                        const SourceDir& current_dir_in) | 
 |       : build_settings(build_settings_in), | 
 |         current_dir(current_dir_in) { | 
 |   } | 
 |   bool operator()(const Value& v, SourceDir* out, Err* err) const { | 
 |     *out = current_dir.ResolveRelativeDir(v, err, | 
 |                                           build_settings->root_path_utf8()); | 
 |     return true; | 
 |   } | 
 |   const BuildSettings* build_settings; | 
 |   const SourceDir& current_dir; | 
 | }; | 
 |  | 
 | // Fills in a label. | 
 | template<typename T> struct LabelResolver { | 
 |   LabelResolver(const SourceDir& current_dir_in, | 
 |                 const Label& current_toolchain_in) | 
 |       : current_dir(current_dir_in), | 
 |         current_toolchain(current_toolchain_in) {} | 
 |   bool operator()(const Value& v, Label* out, Err* err) const { | 
 |     if (!v.VerifyTypeIs(Value::STRING, err)) | 
 |       return false; | 
 |     *out = Label::Resolve(current_dir, current_toolchain, v, err); | 
 |     return !err->has_error(); | 
 |   } | 
 |   const SourceDir& current_dir; | 
 |   const Label& current_toolchain; | 
 | }; | 
 |  | 
 | // Fills the label part of a LabelPtrPair, leaving the pointer null. | 
 | template<typename T> struct LabelPtrResolver { | 
 |   LabelPtrResolver(const SourceDir& current_dir_in, | 
 |                    const Label& current_toolchain_in) | 
 |       : current_dir(current_dir_in), | 
 |         current_toolchain(current_toolchain_in) {} | 
 |   bool operator()(const Value& v, LabelPtrPair<T>* out, Err* err) const { | 
 |     if (!v.VerifyTypeIs(Value::STRING, err)) | 
 |       return false; | 
 |     out->label = Label::Resolve(current_dir, current_toolchain, v, err); | 
 |     out->origin = v.origin(); | 
 |     return !err->has_error(); | 
 |   } | 
 |   const SourceDir& current_dir; | 
 |   const Label& current_toolchain; | 
 | }; | 
 |  | 
 | struct LabelPatternResolver { | 
 |   LabelPatternResolver(const SourceDir& current_dir_in) | 
 |       : current_dir(current_dir_in) { | 
 |   } | 
 |   bool operator()(const Value& v, LabelPattern* out, Err* err) const { | 
 |     *out = LabelPattern::GetPattern(current_dir, v, err); | 
 |     return !err->has_error(); | 
 |   } | 
 |   const SourceDir& current_dir; | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | bool ExtractListOfStringValues(const Value& value, | 
 |                                std::vector<std::string>* dest, | 
 |                                Err* err) { | 
 |   if (!value.VerifyTypeIs(Value::LIST, err)) | 
 |     return false; | 
 |   const std::vector<Value>& input_list = value.list_value(); | 
 |   dest->reserve(input_list.size()); | 
 |   for (const auto& item : input_list) { | 
 |     if (!item.VerifyTypeIs(Value::STRING, err)) | 
 |       return false; | 
 |     dest->push_back(item.string_value()); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool ExtractListOfRelativeFiles(const BuildSettings* build_settings, | 
 |                                 const Value& value, | 
 |                                 const SourceDir& current_dir, | 
 |                                 std::vector<SourceFile>* files, | 
 |                                 Err* err) { | 
 |   return ListValueExtractor(value, files, err, | 
 |                             RelativeFileConverter(build_settings, current_dir)); | 
 | } | 
 |  | 
 | bool ExtractListOfLibs(const BuildSettings* build_settings, | 
 |                        const Value& value, | 
 |                        const SourceDir& current_dir, | 
 |                        std::vector<LibFile>* libs, | 
 |                        Err* err) { | 
 |   return ListValueExtractor(value, libs, err, | 
 |                             LibFileConverter(build_settings, current_dir)); | 
 | } | 
 |  | 
 | bool ExtractListOfRelativeDirs(const BuildSettings* build_settings, | 
 |                                const Value& value, | 
 |                                const SourceDir& current_dir, | 
 |                                std::vector<SourceDir>* dest, | 
 |                                Err* err) { | 
 |   return ListValueExtractor(value, dest, err, | 
 |                             RelativeDirConverter(build_settings, current_dir)); | 
 | } | 
 |  | 
 | bool ExtractListOfLabels(const Value& value, | 
 |                          const SourceDir& current_dir, | 
 |                          const Label& current_toolchain, | 
 |                          LabelTargetVector* dest, | 
 |                          Err* err) { | 
 |   return ListValueExtractor(value, dest, err, | 
 |                             LabelPtrResolver<Target>(current_dir, | 
 |                                                      current_toolchain)); | 
 | } | 
 |  | 
 | bool ExtractListOfUniqueLabels(const Value& value, | 
 |                                const SourceDir& current_dir, | 
 |                                const Label& current_toolchain, | 
 |                                UniqueVector<Label>* dest, | 
 |                                Err* err) { | 
 |   return ListValueUniqueExtractor(value, dest, err, | 
 |                                   LabelResolver<Config>(current_dir, | 
 |                                                         current_toolchain)); | 
 | } | 
 |  | 
 | bool ExtractListOfUniqueLabels(const Value& value, | 
 |                                const SourceDir& current_dir, | 
 |                                const Label& current_toolchain, | 
 |                                UniqueVector<LabelConfigPair>* dest, | 
 |                                Err* err) { | 
 |   return ListValueUniqueExtractor(value, dest, err, | 
 |                                   LabelPtrResolver<Config>(current_dir, | 
 |                                                            current_toolchain)); | 
 | } | 
 |  | 
 | bool ExtractListOfUniqueLabels(const Value& value, | 
 |                                const SourceDir& current_dir, | 
 |                                const Label& current_toolchain, | 
 |                                UniqueVector<LabelTargetPair>* dest, | 
 |                                Err* err) { | 
 |   return ListValueUniqueExtractor(value, dest, err, | 
 |                                   LabelPtrResolver<Target>(current_dir, | 
 |                                                            current_toolchain)); | 
 | } | 
 |  | 
 | bool ExtractRelativeFile(const BuildSettings* build_settings, | 
 |                          const Value& value, | 
 |                          const SourceDir& current_dir, | 
 |                          SourceFile* file, | 
 |                          Err* err) { | 
 |   RelativeFileConverter converter(build_settings, current_dir); | 
 |   return converter(value, file, err); | 
 | } | 
 |  | 
 | bool ExtractListOfLabelPatterns(const Value& value, | 
 |                                 const SourceDir& current_dir, | 
 |                                 std::vector<LabelPattern>* patterns, | 
 |                                 Err* err) { | 
 |   return ListValueExtractor(value, patterns, err, | 
 |                             LabelPatternResolver(current_dir)); | 
 | } |