8 #include <boost/assign.hpp>
9 #include <boost/range/adaptor/indexed.hpp>
12 #include <fmt/format.h>
13 #include <nlohmann/json.hpp>
28 template <
class KeywordType>
29 KeywordType ParseKeywordObject(nlohmann::json
const& obj) {
30 assert(obj.is_object());
32 if (!obj.contains(
"name")) {
33 throw std::invalid_argument(
"field 'name' missing");
35 if (!obj[
"name"].is_string()) {
36 throw std::invalid_argument(
"field 'name' must be a string");
38 if (!obj.contains(
"value")) {
39 throw std::invalid_argument(
"field 'value' missing");
42 typename KeywordType::ValueType kw_value;
43 auto name = obj[
"name"].get<std::string>();
44 auto value = obj[
"value"];
45 if (value.is_boolean()) {
46 kw_value = value.get<
bool>();
47 }
else if (value.is_string()) {
48 kw_value = value.get<std::string>();
49 }
else if (value.is_number_float()) {
50 kw_value = value.get<
double>();
51 }
else if (value.is_number_unsigned()) {
52 kw_value = value.get<uint64_t>();
53 }
else if (value.is_number_integer()) {
54 kw_value = value.get<int64_t>();
56 throw std::invalid_argument(fmt::format(
"unsupported type: {}", value.type_name()));
59 std::optional<std::string> kw_comment;
60 if (obj.contains(
"comment")) {
61 auto const& comment = obj[
"comment"];
62 if (!comment.is_string()) {
63 throw std::invalid_argument(fmt::format(
64 "field 'comment' type must be a string, got '{}'", comment.type_name()));
66 kw_comment = comment.get<std::string>();
68 return KeywordType(name, kw_value, kw_comment);
75 auto parsed = nlohmann::json::parse(keywords);
80 using namespace boost::assign;
81 using namespace boost::adaptors;
83 if (!keywords.is_array()) {
84 throw std::invalid_argument(
85 fmt::format(
"root element parsing error: expected array of objects but got '{}'",
86 keywords.type_name()));
89 std::vector<KeywordVariant> parsed_keywords;
90 parsed_keywords.reserve(keywords.size());
92 for (
auto const& index : keywords | indexed(0u)) {
93 auto const& kw_obj = index.value();
95 if (!kw_obj.is_object()) {
96 throw std::invalid_argument(
97 fmt::format(
"keyword [{}]: parsing error, expected array but got {}",
99 keywords.type_name()));
101 if (!kw_obj.contains(
"type")) {
102 throw std::invalid_argument(
103 fmt::format(
"keyword [{}]: parsing error: Field 'type' "
107 if (!kw_obj[
"type"].is_string()) {
108 throw std::invalid_argument(
109 fmt::format(
"keyword [{}]: parsing error: Field 'type' "
114 auto type = kw_obj[
"type"].get<std::string>();
115 if (type ==
"valueKeyword") {
116 parsed_keywords.push_back(ParseKeywordObject<ValueKeyword>(kw_obj));
118 }
else if (type ==
"esoKeyword") {
119 parsed_keywords.push_back(ParseKeywordObject<EsoKeyword>(kw_obj));
122 throw std::invalid_argument(
123 fmt::format(
"unknown keyword type, expected"
124 "one of 'valueKeyword' or 'esoKeyword', but got "
128 }
catch (std::invalid_argument
const& exc) {
129 throw std::invalid_argument(
130 fmt::format(
"keyword [{}]: parsing error: {}", index.index(), exc.what()));
134 return parsed_keywords;