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