diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2023-06-09 09:00:56 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2023-06-09 09:00:56 +0200 |
commit | 28b2c999c4d0cf0cbb65eebbd3e0159da61d653a (patch) | |
tree | 325918b51d7358eb78a71e3cf21882f3999c1f22 | |
parent | 1c30f9e9c4fca846f05e881638920a9beb082fd1 (diff) |
Diagnose multiple values in typed concatenation (GH issue #263)
-rw-r--r-- | libbuild2/parser.cxx | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index 6214648..cc20b21 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -6988,9 +6988,35 @@ namespace build2 bool concat_quoted_first (false); name concat_data; + auto concat_diag_multiple = [this] (const location& loc, + const char* what_expansion) + { + diag_record dr (fail (loc)); + + dr << "concatenating " << what_expansion << " contains multiple values"; + + // See if this looks like a subscript without an evaluation context and + // help the user out. + // + if (mode () != lexer_mode::eval) + { + const token& t (peeked ()); // Should be peeked at. + + if (t.type == type::word && + t.qtype == quote_type::unquoted && + t.value[0] == '[') + { + dr << info << "wrap it in (...) evaluation context if this " + << "is value subscript"; + } + } + }; + auto concat_typed = [this, what, &vnull, &vtype, - &concat, &concat_data] (value&& rhs, - const location& loc) + &concat, &concat_data, + &concat_diag_multiple] (value&& rhs, + const location& loc, + const char* what_expansion) { // If we have no LHS yet, then simply copy value/type. // @@ -7007,6 +7033,10 @@ namespace build2 // RHS. // + // Note that if RHS contains multiple values then we expect the result + // to be a single value somehow or, more likely, there to be no + // suitable $builtin.concat() overload. + // a.push_back (move (rhs)); const char* l ((a[0].type != nullptr ? a[0].type->name : "<untyped>")); @@ -7058,7 +7088,12 @@ namespace build2 // if (!d.empty ()) { - assert (d.size () == 1); // Must be a single value. + if (d.size () != 1) + { + assert (what_expansion != nullptr); + concat_diag_multiple (loc, what_expansion); + } + concat_data = move (d[0]); } } @@ -7353,7 +7388,7 @@ namespace build2 // names ns; ns.push_back (name (move (val))); - concat_typed (value (move (ns)), get_location (t)); + concat_typed (value (move (ns)), get_location (t), nullptr); } else { @@ -8296,7 +8331,7 @@ namespace build2 if (result != &result_data) // Same reason as above. result = &(result_data = *result); - concat_typed (move (result_data), loc); + concat_typed (move (result_data), loc, what); } // // Untyped concatenation. Note that if RHS is NULL/empty, we still @@ -8313,27 +8348,7 @@ namespace build2 // This should be a simple value or a simple directory. // if (lv.size () > 1) - { - diag_record dr (fail (loc)); - - dr << "concatenating " << what << " contains multiple values"; - - // See if this looks like a subscript without an evaluation - // context and help the user out. - // - if (mode () != lexer_mode::eval) - { - const token& t (peeked ()); // Should be peeked at. - - if (t.type == type::word && - t.qtype == quote_type::unquoted && - t.value[0] == '[') - { - dr << info << "wrap it in (...) evaluation context if this " - << "is value subscript"; - } - } - } + concat_diag_multiple (loc, what); const name& n (lv[0]); |