From 218a739b33325c5dd6baa5cf6291dad849ad2441 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 14 Dec 2022 08:03:32 +0200 Subject: Handle NULL values in $string() and $concat() functions This is relied upon by the parser to provide conversion/concatenation semantics consistent with untyped values. Note that we handle NULL values only for types that have empty representation. --- libbuild2/functions-bool.cxx | 3 +++ libbuild2/functions-integer.cxx | 3 +++ libbuild2/functions-name.cxx | 13 ++++++++++- libbuild2/functions-path.cxx | 13 ++++++++++- libbuild2/functions-project-name.cxx | 13 ++++++++++- libbuild2/functions-string.cxx | 34 ++++++++++++++++----------- libbuild2/functions-target-triplet.cxx | 19 +++++++++++++-- libbuild2/parser.cxx | 3 ++- tests/value/concat.testscript | 42 ++++++++++++++++++++++++++++++++++ 9 files changed, 124 insertions(+), 19 deletions(-) diff --git a/libbuild2/functions-bool.cxx b/libbuild2/functions-bool.cxx index 1ae89d2..1d9c72f 100644 --- a/libbuild2/functions-bool.cxx +++ b/libbuild2/functions-bool.cxx @@ -15,6 +15,9 @@ namespace build2 // $string() // + // Note that we don't handle NULL values for this type since it has no + // empty representation. + // f["string"] += [](bool b) {return b ? "true" : "false";}; } } diff --git a/libbuild2/functions-integer.cxx b/libbuild2/functions-integer.cxx index ddfc250..a634ae9 100644 --- a/libbuild2/functions-integer.cxx +++ b/libbuild2/functions-integer.cxx @@ -69,6 +69,9 @@ namespace build2 // $string() // $string([, [, ]]) // + // Note that we don't handle NULL values for these type since they have no + // empty representation. + // f["string"] += [](int64_t i) {return to_string (i);}; f["string"] += [](uint64_t i, optional base, optional width) diff --git a/libbuild2/functions-name.cxx b/libbuild2/functions-name.cxx index 9011cc0..84608d4 100644 --- a/libbuild2/functions-name.cxx +++ b/libbuild2/functions-name.cxx @@ -142,7 +142,13 @@ namespace build2 // function_family fn (m, "name"); - fn["string"] += [](name n) {return to_string (n);}; + // Note that we must handle NULL values (relied upon by the parser + // to provide conversion semantics consistent with untyped values). + // + fn["string"] += [](name* n) + { + return n != nullptr ? to_string (move (*n)) : string (); + }; fn["name"] += [](const scope* s, name n) { @@ -438,6 +444,11 @@ namespace build2 // function_family fb (m, "builtin"); + // Note that while we should normally handle NULL values (relied upon by + // the parser to provide concatenation semantics consistent with untyped + // values), the result will unlikely be what the user expected. So for now + // we keep it a bit tighter. + // fb[".concat"] += [](dir_path d, name n) { d /= n.dir; diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx index 0c9b57f..b5511ad 100644 --- a/libbuild2/functions-path.cxx +++ b/libbuild2/functions-path.cxx @@ -161,7 +161,13 @@ namespace build2 // string // - f["string"] += [](path p) {return move (p).string ();}; + // Note that we must handle NULL values (relied upon by the parser + // to provide conversion semantics consistent with untyped values). + // + f["string"] += [](path* p) + { + return p != nullptr ? move (*p).string () : string (); + }; f["string"] += [](paths v) { @@ -694,6 +700,11 @@ namespace build2 // function_family b (m, "builtin", &path_thunk); + // Note that while we should normally handle NULL values (relied upon by + // the parser to provide concatenation semantics consistent with untyped + // values), the result will unlikely be what the user expected, especially + // if the NULL value is on the LHS. So for now we keep it a bit tighter. + // b[".concat"] += &concat_path_string; b[".concat"] += &concat_dir_path_string; diff --git a/libbuild2/functions-project-name.cxx b/libbuild2/functions-project-name.cxx index 145e62c..4a8394d 100644 --- a/libbuild2/functions-project-name.cxx +++ b/libbuild2/functions-project-name.cxx @@ -13,7 +13,13 @@ namespace build2 { function_family f (m, "project_name"); - f["string"] += [](project_name p) {return move (p).string ();}; + // Note that we must handle NULL values (relied upon by the parser + // to provide conversion semantics consistent with untyped values). + // + f["string"] += [](project_name* p) + { + return p != nullptr ? move (*p).string () : string (); + }; f["base"] += [](project_name p, optional ext) { @@ -32,6 +38,11 @@ namespace build2 // function_family b (m, "builtin"); + // Note that while we should normally handle NULL values (relied upon by + // the parser to provide concatenation semantics consistent with untyped + // values), the result will unlikely be what the user expected. So for now + // we keep it a bit tighter. + // b[".concat"] += [](project_name n, string s) { string r (move (n).string ()); diff --git a/libbuild2/functions-string.cxx b/libbuild2/functions-string.cxx index f5d7cb1..06fe89d 100644 --- a/libbuild2/functions-string.cxx +++ b/libbuild2/functions-string.cxx @@ -39,12 +39,13 @@ namespace build2 { function_family f (m, "string"); - f["string"] += [](string s) {return s;}; - - // @@ Shouldn't it concatenate elements into the single string? - // @@ Doesn't seem to be used so far. Can consider removing. + // Note that we must handle NULL values (relied upon by the parser + // to provide conversion semantics consistent with untyped values). // - // f["string"] += [](strings v) {return v;}; + f["string"] += [](string* s) + { + return s != nullptr ? move (*s) : string (); + }; // Compare ASCII strings ignoring case and returning the boolean value. // @@ -195,19 +196,26 @@ namespace build2 // function_family b (m, "builtin"); - b[".concat"] += [](string l, string r) {l += r; return l;}; + // Note that we must handle NULL values (relied upon by the parser to + // provide concatenation semantics consistent with untyped values). + // + b[".concat"] += [](string* l, string* r) + { + return l != nullptr + ? r != nullptr ? move (*l += *r) : move (*l) + : r != nullptr ? move (*r) : string (); + }; - b[".concat"] += [](string l, names ur) + b[".concat"] += [](string* l, names* ur) { - l += convert (move (ur)); - return l; + string r (ur != nullptr ? convert (move (*ur)) : string ()); + return l != nullptr ? move (*l += r) : move (r); }; - b[".concat"] += [](names ul, string r) + b[".concat"] += [](names* ul, string* r) { - string l (convert (move (ul))); - l += r; - return l; + string l (ul != nullptr ? convert (move (*ul)) : string ()); + return r != nullptr ? move (l += *r) : move (l); }; } } diff --git a/libbuild2/functions-target-triplet.cxx b/libbuild2/functions-target-triplet.cxx index 4b0ec02..b89cadf 100644 --- a/libbuild2/functions-target-triplet.cxx +++ b/libbuild2/functions-target-triplet.cxx @@ -13,13 +13,28 @@ namespace build2 { function_family f (m, "target_triplet"); - f["string"] += [](target_triplet t) {return t.string ();}; - f["representation"] += [](target_triplet t) {return t.representation ();}; + // Note that we must handle NULL values (relied upon by the parser + // to provide conversion semantics consistent with untyped values). + // + f["string"] += [](target_triplet* t) + { + return t != nullptr ? t->string () : string (); + }; + + f["representation"] += [](target_triplet t) + { + return t.representation (); + }; // Target triplet-specific overloads from builtins. // function_family b (m, "builtin"); + // Note that while we should normally handle NULL values (relied upon by + // the parser to provide concatenation semantics consistent with untyped + // values), the result will unlikely be what the user expected. So for now + // we keep it a bit tighter. + // b[".concat"] += [](target_triplet l, string sr) {return l.string () + sr;}; b[".concat"] += [](string sl, target_triplet r) {return sl + r.string ();}; diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index dd2944d..812f201 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -7719,7 +7719,8 @@ namespace build2 // then it should not be overloaded for a type). In a quoted // context we use $string() which returns a "canonical // representation" (e.g., a directory path without a trailing - // slash). + // slash). Note: looks like we use typed $concat() now in the + // unquoted context. // if (result->type != nullptr && quoted) { diff --git a/tests/value/concat.testscript b/tests/value/concat.testscript index 97391c4..69ec9fc 100644 --- a/tests/value/concat.testscript +++ b/tests/value/concat.testscript @@ -3,6 +3,48 @@ .include ../common.testscript +: null +: +{ + : untyped + : + $* <>/EOO + x = [null] + + print y "$x x" + print "x $x" y + + print $x"x" + print "x"$x + print $x$x + EOI + y x + x y + x + x + {} + EOO + + : string + : + $* <>/EOO + x = [string,null] + + print y "$x x" + print "x $x" y + + print $x"x" + print "x"$x + print $x$x + EOI + y x + x y + x + x + {} + EOO +} + : dir_path : { -- cgit v1.1