215 lines
4.8 KiB
C
215 lines
4.8 KiB
C
#include "frontend.h"
|
|
|
|
#include <bshell/ast.h>
|
|
#include <bshell/compile.h>
|
|
#include <bshell/file.h>
|
|
#include <bshell/format.h>
|
|
#include <bshell/parse/lex.h>
|
|
#include <bshell/parse/parse.h>
|
|
#include <bshell/parse/token.h>
|
|
#include <bshell/verb.h>
|
|
#include <fx/cmdline/cmd.h>
|
|
#include <fx/io/path.h>
|
|
#include <stdio.h>
|
|
|
|
enum {
|
|
CMD_ROOT,
|
|
OPT_LEX,
|
|
OPT_PARSE,
|
|
OPT_EVAL,
|
|
OPT_PRINT_LEX,
|
|
OPT_PRINT_AST,
|
|
OPT_PRINT_BYTECODE,
|
|
ARG_SCRIPT_FILE,
|
|
};
|
|
|
|
#define FEATURE_FLAGS \
|
|
(FRONTEND_F_ENABLE_LEX | FRONTEND_F_ENABLE_PARSE \
|
|
| FRONTEND_F_ENABLE_EVAL)
|
|
#define PRINT_FLAGS \
|
|
(FRONTEND_F_PRINT_LEX | FRONTEND_F_PRINT_AST \
|
|
| FRONTEND_F_PRINT_BYTECODE)
|
|
|
|
const char *exec_name = NULL;
|
|
|
|
static enum frontend_flags collect_frontend_flags(const fx_arglist *opt)
|
|
{
|
|
enum frontend_flags result = 0;
|
|
#define OPTION_IS_SET(id) \
|
|
fx_arglist_get_count(opt, id, FX_COMMAND_INVALID_ID) > 0
|
|
|
|
if (OPTION_IS_SET(OPT_LEX)) {
|
|
result |= FRONTEND_F_ENABLE_LEX;
|
|
}
|
|
|
|
if (OPTION_IS_SET(OPT_PARSE)) {
|
|
result |= FRONTEND_F_ENABLE_PARSE;
|
|
}
|
|
|
|
if (OPTION_IS_SET(OPT_EVAL)) {
|
|
result |= FRONTEND_F_ENABLE_EVAL;
|
|
}
|
|
|
|
if (OPTION_IS_SET(OPT_PRINT_LEX)) {
|
|
result |= FRONTEND_F_PRINT_LEX;
|
|
}
|
|
|
|
if (OPTION_IS_SET(OPT_PRINT_AST)) {
|
|
result |= FRONTEND_F_PRINT_AST;
|
|
}
|
|
|
|
if (OPTION_IS_SET(OPT_PRINT_BYTECODE)) {
|
|
result |= FRONTEND_F_PRINT_BYTECODE;
|
|
}
|
|
|
|
if ((result & PRINT_FLAGS) && !(result & FEATURE_FLAGS)) {
|
|
result |= FRONTEND_F_ENABLE_EVAL;
|
|
}
|
|
|
|
#undef OPTION_IS_SET
|
|
return result;
|
|
}
|
|
|
|
static int bshell(
|
|
const fx_command *self,
|
|
const fx_arglist *opt,
|
|
const fx_array *args)
|
|
{
|
|
enum frontend_flags flags = collect_frontend_flags(opt);
|
|
if (flags == 0) {
|
|
flags = FRONTEND_DEFAULT_FLAGS;
|
|
}
|
|
|
|
struct frontend_ctx ctx;
|
|
frontend_init(&ctx, flags);
|
|
enum bshell_status status = BSHELL_SUCCESS;
|
|
|
|
fx_path *config_base_dir = fx_path_get_system(FX_PATH_CONFIG);
|
|
fx_path *profile_path = fx_path_join_list(
|
|
3,
|
|
&FX_VALUE_OBJECT(config_base_dir),
|
|
&FX_CSTR("bshell"),
|
|
&FX_CSTR("profile.bshell"));
|
|
fx_path_unref(config_base_dir);
|
|
|
|
if (fx_path_is_file(profile_path)) {
|
|
status = frontend_eval_file(
|
|
&ctx,
|
|
NULL,
|
|
fx_path_get_cstr(profile_path));
|
|
|
|
if (status != BSHELL_SUCCESS) {
|
|
fprintf(stderr,
|
|
"%s: cannot evaluate '%s': %s\n",
|
|
exec_name,
|
|
fx_path_get_cstr(profile_path),
|
|
bshell_status_get_description(status));
|
|
}
|
|
}
|
|
fx_path_unref(profile_path);
|
|
|
|
size_t nr_input_files = fx_arglist_get_count(
|
|
opt,
|
|
FX_COMMAND_INVALID_ID,
|
|
ARG_SCRIPT_FILE);
|
|
|
|
if (nr_input_files == 0) {
|
|
printf("B Shell " BSHELL_VERSION "\n");
|
|
frontend_repl(&ctx);
|
|
frontend_cleanup(&ctx);
|
|
return 0;
|
|
}
|
|
|
|
fx_arglist_iterator it;
|
|
fx_arglist_iterator_begin(
|
|
opt,
|
|
FX_COMMAND_INVALID_ID,
|
|
ARG_SCRIPT_FILE,
|
|
&it);
|
|
|
|
while (fx_arglist_iterator_is_valid(&it)) {
|
|
const char *script_path = it.value->val_str;
|
|
status = frontend_eval_file(&ctx, NULL, script_path);
|
|
|
|
if (status != BSHELL_SUCCESS) {
|
|
fprintf(stderr,
|
|
"%s: cannot open '%s': %s\n",
|
|
exec_name,
|
|
script_path,
|
|
bshell_status_get_description(status));
|
|
}
|
|
|
|
fx_arglist_iterator_next(&it);
|
|
}
|
|
|
|
frontend_cleanup(&ctx);
|
|
return 0;
|
|
}
|
|
|
|
FX_COMMAND(CMD_ROOT, FX_COMMAND_INVALID_ID)
|
|
{
|
|
FX_COMMAND_NAME("bshell");
|
|
FX_COMMAND_DESC("B Shell script interpreter.");
|
|
FX_COMMAND_FUNCTION(bshell);
|
|
|
|
FX_COMMAND_OPTION(OPT_LEX)
|
|
{
|
|
FX_OPTION_LONG_NAME("lex");
|
|
FX_OPTION_SHORT_NAME('l');
|
|
FX_OPTION_DESC("Enable lexing of shell input.");
|
|
}
|
|
|
|
FX_COMMAND_OPTION(OPT_PARSE)
|
|
{
|
|
FX_OPTION_LONG_NAME("parse");
|
|
FX_OPTION_SHORT_NAME('a');
|
|
FX_OPTION_DESC(
|
|
"Enable parsing and ast generation of shell input.");
|
|
}
|
|
|
|
FX_COMMAND_OPTION(OPT_EVAL)
|
|
{
|
|
FX_OPTION_LONG_NAME("eval");
|
|
FX_OPTION_SHORT_NAME('b');
|
|
FX_OPTION_DESC(
|
|
"Enable evaluation and bytecode generation of shell "
|
|
"input. This option is the default if no 'enable' "
|
|
"flags are specified.");
|
|
}
|
|
|
|
FX_COMMAND_OPTION(OPT_PRINT_LEX)
|
|
{
|
|
FX_OPTION_LONG_NAME("print-lex");
|
|
FX_OPTION_SHORT_NAME('L');
|
|
FX_OPTION_DESC("Print lex tokens generated from shell input.");
|
|
}
|
|
|
|
FX_COMMAND_OPTION(OPT_PRINT_AST)
|
|
{
|
|
FX_OPTION_LONG_NAME("print-ast");
|
|
FX_OPTION_SHORT_NAME('A');
|
|
FX_OPTION_DESC("Print ast nodes generated from shell input.");
|
|
}
|
|
|
|
FX_COMMAND_OPTION(OPT_PRINT_BYTECODE)
|
|
{
|
|
FX_OPTION_LONG_NAME("print-bytecode");
|
|
FX_OPTION_SHORT_NAME('B');
|
|
FX_OPTION_DESC("Print bytecode generated from shell input.");
|
|
}
|
|
|
|
FX_COMMAND_ARG(ARG_SCRIPT_FILE)
|
|
{
|
|
FX_ARG_DESC("Script file to evaluate.");
|
|
FX_ARG_NR_VALUES(FX_ARG_0_OR_MORE_VALUES);
|
|
}
|
|
|
|
FX_COMMAND_HELP_OPTION();
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
exec_name = argv[0];
|
|
return fx_command_dispatch(CMD_ROOT, argc, argv);
|
|
}
|