376 lines
12 KiB
C
376 lines
12 KiB
C
/* 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 <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "jerryscript-port.h"
|
|
#include "jerryscript-port-default.h"
|
|
|
|
#include "cli.h"
|
|
#include "main-utils.h"
|
|
#include "main-options.h"
|
|
|
|
/**
|
|
* Command line option IDs
|
|
*/
|
|
typedef enum
|
|
{
|
|
OPT_HELP,
|
|
OPT_VERSION,
|
|
OPT_MEM_STATS,
|
|
OPT_TEST262_OBJECT,
|
|
OPT_PARSE_ONLY,
|
|
OPT_SHOW_OP,
|
|
OPT_SHOW_RE_OP,
|
|
OPT_DEBUG_SERVER,
|
|
OPT_DEBUG_PORT,
|
|
OPT_DEBUG_CHANNEL,
|
|
OPT_DEBUG_PROTOCOL,
|
|
OPT_DEBUG_SERIAL_CONFIG,
|
|
OPT_DEBUGGER_WAIT_SOURCE,
|
|
OPT_EXEC_SNAP,
|
|
OPT_EXEC_SNAP_FUNC,
|
|
OPT_MODULE,
|
|
OPT_LOG_LEVEL,
|
|
OPT_NO_PROMPT,
|
|
OPT_CALL_ON_EXIT,
|
|
OPT_USE_STDIN,
|
|
} main_opt_id_t;
|
|
|
|
/**
|
|
* Command line options
|
|
*/
|
|
static const cli_opt_t main_opts[] =
|
|
{
|
|
CLI_OPT_DEF (.id = OPT_HELP, .opt = "h", .longopt = "help",
|
|
.help = "print this help and exit"),
|
|
CLI_OPT_DEF (.id = OPT_VERSION, .opt = "v", .longopt = "version",
|
|
.help = "print tool and library version and exit"),
|
|
CLI_OPT_DEF (.id = OPT_MEM_STATS, .longopt = "mem-stats",
|
|
.help = "dump memory statistics"),
|
|
CLI_OPT_DEF (.id = OPT_TEST262_OBJECT, .longopt = "test262-object",
|
|
.help = "create test262 object"),
|
|
CLI_OPT_DEF (.id = OPT_PARSE_ONLY, .longopt = "parse-only",
|
|
.help = "don't execute JS input"),
|
|
CLI_OPT_DEF (.id = OPT_SHOW_OP, .longopt = "show-opcodes",
|
|
.help = "dump parser byte-code"),
|
|
CLI_OPT_DEF (.id = OPT_SHOW_RE_OP, .longopt = "show-regexp-opcodes",
|
|
.help = "dump regexp byte-code"),
|
|
CLI_OPT_DEF (.id = OPT_DEBUG_SERVER, .longopt = "start-debug-server",
|
|
.help = "start debug server and wait for a connecting client"),
|
|
CLI_OPT_DEF (.id = OPT_DEBUG_PORT, .longopt = "debug-port", .meta = "NUM",
|
|
.help = "debug server port (default: 5001)"),
|
|
CLI_OPT_DEF (.id = OPT_DEBUG_CHANNEL, .longopt = "debug-channel", .meta = "[websocket|rawpacket]",
|
|
.help = "Specify the debugger transmission channel (default: websocket)"),
|
|
CLI_OPT_DEF (.id = OPT_DEBUG_PROTOCOL, .longopt = "debug-protocol", .meta = "PROTOCOL",
|
|
.help = "Specify the transmission protocol over the communication channel (tcp|serial, default: tcp)"),
|
|
CLI_OPT_DEF (.id = OPT_DEBUG_SERIAL_CONFIG, .longopt = "serial-config", .meta = "OPTIONS_STRING",
|
|
.help = "Configure parameters for serial port (default: /dev/ttyS0,115200,8,N,1)"),
|
|
CLI_OPT_DEF (.id = OPT_DEBUGGER_WAIT_SOURCE, .longopt = "debugger-wait-source",
|
|
.help = "wait for an executable source from the client"),
|
|
CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE",
|
|
.help = "execute input snapshot file(s)"),
|
|
CLI_OPT_DEF (.id = OPT_EXEC_SNAP_FUNC, .longopt = "exec-snapshot-func", .meta = "FILE NUM",
|
|
.help = "execute specific function from input snapshot file(s)"),
|
|
CLI_OPT_DEF (.id = OPT_MODULE, .opt = "m", .longopt = "module", .meta = "FILE",
|
|
.help = "execute module file"),
|
|
CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "log-level", .meta = "NUM",
|
|
.help = "set log level (0-3)"),
|
|
CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "no-prompt",
|
|
.help = "don't print prompt in REPL mode"),
|
|
CLI_OPT_DEF (.id = OPT_CALL_ON_EXIT, .longopt = "call-on-exit", .meta = "STRING",
|
|
.help = "invoke the specified function when the process is just about to exit"),
|
|
CLI_OPT_DEF (.id = OPT_USE_STDIN, .opt = "", .help = "read from standard input"),
|
|
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
|
|
.help = "input JS file(s)")
|
|
};
|
|
|
|
/**
|
|
* Check whether a usage-related condition holds. If not, print an error
|
|
* message, print the usage, and terminate the application.
|
|
*/
|
|
static void
|
|
check_usage (bool condition, /**< the condition that must hold */
|
|
const char *name, /**< name of the application (argv[0]) */
|
|
const char *msg, /**< error message to print if condition does not hold */
|
|
const char *opt) /**< optional part of the error message */
|
|
{
|
|
if (!condition)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%s: %s%s\n", name, msg, opt != NULL ? opt : "");
|
|
exit (JERRY_STANDALONE_EXIT_CODE_FAIL);
|
|
}
|
|
} /* check_usage */
|
|
|
|
/**
|
|
* Check whether JerryScript has a requested feature enabled or not. If not,
|
|
* print a warning message.
|
|
*
|
|
* @return the status of the feature.
|
|
*/
|
|
static bool
|
|
check_feature (jerry_feature_t feature, /**< feature to check */
|
|
const char *option) /**< command line option that triggered this check */
|
|
{
|
|
if (!jerry_is_feature_enabled (feature))
|
|
{
|
|
jerry_port_default_set_log_level (JERRY_LOG_LEVEL_WARNING);
|
|
jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Ignoring '%s' option because this feature is disabled!\n", option);
|
|
return false;
|
|
}
|
|
return true;
|
|
} /* check_feature */
|
|
|
|
/**
|
|
* parse input arguments
|
|
*/
|
|
void
|
|
main_parse_args (int argc, /**< argc */
|
|
char **argv, /**< argv */
|
|
main_args_t *arguments_p) /**< [in/out] arguments reference */
|
|
{
|
|
arguments_p->source_count = 0;
|
|
|
|
arguments_p->debug_channel = "websocket";
|
|
arguments_p->debug_protocol = "tcp";
|
|
arguments_p->debug_serial_config = "/dev/ttyS0,115200,8,N,1";
|
|
arguments_p->debug_port = 5001;
|
|
|
|
arguments_p->exit_cb_name_p = NULL;
|
|
arguments_p->init_flags = JERRY_INIT_EMPTY;
|
|
arguments_p->option_flags = OPT_FLAG_EMPTY;
|
|
|
|
cli_state_t cli_state = cli_init (main_opts, argc, argv);
|
|
for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state))
|
|
{
|
|
switch (id)
|
|
{
|
|
case OPT_HELP:
|
|
{
|
|
cli_help (argv[0], NULL, main_opts);
|
|
exit (JERRY_STANDALONE_EXIT_CODE_OK);
|
|
|
|
break;
|
|
}
|
|
case OPT_VERSION:
|
|
{
|
|
printf ("Version: %d.%d.%d%s\n",
|
|
JERRY_API_MAJOR_VERSION,
|
|
JERRY_API_MINOR_VERSION,
|
|
JERRY_API_PATCH_VERSION,
|
|
JERRY_COMMIT_HASH);
|
|
exit (JERRY_STANDALONE_EXIT_CODE_OK);
|
|
|
|
break;
|
|
}
|
|
case OPT_MEM_STATS:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_MEM_STATS, cli_state.arg))
|
|
{
|
|
jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
|
|
arguments_p->init_flags |= JERRY_INIT_MEM_STATS;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_TEST262_OBJECT:
|
|
{
|
|
arguments_p->option_flags |= OPT_FLAG_TEST262_OBJECT;
|
|
break;
|
|
}
|
|
case OPT_PARSE_ONLY:
|
|
{
|
|
arguments_p->option_flags |= OPT_FLAG_PARSE_ONLY;
|
|
break;
|
|
}
|
|
case OPT_SHOW_OP:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state.arg))
|
|
{
|
|
jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
|
|
arguments_p->init_flags |= JERRY_INIT_SHOW_OPCODES;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_CALL_ON_EXIT:
|
|
{
|
|
arguments_p->exit_cb_name_p = cli_consume_string (&cli_state);
|
|
break;
|
|
}
|
|
case OPT_SHOW_RE_OP:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_REGEXP_DUMP, cli_state.arg))
|
|
{
|
|
jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
|
|
arguments_p->init_flags |= JERRY_INIT_SHOW_REGEXP_OPCODES;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_DEBUG_SERVER:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
|
|
{
|
|
arguments_p->option_flags |= OPT_FLAG_DEBUG_SERVER;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_DEBUG_PORT:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
|
|
{
|
|
arguments_p->debug_port = (uint16_t) cli_consume_int (&cli_state);
|
|
}
|
|
break;
|
|
}
|
|
case OPT_DEBUG_CHANNEL:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
|
|
{
|
|
const char *debug_channel = cli_consume_string (&cli_state);
|
|
check_usage (!strcmp (debug_channel, "websocket") || !strcmp (debug_channel, "rawpacket"),
|
|
argv[0], "Error: invalid value for --debug-channel: ", cli_state.arg);
|
|
|
|
arguments_p->debug_channel = debug_channel;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_DEBUG_PROTOCOL:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
|
|
{
|
|
const char *debug_protocol = cli_consume_string (&cli_state);
|
|
check_usage (!strcmp (debug_protocol, "tcp") || !strcmp (debug_protocol, "serial"),
|
|
argv[0], "Error: invalid value for --debug-protocol: ", cli_state.arg);
|
|
|
|
arguments_p->debug_protocol = debug_protocol;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_DEBUG_SERIAL_CONFIG:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
|
|
{
|
|
arguments_p->debug_serial_config = cli_consume_string (&cli_state);
|
|
}
|
|
break;
|
|
}
|
|
case OPT_DEBUGGER_WAIT_SOURCE:
|
|
{
|
|
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
|
|
{
|
|
arguments_p->option_flags |= OPT_FLAG_WAIT_SOURCE;
|
|
}
|
|
break;
|
|
}
|
|
case OPT_EXEC_SNAP:
|
|
{
|
|
const bool is_enabled = check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg);
|
|
const uint32_t path_index = cli_consume_path (&cli_state);
|
|
|
|
if (is_enabled)
|
|
{
|
|
main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
|
|
arguments_p->source_count++;
|
|
|
|
source_p->type = SOURCE_SNAPSHOT;
|
|
source_p->path_index = path_index;
|
|
source_p->snapshot_index = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OPT_EXEC_SNAP_FUNC:
|
|
{
|
|
const bool is_enabled = check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg);
|
|
const uint32_t path_index = cli_consume_path (&cli_state);
|
|
const uint16_t snapshot_index = (uint16_t) cli_consume_int (&cli_state);
|
|
|
|
if (is_enabled)
|
|
{
|
|
main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
|
|
arguments_p->source_count++;
|
|
|
|
source_p->type = SOURCE_SNAPSHOT;
|
|
source_p->path_index = path_index;
|
|
source_p->snapshot_index = snapshot_index;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OPT_MODULE:
|
|
{
|
|
const uint32_t path_index = cli_consume_path (&cli_state);
|
|
|
|
main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
|
|
arguments_p->source_count++;
|
|
|
|
source_p->type = SOURCE_MODULE;
|
|
source_p->path_index = path_index;
|
|
source_p->snapshot_index = 0;
|
|
|
|
break;
|
|
}
|
|
case OPT_LOG_LEVEL:
|
|
{
|
|
long int log_level = cli_consume_int (&cli_state);
|
|
check_usage (log_level >= 0 && log_level <= 3,
|
|
argv[0], "Error: invalid value for --log-level: ", cli_state.arg);
|
|
|
|
jerry_port_default_set_log_level ((jerry_log_level_t) log_level);
|
|
break;
|
|
}
|
|
case OPT_NO_PROMPT:
|
|
{
|
|
arguments_p->option_flags |= OPT_FLAG_NO_PROMPT;
|
|
break;
|
|
}
|
|
case OPT_USE_STDIN:
|
|
{
|
|
arguments_p->option_flags |= OPT_FLAG_USE_STDIN;
|
|
break;
|
|
}
|
|
case CLI_OPT_DEFAULT:
|
|
{
|
|
main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
|
|
arguments_p->source_count++;
|
|
|
|
source_p->type = SOURCE_SCRIPT;
|
|
source_p->path_index = cli_consume_path (&cli_state);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
cli_state.error = "Internal error";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cli_state.error != NULL)
|
|
{
|
|
if (cli_state.arg != NULL)
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state.error, cli_state.arg);
|
|
}
|
|
else
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state.error);
|
|
}
|
|
|
|
exit (JERRY_STANDALONE_EXIT_CODE_FAIL);
|
|
}
|
|
} /* main_parse_args */
|