| // 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)); | |
| } |