diff options
-rw-r--r-- | doc/concepts/expressions.org | 14 | ||||
-rw-r--r-- | src/buildtool/build_engine/expression/evaluator.cpp | 37 |
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) { |