/* 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 #include #include #include #include "jerryscript-port-default.h" #include "jerryscript-port.h" #include "jerryscript.h" #include "jerryscript-ext/debugger.h" #include "jerryscript-ext/handler.h" #include "main-options.h" #include "main-utils.h" /** * Temporal buffer size. */ #define JERRY_BUFFER_SIZE 256u #if defined(JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) /** * The alloc function passed to jerry_create_context */ static void * context_alloc (size_t size, void *cb_data_p) { (void) cb_data_p; /* unused */ return malloc (size); } /* context_alloc */ #endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */ int main (int argc, char **argv) { union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; srand (now.u); JERRY_VLA (main_source_t, sources_p, argc); main_args_t arguments; arguments.sources_p = sources_p; main_parse_args (argc, argv, &arguments); #if defined(JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) jerry_context_t *context_p = jerry_create_context (JERRY_GLOBAL_HEAP_SIZE * 1024, context_alloc, NULL); jerry_port_default_set_current_context (context_p); #endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */ restart: main_init_engine (&arguments); int return_code = JERRY_STANDALONE_EXIT_CODE_FAIL; jerry_value_t ret_value; for (uint32_t source_index = 0; source_index < arguments.source_count; source_index++) { main_source_t *source_file_p = sources_p + source_index; const char *file_path_p = argv[source_file_p->path_index]; if (source_file_p->type == SOURCE_MODULE) { jerry_value_t specifier = jerry_create_string_from_utf8 ((const jerry_char_t *) file_path_p); jerry_value_t referrer = jerry_create_undefined (); ret_value = jerry_port_module_resolve (specifier, referrer, NULL); jerry_release_value (referrer); jerry_release_value (specifier); if (!jerry_value_is_error (ret_value)) { if (jerry_module_get_state (ret_value) != JERRY_MODULE_STATE_UNLINKED) { /* A module can be evaluated only once. */ jerry_release_value (ret_value); continue; } jerry_value_t link_val = jerry_module_link (ret_value, NULL, NULL); if (jerry_value_is_error (link_val)) { jerry_release_value (ret_value); ret_value = link_val; } else { jerry_release_value (link_val); jerry_value_t module_val = ret_value; ret_value = jerry_module_evaluate (module_val); jerry_release_value (module_val); } } if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); goto exit; } jerry_release_value (ret_value); continue; } size_t source_size; uint8_t *source_p = jerry_port_read_source (file_path_p, &source_size); if (source_p == NULL) { goto exit; } switch (source_file_p->type) { case SOURCE_SNAPSHOT: { ret_value = jerry_exec_snapshot ((uint32_t *) source_p, source_size, source_file_p->snapshot_index, JERRY_SNAPSHOT_EXEC_COPY_DATA, NULL); jerry_port_release_source (source_p); break; } default: { assert (source_file_p->type == SOURCE_SCRIPT || source_file_p->type == SOURCE_MODULE); if (!jerry_is_valid_utf8_string ((jerry_char_t *) source_p, (jerry_size_t) source_size)) { jerry_port_release_source (source_p); jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string."); goto exit; } jerry_parse_options_t parse_options; parse_options.options = JERRY_PARSE_HAS_RESOURCE; parse_options.resource_name = jerry_create_string_sz ((const jerry_char_t *) file_path_p, (jerry_size_t) strlen (file_path_p)); ret_value = jerry_parse (source_p, source_size, &parse_options); jerry_release_value (parse_options.resource_name); jerry_port_release_source (source_p); if (!jerry_value_is_error (ret_value) && !(arguments.option_flags & OPT_FLAG_PARSE_ONLY)) { jerry_value_t func_val = ret_value; ret_value = jerry_run (func_val); jerry_release_value (func_val); } break; } } if (jerry_value_is_error (ret_value)) { if (main_is_value_reset (ret_value)) { jerry_cleanup (); goto restart; } main_print_unhandled_exception (ret_value); goto exit; } jerry_release_value (ret_value); } if (arguments.option_flags & OPT_FLAG_WAIT_SOURCE) { while (true) { jerry_debugger_wait_for_source_status_t receive_status; receive_status = jerry_debugger_wait_for_client_source (main_wait_for_source_callback, NULL, &ret_value); if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Connection aborted before source arrived."); goto exit; } if (receive_status == JERRY_DEBUGGER_SOURCE_END) { jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n"); break; } assert (receive_status == JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED || receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED); if (receive_status == JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED || main_is_value_reset (ret_value)) { jerry_cleanup (); goto restart; } assert (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED); jerry_release_value (ret_value); } } else if (arguments.option_flags & OPT_FLAG_USE_STDIN) { char buffer[JERRY_BUFFER_SIZE]; char *source_p = NULL; size_t source_size = 0; while (!feof (stdin)) { size_t read_bytes = fread (buffer, 1u, JERRY_BUFFER_SIZE, stdin); size_t new_size = source_size + read_bytes; source_p = realloc (source_p, new_size); memcpy (source_p + source_size, buffer, read_bytes); source_size = new_size; } ret_value = jerry_parse ((jerry_char_t *) source_p, source_size, NULL); free (source_p); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); goto exit; } jerry_value_t func_val = ret_value; ret_value = jerry_run (func_val); jerry_release_value (func_val); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); goto exit; } jerry_release_value (ret_value); } else if (arguments.source_count == 0) { const char *prompt = (arguments.option_flags & OPT_FLAG_NO_PROMPT) ? "" : "jerry> "; char buffer[JERRY_BUFFER_SIZE]; while (true) { printf ("%s", prompt); char *str_p = fgets (buffer, JERRY_BUFFER_SIZE, stdin); if (str_p == NULL) { printf ("\n"); break; } size_t len = strlen (str_p); if (len == 0) { continue; } if (!jerry_is_valid_utf8_string ((jerry_char_t *) str_p, (jerry_size_t) len)) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.\n"); continue; } ret_value = jerry_parse ((jerry_char_t *) str_p, len, NULL); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); continue; } jerry_value_t func_val = ret_value; ret_value = jerry_run (func_val); jerry_release_value (func_val); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); continue; } const jerry_value_t args[] = { ret_value }; jerry_value_t ret_val_print = jerryx_handler_print (NULL, args, 1); jerry_release_value (ret_val_print); jerry_release_value (ret_value); ret_value = jerry_run_all_enqueued_jobs (); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); continue; } jerry_release_value (ret_value); } } ret_value = jerry_run_all_enqueued_jobs (); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); goto exit; } jerry_release_value (ret_value); if (arguments.exit_cb_name_p != NULL) { jerry_value_t global = jerry_get_global_object (); jerry_value_t name_str = jerry_create_string ((jerry_char_t *) arguments.exit_cb_name_p); jerry_value_t callback_fn = jerry_get_property (global, name_str); jerry_release_value (global); jerry_release_value (name_str); if (jerry_value_is_function (callback_fn)) { ret_value = jerry_call_function (callback_fn, jerry_create_undefined (), NULL, 0); if (jerry_value_is_error (ret_value)) { main_print_unhandled_exception (ret_value); goto exit; } jerry_release_value (ret_value); } jerry_release_value (callback_fn); } return_code = JERRY_STANDALONE_EXIT_CODE_OK; exit: jerry_cleanup (); #if defined(JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) free (context_p); #endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */ return return_code; } /* main */