summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/build_engine/base_maps/expression_function.hpp6
-rw-r--r--src/buildtool/build_engine/expression/evaluator.cpp96
-rw-r--r--src/buildtool/build_engine/expression/evaluator.hpp25
-rw-r--r--src/buildtool/build_engine/expression/expression_ptr.cpp8
-rw-r--r--src/buildtool/build_engine/expression/expression_ptr.hpp2
5 files changed, 114 insertions, 23 deletions
diff --git a/src/buildtool/build_engine/base_maps/expression_function.hpp b/src/buildtool/build_engine/base_maps/expression_function.hpp
index 41e6ad83..a5235807 100644
--- a/src/buildtool/build_engine/base_maps/expression_function.hpp
+++ b/src/buildtool/build_engine/base_maps/expression_function.hpp
@@ -51,11 +51,13 @@ class ExpressionFunction {
[](std::string const& error) noexcept -> void {
Logger::Log(LogLevel::Error, error);
},
+ std::function<std::string(ExpressionPtr)> annotate_object =
+ [](auto const& /*unused*/) { return std::string{}; },
std::function<void(void)> const& note_user_context =
[]() noexcept -> void {}) const noexcept -> ExpressionPtr {
try { // try-catch to silence clang-tidy's bugprone-exception-escape,
// only imports_caller can throw but it is not called here.
- auto imports_caller = [this, &functions](
+ auto imports_caller = [this, &functions, &annotate_object](
SubExprEvaluator&& /*eval*/,
ExpressionPtr const& expr,
Configuration const& env) {
@@ -69,6 +71,7 @@ class ExpressionFunction {
env,
functions,
[&ss](auto const& msg) { ss << msg; },
+ annotate_object,
[&user_context]() { user_context = true; }
);
@@ -94,6 +97,7 @@ class ExpressionFunction {
FunctionMap::MakePtr(
functions, "CALL_EXPRESSION", imports_caller),
logger,
+ annotate_object,
note_user_context);
} catch (...) {
EnsuresAudit(false); // ensure that the try-block never throws
diff --git a/src/buildtool/build_engine/expression/evaluator.cpp b/src/buildtool/build_engine/expression/evaluator.cpp
index 34e0873b..b642eeec 100644
--- a/src/buildtool/build_engine/expression/evaluator.cpp
+++ b/src/buildtool/build_engine/expression/evaluator.cpp
@@ -361,8 +361,13 @@ auto Union(Expression::list_t const& dicts, size_t from, size_t to)
fmt::format("Map union not essentially disjoint as claimed, "
"duplicate key {}; conflicting values:\n- {}\n- {}",
nlohmann::json(dup->get()).dump(),
- left_val->ToString(),
- right_val->ToString())};
+ left_val->ToAbbrevString(
+ Evaluator::GetExpressionLogLimit()),
+ right_val->ToAbbrevString(
+ Evaluator::GetExpressionLogLimit())),
+ false,
+ false,
+ std::vector<ExpressionPtr>{left_val, right_val}};
}
}
return ExpressionPtr{Expression::map_t{left, right}};
@@ -432,12 +437,14 @@ auto UnaryExpr(std::function<ExpressionPtr(ExpressionPtr const&)> const& f)
} catch (Evaluator::EvaluationError const& ex) {
throw Evaluator::EvaluationError::WhileEval(
fmt::format("Having evaluated the argument to {}:",
- argument->ToString()),
+ argument->ToAbbrevString(
+ Evaluator::GetExpressionLogLimit())),
ex);
} catch (std::exception const& ex) {
throw Evaluator::EvaluationError::WhileEvaluating(
fmt::format("Having evaluated the argument to {}:",
- argument->ToString()),
+ argument->ToAbbrevString(
+ Evaluator::GetExpressionLogLimit())),
ex);
}
};
@@ -897,6 +904,20 @@ auto ContextExpr(SubExprEvaluator&& eval,
Configuration const& env) -> ExpressionPtr {
try {
return eval(expr->Get("$1", Expression::kNone), env);
+ } catch (Evaluator::EvaluationError const& ex) {
+ auto msg_expr = expr->Get("msg", map_t{});
+ std::string context{};
+ try {
+ auto msg_val = eval(msg_expr, env);
+ context = msg_val->ToString();
+ } catch (std::exception const&) {
+ context = "[non evaluating term] " + msg_expr->ToString();
+ }
+ std::stringstream ss{};
+ ss << "In Context " << context << std::endl;
+ ss << ex.what();
+ throw Evaluator::EvaluationError(
+ ss.str(), true, true, ex.InvolvedObjects());
} catch (std::exception const& ex) {
auto msg_expr = expr->Get("msg", map_t{});
std::string context{};
@@ -924,12 +945,36 @@ auto DisjointUnionExpr(SubExprEvaluator&& eval,
}
try {
return Union</*kDisjoint=*/true>(argument);
+ } catch (Evaluator::EvaluationError const& ex) {
+ auto msg_expr = expr->Map().Find("msg");
+ if (not msg_expr) {
+ throw Evaluator::EvaluationError::WhileEval(
+ fmt::format("Having evaluated the argument to {}:",
+ argument->ToAbbrevString(
+ Evaluator::GetExpressionLogLimit())),
+ ex);
+ }
+ std::string msg;
+ try {
+ auto msg_val = eval(**msg_expr, env);
+ msg = msg_val->ToString();
+ } catch (std::exception const&) {
+ msg = "[non evaluating term] " + (**msg_expr)->ToString();
+ }
+ std::stringstream ss{};
+ ss << msg << std::endl;
+ ss << "Underlying " << ex.what() << std::endl;
+ ss << "The argument of the union was "
+ << argument->ToAbbrevString(Evaluator::GetExpressionLogLimit());
+ throw Evaluator::EvaluationError(
+ ss.str(), false, true, ex.InvolvedObjects());
} catch (std::exception const& ex) {
auto msg_expr = expr->Map().Find("msg");
if (not msg_expr) {
throw Evaluator::EvaluationError::WhileEvaluating(
fmt::format("Having evaluated the argument to {}:",
- argument->ToString()),
+ argument->ToAbbrevString(
+ Evaluator::GetExpressionLogLimit())),
ex);
}
std::string msg;
@@ -942,7 +987,8 @@ auto DisjointUnionExpr(SubExprEvaluator&& eval,
std::stringstream ss{};
ss << msg << std::endl;
ss << "Reason: " << ex.what() << std::endl;
- ss << "The argument of the union was " << argument->ToString();
+ ss << "The argument of the union was "
+ << argument->ToAbbrevString(Evaluator::GetExpressionLogLimit());
throw Evaluator::EvaluationError(ss.str(), false, true);
}
}
@@ -1021,23 +1067,31 @@ auto const kBuiltInFunctions =
{"env", EnvExpr},
{"concat_target_name", ConcatTargetNameExpr}});
-} // namespace
-
-auto Evaluator::EvaluationError::WhileEvaluating(ExpressionPtr const& expr,
- Configuration const& env,
- std::exception const& ex)
- -> Evaluator::EvaluationError {
+auto ExtendedErrorMessage(ExpressionPtr const& expr,
+ Configuration const& env,
+ std::exception const& ex) -> std::string {
std::stringstream ss{};
ss << "* ";
if (expr->IsMap() and expr->Map().contains("type") and
expr["type"]->IsString()) {
ss << expr["type"]->ToString() << "-expression ";
}
- ss << expr->ToAbbrevString(Config().expression_log_limit) << std::endl;
+ ss << expr->ToAbbrevString(Evaluator::GetExpressionLogLimit()) << std::endl;
ss << " environment " << std::endl;
- ss << env.Enumerate(" - ", Config().expression_log_limit) << std::endl;
+ ss << env.Enumerate(" - ", Evaluator::GetExpressionLogLimit())
+ << std::endl;
ss << ex.what();
- return EvaluationError{ss.str(), true /* while_eval */};
+ return ss.str();
+}
+
+} // namespace
+
+auto Evaluator::EvaluationError::WhileEvaluating(ExpressionPtr const& expr,
+ Configuration const& env,
+ std::exception const& ex)
+ -> Evaluator::EvaluationError {
+ return EvaluationError{ExtendedErrorMessage(expr, env, ex),
+ true /* while_eval */};
}
auto Evaluator::EvaluationError::WhileEval(ExpressionPtr const& expr,
@@ -1047,7 +1101,8 @@ auto Evaluator::EvaluationError::WhileEval(ExpressionPtr const& expr,
if (ex.UserContext()) {
return ex;
}
- return Evaluator::EvaluationError::WhileEvaluating(expr, env, ex);
+ return EvaluationError{
+ ExtendedErrorMessage(expr, env, ex), true, false, ex.InvolvedObjects()};
}
auto Evaluator::EvaluationError::WhileEvaluating(const std::string& where,
@@ -1065,7 +1120,10 @@ auto Evaluator::EvaluationError::WhileEval(const std::string& where,
if (ex.UserContext()) {
return ex;
}
- return Evaluator::EvaluationError::WhileEvaluating(where, ex);
+ std::stringstream ss{};
+ ss << where << std::endl;
+ ss << ex.what();
+ return EvaluationError{ss.str(), true, false, ex.InvolvedObjects()};
}
auto Evaluator::EvaluateExpression(
@@ -1073,6 +1131,7 @@ auto Evaluator::EvaluateExpression(
Configuration const& env,
FunctionMapPtr const& provider_functions,
std::function<void(std::string const&)> const& logger,
+ std::function<std::string(ExpressionPtr)> const& annotate_object,
std::function<void(void)> const& note_user_context) noexcept
-> ExpressionPtr {
std::stringstream ss{};
@@ -1096,6 +1155,9 @@ auto Evaluator::EvaluateExpression(
}
}
ss << ex.what();
+ for (auto const& object : ex.InvolvedObjects()) {
+ ss << annotate_object(object);
+ }
} catch (std::exception const& ex) {
ss << ex.what();
}
diff --git a/src/buildtool/build_engine/expression/evaluator.hpp b/src/buildtool/build_engine/expression/evaluator.hpp
index efcbeaca..598b36d4 100644
--- a/src/buildtool/build_engine/expression/evaluator.hpp
+++ b/src/buildtool/build_engine/expression/evaluator.hpp
@@ -18,6 +18,8 @@
#include <cstddef>
#include <exception>
#include <string>
+#include <utility>
+#include <vector>
#include "src/buildtool/build_engine/expression/expression.hpp"
#include "src/buildtool/build_engine/expression/function_map.hpp"
@@ -36,17 +38,24 @@ class Evaluator {
Config().expression_log_limit = width;
}
+ static auto GetExpressionLogLimit() -> std::size_t {
+ return Config().expression_log_limit;
+ }
+
class EvaluationError : public std::exception {
public:
explicit EvaluationError(std::string const& msg,
bool while_eval = false,
- bool user_context = false) noexcept
+ bool user_context = false,
+ std::vector<ExpressionPtr> involved_objetcs =
+ std::vector<ExpressionPtr>{}) noexcept
: msg_{(while_eval ? ""
: (user_context ? "UserError: "
: "EvaluationError: ")) +
msg},
while_eval_{while_eval},
- user_context_{user_context} {}
+ user_context_{user_context},
+ involved_objects_{std::move(std::move(involved_objetcs))} {}
[[nodiscard]] auto what() const noexcept -> char const* final {
return msg_.c_str();
}
@@ -57,6 +66,15 @@ class Evaluator {
[[nodiscard]] auto UserContext() const -> bool { return user_context_; }
+ [[nodiscard]] auto InvolvedObjects() const& noexcept
+ -> std::vector<ExpressionPtr> const& {
+ return involved_objects_;
+ }
+
+ [[nodiscard]] auto InvolvedObjects() && -> std::vector<ExpressionPtr> {
+ return involved_objects_;
+ }
+
[[nodiscard]] static auto WhileEvaluating(ExpressionPtr const& expr,
Configuration const& env,
std::exception const& ex)
@@ -79,6 +97,7 @@ class Evaluator {
std::string msg_;
bool while_eval_;
bool user_context_;
+ std::vector<ExpressionPtr> involved_objects_;
};
// Exception-free evaluation of expression
@@ -87,6 +106,8 @@ class Evaluator {
Configuration const& env,
FunctionMapPtr const& provider_functions,
std::function<void(std::string const&)> const& logger,
+ std::function<std::string(ExpressionPtr)> const& annotate_object =
+ [](auto const& /*unused*/) { return std::string{}; },
std::function<void(void)> const& note_user_context = []() {}) noexcept
-> ExpressionPtr;
diff --git a/src/buildtool/build_engine/expression/expression_ptr.cpp b/src/buildtool/build_engine/expression/expression_ptr.cpp
index 368d2816..68b45c6f 100644
--- a/src/buildtool/build_engine/expression/expression_ptr.cpp
+++ b/src/buildtool/build_engine/expression/expression_ptr.cpp
@@ -60,10 +60,12 @@ auto ExpressionPtr::Evaluate(
Configuration const& env,
FunctionMapPtr const& functions,
std::function<void(std::string const&)> const& logger,
- std::function<void(void)> const& note_user_context) const noexcept
- -> ExpressionPtr {
+ std::function<std::string(ExpressionPtr)> const& annotate_object,
+ std::function<void(void)> const& note_user_context
+
+) const noexcept -> ExpressionPtr {
return Evaluator::EvaluateExpression(
- *this, env, functions, logger, note_user_context);
+ *this, env, functions, logger, annotate_object, note_user_context);
}
auto ExpressionPtr::IsCacheable() const noexcept -> bool {
diff --git a/src/buildtool/build_engine/expression/expression_ptr.hpp b/src/buildtool/build_engine/expression/expression_ptr.hpp
index 77b1cfba..f8b9a77f 100644
--- a/src/buildtool/build_engine/expression/expression_ptr.hpp
+++ b/src/buildtool/build_engine/expression/expression_ptr.hpp
@@ -83,6 +83,8 @@ class ExpressionPtr {
[](std::string const& error) noexcept -> void {
Logger::Log(LogLevel::Error, error);
},
+ std::function<std::string(ExpressionPtr)> const& annotate_object =
+ [](auto const& /*unused*/) { return std::string{}; },
std::function<void(void)> const& note_user_context =
[]() noexcept -> void {}) const noexcept -> ExpressionPtr;