diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2024-02-20 15:40:02 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2024-02-20 16:08:14 +0200 |
commit | 0efae7db7b5870246f1e294a5fedaa69e9c90331 (patch) | |
tree | fd53e7b4b416a63c8e082dead3ef1d6496fa872a /libbuild2/variable.cxx | |
parent | 6ff1cf35f78a24d52603d84eac9349b3d4670c6c (diff) |
Add json_map and json_set buildfile value types
These expose the std::map<json_value,json_value> and std::set<json_value>
types to buildfiles.
New functions:
$size(<json-set>)
$size(<json-map>)
$keys(<json-map>)
Note that the $keys() function returns the list of map key as a json array.
For example:
m = [json_map] 2@([json] a@1 b@2) 1@([json] 1 2)
s = [json_set] ([json] x@1 y@2) ([json] a@1 b@2)
print ($m[2][b]) # 2
print ($s[([json] y@2 x@1)]) # true
Diffstat (limited to 'libbuild2/variable.cxx')
-rw-r--r-- | libbuild2/variable.cxx | 90 |
1 files changed, 58 insertions, 32 deletions
diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 4a08b4d..ab65237 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -1635,6 +1635,17 @@ namespace build2 } json_value value_traits<json_value>:: + convert (name&& l, name* r) + { + // Here we expect either a simple value or a serialized representation. + // + if (r != nullptr) + throw invalid_argument ("pair in json element value"); + + return to_json_value (l, "json element"); + } + + json_value value_traits<json_value>:: convert (names&& ns) { size_t n (ns.size ()); @@ -1781,56 +1792,36 @@ namespace build2 } } - static names_view - json_reverse (const value& x, names& ns, bool) + name value_traits<json_value>:: + reverse (const json_value& v) { - const json_value& v (x.as<json_value> ()); - switch (v.type) { case json_type::null: { - // @@ Hm, it would be nice if this somehow got mapped to [null]/empty - // but still be round-trippable to JSON null. Perhaps via type - // hint? - // - // But won't `print ([json] null)` printing nothing be - // surprising. Also, it's not clear that mapping JSON null to out - // [null] is a good idea since our [null] means "no value" while - // JSON null means "null value". - // - // Maybe the current semantics is the best: we map our [null] and - // empty names to JSON null (naturally) but we always reverse JSON - // null to the JSON "null" literal. Or maybe we could reverse it to - // null but type-hint it that it's a spelling or [null]/empty. - // Quite fuzzy, admittedly. In our model null values decay to empty - // so JSON null decaying to "null" literal is strange. Let's try - // and see how it goes. See also json_subscript_impl() below. + // Return empty to be consistent with other places. // #if 0 - ns.push_back (name ("null")); + return name ("null"); +#else + return name (); #endif - break; } case json_type::boolean: { - ns.push_back (name (v.boolean ? "true" : "false")); - break; + return name (v.boolean ? "true" : "false"); } case json_type::signed_number: { - ns.push_back (value_traits<int64_t>::reverse (v.signed_number)); - break; + return value_traits<int64_t>::reverse (v.signed_number); } case json_type::unsigned_number: { - ns.push_back (value_traits<uint64_t>::reverse (v.unsigned_number)); - break; + return value_traits<uint64_t>::reverse (v.unsigned_number); } case json_type::hexadecimal_number: { - ns.push_back (name (to_string (v.unsigned_number, 16))); - break; + return name (to_string (v.unsigned_number, 16)); } case json_type::string: // @@ -1868,6 +1859,10 @@ namespace build2 } catch (const invalid_json_output& e) { + // Note that while it feels like value_traits::reverse() should + // throw invalid_argument, we don't currently handle it anywhere so + // for now let's just fail. + // // Note: the same diagnostics as in $json.serialize(). // diag_record dr; @@ -1882,11 +1877,38 @@ namespace build2 #else fail << "json serialization requested during bootstrap"; #endif - ns.push_back (name (move (o))); - break; + return name (move (o)); } } + assert (false); + return name (); + } + + static names_view + json_reverse (const value& x, names& ns, bool reduce) + { + const json_value& v (x.as<json_value> ()); + + // @@ Hm, it would be nice if JSON null somehow got mapped to [null]/empty + // but still be round-trippable to JSON null. Perhaps via type hint? + // + // But won't `print ([json] null)` printing nothing be surprising. + // Also, it's not clear that mapping JSON null to out [null] is a good + // idea since our [null] means "no value" while JSON null means "null + // value". + // + // Maybe the current semantics is the best: we map our [null] and empty + // names to JSON null (naturally) but we always reverse JSON null to + // the JSON "null" literal. Or maybe we could reverse it to null but + // type-hint it that it's a spelling or [null]/empty. Quite fuzzy, + // admittedly. In our model null values decay to empty so JSON null + // decaying to "null" literal is strange. Let's try and see how it + // goes. See also json_subscript_impl() below. + // + if (v.type != json_type::null || !reduce) + ns.push_back (value_traits<json_value>::reverse (v)); + return ns; } @@ -3294,11 +3316,15 @@ namespace build2 value_traits<vector<pair<string, optional<bool>>>>; template struct LIBBUILD2_DEFEXPORT value_traits<set<string>>; + template struct LIBBUILD2_DEFEXPORT value_traits<set<json_value>>; template struct LIBBUILD2_DEFEXPORT value_traits<map<string, string>>; template struct LIBBUILD2_DEFEXPORT + value_traits<map<json_value, json_value>>; + + template struct LIBBUILD2_DEFEXPORT value_traits<map<string, optional<string>>>; template struct LIBBUILD2_DEFEXPORT |