diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index f41a45600..22e6f6aca 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -23,6 +23,9 @@ Possible types of an error: - JERRY_ERROR_TYPE - type error - JERRY_ERROR_URI - URI error +There is also a special value `JERRY_ERROR_NONE` which is not an error type +this value can only be returned by the [jerry_get_error_type](#jerry_get_error_type). + ## jerry_feature_t Possible compile time enabled feature types: @@ -1477,7 +1480,50 @@ jerry_is_feature_enabled (const jerry_feature_t feature); } ``` -# Error flag manipulation functions +# Error manipulation functions + +## jerry_get_error_type + +**Summary** + +Returns the type of the Error object if possible. + +If a non-error object is used as the input for the function the method +will return `JERRY_ERROR_NONE` indicating that the value was not +an Error object. However it is still possible that the value contains +error semantics. To correctly detect if a value have error use the +[jerry_value_has_error_flag](#jerry_value_has_error_flag) method. + +**Prototype** + +```c +jerry_error_t +jerry_get_error_type (const jerry_value_t value); +``` + +- `value` - api value (possible error object) +- return value + - JERRY_ERROR_NONE if the input is not an error object + - one of the [jerry_error_t](#jerry_error_t) value + +**Example** + +```c +{ + jerry_value_t error_obj = jerry_create_error (JERRY_ERROR_RANGE, + (const jerry_char_t *) "error msg"); + jerry_error_t error_type = jerry_get_error_type (error_obj); + + // error_type is now JERRY_ERROR_RANGE. + + jerry_release_value (error_obj); +} +``` + +**See also** + +- [jerry_create_error](#jerry_create_error) +- [jerry_value_has_error_flag](#jerry_value_has_error_flag) ## jerry_value_has_error_flag @@ -2707,6 +2753,11 @@ jerry_create_boolean (bool value); Create new JavaScript error object. +Important! The `error_type` argument *must not be* +`JERRY_ERROR_NONE`. +Creating an error with no error type is not valid. + + **Prototype** ```c diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 0430c5ef9..0fc8e2b8c 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -42,7 +42,8 @@ JERRY_STATIC_ASSERT (sizeof (jerry_value_t) == sizeof (ecma_value_t), size_of_jerry_value_t_must_be_equal_to_size_of_ecma_value_t); -JERRY_STATIC_ASSERT ((int) ECMA_ERROR_COMMON == (int) JERRY_ERROR_COMMON +JERRY_STATIC_ASSERT ((int) ECMA_ERROR_NONE == (int) JERRY_ERROR_NONE + && (int) ECMA_ERROR_COMMON == (int) JERRY_ERROR_COMMON && (int) ECMA_ERROR_EVAL == (int) JERRY_ERROR_EVAL && (int) ECMA_ERROR_RANGE == (int) JERRY_ERROR_RANGE && (int) ECMA_ERROR_REFERENCE == (int) JERRY_ERROR_REFERENCE @@ -918,6 +919,28 @@ jerry_value_t jerry_get_value_without_error_flag (jerry_value_t value) /**< api return jerry_acquire_value (jerry_get_arg_value (value)); } /* jerry_get_value_without_error_flag */ +/** + * Return the type of the Error object if possible. + * + * @return one of the jerry_error_t value as the type of the Error object + * JERRY_ERROR_NONE - if the input value is not an Error object + */ +jerry_error_t +jerry_get_error_type (const jerry_value_t value) /**< api value */ +{ + jerry_value_t object = jerry_get_arg_value (value); + + if (!ecma_is_value_object (object)) + { + return JERRY_ERROR_NONE; + } + + ecma_object_t *object_p = ecma_get_object_from_value (object); + ecma_standard_error_t error_type = ecma_get_error_type (object_p); + + return error_type; +} /* jerry_get_error_type */ + /** * Get boolean from the specified value. * diff --git a/jerry-core/ecma/operations/ecma-exceptions.c b/jerry-core/ecma/operations/ecma-exceptions.c index 49cf0fa38..3e762c7a0 100644 --- a/jerry-core/ecma/operations/ecma-exceptions.c +++ b/jerry-core/ecma/operations/ecma-exceptions.c @@ -30,10 +30,36 @@ * \addtogroup exceptions Exceptions * @{ */ +typedef struct +{ + ecma_standard_error_t error_type; + ecma_builtin_id_t error_prototype_id; +} ecma_error_mapping_t; + +const ecma_error_mapping_t ecma_error_mappings[] = +{ +#define ERROR_ELEMENT(TYPE, ID) { TYPE, ID } + ERROR_ELEMENT (ECMA_ERROR_COMMON, ECMA_BUILTIN_ID_ERROR_PROTOTYPE), + +#ifndef CONFIG_DISABLE_ERROR_BUILTINS + ERROR_ELEMENT (ECMA_ERROR_EVAL, ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_RANGE, ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_REFERENCE, ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_TYPE, ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_URI, ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_SYNTAX, ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE), +#endif /* !CONFIG_DISABLE_ERROR_BUILTINS */ + +#undef ERROR_ELEMENT +}; /** * Standard ecma-error object constructor. * + * Note: + * calling with ECMA_ERROR_NONE does not make sense thus it will + * cause a fault in the system. + * * @return pointer to ecma-object representing specified error * with reference counter set to one. */ @@ -86,6 +112,12 @@ ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error typ prototype_id = ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE; break; } + + case ECMA_ERROR_NONE: + { + JERRY_UNREACHABLE (); + break; + } } #else JERRY_UNUSED (error_type); @@ -105,6 +137,32 @@ ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error typ return new_error_obj_p; } /* ecma_new_standard_error */ +/** + * Return the error type for an Error object. + * + * @return one of the ecma_standard_error_t value + * if it is not an Error object then ECMA_ERROR_NONE will be returned + */ +ecma_standard_error_t +ecma_get_error_type (ecma_object_t *error_object) /**< possible error object */ +{ + ecma_object_t *prototype_p = ecma_get_object_prototype (error_object); + if (prototype_p != NULL) + { + uint8_t builtin_id = ecma_get_object_builtin_id (prototype_p); + + for (uint8_t idx = 0; idx < sizeof (ecma_error_mappings) / sizeof (ecma_error_mappings[0]); idx++) + { + if (ecma_error_mappings[idx].error_prototype_id == builtin_id) + { + return ecma_error_mappings[idx].error_type; + } + } + } + + return ECMA_ERROR_NONE; +} /* ecma_get_error_type */ + /** * Standard ecma-error object constructor. * diff --git a/jerry-core/ecma/operations/ecma-exceptions.h b/jerry-core/ecma/operations/ecma-exceptions.h index 7decda232..c11c53a69 100644 --- a/jerry-core/ecma/operations/ecma-exceptions.h +++ b/jerry-core/ecma/operations/ecma-exceptions.h @@ -39,6 +39,8 @@ */ typedef enum { + ECMA_ERROR_NONE, /**< Not an Error */ + ECMA_ERROR_COMMON, /**< Error */ ECMA_ERROR_EVAL, /**< EvalError */ ECMA_ERROR_RANGE, /**< RangeError */ @@ -48,6 +50,7 @@ typedef enum ECMA_ERROR_URI /**< URIError */ } ecma_standard_error_t; +ecma_standard_error_t ecma_get_error_type (ecma_object_t *error_object); 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); diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index e3d15d747..d4ef229c3 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -64,6 +64,8 @@ typedef enum */ typedef enum { + JERRY_ERROR_NONE = 0, /**< No Error */ + JERRY_ERROR_COMMON, /**< Error */ JERRY_ERROR_EVAL, /**< EvalError */ JERRY_ERROR_RANGE, /**< RangeError */ @@ -299,6 +301,11 @@ void jerry_value_set_error_flag (jerry_value_t *value_p); void jerry_value_set_abort_flag (jerry_value_t *value_p); jerry_value_t jerry_get_value_without_error_flag (jerry_value_t value); +/** + * Error object function(s). + */ +jerry_error_t jerry_get_error_type (const jerry_value_t value); + /** * Getter functions of 'jerry_value_t'. */ diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index da69db420..8bc1ead97 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -81,60 +81,6 @@ read_file (const char *file_name, return (const uint32_t *) buffer; } /* read_file */ -/** - * Check whether an error is a SyntaxError or not - * - * @return true - if param is SyntaxError - * false - otherwise - */ -static bool -jerry_value_is_syntax_error (jerry_value_t error_value) /**< error value */ -{ - assert (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)); - - if (!jerry_value_is_object (error_value)) - { - return false; - } - - jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *)"name"); - jerry_value_t error_name = jerry_get_property (error_value, prop_name); - jerry_release_value (prop_name); - - if (jerry_value_has_error_flag (error_name) - || !jerry_value_is_string (error_name)) - { - jerry_release_value (error_name); - return false; - } - - jerry_size_t err_str_size = jerry_get_string_size (error_name); - const char syntax_error_str[] = "SyntaxError"; - - if (err_str_size != strlen (syntax_error_str) - 1) - { - jerry_release_value (error_name); - return false; - } - - jerry_char_t err_str_buf[err_str_size]; - - jerry_size_t sz = jerry_string_to_char_buffer (error_name, err_str_buf, err_str_size); - jerry_release_value (error_name); - - if (sz == 0) - { - return false; - } - - if (!strncmp ((char *) err_str_buf, syntax_error_str, sizeof (syntax_error_str) - 1)) - { - return true; - } - - return false; -} /* jerry_value_is_syntax_error */ - /** * Print error value */ @@ -159,7 +105,8 @@ print_unhandled_exception (jerry_value_t error_value) /**< error value */ assert (sz == err_str_size); err_str_buf[err_str_size] = 0; - if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) && jerry_value_is_syntax_error (error_value)) + if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) + && jerry_get_error_type (error_value) == JERRY_ERROR_SYNTAX) { unsigned int err_line = 0; unsigned int err_col = 0; diff --git a/targets/nuttx-stm32f4/jerry_main.c b/targets/nuttx-stm32f4/jerry_main.c index 4105faba9..c644f5e92 100644 --- a/targets/nuttx-stm32f4/jerry_main.c +++ b/targets/nuttx-stm32f4/jerry_main.c @@ -119,59 +119,6 @@ read_file (const char *file_name, /**< source code */ return (const uint8_t *) buffer; } /* read_file */ -/** - * Check whether an error is a SyntaxError or not - * - * @return true - if param is SyntaxError - * false - otherwise - */ -static bool -jerry_value_is_syntax_error (jerry_value_t error_value) /**< error value */ -{ - assert (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)); - - if (!jerry_value_is_object (error_value)) - { - return false; - } - - jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *)"name"); - jerry_value_t error_name = jerry_get_property (error_value, prop_name); - jerry_release_value (prop_name); - - if (jerry_value_has_error_flag (error_name) - || !jerry_value_is_string (error_name)) - { - return false; - } - - jerry_size_t err_str_size = jerry_get_string_size (error_name); - const char syntax_error_str[] = "SyntaxError"; - - if (err_str_size != strlen (syntax_error_str) - 1) - { - jerry_release_value (error_name); - return false; - } - - jerry_char_t err_str_buf[err_str_size]; - - jerry_size_t sz = jerry_string_to_char_buffer (error_name, err_str_buf, err_str_size); - jerry_release_value (error_name); - - if (sz == 0) - { - return false; - } - - if (!strncmp ((char *) err_str_buf, syntax_error_str, sizeof (syntax_error_str) - 1)) - { - return true; - } - - return false; -} /* jerry_value_is_syntax_error */ - /** * Convert string into unsigned integer * @@ -222,7 +169,8 @@ print_unhandled_exception (jerry_value_t error_value, /**< error value */ assert (sz == err_str_size); err_str_buf[err_str_size] = 0; - if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) && jerry_value_is_syntax_error (error_value)) + if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) + && jerry_get_error_type (error_value) == JERRY_ERROR_SYNTAX) { uint32_t err_line = 0; uint32_t err_col = 0; diff --git a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c index 5fb18d3e6..80d16f559 100644 --- a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c +++ b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c @@ -121,59 +121,6 @@ read_file (const char *file_name, /**< source code */ return (const uint8_t *) buffer; } /* read_file */ -/** - * Check whether an error is a SyntaxError or not - * - * @return true - if param is SyntaxError - * false - otherwise - */ -static bool -jerry_value_is_syntax_error (jerry_value_t error_value) /**< error value */ -{ - assert (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)); - - if (!jerry_value_is_object (error_value)) - { - return false; - } - - jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *)"name"); - jerry_value_t error_name = jerry_get_property (error_value, prop_name); - jerry_release_value (prop_name); - - if (jerry_value_has_error_flag (error_name) - || !jerry_value_is_string (error_name)) - { - return false; - } - - jerry_size_t err_str_size = jerry_get_string_size (error_name); - const char syntax_error_str[] = "SyntaxError"; - - if (err_str_size != strlen (syntax_error_str) - 1) - { - jerry_release_value (error_name); - return false; - } - - jerry_char_t err_str_buf[err_str_size]; - - jerry_size_t sz = jerry_string_to_char_buffer (error_name, err_str_buf, err_str_size); - jerry_release_value (error_name); - - if (sz == 0) - { - return false; - } - - if (!strncmp ((char *) err_str_buf, syntax_error_str, sizeof (syntax_error_str) - 1)) - { - return true; - } - - return false; -} /* jerry_value_is_syntax_error */ - /** * Print error value */ @@ -200,7 +147,8 @@ print_unhandled_exception (jerry_value_t error_value, /**< error value */ assert (sz == err_str_size); err_str_buf[err_str_size] = 0; - if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) && jerry_value_is_syntax_error (error_value)) + if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) + && jerry_get_error_type (error_value) == JERRY_ERROR_SYNTAX) { unsigned int err_line = 0; unsigned int err_col = 0; diff --git a/tests/unit-core/test-api-errortype.c b/tests/unit-core/test-api-errortype.c new file mode 100644 index 000000000..db17ecb4d --- /dev/null +++ b/tests/unit-core/test-api-errortype.c @@ -0,0 +1,66 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "test-common.h" + +int +main (void) +{ + TEST_INIT (); + + jerry_init (JERRY_INIT_EMPTY); + + jerry_error_t errors[] = + { + JERRY_ERROR_COMMON, + JERRY_ERROR_EVAL, + JERRY_ERROR_RANGE, + JERRY_ERROR_REFERENCE, + JERRY_ERROR_SYNTAX, + JERRY_ERROR_TYPE, + JERRY_ERROR_URI + }; + + for (size_t idx = 0; idx < sizeof (errors) / sizeof (errors[0]); idx++) + { + jerry_value_t error_obj = jerry_create_error (errors[idx], (const jerry_char_t *)"test"); + TEST_ASSERT (jerry_value_has_error_flag (error_obj)); + TEST_ASSERT (jerry_get_error_type (error_obj) == errors[idx]); + + jerry_value_clear_error_flag (&error_obj); + + TEST_ASSERT (jerry_get_error_type (error_obj) == errors[idx]); + + jerry_release_value (error_obj); + } + + jerry_value_t test_values[] = + { + jerry_create_number (11), + jerry_create_string ((const jerry_char_t *) "message"), + jerry_create_boolean (true), + jerry_create_object (), + }; + + for (size_t idx = 0; idx < sizeof (test_values) / sizeof (test_values[0]); idx++) + { + jerry_error_t error_type = jerry_get_error_type (test_values[idx]); + TEST_ASSERT (error_type == JERRY_ERROR_NONE); + jerry_release_value (test_values[idx]); + } + + jerry_cleanup (); +} /* main */ diff --git a/tests/unit-core/test-arraybuffer.c b/tests/unit-core/test-arraybuffer.c index 12a363acb..eead34cf3 100644 --- a/tests/unit-core/test-arraybuffer.c +++ b/tests/unit-core/test-arraybuffer.c @@ -366,24 +366,7 @@ main (void) { jerry_value_t input_buffer = jerry_create_arraybuffer_external (0, NULL, NULL); TEST_ASSERT (jerry_value_has_error_flag (input_buffer)); - jerry_value_clear_error_flag (&input_buffer); - - if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)) - { - jerry_char_t error_str[15]; - jerry_char_t expected_error_str[15] = "RangeError"; - - jerry_char_t *name_str_p = (jerry_char_t *) "name"; - jerry_value_t name_key = jerry_create_string (name_str_p); - jerry_value_t name_value = jerry_get_property (input_buffer, name_key); - - jerry_size_t name_size = jerry_string_to_char_buffer (name_value, error_str, sizeof (error_str)); - TEST_ASSERT (name_size == strlen ((char *) expected_error_str)); - TEST_ASSERT (strncmp ((char *) error_str, (char *) expected_error_str, name_size) == 0); - - jerry_release_value (name_value); - jerry_release_value (name_key); - } + TEST_ASSERT (jerry_get_error_type (input_buffer) == JERRY_ERROR_RANGE); jerry_release_value (input_buffer); }