From 19b1f25a1209c7af9e73c0e68ba33574a3b4cbb7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 23 Jan 2024 09:22:36 +0200 Subject: Add reverse --- libbuild2/json.cxx | 2 ++ libbuild2/json.hxx | 20 ++++++++++++- libbuild2/parser.cxx | 1 + libbuild2/variable.cxx | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 3 deletions(-) diff --git a/libbuild2/json.cxx b/libbuild2/json.cxx index dfa1a07..53f7ae4 100644 --- a/libbuild2/json.cxx +++ b/libbuild2/json.cxx @@ -181,6 +181,8 @@ namespace build2 container_type c; // For exception safety. while (*p.next () != event::end_object) { + // @@ Override duplicates or fail? + string_type n (p.name ()); json_value v (p); v.name = move (n); diff --git a/libbuild2/json.hxx b/libbuild2/json.hxx index 6fc633c..9a57b8f 100644 --- a/libbuild2/json.hxx +++ b/libbuild2/json.hxx @@ -241,13 +241,31 @@ namespace build2 // names are ignored. // int - compare (const json_value&, bool ignore_name = false) const; + compare (const json_value&, bool ignore_name = false) const; }; // Throws invalid_json_output. // LIBBUILD2_SYMEXPORT void serialize (butl::json::buffer_serializer&, const json_value&); + + inline bool + operator== (const json_value& x, const json_value& y) {return x.compare (y) == 0;} + + inline bool + operator!= (const json_value& x, const json_value& y) {return !(x == y);} + + inline bool + operator< (const json_value& x, const json_value& y) {return x.compare (y) < 0;} + + inline bool + operator<= (const json_value& x, const json_value& y) {return x.compare (y) <= 0;} + + inline bool + operator> (const json_value& x, const json_value& y) {return !(x <= y);} + + inline bool + operator>= (const json_value& x, const json_value& y) {return !(x < y);} } #endif // LIBBUILD2_JSON_HXX diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index b695018..517f058 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -5753,6 +5753,7 @@ namespace build2 n == "dir_paths" ? ptr (value_traits::value_type) : n == "names" ? ptr (value_traits>::value_type) : n == "cmdline" ? ptr (value_traits::value_type) : + n == "json" ? ptr (value_traits::value_type) : nullptr; } diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index c83d55e..efc1eb2 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -1743,9 +1743,81 @@ namespace build2 */ static names_view - json_reverse (const value&, names& storage, bool) + json_reverse (const value& x, names& ns, bool) { - return names_view (storage); // @@ TODO + const json_value& v (x.as ()); + + 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? + // + ns.push_back (name ("null")); + break; + } + case json_type::boolean: + { + ns.push_back (name (v.boolean ? "true" : "false")); + break; + } + case json_type::signed_number: + { + ns.push_back (value_traits::reverse (v.signed_number)); + break; + } + case json_type::unsigned_number: + { + ns.push_back (value_traits::reverse (v.unsigned_number)); + break; + } + case json_type::string: + // @@ Hm, it would be nice if this somehow got mapped to unquoted + // string but still be round-trippable to JSON null. Perhaps via + // type hint? + // + // @@ If not, optimize for case where no escaping/quoting required? + // + case json_type::array: + case json_type::object: + { + // Serialize as JSON output. + // + string o; + +#ifndef BUILD2_BOOTSTRAP + using namespace butl::json; + + try + { + // Disable pretty-printing so that the output is all on the same + // line. While it's not going to be easy to read for larger JSON + // outputs, it will fit better into the existing model where none of + // the value representations use formatting newlines. If a pretty- + // printed representation is required, then the @@ function can be + // used to obtain it. + // + buffer_serializer s (o, 0 /* indentation */); + serialize (s, v); + } + catch (const invalid_json_output& e) + { + // @@ How can we communicate event, offset? But for that to be + // useful we would also need to somehow also dump the value. + // + fail << "invalid json value: " << e; + } +#else + fail << "json serialization requested during bootstrap"; +#endif + ns.push_back (name (move (o))); + break; + } + } + + return ns; } static int -- cgit v1.1