Skip to content

Improve error message #1577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions jerry-core/ecma/operations/ecma-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
* limitations under the License.
*/

#include <stdarg.h>
#include "ecma-builtins.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
Expand Down Expand Up @@ -156,6 +158,95 @@ ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */
return ecma_make_error_obj_value (error_obj_p);
} /* ecma_raise_standard_error */

#ifdef JERRY_ENABLE_ERROR_MESSAGES

/**
* Raise a standard ecma-error with the given format string and arguments.
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< error type */
const char *format, /**< format string */
...) /**< ecma-values */
{
JERRY_ASSERT (format != NULL);

ecma_string_t *error_msg_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
ecma_string_t *string1_p;
ecma_string_t *string2_p;

const char *start_p = format;
const char *end_p = format;

va_list args;

va_start (args, format);

while (*end_p)
{
if (*end_p == '%')
{
/* Concat template string. */
if (end_p > start_p)
{
string1_p = error_msg_p;
string2_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) start_p,
(lit_utf8_size_t) (end_p - start_p));
error_msg_p = ecma_concat_ecma_strings (string1_p, string2_p);
ecma_deref_ecma_string (string1_p);
ecma_deref_ecma_string (string2_p);
}

/* Convert an argument to string without side effects. */
ecma_string_t *arg_string_p;
const ecma_value_t arg_val = va_arg (args, ecma_value_t);
if (unlikely (ecma_is_value_object (arg_val)))
{
ecma_object_t *arg_object_p = ecma_get_object_from_value (arg_val);
lit_magic_string_id_t class_name = ecma_object_get_class_name (arg_object_p);
arg_string_p = ecma_get_magic_string (class_name);
}
else
{
jerry_value_t str_val = ecma_op_to_string (arg_val);
arg_string_p = ecma_get_string_from_value (str_val);
}

/* Concat argument. */
string1_p = error_msg_p;
string2_p = arg_string_p;
error_msg_p = ecma_concat_ecma_strings (string1_p, string2_p);
ecma_deref_ecma_string (string1_p);
ecma_deref_ecma_string (string2_p);

start_p = end_p + 1;
}

end_p++;
}

va_end (args);

/* Concat reset of template string. */
if (start_p < end_p)
{
string1_p = error_msg_p;
string2_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) start_p,
(lit_utf8_size_t) (end_p - start_p));
error_msg_p = ecma_concat_ecma_strings (string1_p, string2_p);
ecma_deref_ecma_string (string1_p);
ecma_deref_ecma_string (string2_p);
}

ecma_object_t *error_obj_p = ecma_new_standard_error_with_message (error_type, error_msg_p);
ecma_deref_ecma_string (error_msg_p);
return ecma_make_error_obj_value (error_obj_p);
} /* ecma_raise_standard_error_with_format */

#endif /* JERRY_ENABLE_ERROR_MESSAGES */

/**
* Raise a common error with the given message.
*
Expand Down
3 changes: 3 additions & 0 deletions jerry-core/ecma/operations/ecma-exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ typedef enum
ecma_object_t *ecma_new_standard_error (ecma_standard_error_t error_type);
ecma_object_t *ecma_new_standard_error_with_message (ecma_standard_error_t error_type, ecma_string_t *message_string_p);
ecma_value_t ecma_raise_standard_error (ecma_standard_error_t error_type, const lit_utf8_byte_t *msg_p);
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, const char *msg_p, ...);
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
ecma_value_t ecma_raise_common_error (const char *msg_p);
ecma_value_t ecma_raise_eval_error (const char *msg_p);
ecma_value_t ecma_raise_range_error (const char *msg_p);
Expand Down
20 changes: 18 additions & 2 deletions jerry-core/ecma/operations/ecma-get-put-value.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,15 @@ ecma_op_get_value_lex_env_base (ecma_object_t *ref_base_lex_env_p, /**< referenc
/* 3. */
if (unlikely (is_unresolvable_reference))
{
return ecma_raise_reference_error (ECMA_ERR_MSG ("Cannot resolve reference."));
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t var_name_val = ecma_make_string_value (var_name_string_p);
ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
"% is not defined",
var_name_val);
#else /* !JERRY_ENABLE_ERROR_MESSAGES */
ecma_value_t error_value = ecma_raise_reference_error (NULL);
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
return error_value;
}

/* 5. */
Expand Down Expand Up @@ -149,7 +157,15 @@ ecma_op_put_value_lex_env_base (ecma_object_t *ref_base_lex_env_p, /**< referenc
/* 3.a. */
if (is_strict)
{
return ecma_raise_reference_error (ECMA_ERR_MSG ("Cannot resolve reference."));
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t var_name_val = ecma_make_string_value (var_name_string_p);
ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
"% is not defined",
var_name_val);
#else /* !JERRY_ENABLE_ERROR_MESSAGES */
ecma_value_t error_value = ecma_raise_reference_error (NULL);
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
return error_value;
}
else
{
Expand Down
10 changes: 9 additions & 1 deletion jerry-core/ecma/operations/ecma-reference.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,15 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
}

return ecma_raise_reference_error (ECMA_ERR_MSG ("Cannot resolve reference."));
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t name_val = ecma_make_string_value (name_p);
ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
"% is not defined",
name_val);
#else /* !JERRY_ENABLE_ERROR_MESSAGES */
ecma_value_t error_value = ecma_raise_reference_error (NULL);
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
return error_value;
} /* ecma_op_resolve_reference_value */

/**
Expand Down
68 changes: 17 additions & 51 deletions jerry-core/parser/js/js-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -2345,13 +2345,6 @@ parser_send_breakpoints (parser_context_t *context_p, /**< context */

#endif /* JERRY_DEBUGGER */

#define PARSE_ERR_POS_START " [line: "
#define PARSE_ERR_POS_START_SIZE ((uint32_t) sizeof (PARSE_ERR_POS_START) - 1)
#define PARSE_ERR_POS_MIDDLE ", column: "
#define PARSE_ERR_POS_MIDDLE_SIZE ((uint32_t) sizeof (PARSE_ERR_POS_MIDDLE) - 1)
#define PARSE_ERR_POS_END "]"
#define PARSE_ERR_POS_END_SIZE ((uint32_t) sizeof (PARSE_ERR_POS_END))

#endif /* JERRY_JS_PARSER */

/**
Expand Down Expand Up @@ -2397,50 +2390,23 @@ parser_parse_script (const uint8_t *source_p, /**< source code */
return ecma_make_error_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL));
}
#ifdef JERRY_ENABLE_ERROR_MESSAGES
const char *err_str_p = parser_error_to_string (parser_error.error);
uint32_t err_str_size = lit_zt_utf8_string_size ((const lit_utf8_byte_t *) err_str_p);

char line_str_p[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
uint32_t line_len = ecma_uint32_to_utf8_string (parser_error.line,
(lit_utf8_byte_t *) line_str_p,
ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);

char col_str_p[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
uint32_t col_len = ecma_uint32_to_utf8_string (parser_error.column,
(lit_utf8_byte_t *) col_str_p,
ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);

uint32_t msg_size = (err_str_size
+ line_len
+ col_len
+ PARSE_ERR_POS_START_SIZE
+ PARSE_ERR_POS_MIDDLE_SIZE
+ PARSE_ERR_POS_END_SIZE);

ecma_value_t error_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);

JMEM_DEFINE_LOCAL_ARRAY (error_msg_p, msg_size, char);
char *err_msg_pos_p = error_msg_p;

strncpy (err_msg_pos_p, err_str_p, err_str_size);
err_msg_pos_p += err_str_size;

strncpy (err_msg_pos_p, PARSE_ERR_POS_START, PARSE_ERR_POS_START_SIZE);
err_msg_pos_p += PARSE_ERR_POS_START_SIZE;

strncpy (err_msg_pos_p, line_str_p, line_len);
err_msg_pos_p += line_len;

strncpy (err_msg_pos_p, PARSE_ERR_POS_MIDDLE, PARSE_ERR_POS_MIDDLE_SIZE);
err_msg_pos_p += PARSE_ERR_POS_MIDDLE_SIZE;

strncpy (err_msg_pos_p, col_str_p, col_len);
err_msg_pos_p += col_len;

strncpy (err_msg_pos_p, PARSE_ERR_POS_END, PARSE_ERR_POS_END_SIZE);

error_value = ecma_raise_syntax_error (error_msg_p);
JMEM_FINALIZE_LOCAL_ARRAY (error_msg_p);
const lit_utf8_byte_t *err_bytes_p = (const lit_utf8_byte_t *) parser_error_to_string (parser_error.error);
lit_utf8_size_t err_bytes_size = lit_zt_utf8_string_size (err_bytes_p);

ecma_string_t *err_str_p = ecma_new_ecma_string_from_utf8 (err_bytes_p, err_bytes_size);
ecma_value_t err_str_val = ecma_make_string_value (err_str_p);
ecma_value_t line_str_val = ecma_make_uint32_value (parser_error.line);
ecma_value_t col_str_val = ecma_make_uint32_value (parser_error.column);

ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_SYNTAX,
"% [line: %, column: %]",
err_str_val,
line_str_val,
col_str_val);

ecma_free_value (col_str_val);
ecma_free_value (line_str_val);
ecma_free_value (err_str_val);

return error_value;
#else /* !JERRY_ENABLE_ERROR_MESSAGES */
Expand Down
35 changes: 24 additions & 11 deletions jerry-core/vm/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,15 @@ vm_op_get_value (ecma_value_t object, /**< base object */

if (unlikely (ecma_is_value_undefined (object) || ecma_is_value_null (object)))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Base object cannot be null or undefined."));
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE,
"Cannot read property '%' of %",
property,
object);
#else /* !JERRY_ENABLE_ERROR_MESSAGES */
ecma_value_t error_value = ecma_raise_type_error (NULL);
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
return error_value;
}

ecma_value_t prop_to_string_result = ecma_op_to_string (property);
Expand Down Expand Up @@ -136,8 +144,20 @@ vm_op_set_value (ecma_value_t object, /**< base object */

if (ECMA_IS_VALUE_ERROR (to_object))
{
#ifdef JERRY_ENABLE_ERROR_MESSAGES
ecma_free_value (to_object);

ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE,
"Cannot set property '%' of %",
property,
object);
ecma_free_value (property);

return error_value;
#else /* !JERRY_ENABLE_ERROR_MESSAGES */
ecma_free_value (property);
return to_object;
#endif /* JERRY_ENABLE_ERROR_MESSAGES */
}

object = to_object;
Expand Down Expand Up @@ -1082,16 +1102,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
name_p);

if (ref_base_lex_env_p != NULL)
{
result = ecma_op_get_value_lex_env_base (ref_base_lex_env_p,
name_p,
is_strict);
}
else
{
result = ecma_raise_reference_error (ECMA_ERR_MSG ("Cannot resolve reference."));
}
result = ecma_op_get_value_lex_env_base (ref_base_lex_env_p,
name_p,
is_strict);

if (ECMA_IS_VALUE_ERROR (result))
{
Expand Down