Files
bshell/bshell/main.c
T

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);
}