frontend: re-organise frontend functionality; add feature and logging switches
This commit is contained in:
@@ -24,7 +24,7 @@ add_executable(bshell ${bshell_sources})
|
|||||||
|
|
||||||
target_link_libraries(bshell
|
target_link_libraries(bshell
|
||||||
bshell.core bshell.runtime
|
bshell.core bshell.runtime
|
||||||
FX::Runtime FX::Collections)
|
FX::Runtime FX::Collections FX::Cmdline)
|
||||||
|
|
||||||
if (bshell_interactive)
|
if (bshell_interactive)
|
||||||
target_link_libraries(bshell FX::Term)
|
target_link_libraries(bshell FX::Term)
|
||||||
|
|||||||
@@ -0,0 +1,250 @@
|
|||||||
|
#include "frontend.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include <bshell/ast.h>
|
||||||
|
#include <bshell/compile.h>
|
||||||
|
#include <bshell/file.h>
|
||||||
|
#include <bshell/runtime/runtime.h>
|
||||||
|
#include <fx/io/path.h>
|
||||||
|
#include <fx/reflection/assembly.h>
|
||||||
|
|
||||||
|
#if BSHELL_INTERACTIVE == 1
|
||||||
|
#include "line-ed/line-ed.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FRONTEND_FLAG_SET(f, flag) \
|
||||||
|
(((f)->ctx_flags & (FRONTEND_F_##flag)) == (FRONTEND_F_##flag))
|
||||||
|
|
||||||
|
enum eval_flags {
|
||||||
|
EVAL_PRINT_RESULT = 0x01u,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const fx_assembly *bshell_assembly_get(void);
|
||||||
|
extern const fx_assembly *bshell_runtime_assembly_get(void);
|
||||||
|
extern const fx_assembly *bshell_core_assembly_get(void);
|
||||||
|
|
||||||
|
static void lex_token_scanned(
|
||||||
|
struct bshell_lex_ctx *ctx,
|
||||||
|
struct bshell_lex_token *tok)
|
||||||
|
{
|
||||||
|
print_lex_token(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
void frontend_init(struct frontend_ctx *ctx, enum frontend_flags flags)
|
||||||
|
{
|
||||||
|
memset(ctx, 0x0, sizeof *ctx);
|
||||||
|
|
||||||
|
bshell_assembly_get();
|
||||||
|
bshell_runtime_assembly_get();
|
||||||
|
bshell_core_assembly_get();
|
||||||
|
|
||||||
|
ctx->ctx_flags = flags;
|
||||||
|
ctx->ctx_block = bshell_scriptblock_create();
|
||||||
|
ctx->ctx_rt = bshell_runtime_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status lex_only(
|
||||||
|
struct frontend_ctx *ctx,
|
||||||
|
struct bshell_line_source *linesrc,
|
||||||
|
enum eval_flags flags)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
struct bshell_lex_token *tok
|
||||||
|
= bshell_lex_ctx_peek(&ctx->ctx_lex);
|
||||||
|
|
||||||
|
if (!tok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_lex_ctx_discard(&ctx->ctx_lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status parse_only(
|
||||||
|
struct frontend_ctx *ctx,
|
||||||
|
struct bshell_line_source *linesrc,
|
||||||
|
enum eval_flags flags)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
struct bshell_ast_node *node
|
||||||
|
= bshell_parse_ctx_read_node(&ctx->ctx_parse);
|
||||||
|
if (!node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FRONTEND_FLAG_SET(ctx, PRINT_AST)) {
|
||||||
|
print_ast_node_recursive(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_ast_node_destroy(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status eval(
|
||||||
|
struct frontend_ctx *ctx,
|
||||||
|
struct bshell_line_source *linesrc,
|
||||||
|
enum eval_flags flags)
|
||||||
|
{
|
||||||
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
|
||||||
|
bshell_lex_ctx_init(&ctx->ctx_lex, 0, linesrc);
|
||||||
|
if (FRONTEND_FLAG_SET(ctx, PRINT_LEX)) {
|
||||||
|
ctx->ctx_lex.lex_token_scanned = lex_token_scanned;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FRONTEND_FLAG_SET(ctx, ENABLE_PARSE)) {
|
||||||
|
status = lex_only(ctx, linesrc, flags);
|
||||||
|
bshell_lex_ctx_cleanup(&ctx->ctx_lex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_parse_ctx_init(&ctx->ctx_parse, &ctx->ctx_lex);
|
||||||
|
if (!FRONTEND_FLAG_SET(ctx, ENABLE_EVAL)) {
|
||||||
|
status = parse_only(ctx, linesrc, flags);
|
||||||
|
bshell_parse_ctx_cleanup(&ctx->ctx_parse);
|
||||||
|
bshell_lex_ctx_cleanup(&ctx->ctx_lex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct bshell_ast_node *node
|
||||||
|
= bshell_parse_ctx_read_node(&ctx->ctx_parse);
|
||||||
|
if (!node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FRONTEND_FLAG_SET(ctx, PRINT_AST)) {
|
||||||
|
print_ast_node_recursive(node);
|
||||||
|
printf("----\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_clear_text(ctx->ctx_block);
|
||||||
|
switch (node->n_type) {
|
||||||
|
case BSHELL_AST_FUNC: {
|
||||||
|
bshell_function *func = NULL;
|
||||||
|
bshell_compile_function(node, &func);
|
||||||
|
if (FRONTEND_FLAG_SET(ctx, PRINT_BYTECODE)) {
|
||||||
|
print_function(func);
|
||||||
|
}
|
||||||
|
bshell_runtime_define_function(ctx->ctx_rt, func);
|
||||||
|
bshell_function_unref(func);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
bshell_compile(node, ctx->ctx_block);
|
||||||
|
if (FRONTEND_FLAG_SET(ctx, PRINT_BYTECODE)) {
|
||||||
|
print_scriptblock(ctx->ctx_block, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value result = bshell_runtime_eval_global(
|
||||||
|
ctx->ctx_rt,
|
||||||
|
ctx->ctx_block);
|
||||||
|
|
||||||
|
bool print_result = flags & EVAL_PRINT_RESULT
|
||||||
|
&& result.v_type != NULL;
|
||||||
|
if (print_result) {
|
||||||
|
bshell_runtime_begin_output(ctx->ctx_rt);
|
||||||
|
bshell_runtime_output_value(
|
||||||
|
ctx->ctx_rt,
|
||||||
|
&result);
|
||||||
|
bshell_runtime_end_output(ctx->ctx_rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_unset(&result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_ast_node_destroy(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_parse_ctx_cleanup(&ctx->ctx_parse);
|
||||||
|
bshell_lex_ctx_cleanup(&ctx->ctx_lex);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_path *create_path(const char *dir_path, const char *script_path)
|
||||||
|
{
|
||||||
|
if (!script_path) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_path *paths[2] = {0};
|
||||||
|
|
||||||
|
if (dir_path) {
|
||||||
|
paths[0] = fx_path_create_from_cstr(dir_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (script_path) {
|
||||||
|
paths[1] = fx_path_create_from_cstr(script_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir_path) {
|
||||||
|
return paths[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_path *result = fx_path_join(
|
||||||
|
(const fx_path **)paths,
|
||||||
|
sizeof paths / sizeof paths[0]);
|
||||||
|
fx_path_unref(paths[0]);
|
||||||
|
fx_path_unref(paths[1]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status frontend_eval_file(
|
||||||
|
struct frontend_ctx *ctx,
|
||||||
|
const char *dir_path,
|
||||||
|
const char *script_path)
|
||||||
|
{
|
||||||
|
fx_path *path = create_path(dir_path, script_path);
|
||||||
|
if (!path) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bshell_file *file = NULL;
|
||||||
|
ctx->ctx_status = bshell_file_open(fx_path_ptr(path), &file);
|
||||||
|
fx_path_unref(path);
|
||||||
|
|
||||||
|
if (!FX_OK(ctx->ctx_status)) {
|
||||||
|
return ctx->ctx_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bshell_line_source *linesrc = &file->f_base;
|
||||||
|
|
||||||
|
ctx->ctx_status = eval(ctx, linesrc, 0);
|
||||||
|
|
||||||
|
bshell_file_close(file);
|
||||||
|
|
||||||
|
return ctx->ctx_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status frontend_repl(struct frontend_ctx *ctx)
|
||||||
|
{
|
||||||
|
#if BSHELL_INTERACTIVE
|
||||||
|
struct line_ed *ed = line_ed_create();
|
||||||
|
|
||||||
|
struct bshell_line_source *linesrc = line_ed_to_line_source(ed);
|
||||||
|
|
||||||
|
ctx->ctx_status = eval(ctx, linesrc, EVAL_PRINT_RESULT);
|
||||||
|
|
||||||
|
line_ed_destroy(ed);
|
||||||
|
|
||||||
|
return ctx->ctx_status;
|
||||||
|
#else
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void frontend_cleanup(struct frontend_ctx *ctx)
|
||||||
|
{
|
||||||
|
bshell_runtime_destroy(ctx->ctx_rt);
|
||||||
|
bshell_scriptblock_unref(ctx->ctx_block);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef FRONTEND_H_
|
||||||
|
#define FRONTEND_H_
|
||||||
|
|
||||||
|
#include <bshell/parse/lex.h>
|
||||||
|
#include <bshell/parse/parse.h>
|
||||||
|
#include <bshell/runtime/script-block.h>
|
||||||
|
#include <bshell/status.h>
|
||||||
|
|
||||||
|
struct line_ed;
|
||||||
|
struct bshell_file;
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define FRONTEND_DEFAULT_FLAGS (FRONTEND_F_ENABLE_EVAL)
|
||||||
|
|
||||||
|
enum frontend_flags {
|
||||||
|
FRONTEND_F_ENABLE_LEX = 0x01u,
|
||||||
|
FRONTEND_F_ENABLE_PARSE = 0x03u,
|
||||||
|
FRONTEND_F_ENABLE_EVAL = 0x07u,
|
||||||
|
|
||||||
|
FRONTEND_F_PRINT_LEX = 0x10u,
|
||||||
|
FRONTEND_F_PRINT_AST = 0x20u,
|
||||||
|
FRONTEND_F_PRINT_BYTECODE = 0x40u,
|
||||||
|
|
||||||
|
FRONTEND_F_INTERACTIVE = 0x80u,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct frontend_ctx {
|
||||||
|
enum bshell_status ctx_status;
|
||||||
|
enum frontend_flags ctx_flags;
|
||||||
|
|
||||||
|
struct bshell_lex_ctx ctx_lex;
|
||||||
|
struct bshell_parse_ctx ctx_parse;
|
||||||
|
|
||||||
|
struct bshell_runtime *ctx_rt;
|
||||||
|
bshell_scriptblock *ctx_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void frontend_init(struct frontend_ctx *ctx, enum frontend_flags flags);
|
||||||
|
|
||||||
|
extern enum bshell_status frontend_eval_file(
|
||||||
|
struct frontend_ctx *ctx,
|
||||||
|
const char *dir_path,
|
||||||
|
const char *script_path);
|
||||||
|
extern enum bshell_status frontend_repl(struct frontend_ctx *ctx);
|
||||||
|
|
||||||
|
extern void frontend_cleanup(struct frontend_ctx *ctx);
|
||||||
|
|
||||||
|
#endif
|
||||||
+160
-154
@@ -1,4 +1,4 @@
|
|||||||
#include "debug.h"
|
#include "frontend.h"
|
||||||
|
|
||||||
#include <bshell/ast.h>
|
#include <bshell/ast.h>
|
||||||
#include <bshell/compile.h>
|
#include <bshell/compile.h>
|
||||||
@@ -7,177 +7,183 @@
|
|||||||
#include <bshell/parse/lex.h>
|
#include <bshell/parse/lex.h>
|
||||||
#include <bshell/parse/parse.h>
|
#include <bshell/parse/parse.h>
|
||||||
#include <bshell/parse/token.h>
|
#include <bshell/parse/token.h>
|
||||||
#include <bshell/runtime/runtime.h>
|
|
||||||
#include <bshell/verb.h>
|
#include <bshell/verb.h>
|
||||||
|
#include <fx/cmdline/cmd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if BSHELL_INTERACTIVE == 1
|
enum {
|
||||||
#include "line-ed/line-ed.h"
|
CMD_ROOT,
|
||||||
#endif
|
OPT_LEX,
|
||||||
|
OPT_PARSE,
|
||||||
|
OPT_EVAL,
|
||||||
|
OPT_PRINT_LEX,
|
||||||
|
OPT_PRINT_AST,
|
||||||
|
OPT_PRINT_BYTECODE,
|
||||||
|
ARG_SCRIPT_FILE,
|
||||||
|
};
|
||||||
|
|
||||||
extern const fx_assembly *bshell_assembly_get(void);
|
#define FEATURE_FLAGS \
|
||||||
extern const fx_assembly *bshell_runtime_assembly_get(void);
|
(FRONTEND_F_ENABLE_LEX | FRONTEND_F_ENABLE_PARSE \
|
||||||
extern const fx_assembly *bshell_core_assembly_get(void);
|
| FRONTEND_F_ENABLE_EVAL)
|
||||||
|
#define PRINT_FLAGS \
|
||||||
|
(FRONTEND_F_PRINT_LEX | FRONTEND_F_PRINT_AST \
|
||||||
|
| FRONTEND_F_PRINT_BYTECODE)
|
||||||
|
|
||||||
static void print_token_queue(fx_queue *q)
|
const char *exec_name = NULL;
|
||||||
|
|
||||||
|
static enum frontend_flags collect_frontend_flags(const fx_arglist *opt)
|
||||||
{
|
{
|
||||||
fx_queue_entry *cur = fx_queue_first(q);
|
enum frontend_flags result = 0;
|
||||||
while (cur) {
|
#define OPTION_IS_SET(id) \
|
||||||
struct bshell_lex_token *tok
|
fx_arglist_get_count(opt, id, FX_COMMAND_INVALID_ID) > 0
|
||||||
= fx_unbox(struct bshell_lex_token, cur, tok_entry);
|
|
||||||
print_lex_token(tok);
|
|
||||||
cur = fx_queue_next(cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lex_only(struct bshell_lex_ctx *lex)
|
if (OPTION_IS_SET(OPT_LEX)) {
|
||||||
{
|
result |= FRONTEND_F_ENABLE_LEX;
|
||||||
while (1) {
|
|
||||||
struct bshell_lex_token *tok = bshell_lex_ctx_peek(lex);
|
|
||||||
if (!tok) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bshell_lex_ctx_discard(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 void lex_and_parse(struct bshell_parse_ctx *parse)
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BSHELL_VERBOSE == 1
|
FX_COMMAND(CMD_ROOT, FX_COMMAND_INVALID_ID)
|
||||||
static void lex_token_scanned(
|
|
||||||
struct bshell_lex_ctx *ctx,
|
|
||||||
struct bshell_lex_token *tok)
|
|
||||||
{
|
{
|
||||||
print_lex_token(tok);
|
FX_COMMAND_NAME("bshell");
|
||||||
}
|
FX_COMMAND_DESC("B Shell script interpreter.");
|
||||||
#endif
|
FX_COMMAND_FUNCTION(bshell);
|
||||||
|
|
||||||
extern int compare_token_types(unsigned int a, unsigned int b);
|
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)
|
int main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
bshell_assembly_get();
|
exec_name = argv[0];
|
||||||
bshell_runtime_assembly_get();
|
return fx_command_dispatch(CMD_ROOT, argc, argv);
|
||||||
bshell_core_assembly_get();
|
|
||||||
|
|
||||||
bshell_init_all_verbs();
|
|
||||||
bshell_table_init();
|
|
||||||
|
|
||||||
struct bshell_file *file = NULL;
|
|
||||||
struct line_ed *ed = NULL;
|
|
||||||
struct bshell_line_source *linesrc = NULL;
|
|
||||||
|
|
||||||
enum bshell_status status = BSHELL_SUCCESS;
|
|
||||||
bool interactive = true;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
status = bshell_file_open(argv[1], &file);
|
|
||||||
linesrc = &file->f_base;
|
|
||||||
interactive = false;
|
|
||||||
|
|
||||||
if (!FX_OK(status)) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: cannot open '%s': %s\n",
|
|
||||||
argv[0],
|
|
||||||
argv[1],
|
|
||||||
bshell_status_get_description(status));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#if BSHELL_INTERACTIVE == 1
|
|
||||||
ed = line_ed_create();
|
|
||||||
linesrc = line_ed_to_line_source(ed);
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "Interactive mode is not supported.\n");
|
|
||||||
return -1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bshell_lex_ctx lex = {0};
|
|
||||||
bshell_lex_ctx_init(&lex, 0, linesrc);
|
|
||||||
#if BSHELL_VERBOSE == 1
|
|
||||||
lex.lex_token_scanned = lex_token_scanned;
|
|
||||||
#endif
|
|
||||||
struct bshell_parse_ctx parse = {0};
|
|
||||||
bshell_parse_ctx_init(&parse, &lex);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
lex_only(&lex);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (interactive) {
|
|
||||||
printf("B Shell " BSHELL_VERSION "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bshell_scriptblock *block = bshell_scriptblock_create();
|
|
||||||
struct bshell_runtime *rt = bshell_runtime_create();
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
struct bshell_ast_node *node
|
|
||||||
= bshell_parse_ctx_read_node(&parse);
|
|
||||||
if (!node) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if BSHELL_VERBOSE == 1
|
|
||||||
print_ast_node_recursive(node);
|
|
||||||
printf("----\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bshell_scriptblock_clear_text(block);
|
|
||||||
switch (node->n_type) {
|
|
||||||
case BSHELL_AST_FUNC: {
|
|
||||||
bshell_function *func = NULL;
|
|
||||||
bshell_compile_function(node, &func);
|
|
||||||
#if BSHELL_VERBOSE == 1
|
|
||||||
print_function(func);
|
|
||||||
#endif
|
|
||||||
bshell_runtime_define_function(rt, func);
|
|
||||||
bshell_function_unref(func);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
bshell_compile(node, block);
|
|
||||||
#if BSHELL_VERBOSE == 1
|
|
||||||
print_scriptblock(block, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fx_value result = bshell_runtime_eval_global(rt, block);
|
|
||||||
|
|
||||||
if (interactive && result.v_type != NULL) {
|
|
||||||
format_value_default(&result, fx_stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
fx_value_unset(&result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bshell_ast_node_destroy(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
bshell_runtime_destroy(rt);
|
|
||||||
bshell_scriptblock_unref(block);
|
|
||||||
|
|
||||||
bshell_parse_ctx_cleanup(&parse);
|
|
||||||
bshell_lex_ctx_cleanup(&lex);
|
|
||||||
|
|
||||||
#if BSHELL_INTERACTIVE == 1
|
|
||||||
if (ed) {
|
|
||||||
line_ed_destroy(ed);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
bshell_file_close(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bshell_cleanup_all_verbs();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user