diff --git a/jerry-core/ecma/operations/ecma-eval.c b/jerry-core/ecma/operations/ecma-eval.c index e18502e9f..1144507ba 100644 --- a/jerry-core/ecma/operations/ecma-eval.c +++ b/jerry-core/ecma/operations/ecma-eval.c @@ -90,34 +90,32 @@ ecma_op_eval_chars_buffer (const jerry_api_char_t *code_p, /**< code characters { JERRY_ASSERT (code_p != NULL); - ecma_value_t completion; + ecma_value_t ret_value; ecma_compiled_code_t *bytecode_data_p; jsp_status_t parse_status; bool is_strict_call = (is_direct && is_called_from_strict_mode_code); + jerry_api_object_t *error_obj_p = NULL; parse_status = parser_parse_eval (code_p, code_buffer_size, is_strict_call, - &bytecode_data_p); + &bytecode_data_p, + &error_obj_p); - if (parse_status == JSP_STATUS_SYNTAX_ERROR) + if (parse_status == JSP_STATUS_OK) { - completion = ecma_raise_syntax_error (""); - } - else if (parse_status == JSP_STATUS_REFERENCE_ERROR) - { - completion = ecma_raise_reference_error (""); + ret_value = vm_run_eval (bytecode_data_p, is_direct); } else { - JERRY_ASSERT (parse_status == JSP_STATUS_OK); + JERRY_ASSERT (parse_status == JSP_STATUS_SYNTAX_ERROR); - completion = vm_run_eval (bytecode_data_p, is_direct); + ret_value = ecma_make_error_obj_value (error_obj_p); } - return completion; + return ret_value; } /* ecma_op_eval_chars_buffer */ /** diff --git a/jerry-core/ecma/operations/ecma-exceptions.c b/jerry-core/ecma/operations/ecma-exceptions.c index 52378daa6..239d0e6ef 100644 --- a/jerry-core/ecma/operations/ecma-exceptions.c +++ b/jerry-core/ecma/operations/ecma-exceptions.c @@ -18,6 +18,7 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" +#include "ecma-objects.h" #include "jrt.h" /** \addtogroup ecma ECMA diff --git a/jerry-core/jerry-api.h b/jerry-core/jerry-api.h index 7d4aa2f14..555b0088f 100644 --- a/jerry-core/jerry-api.h +++ b/jerry-core/jerry-api.h @@ -319,6 +319,11 @@ void jerry_register_external_magic_strings (const jerry_api_char_ptr_t *, uint32 size_t jerry_parse_and_save_snapshot (const jerry_api_char_t *, size_t, bool, uint8_t *, size_t); jerry_completion_code_t jerry_exec_snapshot (const void *, size_t, bool, jerry_api_value_t *); +jerry_api_size_t jerry_api_get_string_size (const jerry_api_string_t *); +jerry_api_length_t jerry_api_get_string_length (const jerry_api_string_t *); + +jerry_api_string_t *jerry_api_value_to_string (const jerry_api_value_t *); + /** * @} */ diff --git a/jerry-core/jerry.c b/jerry-core/jerry.c index 30144f5fc..97a763dc7 100644 --- a/jerry-core/jerry.c +++ b/jerry-core/jerry.c @@ -1704,7 +1704,8 @@ jerry_reg_err_callback (jerry_error_callback_t callback) /**< pointer to callbac */ bool jerry_parse (const jerry_api_char_t *source_p, /**< script source */ - size_t source_size) /**< script source size */ + size_t source_size, /**< script source size */ + jerry_api_object_t **error_obj_p) /**< [out] error object */ { jerry_assert_api_available (); @@ -1717,11 +1718,12 @@ jerry_parse (const jerry_api_char_t *source_p, /**< script source */ parse_status = parser_parse_script (source_p, source_size, - &bytecode_data_p); + &bytecode_data_p, + error_obj_p); if (parse_status != JSP_STATUS_OK) { - JERRY_ASSERT (parse_status == JSP_STATUS_SYNTAX_ERROR || parse_status == JSP_STATUS_REFERENCE_ERROR); + JERRY_ASSERT (parse_status == JSP_STATUS_SYNTAX_ERROR); return false; } @@ -1747,11 +1749,11 @@ jerry_parse (const jerry_api_char_t *source_p, /**< script source */ * @return completion status */ jerry_completion_code_t -jerry_run (void) +jerry_run (jerry_api_object_t **error_obj_p) { jerry_assert_api_available (); - return vm_run_global (); + return vm_run_global (error_obj_p); } /* jerry_run */ /** @@ -1767,8 +1769,9 @@ jerry_run_simple (const jerry_api_char_t *script_source, /**< script source */ jerry_init (flags); jerry_completion_code_t ret_code = JERRY_COMPLETION_CODE_OK; + jerry_api_object_t *error_obj_p = NULL; - if (!jerry_parse (script_source, script_source_size)) + if (!jerry_parse (script_source, script_source_size, &error_obj_p)) { /* unhandled SyntaxError */ ret_code = JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION; @@ -1777,7 +1780,7 @@ jerry_run_simple (const jerry_api_char_t *script_source, /**< script source */ { if ((flags & JERRY_FLAG_PARSE_ONLY) == 0) { - ret_code = jerry_run (); + ret_code = jerry_run (&error_obj_p); } } @@ -2055,17 +2058,25 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t *source_p, /**< script sou size_t compiled_code_start = snapshot_buffer_write_offset; snapshot_report_byte_code_compilation = true; + jerry_api_object_t *error_obj_p = NULL; if (is_for_global) { - parse_status = parser_parse_script (source_p, source_size, &bytecode_data_p); + parse_status = parser_parse_script (source_p, source_size, &bytecode_data_p, &error_obj_p); } else { parse_status = parser_parse_eval (source_p, source_size, false, - &bytecode_data_p); + &bytecode_data_p, + &error_obj_p); + } + + if (parse_status != JSP_STATUS_OK) + { + JERRY_ASSERT (error_obj_p != NULL); + ecma_deref_object (error_obj_p); } snapshot_report_byte_code_compilation = false; @@ -2361,7 +2372,21 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */ { vm_init (bytecode_p, false); - ret_code = vm_run_global (); + ecma_object_t *error_obj_p = NULL; + + ret_code = vm_run_global (&error_obj_p); + + if (ret_code == JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION) + { + JERRY_ASSERT (error_obj_p != NULL); + + ecma_deref_object (error_obj_p); + } + else + { + JERRY_ASSERT (ret_code == JERRY_COMPLETION_CODE_OK); + JERRY_ASSERT (error_obj_p == NULL); + } vm_finalize (); } @@ -2385,3 +2410,49 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */ return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_VERSION; #endif /* !JERRY_ENABLE_SNAPSHOT_EXEC */ } /* jerry_exec_snapshot */ + +/** + * Call the ToString ecma builtin operation on the api value. + * + * @return string value + */ +jerry_api_string_t * +jerry_api_value_to_string (const jerry_api_value_t *in_value_p) /**< input value */ +{ + jerry_assert_api_available (); + + ecma_value_t in_value; + jerry_api_convert_api_value_to_ecma_value (&in_value, in_value_p); + + ecma_value_t str_value = ecma_op_to_string (in_value); + + ecma_free_value (in_value); + + return (jerry_api_string_t *) ecma_get_string_from_value (str_value); +} /* jerry_api_value_to_string */ + +/** + * Get size of Jerry string + * + * @return number of bytes in the buffer needed to represent the string + */ +jerry_api_size_t +jerry_api_get_string_size (const jerry_api_string_t *str_p) /**< input string */ +{ + jerry_assert_api_available (); + + return ecma_string_get_size ((ecma_string_t *) str_p); +} /* jerry_api_get_string_size */ + +/** + * Get length of Jerry string + * + * @return number of characters in the string + */ +jerry_api_length_t +jerry_api_get_string_length (const jerry_api_string_t *str_p) /**< input string */ +{ + jerry_assert_api_available (); + + return ecma_string_get_length ((ecma_string_t *) str_p); +} /* jerry_api_get_string_length */ diff --git a/jerry-core/jerry.h b/jerry-core/jerry.h index 56ad3bd52..5b16c4bde 100644 --- a/jerry-core/jerry.h +++ b/jerry-core/jerry.h @@ -93,8 +93,8 @@ void jerry_cleanup (void); void jerry_get_memory_limits (size_t *, size_t *); void jerry_reg_err_callback (jerry_error_callback_t); -bool jerry_parse (const jerry_api_char_t *, size_t); -jerry_completion_code_t jerry_run (void); +bool jerry_parse (const jerry_api_char_t *, size_t, jerry_api_object_t **); +jerry_completion_code_t jerry_run (jerry_api_object_t **); jerry_completion_code_t jerry_run_simple (const jerry_api_char_t *, size_t, jerry_flag_t); /** diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 7b664a569..d37c06e5d 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2254,19 +2254,22 @@ parser_set_show_instrs (int show_instrs) /**< flag indicating whether to dump by #endif /* PARSER_DUMP_BYTE_CODE */ } /* parser_set_show_instrs */ - /** * Parse EcamScript source code */ jsp_status_t parser_parse_script (const jerry_api_char_t *source_p, /**< source code */ size_t size, /**< size of the source code */ - ecma_compiled_code_t **bytecode_data_p) /**< result */ + ecma_compiled_code_t **bytecode_data_p, /**< [out] JS bytecode */ + jerry_api_object_t **error_obj_p) /**< [out] error object */ { - *bytecode_data_p = parser_parse_source (source_p, size, false, NULL); + parser_error_location parse_error; + *bytecode_data_p = parser_parse_source (source_p, size, false, &parse_error); if (!*bytecode_data_p) { + *error_obj_p = jerry_api_create_error (JERRY_API_ERROR_SYNTAX, + (const jerry_api_char_t *) parser_error_to_string (parse_error.error)); return JSP_STATUS_SYNTAX_ERROR; } @@ -2280,19 +2283,22 @@ jsp_status_t parser_parse_eval (const jerry_api_char_t *source_p, /**< source code */ size_t size, /**< size of the source code */ bool is_strict, /**< strict mode */ - ecma_compiled_code_t **bytecode_data_p) /**< result */ + ecma_compiled_code_t **bytecode_data_p, /**< [out] JS bytecode */ + jerry_api_object_t **error_obj_p) /**< [out] error object */ { - *bytecode_data_p = parser_parse_source (source_p, size, is_strict, NULL); + parser_error_location parse_error; + *bytecode_data_p = parser_parse_source (source_p, size, is_strict, &parse_error); if (!*bytecode_data_p) { + *error_obj_p = jerry_api_create_error (JERRY_API_ERROR_SYNTAX, + (const jerry_api_char_t *) parser_error_to_string (parse_error.error)); return JSP_STATUS_SYNTAX_ERROR; } return JSP_STATUS_OK; } /* parser_parse_eval */ - /** * @} * @} diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index e71db227d..845597529 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -135,16 +135,20 @@ typedef enum { JSP_STATUS_OK, /**< parse finished successfully, no early errors occured */ JSP_STATUS_SYNTAX_ERROR, /**< SyntaxError early error occured */ - JSP_STATUS_REFERENCE_ERROR /**< ReferenceError early error occured */ } jsp_status_t; extern void parser_set_show_instrs (int); /* Note: source must be a valid UTF-8 string */ -extern jsp_status_t parser_parse_script (const jerry_api_char_t *, size_t, - ecma_compiled_code_t **); -extern jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool, - ecma_compiled_code_t **); +extern jsp_status_t parser_parse_script (const jerry_api_char_t *, + size_t, + ecma_compiled_code_t **, + jerry_api_object_t **); +extern jsp_status_t parser_parse_eval (const jerry_api_char_t *, + size_t, + bool, + ecma_compiled_code_t **, + jerry_api_object_t **); const char *parser_error_to_string (parser_error_t); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 3121bea9c..2ea46bcc6 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -177,7 +177,7 @@ static const uint32_t vm_ext_decode_table[] = * @return completion code */ jerry_completion_code_t -vm_run_global (void) +vm_run_global (ecma_object_t **error_obj_p) { jerry_completion_code_t ret_code; @@ -186,24 +186,24 @@ vm_run_global (void) ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_value_t completion_value = vm_run (__program, - ecma_make_object_value (glob_obj_p), - lex_env_p, - false, - NULL, - 0); + ecma_value_t ret_value = vm_run (__program, + ecma_make_object_value (glob_obj_p), + lex_env_p, + false, + NULL, + 0); - if (ecma_is_value_error (completion_value)) + if (ecma_is_value_error (ret_value)) { + *error_obj_p = ecma_get_object_from_value (ret_value); ret_code = JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION; } else { + ecma_free_value (ret_value); ret_code = JERRY_COMPLETION_CODE_OK; } - ecma_free_value (completion_value); - ecma_deref_object (glob_obj_p); ecma_deref_object (lex_env_p); diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index e6718d5b2..b1e953856 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -194,7 +194,7 @@ typedef enum extern void vm_init (ecma_compiled_code_t *, bool); extern void vm_finalize (void); -extern jerry_completion_code_t vm_run_global (void); +extern jerry_completion_code_t vm_run_global (ecma_object_t **); extern ecma_value_t vm_run_eval (ecma_compiled_code_t *, bool); extern ecma_value_t vm_run (const ecma_compiled_code_t *, ecma_value_t, diff --git a/main-unix.c b/main-unix.c index 977b6ce83..bcb52e96e 100644 --- a/main-unix.c +++ b/main-unix.c @@ -411,6 +411,8 @@ main (int argc, } } + jerry_api_object_t *err_obj_p = NULL; + if (is_ok) { size_t source_size; @@ -450,14 +452,14 @@ main (int argc, } else { - if (!jerry_parse (source_p, source_size)) + if (!jerry_parse (source_p, source_size, &err_obj_p)) { /* unhandled SyntaxError */ ret_code = JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION; } else if ((flags & JERRY_FLAG_PARSE_ONLY) == 0) { - ret_code = jerry_run (); + ret_code = jerry_run (&err_obj_p); } } } @@ -534,8 +536,6 @@ main (int argc, jerry_api_release_value (&print_function); } - jerry_cleanup (); - #ifdef JERRY_ENABLE_LOG if (jerry_log_file && jerry_log_file != stdout) { @@ -546,10 +546,36 @@ main (int argc, if (ret_code == JERRY_COMPLETION_CODE_OK) { + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_OK; } - else + else if (ret_code == JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION) { + if (err_obj_p != NULL) + { + jerry_api_char_t err_str_buf[256]; + + jerry_api_value_t err_value = jerry_api_create_object_value (err_obj_p); + jerry_api_string_t *err_str_p = jerry_api_value_to_string (&err_value); + + jerry_api_size_t err_str_size = jerry_api_get_string_size (err_str_p); + JERRY_ASSERT (err_str_size < 256); + ssize_t sz = jerry_api_string_to_char_buffer (err_str_p, err_str_buf, err_str_size); + JERRY_ASSERT (sz > 0); + err_str_buf[err_str_size] = 0; + + JERRY_ERROR_MSG ("%s\n", err_str_buf); + + jerry_api_release_string (err_str_p); + jerry_api_release_object (err_obj_p); + } + + jerry_cleanup (); return JERRY_STANDALONE_EXIT_CODE_FAIL; } + + JERRY_ASSERT (ret_code == JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT + || ret_code == JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_VERSION); + jerry_cleanup (); + return JERRY_STANDALONE_EXIT_CODE_FAIL; } /* main */ diff --git a/tests/unit/test-api.c b/tests/unit/test-api.c index 73481fbf0..20db6d4c2 100644 --- a/tests/unit/test-api.c +++ b/tests/unit/test-api.c @@ -332,14 +332,15 @@ main (void) jerry_api_object_t *global_obj_p, *obj_p; jerry_api_object_t *external_func_p, *external_construct_p; jerry_api_object_t *throw_test_handler_p; + jerry_api_object_t *err_obj_p = NULL; jerry_api_value_t res, args[2]; char buffer[32]; - is_ok = jerry_parse ((jerry_api_char_t *) test_source, strlen (test_source)); - JERRY_ASSERT (is_ok); + is_ok = jerry_parse ((jerry_api_char_t *) test_source, strlen (test_source), &err_obj_p); + JERRY_ASSERT (is_ok && err_obj_p == NULL); - is_ok = (jerry_run () == JERRY_COMPLETION_CODE_OK); - JERRY_ASSERT (is_ok); + is_ok = (jerry_run (&err_obj_p) == JERRY_COMPLETION_CODE_OK); + JERRY_ASSERT (is_ok && err_obj_p == NULL); global_obj_p = jerry_api_get_global (); @@ -684,11 +685,11 @@ main (void) magic_string_lengths); const char *ms_code_src_p = "var global = {}; var console = [1]; var process = 1;"; - is_ok = jerry_parse ((jerry_api_char_t *) ms_code_src_p, strlen (ms_code_src_p)); - JERRY_ASSERT (is_ok); + is_ok = jerry_parse ((jerry_api_char_t *) ms_code_src_p, strlen (ms_code_src_p), &err_obj_p); + JERRY_ASSERT (is_ok && err_obj_p == NULL); - is_ok = (jerry_run () == JERRY_COMPLETION_CODE_OK); - JERRY_ASSERT (is_ok); + is_ok = (jerry_run (&err_obj_p) == JERRY_COMPLETION_CODE_OK); + JERRY_ASSERT (is_ok && err_obj_p == NULL); jerry_cleanup ();