From 03f2024b6ecf9bea7941a521779d18ca1d757a9f Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sun, 19 Apr 2020 01:12:51 +0100 Subject: [PATCH] LibJS: Improve CallExpression::execute()'s error messages --- Libraries/LibJS/AST.cpp | 36 +++++++++++++++++++++++++++--------- Libraries/LibJS/AST.h | 2 ++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 4fec6571283..f384defa264 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -92,17 +92,24 @@ Value CallExpression::execute(Interpreter& interpreter) const ASSERT(!callee.is_empty()); - if (is_new_expression()) { - if (!callee.is_object() - || !callee.as_object().is_function() - || (callee.as_object().is_native_function() - && !static_cast(callee.as_object()).has_constructor())) - return interpreter.throw_exception(String::format("%s is not a constructor", callee.to_string().characters())); + if (!callee.is_object() + || !callee.as_object().is_function() + || (callee.as_object().is_native_function() && !static_cast(callee.as_object()).has_constructor())) { + String error_message; + auto call_type = is_new_expression() ? "constructor" : "function"; + if (m_callee->is_identifier() || m_callee->is_member_expression()) { + String expression_string; + if (m_callee->is_identifier()) + expression_string = static_cast(*m_callee).string(); + else + expression_string = static_cast(*m_callee).to_string_approximation(); + error_message = String::format("%s is not a %s (evaluated from '%s')", callee.to_string().characters(), call_type, expression_string.characters()); + } else { + error_message = String::format("%s is not a %s", callee.to_string().characters(), call_type); + } + return interpreter.throw_exception(error_message); } - if (!callee.is_object() || !callee.as_object().is_function()) - return interpreter.throw_exception(String::format("%s is not a function", callee.to_string().characters())); - auto& function = static_cast(callee.as_object()); Vector arguments; @@ -943,6 +950,17 @@ PropertyName MemberExpression::computed_property_name(Interpreter& interpreter) return PropertyName(index.to_string()); } +String MemberExpression::to_string_approximation() const +{ + String object_string = ""; + if (m_object->is_identifier()) + object_string = static_cast(*m_object).string(); + if (is_computed()) + return String::format("%s[]", object_string.characters()); + ASSERT(m_property->is_identifier()); + return String::format("%s.%s", object_string.characters(), static_cast(*m_property).string().characters()); +} + Value MemberExpression::execute(Interpreter& interpreter) const { auto object_value = m_object->execute(interpreter); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 09835df3ec0..58c1bbe8ca4 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -716,6 +716,8 @@ public: PropertyName computed_property_name(Interpreter&) const; + String to_string_approximation() const; + private: virtual bool is_member_expression() const override { return true; } virtual const char* class_name() const override { return "MemberExpression"; }