From 0efae7db7b5870246f1e294a5fedaa69e9c90331 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 20 Feb 2024 15:40:02 +0200 Subject: Add json_map and json_set buildfile value types These expose the std::map and std::set types to buildfiles. New functions: $size() $size() $keys() 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 --- libbuild2/parser.cxx | 87 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 33 deletions(-) (limited to 'libbuild2/parser.cxx') diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index bf806be..5572104 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -6066,7 +6066,12 @@ namespace build2 { if (n[4] == '\0') return &value_traits::value_type; if (n == "json_array") return &value_traits::value_type; - if (n == "json_object") return &value_traits::value_type; + if (n == "json_object") + return &value_traits::value_type; + if (n == "json_set") + return &value_traits>::value_type; + if (n == "json_map") + return &value_traits>::value_type; } break; } @@ -6266,6 +6271,8 @@ namespace build2 if (n == "null") { + // @@ Looks like here we assume representationally empty? + // if (rhs && !rhs.empty ()) // Note: null means we had an expansion. fail (l) << "value with null attribute"; @@ -7808,9 +7815,9 @@ namespace build2 // an empty sequence of names rather than a sequence of one empty // name. // - if (!d.empty ()) + if (size_t n = d.size ()) { - if (d.size () != 1) + if (n != 1) { assert (what_expansion != nullptr); concat_diag_multiple (loc, what_expansion); @@ -9079,7 +9086,7 @@ namespace build2 // Untyped concatenation. Note that if RHS is NULL/empty, we still // set the concat flag. // - else if (!result->null && !result->empty ()) + else if (!result->null) { // This can only be an untyped value. // @@ -9087,33 +9094,36 @@ namespace build2 // const names& lv (cast (*result)); - // This should be a simple value or a simple directory. - // - if (lv.size () > 1) - concat_diag_multiple (loc, what); + if (size_t s = lv.size ()) + { + // This should be a simple value or a simple directory. + // + if (s > 1) + concat_diag_multiple (loc, what); - const name& n (lv[0]); + const name& n (lv[0]); - if (n.qualified ()) - fail (loc) << "concatenating " << what << " contains project " - << "name"; + if (n.qualified ()) + fail (loc) << "concatenating " << what << " contains project " + << "name"; - if (n.typed ()) - fail (loc) << "concatenating " << what << " contains target type"; + if (n.typed ()) + fail (loc) << "concatenating " << what << " contains target type"; - if (!n.dir.empty ()) - { - if (!n.value.empty ()) - fail (loc) << "concatenating " << what << " contains " - << "directory"; + if (!n.dir.empty ()) + { + if (!n.value.empty ()) + fail (loc) << "concatenating " << what << " contains " + << "directory"; - // Note that here we cannot assume what's in dir is really a - // path (think s/foo/bar/) so we have to reverse it exactly. - // - concat_data.value += n.dir.representation (); + // Note that here we cannot assume what's in dir is really a + // path (think s/foo/bar/) so we have to reverse it exactly. + // + concat_data.value += n.dir.representation (); + } + else + concat_data.value += n.value; } - else - concat_data.value += n.value; } // The same little hack as in the word case ($empty+foo). @@ -9139,16 +9149,27 @@ namespace build2 // Nothing else to do here if the result is NULL or empty. // - if (result->null || result->empty ()) - continue; - - // @@ Could move if nv is result_data; see untypify(). + // Note that we cannot use value::empty() here since we are + // interested in representationally empty. // - names nv_storage; - names_view nv (reverse (*result, nv_storage, true /* reduce */)); + if (!result->null) + { + // @@ Could move if nv is result_data; see untypify(). + // + // Nuance: we should only be reducing empty simple value to empty + // list if we are not a second half of a pair. + // + bool pair (!ns.empty () && ns.back ().pair); + + names nv_storage; + names_view nv (reverse (*result, nv_storage, !pair /* reduce */)); - count = splice_names ( - loc, nv, move (nv_storage), ns, what, pairn, pp, dp, tp); + if (!nv.empty ()) + { + count = splice_names ( + loc, nv, move (nv_storage), ns, what, pairn, pp, dp, tp); + } + } } continue; -- cgit v1.1