diff options
Diffstat (limited to 'src')
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; |