summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/concepts/expressions.org14
-rw-r--r--src/buildtool/build_engine/expression/evaluator.cpp37
2 files changed, 43 insertions, 8 deletions
diff --git a/doc/concepts/expressions.org b/doc/concepts/expressions.org
index 5b7e2f2c..2dff612a 100644
--- a/doc/concepts/expressions.org
+++ b/doc/concepts/expressions.org
@@ -121,7 +121,8 @@ expression.
****** Sequential case distinction on arbitrary values: ~"case*"~
If the key ~"case"~ is present, it has to be a list of pairs. In this
-case, the key ~"expr"~ is evaluated. The result of that evaluation
+case, the key ~"expr"~ is evaluated. It is an error if that evaluates
+to a name-containg value. The result of that evaluation
is sequentially compared to the evaluation of the first components
of the ~"case"~ list until an equal value is found. In this case,
the evalaution of the second component of the pair is the value of
@@ -188,7 +189,8 @@ those) argument(s) to obtain the final result.
***** Unary functions
-- ~"nub_right"~ The argument has to be a list. The result is the
+- ~"nub_right"~ The argument has to be a list. It is an error if that list
+ contains (directly or indirectly) a name. The result is the
input list, except that for all duplicate values, all but the
rightmost occurence is removed.
@@ -268,11 +270,14 @@ those) argument(s) to obtain the final result.
conflicts can also occur in non-flat staging if two keys are
different as strings, but name the same path (like ~"foo.txt"~
and ~"./foo.txt"~), and are assigned different values.
+ It also is an error if the values for keys in conflicting positions
+ are name-containing.
***** Binary functions
- ~"=="~ The result is ~true~ is the arguments are equal, ~false~
- otherwise.
+ otherwise. It is an error if one of the arguments are name-containing
+ values.
- ~"concat_target_name"~ This function is only present to simplify
transitions from some other build systems and normally not used
@@ -325,4 +330,5 @@ that evaluation included in the error message presented to the user.
- ~"disjoint_map_union"~ Like ~"map_union"~ but it is an error,
if two (or more) maps contain the same key, but map it to
- different values.
+ different values. It is also an error if the argument is a
+ name-containing value.
diff --git a/src/buildtool/build_engine/expression/evaluator.cpp b/src/buildtool/build_engine/expression/evaluator.cpp
index ed6c6014..9789c519 100644
--- a/src/buildtool/build_engine/expression/evaluator.cpp
+++ b/src/buildtool/build_engine/expression/evaluator.cpp
@@ -158,6 +158,13 @@ auto NubRight(ExpressionPtr const& expr) -> ExpressionPtr {
throw Evaluator::EvaluationError{fmt::format(
"nub_right expects list but instead got: {}.", expr->ToString())};
}
+ if (not expr->IsCacheable()) {
+ throw Evaluator::EvaluationError{
+ fmt::format("Implicit comparison by passing name-containing value "
+ "to nub_right: {}",
+ expr->ToString())};
+ }
+ // short-cut evaluation for efficiency
if (expr->List().empty()) {
return expr;
}
@@ -456,6 +463,10 @@ auto SeqCaseExpr(SubExprEvaluator&& eval,
throw Evaluator::EvaluationError{"missing expr in case"};
}
auto const& cmp = eval(e->get(), env);
+ if (not cmp->IsCacheable()) {
+ throw Evaluator::EvaluationError{fmt::format(
+ "Comparison of name-containing values: {}", cmp->ToString())};
+ }
for (const auto& pair : cases->get()->List()) {
if (not pair->IsList() or pair->List().size() != 2) {
throw Evaluator::EvaluationError{
@@ -474,8 +485,19 @@ auto SeqCaseExpr(SubExprEvaluator&& eval,
auto EqualExpr(SubExprEvaluator&& eval,
ExpressionPtr const& expr,
Configuration const& env) -> ExpressionPtr {
- return ExpressionPtr{EvalArgument(expr, "$1", eval, env) ==
- EvalArgument(expr, "$2", eval, env)};
+ auto a = EvalArgument(expr, "$1", eval, env);
+ if (not a->IsCacheable()) {
+ throw Evaluator::EvaluationError{fmt::format(
+ "Comparison of name-containing values; first argument is {}",
+ a->ToString())};
+ }
+ auto b = EvalArgument(expr, "$2", eval, env);
+ if (not b->IsCacheable()) {
+ throw Evaluator::EvaluationError{fmt::format(
+ "Comparison of name-containing values; second argument is {}",
+ b->ToString())};
+ }
+ return ExpressionPtr{a == b};
}
auto ChangeEndingExpr(SubExprEvaluator&& eval,
@@ -574,7 +596,8 @@ auto ToSubdirExpr(SubExprEvaluator&& eval,
for (auto const& el : d->Map()) {
std::filesystem::path k{el.first};
auto new_key = ToNormalPath(subdir / k.filename()).string();
- if (result.contains(new_key) && !(result[new_key] == el.second)) {
+ if (result.contains(new_key) &&
+ !((result[new_key] == el.second) && el.second->IsCacheable())) {
// Check if the user specifed an error message for that case,
// otherwise just generate a generic error message.
auto msg_expr = expr->Map().Find("msg");
@@ -607,7 +630,8 @@ auto ToSubdirExpr(SubExprEvaluator&& eval,
for (auto const& el : d->Map()) {
auto new_key = ToNormalPath(subdir / el.first).string();
if (auto it = result.find(new_key);
- it != result.end() && !(it->second == el.second)) {
+ it != result.end() &&
+ (!((it->second == el.second) && el.second->IsCacheable()))) {
auto msg_expr = expr->Map().Find("msg");
if (not msg_expr) {
throw Evaluator::EvaluationError{fmt::format(
@@ -785,6 +809,11 @@ auto DisjointUnionExpr(SubExprEvaluator&& eval,
ExpressionPtr const& expr,
Configuration const& env) -> ExpressionPtr {
auto argument = EvalArgument(expr, "$1", eval, env);
+ if (not argument->IsCacheable()) {
+ throw Evaluator::EvaluationError{
+ fmt::format("Argument to disjoint_map_union is name-containing: {}",
+ argument->ToString())};
+ }
try {
return Union</*kDisjoint=*/true>(argument);
} catch (std::exception const& ex) {