diff --git a/CMakeLists.txt b/CMakeLists.txt index 61889b1..6083c12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,34 +17,8 @@ execute_process( COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/build-id.py OUTPUT_VARIABLE bshell_version) - -set(source_dirs - ast compile parse parse/lex parse/syntax - runtime format command cmdlets aliases) - -if (bshell_interactive EQUAL 1) - message(STATUS "Interactive support: Enabled") - set(source_dirs ${source_dirs} line-ed) -else () - message(STATUS "Interactive support: Disabled") -endif () - -file(GLOB bshell_sources - bshell/*.c - bshell/*.h) - -foreach (d ${source_dirs}) - file(GLOB sources - bshell/${d}/*.c - bshell/${d}/*.h) - set(bshell_sources ${bshell_sources} ${sources}) -endforeach (d) - message(STATUS "B Shell version: ${bshell_version}") -add_executable(bshell ${bshell_sources}) - -target_link_libraries(bshell FX::Runtime FX::Collections FX::Term) -target_compile_definitions(bshell PUBLIC - BSHELL_VERSION="${bshell_version}" - BSHELL_INTERACTIVE=${bshell_interactive}) +add_subdirectory(bshell) +add_subdirectory(bshell.runtime) +add_subdirectory(bshell.core) diff --git a/bshell.core/CMakeLists.txt b/bshell.core/CMakeLists.txt new file mode 100644 index 0000000..b6ad822 --- /dev/null +++ b/bshell.core/CMakeLists.txt @@ -0,0 +1,20 @@ +set(source_dirs aliases cmdlets) + +file(GLOB sources + *.c + *.h) + +foreach (d ${source_dirs}) + file(GLOB d_sources + ${d}/*.c + ${d}/*.h) + set(sources ${sources} ${d_sources}) +endforeach (d) + +message(STATUS ${sources}) +add_library(bshell.core SHARED ${sources}) + +target_link_libraries(bshell.core bshell.runtime FX::Runtime FX::Collections FX::Term) +target_include_directories(bshell.core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_compile_definitions(bshell.core PUBLIC + BSHELL_VERSION="${bshell_version}") diff --git a/bshell/aliases/echo.c b/bshell.core/aliases/echo.c similarity index 94% rename from bshell/aliases/echo.c rename to bshell.core/aliases/echo.c index 8193124..3294fbb 100644 --- a/bshell/aliases/echo.c +++ b/bshell.core/aliases/echo.c @@ -1,6 +1,5 @@ -#include "../command/alias.h" -#include "../command/command.h" - +#include +#include #include #include #include diff --git a/bshell/aliases/percent.c b/bshell.core/aliases/percent.c similarity index 94% rename from bshell/aliases/percent.c rename to bshell.core/aliases/percent.c index 894b216..29a2228 100644 --- a/bshell/aliases/percent.c +++ b/bshell.core/aliases/percent.c @@ -1,6 +1,5 @@ -#include "../command/alias.h" -#include "../command/command.h" - +#include +#include #include #include #include diff --git a/bshell.core/assembly.c b/bshell.core/assembly.c new file mode 100644 index 0000000..9625b54 --- /dev/null +++ b/bshell.core/assembly.c @@ -0,0 +1,22 @@ +#include +#include + +FX_ASSEMBLY_BEGIN(bshell_core) + FX_ASSEMBLY_NAME("bshell.core"); + FX_ASSEMBLY_VERSION(0, 1, 0, 0); + FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "get_verb", bshell_get_verb); + FX_ASSEMBLY_EXPORT_TYPE( + "bshell.core", + "write_output", + bshell_write_output); + FX_ASSEMBLY_EXPORT_TYPE( + "bshell.core", + "foreach_object", + bshell_foreach_object); + FX_ASSEMBLY_EXPORT_TYPE( + "bshell.core", + "get_command", + bshell_get_command); + FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "percent", bshell_percent); + FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "echo", bshell_echo); +FX_ASSEMBLY_END(bshell_core) diff --git a/bshell/cmdlets/foreach-object.c b/bshell.core/cmdlets/foreach-object.c similarity index 83% rename from bshell/cmdlets/foreach-object.c rename to bshell.core/cmdlets/foreach-object.c index dff3a27..39bd5ae 100644 --- a/bshell/cmdlets/foreach-object.c +++ b/bshell.core/cmdlets/foreach-object.c @@ -1,10 +1,9 @@ -#include "../command/cmdlet.h" -#include "../command/command.h" -#include "../runtime/pipeline.h" -#include "../runtime/runtime.h" -#include "../script-block.h" -#include "../status.h" - +#include +#include +#include +#include +#include +#include #include #include #include @@ -24,9 +23,8 @@ struct bshell_foreach_object_p { static enum bshell_status begin_processing(bshell_cmdlet *cmdlet) { - struct bshell_foreach_object_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_FOREACH_OBJECT); + struct bshell_foreach_object_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_FOREACH_OBJECT); const fx_value *block_v = bshell_command_get_arg(cmdlet, 1); if (!block_v) { @@ -42,9 +40,8 @@ static enum bshell_status process_record( bshell_pipeline *pipeline, struct bshell_runtime *rt) { - struct bshell_foreach_object_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_FOREACH_OBJECT); + struct bshell_foreach_object_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_FOREACH_OBJECT); fx_value in = bshell_pipeline_read_value(pipeline); if (!fx_value_is_set(&in)) { @@ -65,9 +62,8 @@ static enum bshell_status process_record( static enum bshell_status end_processing(bshell_cmdlet *cmdlet) { - struct bshell_foreach_object_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_FOREACH_OBJECT); + struct bshell_foreach_object_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_FOREACH_OBJECT); return BSHELL_SUCCESS; } diff --git a/bshell/cmdlets/format-table.c b/bshell.core/cmdlets/format-table.c similarity index 84% rename from bshell/cmdlets/format-table.c rename to bshell.core/cmdlets/format-table.c index 8c78e40..29cd224 100644 --- a/bshell/cmdlets/format-table.c +++ b/bshell.core/cmdlets/format-table.c @@ -1,5 +1,4 @@ -#include "../status.h" - +#include #include #include diff --git a/bshell/cmdlets/get-command.c b/bshell.core/cmdlets/get-command.c similarity index 57% rename from bshell/cmdlets/get-command.c rename to bshell.core/cmdlets/get-command.c index ae4df48..8a09323 100644 --- a/bshell/cmdlets/get-command.c +++ b/bshell.core/cmdlets/get-command.c @@ -1,10 +1,9 @@ -#include "../command/cmdlet.h" -#include "../command/command.h" -#include "../runtime/pipeline.h" -#include "../runtime/runtime.h" -#include "../runtime/scope.h" -#include "../status.h" - +#include +#include +#include +#include +#include +#include #include #include #include @@ -23,13 +22,10 @@ struct bshell_get_command_p { bool c_eof; }; -extern const fx_assembly *bshell_assembly_get(void); - static enum bshell_status begin_processing(bshell_cmdlet *cmdlet) { - struct bshell_get_command_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_GET_COMMAND); + struct bshell_get_command_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_GET_COMMAND); return BSHELL_SUCCESS; } @@ -38,66 +34,73 @@ static enum bshell_status process_record( bshell_pipeline *pipeline, struct bshell_runtime *rt) { - struct bshell_get_command_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_GET_COMMAND); + struct bshell_get_command_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_GET_COMMAND); if (p->c_eof) { return BSHELL_SUCCESS; } - fx_iterator *it = fx_iterator_begin(rt->rt_aliases); - fx_foreach(item_v, it) + fx_iterator *aliases = fx_iterator_begin(rt->rt_aliases); + fx_foreach(item_v, aliases) { fx_hashtable_item *item; fx_value_get_object(&item_v, &item); fx_value alias_v = fx_hashtable_item_get_value(item); bshell_pipeline_write_value(pipeline, alias_v, false); } - fx_iterator_unref(it); + fx_iterator_unref(aliases); - fx_queue_entry *cur = fx_queue_last(&rt->rt_scope); - while (cur) { - struct runtime_scope *scope = fx_unbox( - struct runtime_scope, - cur, - s_entry); - - it = fx_iterator_begin(scope->s_functions); - fx_foreach(item_v, it) + struct bshell_runtime_scope *scope + = bshell_runtime_get_current_scope(rt); + while (scope) { + fx_hashtable *function_map + = bshell_runtime_scope_get_functions(scope); + fx_iterator *functions = fx_iterator_begin(function_map); + fx_foreach(item_v, functions) { fx_hashtable_item *item; fx_value_get_object(&item_v, &item); fx_value func_v = fx_hashtable_item_get_value(item); bshell_pipeline_write_value(pipeline, func_v, false); } - fx_iterator_unref(it); + fx_iterator_unref(functions); - cur = fx_queue_prev(cur); + scope = bshell_runtime_get_parent_scope(rt, scope); } - const fx_assembly *self = bshell_assembly_get(); - it = fx_assembly_get_types(self); - fx_foreach(v, it) + fx_iterator *assemblies = fx_assembly_get_all(); + fx_foreach(asm_v, assemblies) { - fx_type *ty = NULL; - fx_value_get_object(&v, &ty); - if (fx_type_id_compare(fx_type_get_id(ty), BSHELL_TYPE_CMDLET) - == 0) { - continue; - } - bshell_command_class *cmd = fx_type_get_interface( - ty, - BSHELL_TYPE_COMMAND); - if (!cmd) { - continue; + fx_assembly *assembly = NULL; + fx_value_get_object(&asm_v, &assembly); + fx_iterator *types = fx_assembly_get_types(assembly); + fx_foreach(v, types) + { + fx_type *ty = NULL; + fx_value_get_object(&v, &ty); + fx_type_flags ty_flags = fx_type_get_flags(ty); + bool is_abstract = (ty_flags & FX_TYPE_F_ABSTRACT) != 0; + if (is_abstract) { + continue; + } + + bshell_command_class *cmd = fx_type_get_interface( + ty, + BSHELL_TYPE_COMMAND); + if (!cmd) { + continue; + } + + fx_value callable = FX_VALUE_OBJECT( + fx_object_create(fx_type_get_id(ty))); + bshell_pipeline_write_value(pipeline, callable, false); + fx_value_unset(&callable); } - fx_value callable = FX_VALUE_OBJECT( - fx_object_create(fx_type_get_id(ty))); - bshell_pipeline_write_value(pipeline, callable, false); - fx_value_unset(&callable); + fx_iterator_unref(types); } - fx_iterator_unref(it); + + fx_iterator_unref(assemblies); p->c_eof = true; return BSHELL_SUCCESS; @@ -105,9 +108,8 @@ static enum bshell_status process_record( static enum bshell_status end_processing(bshell_cmdlet *cmdlet) { - struct bshell_get_command_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_GET_COMMAND); + struct bshell_get_command_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_GET_COMMAND); return BSHELL_SUCCESS; } diff --git a/bshell/cmdlets/get-verb.c b/bshell.core/cmdlets/get-verb.c similarity index 86% rename from bshell/cmdlets/get-verb.c rename to bshell.core/cmdlets/get-verb.c index a8f6760..659556d 100644 --- a/bshell/cmdlets/get-verb.c +++ b/bshell.core/cmdlets/get-verb.c @@ -1,8 +1,7 @@ -#include "../command/cmdlet.h" -#include "../command/command.h" -#include "../runtime/pipeline.h" -#include "../status.h" - +#include +#include +#include +#include #include #include #include @@ -23,9 +22,8 @@ struct bshell_get_verb_p { static enum bshell_status begin_processing(bshell_cmdlet *cmdlet) { - struct bshell_get_verb_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_GET_VERB); + struct bshell_get_verb_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_GET_VERB); p->c_verbs = bshell_get_all_verbs(); p->c_it = fx_iterator_begin(p->c_verbs); return BSHELL_SUCCESS; @@ -36,9 +34,8 @@ static enum bshell_status process_record( bshell_pipeline *pipeline, struct bshell_runtime *rt) { - struct bshell_get_verb_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_GET_VERB); + struct bshell_get_verb_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_GET_VERB); do { fx_value v = fx_iterator_get_value(p->c_it); @@ -72,9 +69,8 @@ static enum bshell_status process_record( static enum bshell_status end_processing(bshell_cmdlet *cmdlet) { - struct bshell_get_verb_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_GET_VERB); + struct bshell_get_verb_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_GET_VERB); if (p->c_it) { fx_iterator_unref(p->c_it); p->c_it = NULL; diff --git a/bshell/cmdlets/write-output.c b/bshell.core/cmdlets/write-output.c similarity index 81% rename from bshell/cmdlets/write-output.c rename to bshell.core/cmdlets/write-output.c index ff05f06..4661243 100644 --- a/bshell/cmdlets/write-output.c +++ b/bshell.core/cmdlets/write-output.c @@ -1,9 +1,8 @@ -#include "../command/cmdlet.h" -#include "../command/command.h" -#include "../format/format.h" -#include "../runtime/pipeline.h" -#include "../status.h" - +#include +#include +#include +#include +#include #include #include #include @@ -20,7 +19,7 @@ FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_write_output) FX_TYPE_CLASS_DECLARATION_END(bshell_write_output) struct bshell_write_output_p { - struct table_format_ctx w_table_ctx; + struct bshell_table_ctx w_table_ctx; bool w_table_initialised; }; @@ -28,13 +27,13 @@ static void initialise_table( struct bshell_write_output_p *cmd, const fx_value *first_record) { - table_format_ctx_init(&cmd->w_table_ctx, fx_stdout); + bshell_table_ctx_init(&cmd->w_table_ctx, fx_stdout); const fx_type *ty = fx_type_get_by_id(first_record->v_type); - table_format_ctx_prepare_columns_from_format( + bshell_table_ctx_prepare_columns_from_format( &cmd->w_table_ctx, ty, NULL); - table_format_ctx_print_headers(&cmd->w_table_ctx); + bshell_table_ctx_print_headers(&cmd->w_table_ctx); cmd->w_table_initialised = true; } @@ -66,14 +65,13 @@ static void write_value( initialise_table(cmd, value); } - table_format_ctx_print_record(&cmd->w_table_ctx, value); + bshell_table_ctx_print_record(&cmd->w_table_ctx, value); } static enum bshell_status begin_processing(bshell_cmdlet *cmdlet) { - struct bshell_write_output_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_WRITE_OUTPUT); + struct bshell_write_output_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_WRITE_OUTPUT); for (size_t i = 1;; i++) { const fx_value *v = bshell_command_get_arg(cmdlet, i); if (!v) { @@ -91,9 +89,8 @@ static enum bshell_status process_record( bshell_pipeline *pipeline, struct bshell_runtime *rt) { - struct bshell_write_output_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_WRITE_OUTPUT); + struct bshell_write_output_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_WRITE_OUTPUT); fx_value in = bshell_pipeline_read_value(pipeline); if (fx_value_is_set(&in)) { @@ -106,9 +103,8 @@ static enum bshell_status process_record( static enum bshell_status end_processing(bshell_cmdlet *cmdlet) { - struct bshell_write_output_p *p = fx_object_get_private( - cmdlet, - BSHELL_TYPE_WRITE_OUTPUT); + struct bshell_write_output_p *p + = fx_object_get_private(cmdlet, BSHELL_TYPE_WRITE_OUTPUT); return BSHELL_SUCCESS; } diff --git a/bshell.runtime/CMakeLists.txt b/bshell.runtime/CMakeLists.txt new file mode 100644 index 0000000..49e06ff --- /dev/null +++ b/bshell.runtime/CMakeLists.txt @@ -0,0 +1,22 @@ +set(source_dirs + ast compile parse parse/lex parse/syntax + format runtime command) + +file(GLOB sources + *.c + *.h) + +foreach (d ${source_dirs}) + file(GLOB d_sources + ${d}/*.c + ${d}/*.h) + set(sources ${sources} ${d_sources}) +endforeach (d) + +message(STATUS ${sources}) +add_library(bshell.runtime SHARED ${sources}) + +target_link_libraries(bshell.runtime FX::Runtime FX::Collections FX::Term) +target_include_directories(bshell.runtime PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_compile_definitions(bshell.runtime PUBLIC + BSHELL_VERSION="${bshell_version}") diff --git a/bshell.runtime/assembly.c b/bshell.runtime/assembly.c new file mode 100644 index 0000000..7e4c750 --- /dev/null +++ b/bshell.runtime/assembly.c @@ -0,0 +1,16 @@ +#include +#include + +FX_ASSEMBLY_BEGIN(bshell_runtime) + FX_ASSEMBLY_NAME("bshell.runtime"); + FX_ASSEMBLY_VERSION(0, 1, 0, 0); + FX_ASSEMBLY_EXPORT_TYPE("bshell.runtime", "command", bshell_command); + FX_ASSEMBLY_EXPORT_TYPE("bshell.runtime", "alias", bshell_alias); + // FX_ASSEMBLY_EXPORT_TYPE("bshell.runtime", "function", + // bshell_function); + FX_ASSEMBLY_EXPORT_TYPE("bshell.runtime", "cmdlet", bshell_cmdlet); + FX_ASSEMBLY_EXPORT_TYPE( + "bshell.runtime", + "scriptblock", + bshell_scriptblock); +FX_ASSEMBLY_END(bshell_runtime) diff --git a/bshell.runtime/ast/array.c b/bshell.runtime/ast/array.c new file mode 100644 index 0000000..9181078 --- /dev/null +++ b/bshell.runtime/ast/array.c @@ -0,0 +1,28 @@ +#include +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_array_ast_node *array = (struct bshell_array_ast_node *) + node; + + fx_queue_entry *cur = fx_queue_first(&array->n_items); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition array_bshell_ast_node = { + .def_id = BSHELL_AST_ARRAY, + .def_node_size = sizeof(struct bshell_array_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/ast.c b/bshell.runtime/ast/ast.c new file mode 100644 index 0000000..80a0b8a --- /dev/null +++ b/bshell.runtime/ast/ast.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include + +extern struct bshell_ast_node_definition null_bshell_ast_node; +extern struct bshell_ast_node_definition int_bshell_ast_node; +extern struct bshell_ast_node_definition double_bshell_ast_node; +extern struct bshell_ast_node_definition word_bshell_ast_node; +extern struct bshell_ast_node_definition var_bshell_ast_node; +extern struct bshell_ast_node_definition string_bshell_ast_node; +extern struct bshell_ast_node_definition fstring_bshell_ast_node; +extern struct bshell_ast_node_definition cmdcall_bshell_ast_node; +extern struct bshell_ast_node_definition pipeline_bshell_ast_node; +extern struct bshell_ast_node_definition redirection_bshell_ast_node; +extern struct bshell_ast_node_definition block_bshell_ast_node; +extern struct bshell_ast_node_definition stmt_list_bshell_ast_node; +extern struct bshell_ast_node_definition func_bshell_ast_node; +extern struct bshell_ast_node_definition array_bshell_ast_node; +extern struct bshell_ast_node_definition hashtable_bshell_ast_node; +extern struct bshell_ast_node_definition hashtable_item_bshell_ast_node; +extern struct bshell_ast_node_definition if_bshell_ast_node; +extern struct bshell_ast_node_definition if_branch_bshell_ast_node; +extern struct bshell_ast_node_definition op_bshell_ast_node; + +static const struct bshell_ast_node_definition *bshell_ast_node_definitions[] + = { + [BSHELL_AST_NULL] = &null_bshell_ast_node, + [BSHELL_AST_INT] = &int_bshell_ast_node, + [BSHELL_AST_DOUBLE] = &double_bshell_ast_node, + [BSHELL_AST_WORD] = &word_bshell_ast_node, + [BSHELL_AST_VAR] = &var_bshell_ast_node, + [BSHELL_AST_STRING] = &string_bshell_ast_node, + [BSHELL_AST_FSTRING] = &fstring_bshell_ast_node, + [BSHELL_AST_CMDCALL] = &cmdcall_bshell_ast_node, + [BSHELL_AST_PIPELINE] = &pipeline_bshell_ast_node, + [BSHELL_AST_REDIRECTION] = &redirection_bshell_ast_node, + [BSHELL_AST_BLOCK] = &block_bshell_ast_node, + [BSHELL_AST_STMT_LIST] = &stmt_list_bshell_ast_node, + [BSHELL_AST_FUNC] = &func_bshell_ast_node, + [BSHELL_AST_ARRAY] = &array_bshell_ast_node, + [BSHELL_AST_IF] = &if_bshell_ast_node, + [BSHELL_AST_IF_BRANCH] = &if_branch_bshell_ast_node, + [BSHELL_AST_HASHTABLE] = &hashtable_bshell_ast_node, + [BSHELL_AST_HASHTABLE_ITEM] = &hashtable_item_bshell_ast_node, + [BSHELL_AST_OP] = &op_bshell_ast_node, +}; +static const size_t nr_bshell_ast_node_definitions + = sizeof bshell_ast_node_definitions + / sizeof bshell_ast_node_definitions[0]; + +struct bshell_ast_node *bshell_ast_node_create(enum bshell_ast_node_type type) +{ + assert(type < nr_bshell_ast_node_definitions); + + const struct bshell_ast_node_definition *def + = bshell_ast_node_definitions[type]; + struct bshell_ast_node *out = malloc(def->def_node_size); + if (!out) { + return NULL; + } + + memset(out, 0x0, def->def_node_size); + + out->n_type = type; + + return out; +} + +void bshell_ast_node_destroy(struct bshell_ast_node *node) +{ + assert(node->n_type < nr_bshell_ast_node_definitions); + + struct bshell_ast_iterator it = {0}; + bshell_ast_iterator_enqueue(&it, node); + + while (1) { + node = bshell_ast_iterator_peek(&it); + if (!node) { + break; + } + + const struct bshell_ast_node_definition *def + = bshell_ast_node_definitions[node->n_type]; + + if (def->def_cleanup) { + def->def_cleanup(node); + } + + bshell_ast_iterator_dequeue(&it); + free(node); + } +} + +void bshell_ast_node_to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + const struct bshell_ast_node_definition *def + = bshell_ast_node_definitions[node->n_type]; + if (def->def_to_string) { + def->def_to_string(node, out); + } +} + +#define ENUM_STR(x) \ + case x: \ + return #x + +const char *bshell_ast_node_type_to_string(enum bshell_ast_node_type type) +{ + switch (type) { + ENUM_STR(BSHELL_AST_NONE); + ENUM_STR(BSHELL_AST_NULL); + ENUM_STR(BSHELL_AST_STMT_LIST); + ENUM_STR(BSHELL_AST_INT); + ENUM_STR(BSHELL_AST_DOUBLE); + ENUM_STR(BSHELL_AST_WORD); + ENUM_STR(BSHELL_AST_STRING); + ENUM_STR(BSHELL_AST_FSTRING); + ENUM_STR(BSHELL_AST_VAR); + ENUM_STR(BSHELL_AST_VAR_SPLAT); + ENUM_STR(BSHELL_AST_FLAG); + ENUM_STR(BSHELL_AST_CMDCALL); + ENUM_STR(BSHELL_AST_PIPELINE); + ENUM_STR(BSHELL_AST_REDIRECTION); + ENUM_STR(BSHELL_AST_BLOCK); + ENUM_STR(BSHELL_AST_FUNC); + ENUM_STR(BSHELL_AST_IF); + ENUM_STR(BSHELL_AST_IF_BRANCH); + ENUM_STR(BSHELL_AST_OP); + ENUM_STR(BSHELL_AST_ARRAY); + ENUM_STR(BSHELL_AST_HASHTABLE); + ENUM_STR(BSHELL_AST_HASHTABLE_ITEM); + default: + return ""; + } +} + +struct bshell_ast_node *bshell_ast_iterator_peek(struct bshell_ast_iterator *it) +{ + fx_queue_entry *cur = fx_queue_first(&it->it_queue); + if (!cur) { + return NULL; + } + + return fx_unbox(struct bshell_ast_node, cur, n_it.e_entry); +} + +struct bshell_ast_node *bshell_ast_iterator_dequeue( + struct bshell_ast_iterator *it) +{ + fx_queue_entry *cur = fx_queue_first(&it->it_queue); + if (!cur) { + return NULL; + } + + struct bshell_ast_node *node = fx_unbox( + struct bshell_ast_node, + cur, + n_it.e_entry); + const struct bshell_ast_node_definition *def + = bshell_ast_node_definitions[node->n_type]; + + it->it_insert_after = cur; + if (def->def_collect_children) { + def->def_collect_children(node, it); + } + + fx_queue_pop_front(&it->it_queue); + return fx_unbox(struct bshell_ast_node, cur, n_it.e_entry); +} + +void bshell_ast_iterator_enqueue( + struct bshell_ast_iterator *it, + struct bshell_ast_node *node) +{ + unsigned long new_depth = 0; + + fx_queue_entry *cur = fx_queue_first(&it->it_queue); + if (cur) { + struct bshell_ast_node *cur_node = fx_unbox( + struct bshell_ast_node, + cur, + n_it.e_entry); + new_depth = cur_node->n_it.e_depth + 1; + } + + node->n_it.e_depth = new_depth; + + if (!it->it_insert_after) { + fx_queue_push_back(&it->it_queue, &node->n_it.e_entry); + return; + } + + fx_queue_insert_after( + &it->it_queue, + &node->n_it.e_entry, + it->it_insert_after); + it->it_insert_after = &node->n_it.e_entry; +} + +enum bshell_status bshell_ast_node_iterate( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it, + bshell_ast_iterator_callback callback, + void *arg) +{ + fx_queue_push_back(&it->it_queue, &node->n_it.e_entry); + node->n_it.e_depth = 0; + + fx_queue_entry *entry = fx_queue_first(&it->it_queue); + + while (entry) { + struct bshell_ast_iterator_entry *it_entry = fx_unbox( + struct bshell_ast_iterator_entry, + entry, + e_entry); + node = fx_unbox(struct bshell_ast_node, it_entry, n_it); + + if (!node) { + /* this should never happen. */ + return BSHELL_ERR_INTERNAL_FAILURE; + } + + struct bshell_ast_iterate_result result = callback( + node, + BSHELL_AST_ITERATION_PRE, + it, + arg); + if (result.r_status != BSHELL_SUCCESS + || result.r_flags & BSHELL_AST_ITERATE_STOP) { + return result.r_status; + } + + const struct bshell_ast_node_definition *type + = bshell_ast_node_definitions[node->n_type]; + if (type->def_collect_children + && result.r_flags & BSHELL_AST_ITERATE_ADD_CHILDREN) { + it->it_insert_after = entry; + type->def_collect_children(node, it); + } + + if (!(result.r_flags & BSHELL_AST_ITERATE_REPEAT)) { + entry = fx_queue_next(entry); + } + } + + while (!fx_queue_empty(&it->it_queue)) { + fx_queue_entry *entry = fx_queue_last(&it->it_queue); + if (!entry) { + break; + } + + node = fx_unbox(struct bshell_ast_node, entry, n_it); + + if (!node) { + /* this should never happen. */ + return BSHELL_ERR_INTERNAL_FAILURE; + } + + struct bshell_ast_iterate_result result = callback( + node, + BSHELL_AST_ITERATION_POST, + it, + arg); + if (result.r_status != BSHELL_SUCCESS + || result.r_flags & BSHELL_AST_ITERATE_STOP) { + return result.r_status; + } + + if (!(result.r_flags & BSHELL_AST_ITERATE_REPEAT)) { + fx_queue_pop_back(&it->it_queue); + } + } + + return BSHELL_SUCCESS; +} diff --git a/bshell.runtime/ast/block.c b/bshell.runtime/ast/block.c new file mode 100644 index 0000000..0266a67 --- /dev/null +++ b/bshell.runtime/ast/block.c @@ -0,0 +1,26 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_block_ast_node *block = (struct bshell_block_ast_node *) + node; + fx_queue_entry *cur = fx_queue_first(&block->n_statements); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition block_bshell_ast_node = { + .def_id = BSHELL_AST_BLOCK, + .def_node_size = sizeof(struct bshell_block_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/cmdcall.c b/bshell.runtime/ast/cmdcall.c new file mode 100644 index 0000000..3904f77 --- /dev/null +++ b/bshell.runtime/ast/cmdcall.c @@ -0,0 +1,37 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_cmdcall_ast_node *cmdcall = (struct + bshell_cmdcall_ast_node *) + node; + fx_queue_entry *cur = fx_queue_first(&cmdcall->n_args); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + cur = fx_queue_first(&cmdcall->n_redirect); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition cmdcall_bshell_ast_node = { + .def_id = BSHELL_AST_CMDCALL, + .def_node_size = sizeof(struct bshell_cmdcall_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/double.c b/bshell.runtime/ast/double.c new file mode 100644 index 0000000..854c372 --- /dev/null +++ b/bshell.runtime/ast/double.c @@ -0,0 +1,16 @@ +#include +#include +#include + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + struct bshell_double_ast_node *i = (struct bshell_double_ast_node *) + node; + fx_value_to_string(&i->n_value->tok_number, (fx_stream *)out, NULL); +} + +struct bshell_ast_node_definition double_bshell_ast_node = { + .def_id = BSHELL_AST_DOUBLE, + .def_node_size = sizeof(struct bshell_double_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell.runtime/ast/fstring.c b/bshell.runtime/ast/fstring.c new file mode 100644 index 0000000..40b09e2 --- /dev/null +++ b/bshell.runtime/ast/fstring.c @@ -0,0 +1,26 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_fstring_ast_node *fstring; + fstring = (struct bshell_fstring_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&fstring->n_elements); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition fstring_bshell_ast_node = { + .def_id = BSHELL_AST_FSTRING, + .def_node_size = sizeof(struct bshell_fstring_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/func.c b/bshell.runtime/ast/func.c new file mode 100644 index 0000000..6564ddc --- /dev/null +++ b/bshell.runtime/ast/func.c @@ -0,0 +1,39 @@ +#include +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_func_ast_node *func = (struct bshell_func_ast_node *)node; + + fx_queue_entry *cur = fx_queue_first(&func->n_params); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + if (func->n_body) { + bshell_ast_iterator_enqueue(it, func->n_body); + } + + return BSHELL_SUCCESS; +} + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + const struct bshell_func_ast_node *func = (const struct + bshell_func_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%s", func->n_name->tok_str); +} + +struct bshell_ast_node_definition func_bshell_ast_node = { + .def_id = BSHELL_AST_FUNC, + .def_node_size = sizeof(struct bshell_func_ast_node), + .def_collect_children = collect_children, + .def_to_string = to_string, +}; diff --git a/bshell.runtime/ast/hashtable-item.c b/bshell.runtime/ast/hashtable-item.c new file mode 100644 index 0000000..bb54e0a --- /dev/null +++ b/bshell.runtime/ast/hashtable-item.c @@ -0,0 +1,26 @@ +#include +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_hashtable_item_ast_node *item + = (struct bshell_hashtable_item_ast_node *)node; + + if (item->n_key) { + bshell_ast_iterator_enqueue(it, item->n_key); + } + + if (item->n_value) { + bshell_ast_iterator_enqueue(it, item->n_value); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition hashtable_item_bshell_ast_node = { + .def_id = BSHELL_AST_HASHTABLE_ITEM, + .def_node_size = sizeof(struct bshell_hashtable_item_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/hashtable.c b/bshell.runtime/ast/hashtable.c new file mode 100644 index 0000000..64563f5 --- /dev/null +++ b/bshell.runtime/ast/hashtable.c @@ -0,0 +1,24 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_hashtable_ast_node *hashtable + = (struct bshell_hashtable_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&hashtable->n_items); + while (cur) { + struct bshell_ast_node *child + = fx_unbox(struct bshell_ast_node, cur, n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition hashtable_bshell_ast_node = { + .def_id = BSHELL_AST_HASHTABLE, + .def_node_size = sizeof(struct bshell_hashtable_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/if-branch.c b/bshell.runtime/ast/if-branch.c new file mode 100644 index 0000000..a7d0d29 --- /dev/null +++ b/bshell.runtime/ast/if-branch.c @@ -0,0 +1,24 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_if_branch_ast_node *if_branch + = (struct bshell_if_branch_ast_node *)node; + if (if_branch->n_cond) { + bshell_ast_iterator_enqueue(it, if_branch->n_cond); + } + + if (if_branch->n_body) { + bshell_ast_iterator_enqueue(it, if_branch->n_body); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition if_branch_bshell_ast_node = { + .def_id = BSHELL_AST_IF_BRANCH, + .def_node_size = sizeof(struct bshell_if_branch_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/if.c b/bshell.runtime/ast/if.c new file mode 100644 index 0000000..356f589 --- /dev/null +++ b/bshell.runtime/ast/if.c @@ -0,0 +1,23 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_if_ast_node *if_group = (struct bshell_if_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&if_group->n_branches); + while (cur) { + struct bshell_ast_node *child + = fx_unbox(struct bshell_ast_node, cur, n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition if_bshell_ast_node = { + .def_id = BSHELL_AST_IF, + .def_node_size = sizeof(struct bshell_if_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/int.c b/bshell.runtime/ast/int.c new file mode 100644 index 0000000..b3daf45 --- /dev/null +++ b/bshell.runtime/ast/int.c @@ -0,0 +1,15 @@ +#include +#include +#include + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + struct bshell_int_ast_node *i = (struct bshell_int_ast_node *)node; + fx_value_to_string(&i->n_value->tok_number, (fx_stream *)out, NULL); +} + +struct bshell_ast_node_definition int_bshell_ast_node = { + .def_id = BSHELL_AST_INT, + .def_node_size = sizeof(struct bshell_int_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell.runtime/ast/null.c b/bshell.runtime/ast/null.c new file mode 100644 index 0000000..6f49905 --- /dev/null +++ b/bshell.runtime/ast/null.c @@ -0,0 +1,7 @@ +#include +#include + +struct bshell_ast_node_definition null_bshell_ast_node = { + .def_id = BSHELL_AST_NULL, + .def_node_size = sizeof(struct bshell_null_ast_node), +}; diff --git a/bshell.runtime/ast/op.c b/bshell.runtime/ast/op.c new file mode 100644 index 0000000..513310e --- /dev/null +++ b/bshell.runtime/ast/op.c @@ -0,0 +1,38 @@ +#include +#include +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_op_ast_node *op = (struct bshell_op_ast_node *)node; + + if (op->n_left) { + bshell_ast_iterator_enqueue(it, op->n_left); + } + + if (op->n_right) { + bshell_ast_iterator_enqueue(it, op->n_right); + } + + return BSHELL_SUCCESS; +} + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + const struct bshell_op_ast_node *op = (const struct bshell_op_ast_node + *)node; + fx_bstr_write_fmt( + out, + NULL, + "%s", + bshell_operator_id_to_string(op->n_op->op_id)); +} + +struct bshell_ast_node_definition op_bshell_ast_node = { + .def_id = BSHELL_AST_OP, + .def_node_size = sizeof(struct bshell_op_ast_node), + .def_collect_children = collect_children, + .def_to_string = to_string, +}; diff --git a/bshell.runtime/ast/pipeline.c b/bshell.runtime/ast/pipeline.c new file mode 100644 index 0000000..204d0f6 --- /dev/null +++ b/bshell.runtime/ast/pipeline.c @@ -0,0 +1,26 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_pipeline_ast_node *pipeline; + pipeline = (struct bshell_pipeline_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&pipeline->n_stages); + while (cur) { + struct bshell_ast_node *child = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition pipeline_bshell_ast_node = { + .def_id = BSHELL_AST_PIPELINE, + .def_node_size = sizeof(struct bshell_pipeline_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell/ast/redirection.c b/bshell.runtime/ast/redirection.c similarity index 56% rename from bshell/ast/redirection.c rename to bshell.runtime/ast/redirection.c index b60e1bc..d5ba3fd 100644 --- a/bshell/ast/redirection.c +++ b/bshell.runtime/ast/redirection.c @@ -1,23 +1,23 @@ -#include "ast.h" +#include static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) { - struct redirection_ast_node *redirection - = (struct redirection_ast_node *)node; + struct bshell_redirection_ast_node *redirection + = (struct bshell_redirection_ast_node *)node; if (redirection->n_out_path_expr) { - ast_iterator_enqueue(it, redirection->n_out_path_expr); + bshell_ast_iterator_enqueue(it, redirection->n_out_path_expr); } return BSHELL_SUCCESS; } -static void to_string(const struct ast_node *node, fx_bstr *out) +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) { - struct redirection_ast_node *redirection - = (struct redirection_ast_node *)node; + struct bshell_redirection_ast_node *redirection + = (struct bshell_redirection_ast_node *)node; fx_bstr_write_fmt(out, NULL, "&%u", redirection->n_in); if (redirection->n_append) { @@ -41,9 +41,9 @@ static void to_string(const struct ast_node *node, fx_bstr *out) } } -struct ast_node_definition redirection_ast_node = { - .def_id = AST_REDIRECTION, - .def_node_size = sizeof(struct redirection_ast_node), +struct bshell_ast_node_definition redirection_bshell_ast_node = { + .def_id = BSHELL_AST_REDIRECTION, + .def_node_size = sizeof(struct bshell_redirection_ast_node), .def_collect_children = collect_children, .def_to_string = to_string, }; diff --git a/bshell.runtime/ast/stmt-list.c b/bshell.runtime/ast/stmt-list.c new file mode 100644 index 0000000..e86887d --- /dev/null +++ b/bshell.runtime/ast/stmt-list.c @@ -0,0 +1,24 @@ +#include + +static enum bshell_status collect_children( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it) +{ + struct bshell_stmt_list_ast_node *stmt_list + = (struct bshell_stmt_list_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&stmt_list->n_statements); + while (cur) { + struct bshell_ast_node *child + = fx_unbox(struct bshell_ast_node, cur, n_entry); + bshell_ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct bshell_ast_node_definition stmt_list_bshell_ast_node = { + .def_id = BSHELL_AST_STMT_LIST, + .def_node_size = sizeof(struct bshell_stmt_list_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell.runtime/ast/string.c b/bshell.runtime/ast/string.c new file mode 100644 index 0000000..e3e46a9 --- /dev/null +++ b/bshell.runtime/ast/string.c @@ -0,0 +1,16 @@ +#include +#include + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + const struct bshell_string_ast_node *string = (const struct + bshell_string_ast_node *) + node; + fx_bstr_write_fmt(out, NULL, "%s", string->n_value->tok_str); +} + +struct bshell_ast_node_definition string_bshell_ast_node = { + .def_id = BSHELL_AST_STRING, + .def_node_size = sizeof(struct bshell_string_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell.runtime/ast/var.c b/bshell.runtime/ast/var.c new file mode 100644 index 0000000..80269ca --- /dev/null +++ b/bshell.runtime/ast/var.c @@ -0,0 +1,15 @@ +#include +#include + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + const struct bshell_var_ast_node *var = (const struct + bshell_var_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%s", var->n_ident->tok_str); +} + +struct bshell_ast_node_definition var_bshell_ast_node = { + .def_id = BSHELL_AST_VAR, + .def_node_size = sizeof(struct bshell_var_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell.runtime/ast/word.c b/bshell.runtime/ast/word.c new file mode 100644 index 0000000..f62a5d1 --- /dev/null +++ b/bshell.runtime/ast/word.c @@ -0,0 +1,15 @@ +#include +#include + +static void to_string(const struct bshell_ast_node *node, fx_bstr *out) +{ + const struct bshell_word_ast_node *word = (const struct + bshell_word_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%s", word->n_value->tok_str); +} + +struct bshell_ast_node_definition word_bshell_ast_node = { + .def_id = BSHELL_AST_WORD, + .def_node_size = sizeof(struct bshell_word_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell/command/alias.c b/bshell.runtime/command/alias.c similarity index 87% rename from bshell/command/alias.c rename to bshell.runtime/command/alias.c index dacae26..d2993e3 100644 --- a/bshell/command/alias.c +++ b/bshell.runtime/command/alias.c @@ -1,8 +1,6 @@ -#include "alias.h" - -#include "../status.h" -#include "command.h" - +#include +#include +#include #include #include #include @@ -18,9 +16,8 @@ enum bshell_status bshell_alias_get_callable_name( const bshell_alias *alias, fx_string *out) { - bshell_alias_class *c = fx_object_get_interface( - alias, - BSHELL_TYPE_ALIAS); + bshell_alias_class *c + = fx_object_get_interface(alias, BSHELL_TYPE_ALIAS); if (!c) { return BSHELL_ERR_NOT_SUPPORTED; } @@ -41,9 +38,8 @@ enum bshell_status bshell_alias_get_target_name( const bshell_alias *alias, fx_string *out) { - bshell_alias_class *c = fx_object_get_interface( - alias, - BSHELL_TYPE_ALIAS); + bshell_alias_class *c + = fx_object_get_interface(alias, BSHELL_TYPE_ALIAS); if (!c) { return BSHELL_ERR_NOT_SUPPORTED; } @@ -95,6 +91,10 @@ static enum bshell_status get_description( target_name = c->a_get_target_name(cmd); } + if (!callable_name || !target_name) { + return BSHELL_ERR_NOT_SUPPORTED; + } + fx_string_append_cstr(out, callable_name); fx_string_append_cstr(out, " -> "); fx_string_append_cstr(out, target_name); @@ -125,7 +125,8 @@ FX_TYPE_CLASS_END(bshell_alias) FX_TYPE_DEFINITION_BEGIN(bshell_alias) FX_TYPE_ID(0x1736c10e, 0xebe6, 0x4ba5, 0x83d9, 0x5da3b7dc706c); - FX_TYPE_NAME("bshell.alias"); + FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT); + FX_TYPE_NAME("bshell.runtime.alias"); FX_TYPE_EXTENDS(BSHELL_TYPE_COMMAND); FX_TYPE_CLASS(bshell_alias_class); FX_TYPE_INSTANCE_INIT(init); diff --git a/bshell/command/cmdlet.c b/bshell.runtime/command/cmdlet.c similarity index 89% rename from bshell/command/cmdlet.c rename to bshell.runtime/command/cmdlet.c index 5dd16b8..c5f838a 100644 --- a/bshell/command/cmdlet.c +++ b/bshell.runtime/command/cmdlet.c @@ -1,8 +1,6 @@ -#include "cmdlet.h" - -#include "../status.h" -#include "command.h" - +#include +#include +#include #include #include #include @@ -52,7 +50,8 @@ FX_TYPE_CLASS_END(bshell_cmdlet) FX_TYPE_DEFINITION_BEGIN(bshell_cmdlet) FX_TYPE_ID(0xc71f4d59, 0x8066, 0x4294, 0xa6b0, 0xe1f3eb04f454); - FX_TYPE_NAME("bshell.cmdlet"); + FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT); + FX_TYPE_NAME("bshell.runtime.cmdlet"); FX_TYPE_EXTENDS(BSHELL_TYPE_COMMAND); FX_TYPE_CLASS(bshell_cmdlet_class); FX_TYPE_INSTANCE_INIT(init); diff --git a/bshell/command/command.c b/bshell.runtime/command/command.c similarity index 78% rename from bshell/command/command.c rename to bshell.runtime/command/command.c index 79bbc51..13b53c5 100644 --- a/bshell/command/command.c +++ b/bshell.runtime/command/command.c @@ -1,8 +1,6 @@ -#include "command.h" - -#include "../runtime/pipeline.h" -#include "../status.h" - +#include +#include +#include #include #include #include @@ -61,9 +59,8 @@ static fx_status get_command_type( { bshell_command *cmd = NULL; fx_value_get_object(cmd_v, &cmd); - bshell_command_class *cmd_class = fx_object_get_interface( - cmd, - BSHELL_TYPE_COMMAND); + bshell_command_class *cmd_class + = fx_object_get_interface(cmd, BSHELL_TYPE_COMMAND); *out = FX_CSTR(cmd_class->c_command_type); return FX_SUCCESS; @@ -76,9 +73,8 @@ static fx_status get_name( { bshell_command *cmd = NULL; fx_value_get_object(cmd_v, &cmd); - bshell_command_class *cmd_class = fx_object_get_interface( - cmd, - BSHELL_TYPE_COMMAND); + bshell_command_class *cmd_class + = fx_object_get_interface(cmd, BSHELL_TYPE_COMMAND); fx_string *result = fx_string_create(); const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd)); @@ -146,7 +142,7 @@ static fx_status get_source( return FX_SUCCESS; } -extern const fx_assembly *bshell_assembly_get(void); +extern const fx_assembly *bshell_runtime_assembly_get(void); bshell_command *bshell_command_find_static(const char *name) { @@ -154,32 +150,50 @@ bshell_command *bshell_command_find_static(const char *name) fx_string *call_name = fx_string_create_from_cstr(name); fx_string_transform_lowercase(call_name); - const fx_assembly *self = bshell_assembly_get(); - fx_iterator *it = fx_assembly_get_types(self); - fx_foreach(v, it) + bshell_command *result = NULL; + + fx_iterator *assemblies = fx_assembly_get_all(); + fx_foreach(asm_v, assemblies) { - fx_type *ty = NULL; - fx_value_get_object(&v, &ty); - const char *ty_name = fx_type_get_name(ty); - bshell_command_class *cmd = fx_type_get_interface( - ty, - BSHELL_TYPE_COMMAND); - if (!cmd || !cmd->c_get_callable_name_static) { - continue; + fx_assembly *assembly = NULL; + fx_value_get_object(&asm_v, &assembly); + fx_iterator *types = fx_assembly_get_types(assembly); + fx_foreach(v, types) + { + fx_type *ty = NULL; + fx_value_get_object(&v, &ty); + if (fx_type_id_compare( + fx_type_get_id(ty), + BSHELL_TYPE_COMMAND) + == 0) { + continue; + } + bshell_command_class *cmd = fx_type_get_interface( + ty, + BSHELL_TYPE_COMMAND); + if (!cmd || !cmd->c_get_callable_name_static) { + continue; + } + + fx_string_clear(target_name); + cmd->c_get_callable_name_static(ty, target_name); + + if (!fx_strcmp_nocase( + fx_string_get_cstr(call_name), + fx_string_get_cstr(target_name))) { + result = fx_object_create(fx_type_get_id(ty)); + break; + } } - fx_string_clear(target_name); - cmd->c_get_callable_name_static(ty, target_name); - - if (!fx_strcmp_nocase( - fx_string_get_cstr(call_name), - fx_string_get_cstr(target_name))) { - return fx_object_create(fx_type_get_id(ty)); - } + fx_iterator_unref(types); } - fx_iterator_unref(it); - return NULL; + fx_iterator_unref(assemblies); + fx_string_unref(call_name); + fx_string_unref(target_name); + + return result; } void bshell_command_set_args( @@ -265,7 +279,8 @@ FX_TYPE_CLASS_END(bshell_command) FX_TYPE_DEFINITION_BEGIN(bshell_command) FX_TYPE_ID(0x5c50630d, 0x7535, 0x40ed, 0xbae5, 0x88aabc274d79); - FX_TYPE_NAME("bshell.command"); + FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT); + FX_TYPE_NAME("bshell.runtime.command"); FX_TYPE_CLASS(bshell_command_class); FX_TYPE_INSTANCE_INIT(init); FX_TYPE_INSTANCE_PRIVATE(struct bshell_command_p); diff --git a/bshell/command/function.c b/bshell.runtime/command/function.c similarity index 100% rename from bshell/command/function.c rename to bshell.runtime/command/function.c diff --git a/bshell/compile/array.c b/bshell.runtime/compile/array.c similarity index 80% rename from bshell/compile/array.c rename to bshell.runtime/compile/array.c index b51c6dc..f348c89 100644 --- a/bshell/compile/array.c +++ b/bshell.runtime/compile/array.c @@ -5,9 +5,10 @@ static const struct compile_value_type array_item_type = {}; struct compile_result compile_array( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { - struct array_ast_node *array = (struct array_ast_node *)src; + struct bshell_array_ast_node *array; + array = (struct bshell_array_ast_node *)src; size_t nr_items = fx_queue_length(&array->n_items); for (size_t i = 0; i < nr_items; i++) { struct compile_value *item = compile_pop_value(ctx); @@ -17,7 +18,7 @@ struct compile_result compile_array( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_MK_ARRAY, + BSHELL_OPCODE_MK_ARRAY, nr_items); compile_push_value(ctx, &array_type, src); return COMPILE_OK(0); diff --git a/bshell/compile/block.c b/bshell.runtime/compile/block.c similarity index 81% rename from bshell/compile/block.c rename to bshell.runtime/compile/block.c index c284fad..a5f64a0 100644 --- a/bshell/compile/block.c +++ b/bshell.runtime/compile/block.c @@ -1,6 +1,6 @@ -#include "../compile.h" #include "compile-node.h" +#include #include static enum bshell_status block_load( @@ -9,7 +9,7 @@ static enum bshell_status block_load( { bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_LDBLOCK, + BSHELL_OPCODE_LDBLOCK, value->v_pool); return BSHELL_SUCCESS; } @@ -20,7 +20,7 @@ static const struct compile_value_type block_type = { struct compile_result compile_block( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { bshell_scriptblock *sub_block = bshell_scriptblock_create(); if (!sub_block) { @@ -45,14 +45,18 @@ struct compile_result compile_block( enum bshell_status compile_block_immediate( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { enum bshell_status status = BSHELL_SUCCESS; - struct block_ast_node *block = (struct block_ast_node *)src; + struct bshell_block_ast_node *block = (struct bshell_block_ast_node *) + src; fx_queue_entry *cur = fx_queue_first(&block->n_statements); while (cur && status == BSHELL_SUCCESS) { - struct ast_node *node = fx_unbox(struct ast_node, cur, n_entry); + struct bshell_ast_node *node = fx_unbox( + struct bshell_ast_node, + cur, + n_entry); status = compile_node(ctx, node); cur = fx_queue_next(cur); } diff --git a/bshell/compile/command.c b/bshell.runtime/compile/command.c similarity index 68% rename from bshell/compile/command.c rename to bshell.runtime/compile/command.c index ee0fab8..9460706 100644 --- a/bshell/compile/command.c +++ b/bshell.runtime/compile/command.c @@ -4,9 +4,9 @@ enum bshell_status cmdcall_load( struct compile_ctx *ctx, struct compile_value *value) { - struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *) - value->v_node; - bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_PEXEC, 1); + struct bshell_cmdcall_ast_node *cmdcall; + cmdcall = (struct bshell_cmdcall_ast_node *)value->v_node; + bshell_scriptblock_push_instruction(ctx->c_block, BSHELL_OPCODE_PEXEC, 1); return BSHELL_SUCCESS; } @@ -14,12 +14,12 @@ enum bshell_status pipeline_load( struct compile_ctx *ctx, struct compile_value *value) { - struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *) - value->v_node; + struct bshell_pipeline_ast_node *pipeline; + pipeline = (struct bshell_pipeline_ast_node *)value->v_node; size_t nr_items = fx_queue_length(&pipeline->n_stages); bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_PEXEC, + BSHELL_OPCODE_PEXEC, nr_items); return BSHELL_SUCCESS; } @@ -34,9 +34,10 @@ static const struct compile_value_type pipeline_type = { struct compile_result compile_cmdcall( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { - struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)src; + struct bshell_cmdcall_ast_node *cmdcall; + cmdcall = (struct bshell_cmdcall_ast_node *)src; size_t nr_args = fx_queue_length(&cmdcall->n_args); for (size_t i = 0; i < nr_args; i++) { struct compile_value *arg = compile_pop_value(ctx); @@ -46,7 +47,7 @@ struct compile_result compile_cmdcall( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_LDCMD, + BSHELL_OPCODE_LDCMD, nr_args); compile_push_value(ctx, &cmdcall_type, src); @@ -55,13 +56,14 @@ struct compile_result compile_cmdcall( struct compile_result compile_pipeline( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { - struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)src; + struct bshell_pipeline_ast_node *pipeline; + pipeline = (struct bshell_pipeline_ast_node *)src; size_t nr_items = fx_queue_length(&pipeline->n_stages); for (size_t i = 0; i < nr_items; i++) { struct compile_value *item = compile_pop_value(ctx); - if (item->v_node->n_type != AST_CMDCALL) { + if (item->v_node->n_type != BSHELL_AST_CMDCALL) { compile_value_load(ctx, item); } compile_value_destroy(item); diff --git a/bshell/compile/compile-node.h b/bshell.runtime/compile/compile-node.h similarity index 82% rename from bshell/compile/compile-node.h rename to bshell.runtime/compile/compile-node.h index 75e3358..6e71070 100644 --- a/bshell/compile/compile-node.h +++ b/bshell.runtime/compile/compile-node.h @@ -1,11 +1,11 @@ #ifndef COMPILE_COMPILE_NODE_H_ #define COMPILE_COMPILE_NODE_H_ -#include "../ast/ast.h" -#include "../operator.h" -#include "../parse/token.h" -#include "../script-block.h" - +#include +#include +#include +#include +#include #include #include @@ -27,7 +27,7 @@ struct compile_result { typedef struct compile_result (*compile_begin_impl)(struct compile_ctx *); typedef struct compile_result (*compile_end_impl)(struct compile_ctx *); typedef struct compile_result ( - *compile_node_impl)(struct compile_ctx *, struct ast_node *); + *compile_node_impl)(struct compile_ctx *, struct bshell_ast_node *); enum compile_state_type_id { COMPILE_NORMAL = 0, @@ -43,11 +43,11 @@ struct compile_value_type { struct compile_value { const struct compile_value_type *v_type; - enum operator_id v_op; + enum bshell_operator_id v_op; struct compile_value *v_left, *v_right; struct compile_value **v_args; size_t v_nr_args; - struct ast_node *v_node; + struct bshell_ast_node *v_node; unsigned long v_pool; fx_queue_entry v_entry; }; @@ -94,11 +94,11 @@ extern struct compile_state *compile_get_state(const struct compile_ctx *ctx); extern enum bshell_status compile_push_value( struct compile_ctx *ctx, const struct compile_value_type *type, - struct ast_node *node); + struct bshell_ast_node *node); extern enum bshell_status compile_push_value_array( struct compile_ctx *ctx, const struct compile_value_type *type, - struct ast_node *node, + struct bshell_ast_node *node, struct compile_value **values, size_t nr_values); extern enum bshell_status compile_push_pool_value( @@ -107,9 +107,9 @@ extern enum bshell_status compile_push_pool_value( unsigned long pool_slot); extern enum bshell_status compile_push_op( struct compile_ctx *ctx, - struct ast_node *node, + struct bshell_ast_node *node, const struct compile_value_type *type, - enum operator_id op, + enum bshell_operator_id op, struct compile_value *left, struct compile_value *right); extern struct compile_value *compile_pop_value(struct compile_ctx *ctx); @@ -128,60 +128,60 @@ extern enum bshell_status compile_resolve_labels(struct compile_ctx *ctx); extern struct compile_result compile_int( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_double( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_string( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_word( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_op( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_var( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_fstring( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_array( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_hashtable_item( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_hashtable( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_block( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_cmdcall( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern struct compile_result compile_pipeline( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern enum bshell_status compile_if( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern enum bshell_status compile_block_immediate( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern enum bshell_status compile_expression( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); extern enum bshell_status compile_node( struct compile_ctx *ctx, - struct ast_node *src); + struct bshell_ast_node *src); #endif diff --git a/bshell/compile/compile.c b/bshell.runtime/compile/compile.c similarity index 76% rename from bshell/compile/compile.c rename to bshell.runtime/compile/compile.c index 3fe9429..9a8e219 100644 --- a/bshell/compile/compile.c +++ b/bshell.runtime/compile/compile.c @@ -1,20 +1,17 @@ -#include "../compile.h" - -#include "../ast/ast.h" -#include "../debug.h" -#include "../status.h" #include "compile-node.h" -#include +#include +#include +#include extern enum bshell_status compile_node( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { switch (src->n_type) { - case AST_IF: + case BSHELL_AST_IF: return compile_if(ctx, src); - case AST_BLOCK: + case BSHELL_AST_BLOCK: return compile_block_immediate(ctx, src); default: return compile_expression(ctx, src); @@ -24,7 +21,7 @@ extern enum bshell_status compile_node( } enum bshell_status bshell_compile( - struct ast_node *src, + struct bshell_ast_node *src, bshell_scriptblock *dest) { struct compile_ctx ctx = {.c_block = dest}; diff --git a/bshell/compile/const.c b/bshell.runtime/compile/const.c similarity index 72% rename from bshell/compile/const.c rename to bshell.runtime/compile/const.c index d657184..24a0b87 100644 --- a/bshell/compile/const.c +++ b/bshell.runtime/compile/const.c @@ -4,10 +4,11 @@ enum bshell_status int_load( struct compile_ctx *ctx, struct compile_value *value) { - struct int_ast_node *i = (struct int_ast_node *)value->v_node; + struct bshell_int_ast_node *i + = (struct bshell_int_ast_node *)value->v_node; long long v; fx_value_get_longlong(&i->n_value->tok_number, &v); - bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_LDC_INT, v); + bshell_scriptblock_push_instruction(ctx->c_block, BSHELL_OPCODE_LDC_INT, v); return BSHELL_SUCCESS; } @@ -15,11 +16,12 @@ enum bshell_status double_load( struct compile_ctx *ctx, struct compile_value *value) { - struct double_ast_node *d = (struct double_ast_node *)value->v_node; + struct bshell_double_ast_node *d + = (struct bshell_double_ast_node *)value->v_node; double v; fx_value_get_double(&d->n_value->tok_number, &v); unsigned long index = bshell_scriptblock_get_double(ctx->c_block, v); - bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_LDC_FP, index); + bshell_scriptblock_push_instruction(ctx->c_block, BSHELL_OPCODE_LDC_FP, index); return BSHELL_SUCCESS; } @@ -27,7 +29,8 @@ enum bshell_status string_load( struct compile_ctx *ctx, struct compile_value *value) { - struct string_ast_node *s = (struct string_ast_node *)value->v_node; + struct bshell_string_ast_node *s + = (struct bshell_string_ast_node *)value->v_node; unsigned long index = bshell_scriptblock_get_string( ctx->c_block, s->n_value->tok_str); @@ -37,7 +40,7 @@ enum bshell_status string_load( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_LDC_STR, + BSHELL_OPCODE_LDC_STR, index); return BSHELL_SUCCESS; } @@ -46,7 +49,8 @@ enum bshell_status word_load( struct compile_ctx *ctx, struct compile_value *value) { - struct word_ast_node *s = (struct word_ast_node *)value->v_node; + struct bshell_word_ast_node *s + = (struct bshell_word_ast_node *)value->v_node; unsigned long index = bshell_scriptblock_get_string( ctx->c_block, s->n_value->tok_str); @@ -56,7 +60,7 @@ enum bshell_status word_load( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_LDC_STR, + BSHELL_OPCODE_LDC_STR, index); return BSHELL_SUCCESS; } @@ -77,7 +81,9 @@ static const struct compile_value_type word_type = { .v_load = word_load, }; -struct compile_result compile_int(struct compile_ctx *ctx, struct ast_node *src) +struct compile_result compile_int( + struct compile_ctx *ctx, + struct bshell_ast_node *src) { compile_push_value(ctx, &int_type, src); return COMPILE_OK(0); @@ -85,7 +91,7 @@ struct compile_result compile_int(struct compile_ctx *ctx, struct ast_node *src) struct compile_result compile_double( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { compile_push_value(ctx, &double_type, src); return COMPILE_OK(0); @@ -93,7 +99,7 @@ struct compile_result compile_double( struct compile_result compile_string( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { compile_push_value(ctx, &string_type, src); return COMPILE_OK(0); @@ -101,7 +107,7 @@ struct compile_result compile_string( struct compile_result compile_word( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { compile_push_value(ctx, &word_type, src); return COMPILE_OK(0); diff --git a/bshell/compile/expression.c b/bshell.runtime/compile/expression.c similarity index 61% rename from bshell/compile/expression.c rename to bshell.runtime/compile/expression.c index 9d8994e..cbcc7f3 100644 --- a/bshell/compile/expression.c +++ b/bshell.runtime/compile/expression.c @@ -1,22 +1,22 @@ #include "compile-node.h" -static struct ast_iterate_result do_compile_node( - struct ast_node *node, - enum ast_iteration_type it_type, - struct ast_iterator *it, +static struct bshell_ast_iterate_result do_compile_node( + struct bshell_ast_node *node, + enum bshell_ast_iteration_type it_type, + struct bshell_ast_iterator *it, struct compile_ctx *ctx) { - if (it_type != AST_ITERATION_POST) { + if (it_type != BSHELL_AST_ITERATION_POST) { int flags = 0; switch (node->n_type) { - case AST_BLOCK: + case BSHELL_AST_BLOCK: break; default: - flags |= AST_ITERATE_ADD_CHILDREN; + flags |= BSHELL_AST_ITERATE_ADD_CHILDREN; break; } - return AST_ITERATE_OK(flags); + return BSHELL_AST_ITERATE_OK(flags); } ctx->c_depth = node->n_it.e_depth; @@ -37,30 +37,34 @@ static struct ast_iterate_result do_compile_node( } if (!impl) { - return AST_ITERATE_OK(0); + return BSHELL_AST_ITERATE_OK(0); } struct compile_result result = impl(ctx, node); unsigned int flags = 0; if (result.r_flags & COMPILE_REPEAT_NODE) { - flags |= AST_ITERATE_REPEAT; + flags |= BSHELL_AST_ITERATE_REPEAT; } if (result.r_status == BSHELL_SUCCESS) { - return AST_ITERATE_OK(flags); + return BSHELL_AST_ITERATE_OK(flags); } - return AST_ITERATE_ERR(result.r_status); + return BSHELL_AST_ITERATE_ERR(result.r_status); } enum bshell_status compile_expression( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { compile_push_state(ctx, COMPILE_NORMAL); - struct ast_iterator it = {0}; - ast_node_iterate(src, &it, (ast_iterator_callback)do_compile_node, ctx); + struct bshell_ast_iterator it = {0}; + bshell_ast_node_iterate( + src, + &it, + (bshell_ast_iterator_callback)do_compile_node, + ctx); struct compile_value *result = compile_pop_value(ctx); if (result) { diff --git a/bshell/compile/fstring.c b/bshell.runtime/compile/fstring.c similarity index 78% rename from bshell/compile/fstring.c rename to bshell.runtime/compile/fstring.c index 198dc10..a8bdcc7 100644 --- a/bshell/compile/fstring.c +++ b/bshell.runtime/compile/fstring.c @@ -4,15 +4,15 @@ enum bshell_status fstring_load( struct compile_ctx *ctx, struct compile_value *value) { - struct fstring_ast_node *fstring = (struct fstring_ast_node *) - value->v_node; + struct bshell_fstring_ast_node *fstring + = (struct bshell_fstring_ast_node *)value->v_node; for (size_t i = 0; i < value->v_nr_args; i++) { compile_value_load(ctx, value->v_args[i]); } bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_MK_STR, + BSHELL_OPCODE_MK_STR, fx_queue_length(&fstring->n_elements)); return BSHELL_SUCCESS; } @@ -23,9 +23,10 @@ static const struct compile_value_type fstring_type = { struct compile_result compile_fstring( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { - struct fstring_ast_node *fstring = (struct fstring_ast_node *)src; + struct bshell_fstring_ast_node *fstring + = (struct bshell_fstring_ast_node *)src; size_t nr_items = fx_queue_length(&fstring->n_elements); struct compile_value **items = calloc(nr_items, sizeof *items); diff --git a/bshell/compile/hashtable.c b/bshell.runtime/compile/hashtable.c similarity index 84% rename from bshell/compile/hashtable.c rename to bshell.runtime/compile/hashtable.c index c64340c..ff7534a 100644 --- a/bshell/compile/hashtable.c +++ b/bshell.runtime/compile/hashtable.c @@ -5,9 +5,10 @@ static const struct compile_value_type hashtable_item_type = {}; struct compile_result compile_hashtable( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { - struct hashtable_ast_node *hashtable = (struct hashtable_ast_node *)src; + struct bshell_hashtable_ast_node *hashtable + = (struct bshell_hashtable_ast_node *)src; size_t nr_items = fx_queue_length(&hashtable->n_items); for (size_t i = 0; i < nr_items; i++) { struct compile_value *item = compile_pop_value(ctx); @@ -17,7 +18,7 @@ struct compile_result compile_hashtable( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_MK_HTAB, + BSHELL_OPCODE_MK_HTAB, nr_items); compile_push_value(ctx, &hashtable_type, src); return COMPILE_OK(0); @@ -25,7 +26,7 @@ struct compile_result compile_hashtable( struct compile_result compile_hashtable_item( struct compile_ctx *ctx, - struct ast_node *src) + struct bshell_ast_node *src) { struct compile_value *value = compile_pop_value(ctx); struct compile_value *key = compile_pop_value(ctx); diff --git a/bshell/compile/if.c b/bshell.runtime/compile/if.c similarity index 76% rename from bshell/compile/if.c rename to bshell.runtime/compile/if.c index c34b616..953fca5 100644 --- a/bshell/compile/if.c +++ b/bshell.runtime/compile/if.c @@ -1,8 +1,11 @@ #include "compile-node.h" -enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) +enum bshell_status compile_if( + struct compile_ctx *ctx, + struct bshell_ast_node *src) { - struct if_ast_node *if_group = (struct if_ast_node *)src; + struct bshell_if_ast_node *if_group; + if_group = (struct bshell_if_ast_node *)src; size_t nr_labels = fx_queue_length(&if_group->n_branches); // add one extra label for the end of the if group nr_labels++; @@ -20,8 +23,9 @@ enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) i = 0; fx_queue_entry *cur = fx_queue_first(&if_group->n_branches); while (cur) { - struct if_branch_ast_node *branch = fx_unbox( - struct if_branch_ast_node, + struct bshell_if_branch_ast_node *branch; + branch = fx_unbox( + struct bshell_if_branch_ast_node, cur, n_base.n_entry); if (!branch->n_cond) { @@ -29,7 +33,7 @@ enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) compile_ref_label(ctx, label_ids[nr_labels - 1]); bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_BR, + BSHELL_OPCODE_BR, 0); break; } @@ -38,7 +42,7 @@ enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) compile_ref_label(ctx, label_ids[i++]); bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_BR_TRUE, + BSHELL_OPCODE_BR_TRUE, 0); cur = fx_queue_next(cur); @@ -47,8 +51,8 @@ enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) i = 0; cur = fx_queue_first(&if_group->n_branches); while (cur) { - struct if_branch_ast_node *branch = fx_unbox( - struct if_branch_ast_node, + struct bshell_if_branch_ast_node *branch = fx_unbox( + struct bshell_if_branch_ast_node, cur, n_base.n_entry); if (!branch->n_cond) { @@ -63,7 +67,7 @@ enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src) compile_ref_label(ctx, label_ids[nr_labels - 1]); bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_BR, + BSHELL_OPCODE_BR, 0); } } diff --git a/bshell/compile/label.c b/bshell.runtime/compile/label.c similarity index 100% rename from bshell/compile/label.c rename to bshell.runtime/compile/label.c diff --git a/bshell.runtime/compile/normal.c b/bshell.runtime/compile/normal.c new file mode 100644 index 0000000..e6545d1 --- /dev/null +++ b/bshell.runtime/compile/normal.c @@ -0,0 +1,25 @@ +#include "compile-node.h" + +static const compile_node_impl node_compilers[] = { + [BSHELL_AST_INT] = compile_int, + [BSHELL_AST_DOUBLE] = compile_double, + [BSHELL_AST_STRING] = compile_string, + [BSHELL_AST_WORD] = compile_word, + [BSHELL_AST_OP] = compile_op, + [BSHELL_AST_VAR] = compile_var, + [BSHELL_AST_FSTRING] = compile_fstring, + [BSHELL_AST_ARRAY] = compile_array, + [BSHELL_AST_HASHTABLE] = compile_hashtable, + [BSHELL_AST_HASHTABLE_ITEM] = compile_hashtable_item, + [BSHELL_AST_CMDCALL] = compile_cmdcall, + [BSHELL_AST_PIPELINE] = compile_pipeline, + [BSHELL_AST_BLOCK] = compile_block, +}; +static const size_t nr_node_compilers = sizeof node_compilers + / sizeof node_compilers[0]; + +const struct compile_state_type normal_state = { + .s_size = sizeof(struct compile_state), + .s_compile_node = node_compilers, + .s_nr_compile_node = nr_node_compilers, +}; diff --git a/bshell.runtime/compile/op.c b/bshell.runtime/compile/op.c new file mode 100644 index 0000000..ee55f72 --- /dev/null +++ b/bshell.runtime/compile/op.c @@ -0,0 +1,126 @@ +#include "compile-node.h" + +#include + +static enum bshell_opcode opcode_for_op(enum bshell_operator_id op) +{ + switch (op) { + case BSHELL_OP_ADD: + return BSHELL_OPCODE_ADD; + case BSHELL_OP_SUBTRACT: + return BSHELL_OPCODE_SUB; + case BSHELL_OP_MULTIPLY: + return BSHELL_OPCODE_MUL; + case BSHELL_OP_DIVIDE: + return BSHELL_OPCODE_DIV; + case BSHELL_OP_MODULO: + return BSHELL_OPCODE_MOD; + case BSHELL_OP_INCREMENT: + return BSHELL_OPCODE_INC; + case BSHELL_OP_DECREMENT: + return BSHELL_OPCODE_DEC; + case BSHELL_OP_LEFT_SHIFT: + return BSHELL_OPCODE_SHL; + case BSHELL_OP_RIGHT_SHIFT: + return BSHELL_OPCODE_SHR; + case BSHELL_OP_BINARY_AND: + return BSHELL_OPCODE_BAND; + case BSHELL_OP_BINARY_OR: + return BSHELL_OPCODE_BOR; + case BSHELL_OP_BINARY_XOR: + return BSHELL_OPCODE_BXOR; + case BSHELL_OP_BINARY_NOT: + return BSHELL_OPCODE_BNOT; + case BSHELL_OP_LESS_THAN: + return BSHELL_OPCODE_CMP_LT; + case BSHELL_OP_GREATER_THAN: + return BSHELL_OPCODE_CMP_GT; + case BSHELL_OP_EQUAL: + return BSHELL_OPCODE_CMP_EQ; + case BSHELL_OP_NOT_EQUAL: + return BSHELL_OPCODE_CMP_NE; + case BSHELL_OP_LESS_EQUAL: + return BSHELL_OPCODE_CMP_LE; + case BSHELL_OP_GREATER_EQUAL: + return BSHELL_OPCODE_CMP_GE; + case BSHELL_OP_LOGICAL_AND: + return BSHELL_OPCODE_LAND; + case BSHELL_OP_LOGICAL_OR: + return BSHELL_OPCODE_LOR; + case BSHELL_OP_LOGICAL_XOR: + return BSHELL_OPCODE_LXOR; + case BSHELL_OP_LOGICAL_NOT: + return BSHELL_OPCODE_LNOT; + case BSHELL_OP_RANGE: + return BSHELL_OPCODE_RANGE; + case BSHELL_OP_MATCH: + return BSHELL_OPCODE_MATCH; + case BSHELL_OP_REPLACE: + return BSHELL_OPCODE_REPLACE; + case BSHELL_OP_LIKE: + return BSHELL_OPCODE_LIKE; + case BSHELL_OP_IN: + return BSHELL_OPCODE_IN; + case BSHELL_OP_FORMAT: + return BSHELL_OPCODE_FMT; + case BSHELL_OP_CONTAINS: + return BSHELL_OPCODE_CONTAINS; + case BSHELL_OP_USPLIT: + return BSHELL_OPCODE_SPLIT; + case BSHELL_OP_BSPLIT: + return BSHELL_OPCODE_SPLIT; + case BSHELL_OP_UJOIN: + return BSHELL_OPCODE_JOIN; + case BSHELL_OP_BJOIN: + return BSHELL_OPCODE_JOIN; + case BSHELL_OP_IS: + return BSHELL_OPCODE_IS; + case BSHELL_OP_AS: + return BSHELL_OPCODE_AS; + case BSHELL_OP_ACCESS: + return BSHELL_OPCODE_LDPROP; + default: + return BSHELL_OPCODE_NOP; + } +} + +enum bshell_status op_load(struct compile_ctx *ctx, struct compile_value *value) +{ + enum bshell_opcode opcode = opcode_for_op(value->v_op); + if (opcode != BSHELL_OPCODE_NOP) { + compile_value_load(ctx, value->v_right); + compile_value_load(ctx, value->v_left); + bshell_scriptblock_push_instruction( + ctx->c_block, + opcode_for_op(value->v_op), + 0); + return BSHELL_SUCCESS; + } + + switch (value->v_op) { + case BSHELL_OP_ASSIGN: + compile_value_load(ctx, value->v_right); + compile_value_store(ctx, value->v_left); + break; + default: + return BSHELL_ERR_NOT_SUPPORTED; + } + + return BSHELL_SUCCESS; +} + +static const struct compile_value_type op_type = { + .v_load = op_load, +}; + +struct compile_result compile_op( + struct compile_ctx *ctx, + struct bshell_ast_node *src) +{ + struct bshell_op_ast_node *op = (struct bshell_op_ast_node *)src; + struct compile_value *left = NULL, *right = NULL; + left = compile_pop_value(ctx); + right = compile_pop_value(ctx); + compile_push_op(ctx, src, &op_type, op->n_op->op_id, left, right); + return COMPILE_OK(0); +} diff --git a/bshell/compile/stack.c b/bshell.runtime/compile/stack.c similarity index 95% rename from bshell/compile/stack.c rename to bshell.runtime/compile/stack.c index fc94fcf..e3d3e06 100644 --- a/bshell/compile/stack.c +++ b/bshell.runtime/compile/stack.c @@ -3,7 +3,7 @@ enum bshell_status compile_push_value( struct compile_ctx *ctx, const struct compile_value_type *type, - struct ast_node *node) + struct bshell_ast_node *node) { struct compile_value *item = malloc(sizeof *item); if (!item) { @@ -22,7 +22,7 @@ enum bshell_status compile_push_value( enum bshell_status compile_push_value_array( struct compile_ctx *ctx, const struct compile_value_type *type, - struct ast_node *node, + struct bshell_ast_node *node, struct compile_value **values, size_t nr_values) { @@ -63,9 +63,9 @@ enum bshell_status compile_push_pool_value( enum bshell_status compile_push_op( struct compile_ctx *ctx, - struct ast_node *node, + struct bshell_ast_node *node, const struct compile_value_type *type, - enum operator_id op, + enum bshell_operator_id op, struct compile_value *left, struct compile_value *right) { diff --git a/bshell/compile/state.c b/bshell.runtime/compile/state.c similarity index 100% rename from bshell/compile/state.c rename to bshell.runtime/compile/state.c diff --git a/bshell/compile/var.c b/bshell.runtime/compile/var.c similarity index 74% rename from bshell/compile/var.c rename to bshell.runtime/compile/var.c index 97acd66..35eac65 100644 --- a/bshell/compile/var.c +++ b/bshell.runtime/compile/var.c @@ -4,7 +4,8 @@ enum bshell_status var_load( struct compile_ctx *ctx, struct compile_value *value) { - struct var_ast_node *var = (struct var_ast_node *)value->v_node; + struct bshell_var_ast_node *var + = (struct bshell_var_ast_node *)value->v_node; unsigned long index = bshell_scriptblock_get_string( ctx->c_block, var->n_ident->tok_str); @@ -14,7 +15,7 @@ enum bshell_status var_load( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_LDLOCAL, + BSHELL_OPCODE_LDLOCAL, index); return BSHELL_SUCCESS; } @@ -23,7 +24,8 @@ enum bshell_status var_store( struct compile_ctx *ctx, struct compile_value *value) { - struct var_ast_node *var = (struct var_ast_node *)value->v_node; + struct bshell_var_ast_node *var + = (struct bshell_var_ast_node *)value->v_node; unsigned long index = bshell_scriptblock_get_string( ctx->c_block, var->n_ident->tok_str); @@ -33,7 +35,7 @@ enum bshell_status var_store( bshell_scriptblock_push_instruction( ctx->c_block, - OPCODE_STLOCAL, + BSHELL_OPCODE_STLOCAL, index); return BSHELL_SUCCESS; } @@ -43,7 +45,9 @@ static const struct compile_value_type var_type = { .v_store = var_store, }; -struct compile_result compile_var(struct compile_ctx *ctx, struct ast_node *src) +struct compile_result compile_var( + struct compile_ctx *ctx, + struct bshell_ast_node *src) { compile_push_value(ctx, &var_type, src); return COMPILE_OK(0); diff --git a/bshell/file.c b/bshell.runtime/file.c similarity index 79% rename from bshell/file.c rename to bshell.runtime/file.c index b115da2..831faca 100644 --- a/bshell/file.c +++ b/bshell.runtime/file.c @@ -1,7 +1,5 @@ -#include "file.h" - -#include "line-source.h" - +#include +#include #include #include #include @@ -9,24 +7,24 @@ #include static enum bshell_status get_name( - struct line_source *src, + struct bshell_line_source *src, char *buf, size_t count, size_t *nr_read) { - struct file *f = (struct file *)src; + struct bshell_file *f = (struct bshell_file *)src; *nr_read = snprintf(buf, count, "%s", f->f_path); return BSHELL_SUCCESS; } static enum bshell_status get_row( - struct line_source *src, + struct bshell_line_source *src, size_t row, char *buf, size_t count, size_t *nr_read) { - struct file *f = (struct file *)src; + struct bshell_file *f = (struct bshell_file *)src; size_t nr_rows = fx_array_get_size(f->f_lines); if (row > nr_rows) { @@ -50,10 +48,10 @@ static enum bshell_status get_row( } static enum bshell_status readline( - struct line_source *src, + struct bshell_line_source *src, fx_stringstream *out) { - struct file *f = (struct file *)src; + struct bshell_file *f = (struct bshell_file *)src; fx_wchar c = FX_WCHAR_INVALID; size_t nr_read = 0; @@ -78,7 +76,7 @@ static enum bshell_status readline( return BSHELL_SUCCESS; } -enum bshell_status file_open(const char *path, struct file **out) +enum bshell_status bshell_file_open(const char *path, struct bshell_file **out) { FILE *fp = fopen(path, "r"); if (!fp) { @@ -87,7 +85,7 @@ enum bshell_status file_open(const char *path, struct file **out) fx_stream *strp = fx_stream_open_fp(fp); - struct file *file = malloc(sizeof *file); + struct bshell_file *file = malloc(sizeof *file); if (!file) { fclose(fp); return BSHELL_ERR_NO_MEMORY; @@ -108,7 +106,7 @@ enum bshell_status file_open(const char *path, struct file **out) return BSHELL_SUCCESS; } -void file_close(struct file *file) +void bshell_file_close(struct bshell_file *file) { fx_stream_unref(file->f_strp); fx_array_unref(file->f_lines); diff --git a/bshell.runtime/format/command.c b/bshell.runtime/format/command.c new file mode 100644 index 0000000..074b5c9 --- /dev/null +++ b/bshell.runtime/format/command.c @@ -0,0 +1,14 @@ +#include + +static struct bshell_table_column command_table_columns[] = { + TABLE_COLUMN("command_type", "command_type", 13), + TABLE_COLUMN("name", "name", COL_WIDTH_INFINITE), + TABLE_COLUMN("version", "version", 12), + TABLE_COLUMN("source", "source", 35), +}; + +struct bshell_table command_bshell_table = { + .fmt_columns = command_table_columns, + .fmt_column_count + = sizeof command_table_columns / sizeof command_table_columns[0], +}; diff --git a/bshell/format/format.c b/bshell.runtime/format/format.c similarity index 96% rename from bshell/format/format.c rename to bshell.runtime/format/format.c index a5c1c71..045a46e 100644 --- a/bshell/format/format.c +++ b/bshell.runtime/format/format.c @@ -1,5 +1,4 @@ -#include "format.h" - +#include #include #include #include diff --git a/bshell.runtime/format/hashtable.c b/bshell.runtime/format/hashtable.c new file mode 100644 index 0000000..c2071c1 --- /dev/null +++ b/bshell.runtime/format/hashtable.c @@ -0,0 +1,12 @@ +#include + +static struct bshell_table_column hashtable_table_columns[] = { + TABLE_COLUMN("key", "key", 37), + TABLE_COLUMN("value", "value", COL_WIDTH_INFINITE), +}; + +struct bshell_table hashtable_bshell_table = { + .fmt_columns = hashtable_table_columns, + .fmt_column_count + = sizeof hashtable_table_columns / sizeof hashtable_table_columns[0], +}; diff --git a/bshell/format/table.c b/bshell.runtime/format/table.c similarity index 73% rename from bshell/format/table.c rename to bshell.runtime/format/table.c index d847fa4..a11ef22 100644 --- a/bshell/format/table.c +++ b/bshell.runtime/format/table.c @@ -1,5 +1,4 @@ -#include "format.h" - +#include #include #include #include @@ -8,36 +7,36 @@ #include #include -static fx_namemap table_formats = FX_NAMEMAP_INIT; +static fx_namemap bshell_tables = FX_NAMEMAP_INIT; -extern struct table_format hashtable_table_format; -extern struct table_format verb_table_format; -extern struct table_format command_table_format; +extern struct bshell_table hashtable_bshell_table; +extern struct bshell_table verb_bshell_table; +extern struct bshell_table command_bshell_table; -enum bshell_status table_format_init(void) +enum bshell_status bshell_table_init(void) { fx_namemap_put( - &table_formats, + &bshell_tables, "fx.collections.hashtable", - &hashtable_table_format.fmt_entry); + &hashtable_bshell_table.fmt_entry); fx_namemap_put( - &table_formats, + &bshell_tables, "bshell.verb", - &verb_table_format.fmt_entry); + &verb_bshell_table.fmt_entry); fx_namemap_put( - &table_formats, + &bshell_tables, "bshell.command", - &command_table_format.fmt_entry); + &command_bshell_table.fmt_entry); return BSHELL_SUCCESS; } -const struct table_format *table_format_get_for_type(const fx_type *ty) +const struct bshell_table *bshell_table_get_for_type(const fx_type *ty) { while (ty) { const char *name = fx_type_get_name(ty); - fx_namemap_entry *entry = fx_namemap_get(&table_formats, name); + fx_namemap_entry *entry = fx_namemap_get(&bshell_tables, name); if (entry) { - return fx_unbox(struct table_format, entry, fmt_entry); + return fx_unbox(struct bshell_table, entry, fmt_entry); } ty = fx_type_get_parent(ty); @@ -53,43 +52,43 @@ enum bshell_status format_object_table(fx_object *object, fx_stream *dest) return BSHELL_ERR_NOT_SUPPORTED; } - const struct table_format *fmt = table_format_get_for_type(type); + const struct bshell_table *fmt = bshell_table_get_for_type(type); if (!fmt) { return BSHELL_ERR_NOT_SUPPORTED; } - struct table_format_ctx ctx; - table_format_ctx_init(&ctx, dest); + struct bshell_table_ctx ctx; + bshell_table_ctx_init(&ctx, dest); fx_iterator *it = fx_iterator_begin(object); if (!it) { - table_format_ctx_prepare_columns_from_format( + bshell_table_ctx_prepare_columns_from_format( &ctx, fx_type_get_by_id(fx_object_query_type(object)), fmt); - table_format_ctx_print_headers(&ctx); - table_format_ctx_print_record(&ctx, &FX_VALUE_OBJECT(object)); + bshell_table_ctx_print_headers(&ctx); + bshell_table_ctx_print_record(&ctx, &FX_VALUE_OBJECT(object)); } else { fx_value first = fx_iterator_get_value(it); if (first.v_type) { - table_format_ctx_prepare_columns_from_format( + bshell_table_ctx_prepare_columns_from_format( &ctx, fx_type_get_by_id(first.v_type), fmt); } - table_format_ctx_print_headers(&ctx); + bshell_table_ctx_print_headers(&ctx); fx_foreach(value, it) { - table_format_ctx_print_record(&ctx, &value); + bshell_table_ctx_print_record(&ctx, &value); } } - table_format_ctx_cleanup(&ctx); + bshell_table_ctx_cleanup(&ctx); return BSHELL_SUCCESS; } -enum bshell_status table_format_ctx_init( - struct table_format_ctx *ctx, +enum bshell_status bshell_table_ctx_init( + struct bshell_table_ctx *ctx, fx_stream *out) { memset(ctx, 0x0, sizeof *ctx); @@ -97,7 +96,7 @@ enum bshell_status table_format_ctx_init( return BSHELL_SUCCESS; } -enum bshell_status table_format_ctx_cleanup(struct table_format_ctx *ctx) +enum bshell_status bshell_table_ctx_cleanup(struct bshell_table_ctx *ctx) { if (ctx->ctx_columns) { free(ctx->ctx_columns); @@ -107,35 +106,34 @@ enum bshell_status table_format_ctx_cleanup(struct table_format_ctx *ctx) return BSHELL_SUCCESS; } -enum bshell_status table_format_ctx_prepare_columns_from_format( - struct table_format_ctx *ctx, +enum bshell_status bshell_table_ctx_prepare_columns_from_format( + struct bshell_table_ctx *ctx, const fx_type *record_type, - const struct table_format *fmt) + const struct bshell_table *fmt) { if (!fmt && !record_type) { return BSHELL_ERR_INVALID_ARGUMENT; } if (!fmt) { - fmt = table_format_get_for_type(record_type); + fmt = bshell_table_get_for_type(record_type); } if (!fmt) { - return table_format_ctx_prepare_columns_from_object( + return bshell_table_ctx_prepare_columns_from_object( ctx, record_type); } ctx->ctx_fmt = fmt; - struct table_format_ctx_column *columns = calloc( - fmt->fmt_column_count, - sizeof *columns); + struct bshell_table_ctx_column *columns + = calloc(fmt->fmt_column_count, sizeof *columns); if (!columns) { return BSHELL_ERR_NO_MEMORY; } - const struct table_format_column *column_defs = fmt->fmt_columns; + const struct bshell_table_column *column_defs = fmt->fmt_columns; ctx->ctx_columns = columns; ctx->ctx_columns_count = fmt->fmt_column_count; @@ -173,16 +171,16 @@ enum bshell_status table_format_ctx_prepare_columns_from_format( for (size_t i = 0; i < fmt->fmt_column_count; i++) { if (column_defs[i].col_width == COL_WIDTH_INFINITE) { - columns[i].col_width = tty_width - / ctx->ctx_variable_columns_count; + columns[i].col_width + = tty_width / ctx->ctx_variable_columns_count; } } return BSHELL_SUCCESS; } -enum bshell_status table_format_ctx_prepare_columns_from_object( - struct table_format_ctx *ctx, +enum bshell_status bshell_table_ctx_prepare_columns_from_object( + struct bshell_table_ctx *ctx, const fx_type *record_type) { fx_array *properties = fx_array_create(); @@ -200,9 +198,8 @@ enum bshell_status table_format_ctx_prepare_columns_from_object( return BSHELL_SUCCESS; } - struct table_format_ctx_column *columns = calloc( - column_count, - sizeof *columns); + struct bshell_table_ctx_column *columns + = calloc(column_count, sizeof *columns); if (!columns) { fx_array_unref(properties); @@ -235,11 +232,11 @@ enum bshell_status table_format_ctx_prepare_columns_from_object( return BSHELL_SUCCESS; } -enum bshell_status table_format_ctx_print_headers(struct table_format_ctx *ctx) +enum bshell_status bshell_table_ctx_print_headers(struct bshell_table_ctx *ctx) { fx_printf("[bold,bright_green]"); bool repeat = false; - struct table_format_ctx_column *c = NULL; + struct bshell_table_ctx_column *c = NULL; do { repeat = false; @@ -276,7 +273,7 @@ enum bshell_status table_format_ctx_print_headers(struct table_format_ctx *ctx) fx_stream_write_char(ctx->ctx_out, '\n'); for (size_t i = 0; i < ctx->ctx_columns_count; i++) { - struct table_format_ctx_column *c = &ctx->ctx_columns[i]; + struct bshell_table_ctx_column *c = &ctx->ctx_columns[i]; if (c->col_width == 0) { continue; } @@ -301,13 +298,13 @@ enum bshell_status table_format_ctx_print_headers(struct table_format_ctx *ctx) return BSHELL_SUCCESS; } -enum bshell_status table_format_ctx_print_record( - struct table_format_ctx *ctx, +enum bshell_status bshell_table_ctx_print_record( + struct bshell_table_ctx *ctx, const fx_value *record) { fx_stringstream *strm = fx_stringstream_create(); for (size_t i = 0; i < ctx->ctx_columns_count; i++) { - struct table_format_ctx_column *c = &ctx->ctx_columns[i]; + struct bshell_table_ctx_column *c = &ctx->ctx_columns[i]; if (c->col_width == 0) { continue; } diff --git a/bshell/format/verb.c b/bshell.runtime/format/verb.c similarity index 72% rename from bshell/format/verb.c rename to bshell.runtime/format/verb.c index 46731c1..d43e272 100644 --- a/bshell/format/verb.c +++ b/bshell.runtime/format/verb.c @@ -1,13 +1,13 @@ -#include "format.h" +#include -static struct table_format_column verb_table_columns[] = { +static struct bshell_table_column verb_table_columns[] = { TABLE_COLUMN("verb", "verb", 13), TABLE_COLUMN("alias_prefix", "alias_prefix", 13), TABLE_COLUMN("group", "group", 13), TABLE_COLUMN("description", "description", COL_WIDTH_INFINITE), }; -struct table_format verb_table_format = { +struct bshell_table verb_bshell_table = { .fmt_columns = verb_table_columns, .fmt_column_count = sizeof verb_table_columns / sizeof verb_table_columns[0], diff --git a/bshell.runtime/include/bshell/ast.h b/bshell.runtime/include/bshell/ast.h new file mode 100644 index 0000000..e8fe39f --- /dev/null +++ b/bshell.runtime/include/bshell/ast.h @@ -0,0 +1,232 @@ +#ifndef BSHELL_AST_H_ +#define BSHELL_AST_H_ + +#include +#include +#include + +struct bshell_lex_token; + +#define BSHELL_AST_ITERATE_OK(flags) \ + ((struct bshell_ast_iterate_result) {.r_status = BSHELL_SUCCESS, \ + .r_flags = (flags)}) +#define BSHELL_AST_ITERATE_ERR(status) \ + ((struct bshell_ast_iterate_result) {.r_status = (status)}) + +enum bshell_ast_node_type { + BSHELL_AST_NONE = 0x00u, + BSHELL_AST_NULL, + BSHELL_AST_STMT_LIST, + BSHELL_AST_INT, + BSHELL_AST_DOUBLE, + BSHELL_AST_WORD, + BSHELL_AST_STRING, + BSHELL_AST_FSTRING, + BSHELL_AST_VAR, + BSHELL_AST_VAR_SPLAT, + BSHELL_AST_FLAG, + BSHELL_AST_CMDCALL, + BSHELL_AST_FUNCALL, + BSHELL_AST_PIPELINE, + BSHELL_AST_REDIRECTION, + BSHELL_AST_BLOCK, + BSHELL_AST_FUNC, + BSHELL_AST_ARRAY, + BSHELL_AST_HASHTABLE, + BSHELL_AST_HASHTABLE_ITEM, + BSHELL_AST_OP, + BSHELL_AST_IF, + BSHELL_AST_IF_BRANCH, +}; + +struct bshell_ast_iterator_entry { + fx_queue_entry e_entry; + unsigned long e_depth; +}; + +struct bshell_ast_node { + enum bshell_ast_node_type n_type; + struct bshell_ast_node *n_parent; + fx_queue_entry n_entry; + struct bshell_ast_iterator_entry n_it; +}; + +struct bshell_null_ast_node { + struct bshell_ast_node n_base; +}; + +struct bshell_int_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_value; +}; + +struct bshell_double_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_value; +}; + +struct bshell_word_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_value; +}; + +struct bshell_string_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_value; +}; + +struct bshell_fstring_ast_node { + struct bshell_ast_node n_base; + fx_queue n_elements; +}; + +struct bshell_var_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_ident; +}; + +struct bshell_var_splat_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_ident; +}; + +struct bshell_cmdcall_ast_node { + struct bshell_ast_node n_base; + fx_queue n_args; + fx_queue n_redirect; +}; + +struct bshell_funcall_ast_node { + struct bshell_ast_node n_base; + struct bshell_ast_node *n_func; + fx_queue n_args; +}; + +struct bshell_pipeline_ast_node { + struct bshell_ast_node n_base; + fx_queue n_stages; +}; + +struct bshell_redirection_ast_node { + struct bshell_ast_node n_base; + bool n_append : 1; + bool n_out_is_fd : 1; + bool n_out_is_expr : 1; + + unsigned int n_in, n_out; + struct bshell_ast_node *n_out_path_expr; + const char *n_out_path; + struct bshell_lex_token *n_out_tok; +}; + +struct bshell_stmt_list_ast_node { + struct bshell_ast_node n_base; + fx_queue n_statements; +}; + +struct bshell_block_ast_node { + struct bshell_ast_node n_base; + fx_queue n_statements; +}; + +struct bshell_func_ast_node { + struct bshell_ast_node n_base; + struct bshell_lex_token *n_name; + fx_queue n_params; + struct bshell_ast_node *n_body; +}; + +struct bshell_array_ast_node { + struct bshell_ast_node n_base; + fx_queue n_items; +}; + +struct bshell_hashtable_ast_node { + struct bshell_ast_node n_base; + fx_queue n_items; +}; + +struct bshell_hashtable_item_ast_node { + struct bshell_ast_node n_base; + struct bshell_ast_node *n_key, *n_value; +}; + +struct bshell_op_ast_node { + struct bshell_ast_node n_base; + const struct bshell_operator_info *n_op; + struct bshell_ast_node *n_left, *n_right; +}; + +struct bshell_if_branch_ast_node { + struct bshell_ast_node n_base; + struct bshell_ast_node *n_cond; + struct bshell_ast_node *n_body; +}; + +struct bshell_if_ast_node { + struct bshell_ast_node n_base; + fx_queue n_branches; +}; + +struct bshell_ast_iterator { + struct bshell_ast_node *it_cur; + fx_queue it_queue; + unsigned int it_depth; + fx_queue_entry *it_insert_after; +}; + +struct bshell_ast_iterate_result { + enum bshell_status r_status; + enum { + BSHELL_AST_ITERATE_CONTINUE = 0x00u, + BSHELL_AST_ITERATE_STOP = 0x01u, + BSHELL_AST_ITERATE_ADD_CHILDREN = 0x02u, + BSHELL_AST_ITERATE_REPEAT = 0x04u, + } r_flags; +}; + +enum bshell_ast_iteration_type { + BSHELL_AST_ITERATION_PRE, + BSHELL_AST_ITERATION_POST, +}; + +typedef struct bshell_ast_iterate_result (*bshell_ast_iterator_callback)( + struct bshell_ast_node *, + enum bshell_ast_iteration_type, + struct bshell_ast_iterator *, + void *); + +struct bshell_ast_node_definition { + enum bshell_ast_node_type def_id; + size_t def_node_size; + enum bshell_status (*def_collect_children)( + struct bshell_ast_node *, + struct bshell_ast_iterator *); + enum bshell_status (*def_cleanup)(struct bshell_ast_node *); + void (*def_to_string)(const struct bshell_ast_node *, fx_bstr *); +}; + +extern struct bshell_ast_node *bshell_ast_node_create( + enum bshell_ast_node_type type); +extern void bshell_ast_node_destroy(struct bshell_ast_node *node); +extern void bshell_ast_node_to_string( + const struct bshell_ast_node *node, + fx_bstr *out); +extern enum bshell_status bshell_ast_node_iterate( + struct bshell_ast_node *node, + struct bshell_ast_iterator *it, + bshell_ast_iterator_callback callback, + void *arg); + +extern const char *bshell_ast_node_type_to_string( + enum bshell_ast_node_type type); + +extern struct bshell_ast_node *bshell_ast_iterator_peek( + struct bshell_ast_iterator *it); +extern struct bshell_ast_node *bshell_ast_iterator_dequeue( + struct bshell_ast_iterator *it); +extern void bshell_ast_iterator_enqueue( + struct bshell_ast_iterator *it, + struct bshell_ast_node *node); + +#endif diff --git a/bshell/command/alias.h b/bshell.runtime/include/bshell/command/alias.h similarity index 92% rename from bshell/command/alias.h rename to bshell.runtime/include/bshell/command/alias.h index 11ef3ac..596f202 100644 --- a/bshell/command/alias.h +++ b/bshell.runtime/include/bshell/command/alias.h @@ -1,5 +1,5 @@ -#ifndef COMMAND_ALIAS_H_ -#define COMMAND_ALIAS_H_ +#ifndef BSHELL_COMMAND_ALIAS_H_ +#define BSHELL_COMMAND_ALIAS_H_ #include "../verb.h" diff --git a/bshell/command/cmdlet.h b/bshell.runtime/include/bshell/command/cmdlet.h similarity index 85% rename from bshell/command/cmdlet.h rename to bshell.runtime/include/bshell/command/cmdlet.h index be56719..6380a54 100644 --- a/bshell/command/cmdlet.h +++ b/bshell.runtime/include/bshell/command/cmdlet.h @@ -1,5 +1,5 @@ -#ifndef COMMAND_CMDLET_H_ -#define COMMAND_CMDLET_H_ +#ifndef BSHELL_COMMAND_CMDLET_H_ +#define BSHELL_COMMAND_CMDLET_H_ #include "../verb.h" diff --git a/bshell/command/command.h b/bshell.runtime/include/bshell/command/command.h similarity index 96% rename from bshell/command/command.h rename to bshell.runtime/include/bshell/command/command.h index 4195d64..b0b3d31 100644 --- a/bshell/command/command.h +++ b/bshell.runtime/include/bshell/command/command.h @@ -1,5 +1,5 @@ -#ifndef COMMAND_COMMAND_H_ -#define COMMAND_COMMAND_H_ +#ifndef BSHELL_COMMAND_COMMAND_H_ +#define BSHELL_COMMAND_COMMAND_H_ #include #include diff --git a/bshell/command/function.h b/bshell.runtime/include/bshell/command/function.h similarity index 85% rename from bshell/command/function.h rename to bshell.runtime/include/bshell/command/function.h index 4f9e091..05d58dc 100644 --- a/bshell/command/function.h +++ b/bshell.runtime/include/bshell/command/function.h @@ -1,5 +1,5 @@ -#ifndef COMMAND_FUNCTION_H_ -#define COMMAND_FUNCTION_H_ +#ifndef BSHELL_COMMAND_FUNCTION_H_ +#define BSHELL_COMMAND_FUNCTION_H_ #include diff --git a/bshell.runtime/include/bshell/compile.h b/bshell.runtime/include/bshell/compile.h new file mode 100644 index 0000000..4c20b65 --- /dev/null +++ b/bshell.runtime/include/bshell/compile.h @@ -0,0 +1,12 @@ +#ifndef BSHELL_COMPILE_H_ +#define BSHELL_COMPILE_H_ + +#include + +struct bshell_ast_node; + +extern enum bshell_status bshell_compile( + struct bshell_ast_node *src, + bshell_scriptblock *dest); + +#endif diff --git a/bshell.runtime/include/bshell/file.h b/bshell.runtime/include/bshell/file.h new file mode 100644 index 0000000..63fd1e7 --- /dev/null +++ b/bshell.runtime/include/bshell/file.h @@ -0,0 +1,21 @@ +#ifndef BSHELL_FILE_H_ +#define BSHELL_FILE_H_ + +#include +#include +#include + +struct bshell_file { + struct bshell_line_source f_base; + fx_array *f_lines; + char *f_path; + fx_stream *f_strp; + FILE *f_fp; +}; + +extern enum bshell_status bshell_file_open( + const char *path, + struct bshell_file **out); +extern void bshell_file_close(struct bshell_file *file); + +#endif diff --git a/bshell/format/format.h b/bshell.runtime/include/bshell/format.h similarity index 56% rename from bshell/format/format.h rename to bshell.runtime/include/bshell/format.h index 1e74bce..929eca0 100644 --- a/bshell/format/format.h +++ b/bshell.runtime/include/bshell/format.h @@ -1,8 +1,7 @@ -#ifndef FORMAT_H_ -#define FORMAT_H_ - -#include "../status.h" +#ifndef BSHELL_FORMAT_H_ +#define BSHELL_FORMAT_H_ +#include #include #include #include @@ -19,19 +18,19 @@ } #define COL_WIDTH_INFINITE ((size_t)-1) -struct table_format_column { +struct bshell_table_column { const char *col_display_name; const char *col_property_name; size_t col_width; }; -struct table_format { +struct bshell_table { fx_namemap_entry fmt_entry; - const struct table_format_column *fmt_columns; + const struct bshell_table_column *fmt_columns; size_t fmt_column_count; }; -struct table_format_ctx_column { +struct bshell_table_ctx_column { const char *col_title; size_t col_width; size_t col_title_chars_written; @@ -39,17 +38,17 @@ struct table_format_ctx_column { const fx_property *col_property; }; -struct table_format_ctx { - const struct table_format *ctx_fmt; - struct table_format_ctx_column *ctx_columns; +struct bshell_table_ctx { + const struct bshell_table *ctx_fmt; + struct bshell_table_ctx_column *ctx_columns; size_t ctx_columns_count; unsigned int ctx_tty_width; size_t ctx_variable_columns_count; fx_stream *ctx_out; }; -extern enum bshell_status table_format_init(void); -extern const struct table_format *table_format_get_for_type(const fx_type *ty); +extern enum bshell_status bshell_table_init(void); +extern const struct bshell_table *bshell_table_get_for_type(const fx_type *ty); extern enum bshell_status format_object_table( fx_object *object, fx_stream *dest); @@ -57,22 +56,22 @@ extern enum bshell_status format_value_default( const fx_value *value, fx_stream *dest); -extern enum bshell_status table_format_ctx_init( - struct table_format_ctx *ctx, +extern enum bshell_status bshell_table_ctx_init( + struct bshell_table_ctx *ctx, fx_stream *out); -extern enum bshell_status table_format_ctx_cleanup( - struct table_format_ctx *ctx); -extern enum bshell_status table_format_ctx_prepare_columns_from_format( - struct table_format_ctx *ctx, +extern enum bshell_status bshell_table_ctx_cleanup( + struct bshell_table_ctx *ctx); +extern enum bshell_status bshell_table_ctx_prepare_columns_from_format( + struct bshell_table_ctx *ctx, const fx_type *record_type, - const struct table_format *fmt); -extern enum bshell_status table_format_ctx_prepare_columns_from_object( - struct table_format_ctx *ctx, + const struct bshell_table *fmt); +extern enum bshell_status bshell_table_ctx_prepare_columns_from_object( + struct bshell_table_ctx *ctx, const fx_type *record_type); -extern enum bshell_status table_format_ctx_print_headers( - struct table_format_ctx *ctx); -extern enum bshell_status table_format_ctx_print_record( - struct table_format_ctx *ctx, +extern enum bshell_status bshell_table_ctx_print_headers( + struct bshell_table_ctx *ctx); +extern enum bshell_status bshell_table_ctx_print_record( + struct bshell_table_ctx *ctx, const fx_value *record); #endif diff --git a/bshell.runtime/include/bshell/line-source.h b/bshell.runtime/include/bshell/line-source.h new file mode 100644 index 0000000..4200057 --- /dev/null +++ b/bshell.runtime/include/bshell/line-source.h @@ -0,0 +1,40 @@ +#ifndef BSHELL_LINE_SOURCE_H_ +#define BSHELL_LINE_SOURCE_H_ + +#include "status.h" + +#include +#include + +struct bshell_line_source { + enum bshell_status (*s_get_name)( + struct bshell_line_source *, + char *, + size_t, + size_t *); + enum bshell_status ( + *s_readline)(struct bshell_line_source *, fx_stringstream *); + enum bshell_status (*s_get_row)( + struct bshell_line_source *, + size_t, + char *, + size_t, + size_t *); +}; + +extern enum bshell_status bshell_line_source_get_name( + struct bshell_line_source *src, + char *buf, + size_t count, + size_t *nr_read); +extern enum bshell_status bshell_line_source_readline( + struct bshell_line_source *src, + fx_stringstream *out); +extern enum bshell_status bshell_line_source_get_row( + struct bshell_line_source *src, + size_t row, + char *buf, + size_t count, + size_t *nr_read); + +#endif diff --git a/bshell.runtime/include/bshell/parse/lex.h b/bshell.runtime/include/bshell/parse/lex.h new file mode 100644 index 0000000..ae64159 --- /dev/null +++ b/bshell.runtime/include/bshell/parse/lex.h @@ -0,0 +1,97 @@ +#ifndef BSHELL_PARSE_LEX_H_ +#define BSHELL_PARSE_LEX_H_ + +#include +#include +#include +#include +#include + +#define BSHELL_LEX_STATE_MAX_TERMINATORS 16 + +struct bshell_line_source; + +enum bshell_lex_flags { + LEX_PRINT_TOKENS = 0x01u, +}; + +enum bshell_lex_token_flags { + /* a token with this flag not only interrupts the word currently being + * scanned, but also stops multi-words */ + BSHELL_LEX_TOKEN_TERMINATES_WORD = 0x01u, + /* a token with this flag can appear at the start of an arithmetic + * expression. a statement that encounters this token as its first char + * will switch to arithmetic mode */ + BSHELL_LEX_TOKEN_UNARY_ARITHMETIC = 0x02u, + /* if a token has this flag defined, the lexer will + * switch to command mode after encountering it. */ + BSHELL_LEX_TOKEN_COMMAND_MODE = 0x08u, + /* if a token has this flag defined, the lexer will + * switch to statement mode after encountering it. */ + BSHELL_LEX_TOKEN_STATEMENT_MODE = 0x10u, +}; + +enum bshell_lex_state_id { + BSHELL_LEX_STATE_STATEMENT = 0x01u, + BSHELL_LEX_STATE_COMMAND = 0x02u, + BSHELL_LEX_STATE_ARITHMETIC = 0x04u, + BSHELL_LEX_STATE_STRING = 0x08u, + BSHELL_LEX_STATE_WORD = 0x10u, + BSHELL_LEX_STATE_HASHTABLE = 0x20u, +}; + +struct bshell_lex_token_definition { + int id; + const char *name; + uint64_t name_hash; + enum bshell_lex_state_id enabled_states; + enum bshell_lex_token_flags flags; +}; + +struct bshell_lex_symbol_node { + char s_char; + struct bshell_lex_token_definition *s_def; + + fx_queue_entry s_entry; + fx_queue s_children; +}; + +struct bshell_lex_state { + const struct bshell_lex_state_type *s_type; + unsigned int s_terminators[BSHELL_LEX_STATE_MAX_TERMINATORS]; + unsigned int s_nr_terminators; + unsigned int s_paren_depth; + fx_queue_entry s_entry; + fx_string *s_tempstr; + unsigned int s_flags; +}; + +struct bshell_lex_ctx { + enum bshell_lex_flags lex_flags; + fx_queue lex_tokens; + struct bshell_line_source *lex_src; + fx_stringstream *lex_buf; + fx_string *lex_tmp; + fx_wchar lex_ch; + fx_queue lex_state; + void (*lex_token_scanned)( + struct bshell_lex_ctx *, + struct bshell_lex_token *); + enum bshell_lex_token_type lex_prev_token; + struct bshell_char_cell lex_cursor, lex_start, lex_end; + struct bshell_lex_symbol_node *lex_sym_tree; + enum bshell_status lex_status; +}; + +extern enum bshell_status bshell_lex_ctx_init( + struct bshell_lex_ctx *ctx, + enum bshell_lex_flags flags, + struct bshell_line_source *src); +extern enum bshell_status bshell_lex_ctx_cleanup(struct bshell_lex_ctx *ctx); + +extern struct bshell_lex_token *bshell_lex_ctx_peek(struct bshell_lex_ctx *ctx); +extern struct bshell_lex_token *bshell_lex_ctx_claim( + struct bshell_lex_ctx *ctx); +extern void bshell_lex_ctx_discard(struct bshell_lex_ctx *ctx); + +#endif diff --git a/bshell.runtime/include/bshell/parse/parse.h b/bshell.runtime/include/bshell/parse/parse.h new file mode 100644 index 0000000..4be4067 --- /dev/null +++ b/bshell.runtime/include/bshell/parse/parse.h @@ -0,0 +1,22 @@ +#ifndef BSHELL_PARSE_PARSE_H_ +#define BSHELL_PARSE_PARSE_H_ + +#include + +struct bshell_lex_ctx; +struct bshell_ast_node; + +struct bshell_parse_ctx { + struct bshell_lex_ctx *p_src; + enum bshell_status p_status; +}; + +extern enum bshell_status bshell_parse_ctx_init( + struct bshell_parse_ctx *ctx, + struct bshell_lex_ctx *src); +extern void bshell_parse_ctx_cleanup(struct bshell_parse_ctx *ctx); + +extern struct bshell_ast_node *bshell_parse_ctx_read_node( + struct bshell_parse_ctx *ctx); + +#endif diff --git a/bshell.runtime/include/bshell/parse/token.h b/bshell.runtime/include/bshell/parse/token.h new file mode 100644 index 0000000..bc08306 --- /dev/null +++ b/bshell.runtime/include/bshell/parse/token.h @@ -0,0 +1,190 @@ +#ifndef BSHELL_PARSE_TOKEN_H_ +#define BSHELL_PARSE_TOKEN_H_ + +#include +#include +#include + +struct bshell_char_cell { + unsigned long c_row, c_col; +}; + +enum bshell_lex_token_type { + BSHELL_TOK_NONE = 0, + __BSHELL_TOK_INDEX_BASE = 100, + BSHELL_TOK_KEYWORD, + BSHELL_TOK_SYMBOL, + BSHELL_TOK_INT, + BSHELL_TOK_DOUBLE, + BSHELL_TOK_WORD, + BSHELL_TOK_WORD_START, + BSHELL_TOK_WORD_END, + BSHELL_TOK_FLAG, + BSHELL_TOK_OPERATOR, + BSHELL_TOK_VAR, + BSHELL_TOK_VAR_SPLAT, + BSHELL_TOK_STRING, + BSHELL_TOK_STR_START, + BSHELL_TOK_STR_END, + BSHELL_TOK_LINEFEED, + __BSHELL_TOK_INDEX_LIMIT, +}; + +enum bshell_lex_keyword { + BSHELL_KW_NONE = 0, + __BSHELL_KW_INDEX_BASE = 200, + BSHELL_KW_FUNC, + BSHELL_KW_IF, + BSHELL_KW_ELSEIF, + BSHELL_KW_ELSE, + __BSHELL_KW_INDEX_LIMIT, +}; + +enum bshell_lex_operator { + BSHELL_TKOP_NONE = 0, + __BSHELL_TKOP_INDEX_BASE = 300, + BSHELL_TKOP_F, + BSHELL_TKOP_BAND, + BSHELL_TKOP_BOR, + BSHELL_TKOP_BXOR, + BSHELL_TKOP_BNOT, + BSHELL_TKOP_SHL, + BSHELL_TKOP_SHR, + BSHELL_TKOP_EQ, + BSHELL_TKOP_NE, + BSHELL_TKOP_GT, + BSHELL_TKOP_LT, + BSHELL_TKOP_GE, + BSHELL_TKOP_LE, + BSHELL_TKOP_MATCH, + BSHELL_TKOP_NOTMATCH, + BSHELL_TKOP_REPLACE, + BSHELL_TKOP_LIKE, + BSHELL_TKOP_NOTLIKE, + BSHELL_TKOP_IN, + BSHELL_TKOP_NOTIN, + BSHELL_TKOP_CONTAINS, + BSHELL_TKOP_NOTCONTAINS, + BSHELL_TKOP_AND, + BSHELL_TKOP_OR, + BSHELL_TKOP_XOR, + BSHELL_TKOP_NOT, + BSHELL_TKOP_SPLIT, + BSHELL_TKOP_JOIN, + BSHELL_TKOP_IS, + BSHELL_TKOP_ISNOT, + BSHELL_TKOP_AS, + __BSHELL_TKOP_INDEX_LIMIT, +}; + +enum bshell_lex_symbol { + BSHELL_SYM_NONE = 0, + __BSHELL_SYM_INDEX_BASE = 400, + BSHELL_SYM_BANG, + BSHELL_SYM_PLUS, + BSHELL_SYM_HYPHEN, + BSHELL_SYM_FORWARD_SLASH, + BSHELL_SYM_ASTERISK, + BSHELL_SYM_AMPERSAND, + BSHELL_SYM_PERCENT, + BSHELL_SYM_SQUOTE, + BSHELL_SYM_DQUOTE, + BSHELL_SYM_HASH, + BSHELL_SYM_COLON_COLON, + BSHELL_SYM_SEMICOLON, + BSHELL_SYM_COMMA, + BSHELL_SYM_DOLLAR, + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_SYM_DOLLAR_LEFT_BRACE, + BSHELL_SYM_DOT, + BSHELL_SYM_DOT_DOT, + BSHELL_SYM_PIPE, + BSHELL_SYM_AT, + BSHELL_SYM_AT_LEFT_PAREN, + BSHELL_SYM_AT_LEFT_BRACE, + BSHELL_SYM_LEFT_BRACE, + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_LEFT_BRACKET, + BSHELL_SYM_RIGHT_BRACKET, + BSHELL_SYM_LEFT_PAREN, + BSHELL_SYM_RIGHT_PAREN, + BSHELL_SYM_EQUAL, + BSHELL_SYM_PLUS_EQUAL, + BSHELL_SYM_HYPHEN_EQUAL, + BSHELL_SYM_ASTERISK_EQUAL, + BSHELL_SYM_FORWARD_SLASH_EQUAL, + BSHELL_SYM_PERCENT_EQUAL, + BSHELL_SYM_QUESTION_DOT, + BSHELL_SYM_QUESTION_LEFT_BRACKET, + __BSHELL_SYM_INDEX_LIMIT, +}; + +struct bshell_lex_token { + enum bshell_lex_token_type tok_type; + + struct bshell_char_cell tok_start, tok_end; + + fx_queue_entry tok_entry; + + union { + enum bshell_lex_keyword tok_keyword; + enum bshell_lex_symbol tok_symbol; + enum bshell_lex_operator tok_operator; + fx_value tok_number; + char *tok_str; + }; +}; + +extern struct bshell_lex_token *bshell_lex_token_create( + enum bshell_lex_token_type type); +extern struct bshell_lex_token *bshell_lex_token_create_with_string( + enum bshell_lex_token_type type, + const char *s); +extern void bshell_lex_token_destroy(struct bshell_lex_token *tok); + +extern struct bshell_lex_token *bshell_lex_token_change_type( + struct bshell_lex_token *tok, + enum bshell_lex_token_type new_type); +extern void bshell_lex_token_change_string( + struct bshell_lex_token *tok, + const char *s); + +static inline bool bshell_lex_token_is_symbol( + struct bshell_lex_token *tok, + enum bshell_lex_symbol sym) +{ + return (tok->tok_type == BSHELL_TOK_SYMBOL && tok->tok_symbol == sym); +} +static inline bool bshell_lex_token_is_keyword( + struct bshell_lex_token *tok, + enum bshell_lex_keyword kw) +{ + return (tok->tok_type == BSHELL_TOK_KEYWORD && tok->tok_keyword == kw); +} +static inline bool bshell_lex_token_type_has_string_value( + enum bshell_lex_token_type type) +{ + switch (type) { + case BSHELL_TOK_WORD: + case BSHELL_TOK_STRING: + case BSHELL_TOK_FLAG: + case BSHELL_TOK_VAR: + case BSHELL_TOK_VAR_SPLAT: + return true; + default: + return false; + } +} +static inline bool bshell_lex_token_has_string_value( + const struct bshell_lex_token *tok) +{ + return bshell_lex_token_type_has_string_value(tok->tok_type); +} + +extern const char *bshell_token_type_to_string(enum bshell_lex_token_type type); +extern const char *bshell_lex_keyword_to_string( + enum bshell_lex_keyword keyword); +extern const char *bshell_lex_symbol_to_string(enum bshell_lex_symbol sym); +extern const char *bshell_lex_operator_to_string(enum bshell_lex_operator op); + +#endif diff --git a/bshell/runtime/cmdcall.h b/bshell.runtime/include/bshell/runtime/cmdcall.h similarity index 91% rename from bshell/runtime/cmdcall.h rename to bshell.runtime/include/bshell/runtime/cmdcall.h index b3713a7..2bced0e 100644 --- a/bshell/runtime/cmdcall.h +++ b/bshell.runtime/include/bshell/runtime/cmdcall.h @@ -1,5 +1,5 @@ -#ifndef RUNTIME_CMDCALL_H_ -#define RUNTIME_CMDCALL_H_ +#ifndef BSHELL_RUNTIME_CMDCALL_H_ +#define BSHELL_RUNTIME_CMDCALL_H_ #include #include diff --git a/bshell.runtime/include/bshell/runtime/opcode.h b/bshell.runtime/include/bshell/runtime/opcode.h new file mode 100644 index 0000000..69285cc --- /dev/null +++ b/bshell.runtime/include/bshell/runtime/opcode.h @@ -0,0 +1,82 @@ +#ifndef BSHELL_RUNTIME_OPCODE_H_ +#define BSHELL_RUNTIME_OPCODE_H_ + +#include + +#define BSHELL_INSTRUCTION_INVALID 0xFFFFFFFF + +typedef uint32_t bshell_instruction; + +enum bshell_opcode { + BSHELL_OPCODE_NOP = 0, + BSHELL_OPCODE_LDC_INT, + BSHELL_OPCODE_LDC_STR, + BSHELL_OPCODE_LDC_FP, + BSHELL_OPCODE_LDGLOBAL, + BSHELL_OPCODE_LDLOCAL, + BSHELL_OPCODE_LDBLOCK, + BSHELL_OPCODE_LDENV, + BSHELL_OPCODE_LDSTATIC, + BSHELL_OPCODE_LDARG, + BSHELL_OPCODE_LDPROP, + BSHELL_OPCODE_LDELEM, + BSHELL_OPCODE_LDELEM_C, + BSHELL_OPCODE_STLOCAL, + BSHELL_OPCODE_STPROP, + BSHELL_OPCODE_STELEM, + BSHELL_OPCODE_LDCMD, + BSHELL_OPCODE_PEXEC, + BSHELL_OPCODE_CALL, + BSHELL_OPCODE_MK_STR, + BSHELL_OPCODE_MK_ARRAY, + BSHELL_OPCODE_MK_HTAB, + BSHELL_OPCODE_POP, + BSHELL_OPCODE_ADD, + BSHELL_OPCODE_SUB, + BSHELL_OPCODE_MUL, + BSHELL_OPCODE_DIV, + BSHELL_OPCODE_ADD_IP, + BSHELL_OPCODE_MOD, + BSHELL_OPCODE_INC, + BSHELL_OPCODE_DEC, + BSHELL_OPCODE_SHL, + BSHELL_OPCODE_SHR, + BSHELL_OPCODE_BAND, + BSHELL_OPCODE_BOR, + BSHELL_OPCODE_BXOR, + BSHELL_OPCODE_BNOT, + BSHELL_OPCODE_CMP_NULL, + BSHELL_OPCODE_CMP_EQ, + BSHELL_OPCODE_CMP_NE, + BSHELL_OPCODE_CMP_LT, + BSHELL_OPCODE_CMP_GT, + BSHELL_OPCODE_CMP_LE, + BSHELL_OPCODE_CMP_GE, + BSHELL_OPCODE_LAND, + BSHELL_OPCODE_LOR, + BSHELL_OPCODE_LXOR, + BSHELL_OPCODE_LNOT, + BSHELL_OPCODE_BR, + BSHELL_OPCODE_BR_TRUE, + BSHELL_OPCODE_RANGE, + BSHELL_OPCODE_MATCH, + BSHELL_OPCODE_REPLACE, + BSHELL_OPCODE_LIKE, + BSHELL_OPCODE_IN, + BSHELL_OPCODE_FMT, + BSHELL_OPCODE_CONTAINS, + BSHELL_OPCODE_SPLIT, + BSHELL_OPCODE_JOIN, + BSHELL_OPCODE_IS, + BSHELL_OPCODE_AS, +}; + +extern bshell_instruction bshell_instruction_encode( + enum bshell_opcode opcode, + uint32_t arg); +extern void bshell_instruction_decode( + bshell_instruction instr, + enum bshell_opcode *out_opcode, + uint32_t *out_arg); + +#endif diff --git a/bshell.runtime/include/bshell/runtime/operator.h b/bshell.runtime/include/bshell/runtime/operator.h new file mode 100644 index 0000000..7937056 --- /dev/null +++ b/bshell.runtime/include/bshell/runtime/operator.h @@ -0,0 +1,126 @@ +#ifndef BSHELL_RUNTIME_OPERATOR_H_ +#define BSHELL_RUNTIME_OPERATOR_H_ + +enum bshell_operator_precedence { + BSHELL_PRECEDENCE_MINIMUM = 0, + BSHELL_PRECEDENCE_ASSIGN, + BSHELL_PRECEDENCE_PIPELINE, + BSHELL_PRECEDENCE_LOGICAL, + BSHELL_PRECEDENCE_BITWISE, + BSHELL_PRECEDENCE_COMPARISON, + BSHELL_PRECEDENCE_ADDITION, + BSHELL_PRECEDENCE_MULTIPLICATION, + BSHELL_PRECEDENCE_NEGATE, + BSHELL_PRECEDENCE_FORMAT, + BSHELL_PRECEDENCE_RANGE, + BSHELL_PRECEDENCE_NOT, + BSHELL_PRECEDENCE_INCREMENT, + BSHELL_PRECEDENCE_ARRAY, + BSHELL_PRECEDENCE_JOIN, + BSHELL_PRECEDENCE_SPLIT, + BSHELL_PRECEDENCE_CAST, + BSHELL_PRECEDENCE_SUBSCRIPT, + BSHELL_PRECEDENCE_STATIC_ACCESS, + BSHELL_PRECEDENCE_MEMBER_ACCESS, + BSHELL_PRECEDENCE_PARENTHESIS, +}; + +enum bshell_operator_associativity { + BSHELL_ASSOCIATIVITY_LEFT, + BSHELL_ASSOCIATIVITY_RIGHT, +}; + +enum bshell_operator_location { + BSHELL_OPL_PREFIX, + BSHELL_OPL_INFIX, + BSHELL_OPL_POSTFIX, +}; + +enum bshell_operator_arity { + BSHELL_OPA_UNARY, + BSHELL_OPA_BINARY, +}; + +enum bshell_operator_id { + BSHELL_OP_NONE = 0, + BSHELL_OP_ADD, + BSHELL_OP_SUBTRACT, + BSHELL_OP_MULTIPLY, + BSHELL_OP_DIVIDE, + BSHELL_OP_MODULO, + BSHELL_OP_INCREMENT, + BSHELL_OP_DECREMENT, + BSHELL_OP_LEFT_SHIFT, + BSHELL_OP_RIGHT_SHIFT, + BSHELL_OP_BINARY_AND, + BSHELL_OP_BINARY_OR, + BSHELL_OP_BINARY_XOR, + BSHELL_OP_BINARY_NOT, + BSHELL_OP_LESS_THAN, + BSHELL_OP_GREATER_THAN, + BSHELL_OP_EQUAL, + BSHELL_OP_NOT_EQUAL, + BSHELL_OP_LESS_EQUAL, + BSHELL_OP_GREATER_EQUAL, + BSHELL_OP_ASSIGN, + BSHELL_OP_ADD_ASSIGN, + BSHELL_OP_SUBTRACT_ASSIGN, + BSHELL_OP_MULTIPLY_ASSIGN, + BSHELL_OP_DIVIDE_ASSIGN, + BSHELL_OP_MODULO_ASSIGN, + BSHELL_OP_LOGICAL_AND, + BSHELL_OP_LOGICAL_OR, + BSHELL_OP_LOGICAL_XOR, + BSHELL_OP_LOGICAL_NOT, + BSHELL_OP_RANGE, + BSHELL_OP_MATCH, + BSHELL_OP_NOTMATCH, + BSHELL_OP_REPLACE, + BSHELL_OP_LIKE, + BSHELL_OP_NOTLIKE, + BSHELL_OP_IN, + BSHELL_OP_NOTIN, + BSHELL_OP_FORMAT, + BSHELL_OP_CONTAINS, + BSHELL_OP_NOTCONTAINS, + BSHELL_OP_USPLIT, + BSHELL_OP_BSPLIT, + BSHELL_OP_UJOIN, + BSHELL_OP_BJOIN, + BSHELL_OP_IS, + BSHELL_OP_ISNOT, + BSHELL_OP_AS, + + BSHELL_OP_SUBSCRIPT, + BSHELL_OP_CONDITIONAL_SUBSCRIPT, + + BSHELL_OP_ARRAY_DELIMITER, + BSHELL_OP_ACCESS, + BSHELL_OP_STATIC_ACCESS, + BSHELL_OP_CONDITIONAL_ACCESS, + + /* these are not real operators, and are just used internally by the + * parser. */ + BSHELL_OP_CAST, + BSHELL_OP_SUBEXPR, + BSHELL_OP_PAREN, + BSHELL_OP_SCRIPTBLOCK, + BSHELL_OP_ARRAY_START, + BSHELL_OP_HASHTABLE_START, +}; + +struct bshell_operator_info { + enum bshell_operator_id op_id; + enum bshell_operator_precedence op_precedence; + enum bshell_operator_associativity op_associativity; + enum bshell_operator_location op_location; + enum bshell_operator_arity op_arity; +}; + +extern const struct bshell_operator_info *bshell_operator_get_by_id( + enum bshell_operator_id id); +extern const struct bshell_operator_info *bshell_operator_get_by_token( + unsigned int token); +extern const char *bshell_operator_id_to_string(enum bshell_operator_id op); + +#endif diff --git a/bshell/runtime/pipeline.h b/bshell.runtime/include/bshell/runtime/pipeline.h similarity index 94% rename from bshell/runtime/pipeline.h rename to bshell.runtime/include/bshell/runtime/pipeline.h index 6c41244..0a50195 100644 --- a/bshell/runtime/pipeline.h +++ b/bshell.runtime/include/bshell/runtime/pipeline.h @@ -1,5 +1,5 @@ -#ifndef RUNTIME_PIPELINE_H_ -#define RUNTIME_PIPELINE_H_ +#ifndef BSHELL_RUNTIME_PIPELINE_H_ +#define BSHELL_RUNTIME_PIPELINE_H_ #include "../command/command.h" #include "../runtime/cmdcall.h" diff --git a/bshell/runtime/runtime.h b/bshell.runtime/include/bshell/runtime/runtime.h similarity index 68% rename from bshell/runtime/runtime.h rename to bshell.runtime/include/bshell/runtime/runtime.h index 0f23dc8..b5c7841 100644 --- a/bshell/runtime/runtime.h +++ b/bshell.runtime/include/bshell/runtime/runtime.h @@ -1,18 +1,17 @@ -#ifndef RUNTIME_RUNTIME_H_ -#define RUNTIME_RUNTIME_H_ - -#include "../command/command.h" -#include "../script-block.h" -#include "var.h" +#ifndef BSHELL_RUNTIME_RUNTIME_H_ +#define BSHELL_RUNTIME_RUNTIME_H_ +#include +#include +#include #include #include #include -struct runtime_scope; +struct bshell_runtime_scope; struct bshell_runtime { - struct runtime_scope *rt_global; + struct bshell_runtime_scope *rt_global; fx_hashtable *rt_aliases; fx_queue rt_scope; }; @@ -44,4 +43,10 @@ extern enum bshell_status bshell_runtime_push_scope( extern enum bshell_status bshell_runtime_pop_scope(struct bshell_runtime *rt); extern fx_value bshell_runtime_eval(struct bshell_runtime *rt); +extern struct bshell_runtime_scope *bshell_runtime_get_current_scope( + struct bshell_runtime *rt); +extern struct bshell_runtime_scope *bshell_runtime_get_parent_scope( + struct bshell_runtime *rt, + struct bshell_runtime_scope *scope); + #endif diff --git a/bshell.runtime/include/bshell/runtime/scope.h b/bshell.runtime/include/bshell/runtime/scope.h new file mode 100644 index 0000000..f928998 --- /dev/null +++ b/bshell.runtime/include/bshell/runtime/scope.h @@ -0,0 +1,11 @@ +#ifndef BSHELL_RUNTIME_SCOPE_H_ +#define BSHELL_RUNTIME_SCOPE_H_ + +#include + +struct bshell_runtime_scope; + +extern fx_hashtable *bshell_runtime_scope_get_functions( + struct bshell_runtime_scope *scope); + +#endif diff --git a/bshell/script-block.h b/bshell.runtime/include/bshell/runtime/script-block.h similarity index 93% rename from bshell/script-block.h rename to bshell.runtime/include/bshell/runtime/script-block.h index ef341d0..73b1630 100644 --- a/bshell/script-block.h +++ b/bshell.runtime/include/bshell/runtime/script-block.h @@ -1,8 +1,7 @@ -#ifndef SCRIPT_BLOCK_H_ -#define SCRIPT_BLOCK_H_ - -#include "runtime/opcode.h" +#ifndef BSHELL_RUNTIME_SCRIPT_BLOCK_H_ +#define BSHELL_RUNTIME_SCRIPT_BLOCK_H_ +#include #include #include diff --git a/bshell/runtime/var.h b/bshell.runtime/include/bshell/runtime/var.h similarity index 91% rename from bshell/runtime/var.h rename to bshell.runtime/include/bshell/runtime/var.h index 7ef2a7d..b79e7ec 100644 --- a/bshell/runtime/var.h +++ b/bshell.runtime/include/bshell/runtime/var.h @@ -1,5 +1,5 @@ -#ifndef RUNTIME_VAR_H_ -#define RUNTIME_VAR_H_ +#ifndef BSHELL_RUNTIME_VAR_H_ +#define BSHELL_RUNTIME_VAR_H_ #include #include diff --git a/bshell/status.h b/bshell.runtime/include/bshell/status.h similarity index 90% rename from bshell/status.h rename to bshell.runtime/include/bshell/status.h index f0b1da6..82a49be 100644 --- a/bshell/status.h +++ b/bshell.runtime/include/bshell/status.h @@ -1,5 +1,5 @@ -#ifndef STATUS_H_ -#define STATUS_H_ +#ifndef BSHELL_STATUS_H_ +#define BSHELL_STATUS_H_ enum bshell_status { BSHELL_SUCCESS = 0, diff --git a/bshell/verb.h b/bshell.runtime/include/bshell/verb.h similarity index 98% rename from bshell/verb.h rename to bshell.runtime/include/bshell/verb.h index df202d9..75fffdd 100644 --- a/bshell/verb.h +++ b/bshell.runtime/include/bshell/verb.h @@ -1,5 +1,5 @@ -#ifndef VERB_H_ -#define VERB_H_ +#ifndef BSHELL_VERB_H_ +#define BSHELL_VERB_H_ #include #include diff --git a/bshell/line-source.c b/bshell.runtime/line-source.c similarity index 63% rename from bshell/line-source.c rename to bshell.runtime/line-source.c index 0a9c6e6..cb39fee 100644 --- a/bshell/line-source.c +++ b/bshell.runtime/line-source.c @@ -1,7 +1,7 @@ -#include "line-source.h" +#include -enum bshell_status line_source_get_name( - struct line_source *src, +enum bshell_status bshell_line_source_get_name( + struct bshell_line_source *src, char *buf, size_t count, size_t *nr_read) @@ -13,8 +13,8 @@ enum bshell_status line_source_get_name( return BSHELL_ERR_NOT_SUPPORTED; } -enum bshell_status line_source_readline( - struct line_source *src, +enum bshell_status bshell_line_source_readline( + struct bshell_line_source *src, fx_stringstream *out) { if (src->s_readline) { @@ -24,8 +24,8 @@ enum bshell_status line_source_readline( return BSHELL_ERR_NOT_SUPPORTED; } -enum bshell_status line_source_get_row( - struct line_source *src, +enum bshell_status bshell_line_source_get_row( + struct bshell_line_source *src, size_t row, char *buf, size_t count, diff --git a/bshell.runtime/operator.c b/bshell.runtime/operator.c new file mode 100644 index 0000000..1c2f8c1 --- /dev/null +++ b/bshell.runtime/operator.c @@ -0,0 +1,274 @@ +#include +#include + +#define OP(id, p, a, l, u) \ + [BSHELL_OP_##id] = { \ + .op_id = (BSHELL_OP_##id), \ + .op_precedence = (BSHELL_PRECEDENCE_##p), \ + .op_associativity = (BSHELL_ASSOCIATIVITY_##a), \ + .op_location = (BSHELL_OPL_##l), \ + .op_arity = (BSHELL_OPA_##u), \ + } + +#define BSHELL_TOK_OP(id, tok) \ + [BSHELL_TOK_##tok - __BSHELL_TOK_INDEX_BASE] = &operators[BSHELL_OP_##id] +#define BSHELL_SYM_OP(id, sym) \ + [BSHELL_SYM_##sym - __BSHELL_SYM_INDEX_BASE] = &operators[BSHELL_OP_##id] +#define BSHELL_KW_OP(id, kw) [BSHELL_KW_##kw - __BSHELL_KW_INDEX_BASE] = &operators[BSHELL_OP_##id] +#define BSHELL_TKOP_OP(id, kw) \ + [BSHELL_TKOP_##kw - __BSHELL_TKOP_INDEX_BASE] \ + = &operators[BSHELL_OP_##id] + +/* clang-format off */ +static const struct bshell_operator_info operators[] = { + OP(ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY), + OP(CONDITIONAL_ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY), + OP(STATIC_ACCESS, STATIC_ACCESS, LEFT, INFIX, BINARY), + OP(SUBSCRIPT, SUBSCRIPT, LEFT, INFIX, BINARY), + OP(CONDITIONAL_SUBSCRIPT, SUBSCRIPT, LEFT, INFIX, BINARY), + OP(CAST, CAST, LEFT, PREFIX, UNARY), + OP(USPLIT, SPLIT, LEFT, PREFIX, UNARY), + OP(UJOIN, JOIN, LEFT, PREFIX, UNARY), + OP(ARRAY_DELIMITER, ARRAY, LEFT, INFIX, BINARY), + OP(INCREMENT, INCREMENT, LEFT, INFIX, BINARY), + OP(LOGICAL_NOT, NOT, LEFT, PREFIX, UNARY), + OP(RANGE, RANGE, LEFT, INFIX, BINARY), + OP(FORMAT, FORMAT, LEFT, INFIX, BINARY), + OP(MULTIPLY, MULTIPLICATION, LEFT, INFIX, BINARY), + OP(DIVIDE, MULTIPLICATION, LEFT, INFIX, BINARY), + OP(MODULO, MULTIPLICATION, LEFT, INFIX, BINARY), + OP(ADD, ADDITION, LEFT, INFIX, BINARY), + OP(SUBTRACT, ADDITION, LEFT, INFIX, BINARY), + + OP(BSPLIT, COMPARISON, LEFT, INFIX, BINARY), + OP(BJOIN, COMPARISON, LEFT, INFIX, BINARY), + OP(IS, COMPARISON, LEFT, INFIX, BINARY), + OP(ISNOT, COMPARISON, LEFT, INFIX, BINARY), + OP(AS, COMPARISON, LEFT, INFIX, BINARY), + OP(EQUAL, COMPARISON, LEFT, INFIX, BINARY), + OP(NOT_EQUAL, COMPARISON, LEFT, INFIX, BINARY), + OP(GREATER_THAN, COMPARISON, LEFT, INFIX, BINARY), + OP(LESS_THAN, COMPARISON, LEFT, INFIX, BINARY), + OP(GREATER_EQUAL, COMPARISON, LEFT, INFIX, BINARY), + OP(LESS_EQUAL, COMPARISON, LEFT, INFIX, BINARY), + OP(LIKE, COMPARISON, LEFT, INFIX, BINARY), + OP(NOTLIKE, COMPARISON, LEFT, INFIX, BINARY), + OP(MATCH, COMPARISON, LEFT, INFIX, BINARY), + OP(NOTMATCH, COMPARISON, LEFT, INFIX, BINARY), + OP(IN, COMPARISON, LEFT, INFIX, BINARY), + OP(NOTIN, COMPARISON, LEFT, INFIX, BINARY), + OP(CONTAINS, COMPARISON, LEFT, INFIX, BINARY), + OP(NOTCONTAINS, COMPARISON, LEFT, INFIX, BINARY), + OP(REPLACE, COMPARISON, LEFT, INFIX, BINARY), + + OP(LOGICAL_AND, LOGICAL, LEFT, INFIX, BINARY), + OP(LOGICAL_OR, LOGICAL, LEFT, INFIX, BINARY), + OP(LOGICAL_XOR, LOGICAL, LEFT, INFIX, BINARY), + + OP(BINARY_AND, BITWISE, LEFT, INFIX, BINARY), + OP(BINARY_OR, BITWISE, LEFT, INFIX, BINARY), + OP(BINARY_NOT, BITWISE, LEFT, INFIX, BINARY), + OP(BINARY_XOR, BITWISE, LEFT, INFIX, BINARY), + OP(LEFT_SHIFT, BITWISE, LEFT, INFIX, BINARY), + OP(RIGHT_SHIFT, BITWISE, LEFT, INFIX, BINARY), + + OP(ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), + OP(ADD_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), + OP(SUBTRACT_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), + OP(MULTIPLY_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), + OP(DIVIDE_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), + OP(MODULO_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), + + /* these are not real operators, and are just used internally by the + * parser. */ + OP(SUBEXPR, PARENTHESIS, LEFT, PREFIX, UNARY), + OP(ARRAY_START, PARENTHESIS, LEFT, PREFIX, UNARY), + OP(PAREN, PARENTHESIS, LEFT, PREFIX, UNARY), + OP(HASHTABLE_START, PARENTHESIS, LEFT, PREFIX, UNARY), + OP(SCRIPTBLOCK, PARENTHESIS, LEFT, PREFIX, UNARY), +}; +static const size_t nr_operators = sizeof operators / sizeof operators[0]; + +static const struct bshell_operator_info *bshell_operator_symbols[] = { + BSHELL_SYM_OP(LOGICAL_NOT, BANG), + BSHELL_SYM_OP(ASSIGN, EQUAL), + BSHELL_SYM_OP(ADD, PLUS), + BSHELL_SYM_OP(SUBTRACT, HYPHEN), + BSHELL_SYM_OP(MULTIPLY, ASTERISK), + BSHELL_SYM_OP(DIVIDE, FORWARD_SLASH), + BSHELL_SYM_OP(MODULO, PERCENT), + BSHELL_SYM_OP(ADD_ASSIGN, PLUS_EQUAL), + BSHELL_SYM_OP(SUBTRACT_ASSIGN, HYPHEN_EQUAL), + BSHELL_SYM_OP(MULTIPLY_ASSIGN, ASTERISK_EQUAL), + BSHELL_SYM_OP(DIVIDE_ASSIGN, FORWARD_SLASH_EQUAL), + BSHELL_SYM_OP(MODULO_ASSIGN, PERCENT_EQUAL), + BSHELL_SYM_OP(RANGE, DOT_DOT), + BSHELL_SYM_OP(SUBSCRIPT, LEFT_BRACKET), + BSHELL_SYM_OP(CONDITIONAL_SUBSCRIPT, QUESTION_LEFT_BRACKET), + + BSHELL_SYM_OP(ACCESS, DOT), + BSHELL_SYM_OP(CONDITIONAL_ACCESS, QUESTION_DOT), + BSHELL_SYM_OP(STATIC_ACCESS, COLON_COLON), + + /* parser-internal pseudo-operators. */ + + /* CAST uses the same symbol as SUBSCRIPT */ + /* BSHELL_SYM_OP(CAST, LEFT_BRACKET), */ + BSHELL_SYM_OP(SUBEXPR, DOLLAR_LEFT_PAREN), + BSHELL_SYM_OP(PAREN, LEFT_PAREN), + BSHELL_SYM_OP(ARRAY_START, AT_LEFT_PAREN), + BSHELL_SYM_OP(HASHTABLE_START, AT_LEFT_BRACE), +}; +static const size_t nr_bshell_operator_symbols = sizeof bshell_operator_symbols / sizeof bshell_operator_symbols[0]; + +static const struct bshell_operator_info *bshell_operator_token_ops[] = { + BSHELL_TKOP_OP(FORMAT, F), + BSHELL_TKOP_OP(BINARY_AND, BAND), + BSHELL_TKOP_OP(BINARY_OR, BOR), + BSHELL_TKOP_OP(BINARY_XOR, BXOR), + BSHELL_TKOP_OP(BINARY_NOT, BNOT), + BSHELL_TKOP_OP(LEFT_SHIFT, SHL), + BSHELL_TKOP_OP(RIGHT_SHIFT, SHR), + BSHELL_TKOP_OP(EQUAL, EQ), + BSHELL_TKOP_OP(NOT_EQUAL, NE), + BSHELL_TKOP_OP(GREATER_THAN, GT), + BSHELL_TKOP_OP(LESS_THAN, LT), + BSHELL_TKOP_OP(GREATER_EQUAL, GE), + BSHELL_TKOP_OP(LESS_EQUAL, LE), + BSHELL_TKOP_OP(MATCH, MATCH), + BSHELL_TKOP_OP(NOTMATCH, NOTMATCH), + BSHELL_TKOP_OP(REPLACE, REPLACE), + BSHELL_TKOP_OP(LIKE, LIKE), + BSHELL_TKOP_OP(NOTLIKE, NOTLIKE), + BSHELL_TKOP_OP(IN, IN), + BSHELL_TKOP_OP(NOTIN, NOTIN), + BSHELL_TKOP_OP(CONTAINS, CONTAINS), + BSHELL_TKOP_OP(NOTCONTAINS, NOTCONTAINS), + BSHELL_TKOP_OP(LOGICAL_AND, AND), + BSHELL_TKOP_OP(LOGICAL_OR, OR), + BSHELL_TKOP_OP(LOGICAL_XOR, XOR), + BSHELL_TKOP_OP(LOGICAL_NOT, NOT), + /* there are also unary versions of these operators */ + BSHELL_TKOP_OP(BSPLIT, SPLIT), + BSHELL_TKOP_OP(BJOIN, JOIN), + + BSHELL_TKOP_OP(IS, IS), + BSHELL_TKOP_OP(ISNOT, ISNOT), + BSHELL_TKOP_OP(AS, AS), +}; +static const size_t nr_bshell_operator_token_ops = sizeof bshell_operator_token_ops / sizeof bshell_operator_token_ops[0]; + +/* clang-format on */ + +const struct bshell_operator_info *bshell_operator_get_by_token( + unsigned int token) +{ + const struct bshell_operator_info **op_list = NULL; + size_t base = 0; + size_t op_list_size = 0; + + if (token > __BSHELL_TKOP_INDEX_BASE + && token < __BSHELL_TKOP_INDEX_LIMIT) { + op_list = bshell_operator_token_ops; + base = __BSHELL_TKOP_INDEX_BASE; + op_list_size = nr_bshell_operator_token_ops; + } else if (token > __BSHELL_SYM_INDEX_BASE && token < __BSHELL_SYM_INDEX_LIMIT) { + op_list = bshell_operator_symbols; + base = __BSHELL_SYM_INDEX_BASE; + op_list_size = nr_bshell_operator_symbols; + } else { + return NULL; + } + + if (token - base >= op_list_size) { + return NULL; + } + + return op_list[token - base]; +} + +const struct bshell_operator_info *bshell_operator_get_by_id( + enum bshell_operator_id id) +{ + if (id >= nr_operators) { + return NULL; + } + + const struct bshell_operator_info *op = &operators[id]; + if (op->op_id != id) { + return NULL; + } + + return op; +} + +#define ENUM_STR(x) \ + case x: \ + return #x + +const char *bshell_operator_id_to_string(enum bshell_operator_id op) +{ + switch (op) { + ENUM_STR(BSHELL_OP_NONE); + ENUM_STR(BSHELL_OP_ADD); + ENUM_STR(BSHELL_OP_SUBTRACT); + ENUM_STR(BSHELL_OP_MULTIPLY); + ENUM_STR(BSHELL_OP_DIVIDE); + ENUM_STR(BSHELL_OP_MODULO); + ENUM_STR(BSHELL_OP_INCREMENT); + ENUM_STR(BSHELL_OP_DECREMENT); + ENUM_STR(BSHELL_OP_LEFT_SHIFT); + ENUM_STR(BSHELL_OP_RIGHT_SHIFT); + ENUM_STR(BSHELL_OP_BINARY_AND); + ENUM_STR(BSHELL_OP_BINARY_OR); + ENUM_STR(BSHELL_OP_BINARY_XOR); + ENUM_STR(BSHELL_OP_BINARY_NOT); + ENUM_STR(BSHELL_OP_LESS_THAN); + ENUM_STR(BSHELL_OP_GREATER_THAN); + ENUM_STR(BSHELL_OP_EQUAL); + ENUM_STR(BSHELL_OP_NOT_EQUAL); + ENUM_STR(BSHELL_OP_LESS_EQUAL); + ENUM_STR(BSHELL_OP_GREATER_EQUAL); + ENUM_STR(BSHELL_OP_ASSIGN); + ENUM_STR(BSHELL_OP_ADD_ASSIGN); + ENUM_STR(BSHELL_OP_SUBTRACT_ASSIGN); + ENUM_STR(BSHELL_OP_MULTIPLY_ASSIGN); + ENUM_STR(BSHELL_OP_DIVIDE_ASSIGN); + ENUM_STR(BSHELL_OP_MODULO_ASSIGN); + ENUM_STR(BSHELL_OP_LOGICAL_AND); + ENUM_STR(BSHELL_OP_LOGICAL_OR); + ENUM_STR(BSHELL_OP_LOGICAL_XOR); + ENUM_STR(BSHELL_OP_LOGICAL_NOT); + ENUM_STR(BSHELL_OP_RANGE); + ENUM_STR(BSHELL_OP_MATCH); + ENUM_STR(BSHELL_OP_NOTMATCH); + ENUM_STR(BSHELL_OP_REPLACE); + ENUM_STR(BSHELL_OP_LIKE); + ENUM_STR(BSHELL_OP_NOTLIKE); + ENUM_STR(BSHELL_OP_IN); + ENUM_STR(BSHELL_OP_NOTIN); + ENUM_STR(BSHELL_OP_FORMAT); + ENUM_STR(BSHELL_OP_CONTAINS); + ENUM_STR(BSHELL_OP_NOTCONTAINS); + ENUM_STR(BSHELL_OP_USPLIT); + ENUM_STR(BSHELL_OP_BSPLIT); + ENUM_STR(BSHELL_OP_UJOIN); + ENUM_STR(BSHELL_OP_BJOIN); + ENUM_STR(BSHELL_OP_IS); + ENUM_STR(BSHELL_OP_ISNOT); + ENUM_STR(BSHELL_OP_AS); + ENUM_STR(BSHELL_OP_SUBSCRIPT); + ENUM_STR(BSHELL_OP_CONDITIONAL_SUBSCRIPT); + ENUM_STR(BSHELL_OP_ARRAY_DELIMITER); + ENUM_STR(BSHELL_OP_ACCESS); + ENUM_STR(BSHELL_OP_STATIC_ACCESS); + ENUM_STR(BSHELL_OP_CONDITIONAL_ACCESS); + ENUM_STR(BSHELL_OP_CAST); + ENUM_STR(BSHELL_OP_SUBEXPR); + ENUM_STR(BSHELL_OP_PAREN); + ENUM_STR(BSHELL_OP_ARRAY_START); + ENUM_STR(BSHELL_OP_HASHTABLE_START); + default: + return ""; + } +} diff --git a/bshell.runtime/parse/lex/arithmetic.c b/bshell.runtime/parse/lex/arithmetic.c new file mode 100644 index 0000000..3926b7c --- /dev/null +++ b/bshell.runtime/parse/lex/arithmetic.c @@ -0,0 +1,232 @@ +#include "lex-internal.h" + +static enum bshell_status arithmetic_hyphen(struct bshell_lex_ctx *ctx) +{ + fx_wchar c = peek_char(ctx); + if (!fx_wchar_is_alnum(c)) { + push_symbol(ctx, BSHELL_SYM_HYPHEN); + handle_lex_state_transition(ctx, BSHELL_SYM_HYPHEN); + return BSHELL_SUCCESS; + } + + struct bshell_lex_token *tok = NULL; + enum bshell_status status = read_word( + ctx, + READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN, + &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + unsigned int token_type = BSHELL_TOK_WORD; + if (convert_word_to_number(tok)) { + token_type = tok->tok_type; + + /* because of APPEND_HYPHEN (which is needed to ensure operator + * tokens are detected properly), the resulting number will be + * negative. + * this token will be preceded by a HYPHEN token, so the number + * must be positive */ + fx_value neg = FX_INT(-1); + fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number); + push_symbol(ctx, BSHELL_SYM_HYPHEN); + } else if (convert_word_to_operator(ctx, tok)) { + token_type = tok->tok_operator; + } + + enqueue_token(ctx, tok); + return BSHELL_SUCCESS; +} + +static enum bshell_status arithmetic_symbol(struct bshell_lex_ctx *ctx) +{ + const struct bshell_lex_token_definition *sym = NULL; + enum bshell_status status = read_symbol(ctx, &sym); + + if (status != BSHELL_SUCCESS) { + return status; + } + + handle_lex_state_transition(ctx, sym->id); + + struct bshell_lex_token *tok = NULL; + switch (sym->id) { + case BSHELL_SYM_DQUOTE: + return BSHELL_SUCCESS; + case BSHELL_SYM_SQUOTE: + status = read_literal_string(ctx, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + enqueue_token(ctx, tok); + return BSHELL_SUCCESS; + case BSHELL_SYM_HYPHEN: + return arithmetic_hyphen(ctx); + case BSHELL_SYM_HASH: + return read_line_comment(ctx); + case BSHELL_SYM_DOLLAR: + status = read_var(ctx, BSHELL_TOK_VAR, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + enqueue_token(ctx, tok); + return status; + case BSHELL_SYM_AT: + status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + enqueue_token(ctx, tok); + return status; + case BSHELL_SYM_DOLLAR_LEFT_BRACE: + status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + enqueue_token(ctx, tok); + return status; + default: + break; + } + + push_symbol(ctx, sym->id); + + return BSHELL_SUCCESS; +} + +static enum bshell_status arithmetic_word(struct bshell_lex_ctx *ctx) +{ + struct bshell_lex_token *word = NULL; + enum bshell_status status = read_word(ctx, 0, &word); + if (status != BSHELL_SUCCESS) { + return status; + } + + unsigned int token_type = BSHELL_TOK_WORD; + bool kw = false, number = false; + if (convert_word_to_keyword(word)) { + token_type = word->tok_keyword; + } else if (convert_word_to_number(word)) { + token_type = word->tok_type; + } + + handle_lex_state_transition(ctx, token_type); + + enqueue_token(ctx, word); + return BSHELL_SUCCESS; +} + +static enum bshell_status arithmetic_pump_token(struct bshell_lex_ctx *ctx) +{ + fx_wchar c = peek_char(ctx); + bool newline = false; + + set_token_start(ctx); + while (fx_wchar_is_space(c)) { + if (c == '\n') { + newline = true; + } + + set_token_end(ctx); + advance_char_noread(ctx); + c = peek_char_noread(ctx); + } + + if (newline) { + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_LINEFEED); + enqueue_token(ctx, tok); + handle_lex_state_transition(ctx, BSHELL_TOK_LINEFEED); + return BSHELL_SUCCESS; + } + + if (char_can_begin_symbol(ctx, c)) { + return arithmetic_symbol(ctx); + } + + return arithmetic_word(ctx); +} + +static const struct bshell_lex_state_link links[] = { + LINK_CHANGE(BSHELL_SYM_EQUAL, BSHELL_LEX_STATE_STATEMENT), + LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0), + LINK_PUSH(BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, 0), + LINK_POP(BSHELL_SYM_RIGHT_PAREN), + LINK_CHANGE(BSHELL_SYM_SEMICOLON, BSHELL_LEX_STATE_STATEMENT), + LINK_CHANGE(BSHELL_TOK_LINEFEED, BSHELL_LEX_STATE_STATEMENT), + LINK_CHANGE(BSHELL_SYM_PIPE, BSHELL_LEX_STATE_STATEMENT), + LINK_PUSH(BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_HASHTABLE, 0), + LINK_PUSH( + BSHELL_SYM_LEFT_PAREN, + BSHELL_LEX_STATE_STATEMENT, + STATEMENT_F_DISABLE_KEYWORDS), + LINK_END, +}; + +static const unsigned int keywords[] = { + BSHELL_KW_IF, + BSHELL_KW_ELSEIF, + BSHELL_KW_ELSE, + BSHELL_KW_NONE, +}; + +static const unsigned int operators[] = { + BSHELL_TKOP_F, BSHELL_TKOP_BAND, BSHELL_TKOP_BOR, BSHELL_TKOP_BXOR, + BSHELL_TKOP_BNOT, BSHELL_TKOP_SHL, BSHELL_TKOP_SHR, BSHELL_TKOP_EQ, + BSHELL_TKOP_NE, BSHELL_TKOP_GT, BSHELL_TKOP_LT, BSHELL_TKOP_GE, + BSHELL_TKOP_LE, BSHELL_TKOP_MATCH, BSHELL_TKOP_NOTMATCH, BSHELL_TKOP_REPLACE, + BSHELL_TKOP_LIKE, BSHELL_TKOP_NOTLIKE, BSHELL_TKOP_IN, BSHELL_TKOP_NOTIN, + BSHELL_TKOP_CONTAINS, BSHELL_TKOP_NOTCONTAINS, BSHELL_TKOP_AND, BSHELL_TKOP_OR, + BSHELL_TKOP_XOR, BSHELL_TKOP_NOT, BSHELL_TKOP_SPLIT, BSHELL_TKOP_JOIN, + BSHELL_TKOP_IS, BSHELL_TKOP_ISNOT, BSHELL_TKOP_AS, BSHELL_TKOP_NONE, +}; + +static const unsigned int symbols[] = { + BSHELL_SYM_BANG, + BSHELL_SYM_PLUS, + BSHELL_SYM_HYPHEN, + BSHELL_SYM_FORWARD_SLASH, + BSHELL_SYM_ASTERISK, + BSHELL_SYM_AMPERSAND, + BSHELL_SYM_PERCENT, + BSHELL_SYM_SQUOTE, + BSHELL_SYM_DQUOTE, + BSHELL_SYM_HASH, + BSHELL_SYM_DOLLAR, + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_SYM_DOLLAR_LEFT_BRACE, + BSHELL_SYM_AT, + BSHELL_SYM_AT_LEFT_BRACE, + BSHELL_SYM_PIPE, + BSHELL_SYM_COMMA, + BSHELL_SYM_SEMICOLON, + BSHELL_SYM_LEFT_PAREN, + BSHELL_SYM_RIGHT_PAREN, + BSHELL_SYM_LEFT_BRACE, + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_LEFT_BRACKET, + BSHELL_SYM_RIGHT_BRACKET, + BSHELL_SYM_QUESTION_DOT, + BSHELL_SYM_QUESTION_LEFT_BRACKET, + BSHELL_SYM_EQUAL, + BSHELL_SYM_PLUS_EQUAL, + BSHELL_SYM_HYPHEN_EQUAL, + BSHELL_SYM_FORWARD_SLASH_EQUAL, + BSHELL_SYM_ASTERISK_EQUAL, + BSHELL_SYM_PERCENT_EQUAL, + BSHELL_SYM_DOT, + BSHELL_SYM_DOT_DOT, + BSHELL_SYM_COLON_COLON, + BSHELL_SYM_NONE, +}; + +const struct bshell_lex_state_type lex_arithmetic_state = { + .s_id = BSHELL_LEX_STATE_ARITHMETIC, + .s_pump_token = arithmetic_pump_token, + .s_links = links, + .s_keywords = keywords, + .s_operators = operators, + .s_symbols = symbols, +}; diff --git a/bshell/parse/lex/command.c b/bshell.runtime/parse/lex/command.c similarity index 54% rename from bshell/parse/lex/command.c rename to bshell.runtime/parse/lex/command.c index 402e3a8..400c4d8 100644 --- a/bshell/parse/lex/command.c +++ b/bshell.runtime/parse/lex/command.c @@ -1,7 +1,8 @@ -#include "../token.h" #include "lex-internal.h" -static bool char_can_continue_word(struct lex_ctx *ctx, fx_wchar c) +#include + +static bool char_can_continue_word(struct bshell_lex_ctx *ctx, fx_wchar c) { if (fx_wchar_is_alnum(c)) { return true; @@ -15,16 +16,16 @@ static bool char_can_continue_word(struct lex_ctx *ctx, fx_wchar c) return true; } - if (char_can_begin_symbol_in_state(ctx, c, LEX_STATE_WORD)) { + if (char_can_begin_symbol_in_state(ctx, c, BSHELL_LEX_STATE_WORD)) { return false; } return true; } -static enum bshell_status command_symbol(struct lex_ctx *ctx) +static enum bshell_status command_symbol(struct bshell_lex_ctx *ctx) { - const struct lex_token_def *sym = NULL; + const struct bshell_lex_token_definition *sym = NULL; enum bshell_status status = read_symbol(ctx, &sym); if (status != BSHELL_SUCCESS) { @@ -33,11 +34,11 @@ static enum bshell_status command_symbol(struct lex_ctx *ctx) handle_lex_state_transition(ctx, sym->id); - struct lex_token *tok = NULL; + struct bshell_lex_token *tok = NULL; switch (sym->id) { - case SYM_DQUOTE: + case BSHELL_SYM_DQUOTE: return BSHELL_SUCCESS; - case SYM_SQUOTE: + case BSHELL_SYM_SQUOTE: status = read_literal_string(ctx, &tok); if (status != BSHELL_SUCCESS) { return status; @@ -45,36 +46,36 @@ static enum bshell_status command_symbol(struct lex_ctx *ctx) enqueue_token(ctx, tok); return BSHELL_SUCCESS; - case SYM_HASH: + case BSHELL_SYM_HASH: return read_line_comment(ctx); - case SYM_DOLLAR: - status = read_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR: + status = read_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } if (char_can_continue_word(ctx, peek_char(ctx))) { - lex_state_push(ctx, LEX_STATE_WORD, 0); + lex_state_push(ctx, BSHELL_LEX_STATE_WORD, 0); } enqueue_token(ctx, tok); return status; - case SYM_AT: - status = read_var(ctx, TOK_VAR_SPLAT, &tok); + case BSHELL_SYM_AT: + status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; - case SYM_DOLLAR_LEFT_BRACE: - status = read_braced_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR_LEFT_BRACE: + status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } if (char_can_continue_word(ctx, peek_char(ctx))) { - lex_state_push(ctx, LEX_STATE_WORD, 0); + lex_state_push(ctx, BSHELL_LEX_STATE_WORD, 0); } enqueue_token(ctx, tok); @@ -121,9 +122,9 @@ static bool string_is_redirection(const char *s) return true; } -static enum bshell_status command_word(struct lex_ctx *ctx) +static enum bshell_status command_word(struct bshell_lex_ctx *ctx) { - struct lex_token *word = NULL; + struct bshell_lex_token *word = NULL; enum bshell_status status = read_word(ctx, READ_NO_NUMBER_RECOGNITION, &word); if (status != BSHELL_SUCCESS) { @@ -134,11 +135,11 @@ static enum bshell_status command_word(struct lex_ctx *ctx) fx_wchar c = peek_char(ctx); const char *s = word->tok_str; - if (char_can_begin_symbol_in_state(ctx, c, LEX_STATE_WORD)) { + if (char_can_begin_symbol_in_state(ctx, c, BSHELL_LEX_STATE_WORD)) { continue_word = true; } - if (char_has_flags(ctx, c, LEX_TOKEN_TERMINATES_WORD)) { + if (char_has_flags(ctx, c, BSHELL_LEX_TOKEN_TERMINATES_WORD)) { continue_word = false; } @@ -147,14 +148,14 @@ static enum bshell_status command_word(struct lex_ctx *ctx) } if (continue_word) { - lex_state_push(ctx, LEX_STATE_WORD, 0); + lex_state_push(ctx, BSHELL_LEX_STATE_WORD, 0); } enqueue_token(ctx, word); return BSHELL_SUCCESS; } -enum bshell_status command_pump_token(struct lex_ctx *ctx) +enum bshell_status command_pump_token(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); bool newline = false; @@ -171,9 +172,10 @@ enum bshell_status command_pump_token(struct lex_ctx *ctx) } if (newline) { - struct lex_token *tok = lex_token_create(TOK_LINEFEED); + struct bshell_lex_token *tok + = bshell_lex_token_create(BSHELL_TOK_LINEFEED); enqueue_token(ctx, tok); - handle_lex_state_transition(ctx, TOK_LINEFEED); + handle_lex_state_transition(ctx, BSHELL_TOK_LINEFEED); return BSHELL_SUCCESS; } @@ -184,42 +186,42 @@ enum bshell_status command_pump_token(struct lex_ctx *ctx) return command_word(ctx); } -const struct lex_state_link links[] = { - LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0), +const struct bshell_lex_state_link links[] = { + LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0), LINK_PUSH( - SYM_LEFT_PAREN, - LEX_STATE_STATEMENT, + BSHELL_SYM_LEFT_PAREN, + BSHELL_LEX_STATE_STATEMENT, STATEMENT_F_DISABLE_KEYWORDS), - LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0), - LINK_POP(SYM_RIGHT_PAREN), - LINK_POP(SYM_RIGHT_BRACE), - LINK_CHANGE(SYM_SEMICOLON, LEX_STATE_STATEMENT), - LINK_PUSH(SYM_AT_LEFT_BRACE, LEX_STATE_HASHTABLE, 0), - LINK_CHANGE(TOK_LINEFEED, LEX_STATE_STATEMENT), + LINK_PUSH(BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, 0), + LINK_POP(BSHELL_SYM_RIGHT_PAREN), + LINK_POP(BSHELL_SYM_RIGHT_BRACE), + LINK_CHANGE(BSHELL_SYM_SEMICOLON, BSHELL_LEX_STATE_STATEMENT), + LINK_PUSH(BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_HASHTABLE, 0), + LINK_CHANGE(BSHELL_TOK_LINEFEED, BSHELL_LEX_STATE_STATEMENT), LINK_END, }; static const unsigned int symbols[] = { - SYM_DQUOTE, - SYM_SQUOTE, - SYM_DOLLAR, - SYM_DOLLAR_LEFT_PAREN, - SYM_DOLLAR_LEFT_BRACE, - SYM_AT, - SYM_AT_LEFT_BRACE, - SYM_AT_LEFT_PAREN, - SYM_AMPERSAND, - SYM_PIPE, - SYM_SEMICOLON, - SYM_RIGHT_PAREN, - SYM_LEFT_PAREN, - SYM_LEFT_BRACE, - SYM_RIGHT_BRACE, - SYM_NONE, + BSHELL_SYM_DQUOTE, + BSHELL_SYM_SQUOTE, + BSHELL_SYM_DOLLAR, + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_SYM_DOLLAR_LEFT_BRACE, + BSHELL_SYM_AT, + BSHELL_SYM_AT_LEFT_BRACE, + BSHELL_SYM_AT_LEFT_PAREN, + BSHELL_SYM_AMPERSAND, + BSHELL_SYM_PIPE, + BSHELL_SYM_SEMICOLON, + BSHELL_SYM_RIGHT_PAREN, + BSHELL_SYM_LEFT_PAREN, + BSHELL_SYM_LEFT_BRACE, + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_NONE, }; -const struct lex_state_type lex_command_state = { - .s_id = LEX_STATE_COMMAND, +const struct bshell_lex_state_type lex_command_state = { + .s_id = BSHELL_LEX_STATE_COMMAND, .s_pump_token = command_pump_token, .s_links = links, .s_symbols = symbols, diff --git a/bshell/parse/lex/hashtable.c b/bshell.runtime/parse/lex/hashtable.c similarity index 58% rename from bshell/parse/lex/hashtable.c rename to bshell.runtime/parse/lex/hashtable.c index 5cbd78d..4324eab 100644 --- a/bshell/parse/lex/hashtable.c +++ b/bshell.runtime/parse/lex/hashtable.c @@ -1,15 +1,15 @@ #include "lex-internal.h" -static enum bshell_status hashtable_hyphen(struct lex_ctx *ctx) +static enum bshell_status hashtable_hyphen(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); if (!fx_wchar_is_alnum(c)) { - push_symbol(ctx, SYM_HYPHEN); - handle_lex_state_transition(ctx, SYM_HYPHEN); + push_symbol(ctx, BSHELL_SYM_HYPHEN); + handle_lex_state_transition(ctx, BSHELL_SYM_HYPHEN); return BSHELL_SUCCESS; } - struct lex_token *tok = NULL; + struct bshell_lex_token *tok = NULL; enum bshell_status status = read_word( ctx, READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN, @@ -18,7 +18,7 @@ static enum bshell_status hashtable_hyphen(struct lex_ctx *ctx) return status; } - unsigned int token_type = TOK_WORD; + unsigned int token_type = BSHELL_TOK_WORD; if (convert_word_to_number(tok)) { token_type = tok->tok_type; /* because of APPEND_HYPHEN (which is needed to ensure operator @@ -28,7 +28,7 @@ static enum bshell_status hashtable_hyphen(struct lex_ctx *ctx) * must be positive */ fx_value neg = FX_INT(-1); fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number); - push_symbol(ctx, SYM_HYPHEN); + push_symbol(ctx, BSHELL_SYM_HYPHEN); } else if (convert_word_to_operator(ctx, tok)) { token_type = tok->tok_operator; } @@ -38,9 +38,9 @@ static enum bshell_status hashtable_hyphen(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status hashtable_symbol(struct lex_ctx *ctx) +static enum bshell_status hashtable_symbol(struct bshell_lex_ctx *ctx) { - const struct lex_token_def *sym = NULL; + const struct bshell_lex_token_definition *sym = NULL; enum bshell_status status = read_symbol(ctx, &sym); if (status != BSHELL_SUCCESS) { @@ -49,37 +49,37 @@ static enum bshell_status hashtable_symbol(struct lex_ctx *ctx) handle_lex_state_transition(ctx, sym->id); - struct lex_token *tok = NULL; + struct bshell_lex_token *tok = NULL; switch (sym->id) { - case SYM_SQUOTE: + case BSHELL_SYM_SQUOTE: status = read_literal_string(ctx, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return BSHELL_SUCCESS; - case SYM_HYPHEN: + case BSHELL_SYM_HYPHEN: return hashtable_hyphen(ctx); - case SYM_HASH: + case BSHELL_SYM_HASH: return read_line_comment(ctx); - case SYM_DOLLAR: - status = read_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR: + status = read_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; - case SYM_AT: - status = read_var(ctx, TOK_VAR_SPLAT, &tok); + case BSHELL_SYM_AT: + status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; - case SYM_DOLLAR_LEFT_BRACE: - status = read_braced_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR_LEFT_BRACE: + status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } @@ -95,9 +95,9 @@ static enum bshell_status hashtable_symbol(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status hashtable_word(struct lex_ctx *ctx) +static enum bshell_status hashtable_word(struct bshell_lex_ctx *ctx) { - struct lex_token *word = NULL; + struct bshell_lex_token *word = NULL; enum bshell_status status = read_word(ctx, 0, &word); if (status != BSHELL_SUCCESS) { return status; @@ -110,7 +110,7 @@ static enum bshell_status hashtable_word(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status hashtable_pump_token(struct lex_ctx *ctx) +static enum bshell_status hashtable_pump_token(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); bool newline = false; @@ -128,7 +128,7 @@ static enum bshell_status hashtable_pump_token(struct lex_ctx *ctx) #if 1 if (newline) { - struct lex_token *tok = lex_token_create(TOK_LINEFEED); + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_LINEFEED); enqueue_token(ctx, tok); return BSHELL_SUCCESS; } @@ -141,44 +141,44 @@ static enum bshell_status hashtable_pump_token(struct lex_ctx *ctx) return hashtable_word(ctx); } -static const struct lex_state_link links[] = { +static const struct bshell_lex_state_link links[] = { LINK_PUSH_WITH_TERM( - SYM_EQUAL, - LEX_STATE_STATEMENT, + BSHELL_SYM_EQUAL, + BSHELL_LEX_STATE_STATEMENT, 0, - SYM_RIGHT_BRACE, - SYM_SEMICOLON, - TOK_LINEFEED), + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_SEMICOLON, + BSHELL_TOK_LINEFEED), LINK_PUSH_WITH_TERM( - TOK_LINEFEED, - LEX_STATE_STATEMENT, + BSHELL_TOK_LINEFEED, + BSHELL_LEX_STATE_STATEMENT, 0, - SYM_SEMICOLON, - TOK_LINEFEED), - LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0), + BSHELL_SYM_SEMICOLON, + BSHELL_TOK_LINEFEED), + LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0), LINK_PUSH( - SYM_LEFT_PAREN, - LEX_STATE_STATEMENT, + BSHELL_SYM_LEFT_PAREN, + BSHELL_LEX_STATE_STATEMENT, STATEMENT_F_DISABLE_KEYWORDS), - LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0), - LINK_POP2(SYM_RIGHT_BRACE, LINK_ALLOW_RECURSION), + LINK_PUSH(BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, 0), + LINK_POP2(BSHELL_SYM_RIGHT_BRACE, LINK_ALLOW_RECURSION), LINK_END, }; static const unsigned int symbols[] = { - SYM_EQUAL, - SYM_DQUOTE, - SYM_SQUOTE, - SYM_SEMICOLON, - SYM_RIGHT_BRACE, - SYM_DOLLAR_LEFT_PAREN, - SYM_LEFT_PAREN, - SYM_HASH, - SYM_NONE, + BSHELL_SYM_EQUAL, + BSHELL_SYM_DQUOTE, + BSHELL_SYM_SQUOTE, + BSHELL_SYM_SEMICOLON, + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_SYM_LEFT_PAREN, + BSHELL_SYM_HASH, + BSHELL_SYM_NONE, }; -const struct lex_state_type lex_hashtable_state = { - .s_id = LEX_STATE_HASHTABLE, +const struct bshell_lex_state_type lex_hashtable_state = { + .s_id = BSHELL_LEX_STATE_HASHTABLE, .s_pump_token = hashtable_pump_token, .s_links = links, .s_symbols = symbols, diff --git a/bshell.runtime/parse/lex/lex-internal.h b/bshell.runtime/parse/lex/lex-internal.h new file mode 100644 index 0000000..9e48a77 --- /dev/null +++ b/bshell.runtime/parse/lex/lex-internal.h @@ -0,0 +1,204 @@ +#ifndef PARSE_LEX_INTERNAL_H_ +#define PARSE_LEX_INTERNAL_H_ + +#include +#include +#include + +struct bshell_lex_ctx; + +enum state_flags { + /* statement: don't convert matching words to keywords */ + STATEMENT_F_DISABLE_KEYWORDS = 0x01u, + /* arithmetic: don't switch back to statement mode even when + * encountering a token that would otherwise require it. */ + ARITHMETIC_F_DISABLE_STATEMENTS = 0x01u, +}; + +enum read_flags { + READ_APPEND_HYPHEN = 0x01u, + READ_NO_SET_TOKEN_START = 0x02u, + READ_NO_NUMBER_RECOGNITION = 0x04u, +}; + +enum link_flags { + LINK_ALLOW_RECURSION = 0x01u, +}; + +#define LINK_PUSH(tok, target, flags) \ + ((struct bshell_lex_state_link) { \ + .l_token = (tok), \ + .l_type = BSHELL_LEX_STATE_LINK_PUSH, \ + .l_target = (target), \ + .l_target_flags = (flags), \ + }) +#define LINK_PUSH_WITH_TERM(tok, target, flags, ...) \ + ((struct bshell_lex_state_link) { \ + .l_token = (tok), \ + .l_type = BSHELL_LEX_STATE_LINK_PUSH, \ + .l_target = (target), \ + .l_target_flags = (flags), \ + .l_terminators = {__VA_ARGS__, BSHELL_TOK_NONE}, \ + }) +#define LINK_CHANGE(tok, target) \ + ((struct bshell_lex_state_link) { \ + .l_token = (tok), \ + .l_type = BSHELL_LEX_STATE_LINK_CHANGE, \ + .l_target = (target), \ + }) +#define LINK_POP(tok) \ + ((struct bshell_lex_state_link) { \ + .l_token = (tok), \ + .l_type = BSHELL_LEX_STATE_LINK_POP, \ + }) +#define LINK_POP2(tok, flags) \ + ((struct bshell_lex_state_link) { \ + .l_token = (tok), \ + .l_type = BSHELL_LEX_STATE_LINK_POP, \ + .l_flags = (flags), \ + }) +#define LINK_NONE(tok) \ + ((struct bshell_lex_state_link) { \ + .l_token = (tok), \ + .l_type = BSHELL_LEX_STATE_LINK_NONE, \ + }) +#define LINK_END ((struct bshell_lex_state_link) {}) + +struct bshell_lex_state_link { + unsigned int l_token; + enum { + BSHELL_LEX_STATE_LINK_NONE, + BSHELL_LEX_STATE_LINK_PUSH, + BSHELL_LEX_STATE_LINK_CHANGE, + BSHELL_LEX_STATE_LINK_POP, + } l_type; + enum link_flags l_flags; + enum bshell_lex_state_id l_target; + enum state_flags l_target_flags; + unsigned int l_terminators[BSHELL_LEX_STATE_MAX_TERMINATORS]; +}; + +typedef enum bshell_status (*lex_state_pump_token)(struct bshell_lex_ctx *); +typedef enum bshell_status (*lex_state_begin)(struct bshell_lex_ctx *); +typedef enum bshell_status (*lex_state_end)(struct bshell_lex_ctx *); + +struct bshell_lex_state_type { + enum bshell_lex_state_id s_id; + lex_state_pump_token s_pump_token; + lex_state_begin s_begin; + lex_state_end s_end; + + const unsigned int *s_keywords; + const unsigned int *s_operators; + const unsigned int *s_symbols; + const struct bshell_lex_state_link *s_links; +}; + +extern enum bshell_status pump_token_statement(struct bshell_lex_ctx *ctx); +extern enum bshell_status pump_token_expression(struct bshell_lex_ctx *ctx); +extern enum bshell_status pump_token_command(struct bshell_lex_ctx *ctx); +extern enum bshell_status pump_token_arithmetic(struct bshell_lex_ctx *ctx); +extern enum bshell_status pump_token_string(struct bshell_lex_ctx *ctx); + +extern void set_token_start(struct bshell_lex_ctx *ctx); +extern void set_token_end(struct bshell_lex_ctx *ctx); + +extern struct bshell_lex_state *lex_state_push( + struct bshell_lex_ctx *ctx, + enum bshell_lex_state_id state_type, + enum state_flags flags); +extern void lex_state_pop(struct bshell_lex_ctx *ctx); +extern struct bshell_lex_state *lex_state_get(struct bshell_lex_ctx *ctx); +extern void lex_state_change( + struct bshell_lex_ctx *ctx, + enum bshell_lex_state_id type); +extern fx_string *lex_state_get_tempstr(struct bshell_lex_ctx *ctx); +extern void lex_state_add_terminator( + struct bshell_lex_state *state, + unsigned int tok); +extern bool lex_state_terminates_at_token( + struct bshell_lex_ctx *ctx, + unsigned int tok); + +extern fx_wchar peek_char(struct bshell_lex_ctx *ctx); +extern fx_wchar peek_char_noread(struct bshell_lex_ctx *ctx); +extern fx_wchar peek2_char(struct bshell_lex_ctx *ctx); +extern fx_wchar peek2_char_noread(struct bshell_lex_ctx *ctx); +extern void advance_char(struct bshell_lex_ctx *ctx); +extern void advance_char_noread(struct bshell_lex_ctx *ctx); + +extern bool string_is_valid_number( + const char *s, + fx_value *out, + enum bshell_lex_token_type *out_type); +extern bool convert_word_to_number(struct bshell_lex_token *tok); +extern bool convert_word_to_keyword(struct bshell_lex_token *tok); +extern bool convert_word_to_operator( + struct bshell_lex_ctx *ctx, + struct bshell_lex_token *tok); + +extern void enqueue_token( + struct bshell_lex_ctx *ctx, + struct bshell_lex_token *tok); +extern void enqueue_token_with_coordinates( + struct bshell_lex_ctx *ctx, + struct bshell_lex_token *tok, + const struct bshell_char_cell *start, + const struct bshell_char_cell *end); + +extern enum bshell_status read_word( + struct bshell_lex_ctx *ctx, + enum read_flags flags, + struct bshell_lex_token **out); +extern enum bshell_status read_symbol( + struct bshell_lex_ctx *ctx, + const struct bshell_lex_token_definition **out); +extern enum bshell_status read_literal_string( + struct bshell_lex_ctx *ctx, + struct bshell_lex_token **out); +extern enum bshell_status read_line_comment(struct bshell_lex_ctx *lex); +extern enum bshell_status read_var( + struct bshell_lex_ctx *ctx, + enum bshell_lex_token_type type, + struct bshell_lex_token **out); +extern enum bshell_status read_braced_var( + struct bshell_lex_ctx *ctx, + enum bshell_lex_token_type type, + struct bshell_lex_token **out); + +extern enum bshell_status push_symbol( + struct bshell_lex_ctx *ctx, + enum bshell_lex_symbol sym); + +extern bool char_can_begin_symbol(struct bshell_lex_ctx *ctx, char c); +extern bool char_can_begin_symbol_in_state( + struct bshell_lex_ctx *ctx, + char c, + enum bshell_lex_state_id state_type); +extern bool char_has_flags( + struct bshell_lex_ctx *ctx, + char c, + enum bshell_lex_token_flags flags); +extern bool keyword_has_flags( + struct bshell_lex_ctx *ctx, + enum bshell_lex_keyword kw, + enum bshell_lex_token_flags flags); +extern enum bshell_lex_token_flags keyword_get_flags( + struct bshell_lex_ctx *ctx, + enum bshell_lex_keyword kw); +extern bool symbol_has_flags( + struct bshell_lex_ctx *ctx, + enum bshell_lex_symbol sym, + enum bshell_lex_token_flags flags); +extern enum bshell_lex_token_flags symbol_get_flags( + struct bshell_lex_ctx *ctx, + enum bshell_lex_symbol sym); +extern enum bshell_lex_operator get_bshell_operator_with_string( + struct bshell_lex_ctx *ctx, + const char *s); + +extern void handle_lex_state_transition( + struct bshell_lex_ctx *ctx, + unsigned int token); + +#endif diff --git a/bshell/parse/lex/lex.c b/bshell.runtime/parse/lex/lex.c similarity index 57% rename from bshell/parse/lex/lex.c rename to bshell.runtime/parse/lex/lex.c index 0d50706..f6522c9 100644 --- a/bshell/parse/lex/lex.c +++ b/bshell.runtime/parse/lex/lex.c @@ -1,162 +1,181 @@ -#include "../lex.h" - -#include "../../debug.h" -#include "../../line-source.h" -#include "../token.h" #include "lex-internal.h" #include +#include +#include +#include #define SYMBOL_DEF(i, n, f) \ - [i - __SYM_INDEX_BASE] = { \ + [i - __BSHELL_SYM_INDEX_BASE] = { \ .id = (i), \ .name = (n), \ .flags = (f), \ } -#define KW_DEF(i, n, f) \ - [i - __KW_INDEX_BASE] = { \ +#define BSHELL_KW_DEF(i, n, f) \ + [i - __BSHELL_KW_INDEX_BASE] = { \ .id = (i), \ .name = (n), \ .flags = (f), \ } -#define TKOP_DEF(i, n, f) \ - [i - __TKOP_INDEX_BASE] = { \ +#define BSHELL_TKOP_DEF(i, n, f) \ + [i - __BSHELL_TKOP_INDEX_BASE] = { \ .id = (i), \ .name = (n), \ .flags = (f), \ } -static struct lex_token_def keywords[] = { - KW_DEF(KW_FUNC, "func", LEX_TOKEN_COMMAND_MODE), - KW_DEF(KW_IF, "if", 0), - KW_DEF(KW_ELSEIF, "elseif", 0), - KW_DEF(KW_ELSE, "else", 0), +static struct bshell_lex_token_definition keywords[] = { + BSHELL_KW_DEF(BSHELL_KW_FUNC, "func", BSHELL_LEX_TOKEN_COMMAND_MODE), + BSHELL_KW_DEF(BSHELL_KW_IF, "if", 0), + BSHELL_KW_DEF(BSHELL_KW_ELSEIF, "elseif", 0), + BSHELL_KW_DEF(BSHELL_KW_ELSE, "else", 0), }; static const size_t nr_keywords = sizeof keywords / sizeof keywords[0]; -static struct lex_token_def operators[] = { - TKOP_DEF(TKOP_BAND, "-band", 0), - TKOP_DEF(TKOP_BOR, "-bor", 0), - TKOP_DEF(TKOP_BXOR, "-bxor", 0), - TKOP_DEF(TKOP_BNOT, "-bnot", 0), - TKOP_DEF(TKOP_SHL, "-shl", 0), - TKOP_DEF(TKOP_SHR, "-shr", 0), - TKOP_DEF(TKOP_EQ, "-eq", 0), - TKOP_DEF(TKOP_NE, "-ne", 0), - TKOP_DEF(TKOP_GT, "-gt", 0), - TKOP_DEF(TKOP_LT, "-lt", 0), - TKOP_DEF(TKOP_GE, "-ge", 0), - TKOP_DEF(TKOP_LE, "-le", 0), - TKOP_DEF(TKOP_MATCH, "-match", 0), - TKOP_DEF(TKOP_NOTMATCH, "-notmatch", 0), - TKOP_DEF(TKOP_REPLACE, "-replace", 0), - TKOP_DEF(TKOP_LIKE, "-like", 0), - TKOP_DEF(TKOP_NOTLIKE, "-notlike", 0), - TKOP_DEF(TKOP_CONTAINS, "-contains", 0), - TKOP_DEF(TKOP_NOTCONTAINS, "-notcontains", 0), - TKOP_DEF(TKOP_AND, "-and", 0), - TKOP_DEF(TKOP_OR, "-or", 0), - TKOP_DEF(TKOP_XOR, "-xor", 0), - TKOP_DEF(TKOP_NOT, "-not", 0), - TKOP_DEF(TKOP_SPLIT, "-split", 0), - TKOP_DEF(TKOP_JOIN, "-join", 0), - TKOP_DEF(TKOP_IS, "-is", 0), - TKOP_DEF(TKOP_ISNOT, "-isnot", 0), - TKOP_DEF(TKOP_AS, "-as", 0), - TKOP_DEF(TKOP_F, "-f", 0), +static struct bshell_lex_token_definition operators[] = { + BSHELL_TKOP_DEF(BSHELL_TKOP_BAND, "-band", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_BOR, "-bor", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_BXOR, "-bxor", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_BNOT, "-bnot", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_SHL, "-shl", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_SHR, "-shr", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_EQ, "-eq", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_NE, "-ne", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_GT, "-gt", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_LT, "-lt", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_GE, "-ge", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_LE, "-le", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_MATCH, "-match", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_NOTMATCH, "-notmatch", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_REPLACE, "-replace", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_LIKE, "-like", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_NOTLIKE, "-notlike", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_CONTAINS, "-contains", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_NOTCONTAINS, "-notcontains", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_AND, "-and", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_OR, "-or", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_XOR, "-xor", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_NOT, "-not", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_SPLIT, "-split", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_JOIN, "-join", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_IS, "-is", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_ISNOT, "-isnot", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_AS, "-as", 0), + BSHELL_TKOP_DEF(BSHELL_TKOP_F, "-f", 0), }; static const size_t nr_operators = sizeof operators / sizeof operators[0]; -static struct lex_token_def symbols[] = { - SYMBOL_DEF(SYM_BANG, "!", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_PLUS, "+", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_HYPHEN, "-", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_FORWARD_SLASH, "/", 0), - SYMBOL_DEF(SYM_ASTERISK, "*", 0), - SYMBOL_DEF(SYM_AMPERSAND, "&", 0), - SYMBOL_DEF(SYM_PERCENT, "%", 0), - SYMBOL_DEF(SYM_SQUOTE, "'", 0), - SYMBOL_DEF(SYM_DQUOTE, "\"", 0), - SYMBOL_DEF(SYM_HASH, "#", 0), - SYMBOL_DEF(SYM_DOLLAR, "$", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_DOLLAR_LEFT_PAREN, "$(", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_DOLLAR_LEFT_BRACE, "${", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_AT, "@", 0), - SYMBOL_DEF(SYM_PIPE, "|", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_COMMA, ",", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_SEMICOLON, ";", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_AT_LEFT_BRACE, "@{", LEX_TOKEN_UNARY_ARITHMETIC), - SYMBOL_DEF(SYM_AT_LEFT_PAREN, "@(", 0), - SYMBOL_DEF(SYM_LEFT_BRACE, "{", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_RIGHT_BRACE, "}", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_LEFT_BRACKET, "[", 0), - SYMBOL_DEF(SYM_RIGHT_BRACKET, "]", 0), - SYMBOL_DEF(SYM_QUESTION_LEFT_BRACKET, "?[", 0), - SYMBOL_DEF(SYM_LEFT_PAREN, "(", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_RIGHT_PAREN, ")", LEX_TOKEN_TERMINATES_WORD), - SYMBOL_DEF(SYM_EQUAL, "=", 0), - SYMBOL_DEF(SYM_PLUS_EQUAL, "+=", 0), - SYMBOL_DEF(SYM_HYPHEN_EQUAL, "-=", 0), - SYMBOL_DEF(SYM_FORWARD_SLASH_EQUAL, "/=", 0), - SYMBOL_DEF(SYM_ASTERISK_EQUAL, "*=", 0), - SYMBOL_DEF(SYM_PERCENT_EQUAL, "%=", 0), - SYMBOL_DEF(SYM_DOT, ".", 0), - SYMBOL_DEF(SYM_COLON_COLON, "::", 0), - SYMBOL_DEF(SYM_DOT_DOT, "..", 0), - SYMBOL_DEF(SYM_QUESTION_DOT, "?.", 0), +static struct bshell_lex_token_definition symbols[] = { + SYMBOL_DEF(BSHELL_SYM_BANG, "!", BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF(BSHELL_SYM_PLUS, "+", BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF(BSHELL_SYM_HYPHEN, "-", BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF(BSHELL_SYM_FORWARD_SLASH, "/", 0), + SYMBOL_DEF(BSHELL_SYM_ASTERISK, "*", 0), + SYMBOL_DEF(BSHELL_SYM_AMPERSAND, "&", 0), + SYMBOL_DEF(BSHELL_SYM_PERCENT, "%", 0), + SYMBOL_DEF(BSHELL_SYM_SQUOTE, "'", 0), + SYMBOL_DEF(BSHELL_SYM_DQUOTE, "\"", 0), + SYMBOL_DEF(BSHELL_SYM_HASH, "#", 0), + SYMBOL_DEF(BSHELL_SYM_DOLLAR, "$", BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF( + BSHELL_SYM_DOLLAR_LEFT_PAREN, + "$(", + BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF( + BSHELL_SYM_DOLLAR_LEFT_BRACE, + "${", + BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF(BSHELL_SYM_AT, "@", 0), + SYMBOL_DEF(BSHELL_SYM_PIPE, "|", BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF(BSHELL_SYM_COMMA, ",", BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF(BSHELL_SYM_SEMICOLON, ";", BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF( + BSHELL_SYM_AT_LEFT_BRACE, + "@{", + BSHELL_LEX_TOKEN_UNARY_ARITHMETIC), + SYMBOL_DEF(BSHELL_SYM_AT_LEFT_PAREN, "@(", 0), + SYMBOL_DEF( + BSHELL_SYM_LEFT_BRACE, + "{", + BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF( + BSHELL_SYM_RIGHT_BRACE, + "}", + BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF(BSHELL_SYM_LEFT_BRACKET, "[", 0), + SYMBOL_DEF(BSHELL_SYM_RIGHT_BRACKET, "]", 0), + SYMBOL_DEF(BSHELL_SYM_QUESTION_LEFT_BRACKET, "?[", 0), + SYMBOL_DEF( + BSHELL_SYM_LEFT_PAREN, + "(", + BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF( + BSHELL_SYM_RIGHT_PAREN, + ")", + BSHELL_LEX_TOKEN_TERMINATES_WORD), + SYMBOL_DEF(BSHELL_SYM_EQUAL, "=", 0), + SYMBOL_DEF(BSHELL_SYM_PLUS_EQUAL, "+=", 0), + SYMBOL_DEF(BSHELL_SYM_HYPHEN_EQUAL, "-=", 0), + SYMBOL_DEF(BSHELL_SYM_FORWARD_SLASH_EQUAL, "/=", 0), + SYMBOL_DEF(BSHELL_SYM_ASTERISK_EQUAL, "*=", 0), + SYMBOL_DEF(BSHELL_SYM_PERCENT_EQUAL, "%=", 0), + SYMBOL_DEF(BSHELL_SYM_DOT, ".", 0), + SYMBOL_DEF(BSHELL_SYM_COLON_COLON, "::", 0), + SYMBOL_DEF(BSHELL_SYM_DOT_DOT, "..", 0), + SYMBOL_DEF(BSHELL_SYM_QUESTION_DOT, "?.", 0), }; static const size_t nr_symbols = sizeof symbols / sizeof symbols[0]; -extern const struct lex_state_type lex_statement_state; -extern const struct lex_state_type lex_command_state; -extern const struct lex_state_type lex_arithmetic_state; -extern const struct lex_state_type lex_string_state; -extern const struct lex_state_type lex_word_state; -extern const struct lex_state_type lex_hashtable_state; +extern const struct bshell_lex_state_type lex_statement_state; +extern const struct bshell_lex_state_type lex_command_state; +extern const struct bshell_lex_state_type lex_arithmetic_state; +extern const struct bshell_lex_state_type lex_string_state; +extern const struct bshell_lex_state_type lex_word_state; +extern const struct bshell_lex_state_type lex_hashtable_state; -static const struct lex_state_type *state_types[] = { - [LEX_STATE_STATEMENT] = &lex_statement_state, - [LEX_STATE_COMMAND] = &lex_command_state, - [LEX_STATE_ARITHMETIC] = &lex_arithmetic_state, - [LEX_STATE_STRING] = &lex_string_state, - [LEX_STATE_WORD] = &lex_word_state, - [LEX_STATE_HASHTABLE] = &lex_hashtable_state, +static const struct bshell_lex_state_type *state_types[] = { + [BSHELL_LEX_STATE_STATEMENT] = &lex_statement_state, + [BSHELL_LEX_STATE_COMMAND] = &lex_command_state, + [BSHELL_LEX_STATE_ARITHMETIC] = &lex_arithmetic_state, + [BSHELL_LEX_STATE_STRING] = &lex_string_state, + [BSHELL_LEX_STATE_WORD] = &lex_word_state, + [BSHELL_LEX_STATE_HASHTABLE] = &lex_hashtable_state, }; -void set_token_start(struct lex_ctx *ctx) +void set_token_start(struct bshell_lex_ctx *ctx) { memcpy(&ctx->lex_start, &ctx->lex_cursor, sizeof ctx->lex_cursor); } -void set_token_end(struct lex_ctx *ctx) +void set_token_end(struct bshell_lex_ctx *ctx) { memcpy(&ctx->lex_end, &ctx->lex_cursor, sizeof ctx->lex_cursor); } -static const char *lex_state_type_id_to_string(enum lex_state_type_id id) +static const char *lex_state_type_id_to_string(enum bshell_lex_state_id id) { #define ENUM_STR(v) \ case v: \ return #v switch (id) { - ENUM_STR(LEX_STATE_STATEMENT); - ENUM_STR(LEX_STATE_COMMAND); - ENUM_STR(LEX_STATE_ARITHMETIC); - ENUM_STR(LEX_STATE_STRING); - ENUM_STR(LEX_STATE_WORD); - ENUM_STR(LEX_STATE_HASHTABLE); + ENUM_STR(BSHELL_LEX_STATE_STATEMENT); + ENUM_STR(BSHELL_LEX_STATE_COMMAND); + ENUM_STR(BSHELL_LEX_STATE_ARITHMETIC); + ENUM_STR(BSHELL_LEX_STATE_STRING); + ENUM_STR(BSHELL_LEX_STATE_WORD); + ENUM_STR(BSHELL_LEX_STATE_HASHTABLE); default: return ""; } #undef ENUM_STR } -struct lex_state *lex_state_push( - struct lex_ctx *ctx, - enum lex_state_type_id state_type, +struct bshell_lex_state *lex_state_push( + struct bshell_lex_ctx *ctx, + enum bshell_lex_state_id state_type, enum state_flags flags) { - struct lex_state *state = malloc(sizeof *state); + struct bshell_lex_state *state = malloc(sizeof *state); if (!state) { return NULL; } @@ -179,7 +198,7 @@ struct lex_state *lex_state_push( return state; } -void lex_state_pop(struct lex_ctx *ctx) +void lex_state_pop(struct bshell_lex_ctx *ctx) { fx_queue_entry *entry = fx_queue_last(&ctx->lex_state); if (!entry || !fx_queue_prev(entry)) { @@ -187,7 +206,8 @@ void lex_state_pop(struct lex_ctx *ctx) return; } - struct lex_state *state = fx_unbox(struct lex_state, entry, s_entry); + struct bshell_lex_state *state + = fx_unbox(struct bshell_lex_state, entry, s_entry); #if defined(VERBOSE) printf("pop(%s) -> %s\n", @@ -208,19 +228,19 @@ void lex_state_pop(struct lex_ctx *ctx) free(state); } -struct lex_state *lex_state_get(struct lex_ctx *ctx) +struct bshell_lex_state *lex_state_get(struct bshell_lex_ctx *ctx) { fx_queue_entry *entry = fx_queue_last(&ctx->lex_state); if (!entry) { return NULL; } - return fx_unbox(struct lex_state, entry, s_entry); + return fx_unbox(struct bshell_lex_state, entry, s_entry); } -void lex_state_change(struct lex_ctx *ctx, enum lex_state_type_id type) +void lex_state_change(struct bshell_lex_ctx *ctx, enum bshell_lex_state_id type) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); if (!state) { return; } @@ -242,9 +262,9 @@ void lex_state_change(struct lex_ctx *ctx, enum lex_state_type_id type) } } -fx_string *lex_state_get_tempstr(struct lex_ctx *ctx) +fx_string *lex_state_get_tempstr(struct bshell_lex_ctx *ctx) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); if (!state) { return NULL; } @@ -260,21 +280,21 @@ fx_string *lex_state_get_tempstr(struct lex_ctx *ctx) return state->s_tempstr; } -void lex_state_add_terminator(struct lex_state *state, unsigned int tok) +void lex_state_add_terminator(struct bshell_lex_state *state, unsigned int tok) { - if (state->s_nr_terminators < LEX_STATE_MAX_TERMINATORS) { + if (state->s_nr_terminators < BSHELL_LEX_STATE_MAX_TERMINATORS) { state->s_terminators[state->s_nr_terminators++] = tok; } } -static struct lex_symbol_node *get_symbol_node( - struct lex_symbol_node *node, +static struct bshell_lex_symbol_node *get_symbol_node( + struct bshell_lex_symbol_node *node, char c) { fx_queue_entry *entry = fx_queue_first(&node->s_children); while (entry) { - struct lex_symbol_node *child = fx_unbox( - struct lex_symbol_node, + struct bshell_lex_symbol_node *child = fx_unbox( + struct bshell_lex_symbol_node, entry, s_entry); if (child->s_char == c) { @@ -288,12 +308,12 @@ static struct lex_symbol_node *get_symbol_node( } static enum bshell_status put_symbol( - struct lex_symbol_node *tree, - struct lex_token_def *sym) + struct bshell_lex_symbol_node *tree, + struct bshell_lex_token_definition *sym) { for (size_t i = 0; sym->name[i]; i++) { char c = sym->name[i]; - struct lex_symbol_node *child = get_symbol_node(tree, c); + struct bshell_lex_symbol_node *child = get_symbol_node(tree, c); if (child) { tree = child; continue; @@ -317,12 +337,12 @@ static enum bshell_status put_symbol( return BSHELL_SUCCESS; } -static void destroy_symbol_tree(struct lex_symbol_node *tree) +static void destroy_symbol_tree(struct bshell_lex_symbol_node *tree) { fx_queue_entry *entry = fx_queue_first(&tree->s_children); while (entry) { - struct lex_symbol_node *node = fx_unbox( - struct lex_symbol_node, + struct bshell_lex_symbol_node *node = fx_unbox( + struct bshell_lex_symbol_node, entry, s_entry); fx_queue_entry *next = fx_queue_next(entry); @@ -336,9 +356,9 @@ static void destroy_symbol_tree(struct lex_symbol_node *tree) free(tree); } -static struct lex_symbol_node *build_symbol_tree(void) +static struct bshell_lex_symbol_node *build_symbol_tree(void) { - struct lex_symbol_node *root = malloc(sizeof *root); + struct bshell_lex_symbol_node *root = malloc(sizeof *root); if (!root) { return NULL; } @@ -363,12 +383,13 @@ static struct lex_symbol_node *build_symbol_tree(void) return root; } -static void init_token_enabled_states(const struct lex_state_type *state_type) +static void init_token_enabled_states( + const struct bshell_lex_state_type *state_type) { if (state_type->s_keywords) { for (size_t i = 0; state_type->s_keywords[i]; i++) { unsigned int id = state_type->s_keywords[i]; - keywords[id - __KW_INDEX_BASE].enabled_states + keywords[id - __BSHELL_KW_INDEX_BASE].enabled_states |= state_type->s_id; } } @@ -376,7 +397,7 @@ static void init_token_enabled_states(const struct lex_state_type *state_type) if (state_type->s_operators) { for (size_t i = 0; state_type->s_operators[i]; i++) { unsigned int id = state_type->s_operators[i]; - operators[id - __TKOP_INDEX_BASE].enabled_states + operators[id - __BSHELL_TKOP_INDEX_BASE].enabled_states |= state_type->s_id; } } @@ -384,16 +405,16 @@ static void init_token_enabled_states(const struct lex_state_type *state_type) if (state_type->s_symbols) { for (size_t i = 0; state_type->s_symbols[i]; i++) { unsigned int id = state_type->s_symbols[i]; - symbols[id - __SYM_INDEX_BASE].enabled_states + symbols[id - __BSHELL_SYM_INDEX_BASE].enabled_states |= state_type->s_id; } } } -enum bshell_status lex_ctx_init( - struct lex_ctx *ctx, - enum lex_flags flags, - struct line_source *src) +enum bshell_status bshell_lex_ctx_init( + struct bshell_lex_ctx *ctx, + enum bshell_lex_flags flags, + struct bshell_line_source *src) { memset(ctx, 0x0, sizeof *ctx); @@ -401,7 +422,7 @@ enum bshell_status lex_ctx_init( ctx->lex_status = BSHELL_SUCCESS; ctx->lex_buf = fx_stringstream_create(); ctx->lex_sym_tree = build_symbol_tree(); - lex_state_push(ctx, LEX_STATE_STATEMENT, 0); + lex_state_push(ctx, BSHELL_LEX_STATE_STATEMENT, 0); ctx->lex_src = src; ctx->lex_ch = FX_WCHAR_INVALID; ctx->lex_cursor.c_row = ctx->lex_cursor.c_col = 1; @@ -416,7 +437,7 @@ enum bshell_status lex_ctx_init( return BSHELL_SUCCESS; } -enum bshell_status lex_ctx_cleanup(struct lex_ctx *ctx) +enum bshell_status bshell_lex_ctx_cleanup(struct bshell_lex_ctx *ctx) { if (ctx->lex_sym_tree) { destroy_symbol_tree(ctx->lex_sym_tree); @@ -434,15 +455,15 @@ enum bshell_status lex_ctx_cleanup(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status refill_buffer(struct lex_ctx *ctx) +static enum bshell_status refill_buffer(struct bshell_lex_ctx *ctx) { fx_stringstream_reset(ctx->lex_buf); ctx->lex_ch = FX_WCHAR_INVALID; - return line_source_readline(ctx->lex_src, ctx->lex_buf); + return bshell_line_source_readline(ctx->lex_src, ctx->lex_buf); } -static fx_wchar __peek_char(struct lex_ctx *ctx, bool noread) +static fx_wchar __peek_char(struct bshell_lex_ctx *ctx, bool noread) { if (ctx->lex_status != BSHELL_SUCCESS) { return FX_WCHAR_INVALID; @@ -466,17 +487,17 @@ static fx_wchar __peek_char(struct lex_ctx *ctx, bool noread) return ctx->lex_ch; } -fx_wchar peek_char(struct lex_ctx *ctx) +fx_wchar peek_char(struct bshell_lex_ctx *ctx) { return __peek_char(ctx, false); } -fx_wchar peek_char_noread(struct lex_ctx *ctx) +fx_wchar peek_char_noread(struct bshell_lex_ctx *ctx) { return __peek_char(ctx, true); } -static void __advance_char(struct lex_ctx *ctx, bool noread) +static void __advance_char(struct bshell_lex_ctx *ctx, bool noread) { if (ctx->lex_status != BSHELL_SUCCESS) { return; @@ -505,19 +526,19 @@ static void __advance_char(struct lex_ctx *ctx, bool noread) } } -void advance_char(struct lex_ctx *ctx) +void advance_char(struct bshell_lex_ctx *ctx) { return __advance_char(ctx, false); } -void advance_char_noread(struct lex_ctx *ctx) +void advance_char_noread(struct bshell_lex_ctx *ctx) { return __advance_char(ctx, true); } -bool convert_word_to_keyword(struct lex_token *tok) +bool convert_word_to_keyword(struct bshell_lex_token *tok) { - if (!lex_token_has_string_value(tok)) { + if (!bshell_lex_token_has_string_value(tok)) { return false; } @@ -527,7 +548,7 @@ bool convert_word_to_keyword(struct lex_token *tok) continue; } - lex_token_change_type(tok, TOK_KEYWORD); + bshell_lex_token_change_type(tok, BSHELL_TOK_KEYWORD); tok->tok_keyword = keywords[i].id; return true; } @@ -535,18 +556,21 @@ bool convert_word_to_keyword(struct lex_token *tok) return false; } -bool convert_word_to_operator(struct lex_ctx *ctx, struct lex_token *tok) +bool convert_word_to_operator( + struct bshell_lex_ctx *ctx, + struct bshell_lex_token *tok) { - if (!lex_token_has_string_value(tok)) { + if (!bshell_lex_token_has_string_value(tok)) { return false; } - enum token_operator op = get_operator_with_string(ctx, tok->tok_str); - if (op == TKOP_NONE) { + enum bshell_lex_operator op + = get_bshell_operator_with_string(ctx, tok->tok_str); + if (op == BSHELL_TKOP_NONE) { return false; } - lex_token_change_type(tok, TOK_OPERATOR); + bshell_lex_token_change_type(tok, BSHELL_TOK_OPERATOR); tok->tok_operator = op; return true; } @@ -615,7 +639,7 @@ static bool string_could_be_double(const char *s) bool string_is_valid_number( const char *s, fx_value *out, - enum token_type *out_type) + enum bshell_lex_token_type *out_type) { if (s[0] == '\0') { return NULL; @@ -629,7 +653,7 @@ bool string_is_valid_number( } if (out_type) { - *out_type = TOK_DOUBLE; + *out_type = BSHELL_TOK_DOUBLE; } return true; @@ -644,7 +668,7 @@ bool string_is_valid_number( } if (out_type) { - *out_type = TOK_INT; + *out_type = BSHELL_TOK_INT; } return true; @@ -657,7 +681,7 @@ bool string_is_valid_number( } if (out_type) { - *out_type = TOK_INT; + *out_type = BSHELL_TOK_INT; } return true; @@ -666,32 +690,32 @@ bool string_is_valid_number( return false; } -bool convert_word_to_number(struct lex_token *tok) +bool convert_word_to_number(struct bshell_lex_token *tok) { - if (!lex_token_has_string_value(tok)) { + if (!bshell_lex_token_has_string_value(tok)) { return false; } const char *s = tok->tok_str; fx_value value; - enum token_type type; + enum bshell_lex_token_type type; if (!string_is_valid_number(s, &value, &type)) { return false; } - lex_token_change_type(tok, type); + bshell_lex_token_change_type(tok, type); tok->tok_number = value; return true; } -static struct lex_token *get_next_token(struct lex_ctx *ctx) +static struct bshell_lex_token *get_next_token(struct bshell_lex_ctx *ctx) { fx_queue_entry *entry = fx_queue_first(&ctx->lex_tokens); - return fx_unbox(struct lex_token, entry, tok_entry); + return fx_unbox(struct bshell_lex_token, entry, tok_entry); } -void enqueue_token(struct lex_ctx *ctx, struct lex_token *tok) +void enqueue_token(struct bshell_lex_ctx *ctx, struct bshell_lex_token *tok) { enqueue_token_with_coordinates( ctx, @@ -701,14 +725,14 @@ void enqueue_token(struct lex_ctx *ctx, struct lex_token *tok) } extern void enqueue_token_with_coordinates( - struct lex_ctx *ctx, - struct lex_token *tok, - const struct char_cell *start, - const struct char_cell *end) + struct bshell_lex_ctx *ctx, + struct bshell_lex_token *tok, + const struct bshell_char_cell *start, + const struct bshell_char_cell *end) { - if (tok->tok_type == TOK_LINEFEED - && ctx->lex_prev_token == TOK_LINEFEED) { - lex_token_destroy(tok); + if (tok->tok_type == BSHELL_TOK_LINEFEED + && ctx->lex_prev_token == BSHELL_TOK_LINEFEED) { + bshell_lex_token_destroy(tok); return; } @@ -716,20 +740,20 @@ extern void enqueue_token_with_coordinates( tok->tok_end = *end; ctx->lex_prev_token = tok->tok_type; - if (tok && (ctx->lex_flags & LEX_PRINT_TOKENS)) { - print_lex_token(tok); + if (ctx->lex_token_scanned) { + ctx->lex_token_scanned(ctx, tok); } fx_queue_push_back(&ctx->lex_tokens, &tok->tok_entry); } -static struct lex_token *dequeue_next_token(struct lex_ctx *ctx) +static struct bshell_lex_token *dequeue_next_token(struct bshell_lex_ctx *ctx) { fx_queue_entry *entry = fx_queue_pop_front(&ctx->lex_tokens); - return fx_unbox(struct lex_token, entry, tok_entry); + return fx_unbox(struct bshell_lex_token, entry, tok_entry); } -static fx_string *get_temp_string(struct lex_ctx *ctx) +static fx_string *get_temp_string(struct bshell_lex_ctx *ctx) { if (!ctx->lex_tmp) { ctx->lex_tmp = fx_string_create(); @@ -739,9 +763,12 @@ static fx_string *get_temp_string(struct lex_ctx *ctx) return ctx->lex_tmp; } -enum bshell_status push_symbol(struct lex_ctx *ctx, enum token_symbol sym) +enum bshell_status push_symbol( + struct bshell_lex_ctx *ctx, + enum bshell_lex_symbol sym) { - struct lex_token *tok = lex_token_create(TOK_SYMBOL); + struct bshell_lex_token *tok + = bshell_lex_token_create(BSHELL_TOK_SYMBOL); if (!tok) { return BSHELL_ERR_NO_MEMORY; } @@ -752,9 +779,9 @@ enum bshell_status push_symbol(struct lex_ctx *ctx, enum token_symbol sym) } enum bshell_status read_var( - struct lex_ctx *ctx, - enum token_type type, - struct lex_token **out) + struct bshell_lex_ctx *ctx, + enum bshell_lex_token_type type, + struct bshell_lex_token **out) { fx_string *tmp = get_temp_string(ctx); @@ -784,7 +811,7 @@ enum bshell_status read_var( return ctx->lex_status; } - struct lex_token *tok = lex_token_create_with_string( + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( type, fx_string_get_cstr(tmp)); @@ -793,9 +820,9 @@ enum bshell_status read_var( } enum bshell_status read_braced_var( - struct lex_ctx *ctx, - enum token_type type, - struct lex_token **out) + struct bshell_lex_ctx *ctx, + enum bshell_lex_token_type type, + struct bshell_lex_token **out) { fx_string *tmp = get_temp_string(ctx); bool ok = false; @@ -825,7 +852,7 @@ enum bshell_status read_braced_var( return ctx->lex_status; } - struct lex_token *tok = lex_token_create_with_string( + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( type, fx_string_get_cstr(tmp)); @@ -834,8 +861,8 @@ enum bshell_status read_braced_var( } enum bshell_status read_literal_string( - struct lex_ctx *ctx, - struct lex_token **out) + struct bshell_lex_ctx *ctx, + struct bshell_lex_token **out) { fx_string *tmp = get_temp_string(ctx); @@ -859,15 +886,15 @@ enum bshell_status read_literal_string( advance_char(ctx); } - struct lex_token *tok = lex_token_create_with_string( - TOK_STRING, + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( + BSHELL_TOK_STRING, fx_string_get_cstr(tmp)); *out = tok; return BSHELL_SUCCESS; } -enum bshell_status read_line_comment(struct lex_ctx *lex) +enum bshell_status read_line_comment(struct bshell_lex_ctx *lex) { while (true) { fx_wchar c = peek_char(lex); @@ -887,9 +914,9 @@ enum bshell_status read_line_comment(struct lex_ctx *lex) } enum bshell_status read_word( - struct lex_ctx *ctx, + struct bshell_lex_ctx *ctx, enum read_flags flags, - struct lex_token **out) + struct bshell_lex_token **out) { fx_string *tmp = get_temp_string(ctx); bool word_is_number = false; @@ -904,7 +931,7 @@ enum bshell_status read_word( bool number_recog = !(flags & READ_NO_NUMBER_RECOGNITION); - enum token_operator op = TKOP_NONE; + enum bshell_lex_operator op = BSHELL_TKOP_NONE; bool done = false; while (!done) { fx_wchar c = peek_char(ctx); @@ -929,7 +956,7 @@ enum bshell_status read_word( if (char_can_begin_symbol_in_state( ctx, c, - LEX_STATE_ARITHMETIC)) { + BSHELL_LEX_STATE_ARITHMETIC)) { done = true; break; } @@ -941,8 +968,8 @@ enum bshell_status read_word( } if (!fx_wchar_is_alpha(c)) { - op = get_operator_with_string(ctx, s); - if (op != TKOP_NONE) { + op = get_bshell_operator_with_string(ctx, s); + if (op != BSHELL_TKOP_NONE) { done = true; break; } @@ -961,8 +988,8 @@ enum bshell_status read_word( return ctx->lex_status; } - struct lex_token *tok = lex_token_create_with_string( - TOK_WORD, + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( + BSHELL_TOK_WORD, fx_string_get_cstr(tmp)); *out = tok; @@ -970,13 +997,13 @@ enum bshell_status read_word( } enum bshell_status read_symbol( - struct lex_ctx *ctx, - const struct lex_token_def **out) + struct bshell_lex_ctx *ctx, + const struct bshell_lex_token_definition **out) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); set_token_start(ctx); - struct lex_symbol_node *node = ctx->lex_sym_tree; + struct bshell_lex_symbol_node *node = ctx->lex_sym_tree; char prev = 0; while (true) { @@ -985,7 +1012,7 @@ enum bshell_status read_symbol( break; } - struct lex_symbol_node *next = get_symbol_node(node, c); + struct bshell_lex_symbol_node *next = get_symbol_node(node, c); if (!next || (next->s_def && !(next->s_def->enabled_states @@ -1009,9 +1036,9 @@ enum bshell_status read_symbol( } bool char_can_begin_symbol_in_state( - struct lex_ctx *ctx, + struct bshell_lex_ctx *ctx, char c, - enum lex_state_type_id state_type) + enum bshell_lex_state_id state_type) { for (size_t i = 0; i < nr_symbols; i++) { if (!symbols[i].name) { @@ -1030,13 +1057,16 @@ bool char_can_begin_symbol_in_state( return false; } -bool char_can_begin_symbol(struct lex_ctx *ctx, char c) +bool char_can_begin_symbol(struct bshell_lex_ctx *ctx, char c) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); return char_can_begin_symbol_in_state(ctx, c, state->s_type->s_id); } -bool char_has_flags(struct lex_ctx *ctx, char c, enum lex_token_flags flags) +bool char_has_flags( + struct bshell_lex_ctx *ctx, + char c, + enum bshell_lex_token_flags flags) { for (size_t i = 0; i < nr_symbols; i++) { if (!symbols[i].name) { @@ -1054,9 +1084,9 @@ bool char_has_flags(struct lex_ctx *ctx, char c, enum lex_token_flags flags) } bool keyword_has_flags( - struct lex_ctx *ctx, - enum token_keyword kw, - enum lex_token_flags flags) + struct bshell_lex_ctx *ctx, + enum bshell_lex_keyword kw, + enum bshell_lex_token_flags flags) { for (size_t i = 0; i < nr_symbols; i++) { if (keywords[i].id == kw) { @@ -1067,9 +1097,9 @@ bool keyword_has_flags( return false; } -enum lex_token_flags keyword_get_flags( - struct lex_ctx *ctx, - enum token_keyword kw) +enum bshell_lex_token_flags keyword_get_flags( + struct bshell_lex_ctx *ctx, + enum bshell_lex_keyword kw) { for (size_t i = 0; i < nr_symbols; i++) { if (keywords[i].id == kw) { @@ -1081,9 +1111,9 @@ enum lex_token_flags keyword_get_flags( } bool symbol_has_flags( - struct lex_ctx *ctx, - enum token_symbol sym, - enum lex_token_flags flags) + struct bshell_lex_ctx *ctx, + enum bshell_lex_symbol sym, + enum bshell_lex_token_flags flags) { for (size_t i = 0; i < nr_symbols; i++) { if (symbols[i].id == sym) { @@ -1094,9 +1124,9 @@ bool symbol_has_flags( return false; } -enum lex_token_flags symbol_get_flags( - struct lex_ctx *ctx, - enum token_symbol sym) +enum bshell_lex_token_flags symbol_get_flags( + struct bshell_lex_ctx *ctx, + enum bshell_lex_symbol sym) { for (size_t i = 0; i < nr_symbols; i++) { if (symbols[i].id == sym) { @@ -1107,9 +1137,11 @@ enum lex_token_flags symbol_get_flags( return false; } -enum token_operator get_operator_with_string(struct lex_ctx *ctx, const char *s) +enum bshell_lex_operator get_bshell_operator_with_string( + struct bshell_lex_ctx *ctx, + const char *s) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); for (size_t i = 0; i < nr_operators; i++) { const char *op_str = operators[i].name; @@ -1134,24 +1166,33 @@ int compare_token_types(unsigned int a, unsigned int b) } #define BETWEEN(v, lo, hi) ((v) >= (lo) && (v) <= (hi)) - enum token_type a_type = TOK_NONE, b_type = TOK_NONE; + enum bshell_lex_token_type a_type = BSHELL_TOK_NONE, b_type + = BSHELL_TOK_NONE; - if (BETWEEN(a, __KW_INDEX_BASE, __KW_INDEX_LIMIT)) { - a_type = TOK_KEYWORD; - } else if (BETWEEN(a, __TKOP_INDEX_BASE, __TKOP_INDEX_LIMIT)) { - a_type = TOK_OPERATOR; - } else if (BETWEEN(a, __SYM_INDEX_BASE, __SYM_INDEX_LIMIT)) { - a_type = TOK_SYMBOL; + if (BETWEEN(a, __BSHELL_KW_INDEX_BASE, __BSHELL_KW_INDEX_LIMIT)) { + a_type = BSHELL_TOK_KEYWORD; + } else if (BETWEEN(a, + __BSHELL_TKOP_INDEX_BASE, + __BSHELL_TKOP_INDEX_LIMIT)) { + a_type = BSHELL_TOK_OPERATOR; + } else if (BETWEEN(a, + __BSHELL_SYM_INDEX_BASE, + __BSHELL_SYM_INDEX_LIMIT)) { + a_type = BSHELL_TOK_SYMBOL; } else { a_type = a; } - if (BETWEEN(b, __KW_INDEX_BASE, __KW_INDEX_LIMIT)) { - b_type = TOK_KEYWORD; - } else if (BETWEEN(b, __TKOP_INDEX_BASE, __TKOP_INDEX_LIMIT)) { - b_type = TOK_OPERATOR; - } else if (BETWEEN(b, __SYM_INDEX_BASE, __SYM_INDEX_LIMIT)) { - b_type = TOK_SYMBOL; + if (BETWEEN(b, __BSHELL_KW_INDEX_BASE, __BSHELL_KW_INDEX_LIMIT)) { + b_type = BSHELL_TOK_KEYWORD; + } else if (BETWEEN(b, + __BSHELL_TKOP_INDEX_BASE, + __BSHELL_TKOP_INDEX_LIMIT)) { + b_type = BSHELL_TOK_OPERATOR; + } else if (BETWEEN(b, + __BSHELL_SYM_INDEX_BASE, + __BSHELL_SYM_INDEX_LIMIT)) { + b_type = BSHELL_TOK_SYMBOL; } else { b_type = b; } @@ -1174,11 +1215,11 @@ int compare_token_types(unsigned int a, unsigned int b) } static bool do_lex_state_transition( - struct lex_ctx *ctx, + struct bshell_lex_ctx *ctx, unsigned int token, bool recursive) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); enum link_flags required_flags = 0; if (recursive) { required_flags |= LINK_ALLOW_RECURSION; @@ -1193,17 +1234,17 @@ static bool do_lex_state_transition( } } - const struct lex_state_link *table = state->s_type->s_links; + const struct bshell_lex_state_link *table = state->s_type->s_links; if (!table) { return false; } #define MAX_MATCHES 8 - const struct lex_state_link *best_matches[MAX_MATCHES] = {0}; + const struct bshell_lex_state_link *best_matches[MAX_MATCHES] = {0}; unsigned int match_count = 0; int best_score = 0; - for (unsigned int i = 0; table[i].l_token != TOK_NONE; i++) { + for (unsigned int i = 0; table[i].l_token != BSHELL_TOK_NONE; i++) { int score = compare_token_types(table[i].l_token, token); if ((table[i].l_flags & required_flags) != required_flags) { score = 0; @@ -1231,14 +1272,14 @@ static bool do_lex_state_transition( bool result = false; for (unsigned int i = 0; i < match_count; i++) { - const struct lex_state_link *link = best_matches[i]; + const struct bshell_lex_state_link *link = best_matches[i]; switch (link->l_type) { - case LEX_STATE_LINK_POP: + case BSHELL_LEX_STATE_LINK_POP: lex_state_pop(ctx); result = true; break; - case LEX_STATE_LINK_PUSH: { - struct lex_state *state = lex_state_push( + case BSHELL_LEX_STATE_LINK_PUSH: { + struct bshell_lex_state *state = lex_state_push( ctx, link->l_target, link->l_target_flags); @@ -1251,7 +1292,7 @@ static bool do_lex_state_transition( break; } - case LEX_STATE_LINK_CHANGE: + case BSHELL_LEX_STATE_LINK_CHANGE: lex_state_change(ctx, link->l_target); result = true; break; @@ -1263,7 +1304,7 @@ static bool do_lex_state_transition( return result; } -void handle_lex_state_transition(struct lex_ctx *ctx, unsigned int token) +void handle_lex_state_transition(struct bshell_lex_ctx *ctx, unsigned int token) { bool cont = false; bool recursive = false; @@ -1273,11 +1314,11 @@ void handle_lex_state_transition(struct lex_ctx *ctx, unsigned int token) } while (cont); } -static enum bshell_status read_string_content(struct lex_ctx *ctx) +static enum bshell_status read_string_content(struct bshell_lex_ctx *ctx) { fx_wchar c = FX_WCHAR_INVALID; fx_string *str = get_temp_string(ctx); - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); if (!str) { return BSHELL_ERR_NO_MEMORY; @@ -1302,8 +1343,8 @@ static enum bshell_status read_string_content(struct lex_ctx *ctx) return BSHELL_SUCCESS; } - struct lex_token *tok = lex_token_create_with_string( - TOK_STRING, + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( + BSHELL_TOK_STRING, fx_string_get_cstr(str)); enqueue_token(ctx, tok); @@ -1311,7 +1352,7 @@ static enum bshell_status read_string_content(struct lex_ctx *ctx) } #if 0 -static enum bshell_status do_pump_token_string(struct lex_ctx *ctx) +static enum bshell_status do_pump_token_string(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); enum bshell_status status = BSHELL_SUCCESS; @@ -1329,7 +1370,7 @@ static enum bshell_status do_pump_token_string(struct lex_ctx *ctx) return status; } -static enum bshell_status do_pump_token_normal(struct lex_ctx *ctx) +static enum bshell_status do_pump_token_normal(struct bshell_lex_ctx *ctx) { enum bshell_status status = BSHELL_SUCCESS; @@ -1346,7 +1387,7 @@ static enum bshell_status do_pump_token_normal(struct lex_ctx *ctx) } if (newline) { - struct lex_token *tok = lex_token_create(TOK_LINEFEED); + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_LINEFEED); enqueue_token(ctx, tok); return BSHELL_SUCCESS; } @@ -1363,38 +1404,36 @@ static enum bshell_status do_pump_token_normal(struct lex_ctx *ctx) } #endif -static enum bshell_status pump_tokens(struct lex_ctx *ctx) +static enum bshell_status pump_tokens(struct bshell_lex_ctx *ctx) { enum bshell_status status = BSHELL_SUCCESS; while (fx_queue_empty(&ctx->lex_tokens) && status == BSHELL_SUCCESS) { - struct lex_state *state = lex_state_get(ctx); + struct bshell_lex_state *state = lex_state_get(ctx); status = state->s_type->s_pump_token(ctx); } return status; } -static void discard_all_tokens(struct lex_ctx *ctx) +static void discard_all_tokens(struct bshell_lex_ctx *ctx) { fx_queue_entry *cur = fx_queue_first(&ctx->lex_tokens); while (cur) { - struct lex_token *tok = fx_unbox( - struct lex_token, - cur, - tok_entry); - if (tok->tok_type == TOK_LINEFEED) { + struct bshell_lex_token *tok + = fx_unbox(struct bshell_lex_token, cur, tok_entry); + if (tok->tok_type == BSHELL_TOK_LINEFEED) { break; } fx_queue_pop_front(&ctx->lex_tokens); - lex_token_destroy(tok); + bshell_lex_token_destroy(tok); cur = fx_queue_first(&ctx->lex_tokens); } } -struct lex_token *lex_ctx_peek(struct lex_ctx *ctx) +struct bshell_lex_token *bshell_lex_ctx_peek(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = get_next_token(ctx); + struct bshell_lex_token *tok = get_next_token(ctx); if (tok) { return tok; } @@ -1405,9 +1444,9 @@ struct lex_token *lex_ctx_peek(struct lex_ctx *ctx) return tok; } -struct lex_token *lex_ctx_claim(struct lex_ctx *ctx) +struct bshell_lex_token *bshell_lex_ctx_claim(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = dequeue_next_token(ctx); + struct bshell_lex_token *tok = dequeue_next_token(ctx); if (tok) { return tok; } @@ -1421,11 +1460,11 @@ struct lex_token *lex_ctx_claim(struct lex_ctx *ctx) return dequeue_next_token(ctx); } -void lex_ctx_discard(struct lex_ctx *ctx) +void bshell_lex_ctx_discard(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = dequeue_next_token(ctx); + struct bshell_lex_token *tok = dequeue_next_token(ctx); if (tok) { - lex_token_destroy(tok); + bshell_lex_token_destroy(tok); return; } diff --git a/bshell.runtime/parse/lex/statement.c b/bshell.runtime/parse/lex/statement.c new file mode 100644 index 0000000..b45f754 --- /dev/null +++ b/bshell.runtime/parse/lex/statement.c @@ -0,0 +1,254 @@ +#include "lex-internal.h" + +static enum bshell_status statement_hyphen(struct bshell_lex_ctx *ctx) +{ + fx_wchar c = peek_char(ctx); + if (!fx_wchar_is_alnum(c)) { + push_symbol(ctx, BSHELL_SYM_HYPHEN); + handle_lex_state_transition(ctx, BSHELL_SYM_HYPHEN); + return BSHELL_SUCCESS; + } + + struct bshell_lex_token *tok = NULL; + enum bshell_status status = read_word( + ctx, + READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN, + &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + unsigned int token_type = BSHELL_TOK_WORD; + + if (convert_word_to_number(tok)) { + token_type = tok->tok_type; + + /* because of APPEND_HYPHEN (which is needed to ensure operator + * tokens are detected properly), the resulting number will be + * negative. + * this token will be preceded by a HYPHEN token, so the number + * must be positive */ + fx_value neg = FX_INT(-1); + fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number); + push_symbol(ctx, BSHELL_SYM_HYPHEN); + } else if (convert_word_to_operator(ctx, tok)) { + token_type = tok->tok_operator; + } + + handle_lex_state_transition(ctx, token_type); + enqueue_token(ctx, tok); + + return BSHELL_SUCCESS; +} + +static enum bshell_status statement_symbol(struct bshell_lex_ctx *ctx) +{ + const struct bshell_lex_token_definition *sym = NULL; + enum bshell_status status = read_symbol(ctx, &sym); + + if (status != BSHELL_SUCCESS) { + return status; + } + + handle_lex_state_transition(ctx, sym->id); + + struct bshell_lex_token *tok = NULL; + switch (sym->id) { + case BSHELL_SYM_DQUOTE: + return BSHELL_SUCCESS; + case BSHELL_SYM_HYPHEN: + return statement_hyphen(ctx); + case BSHELL_SYM_SQUOTE: + status = read_literal_string(ctx, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + enqueue_token(ctx, tok); + return BSHELL_SUCCESS; + + case BSHELL_SYM_HASH: + return read_line_comment(ctx); + case BSHELL_SYM_DOLLAR: + status = read_var(ctx, BSHELL_TOK_VAR, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + enqueue_token(ctx, tok); + return status; + case BSHELL_SYM_AT: + status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + enqueue_token(ctx, tok); + return status; + case BSHELL_SYM_DOLLAR_LEFT_BRACE: + status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok); + if (status != BSHELL_SUCCESS) { + return status; + } + + enqueue_token(ctx, tok); + return status; + default: + break; + } + + push_symbol(ctx, sym->id); + return BSHELL_SUCCESS; +} + +static enum bshell_status statement_word(struct bshell_lex_ctx *ctx) +{ + struct bshell_lex_token *word = NULL; + enum bshell_status status = read_word(ctx, 0, &word); + if (status != BSHELL_SUCCESS) { + return status; + } + + struct bshell_lex_state *state = lex_state_get(ctx); + + bool enable_keywords = !(state->s_flags & STATEMENT_F_DISABLE_KEYWORDS); + unsigned int token = BSHELL_TOK_WORD; + + if (enable_keywords && convert_word_to_keyword(word)) { + token = word->tok_keyword; + } else if (convert_word_to_number(word)) { + token = word->tok_type; + } + + handle_lex_state_transition(ctx, token); + + enqueue_token(ctx, word); + return BSHELL_SUCCESS; +} + +static enum bshell_status statement_pump_token(struct bshell_lex_ctx *ctx) +{ + fx_wchar c = peek_char(ctx); + bool newline = false; + + set_token_start(ctx); + while (fx_wchar_is_space(c)) { + if (c == '\n') { + newline = true; + } + + set_token_end(ctx); + advance_char_noread(ctx); + c = peek_char_noread(ctx); + } + + if (newline) { + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_LINEFEED); + enqueue_token(ctx, tok); + handle_lex_state_transition(ctx, BSHELL_TOK_LINEFEED); + return BSHELL_SUCCESS; + } + + if (char_can_begin_symbol(ctx, c)) { + return statement_symbol(ctx); + } + + if (char_has_flags(ctx, c, BSHELL_LEX_TOKEN_UNARY_ARITHMETIC)) { + lex_state_change(ctx, BSHELL_LEX_STATE_ARITHMETIC); + return BSHELL_SUCCESS; + } + + return statement_word(ctx); +} + +static const struct bshell_lex_state_link links[] = { + LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0), + /* arithmetic tokens */ + LINK_CHANGE(BSHELL_TOK_KEYWORD, BSHELL_LEX_STATE_ARITHMETIC), + LINK_CHANGE(BSHELL_SYM_SQUOTE, BSHELL_LEX_STATE_ARITHMETIC), + LINK_CHANGE(BSHELL_TOK_INT, BSHELL_LEX_STATE_ARITHMETIC), + LINK_CHANGE(BSHELL_TOK_DOUBLE, BSHELL_LEX_STATE_ARITHMETIC), + LINK_PUSH(BSHELL_SYM_DOLLAR, BSHELL_LEX_STATE_ARITHMETIC, 0), + LINK_PUSH_WITH_TERM( + BSHELL_SYM_DOLLAR_LEFT_BRACE, + BSHELL_LEX_STATE_ARITHMETIC, + 0, + BSHELL_SYM_RIGHT_BRACE), + LINK_CHANGE(BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_ARITHMETIC), + LINK_CHANGE(BSHELL_SYM_AT_LEFT_PAREN, BSHELL_LEX_STATE_ARITHMETIC), + LINK_PUSH_WITH_TERM( + BSHELL_SYM_AT_LEFT_BRACE, + BSHELL_LEX_STATE_HASHTABLE, + 0, + BSHELL_SYM_RIGHT_BRACE), + LINK_PUSH(BSHELL_SYM_AT, BSHELL_LEX_STATE_ARITHMETIC, 0), + LINK_CHANGE(BSHELL_SYM_LEFT_PAREN, BSHELL_LEX_STATE_ARITHMETIC), + LINK_CHANGE(BSHELL_SYM_LEFT_BRACKET, BSHELL_LEX_STATE_ARITHMETIC), + LINK_CHANGE(BSHELL_SYM_BANG, BSHELL_LEX_STATE_ARITHMETIC), + LINK_PUSH_WITH_TERM( + BSHELL_SYM_LEFT_PAREN, + BSHELL_LEX_STATE_STATEMENT, + STATEMENT_F_DISABLE_KEYWORDS, + BSHELL_SYM_RIGHT_PAREN), + + /* statement tokens */ + LINK_PUSH_WITH_TERM( + BSHELL_SYM_LEFT_BRACE, + BSHELL_LEX_STATE_STATEMENT, + 0, + BSHELL_SYM_RIGHT_BRACE), + LINK_PUSH_WITH_TERM( + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_LEX_STATE_STATEMENT, + 0, + BSHELL_SYM_RIGHT_PAREN), + + /* command tokens */ + LINK_CHANGE(BSHELL_KW_FUNC, BSHELL_LEX_STATE_COMMAND), + LINK_CHANGE(BSHELL_SYM_AMPERSAND, BSHELL_LEX_STATE_COMMAND), + LINK_CHANGE(BSHELL_TOK_WORD, BSHELL_LEX_STATE_COMMAND), + LINK_END, +}; + +static const unsigned int keywords[] = { + BSHELL_KW_FUNC, + BSHELL_KW_IF, + BSHELL_KW_ELSEIF, + BSHELL_KW_ELSE, + BSHELL_KW_NONE, +}; + +static const unsigned int operators[] = { + BSHELL_TKOP_BNOT, + BSHELL_TKOP_NOT, + BSHELL_TKOP_NONE, +}; + +static const unsigned int symbols[] = { + BSHELL_SYM_AMPERSAND, + BSHELL_SYM_BANG, + BSHELL_SYM_SQUOTE, + BSHELL_SYM_DQUOTE, + BSHELL_SYM_HASH, + BSHELL_SYM_AT, + BSHELL_SYM_AT_LEFT_PAREN, + BSHELL_SYM_AT_LEFT_BRACE, + BSHELL_SYM_PIPE, + BSHELL_SYM_COMMA, + BSHELL_SYM_SEMICOLON, + BSHELL_SYM_LEFT_BRACE, + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_LEFT_BRACKET, + BSHELL_SYM_RIGHT_BRACKET, + BSHELL_SYM_LEFT_PAREN, + BSHELL_SYM_RIGHT_PAREN, + BSHELL_SYM_NONE, +}; + +const struct bshell_lex_state_type lex_statement_state = { + .s_id = BSHELL_LEX_STATE_STATEMENT, + .s_pump_token = statement_pump_token, + .s_links = links, + .s_keywords = keywords, + .s_operators = operators, + .s_symbols = symbols, +}; diff --git a/bshell/parse/lex/string.c b/bshell.runtime/parse/lex/string.c similarity index 56% rename from bshell/parse/lex/string.c rename to bshell.runtime/parse/lex/string.c index bb7d230..633e651 100644 --- a/bshell/parse/lex/string.c +++ b/bshell.runtime/parse/lex/string.c @@ -1,8 +1,8 @@ #include "lex-internal.h" -static enum bshell_status string_symbol(struct lex_ctx *ctx) +static enum bshell_status string_symbol(struct bshell_lex_ctx *ctx) { - const struct lex_token_def *sym = NULL; + const struct bshell_lex_token_definition *sym = NULL; enum bshell_status status = read_symbol(ctx, &sym); if (status != BSHELL_SUCCESS) { @@ -11,31 +11,31 @@ static enum bshell_status string_symbol(struct lex_ctx *ctx) handle_lex_state_transition(ctx, sym->id); - struct lex_token *tok = NULL; + struct bshell_lex_token *tok = NULL; switch (sym->id) { - case SYM_DQUOTE: + case BSHELL_SYM_DQUOTE: return BSHELL_SUCCESS; - case SYM_DOLLAR_LEFT_PAREN: + case BSHELL_SYM_DOLLAR_LEFT_PAREN: return push_symbol(ctx, sym->id); - case SYM_DOLLAR: - status = read_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR: + status = read_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; - case SYM_AT: - status = read_var(ctx, TOK_VAR_SPLAT, &tok); + case BSHELL_SYM_AT: + status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; - case SYM_DOLLAR_LEFT_BRACE: - status = read_braced_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR_LEFT_BRACE: + status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } @@ -49,7 +49,7 @@ static enum bshell_status string_symbol(struct lex_ctx *ctx) return BSHELL_ERR_BAD_SYNTAX; } -static enum bshell_status string_content(struct lex_ctx *ctx) +static enum bshell_status string_content(struct bshell_lex_ctx *ctx) { fx_wchar c = FX_WCHAR_INVALID; fx_string *temp = lex_state_get_tempstr(ctx); @@ -76,17 +76,17 @@ static enum bshell_status string_content(struct lex_ctx *ctx) return BSHELL_SUCCESS; } - struct lex_token *tok = lex_token_create_with_string( - TOK_STRING, + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( + BSHELL_TOK_STRING, fx_string_get_cstr(temp)); enqueue_token(ctx, tok); return BSHELL_SUCCESS; } -static enum bshell_status string_begin(struct lex_ctx *ctx) +static enum bshell_status string_begin(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = lex_token_create(TOK_STR_START); + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_STR_START); if (!tok) { return BSHELL_ERR_NO_MEMORY; } @@ -95,9 +95,9 @@ static enum bshell_status string_begin(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status string_end(struct lex_ctx *ctx) +static enum bshell_status string_end(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = lex_token_create(TOK_STR_END); + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_STR_END); if (!tok) { return BSHELL_ERR_NO_MEMORY; } @@ -106,7 +106,7 @@ static enum bshell_status string_end(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status string_pump_token(struct lex_ctx *ctx) +static enum bshell_status string_pump_token(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); @@ -117,22 +117,22 @@ static enum bshell_status string_pump_token(struct lex_ctx *ctx) return string_content(ctx); } -static const struct lex_state_link links[] = { - LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0), - LINK_POP(SYM_DQUOTE), +static const struct bshell_lex_state_link links[] = { + LINK_PUSH(BSHELL_SYM_DOLLAR_LEFT_PAREN, BSHELL_LEX_STATE_STATEMENT, 0), + LINK_POP(BSHELL_SYM_DQUOTE), LINK_END, }; static const unsigned int symbols[] = { - SYM_DOLLAR, - SYM_DOLLAR_LEFT_PAREN, - SYM_DOLLAR_LEFT_BRACE, - SYM_DQUOTE, - SYM_NONE, + BSHELL_SYM_DOLLAR, + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_SYM_DOLLAR_LEFT_BRACE, + BSHELL_SYM_DQUOTE, + BSHELL_SYM_NONE, }; -const struct lex_state_type lex_string_state = { - .s_id = LEX_STATE_STRING, +const struct bshell_lex_state_type lex_string_state = { + .s_id = BSHELL_LEX_STATE_STRING, .s_begin = string_begin, .s_end = string_end, .s_pump_token = string_pump_token, diff --git a/bshell/parse/lex/word.c b/bshell.runtime/parse/lex/word.c similarity index 59% rename from bshell/parse/lex/word.c rename to bshell.runtime/parse/lex/word.c index 9ac8f06..357b43b 100644 --- a/bshell/parse/lex/word.c +++ b/bshell.runtime/parse/lex/word.c @@ -1,26 +1,26 @@ #include "lex-internal.h" -static enum bshell_status word_symbol(struct lex_ctx *ctx) +static enum bshell_status word_symbol(struct bshell_lex_ctx *ctx) { - const struct lex_token_def *sym = NULL; + const struct bshell_lex_token_definition *sym = NULL; enum bshell_status status = read_symbol(ctx, &sym); if (status != BSHELL_SUCCESS) { return status; } - struct lex_token *tok = NULL; + struct bshell_lex_token *tok = NULL; switch (sym->id) { - case SYM_DOLLAR_LEFT_PAREN: + case BSHELL_SYM_DOLLAR_LEFT_PAREN: status = push_symbol(ctx, sym->id); if (status != BSHELL_SUCCESS) { return status; } - lex_state_push(ctx, LEX_STATE_STATEMENT, 0); + lex_state_push(ctx, BSHELL_LEX_STATE_STATEMENT, 0); return BSHELL_SUCCESS; - case SYM_RIGHT_PAREN: + case BSHELL_SYM_RIGHT_PAREN: lex_state_pop(ctx); status = push_symbol(ctx, sym->id); @@ -28,16 +28,16 @@ static enum bshell_status word_symbol(struct lex_ctx *ctx) return status; } return BSHELL_SUCCESS; - case SYM_DOLLAR: - status = read_var(ctx, TOK_VAR, &tok); + case BSHELL_SYM_DOLLAR: + status = read_var(ctx, BSHELL_TOK_VAR, &tok); if (status != BSHELL_SUCCESS) { return status; } enqueue_token(ctx, tok); return status; - case SYM_AT: - status = read_var(ctx, TOK_VAR_SPLAT, &tok); + case BSHELL_SYM_AT: + status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok); if (status != BSHELL_SUCCESS) { return status; } @@ -51,7 +51,7 @@ static enum bshell_status word_symbol(struct lex_ctx *ctx) return BSHELL_ERR_BAD_SYNTAX; } -static enum bshell_status word_content(struct lex_ctx *ctx) +static enum bshell_status word_content(struct bshell_lex_ctx *ctx) { fx_wchar c = FX_WCHAR_INVALID; fx_string *temp = lex_state_get_tempstr(ctx); @@ -82,17 +82,17 @@ static enum bshell_status word_content(struct lex_ctx *ctx) return BSHELL_SUCCESS; } - struct lex_token *tok = lex_token_create_with_string( - TOK_WORD, + struct bshell_lex_token *tok = bshell_lex_token_create_with_string( + BSHELL_TOK_WORD, fx_string_get_cstr(temp)); enqueue_token(ctx, tok); return BSHELL_SUCCESS; } -static enum bshell_status word_begin(struct lex_ctx *ctx) +static enum bshell_status word_begin(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = lex_token_create(TOK_WORD_START); + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_WORD_START); if (!tok) { return BSHELL_ERR_NO_MEMORY; } @@ -105,9 +105,9 @@ static enum bshell_status word_begin(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status word_end(struct lex_ctx *ctx) +static enum bshell_status word_end(struct bshell_lex_ctx *ctx) { - struct lex_token *tok = lex_token_create(TOK_WORD_END); + struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_WORD_END); if (!tok) { return BSHELL_ERR_NO_MEMORY; } @@ -116,7 +116,7 @@ static enum bshell_status word_end(struct lex_ctx *ctx) return BSHELL_SUCCESS; } -static enum bshell_status word_pump_token(struct lex_ctx *ctx) +static enum bshell_status word_pump_token(struct bshell_lex_ctx *ctx) { fx_wchar c = peek_char(ctx); @@ -125,7 +125,7 @@ static enum bshell_status word_pump_token(struct lex_ctx *ctx) return BSHELL_SUCCESS; } - if (char_has_flags(ctx, c, LEX_TOKEN_TERMINATES_WORD)) { + if (char_has_flags(ctx, c, BSHELL_LEX_TOKEN_TERMINATES_WORD)) { lex_state_pop(ctx); return BSHELL_SUCCESS; } @@ -138,23 +138,23 @@ static enum bshell_status word_pump_token(struct lex_ctx *ctx) } static const unsigned int symbols[] = { - SYM_AMPERSAND, - SYM_HASH, - SYM_DOLLAR, - SYM_DOLLAR_LEFT_PAREN, - SYM_DOLLAR_LEFT_BRACE, - SYM_PIPE, - SYM_COMMA, - SYM_SEMICOLON, - SYM_LEFT_BRACE, - SYM_RIGHT_BRACE, - SYM_LEFT_PAREN, - SYM_RIGHT_PAREN, - SYM_NONE, + BSHELL_SYM_AMPERSAND, + BSHELL_SYM_HASH, + BSHELL_SYM_DOLLAR, + BSHELL_SYM_DOLLAR_LEFT_PAREN, + BSHELL_SYM_DOLLAR_LEFT_BRACE, + BSHELL_SYM_PIPE, + BSHELL_SYM_COMMA, + BSHELL_SYM_SEMICOLON, + BSHELL_SYM_LEFT_BRACE, + BSHELL_SYM_RIGHT_BRACE, + BSHELL_SYM_LEFT_PAREN, + BSHELL_SYM_RIGHT_PAREN, + BSHELL_SYM_NONE, }; -const struct lex_state_type lex_word_state = { - .s_id = LEX_STATE_WORD, +const struct bshell_lex_state_type lex_word_state = { + .s_id = BSHELL_LEX_STATE_WORD, .s_begin = word_begin, .s_end = word_end, .s_pump_token = word_pump_token, diff --git a/bshell.runtime/parse/parse.c b/bshell.runtime/parse/parse.c new file mode 100644 index 0000000..642bc45 --- /dev/null +++ b/bshell.runtime/parse/parse.c @@ -0,0 +1,55 @@ +#include "syntax.h" + +#include +#include +#include +#include +#include +#include + +enum bshell_status bshell_parse_ctx_init(struct bshell_parse_ctx *ctx, struct bshell_lex_ctx *src) +{ + memset(ctx, 0x0, sizeof *ctx); + + ctx->p_src = src; + + return BSHELL_SUCCESS; +} + +void bshell_parse_ctx_cleanup(struct bshell_parse_ctx *ctx) +{ +} + +struct bshell_ast_node *bshell_parse_ctx_read_node(struct bshell_parse_ctx *ctx) +{ + parse_symbol(ctx, BSHELL_SYM_SEMICOLON); + parse_linefeed(ctx); + + struct bshell_ast_node *result = NULL; + bool ok = parse_statement(ctx, &result); + + return ok ? result : NULL; +} + +void report_error(struct bshell_parse_ctx *ctx, const char *format, ...) +{ + ctx->p_status = BSHELL_ERR_BAD_SYNTAX; + fprintf(stderr, "PARSE: "); + + va_list arg; + va_start(arg, format); + vfprintf(stderr, format, arg); + va_end(arg); + + fprintf(stderr, "\n"); + + struct bshell_lex_token *tok = peek_token(ctx); + fprintf(stderr, " peek_token = "); +#if 0 + if (tok) { + print_bshell_lex_token(tok); + } else { + fprintf(stderr, " EOF\n"); + } +#endif +} diff --git a/bshell.runtime/parse/syntax.h b/bshell.runtime/parse/syntax.h new file mode 100644 index 0000000..c4d07c4 --- /dev/null +++ b/bshell.runtime/parse/syntax.h @@ -0,0 +1,73 @@ +#ifndef PARSE_SYNTAX_H_ +#define PARSE_SYNTAX_H_ + +#include +#include +#include +#include +#include +#include +#include + +extern void report_error(struct bshell_parse_ctx *ctx, const char *format, ...); + +extern struct bshell_lex_token *peek_token(struct bshell_parse_ctx *ctx); +extern enum bshell_lex_token_type peek_token_type(struct bshell_parse_ctx *ctx); +extern enum bshell_lex_keyword peek_unknown_keyword(struct bshell_parse_ctx *ctx); +extern enum bshell_lex_symbol peek_unknown_symbol(struct bshell_parse_ctx *ctx); + +extern struct bshell_lex_token *claim_token(struct bshell_parse_ctx *ctx); +extern void discard_token(struct bshell_parse_ctx *ctx); + +extern bool peek_linefeed(struct bshell_parse_ctx *ctx); +extern bool peek_symbol(struct bshell_parse_ctx *ctx, enum bshell_lex_symbol sym); +extern bool peek_word(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out); +extern bool peek_int(struct bshell_parse_ctx *ctx); + +extern bool parse_linefeed(struct bshell_parse_ctx *ctx); +extern bool parse_symbol(struct bshell_parse_ctx *ctx, enum bshell_lex_symbol sym); +extern bool parse_keyword(struct bshell_parse_ctx *ctx, enum bshell_lex_keyword kw); +extern bool parse_word(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out); +extern bool parse_var(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out); +extern bool parse_flag(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out); + +extern bool peek_arith_expr(struct bshell_parse_ctx *ctx); +extern bool parse_arith_value( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node **out); +extern bool parse_arith_expr( + struct bshell_parse_ctx *ctx, + enum bshell_operator_precedence minimum_precedence, + struct bshell_ast_node **out); + +extern bool peek_keyword_expr(struct bshell_parse_ctx *ctx); +extern bool parse_keyword_expr( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node **out); + +extern bool parse_if(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); +extern bool parse_func(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); + +extern bool parse_fstring(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); + +extern bool parse_block(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); + +extern bool peek_command(struct bshell_parse_ctx *ctx); +extern bool parse_pipeline( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node *first_item, + struct bshell_ast_node **out); +extern bool parse_command(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); +extern bool parse_cmdcall(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); +extern bool parse_redirect(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); + +extern bool parse_expr(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out); +extern bool peek_statement(struct bshell_parse_ctx *ctx); +extern bool parse_statement( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node **out); +extern bool parse_statement_list( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node **out); + +#endif diff --git a/bshell/parse/syntax/arith.c b/bshell.runtime/parse/syntax/arith.c similarity index 51% rename from bshell/parse/syntax/arith.c rename to bshell.runtime/parse/syntax/arith.c index c84f487..a1b2d9d 100644 --- a/bshell/parse/syntax/arith.c +++ b/bshell.runtime/parse/syntax/arith.c @@ -1,7 +1,6 @@ -#include "../../debug.h" -#include "../../operator.h" #include "../syntax.h" +#include #include enum expr_component { @@ -11,24 +10,24 @@ enum expr_component { EXPR_C_UNARY_OP, }; -struct expr_parse_ctx { - fx_queue expr_operator_stack, expr_out_queue; +struct expr_bshell_parse_ctx { + fx_queue expr_bshell_operator_stack, expr_out_queue; enum expr_component expr_prev; unsigned int expr_prev_symbol; - enum operator_precedence expr_minimum_precedence; + enum bshell_operator_precedence expr_minimum_precedence; bool expr_done, expr_fail; }; -static bool op_node_is_complete(struct op_ast_node *node) +static bool op_node_is_complete(struct bshell_op_ast_node *node) { if (!node->n_op) { return false; } switch (node->n_op->op_arity) { - case OPA_UNARY: + case BSHELL_OPA_UNARY: return node->n_right != NULL; - case OPA_BINARY: + case BSHELL_OPA_BINARY: return (node->n_left != NULL && node->n_right != NULL); default: return false; @@ -36,19 +35,19 @@ static bool op_node_is_complete(struct op_ast_node *node) } static bool finalise_expr( - struct expr_parse_ctx *ctx, - struct ast_node **out, - enum operator_precedence minimum_precedence) + struct expr_bshell_parse_ctx *ctx, + struct bshell_ast_node **out, + enum bshell_operator_precedence minimum_precedence) { fx_queue_entry *entry = NULL; while (true) { - entry = fx_queue_pop_back(&ctx->expr_operator_stack); + entry = fx_queue_pop_back(&ctx->expr_bshell_operator_stack); if (!entry) { break; } - struct op_ast_node *node = fx_unbox( - struct op_ast_node, + struct bshell_op_ast_node *node = fx_unbox( + struct bshell_op_ast_node, entry, n_base.n_entry); if (!node) { @@ -56,12 +55,14 @@ static bool finalise_expr( return false; } - const struct operator_info *op = node->n_op; + const struct bshell_operator_info *op = node->n_op; /* if we aren't processing operators below a certain precedence * then leave them on the stack and stop here. */ if (op->op_precedence < minimum_precedence) { - fx_queue_push_back(&ctx->expr_operator_stack, entry); + fx_queue_push_back( + &ctx->expr_bshell_operator_stack, + entry); break; } @@ -74,24 +75,23 @@ static bool finalise_expr( int i = 0; while (entry) { - struct ast_node *item = fx_unbox( - struct ast_node, - entry, - n_entry); + struct bshell_ast_node *item + = fx_unbox(struct bshell_ast_node, entry, n_entry); fx_queue_entry *next = fx_queue_next(entry); fx_queue_delete(&ctx->expr_out_queue, entry); /* if the node is an operand, just push it to a * temporary queue and come back to it later. */ - if (item->n_type != AST_OP) { + if (item->n_type != BSHELL_AST_OP) { /* operand */ fx_queue_push_back(&q, &item->n_entry); goto next; } - const struct operator_info *op = NULL; + const struct bshell_operator_info *op = NULL; - struct op_ast_node *op_node = (struct op_ast_node *)item; + struct bshell_op_ast_node *op_node + = (struct bshell_op_ast_node *)item; /* if an operator node is already complete (i.e. it * already has all the operands it needs, it can be @@ -105,33 +105,35 @@ static bool finalise_expr( * queue... */ op = op_node->n_op; tmp = fx_queue_pop_back(&q); - op_node->n_right = fx_unbox(struct ast_node, tmp, n_entry); + op_node->n_right + = fx_unbox(struct bshell_ast_node, tmp, n_entry); if (op_node->n_right) { - op_node->n_right->n_parent = (struct ast_node *)op_node; + op_node->n_right->n_parent + = (struct bshell_ast_node *)op_node; #if 0 - ast_node_extend_bounds_recursive( - (struct ivy_ast_node *)op_node, - (struct ivy_ast_node *)tmp); + bshell_ast_node_extend_bounds_recursive( + (struct ivy_bshell_ast_node *)op_node, + (struct ivy_bshell_ast_node *)tmp); #endif } - if (op->op_arity == OPA_BINARY) { + if (op->op_arity == BSHELL_OPA_BINARY) { tmp = fx_queue_pop_back(&q); op_node->n_left = fx_unbox( - struct ast_node, + struct bshell_ast_node, tmp, n_entry); if (op_node->n_left) { - op_node->n_left->n_parent = (struct ast_node *) - op_node; + op_node->n_left->n_parent + = (struct bshell_ast_node *)op_node; #if 0 - ast_node_extend_bounds_recursive( - (struct ivy_ast_node *)op_node, - (struct ivy_ast_node *)tmp); + bshell_ast_node_extend_bounds_recursive( + (struct ivy_bshell_ast_node *)op_node, + (struct ivy_bshell_ast_node *)tmp); #endif } } @@ -154,7 +156,7 @@ static bool finalise_expr( * their operands have just been moved to the temporary operand stack * used above. move them back to the parser state's output queue here * so they can be used later. */ - entry = fx_queue_first(&ctx->expr_operator_stack); + entry = fx_queue_first(&ctx->expr_bshell_operator_stack); while (entry) { fx_queue_entry *entry2 = fx_queue_pop_front(&q); if (!entry2) { @@ -168,48 +170,48 @@ static bool finalise_expr( #if 0 debug_printf("** after de-linearisation:\n"); print_expr_queues(state); - ivy_ast_node_print(*expr_tree); + ivy_bshell_ast_node_print(*expr_tree); debug_printf("------\n"); #endif /* the final node remaining on the temp operand stack is the * root node of the new expression tree */ tmp = fx_queue_pop_back(&q); - *out = fx_unbox(struct ast_node, tmp, n_entry); + *out = fx_unbox(struct bshell_ast_node, tmp, n_entry); return true; } -bool peek_arith_expr(struct parse_ctx *ctx) +bool peek_arith_expr(struct bshell_parse_ctx *ctx) { switch (peek_token_type(ctx)) { - case TOK_SYMBOL: - return operator_get_by_token(peek_unknown_symbol(ctx)); - case TOK_INT: - case TOK_DOUBLE: - case TOK_STRING: - case TOK_VAR: - case TOK_STR_START: - case TOK_OPERATOR: + case BSHELL_TOK_SYMBOL: + return bshell_operator_get_by_token(peek_unknown_symbol(ctx)); + case BSHELL_TOK_INT: + case BSHELL_TOK_DOUBLE: + case BSHELL_TOK_STRING: + case BSHELL_TOK_VAR: + case BSHELL_TOK_STR_START: + case BSHELL_TOK_OPERATOR: return true; default: return false; } } -static bool parse_subexpr(struct parse_ctx *ctx, struct ast_node **out) +static bool parse_subexpr(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - if (!parse_symbol(ctx, SYM_LEFT_PAREN)) { + if (!parse_symbol(ctx, BSHELL_SYM_LEFT_PAREN)) { report_error(ctx, "expected `(`"); } - struct ast_node *v = NULL; + struct bshell_ast_node *v = NULL; if (!parse_expr(ctx, &v)) { report_error(ctx, "error while parsing parenthesis expression"); return false; } - if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) { + if (!parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { report_error(ctx, "expected `)` after parenthesis expression"); return false; } @@ -218,26 +220,28 @@ static bool parse_subexpr(struct parse_ctx *ctx, struct ast_node **out) return true; } -static bool parse_stmt_block(struct parse_ctx *ctx, struct ast_node **out) +static bool parse_stmt_block( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node **out) { - if (!parse_symbol(ctx, SYM_DOLLAR_LEFT_PAREN)) { + if (!parse_symbol(ctx, BSHELL_SYM_DOLLAR_LEFT_PAREN)) { report_error(ctx, "expected `$(`"); return false; } - if (parse_symbol(ctx, SYM_RIGHT_PAREN)) { - *out = ast_node_create(AST_NULL); + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { + *out = bshell_ast_node_create(BSHELL_AST_NULL); return true; } - struct ast_node *v = NULL; + struct bshell_ast_node *v = NULL; if (!parse_statement_list(ctx, &v)) { return false; } - if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) { + if (!parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { report_error(ctx, "expected ')' after subexpression"); - ast_node_destroy(v); + bshell_ast_node_destroy(v); return false; } @@ -245,17 +249,18 @@ static bool parse_stmt_block(struct parse_ctx *ctx, struct ast_node **out) return true; } -static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out) +static bool parse_hashtable(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - if (!parse_symbol(ctx, SYM_AT_LEFT_BRACE)) { + if (!parse_symbol(ctx, BSHELL_SYM_AT_LEFT_BRACE)) { report_error(ctx, "expected `@{`"); return false; } parse_linefeed(ctx); - struct hashtable_ast_node *table = (struct hashtable_ast_node *) - ast_node_create(AST_HASHTABLE); + struct bshell_hashtable_ast_node *table + = (struct bshell_hashtable_ast_node *)bshell_ast_node_create( + BSHELL_AST_HASHTABLE); if (!table) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; @@ -264,39 +269,41 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out) size_t nr_items = 0; bool ok = true; while (ok) { - if (parse_symbol(ctx, SYM_RIGHT_BRACE)) { + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_BRACE)) { break; } parse_linefeed(ctx); - struct hashtable_item_ast_node *item = (struct - hashtable_item_ast_node - *) - ast_node_create(AST_HASHTABLE_ITEM); - struct lex_token *tok = NULL; + struct bshell_hashtable_item_ast_node *item + = (struct bshell_hashtable_item_ast_node *) + bshell_ast_node_create( + BSHELL_AST_HASHTABLE_ITEM); + struct bshell_lex_token *tok = NULL; if (parse_word(ctx, &tok)) { - struct string_ast_node *v = (struct string_ast_node *) - ast_node_create(AST_STRING); + struct bshell_string_ast_node *v + = (struct bshell_string_ast_node *) + bshell_ast_node_create( + BSHELL_AST_STRING); v->n_value = tok; - item->n_key = (struct ast_node *)v; + item->n_key = (struct bshell_ast_node *)v; } else if (!parse_arith_value(ctx, &item->n_key)) { report_error(ctx, "failed to parse hashtable key"); - ast_node_destroy((struct ast_node *)item); + bshell_ast_node_destroy((struct bshell_ast_node *)item); ok = false; break; } - if (!parse_symbol(ctx, SYM_EQUAL)) { + if (!parse_symbol(ctx, BSHELL_SYM_EQUAL)) { report_error(ctx, "expected `=` after hashtable key"); - ast_node_destroy((struct ast_node *)item); + bshell_ast_node_destroy((struct bshell_ast_node *)item); ok = false; break; } if (!parse_expr(ctx, &item->n_value)) { report_error(ctx, "failed to parse hashtable value"); - ast_node_destroy((struct ast_node *)item); + bshell_ast_node_destroy((struct bshell_ast_node *)item); ok = false; break; } @@ -304,11 +311,12 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out) fx_queue_push_back(&table->n_items, &item->n_base.n_entry); nr_items++; - if (parse_symbol(ctx, SYM_RIGHT_BRACE)) { + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_BRACE)) { break; } - if (!parse_linefeed(ctx) && !parse_symbol(ctx, SYM_SEMICOLON)) { + if (!parse_linefeed(ctx) + && !parse_symbol(ctx, BSHELL_SYM_SEMICOLON)) { report_error( ctx, "expected `;`, `}`, or linefeed after " @@ -319,23 +327,24 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out) } if (!ok) { - ast_node_destroy((struct ast_node *)table); + bshell_ast_node_destroy((struct bshell_ast_node *)table); return false; } - *out = (struct ast_node *)table; + *out = (struct bshell_ast_node *)table; return true; } -static bool parse_array(struct parse_ctx *ctx, struct ast_node **out) +static bool parse_array(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - if (!parse_symbol(ctx, SYM_AT_LEFT_PAREN)) { + if (!parse_symbol(ctx, BSHELL_SYM_AT_LEFT_PAREN)) { report_error(ctx, "expected `@(`"); return false; } - struct array_ast_node *array = (struct array_ast_node *)ast_node_create( - AST_ARRAY); + struct bshell_array_ast_node *array + = (struct bshell_array_ast_node *)bshell_ast_node_create( + BSHELL_AST_ARRAY); if (!array) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; @@ -344,18 +353,18 @@ static bool parse_array(struct parse_ctx *ctx, struct ast_node **out) size_t nr_items = 0; bool ok = true; while (ok) { - if (parse_symbol(ctx, SYM_RIGHT_PAREN)) { + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { break; } - if (nr_items && !parse_symbol(ctx, SYM_COMMA)) { + if (nr_items && !parse_symbol(ctx, BSHELL_SYM_COMMA)) { report_error( ctx, "expected `,` or `)` after array value"); ok = false; } - struct ast_node *item = NULL; + struct bshell_ast_node *item = NULL; if (!parse_arith_value(ctx, &item)) { report_error(ctx, "failed to parse array item"); ok = false; @@ -367,24 +376,25 @@ static bool parse_array(struct parse_ctx *ctx, struct ast_node **out) } if (!ok) { - ast_node_destroy((struct ast_node *)array); + bshell_ast_node_destroy((struct bshell_ast_node *)array); return false; } - *out = (struct ast_node *)array; + *out = (struct bshell_ast_node *)array; return true; } -bool parse_fstring(struct parse_ctx *ctx, struct ast_node **out) +bool parse_fstring(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - if (peek_token_type(ctx) != TOK_STR_START) { + if (peek_token_type(ctx) != BSHELL_TOK_STR_START) { return false; } discard_token(ctx); - struct fstring_ast_node *fstring = (struct fstring_ast_node *) - ast_node_create(AST_FSTRING); + struct bshell_fstring_ast_node *fstring + = (struct bshell_fstring_ast_node *)bshell_ast_node_create( + BSHELL_AST_FSTRING); if (!fstring) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; @@ -392,12 +402,12 @@ bool parse_fstring(struct parse_ctx *ctx, struct ast_node **out) bool ok = true; while (ok) { - if (peek_token_type(ctx) == TOK_STR_END) { + if (peek_token_type(ctx) == BSHELL_TOK_STR_END) { discard_token(ctx); break; } - struct ast_node *item = NULL; + struct bshell_ast_node *item = NULL; if (!parse_arith_value(ctx, &item)) { ok = false; break; @@ -407,66 +417,71 @@ bool parse_fstring(struct parse_ctx *ctx, struct ast_node **out) } if (!ok) { - ast_node_destroy((struct ast_node *)fstring); + bshell_ast_node_destroy((struct bshell_ast_node *)fstring); fstring = NULL; } - *out = (struct ast_node *)fstring; + *out = (struct bshell_ast_node *)fstring; return ok; } -bool parse_arith_value(struct parse_ctx *ctx, struct ast_node **out) +bool parse_arith_value(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); switch (tok->tok_type) { - case TOK_INT: { - struct int_ast_node *v = (struct int_ast_node *)ast_node_create( - AST_INT); + case BSHELL_TOK_INT: { + struct bshell_int_ast_node *v + = (struct bshell_int_ast_node *)bshell_ast_node_create( + BSHELL_AST_INT); v->n_value = claim_token(ctx); - *out = (struct ast_node *)v; + *out = (struct bshell_ast_node *)v; return true; } - case TOK_DOUBLE: { - struct double_ast_node *v = (struct double_ast_node *) - ast_node_create(AST_DOUBLE); + case BSHELL_TOK_DOUBLE: { + struct bshell_double_ast_node *v + = (struct bshell_double_ast_node *) + bshell_ast_node_create(BSHELL_AST_DOUBLE); v->n_value = claim_token(ctx); - *out = (struct ast_node *)v; + *out = (struct bshell_ast_node *)v; return true; } - case TOK_STRING: { - struct string_ast_node *v = (struct string_ast_node *) - ast_node_create(AST_STRING); + case BSHELL_TOK_STRING: { + struct bshell_string_ast_node *v + = (struct bshell_string_ast_node *) + bshell_ast_node_create(BSHELL_AST_STRING); v->n_value = claim_token(ctx); - *out = (struct ast_node *)v; + *out = (struct bshell_ast_node *)v; return true; } - case TOK_WORD: { - struct word_ast_node *v = (struct word_ast_node *) - ast_node_create(AST_WORD); + case BSHELL_TOK_WORD: { + struct bshell_word_ast_node *v + = (struct bshell_word_ast_node *)bshell_ast_node_create( + BSHELL_AST_WORD); v->n_value = claim_token(ctx); - *out = (struct ast_node *)v; + *out = (struct bshell_ast_node *)v; return true; } - case TOK_VAR: { - struct var_ast_node *v = (struct var_ast_node *)ast_node_create( - AST_VAR); + case BSHELL_TOK_VAR: { + struct bshell_var_ast_node *v + = (struct bshell_var_ast_node *)bshell_ast_node_create( + BSHELL_AST_VAR); v->n_ident = claim_token(ctx); - *out = (struct ast_node *)v; + *out = (struct bshell_ast_node *)v; return true; } - case TOK_STR_START: + case BSHELL_TOK_STR_START: return parse_fstring(ctx, out); - case TOK_SYMBOL: + case BSHELL_TOK_SYMBOL: switch (tok->tok_symbol) { - case SYM_LEFT_PAREN: + case BSHELL_SYM_LEFT_PAREN: return parse_subexpr(ctx, out); - case SYM_DOLLAR_LEFT_PAREN: + case BSHELL_SYM_DOLLAR_LEFT_PAREN: return parse_stmt_block(ctx, out); - case SYM_AT_LEFT_BRACE: + case BSHELL_SYM_AT_LEFT_BRACE: return parse_hashtable(ctx, out); - case SYM_AT_LEFT_PAREN: + case BSHELL_SYM_AT_LEFT_PAREN: return parse_array(ctx, out); - case SYM_LEFT_BRACE: + case BSHELL_SYM_LEFT_BRACE: return parse_block(ctx, out); default: report_error(ctx, "token is not a valid operand"); @@ -479,7 +494,7 @@ bool parse_arith_value(struct parse_ctx *ctx, struct ast_node **out) } } -static bool parse_operand(struct parse_ctx *ctx, struct expr_parse_ctx *expr) +static bool parse_operand(struct bshell_parse_ctx *ctx, struct expr_bshell_parse_ctx *expr) { if (expr->expr_prev == EXPR_C_OPERAND) { report_error(ctx, "encountered two operands in a row"); @@ -488,7 +503,7 @@ static bool parse_operand(struct parse_ctx *ctx, struct expr_parse_ctx *expr) expr->expr_prev = EXPR_C_OPERAND; - struct ast_node *v = NULL; + struct bshell_ast_node *v = NULL; if (!parse_arith_value(ctx, &v)) { return false; } @@ -497,30 +512,30 @@ static bool parse_operand(struct parse_ctx *ctx, struct expr_parse_ctx *expr) return true; } -void arith_push_operator(struct expr_parse_ctx *state, struct op_ast_node *node) +void arith_push_operator( + struct expr_bshell_parse_ctx *state, + struct bshell_op_ast_node *node) { - const struct operator_info *op = node->n_op; + const struct bshell_operator_info *op = node->n_op; if (!op) { return; } while (true) { - fx_queue_entry *top = fx_queue_last( - &state->expr_operator_stack); + fx_queue_entry *top + = fx_queue_last(&state->expr_bshell_operator_stack); if (!top) { break; } - struct ast_node *top_node = fx_unbox( - struct ast_node, - top, - n_entry); - const struct operator_info *top_op = NULL; + struct bshell_ast_node *top_node + = fx_unbox(struct bshell_ast_node, top, n_entry); + const struct bshell_operator_info *top_op = NULL; switch (top_node->n_type) { - case AST_OP: { - struct op_ast_node *op_node = (struct op_ast_node *) - top_node; + case BSHELL_AST_OP: { + struct bshell_op_ast_node *op_node + = (struct bshell_op_ast_node *)top_node; top_op = op_node->n_op; break; } @@ -530,38 +545,40 @@ void arith_push_operator(struct expr_parse_ctx *state, struct op_ast_node *node) if (top_op->op_precedence < op->op_precedence || (top_op->op_precedence == op->op_precedence - && op->op_associativity != ASSOCIATIVITY_LEFT)) { + && op->op_associativity != BSHELL_ASSOCIATIVITY_LEFT)) { break; } - fx_queue_delete(&state->expr_operator_stack, top); + fx_queue_delete(&state->expr_bshell_operator_stack, top); fx_queue_push_back(&state->expr_out_queue, top); } - fx_queue_push_back(&state->expr_operator_stack, &node->n_base.n_entry); + fx_queue_push_back( + &state->expr_bshell_operator_stack, + &node->n_base.n_entry); } static bool parse_unary_operator( - struct parse_ctx *ctx, - struct expr_parse_ctx *expr) + struct bshell_parse_ctx *ctx, + struct expr_bshell_parse_ctx *expr) { - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); - const struct operator_info *op = NULL; + const struct bshell_operator_info *op = NULL; switch (tok->tok_type) { - case TOK_SYMBOL: - op = operator_get_by_token(tok->tok_symbol); + case BSHELL_TOK_SYMBOL: + op = bshell_operator_get_by_token(tok->tok_symbol); break; - case TOK_OPERATOR: + case BSHELL_TOK_OPERATOR: switch (tok->tok_operator) { - case TKOP_SPLIT: - op = operator_get_by_id(OP_USPLIT); + case BSHELL_TKOP_SPLIT: + op = bshell_operator_get_by_id(BSHELL_OP_USPLIT); break; - case TKOP_JOIN: - op = operator_get_by_id(OP_USPLIT); + case BSHELL_TKOP_JOIN: + op = bshell_operator_get_by_id(BSHELL_OP_USPLIT); break; default: - op = operator_get_by_token(tok->tok_operator); + op = bshell_operator_get_by_token(tok->tok_operator); break; } break; @@ -570,7 +587,7 @@ static bool parse_unary_operator( } if (expr->expr_prev == EXPR_C_OPERAND - && op->op_location == OPL_PREFIX) { + && op->op_location == BSHELL_OPL_PREFIX) { report_error( ctx, "unexpected operand before unary " @@ -590,8 +607,9 @@ static bool parse_unary_operator( expr->expr_prev = EXPR_C_BINARY_OP; - struct op_ast_node *op_node = (struct op_ast_node *)ast_node_create( - AST_OP); + struct bshell_op_ast_node *op_node + = (struct bshell_op_ast_node *)bshell_ast_node_create( + BSHELL_AST_OP); if (!op_node) { return false; } @@ -603,26 +621,26 @@ static bool parse_unary_operator( } static bool parse_binary_operator( - struct parse_ctx *ctx, - struct expr_parse_ctx *expr) + struct bshell_parse_ctx *ctx, + struct expr_bshell_parse_ctx *expr) { - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); - const struct operator_info *op = NULL; + const struct bshell_operator_info *op = NULL; switch (tok->tok_type) { - case TOK_SYMBOL: - op = operator_get_by_token(tok->tok_symbol); + case BSHELL_TOK_SYMBOL: + op = bshell_operator_get_by_token(tok->tok_symbol); break; - case TOK_OPERATOR: + case BSHELL_TOK_OPERATOR: switch (tok->tok_operator) { - case TKOP_SPLIT: - op = operator_get_by_id(OP_BSPLIT); + case BSHELL_TKOP_SPLIT: + op = bshell_operator_get_by_id(BSHELL_OP_BSPLIT); break; - case TKOP_JOIN: - op = operator_get_by_id(OP_BJOIN); + case BSHELL_TKOP_JOIN: + op = bshell_operator_get_by_id(BSHELL_OP_BJOIN); break; default: - op = operator_get_by_token(tok->tok_operator); + op = bshell_operator_get_by_token(tok->tok_operator); break; } default: @@ -641,7 +659,7 @@ static bool parse_binary_operator( if (expr->expr_prev != EXPR_C_OPERAND) { switch (op->op_id) { - case OP_PAREN: + case BSHELL_OP_PAREN: break; default: report_error( @@ -654,8 +672,9 @@ static bool parse_binary_operator( expr->expr_prev = EXPR_C_BINARY_OP; - struct op_ast_node *op_node = (struct op_ast_node *)ast_node_create( - AST_OP); + struct bshell_op_ast_node *op_node + = (struct bshell_op_ast_node *)bshell_ast_node_create( + BSHELL_AST_OP); if (!op_node) { return false; } @@ -666,29 +685,30 @@ static bool parse_binary_operator( return true; } -static bool parse_call(struct parse_ctx *ctx, struct expr_parse_ctx *expr) +static bool parse_call(struct bshell_parse_ctx *ctx, struct expr_bshell_parse_ctx *expr) { return false; } -static bool parse_comma(struct parse_ctx *ctx, struct expr_parse_ctx *expr) +static bool parse_comma(struct bshell_parse_ctx *ctx, struct expr_bshell_parse_ctx *expr) { - if (PRECEDENCE_ARRAY < expr->expr_minimum_precedence) { + if (BSHELL_PRECEDENCE_ARRAY < expr->expr_minimum_precedence) { expr->expr_done = true; return true; } - struct ast_node *item = NULL; - if (!finalise_expr(expr, &item, PRECEDENCE_ARRAY)) { + struct bshell_ast_node *item = NULL; + if (!finalise_expr(expr, &item, BSHELL_PRECEDENCE_ARRAY)) { report_error(ctx, "failed to collect first array item."); return false; } - struct array_ast_node *array = (struct array_ast_node *)ast_node_create( - AST_ARRAY); + struct bshell_array_ast_node *array + = (struct bshell_array_ast_node *)bshell_ast_node_create( + BSHELL_AST_ARRAY); if (!array) { ctx->p_status = BSHELL_ERR_NO_MEMORY; - ast_node_destroy(item); + bshell_ast_node_destroy(item); return false; } @@ -697,13 +717,17 @@ static bool parse_comma(struct parse_ctx *ctx, struct expr_parse_ctx *expr) } while (1) { - if (!parse_symbol(ctx, SYM_COMMA)) { + if (!parse_symbol(ctx, BSHELL_SYM_COMMA)) { break; } - if (!parse_arith_expr(ctx, PRECEDENCE_ARRAY + 1, &item)) { + if (!parse_arith_expr( + ctx, + BSHELL_PRECEDENCE_ARRAY + 1, + &item)) { report_error(ctx, "failed to parse array item."); - ast_node_destroy((struct ast_node *)array); + bshell_ast_node_destroy( + (struct bshell_ast_node *)array); return false; } @@ -716,41 +740,16 @@ static bool parse_comma(struct parse_ctx *ctx, struct expr_parse_ctx *expr) return true; } -static void dump_expr_ctx(struct expr_parse_ctx *expr) -{ - printf("op stack:\n"); - fx_queue_entry *entry = fx_queue_first(&expr->expr_operator_stack); - while (entry) { - struct ast_node *node = fx_unbox( - struct ast_node, - entry, - n_entry); - print_ast_node(node); - entry = fx_queue_next(entry); - } - - printf("out queue:\n"); - entry = fx_queue_first(&expr->expr_out_queue); - while (entry) { - struct ast_node *node = fx_unbox( - struct ast_node, - entry, - n_entry); - print_ast_node(node); - entry = fx_queue_next(entry); - } -} - -static bool can_use_command(struct expr_parse_ctx *ctx) +static bool can_use_command(struct expr_bshell_parse_ctx *ctx) { switch (ctx->expr_prev_symbol) { - case TOK_NONE: - case SYM_EQUAL: - case SYM_PLUS_EQUAL: - case SYM_HYPHEN_EQUAL: - case SYM_ASTERISK_EQUAL: - case SYM_FORWARD_SLASH_EQUAL: - case SYM_PERCENT_EQUAL: + case BSHELL_TOK_NONE: + case BSHELL_SYM_EQUAL: + case BSHELL_SYM_PLUS_EQUAL: + case BSHELL_SYM_HYPHEN_EQUAL: + case BSHELL_SYM_ASTERISK_EQUAL: + case BSHELL_SYM_FORWARD_SLASH_EQUAL: + case BSHELL_SYM_PERCENT_EQUAL: return true; default: return false; @@ -758,33 +757,33 @@ static bool can_use_command(struct expr_parse_ctx *ctx) } bool parse_arith_expr( - struct parse_ctx *ctx, - enum operator_precedence minimum_precedence, - struct ast_node **out) + struct bshell_parse_ctx *ctx, + enum bshell_operator_precedence minimum_precedence, + struct bshell_ast_node **out) { - struct expr_parse_ctx expr = { + struct expr_bshell_parse_ctx expr = { .expr_minimum_precedence = minimum_precedence, }; while (!expr.expr_fail && !expr.expr_done) { - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); if (!tok) { break; } switch (tok->tok_type) { - case TOK_LINEFEED: + case BSHELL_TOK_LINEFEED: expr.expr_prev_symbol = tok->tok_type; expr.expr_done = true; break; - case TOK_WORD: { + case BSHELL_TOK_WORD: { if (!can_use_command(&expr)) { expr.expr_fail = !parse_operand(ctx, &expr); break; } expr.expr_prev_symbol = tok->tok_type; - struct ast_node *value = NULL; + struct bshell_ast_node *value = NULL; if (!parse_command(ctx, &value)) { expr.expr_fail = true; break; @@ -796,22 +795,22 @@ bool parse_arith_expr( break; } - case TOK_VAR: - case TOK_INT: - case TOK_DOUBLE: - case TOK_STRING: - case TOK_STR_START: + case BSHELL_TOK_VAR: + case BSHELL_TOK_INT: + case BSHELL_TOK_DOUBLE: + case BSHELL_TOK_STRING: + case BSHELL_TOK_STR_START: expr.expr_prev_symbol = tok->tok_type; expr.expr_fail = !parse_operand(ctx, &expr); expr.expr_prev_symbol = tok->tok_type; break; - case TOK_OPERATOR: + case BSHELL_TOK_OPERATOR: expr.expr_prev_symbol = tok->tok_operator; switch (tok->tok_operator) { /* these two are special cases, as they are both * unary AND binary operators */ - case TKOP_SPLIT: - case TKOP_JOIN: + case BSHELL_TKOP_SPLIT: + case BSHELL_TKOP_JOIN: if (expr.expr_prev == EXPR_C_OPERAND) { expr.expr_fail = !parse_binary_operator( ctx, @@ -823,41 +822,39 @@ bool parse_arith_expr( } break; - case TKOP_BNOT: - case TKOP_NOT: - expr.expr_fail = !parse_unary_operator( - ctx, - &expr); + case BSHELL_TKOP_BNOT: + case BSHELL_TKOP_NOT: + expr.expr_fail + = !parse_unary_operator(ctx, &expr); break; default: - expr.expr_fail = !parse_binary_operator( - ctx, - &expr); + expr.expr_fail + = !parse_binary_operator(ctx, &expr); break; } expr.expr_prev_symbol = tok->tok_operator; break; - case TOK_SYMBOL: + case BSHELL_TOK_SYMBOL: expr.expr_prev_symbol = tok->tok_symbol; switch (tok->tok_symbol) { - case SYM_SEMICOLON: - case SYM_AMPERSAND: - case SYM_PIPE: - case SYM_RIGHT_PAREN: - case SYM_RIGHT_BRACE: - case SYM_RIGHT_BRACKET: + case BSHELL_SYM_SEMICOLON: + case BSHELL_SYM_AMPERSAND: + case BSHELL_SYM_PIPE: + case BSHELL_SYM_RIGHT_PAREN: + case BSHELL_SYM_RIGHT_BRACE: + case BSHELL_SYM_RIGHT_BRACKET: expr.expr_done = true; break; - case SYM_COMMA: + case BSHELL_SYM_COMMA: expr.expr_fail = !parse_comma(ctx, &expr); break; - case SYM_LEFT_PAREN: { + case BSHELL_SYM_LEFT_PAREN: { if (expr.expr_prev == EXPR_C_OPERAND) { return parse_call(ctx, &expr); } - struct ast_node *v = NULL; + struct bshell_ast_node *v = NULL; expr.expr_fail = !parse_subexpr(ctx, &v); if (expr.expr_fail) { break; @@ -869,17 +866,17 @@ bool parse_arith_expr( expr.expr_prev = EXPR_C_OPERAND; break; } - case SYM_DOLLAR_LEFT_PAREN: - case SYM_AT_LEFT_PAREN: - case SYM_AT_LEFT_BRACE: - case SYM_LEFT_BRACE: + case BSHELL_SYM_DOLLAR_LEFT_PAREN: + case BSHELL_SYM_AT_LEFT_PAREN: + case BSHELL_SYM_AT_LEFT_BRACE: + case BSHELL_SYM_LEFT_BRACE: expr.expr_fail = !parse_operand(ctx, &expr); break; default: { - const struct operator_info *op - = operator_get_by_token( + const struct bshell_operator_info *op + = bshell_operator_get_by_token( tok->tok_symbol); - if (op->op_arity == OPA_BINARY) { + if (op->op_arity == BSHELL_OPA_BINARY) { expr.expr_fail = !parse_binary_operator( ctx, &expr); @@ -908,15 +905,15 @@ bool parse_arith_expr( return false; } - struct ast_node *value = NULL; - if (!finalise_expr(&expr, &value, PRECEDENCE_ASSIGN)) { + struct bshell_ast_node *value = NULL; + if (!finalise_expr(&expr, &value, BSHELL_PRECEDENCE_ASSIGN)) { report_error(ctx, "failed to convert expression to AST"); /* TODO cleanup */ return false; } - if (PRECEDENCE_PIPELINE >= expr.expr_minimum_precedence) { - if (peek_symbol(ctx, SYM_PIPE)) { + if (BSHELL_PRECEDENCE_PIPELINE >= expr.expr_minimum_precedence) { + if (peek_symbol(ctx, BSHELL_SYM_PIPE)) { return parse_pipeline(ctx, value, out); } } diff --git a/bshell.runtime/parse/syntax/block.c b/bshell.runtime/parse/syntax/block.c new file mode 100644 index 0000000..613c8c4 --- /dev/null +++ b/bshell.runtime/parse/syntax/block.c @@ -0,0 +1,53 @@ +#include "../syntax.h" + +bool parse_block(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) +{ + if (!parse_symbol(ctx, BSHELL_SYM_LEFT_BRACE)) { + return false; + } + + parse_linefeed(ctx); + + struct bshell_block_ast_node *block + = (struct bshell_block_ast_node *)bshell_ast_node_create( + BSHELL_AST_BLOCK); + + bool ok = true; + while (1) { + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_BRACE)) { + break; + } + + parse_linefeed(ctx); + + struct bshell_ast_node *stmt = NULL; + if (!parse_statement(ctx, &stmt)) { + ok = false; + break; + } + + fx_queue_push_back(&block->n_statements, &stmt->n_entry); + + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_BRACE)) { + break; + } + + if (!parse_linefeed(ctx) + && !parse_symbol(ctx, BSHELL_SYM_SEMICOLON)) { + report_error( + ctx, + "expected `;`, `}`, or linefeed after " + "statement"); + ok = false; + break; + } + } + + if (!ok) { + bshell_ast_node_destroy((struct bshell_ast_node *)block); + block = NULL; + } + + *out = (struct bshell_ast_node *)block; + return true; +} diff --git a/bshell/parse/syntax/command.c b/bshell.runtime/parse/syntax/command.c similarity index 56% rename from bshell/parse/syntax/command.c rename to bshell.runtime/parse/syntax/command.c index 501a68b..a772ba5 100644 --- a/bshell/parse/syntax/command.c +++ b/bshell.runtime/parse/syntax/command.c @@ -1,18 +1,18 @@ -#include "../../debug.h" #include "../syntax.h" #include -static bool parse_fword(struct parse_ctx *ctx, struct ast_node **out) +static bool parse_fword(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - if (peek_token_type(ctx) != TOK_WORD_START) { + if (peek_token_type(ctx) != BSHELL_TOK_WORD_START) { return false; } discard_token(ctx); - struct fstring_ast_node *fstring - = (struct fstring_ast_node *)ast_node_create(AST_FSTRING); + struct bshell_fstring_ast_node *fstring + = (struct bshell_fstring_ast_node *)bshell_ast_node_create( + BSHELL_AST_FSTRING); if (!fstring) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; @@ -20,16 +20,16 @@ static bool parse_fword(struct parse_ctx *ctx, struct ast_node **out) bool ok = true; while (ok) { - if (peek_token_type(ctx) == TOK_WORD_END) { + if (peek_token_type(ctx) == BSHELL_TOK_WORD_END) { discard_token(ctx); break; } - struct ast_node *item = NULL; - if (peek_token_type(ctx) == TOK_WORD) { - struct word_ast_node *n - = (struct word_ast_node *)ast_node_create( - AST_WORD); + struct bshell_ast_node *item = NULL; + if (peek_token_type(ctx) == BSHELL_TOK_WORD) { + struct bshell_word_ast_node *n + = (struct bshell_word_ast_node *) + bshell_ast_node_create(BSHELL_AST_WORD); if (!n) { ctx->p_status = BSHELL_ERR_NO_MEMORY; ok = false; @@ -37,7 +37,7 @@ static bool parse_fword(struct parse_ctx *ctx, struct ast_node **out) } n->n_value = claim_token(ctx); - item = (struct ast_node *)n; + item = (struct bshell_ast_node *)n; } else { if (!parse_arith_value(ctx, &item)) { ok = false; @@ -49,93 +49,98 @@ static bool parse_fword(struct parse_ctx *ctx, struct ast_node **out) } if (!ok) { - ast_node_destroy((struct ast_node *)fstring); + bshell_ast_node_destroy((struct bshell_ast_node *)fstring); fstring = NULL; } - *out = (struct ast_node *)fstring; + *out = (struct bshell_ast_node *)fstring; return ok; return false; } -static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) +static bool parse_cmdcall_arg( + struct bshell_parse_ctx *ctx, + struct bshell_ast_node **out) { if (ctx->p_status != BSHELL_SUCCESS) { return false; } - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); if (!tok) { return false; } - struct ast_node *arg = NULL; + struct bshell_ast_node *arg = NULL; switch (tok->tok_type) { - case TOK_WORD_START: + case BSHELL_TOK_WORD_START: return parse_fword(ctx, out); - case TOK_STR_START: + case BSHELL_TOK_STR_START: return parse_fstring(ctx, out); - case TOK_WORD: { - struct word_ast_node *n - = (struct word_ast_node *)ast_node_create(AST_WORD); + case BSHELL_TOK_WORD: { + struct bshell_word_ast_node *n + = (struct bshell_word_ast_node *)bshell_ast_node_create( + BSHELL_AST_WORD); if (!n) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; } n->n_value = claim_token(ctx); - *out = (struct ast_node *)n; + *out = (struct bshell_ast_node *)n; return true; } - case TOK_VAR: { - struct var_ast_node *n - = (struct var_ast_node *)ast_node_create(AST_VAR); + case BSHELL_TOK_VAR: { + struct bshell_var_ast_node *n + = (struct bshell_var_ast_node *)bshell_ast_node_create( + BSHELL_AST_VAR); if (!n) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; } n->n_ident = claim_token(ctx); - *out = (struct ast_node *)n; + *out = (struct bshell_ast_node *)n; return true; } - case TOK_VAR_SPLAT: { - struct var_splat_ast_node *n - = (struct var_splat_ast_node *)ast_node_create( - AST_VAR_SPLAT); + case BSHELL_TOK_VAR_SPLAT: { + struct bshell_var_splat_ast_node *n + = (struct bshell_var_splat_ast_node *) + bshell_ast_node_create(BSHELL_AST_VAR_SPLAT); if (!n) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; } n->n_ident = claim_token(ctx); - *out = (struct ast_node *)n; + *out = (struct bshell_ast_node *)n; return true; } - case TOK_STRING: { - struct string_ast_node *n - = (struct string_ast_node *)ast_node_create(AST_STRING); + case BSHELL_TOK_STRING: { + struct bshell_string_ast_node *n + = (struct bshell_string_ast_node *) + bshell_ast_node_create(BSHELL_AST_STRING); if (!n) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; } n->n_value = claim_token(ctx); - *out = (struct ast_node *)n; + *out = (struct bshell_ast_node *)n; return true; } - case TOK_SYMBOL: + case BSHELL_TOK_SYMBOL: switch (tok->tok_symbol) { - case SYM_LEFT_PAREN: - case SYM_LEFT_BRACE: - case SYM_DOLLAR_LEFT_PAREN: - case SYM_AT_LEFT_BRACE: - case SYM_AT_LEFT_PAREN: + case BSHELL_SYM_LEFT_PAREN: + case BSHELL_SYM_LEFT_BRACE: + case BSHELL_SYM_DOLLAR_LEFT_PAREN: + case BSHELL_SYM_AT_LEFT_BRACE: + case BSHELL_SYM_AT_LEFT_PAREN: return parse_arith_value(ctx, out); default: report_error( @@ -153,29 +158,29 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) } static bool parse_redirect_to_fd( - struct parse_ctx *ctx, + struct bshell_parse_ctx *ctx, unsigned int in_fd, bool append, - struct ast_node **out) + struct bshell_ast_node **out) { if (ctx->p_status != BSHELL_SUCCESS) { return false; } - struct redirection_ast_node *redirect - = (struct redirection_ast_node *)ast_node_create( - AST_REDIRECTION); + struct bshell_redirection_ast_node *redirect + = (struct bshell_redirection_ast_node *)bshell_ast_node_create( + BSHELL_AST_REDIRECTION); redirect->n_in = in_fd; redirect->n_append = append; - if (!parse_symbol(ctx, SYM_AMPERSAND)) { - ast_node_destroy((struct ast_node *)redirect); + if (!parse_symbol(ctx, BSHELL_SYM_AMPERSAND)) { + bshell_ast_node_destroy((struct bshell_ast_node *)redirect); return false; } - struct lex_token *out_tok = NULL; - struct ast_node *out_expr = NULL; + struct bshell_lex_token *out_tok = NULL; + struct bshell_ast_node *out_expr = NULL; long long out_fd = -1; if (peek_word(ctx, &out_tok)) { @@ -201,29 +206,29 @@ static bool parse_redirect_to_fd( redirect->n_out_path = out_tok->tok_str; } - *out = (struct ast_node *)redirect; + *out = (struct bshell_ast_node *)redirect; return true; } static bool parse_redirect_to_file_squashed( - struct parse_ctx *ctx, + struct bshell_parse_ctx *ctx, unsigned int in_fd, bool append, const char *str, - struct ast_node **out) + struct bshell_ast_node **out) { if (ctx->p_status != BSHELL_SUCCESS) { return false; } - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); if (*str == '\0') { return false; } - struct redirection_ast_node *redirect - = (struct redirection_ast_node *)ast_node_create( - AST_REDIRECTION); + struct bshell_redirection_ast_node *redirect + = (struct bshell_redirection_ast_node *)bshell_ast_node_create( + BSHELL_AST_REDIRECTION); redirect->n_in = in_fd; redirect->n_append = append; @@ -233,29 +238,29 @@ static bool parse_redirect_to_file_squashed( redirect->n_out_tok = claim_token(ctx); - *out = (struct ast_node *)redirect; + *out = (struct bshell_ast_node *)redirect; return true; } static bool parse_redirect_to_file_separate( - struct parse_ctx *ctx, + struct bshell_parse_ctx *ctx, unsigned int in_fd, bool append, - struct ast_node **out) + struct bshell_ast_node **out) { if (ctx->p_status != BSHELL_SUCCESS) { return false; } - struct ast_node *out_path = NULL; + struct bshell_ast_node *out_path = NULL; if (!parse_cmdcall_arg(ctx, &out_path)) { ctx->p_status = BSHELL_ERR_BAD_SYNTAX; return false; } - struct redirection_ast_node *redirect - = (struct redirection_ast_node *)ast_node_create( - AST_REDIRECTION); + struct bshell_redirection_ast_node *redirect + = (struct bshell_redirection_ast_node *)bshell_ast_node_create( + BSHELL_AST_REDIRECTION); redirect->n_in = in_fd; redirect->n_append = append; @@ -263,14 +268,14 @@ static bool parse_redirect_to_file_separate( redirect->n_out_is_expr = true; redirect->n_out_path_expr = out_path; - *out = (struct ast_node *)redirect; + *out = (struct bshell_ast_node *)redirect; return true; } -bool parse_redirect(struct parse_ctx *ctx, struct ast_node **out) +bool parse_redirect(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - struct lex_token *tok = peek_token(ctx); - if (!tok || tok->tok_type != TOK_WORD) { + struct bshell_lex_token *tok = peek_token(ctx); + if (!tok || tok->tok_type != BSHELL_TOK_WORD) { return false; } @@ -319,7 +324,7 @@ bool parse_redirect(struct parse_ctx *ctx, struct ast_node **out) return false; } -static bool peek_cmdcall_item(struct parse_ctx *ctx, bool unrestricted) +static bool peek_cmdcall_item(struct bshell_parse_ctx *ctx, bool unrestricted) { /* each token type falls into one of three categories: * - cmdcall item: the token can be used as part of a command call. the @@ -334,52 +339,53 @@ static bool peek_cmdcall_item(struct parse_ctx *ctx, bool unrestricted) * used. */ switch (peek_token_type(ctx)) { - case TOK_KEYWORD: - case TOK_INT: - case TOK_DOUBLE: - case TOK_VAR: - case TOK_VAR_SPLAT: - case TOK_STRING: - case TOK_WORD_START: + case BSHELL_TOK_KEYWORD: + case BSHELL_TOK_INT: + case BSHELL_TOK_DOUBLE: + case BSHELL_TOK_VAR: + case BSHELL_TOK_VAR_SPLAT: + case BSHELL_TOK_STRING: + case BSHELL_TOK_WORD_START: return unrestricted; - case TOK_SYMBOL: + case BSHELL_TOK_SYMBOL: switch (peek_unknown_symbol(ctx)) { - case SYM_PLUS: - case SYM_HYPHEN: + case BSHELL_SYM_PLUS: + case BSHELL_SYM_HYPHEN: return unrestricted; - case SYM_PIPE: - case SYM_AMPERSAND: - case SYM_SEMICOLON: - case SYM_RIGHT_PAREN: - case SYM_RIGHT_BRACE: - case SYM_RIGHT_BRACKET: + case BSHELL_SYM_PIPE: + case BSHELL_SYM_AMPERSAND: + case BSHELL_SYM_SEMICOLON: + case BSHELL_SYM_RIGHT_PAREN: + case BSHELL_SYM_RIGHT_BRACE: + case BSHELL_SYM_RIGHT_BRACKET: return false; default: return true; } - case TOK_NONE: - case TOK_LINEFEED: + case BSHELL_TOK_NONE: + case BSHELL_TOK_LINEFEED: return false; default: return true; } } -bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out) +bool parse_cmdcall(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - struct cmdcall_ast_node *node - = (struct cmdcall_ast_node *)ast_node_create(AST_CMDCALL); + struct bshell_cmdcall_ast_node *node + = (struct bshell_cmdcall_ast_node *)bshell_ast_node_create( + BSHELL_AST_CMDCALL); if (!node) { ctx->p_status = BSHELL_ERR_NO_MEMORY; return false; } - struct ast_node *child = NULL; + struct bshell_ast_node *child = NULL; bool unrestricted = false; bool ok = true; bool stop = false; - if (parse_symbol(ctx, SYM_AMPERSAND)) { + if (parse_symbol(ctx, BSHELL_SYM_AMPERSAND)) { unrestricted = true; } @@ -387,7 +393,7 @@ bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out) return false; } - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); if (!tok) { return false; } @@ -403,7 +409,7 @@ bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out) break; } - struct lex_token *tok = peek_token(ctx); + struct bshell_lex_token *tok = peek_token(ctx); if (!tok) { break; } @@ -420,47 +426,48 @@ bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out) } if (!ok) { - ast_node_destroy((struct ast_node *)node); + bshell_ast_node_destroy((struct bshell_ast_node *)node); node = NULL; } - *out = (struct ast_node *)node; + *out = (struct bshell_ast_node *)node; return ok; } -bool peek_command(struct parse_ctx *ctx) +bool peek_command(struct bshell_parse_ctx *ctx) { - if (peek_symbol(ctx, SYM_AMPERSAND)) { + if (peek_symbol(ctx, BSHELL_SYM_AMPERSAND)) { return true; } return peek_cmdcall_item(ctx, false); } -bool parse_command(struct parse_ctx *ctx, struct ast_node **out) +bool parse_command(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - struct ast_node *cmdcall = NULL; + struct bshell_ast_node *cmdcall = NULL; if (!parse_cmdcall(ctx, &cmdcall)) { return false; } - struct pipeline_ast_node *pipeline = NULL; + struct bshell_pipeline_ast_node *pipeline = NULL; while (1) { - if (peek_symbol(ctx, SYM_SEMICOLON) || peek_linefeed(ctx)) { + if (peek_symbol(ctx, BSHELL_SYM_SEMICOLON) + || peek_linefeed(ctx)) { break; } - if (!parse_symbol(ctx, SYM_PIPE)) { + if (!parse_symbol(ctx, BSHELL_SYM_PIPE)) { break; } if (!pipeline) { - pipeline = (struct pipeline_ast_node *)ast_node_create( - AST_PIPELINE); + pipeline = (struct bshell_pipeline_ast_node *) + bshell_ast_node_create(BSHELL_AST_PIPELINE); if (!pipeline) { ctx->p_status = BSHELL_ERR_NO_MEMORY; - ast_node_destroy(cmdcall); + bshell_ast_node_destroy(cmdcall); return false; } @@ -478,7 +485,7 @@ bool parse_command(struct parse_ctx *ctx, struct ast_node **out) } if (pipeline) { - *out = (struct ast_node *)pipeline; + *out = (struct bshell_ast_node *)pipeline; } else { *out = cmdcall; } @@ -487,21 +494,22 @@ bool parse_command(struct parse_ctx *ctx, struct ast_node **out) } bool parse_pipeline( - struct parse_ctx *ctx, - struct ast_node *first_item, - struct ast_node **out) + struct bshell_parse_ctx *ctx, + struct bshell_ast_node *first_item, + struct bshell_ast_node **out) { - struct pipeline_ast_node *pipeline - = (struct pipeline_ast_node *)ast_node_create(AST_PIPELINE); + struct bshell_pipeline_ast_node *pipeline + = (struct bshell_pipeline_ast_node *)bshell_ast_node_create( + BSHELL_AST_PIPELINE); fx_queue_push_back(&pipeline->n_stages, &first_item->n_entry); while (1) { - if (!parse_symbol(ctx, SYM_PIPE)) { + if (!parse_symbol(ctx, BSHELL_SYM_PIPE)) { break; } - struct ast_node *cmdcall = NULL; + struct bshell_ast_node *cmdcall = NULL; if (!parse_cmdcall(ctx, &cmdcall)) { ctx->p_status = BSHELL_ERR_BAD_SYNTAX; return false; @@ -510,6 +518,6 @@ bool parse_pipeline( fx_queue_push_back(&pipeline->n_stages, &cmdcall->n_entry); } - *out = (struct ast_node *)pipeline; + *out = (struct bshell_ast_node *)pipeline; return true; } diff --git a/bshell/parse/syntax/expr.c b/bshell.runtime/parse/syntax/expr.c similarity index 54% rename from bshell/parse/syntax/expr.c rename to bshell.runtime/parse/syntax/expr.c index 60d2fe6..97d6604 100644 --- a/bshell/parse/syntax/expr.c +++ b/bshell.runtime/parse/syntax/expr.c @@ -1,10 +1,10 @@ #include "../syntax.h" -bool parse_expr(struct parse_ctx *ctx, struct ast_node **out) +bool parse_expr(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { bool ok = false; if (!ok && peek_arith_expr(ctx)) { - ok = parse_arith_expr(ctx, PRECEDENCE_MINIMUM, out); + ok = parse_arith_expr(ctx, BSHELL_PRECEDENCE_MINIMUM, out); } if (!ok && peek_command(ctx)) { diff --git a/bshell/parse/syntax/func.c b/bshell.runtime/parse/syntax/func.c similarity index 54% rename from bshell/parse/syntax/func.c rename to bshell.runtime/parse/syntax/func.c index 85d670b..5360be7 100644 --- a/bshell/parse/syntax/func.c +++ b/bshell.runtime/parse/syntax/func.c @@ -1,41 +1,42 @@ #include "../syntax.h" -bool parse_func(struct parse_ctx *ctx, struct ast_node **out) +bool parse_func(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - if (!parse_keyword(ctx, KW_FUNC)) { + if (!parse_keyword(ctx, BSHELL_KW_FUNC)) { return false; } - struct lex_token *name = NULL; + struct bshell_lex_token *name = NULL; if (!parse_word(ctx, &name)) { report_error(ctx, "expected function identifier"); return false; } - struct func_ast_node *func - = (struct func_ast_node *)ast_node_create(AST_FUNC); + struct bshell_func_ast_node *func + = (struct bshell_func_ast_node *)bshell_ast_node_create( + BSHELL_AST_FUNC); if (!func) { ctx->p_status = BSHELL_ERR_NO_MEMORY; - lex_token_destroy(name); + bshell_lex_token_destroy(name); return false; } func->n_name = name; - if (!parse_symbol(ctx, SYM_LEFT_PAREN)) { + if (!parse_symbol(ctx, BSHELL_SYM_LEFT_PAREN)) { report_error(ctx, "expected `(` after function identifier"); - ast_node_destroy((struct ast_node *)func); + bshell_ast_node_destroy((struct bshell_ast_node *)func); return false; } size_t nr_args = 0; bool ok = true; while (1) { - if (parse_symbol(ctx, SYM_RIGHT_PAREN)) { + if (parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { break; } - if (nr_args > 0 && !parse_symbol(ctx, SYM_COMMA)) { + if (nr_args > 0 && !parse_symbol(ctx, BSHELL_SYM_COMMA)) { report_error( ctx, "expected `,` or `)` after parameter name"); @@ -43,19 +44,21 @@ bool parse_func(struct parse_ctx *ctx, struct ast_node **out) break; } - struct lex_token *param_token = NULL; - struct var_ast_node *param_node = NULL; + struct bshell_lex_token *param_token = NULL; + struct bshell_var_ast_node *param_node = NULL; if (!parse_var(ctx, ¶m_token)) { report_error(ctx, "expected parameter variable"); ok = false; break; } - param_node = (struct var_ast_node *)ast_node_create(AST_VAR); + param_node + = (struct bshell_var_ast_node *)bshell_ast_node_create( + BSHELL_AST_VAR); if (!param_node) { ok = false; ctx->p_status = BSHELL_ERR_NO_MEMORY; - lex_token_destroy(param_token); + bshell_lex_token_destroy(param_token); break; } @@ -70,16 +73,16 @@ bool parse_func(struct parse_ctx *ctx, struct ast_node **out) ctx->p_status = BSHELL_ERR_BAD_SYNTAX; } - ast_node_destroy((struct ast_node *)func); + bshell_ast_node_destroy((struct bshell_ast_node *)func); return false; } if (!parse_block(ctx, &func->n_body)) { report_error(ctx, "failed to parse function body"); - ast_node_destroy((struct ast_node *)func); + bshell_ast_node_destroy((struct bshell_ast_node *)func); return false; } - *out = (struct ast_node *)func; + *out = (struct bshell_ast_node *)func; return true; } diff --git a/bshell.runtime/parse/syntax/generic.c b/bshell.runtime/parse/syntax/generic.c new file mode 100644 index 0000000..c2974df --- /dev/null +++ b/bshell.runtime/parse/syntax/generic.c @@ -0,0 +1,158 @@ +#include "../syntax.h" + +#include +#include +#include + +struct bshell_lex_token *claim_token(struct bshell_parse_ctx *ctx) +{ + return bshell_lex_ctx_claim(ctx->p_src); +} + +void discard_token(struct bshell_parse_ctx *ctx) +{ + return bshell_lex_ctx_discard(ctx->p_src); +} + +struct bshell_lex_token *peek_token(struct bshell_parse_ctx *ctx) +{ + return bshell_lex_ctx_peek(ctx->p_src); +} + +enum bshell_lex_token_type peek_token_type(struct bshell_parse_ctx *ctx) +{ + struct bshell_lex_token *tok = peek_token(ctx); + return tok ? tok->tok_type : BSHELL_TOK_NONE; +} + +enum bshell_lex_symbol peek_unknown_symbol(struct bshell_parse_ctx *ctx) +{ + struct bshell_lex_token *tok = peek_token(ctx); + return (tok && tok->tok_type == BSHELL_TOK_SYMBOL) ? tok->tok_symbol + : BSHELL_SYM_NONE; +} + +enum bshell_lex_keyword peek_unknown_keyword(struct bshell_parse_ctx *ctx) +{ + struct bshell_lex_token *tok = peek_token(ctx); + return (tok && tok->tok_type == BSHELL_TOK_KEYWORD) ? tok->tok_keyword + : BSHELL_KW_NONE; +} + +bool peek_word(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (tok && tok->tok_type == BSHELL_TOK_WORD) { + *out = tok; + return true; + } + + return false; +} + +bool peek_linefeed(struct bshell_parse_ctx *ctx) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (tok && tok->tok_type == BSHELL_TOK_LINEFEED) { + return true; + } + + return false; +} + +bool peek_symbol(struct bshell_parse_ctx *ctx, enum bshell_lex_symbol sym) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (!tok) { + return false; + } + + if (tok->tok_type != BSHELL_TOK_SYMBOL) { + return false; + } + + if (tok->tok_symbol != sym) { + return false; + } + + return true; +} + +bool parse_linefeed(struct bshell_parse_ctx *ctx) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (tok && tok->tok_type == BSHELL_TOK_LINEFEED) { + discard_token(ctx); + return true; + } + + return false; +} + +bool parse_symbol(struct bshell_parse_ctx *ctx, enum bshell_lex_symbol sym) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (!tok) { + return false; + } + + if (tok->tok_type != BSHELL_TOK_SYMBOL) { + return false; + } + + if (tok->tok_symbol != sym) { + return false; + } + + discard_token(ctx); + return true; +} + +bool parse_keyword(struct bshell_parse_ctx *ctx, enum bshell_lex_keyword kw) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (!tok) { + return false; + } + + if (tok->tok_type != BSHELL_TOK_KEYWORD) { + return false; + } + + if (tok->tok_keyword != kw) { + return false; + } + + discard_token(ctx); + return true; +} + +bool parse_word(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (!tok) { + return false; + } + + if (tok->tok_type != BSHELL_TOK_WORD) { + return false; + } + + *out = claim_token(ctx); + return true; +} + +bool parse_var(struct bshell_parse_ctx *ctx, struct bshell_lex_token **out) +{ + struct bshell_lex_token *tok = peek_token(ctx); + if (!tok) { + return false; + } + + if (tok->tok_type != BSHELL_TOK_VAR) { + return false; + } + + *out = claim_token(ctx); + return true; +} diff --git a/bshell.runtime/parse/syntax/if-else.c b/bshell.runtime/parse/syntax/if-else.c new file mode 100644 index 0000000..b31310c --- /dev/null +++ b/bshell.runtime/parse/syntax/if-else.c @@ -0,0 +1,130 @@ +#include "../syntax.h" + +static bool add_branch( + struct bshell_if_ast_node *group, + struct bshell_ast_node *cond, + struct bshell_ast_node *body) +{ + struct bshell_if_branch_ast_node *branch + = (struct bshell_if_branch_ast_node *)bshell_ast_node_create( + BSHELL_AST_IF_BRANCH); + if (!branch) { + return false; + } + + branch->n_cond = cond; + branch->n_body = body; + fx_queue_push_back(&group->n_branches, &branch->n_base.n_entry); + + return true; +} + +bool parse_if(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) +{ + if (!parse_keyword(ctx, BSHELL_KW_IF)) { + return false; + } + + if (!parse_symbol(ctx, BSHELL_SYM_LEFT_PAREN)) { + report_error(ctx, "expected `(` after `if`"); + return false; + } + + struct bshell_ast_node *if_cond = NULL, *if_body = NULL; + if (!parse_expr(ctx, &if_cond)) { + report_error(ctx, "invalid if condition"); + return false; + } + + if (!parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { + report_error(ctx, "expected `)` after if-condition"); + bshell_ast_node_destroy(if_cond); + return false; + } + + if (!parse_block(ctx, &if_body)) { + report_error(ctx, "invalid if body"); + bshell_ast_node_destroy(if_cond); + return false; + } + + struct bshell_if_ast_node *if_group + = (struct bshell_if_ast_node *)bshell_ast_node_create( + BSHELL_AST_IF); + if (!if_group) { + ctx->p_status = BSHELL_ERR_NO_MEMORY; + bshell_ast_node_destroy(if_cond); + bshell_ast_node_destroy(if_body); + return false; + } + + if (!add_branch(if_group, if_cond, if_body)) { + ctx->p_status = BSHELL_ERR_NO_MEMORY; + bshell_ast_node_destroy(if_cond); + bshell_ast_node_destroy(if_body); + bshell_ast_node_destroy((struct bshell_ast_node *)if_group); + return false; + } + + bool done = false; + while (!done) { + struct bshell_ast_node *cond = NULL, *body = NULL; + if (parse_keyword(ctx, BSHELL_KW_ELSE)) { + done = true; + } else if (parse_keyword(ctx, BSHELL_KW_ELSEIF)) { + if (!parse_symbol(ctx, BSHELL_SYM_LEFT_PAREN)) { + report_error( + ctx, + "expected `(` after `elseif`"); + return false; + } + + if (!parse_expr(ctx, &cond)) { + report_error( + ctx, + "invalid conditional expression"); + bshell_ast_node_destroy( + (struct bshell_ast_node *)if_group); + return false; + } + + if (!parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) { + report_error( + ctx, + "expected `)` after elseif-condition"); + bshell_ast_node_destroy(if_cond); + return false; + } + } else { + done = true; + break; + } + + if (!parse_block(ctx, &body)) { + report_error(ctx, "invalid conditional body"); + if (cond) { + bshell_ast_node_destroy(cond); + } + + bshell_ast_node_destroy( + (struct bshell_ast_node *)if_group); + return false; + } + + if (!add_branch(if_group, cond, body)) { + report_error(ctx, "failed to add branch to if-group"); + if (cond) { + bshell_ast_node_destroy(cond); + } + + bshell_ast_node_destroy(body); + bshell_ast_node_destroy( + (struct bshell_ast_node *)if_group); + return false; + } + } + + *out = (struct bshell_ast_node *)if_group; + + return true; +} diff --git a/bshell.runtime/parse/syntax/keyword.c b/bshell.runtime/parse/syntax/keyword.c new file mode 100644 index 0000000..680f10d --- /dev/null +++ b/bshell.runtime/parse/syntax/keyword.c @@ -0,0 +1,21 @@ +#include "../syntax.h" + +bool peek_keyword_expr(struct bshell_parse_ctx *ctx) +{ + return peek_unknown_keyword(ctx) != BSHELL_KW_NONE; +} + +bool parse_keyword_expr(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) +{ + switch (peek_unknown_keyword(ctx)) { + case BSHELL_KW_NONE: + return false; + case BSHELL_KW_IF: + return parse_if(ctx, out); + case BSHELL_KW_FUNC: + return parse_func(ctx, out); + default: + ctx->p_status = BSHELL_ERR_BAD_SYNTAX; + return false; + } +} diff --git a/bshell/parse/syntax/statement.c b/bshell.runtime/parse/syntax/statement.c similarity index 57% rename from bshell/parse/syntax/statement.c rename to bshell.runtime/parse/syntax/statement.c index aa064ea..75eb5d8 100644 --- a/bshell/parse/syntax/statement.c +++ b/bshell.runtime/parse/syntax/statement.c @@ -1,6 +1,6 @@ #include "../syntax.h" -bool peek_statement(struct parse_ctx *ctx) +bool peek_statement(struct bshell_parse_ctx *ctx) { if (peek_keyword_expr(ctx)) { return true; @@ -17,7 +17,7 @@ bool peek_statement(struct parse_ctx *ctx) return false; } -bool parse_statement(struct parse_ctx *ctx, struct ast_node **out) +bool parse_statement(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { if (!peek_token(ctx)) { /* error, or EOF */ @@ -33,7 +33,7 @@ bool parse_statement(struct parse_ctx *ctx, struct ast_node **out) if (!ok && peek_arith_expr(ctx)) { unknown = false; - ok = parse_arith_expr(ctx, PRECEDENCE_MINIMUM, out); + ok = parse_arith_expr(ctx, BSHELL_PRECEDENCE_MINIMUM, out); } if (!ok && peek_command(ctx)) { @@ -51,32 +51,33 @@ bool parse_statement(struct parse_ctx *ctx, struct ast_node **out) return ok; } -static struct ast_node *convert_single_statement( - struct stmt_list_ast_node *list) +static struct bshell_ast_node *convert_single_statement( + struct bshell_stmt_list_ast_node *list) { fx_queue_entry *first_entry = fx_queue_first(&list->n_statements); if (!first_entry || fx_queue_next(first_entry)) { - return (struct ast_node *)list; + return (struct bshell_ast_node *)list; } fx_queue_delete(&list->n_statements, first_entry); - struct ast_node *first - = fx_unbox(struct ast_node, first_entry, n_entry); - ast_node_destroy((struct ast_node *)list); + struct bshell_ast_node *first + = fx_unbox(struct bshell_ast_node, first_entry, n_entry); + bshell_ast_node_destroy((struct bshell_ast_node *)list); return first; } -bool parse_statement_list(struct parse_ctx *ctx, struct ast_node **out) +bool parse_statement_list(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out) { - struct stmt_list_ast_node *stmt_list - = (struct stmt_list_ast_node *)ast_node_create(AST_STMT_LIST); + struct bshell_stmt_list_ast_node *stmt_list + = (struct bshell_stmt_list_ast_node *)bshell_ast_node_create( + BSHELL_AST_STMT_LIST); bool ok = true; while (ok) { parse_linefeed(ctx); - struct ast_node *stmt = NULL; + struct bshell_ast_node *stmt = NULL; if (!parse_statement(ctx, &stmt)) { ok = false; break; @@ -84,13 +85,13 @@ bool parse_statement_list(struct parse_ctx *ctx, struct ast_node **out) fx_queue_push_back(&stmt_list->n_statements, &stmt->n_entry); - if (!parse_symbol(ctx, SYM_SEMICOLON)) { + if (!parse_symbol(ctx, BSHELL_SYM_SEMICOLON)) { break; } } if (!ok) { - ast_node_destroy((struct ast_node *)stmt_list); + bshell_ast_node_destroy((struct bshell_ast_node *)stmt_list); return false; } diff --git a/bshell.runtime/parse/token.c b/bshell.runtime/parse/token.c new file mode 100644 index 0000000..9db3038 --- /dev/null +++ b/bshell.runtime/parse/token.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include + +struct bshell_lex_token *bshell_lex_token_create( + enum bshell_lex_token_type type) +{ + struct bshell_lex_token *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + + out->tok_type = type; + + return out; +} + +struct bshell_lex_token *bshell_lex_token_create_with_string( + enum bshell_lex_token_type type, + const char *s) +{ + struct bshell_lex_token *tok = bshell_lex_token_create(type); + if (!tok) { + return NULL; + } + + tok->tok_str = fx_strdup(s); + if (!tok->tok_str) { + free(tok); + return NULL; + } + + return tok; +} + +void bshell_lex_token_destroy(struct bshell_lex_token *tok) +{ + switch (tok->tok_type) { + case BSHELL_TOK_WORD: + case BSHELL_TOK_FLAG: + case BSHELL_TOK_STRING: + if (tok->tok_str) { + free(tok->tok_str); + } + + break; + default: + break; + } + + free(tok); +} + +struct bshell_lex_token *bshell_lex_token_change_type( + struct bshell_lex_token *tok, + enum bshell_lex_token_type new_type) +{ + switch (tok->tok_type) { + case BSHELL_TOK_WORD: + case BSHELL_TOK_FLAG: + case BSHELL_TOK_STRING: + if (tok->tok_str) { + free(tok->tok_str); + tok->tok_str = NULL; + } + break; + default: + break; + } + + tok->tok_type = new_type; + return tok; +} + +void bshell_lex_token_change_string(struct bshell_lex_token *tok, const char *s) +{ + if (!bshell_lex_token_has_string_value(tok)) { + return; + } + + if (tok->tok_str) { + free(tok->tok_str); + } + + tok->tok_str = fx_strdup(s); +} + +#define ENUM_STR(x) \ + case x: \ + return #x + +const char *bshell_token_type_to_string(enum bshell_lex_token_type type) +{ + switch (type) { + ENUM_STR(BSHELL_TOK_NONE); + ENUM_STR(BSHELL_TOK_KEYWORD); + ENUM_STR(BSHELL_TOK_SYMBOL); + ENUM_STR(BSHELL_TOK_INT); + ENUM_STR(BSHELL_TOK_DOUBLE); + ENUM_STR(BSHELL_TOK_WORD); + ENUM_STR(BSHELL_TOK_WORD_START); + ENUM_STR(BSHELL_TOK_WORD_END); + ENUM_STR(BSHELL_TOK_OPERATOR); + ENUM_STR(BSHELL_TOK_VAR); + ENUM_STR(BSHELL_TOK_VAR_SPLAT); + ENUM_STR(BSHELL_TOK_FLAG); + ENUM_STR(BSHELL_TOK_STRING); + ENUM_STR(BSHELL_TOK_STR_START); + ENUM_STR(BSHELL_TOK_STR_END); + ENUM_STR(BSHELL_TOK_LINEFEED); + default: + return ""; + } +} + +const char *bshell_lex_keyword_to_string(enum bshell_lex_keyword keyword) +{ + switch (keyword) { + ENUM_STR(BSHELL_KW_NONE); + ENUM_STR(BSHELL_KW_FUNC); + ENUM_STR(BSHELL_KW_IF); + ENUM_STR(BSHELL_KW_ELSEIF); + ENUM_STR(BSHELL_KW_ELSE); + default: + return ""; + } +} + +const char *bshell_lex_symbol_to_string(enum bshell_lex_symbol sym) +{ + switch (sym) { + ENUM_STR(BSHELL_SYM_NONE); + ENUM_STR(BSHELL_SYM_PLUS); + ENUM_STR(BSHELL_SYM_HYPHEN); + ENUM_STR(BSHELL_SYM_FORWARD_SLASH); + ENUM_STR(BSHELL_SYM_ASTERISK); + ENUM_STR(BSHELL_SYM_AMPERSAND); + ENUM_STR(BSHELL_SYM_PERCENT); + ENUM_STR(BSHELL_SYM_SQUOTE); + ENUM_STR(BSHELL_SYM_DQUOTE); + ENUM_STR(BSHELL_SYM_HASH); + ENUM_STR(BSHELL_SYM_COLON_COLON); + ENUM_STR(BSHELL_SYM_SEMICOLON); + ENUM_STR(BSHELL_SYM_COMMA); + ENUM_STR(BSHELL_SYM_DOLLAR); + ENUM_STR(BSHELL_SYM_DOLLAR_LEFT_PAREN); + ENUM_STR(BSHELL_SYM_DOLLAR_LEFT_BRACE); + ENUM_STR(BSHELL_SYM_DOT); + ENUM_STR(BSHELL_SYM_DOT_DOT); + ENUM_STR(BSHELL_SYM_PIPE); + ENUM_STR(BSHELL_SYM_AT); + ENUM_STR(BSHELL_SYM_AT_LEFT_PAREN); + ENUM_STR(BSHELL_SYM_AT_LEFT_BRACE); + ENUM_STR(BSHELL_SYM_LEFT_BRACE); + ENUM_STR(BSHELL_SYM_RIGHT_BRACE); + ENUM_STR(BSHELL_SYM_LEFT_BRACKET); + ENUM_STR(BSHELL_SYM_RIGHT_BRACKET); + ENUM_STR(BSHELL_SYM_LEFT_PAREN); + ENUM_STR(BSHELL_SYM_RIGHT_PAREN); + ENUM_STR(BSHELL_SYM_EQUAL); + ENUM_STR(BSHELL_SYM_PLUS_EQUAL); + ENUM_STR(BSHELL_SYM_HYPHEN_EQUAL); + ENUM_STR(BSHELL_SYM_ASTERISK_EQUAL); + ENUM_STR(BSHELL_SYM_FORWARD_SLASH_EQUAL); + ENUM_STR(BSHELL_SYM_PERCENT_EQUAL); + ENUM_STR(BSHELL_SYM_QUESTION_DOT); + ENUM_STR(BSHELL_SYM_QUESTION_LEFT_BRACKET); + default: + return ""; + } +} + +const char *bshell_lex_operator_to_string(enum bshell_lex_operator op) +{ + switch (op) { + ENUM_STR(BSHELL_TKOP_BAND); + ENUM_STR(BSHELL_TKOP_BOR); + ENUM_STR(BSHELL_TKOP_BXOR); + ENUM_STR(BSHELL_TKOP_BNOT); + ENUM_STR(BSHELL_TKOP_SHL); + ENUM_STR(BSHELL_TKOP_SHR); + ENUM_STR(BSHELL_TKOP_EQ); + ENUM_STR(BSHELL_TKOP_NE); + ENUM_STR(BSHELL_TKOP_GT); + ENUM_STR(BSHELL_TKOP_LT); + ENUM_STR(BSHELL_TKOP_GE); + ENUM_STR(BSHELL_TKOP_LE); + ENUM_STR(BSHELL_TKOP_MATCH); + ENUM_STR(BSHELL_TKOP_NOTMATCH); + ENUM_STR(BSHELL_TKOP_REPLACE); + ENUM_STR(BSHELL_TKOP_LIKE); + ENUM_STR(BSHELL_TKOP_NOTLIKE); + ENUM_STR(BSHELL_TKOP_IN); + ENUM_STR(BSHELL_TKOP_F); + ENUM_STR(BSHELL_TKOP_NOTIN); + ENUM_STR(BSHELL_TKOP_CONTAINS); + ENUM_STR(BSHELL_TKOP_NOTCONTAINS); + ENUM_STR(BSHELL_TKOP_AND); + ENUM_STR(BSHELL_TKOP_OR); + ENUM_STR(BSHELL_TKOP_XOR); + ENUM_STR(BSHELL_TKOP_NOT); + ENUM_STR(BSHELL_TKOP_SPLIT); + ENUM_STR(BSHELL_TKOP_JOIN); + ENUM_STR(BSHELL_TKOP_IS); + ENUM_STR(BSHELL_TKOP_ISNOT); + ENUM_STR(BSHELL_TKOP_AS); + default: + return ""; + } +} diff --git a/bshell/runtime/cmdcall.c b/bshell.runtime/runtime/cmdcall.c similarity index 76% rename from bshell/runtime/cmdcall.c rename to bshell.runtime/runtime/cmdcall.c index 96050e4..3871b0a 100644 --- a/bshell/runtime/cmdcall.c +++ b/bshell.runtime/runtime/cmdcall.c @@ -1,11 +1,9 @@ -#include "cmdcall.h" - -#include "../command/alias.h" -#include "../command/command.h" -#include "../runtime/pipeline.h" -#include "../status.h" -#include "runtime.h" - +#include +#include +#include +#include +#include +#include #include #include #include @@ -29,8 +27,6 @@ struct bshell_cmdcall_p { fx_array *cmd_args_processed; }; -extern const fx_assembly *bshell_assembly_get(void); - static void cmdcall_fini(fx_object *obj, void *priv) { struct bshell_cmdcall_p *cmdcall = priv; @@ -74,67 +70,6 @@ static const fx_value *get_arg(struct bshell_cmdcall_p *cmdcall, size_t index) return &cmdcall->cmd_args.items[cmdcall->cmd_args.count - index - 1]; } -static bshell_command *find_call_target(const char *name) -{ -#if 0 -#define VERB_MAX 32 - const char *hyphen = strchr(name, '-'); - if (!hyphen) { - return NULL; - } - - const char *noun = hyphen + 1; - - size_t verb_length = hyphen - name; - if (verb_length >= VERB_MAX) { - return NULL; - } - - char verb[VERB_MAX] = {}; - memcpy(verb, name, verb_length); - for (size_t i = 0; i < verb_length; i++) { - verb[i] = tolower(verb[i]); - } - - bshell_verb *verb_info = bshell_verb_get_by_name(verb); - if (!verb_info) { - return NULL; - } - - enum bshell_verb_id verb_id = bshell_verb_get_id(verb_info); - fx_string *target_name = fx_string_create(); - fx_string *call_name = fx_string_create_from_cstr(name); - fx_string_transform_lowercase(call_name); - - const fx_assembly *self = bshell_assembly_get(); - fx_iterator *it = fx_assembly_get_types(self); - fx_foreach(v, it) - { - fx_type *ty = NULL; - fx_value_get_object(&v, &ty); - const char *ty_name = fx_type_get_name(ty); - bshell_command_class *cmd = fx_type_get_interface( - ty, - BSHELL_TYPE_COMMAND); - if (!cmd || !cmd->c_get_callable_name_static) { - continue; - } - - cmd->c_get_callable_name( - - if (fx_strcmp_nocase(cmdlet->c_noun, noun) != 0) { - continue; - } - - return fx_object_create(fx_type_get_id(ty)); - } - fx_iterator_unref(it); - -#undef VERB_MAX -#endif - return NULL; -} - static bshell_command *__resolve_call_target( const char *callable_name, struct bshell_runtime *rt) @@ -160,16 +95,14 @@ static enum bshell_status resolve_call_target( while (1) { const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s); - bshell_command *cmd = bshell_runtime_find_command( - rt, - cmd_name_cstr); + bshell_command *cmd + = bshell_runtime_find_command(rt, cmd_name_cstr); if (!cmd) { break; } - bshell_alias_class *alias = fx_object_get_interface( - cmd, - BSHELL_TYPE_ALIAS); + bshell_alias_class *alias + = fx_object_get_interface(cmd, BSHELL_TYPE_ALIAS); if (alias) { fx_string_clear(cmd_name_s); fx_string_append_cstr(cmd_name_s, alias->a_target_name); @@ -212,8 +145,8 @@ static enum bshell_status process_args(struct bshell_cmdcall_p *cmdcall) for (i32 i = cmdcall->cmd_args.count - 1; i >= 0; i--) { fx_stringstream_reset(str); fx_value_to_string(&cmdcall->cmd_args.items[i], str, NULL); - fx_string *arg_str = fx_string_create_from_cstr( - fx_stringstream_ptr(str)); + fx_string *arg_str + = fx_string_create_from_cstr(fx_stringstream_ptr(str)); fx_array_push_back( cmdcall->cmd_args_processed, FX_VALUE_OBJECT(arg_str)); diff --git a/bshell/runtime/eval.c b/bshell.runtime/runtime/eval.c similarity index 73% rename from bshell/runtime/eval.c rename to bshell.runtime/runtime/eval.c index 8a11422..0979556 100644 --- a/bshell/runtime/eval.c +++ b/bshell.runtime/runtime/eval.c @@ -1,10 +1,10 @@ -#include "../format/format.h" -#include "../status.h" -#include "cmdcall.h" -#include "pipeline.h" -#include "runtime.h" #include "scope.h" +#include +#include +#include +#include +#include #include #include #include @@ -12,7 +12,7 @@ static enum bshell_status eval_instruction( struct bshell_runtime *rt, - struct runtime_scope *scope, + struct bshell_runtime_scope *scope, bshell_instruction instr) { fx_value x, y, z; @@ -27,24 +27,24 @@ static enum bshell_status eval_instruction( bshell_instruction_decode(instr, &opcode, &arg); switch (opcode) { - case OPCODE_LDC_INT: + case BSHELL_OPCODE_LDC_INT: x = FX_INT(arg); - runtime_scope_push_value(scope, &x); + bshell_runtime_scope_push_value(scope, &x); fx_value_unset(&x); break; - case OPCODE_LDC_FP: + case BSHELL_OPCODE_LDC_FP: pool_value = bshell_scriptblock_get_pool_value( scope->s_block, arg, FX_TYPE_DOUBLE); if (pool_value) { - runtime_scope_push_value(scope, pool_value); + bshell_runtime_scope_push_value(scope, pool_value); } else { fprintf(stderr, "RUNTIME: invalid ldc.fp operand\n"); return BSHELL_ERR_BAD_SYNTAX; } break; - case OPCODE_LDC_STR: + case BSHELL_OPCODE_LDC_STR: pool_value = bshell_scriptblock_get_pool_value( scope->s_block, arg, @@ -56,15 +56,15 @@ static enum bshell_status eval_instruction( FX_TYPE_CSTR); } if (pool_value) { - runtime_scope_push_value(scope, pool_value); + bshell_runtime_scope_push_value(scope, pool_value); } else { fprintf(stderr, "RUNTIME: invalid ldc.str operand\n"); return BSHELL_ERR_BAD_SYNTAX; } break; - case OPCODE_ADD: - x = runtime_scope_pop_value(scope); - y = runtime_scope_pop_value(scope); + case BSHELL_OPCODE_ADD: + x = bshell_runtime_scope_pop_value(scope); + y = bshell_runtime_scope_pop_value(scope); type = fx_value_get_common_type(&x, &y); if (!type) { fprintf(stderr, @@ -93,12 +93,12 @@ static enum bshell_status eval_instruction( "operator\n"); return BSHELL_ERR_NOT_SUPPORTED; } - runtime_scope_push_value(scope, &z); + bshell_runtime_scope_push_value(scope, &z); fx_value_unset(&z); break; - case OPCODE_SUB: - x = runtime_scope_pop_value(scope); - y = runtime_scope_pop_value(scope); + case BSHELL_OPCODE_SUB: + x = bshell_runtime_scope_pop_value(scope); + y = bshell_runtime_scope_pop_value(scope); type = fx_value_get_common_type(&x, &y); if (!type) { fprintf(stderr, @@ -114,12 +114,12 @@ static enum bshell_status eval_instruction( "operator\n"); return BSHELL_ERR_NOT_SUPPORTED; } - runtime_scope_push_value(scope, &z); + bshell_runtime_scope_push_value(scope, &z); fx_value_unset(&z); break; - case OPCODE_MUL: - x = runtime_scope_pop_value(scope); - y = runtime_scope_pop_value(scope); + case BSHELL_OPCODE_MUL: + x = bshell_runtime_scope_pop_value(scope); + y = bshell_runtime_scope_pop_value(scope); type = fx_value_get_common_type(&x, &y); if (!type) { fprintf(stderr, @@ -135,12 +135,12 @@ static enum bshell_status eval_instruction( "operator\n"); return BSHELL_ERR_NOT_SUPPORTED; } - runtime_scope_push_value(scope, &z); + bshell_runtime_scope_push_value(scope, &z); fx_value_unset(&z); break; - case OPCODE_DIV: - x = runtime_scope_pop_value(scope); - y = runtime_scope_pop_value(scope); + case BSHELL_OPCODE_DIV: + x = bshell_runtime_scope_pop_value(scope); + y = bshell_runtime_scope_pop_value(scope); status = fx_value_change_type(&x, &x, FX_TYPE_DOUBLE); if (!FX_OK(status)) { fprintf(stderr, @@ -164,10 +164,10 @@ static enum bshell_status eval_instruction( "operator\n"); return BSHELL_ERR_NOT_SUPPORTED; } - runtime_scope_push_value(scope, &z); + bshell_runtime_scope_push_value(scope, &z); fx_value_unset(&z); break; - case OPCODE_LDLOCAL: + case BSHELL_OPCODE_LDLOCAL: pool_value = bshell_scriptblock_get_pool_value( scope->s_block, arg, @@ -180,15 +180,15 @@ static enum bshell_status eval_instruction( fx_value_get_cstr(pool_value, &s); var = bshell_runtime_find_var(rt, s); if (var) { - runtime_scope_push_value( + bshell_runtime_scope_push_value( scope, bshell_variable_get_value(var)); } else { - runtime_scope_push_value(scope, &FX_VALUE_EMPTY); + bshell_runtime_scope_push_value(scope, &FX_VALUE_EMPTY); } break; - case OPCODE_LDBLOCK: + case BSHELL_OPCODE_LDBLOCK: pool_value = bshell_scriptblock_get_pool_value( scope->s_block, arg, @@ -198,20 +198,20 @@ static enum bshell_status eval_instruction( return BSHELL_ERR_BAD_SYNTAX; } - runtime_scope_push_value(scope, pool_value); + bshell_runtime_scope_push_value(scope, pool_value); break; - case OPCODE_LDPROP: { + case BSHELL_OPCODE_LDPROP: { /* container */ - x = runtime_scope_pop_value(scope); + x = bshell_runtime_scope_pop_value(scope); /* property */ - y = runtime_scope_pop_value(scope); + y = bshell_runtime_scope_pop_value(scope); const fx_type *ty = fx_type_get_by_id(x.v_type); if (!ty) { fx_value_unset(&x); fx_value_unset(&y); - runtime_scope_push_value(scope, &FX_VALUE_EMPTY); + bshell_runtime_scope_push_value(scope, &FX_VALUE_EMPTY); break; } @@ -219,26 +219,25 @@ static enum bshell_status eval_instruction( fx_value_to_string(&y, strm, NULL); fx_value_unset(&y); - const fx_property *prop = fx_type_get_property( - ty, - fx_stringstream_ptr(strm)); + const fx_property *prop + = fx_type_get_property(ty, fx_stringstream_ptr(strm)); fx_stringstream_unref(strm); if (!prop) { fx_value_unset(&x); - runtime_scope_push_value(scope, &FX_VALUE_EMPTY); + bshell_runtime_scope_push_value(scope, &FX_VALUE_EMPTY); break; } fx_property_get_value(prop, &x, &z); fx_value_unset(&x); - runtime_scope_push_value(scope, &z); + bshell_runtime_scope_push_value(scope, &z); fx_value_unset(&z); break; } - case OPCODE_STLOCAL: - x = runtime_scope_pop_value(scope); + case BSHELL_OPCODE_STLOCAL: + x = bshell_runtime_scope_pop_value(scope); pool_value = bshell_scriptblock_get_pool_value( scope->s_block, arg, @@ -255,15 +254,15 @@ static enum bshell_status eval_instruction( } bshell_variable_set_value(var, &x); - runtime_scope_push_value(scope, &x); + bshell_runtime_scope_push_value(scope, &x); fx_value_unset(&x); break; - case OPCODE_MK_STR: { + case BSHELL_OPCODE_MK_STR: { fx_string *result = fx_string_create(); fx_stringstream *strm = fx_stringstream_create(); while (arg > 0) { - x = runtime_scope_pop_value(scope); + x = bshell_runtime_scope_pop_value(scope); fx_stringstream_reset(strm); fx_value_to_string(&x, strm, NULL); fx_string_prepend_cstr( @@ -275,16 +274,16 @@ static enum bshell_status eval_instruction( fx_stringstream_unref(strm); y = FX_VALUE_OBJECT(result); - runtime_scope_push_value(scope, &y); + bshell_runtime_scope_push_value(scope, &y); fx_value_unset(&y); break; } - case OPCODE_MK_HTAB: { + case BSHELL_OPCODE_MK_HTAB: { fx_hashtable *result = fx_hashtable_create(); while (arg > 0) { - fx_value key = runtime_scope_pop_value(scope); - fx_value value = runtime_scope_pop_value(scope); + fx_value key = bshell_runtime_scope_pop_value(scope); + fx_value value = bshell_runtime_scope_pop_value(scope); fx_hashtable_put(result, &key, &value); fx_value_unset(&key); fx_value_unset(&value); @@ -292,30 +291,30 @@ static enum bshell_status eval_instruction( } y = FX_VALUE_OBJECT(result); - runtime_scope_push_value(scope, &y); + bshell_runtime_scope_push_value(scope, &y); fx_value_unset(&y); break; } - case OPCODE_MK_ARRAY: { + case BSHELL_OPCODE_MK_ARRAY: { fx_array *result = fx_array_create(); while (arg > 0) { - fx_value value = runtime_scope_pop_value(scope); + fx_value value = bshell_runtime_scope_pop_value(scope); fx_array_push_front(result, value); fx_value_unset(&value); arg--; } y = FX_VALUE_OBJECT(result); - runtime_scope_push_value(scope, &y); + bshell_runtime_scope_push_value(scope, &y); fx_value_unset(&y); break; } - case OPCODE_LDCMD: { + case BSHELL_OPCODE_LDCMD: { bshell_cmdcall *result = bshell_cmdcall_create(); while (arg > 0) { - fx_value cmd_arg = runtime_scope_pop_value(scope); + fx_value cmd_arg = bshell_runtime_scope_pop_value(scope); bshell_cmdcall_push_arg(result, cmd_arg); fx_value_unset(&cmd_arg); arg--; @@ -327,15 +326,15 @@ static enum bshell_status eval_instruction( } y = FX_VALUE_OBJECT(result); - runtime_scope_push_value(scope, &y); + bshell_runtime_scope_push_value(scope, &y); fx_value_unset(&y); break; } - case OPCODE_PEXEC: { + case BSHELL_OPCODE_PEXEC: { bshell_pipeline *pipeline = bshell_pipeline_create(); bool single = (arg == 1); while (arg > 0) { - fx_value cmd = runtime_scope_pop_value(scope); + fx_value cmd = bshell_runtime_scope_pop_value(scope); bshell_cmdcall *cmdcall = NULL; if (fx_value_is_type(&cmd, BSHELL_TYPE_CMDCALL)) { fx_value_get_object(&cmd, &cmdcall); @@ -354,8 +353,8 @@ static enum bshell_status eval_instruction( int end_of_data = 0; bool columns_initialised = false; fx_value record = FX_VALUE_EMPTY; - struct table_format_ctx table_ctx; - table_format_ctx_init(&table_ctx, fx_stdout); + struct bshell_table_ctx table_ctx; + bshell_table_ctx_init(&table_ctx, fx_stdout); while (1) { bstatus = bshell_pipeline_pump_record( pipeline, @@ -371,21 +370,21 @@ static enum bshell_status eval_instruction( } if (!columns_initialised) { - const fx_type *ty = fx_type_get_by_id( - record.v_type); - table_format_ctx_prepare_columns_from_format( + const fx_type *ty + = fx_type_get_by_id(record.v_type); + bshell_table_ctx_prepare_columns_from_format( &table_ctx, ty, NULL); - table_format_ctx_print_headers(&table_ctx); + bshell_table_ctx_print_headers(&table_ctx); columns_initialised = true; } - table_format_ctx_print_record(&table_ctx, &record); + bshell_table_ctx_print_record(&table_ctx, &record); fx_value_unset(&record); } - table_format_ctx_cleanup(&table_ctx); + bshell_table_ctx_cleanup(&table_ctx); bshell_pipeline_unref(pipeline); break; } @@ -404,7 +403,7 @@ static fx_value runtime_eval(struct bshell_runtime *rt) { enum bshell_status status = BSHELL_SUCCESS; while (status == BSHELL_SUCCESS) { - struct runtime_scope *scope = runtime_get_scope(rt); + struct bshell_runtime_scope *scope = runtime_get_scope(rt); if (scope->s_ip >= scope->s_nr_instr) { break; } @@ -413,8 +412,8 @@ static fx_value runtime_eval(struct bshell_runtime *rt) status = eval_instruction(rt, scope, instr); } - struct runtime_scope *scope = runtime_get_scope(rt); - return runtime_scope_pop_value(scope); + struct bshell_runtime_scope *scope = runtime_get_scope(rt); + return bshell_runtime_scope_pop_value(scope); } fx_value bshell_runtime_eval_global( @@ -422,7 +421,7 @@ fx_value bshell_runtime_eval_global( bshell_scriptblock *block) { enum bshell_status status = BSHELL_SUCCESS; - runtime_scope_set_block(rt->rt_global, block); + bshell_runtime_scope_set_block(rt->rt_global, block); return runtime_eval(rt); } @@ -445,10 +444,8 @@ enum bshell_status bshell_runtime_push_scope( struct bshell_runtime *rt, bshell_scriptblock *block) { - struct runtime_scope *scope = runtime_push_scope( - rt, - RUNTIME_SCOPE_SCRIPT, - block); + struct bshell_runtime_scope *scope + = runtime_push_scope(rt, RUNTIME_SCOPE_SCRIPT, block); return scope ? BSHELL_SUCCESS : BSHELL_ERR_NO_MEMORY; } diff --git a/bshell/runtime/opcode.c b/bshell.runtime/runtime/opcode.c similarity index 57% rename from bshell/runtime/opcode.c rename to bshell.runtime/runtime/opcode.c index e4c39d8..7eda7af 100644 --- a/bshell/runtime/opcode.c +++ b/bshell.runtime/runtime/opcode.c @@ -1,19 +1,18 @@ -#include "opcode.h" - +#include #include -#define OPCODE_MAX 0xFF -#define ARG_MAX 0xFFFFFF +#define BSHELL_OPCODE_MAX 0xFF +#define ARG_MAX 0xFFFFFF bshell_instruction bshell_instruction_encode( enum bshell_opcode opcode, uint32_t arg) { - if (opcode > OPCODE_MAX) { + if (opcode > BSHELL_OPCODE_MAX) { return BSHELL_INSTRUCTION_INVALID; } - return fx_u32_htob((opcode & OPCODE_MAX) | (arg & ARG_MAX) << 8); + return fx_u32_htob((opcode & BSHELL_OPCODE_MAX) | (arg & ARG_MAX) << 8); } void bshell_instruction_decode( @@ -22,6 +21,6 @@ void bshell_instruction_decode( uint32_t *out_arg) { instr = fx_u32_btoh(instr); - *out_opcode = (instr & OPCODE_MAX); + *out_opcode = (instr & BSHELL_OPCODE_MAX); *out_arg = ((instr >> 8) & ARG_MAX); } diff --git a/bshell/runtime/pipeline.c b/bshell.runtime/runtime/pipeline.c similarity index 98% rename from bshell/runtime/pipeline.c rename to bshell.runtime/runtime/pipeline.c index 324bded..7a0a5d2 100644 --- a/bshell/runtime/pipeline.c +++ b/bshell.runtime/runtime/pipeline.c @@ -1,8 +1,6 @@ -#include "pipeline.h" - -#include "../status.h" -#include "cmdcall.h" - +#include +#include +#include #include #include #include diff --git a/bshell/runtime/runtime.c b/bshell.runtime/runtime/runtime.c similarity index 69% rename from bshell/runtime/runtime.c rename to bshell.runtime/runtime/runtime.c index 326e2d8..351c2c3 100644 --- a/bshell/runtime/runtime.c +++ b/bshell.runtime/runtime/runtime.c @@ -1,7 +1,6 @@ -#include "runtime.h" - #include "scope.h" +#include #include #include @@ -33,10 +32,8 @@ bshell_variable *bshell_runtime_find_var( bshell_variable *var = NULL; fx_queue_entry *cur = fx_queue_last(&rt->rt_scope); while (cur) { - struct runtime_scope *scope = fx_unbox( - struct runtime_scope, - cur, - s_entry); + struct bshell_runtime_scope *scope + = fx_unbox(struct bshell_runtime_scope, cur, s_entry); var = var_map_get(&scope->s_vars, name); if (var) { break; @@ -52,7 +49,7 @@ bshell_variable *bshell_runtime_define_var( struct bshell_runtime *rt, const char *name) { - struct runtime_scope *scope = runtime_get_scope(rt); + struct bshell_runtime_scope *scope = runtime_get_scope(rt); if (!scope) { return NULL; } @@ -71,9 +68,8 @@ bshell_command *bshell_runtime_find_command( const char *callable_name) { bshell_command *alias = NULL, *func = NULL; - const fx_value *alias_v = fx_hashtable_get( - rt->rt_aliases, - &FX_CSTR(callable_name)); + const fx_value *alias_v + = fx_hashtable_get(rt->rt_aliases, &FX_CSTR(callable_name)); if (alias_v) { fx_value_get_object(alias_v, &alias); bshell_command_ref(alias); @@ -82,10 +78,8 @@ bshell_command *bshell_runtime_find_command( fx_queue_entry *cur = fx_queue_last(&rt->rt_scope); while (cur) { - struct runtime_scope *scope = fx_unbox( - struct runtime_scope, - cur, - s_entry); + struct bshell_runtime_scope *scope + = fx_unbox(struct bshell_runtime_scope, cur, s_entry); const fx_value *func_v = fx_hashtable_get( scope->s_functions, &FX_CSTR(callable_name)); @@ -106,3 +100,17 @@ bshell_command *bshell_runtime_find_command( /* TODO find native executables */ return NULL; } + +struct bshell_runtime_scope *bshell_runtime_get_current_scope( + struct bshell_runtime *rt) +{ + return runtime_get_scope(rt); +} + +struct bshell_runtime_scope *bshell_runtime_get_parent_scope( + struct bshell_runtime *rt, + struct bshell_runtime_scope *scope) +{ + fx_queue_entry *parent = fx_queue_prev(&scope->s_entry); + return fx_unbox(struct bshell_runtime_scope, parent, s_entry); +} diff --git a/bshell/runtime/scope.c b/bshell.runtime/runtime/scope.c similarity index 60% rename from bshell/runtime/scope.c rename to bshell.runtime/runtime/scope.c index 8e70ab4..682a362 100644 --- a/bshell/runtime/scope.c +++ b/bshell.runtime/runtime/scope.c @@ -1,17 +1,16 @@ #include "scope.h" -#include "runtime.h" - +#include #include #include #include -struct runtime_scope *runtime_push_scope( +struct bshell_runtime_scope *runtime_push_scope( struct bshell_runtime *rt, - enum runtime_scope_type type, + enum bshell_runtime_scope_type type, bshell_scriptblock *block) { - struct runtime_scope *out = malloc(sizeof *out); + struct bshell_runtime_scope *out = malloc(sizeof *out); if (!out) { return NULL; } @@ -22,7 +21,7 @@ struct runtime_scope *runtime_push_scope( out->s_functions = fx_hashtable_create(); if (block) { - runtime_scope_set_block(out, block); + bshell_runtime_scope_set_block(out, block); } fx_queue_push_back(&rt->rt_scope, &out->s_entry); @@ -36,27 +35,25 @@ void runtime_pop_scope(struct bshell_runtime *rt) return; } - struct runtime_scope *scope = fx_unbox( - struct runtime_scope, - entry, - s_entry); + struct bshell_runtime_scope *scope + = fx_unbox(struct bshell_runtime_scope, entry, s_entry); /* TODO */ fx_hashtable_unref(scope->s_functions); free(scope); } -struct runtime_scope *runtime_get_scope(struct bshell_runtime *rt) +struct bshell_runtime_scope *runtime_get_scope(struct bshell_runtime *rt) { fx_queue_entry *entry = fx_queue_last(&rt->rt_scope); if (!entry) { return NULL; } - return fx_unbox(struct runtime_scope, entry, s_entry); + return fx_unbox(struct bshell_runtime_scope, entry, s_entry); } -void runtime_scope_push_value( - struct runtime_scope *scope, +void bshell_runtime_scope_push_value( + struct bshell_runtime_scope *scope, const fx_value *value) { fx_value *slot = fx_vector_emplace_back(scope->s_stack, NULL); @@ -67,7 +64,7 @@ void runtime_scope_push_value( fx_value_copy(slot, value); } -fx_value runtime_scope_pop_value(struct runtime_scope *scope) +fx_value bshell_runtime_scope_pop_value(struct bshell_runtime_scope *scope) { if (scope->s_stack.count == 0) { return FX_VALUE_EMPTY; @@ -78,8 +75,8 @@ fx_value runtime_scope_pop_value(struct runtime_scope *scope) return v; } -void runtime_scope_set_block( - struct runtime_scope *scope, +void bshell_runtime_scope_set_block( + struct bshell_runtime_scope *scope, bshell_scriptblock *block) { scope->s_block = block; @@ -87,3 +84,9 @@ void runtime_scope_set_block( bshell_scriptblock_get_text(block, &scope->s_instr, &scope->s_nr_instr); bshell_scriptblock_get_pool(block, &scope->s_pool, &scope->s_nr_pool); } + +fx_hashtable *bshell_runtime_scope_get_functions( + struct bshell_runtime_scope *scope) +{ + return scope->s_functions; +} diff --git a/bshell/runtime/scope.h b/bshell.runtime/runtime/scope.h similarity index 51% rename from bshell/runtime/scope.h rename to bshell.runtime/runtime/scope.h index f92cd8d..5fe3d5f 100644 --- a/bshell/runtime/scope.h +++ b/bshell.runtime/runtime/scope.h @@ -1,9 +1,9 @@ -#ifndef RUNTIME_SCOPE_H_ -#define RUNTIME_SCOPE_H_ +#ifndef BSHELL_RUNTIME_SCOPE_H_ +#define BSHELL_RUNTIME_SCOPE_H_ -#include "../script-block.h" #include "var-map.h" +#include #include #include #include @@ -11,14 +11,14 @@ struct bshell_runtime; -enum runtime_scope_type { +enum bshell_runtime_scope_type { RUNTIME_SCOPE_OTHER = 0, RUNTIME_SCOPE_SCRIPT, RUNTIME_SCOPE_GLOBAL, }; -struct runtime_scope { - enum runtime_scope_type s_type; +struct bshell_runtime_scope { + enum bshell_runtime_scope_type s_type; fx_queue_entry s_entry; struct var_map s_vars; fx_hashtable *s_functions; @@ -32,20 +32,20 @@ struct runtime_scope { size_t s_nr_pool; }; -extern struct runtime_scope *runtime_push_scope( +extern struct bshell_runtime_scope *runtime_push_scope( struct bshell_runtime *rt, - enum runtime_scope_type type, + enum bshell_runtime_scope_type type, bshell_scriptblock *block); extern void runtime_pop_scope(struct bshell_runtime *rt); -extern struct runtime_scope *runtime_get_scope(struct bshell_runtime *rt); +extern struct bshell_runtime_scope *runtime_get_scope(struct bshell_runtime *rt); -extern void runtime_scope_push_value( - struct runtime_scope *scope, +extern void bshell_runtime_scope_push_value( + struct bshell_runtime_scope *scope, const fx_value *value); -extern fx_value runtime_scope_pop_value(struct runtime_scope *scope); +extern fx_value bshell_runtime_scope_pop_value(struct bshell_runtime_scope *scope); -extern void runtime_scope_set_block( - struct runtime_scope *scope, +extern void bshell_runtime_scope_set_block( + struct bshell_runtime_scope *scope, bshell_scriptblock *block); #endif diff --git a/bshell/runtime/var-map.c b/bshell.runtime/runtime/var-map.c similarity index 100% rename from bshell/runtime/var-map.c rename to bshell.runtime/runtime/var-map.c diff --git a/bshell/runtime/var-map.h b/bshell.runtime/runtime/var-map.h similarity index 72% rename from bshell/runtime/var-map.h rename to bshell.runtime/runtime/var-map.h index d24fff8..cbd96e8 100644 --- a/bshell/runtime/var-map.h +++ b/bshell.runtime/runtime/var-map.h @@ -1,8 +1,8 @@ -#ifndef RUNTIME_VAR_MAP_H_ -#define RUNTIME_VAR_MAP_H_ +#ifndef BSHELL_RUNTIME_VAR_MAP_H_ +#define BSHELL_RUNTIME_VAR_MAP_H_ -#include "../status.h" -#include "var.h" +#include +#include struct var_map_entry { bshell_variable *e_var; diff --git a/bshell/runtime/var.c b/bshell.runtime/runtime/var.c similarity index 94% rename from bshell/runtime/var.c rename to bshell.runtime/runtime/var.c index cc6ccd0..0a12868 100644 --- a/bshell/runtime/var.c +++ b/bshell.runtime/runtime/var.c @@ -1,5 +1,4 @@ -#include "var.h" - +#include #include #include #include @@ -43,9 +42,8 @@ bshell_variable *bshell_variable_create(const char *name) return NULL; } - struct bshell_variable_p *p = fx_object_get_private( - var, - BSHELL_TYPE_VARIABLE); + struct bshell_variable_p *p + = fx_object_get_private(var, BSHELL_TYPE_VARIABLE); p->var_name = fx_strdup(name); if (!p->var_name) { diff --git a/bshell/script-block.c b/bshell.runtime/script-block.c similarity index 98% rename from bshell/script-block.c rename to bshell.runtime/script-block.c index 13443fa..6800529 100644 --- a/bshell/script-block.c +++ b/bshell.runtime/script-block.c @@ -1,7 +1,5 @@ -#include "script-block.h" - -#include "status.h" - +#include +#include #include #include #include @@ -348,7 +346,7 @@ FX_TYPE_CLASS_END(bshell_scriptblock) FX_TYPE_DEFINITION_BEGIN(bshell_scriptblock) FX_TYPE_ID(0x02b87313, 0x83f6, 0x4a57, 0xa573, 0x62cf492391ce); - FX_TYPE_NAME("bshell.scriptblock"); + FX_TYPE_NAME("bshell.runtime.scriptblock"); FX_TYPE_CLASS(bshell_scriptblock_class); FX_TYPE_INSTANCE_PRIVATE(struct bshell_scriptblock_p); FX_TYPE_INSTANCE_FINI(scriptblock_fini); diff --git a/bshell/status.c b/bshell.runtime/status.c similarity index 92% rename from bshell/status.c rename to bshell.runtime/status.c index 662c383..f489c8a 100644 --- a/bshell/status.c +++ b/bshell.runtime/status.c @@ -1,5 +1,4 @@ -#include "status.h" - +#include #include enum bshell_status bshell_status_from_errno(int err) diff --git a/bshell/verb.c b/bshell.runtime/verb.c similarity index 99% rename from bshell/verb.c rename to bshell.runtime/verb.c index 1beb445..3135d39 100644 --- a/bshell/verb.c +++ b/bshell.runtime/verb.c @@ -1,7 +1,5 @@ -#include "verb.h" - -#include "status.h" - +#include +#include #include #include #include diff --git a/bshell/CMakeLists.txt b/bshell/CMakeLists.txt new file mode 100644 index 0000000..a82d605 --- /dev/null +++ b/bshell/CMakeLists.txt @@ -0,0 +1,30 @@ +set(source_dirs + ast compile parse parse/lex parse/syntax + runtime format command cmdlets aliases) + +if (bshell_interactive EQUAL 1) + message(STATUS "Interactive support: Enabled") + set(source_dirs ${source_dirs} line-ed) +else () + message(STATUS "Interactive support: Disabled") +endif () + +file(GLOB bshell_sources + *.c + *.h) + +foreach (d ${source_dirs}) + file(GLOB sources + ${d}/*.c + ${d}/*.h) + set(bshell_sources ${bshell_sources} ${sources}) +endforeach (d) + +add_executable(bshell ${bshell_sources}) + +target_link_libraries(bshell + bshell.core bshell.runtime + FX::Runtime FX::Collections FX::Term) +target_compile_definitions(bshell PUBLIC + BSHELL_VERSION="${bshell_version}" + BSHELL_INTERACTIVE=${bshell_interactive}) diff --git a/bshell/assembly.c b/bshell/assembly.c index 34094fc..ff51590 100644 --- a/bshell/assembly.c +++ b/bshell/assembly.c @@ -4,21 +4,4 @@ FX_ASSEMBLY_BEGIN(bshell) FX_ASSEMBLY_NAME("bshell"); FX_ASSEMBLY_VERSION(0, 1, 0, 0); - FX_ASSEMBLY_EXPORT_TYPE("bshell", "cmdlet", bshell_cmdlet); - FX_ASSEMBLY_EXPORT_TYPE("bshell", "scriptblock", bshell_scriptblock); - FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "get_verb", bshell_get_verb); - FX_ASSEMBLY_EXPORT_TYPE( - "bshell.core", - "write_output", - bshell_write_output); - FX_ASSEMBLY_EXPORT_TYPE( - "bshell.core", - "foreach_object", - bshell_foreach_object); - FX_ASSEMBLY_EXPORT_TYPE( - "bshell.core", - "get_command", - bshell_get_command); - FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "percent", bshell_percent); - FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "echo", bshell_echo); FX_ASSEMBLY_END(bshell) diff --git a/bshell/ast/array.c b/bshell/ast/array.c deleted file mode 100644 index 7eaa59e..0000000 --- a/bshell/ast/array.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct array_ast_node *array = (struct array_ast_node *)node; - - fx_queue_entry *cur = fx_queue_first(&array->n_items); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition array_ast_node = { - .def_id = AST_ARRAY, - .def_node_size = sizeof(struct array_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/ast.c b/bshell/ast/ast.c deleted file mode 100644 index f887a17..0000000 --- a/bshell/ast/ast.c +++ /dev/null @@ -1,270 +0,0 @@ -#include "ast.h" - -#include "../status.h" - -#include -#include -#include - -extern struct ast_node_definition null_ast_node; -extern struct ast_node_definition int_ast_node; -extern struct ast_node_definition double_ast_node; -extern struct ast_node_definition word_ast_node; -extern struct ast_node_definition var_ast_node; -extern struct ast_node_definition string_ast_node; -extern struct ast_node_definition fstring_ast_node; -extern struct ast_node_definition cmdcall_ast_node; -extern struct ast_node_definition pipeline_ast_node; -extern struct ast_node_definition redirection_ast_node; -extern struct ast_node_definition block_ast_node; -extern struct ast_node_definition stmt_list_ast_node; -extern struct ast_node_definition func_ast_node; -extern struct ast_node_definition array_ast_node; -extern struct ast_node_definition hashtable_ast_node; -extern struct ast_node_definition hashtable_item_ast_node; -extern struct ast_node_definition if_ast_node; -extern struct ast_node_definition if_branch_ast_node; -extern struct ast_node_definition op_ast_node; - -static const struct ast_node_definition *ast_node_definitions[] = { - [AST_NULL] = &null_ast_node, - [AST_INT] = &int_ast_node, - [AST_DOUBLE] = &double_ast_node, - [AST_WORD] = &word_ast_node, - [AST_VAR] = &var_ast_node, - [AST_STRING] = &string_ast_node, - [AST_FSTRING] = &fstring_ast_node, - [AST_CMDCALL] = &cmdcall_ast_node, - [AST_PIPELINE] = &pipeline_ast_node, - [AST_REDIRECTION] = &redirection_ast_node, - [AST_BLOCK] = &block_ast_node, - [AST_STMT_LIST] = &stmt_list_ast_node, - [AST_FUNC] = &func_ast_node, - [AST_ARRAY] = &array_ast_node, - [AST_IF] = &if_ast_node, - [AST_IF_BRANCH] = &if_branch_ast_node, - [AST_HASHTABLE] = &hashtable_ast_node, - [AST_HASHTABLE_ITEM] = &hashtable_item_ast_node, - [AST_OP] = &op_ast_node, -}; -static const size_t nr_ast_node_definitions = sizeof ast_node_definitions - / sizeof ast_node_definitions[0]; - -struct ast_node *ast_node_create(enum ast_node_type type) -{ - assert(type < nr_ast_node_definitions); - - const struct ast_node_definition *def = ast_node_definitions[type]; - struct ast_node *out = malloc(def->def_node_size); - if (!out) { - return NULL; - } - - memset(out, 0x0, def->def_node_size); - - out->n_type = type; - - return out; -} - -void ast_node_destroy(struct ast_node *node) -{ - assert(node->n_type < nr_ast_node_definitions); - - struct ast_iterator it = {0}; - ast_iterator_enqueue(&it, node); - - while (1) { - node = ast_iterator_peek(&it); - if (!node) { - break; - } - - const struct ast_node_definition *def = ast_node_definitions - [node->n_type]; - - if (def->def_cleanup) { - def->def_cleanup(node); - } - - ast_iterator_dequeue(&it); - free(node); - } -} - -void ast_node_to_string(const struct ast_node *node, fx_bstr *out) -{ - const struct ast_node_definition *def = ast_node_definitions - [node->n_type]; - if (def->def_to_string) { - def->def_to_string(node, out); - } -} - -#define ENUM_STR(x) \ - case x: \ - return #x - -const char *ast_node_type_to_string(enum ast_node_type type) -{ - switch (type) { - ENUM_STR(AST_NONE); - ENUM_STR(AST_NULL); - ENUM_STR(AST_STMT_LIST); - ENUM_STR(AST_INT); - ENUM_STR(AST_DOUBLE); - ENUM_STR(AST_WORD); - ENUM_STR(AST_STRING); - ENUM_STR(AST_FSTRING); - ENUM_STR(AST_VAR); - ENUM_STR(AST_VAR_SPLAT); - ENUM_STR(AST_FLAG); - ENUM_STR(AST_CMDCALL); - ENUM_STR(AST_PIPELINE); - ENUM_STR(AST_REDIRECTION); - ENUM_STR(AST_BLOCK); - ENUM_STR(AST_FUNC); - ENUM_STR(AST_IF); - ENUM_STR(AST_IF_BRANCH); - ENUM_STR(AST_OP); - ENUM_STR(AST_ARRAY); - ENUM_STR(AST_HASHTABLE); - ENUM_STR(AST_HASHTABLE_ITEM); - default: - return ""; - } -} - -struct ast_node *ast_iterator_peek(struct ast_iterator *it) -{ - fx_queue_entry *cur = fx_queue_first(&it->it_queue); - if (!cur) { - return NULL; - } - - return fx_unbox(struct ast_node, cur, n_it.e_entry); -} - -struct ast_node *ast_iterator_dequeue(struct ast_iterator *it) -{ - fx_queue_entry *cur = fx_queue_first(&it->it_queue); - if (!cur) { - return NULL; - } - - struct ast_node *node = fx_unbox(struct ast_node, cur, n_it.e_entry); - const struct ast_node_definition *def = ast_node_definitions - [node->n_type]; - - it->it_insert_after = cur; - if (def->def_collect_children) { - def->def_collect_children(node, it); - } - - fx_queue_pop_front(&it->it_queue); - return fx_unbox(struct ast_node, cur, n_it.e_entry); -} - -void ast_iterator_enqueue(struct ast_iterator *it, struct ast_node *node) -{ - unsigned long new_depth = 0; - - fx_queue_entry *cur = fx_queue_first(&it->it_queue); - if (cur) { - struct ast_node *cur_node = fx_unbox( - struct ast_node, - cur, - n_it.e_entry); - new_depth = cur_node->n_it.e_depth + 1; - } - - node->n_it.e_depth = new_depth; - - if (!it->it_insert_after) { - fx_queue_push_back(&it->it_queue, &node->n_it.e_entry); - return; - } - - fx_queue_insert_after( - &it->it_queue, - &node->n_it.e_entry, - it->it_insert_after); - it->it_insert_after = &node->n_it.e_entry; -} - -enum bshell_status ast_node_iterate( - struct ast_node *node, - struct ast_iterator *it, - ast_iterator_callback callback, - void *arg) -{ - fx_queue_push_back(&it->it_queue, &node->n_it.e_entry); - node->n_it.e_depth = 0; - - fx_queue_entry *entry = fx_queue_first(&it->it_queue); - - while (entry) { - struct ast_iterator_entry *it_entry = fx_unbox( - struct ast_iterator_entry, - entry, - e_entry); - node = fx_unbox(struct ast_node, it_entry, n_it); - - if (!node) { - /* this should never happen. */ - return BSHELL_ERR_INTERNAL_FAILURE; - } - - struct ast_iterate_result result = callback( - node, - AST_ITERATION_PRE, - it, - arg); - if (result.r_status != BSHELL_SUCCESS - || result.r_flags & AST_ITERATE_STOP) { - return result.r_status; - } - - const struct ast_node_definition *type = ast_node_definitions - [node->n_type]; - if (type->def_collect_children - && result.r_flags & AST_ITERATE_ADD_CHILDREN) { - it->it_insert_after = entry; - type->def_collect_children(node, it); - } - - if (!(result.r_flags & AST_ITERATE_REPEAT)) { - entry = fx_queue_next(entry); - } - } - - while (!fx_queue_empty(&it->it_queue)) { - fx_queue_entry *entry = fx_queue_last(&it->it_queue); - if (!entry) { - break; - } - - node = fx_unbox(struct ast_node, entry, n_it); - - if (!node) { - /* this should never happen. */ - return BSHELL_ERR_INTERNAL_FAILURE; - } - - struct ast_iterate_result result = callback( - node, - AST_ITERATION_POST, - it, - arg); - if (result.r_status != BSHELL_SUCCESS - || result.r_flags & AST_ITERATE_STOP) { - return result.r_status; - } - - if (!(result.r_flags & AST_ITERATE_REPEAT)) { - fx_queue_pop_back(&it->it_queue); - } - } - - return BSHELL_SUCCESS; -} diff --git a/bshell/ast/ast.h b/bshell/ast/ast.h deleted file mode 100644 index 447aabb..0000000 --- a/bshell/ast/ast.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef AST_H_ -#define AST_H_ - -#include "../status.h" - -#include -#include - -struct lex_token; - -#define AST_ITERATE_OK(flags) \ - ((struct ast_iterate_result) {.r_status = BSHELL_SUCCESS, \ - .r_flags = (flags)}) -#define AST_ITERATE_ERR(status) \ - ((struct ast_iterate_result) {.r_status = (status)}) - -enum ast_node_type { - AST_NONE = 0x00u, - AST_NULL, - AST_STMT_LIST, - AST_INT, - AST_DOUBLE, - AST_WORD, - AST_STRING, - AST_FSTRING, - AST_VAR, - AST_VAR_SPLAT, - AST_FLAG, - AST_CMDCALL, - AST_FUNCALL, - AST_PIPELINE, - AST_REDIRECTION, - AST_BLOCK, - AST_FUNC, - AST_ARRAY, - AST_HASHTABLE, - AST_HASHTABLE_ITEM, - AST_OP, - AST_IF, - AST_IF_BRANCH, -}; - -struct ast_iterator_entry { - fx_queue_entry e_entry; - unsigned long e_depth; -}; - -struct ast_node { - enum ast_node_type n_type; - struct ast_node *n_parent; - fx_queue_entry n_entry; - struct ast_iterator_entry n_it; -}; - -struct null_ast_node { - struct ast_node n_base; -}; - -struct int_ast_node { - struct ast_node n_base; - struct lex_token *n_value; -}; - -struct double_ast_node { - struct ast_node n_base; - struct lex_token *n_value; -}; - -struct word_ast_node { - struct ast_node n_base; - struct lex_token *n_value; -}; - -struct string_ast_node { - struct ast_node n_base; - struct lex_token *n_value; -}; - -struct fstring_ast_node { - struct ast_node n_base; - fx_queue n_elements; -}; - -struct var_ast_node { - struct ast_node n_base; - struct lex_token *n_ident; -}; - -struct var_splat_ast_node { - struct ast_node n_base; - struct lex_token *n_ident; -}; - -struct cmdcall_ast_node { - struct ast_node n_base; - fx_queue n_args; - fx_queue n_redirect; -}; - -struct funcall_ast_node { - struct ast_node n_base; - struct ast_node *n_func; - fx_queue n_args; -}; - -struct pipeline_ast_node { - struct ast_node n_base; - fx_queue n_stages; -}; - -struct redirection_ast_node { - struct ast_node n_base; - bool n_append : 1; - bool n_out_is_fd : 1; - bool n_out_is_expr : 1; - - unsigned int n_in, n_out; - struct ast_node *n_out_path_expr; - const char *n_out_path; - struct lex_token *n_out_tok; -}; - -struct stmt_list_ast_node { - struct ast_node n_base; - fx_queue n_statements; -}; - -struct block_ast_node { - struct ast_node n_base; - fx_queue n_statements; -}; - -struct func_ast_node { - struct ast_node n_base; - struct lex_token *n_name; - fx_queue n_params; - struct ast_node *n_body; -}; - -struct array_ast_node { - struct ast_node n_base; - fx_queue n_items; -}; - -struct hashtable_ast_node { - struct ast_node n_base; - fx_queue n_items; -}; - -struct hashtable_item_ast_node { - struct ast_node n_base; - struct ast_node *n_key, *n_value; -}; - -struct op_ast_node { - struct ast_node n_base; - const struct operator_info *n_op; - struct ast_node *n_left, *n_right; -}; - -struct if_branch_ast_node { - struct ast_node n_base; - struct ast_node *n_cond; - struct ast_node *n_body; -}; - -struct if_ast_node { - struct ast_node n_base; - fx_queue n_branches; -}; - -struct ast_iterator { - struct ast_node *it_cur; - fx_queue it_queue; - unsigned int it_depth; - fx_queue_entry *it_insert_after; -}; - -struct ast_iterate_result { - enum bshell_status r_status; - enum { - AST_ITERATE_CONTINUE = 0x00u, - AST_ITERATE_STOP = 0x01u, - AST_ITERATE_ADD_CHILDREN = 0x02u, - AST_ITERATE_REPEAT = 0x04u, - } r_flags; -}; - -enum ast_iteration_type { - AST_ITERATION_PRE, - AST_ITERATION_POST, -}; - -typedef struct ast_iterate_result (*ast_iterator_callback)( - struct ast_node *, - enum ast_iteration_type, - struct ast_iterator *, - void *); - -struct ast_node_definition { - enum ast_node_type def_id; - size_t def_node_size; - enum bshell_status (*def_collect_children)( - struct ast_node *, - struct ast_iterator *); - enum bshell_status (*def_cleanup)(struct ast_node *); - void (*def_to_string)(const struct ast_node *, fx_bstr *); -}; - -extern struct ast_node *ast_node_create(enum ast_node_type type); -extern void ast_node_destroy(struct ast_node *node); -extern void ast_node_to_string(const struct ast_node *node, fx_bstr *out); -extern enum bshell_status ast_node_iterate( - struct ast_node *node, - struct ast_iterator *it, - ast_iterator_callback callback, - void *arg); - -extern const char *ast_node_type_to_string(enum ast_node_type type); - -extern struct ast_node *ast_iterator_peek(struct ast_iterator *it); -extern struct ast_node *ast_iterator_dequeue(struct ast_iterator *it); -extern void ast_iterator_enqueue( - struct ast_iterator *it, - struct ast_node *node); - -#endif diff --git a/bshell/ast/block.c b/bshell/ast/block.c deleted file mode 100644 index 90681e3..0000000 --- a/bshell/ast/block.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct block_ast_node *block = (struct block_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&block->n_statements); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition block_ast_node = { - .def_id = AST_BLOCK, - .def_node_size = sizeof(struct block_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/cmdcall.c b/bshell/ast/cmdcall.c deleted file mode 100644 index b895843..0000000 --- a/bshell/ast/cmdcall.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&cmdcall->n_args); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - cur = fx_queue_first(&cmdcall->n_redirect); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition cmdcall_ast_node = { - .def_id = AST_CMDCALL, - .def_node_size = sizeof(struct cmdcall_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/double.c b/bshell/ast/double.c deleted file mode 100644 index d3a70bb..0000000 --- a/bshell/ast/double.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -#include - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - struct double_ast_node *i = (struct double_ast_node *)node; - fx_value_to_string(&i->n_value->tok_number, (fx_stream *)out, NULL); -} - -struct ast_node_definition double_ast_node = { - .def_id = AST_DOUBLE, - .def_node_size = sizeof(struct double_ast_node), - .def_to_string = to_string, -}; diff --git a/bshell/ast/fstring.c b/bshell/ast/fstring.c deleted file mode 100644 index 894ba18..0000000 --- a/bshell/ast/fstring.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct fstring_ast_node *fstring = (struct fstring_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&fstring->n_elements); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition fstring_ast_node = { - .def_id = AST_FSTRING, - .def_node_size = sizeof(struct fstring_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/func.c b/bshell/ast/func.c deleted file mode 100644 index 61c53a6..0000000 --- a/bshell/ast/func.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct func_ast_node *func = (struct func_ast_node *)node; - - fx_queue_entry *cur = fx_queue_first(&func->n_params); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - if (func->n_body) { - ast_iterator_enqueue(it, func->n_body); - } - - return BSHELL_SUCCESS; -} - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - const struct func_ast_node *func = (const struct func_ast_node *)node; - fx_bstr_write_fmt(out, NULL, "%s", func->n_name->tok_str); -} - -struct ast_node_definition func_ast_node = { - .def_id = AST_FUNC, - .def_node_size = sizeof(struct func_ast_node), - .def_collect_children = collect_children, - .def_to_string = to_string, -}; diff --git a/bshell/ast/hashtable-item.c b/bshell/ast/hashtable-item.c deleted file mode 100644 index 64cd17c..0000000 --- a/bshell/ast/hashtable-item.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct hashtable_item_ast_node *item - = (struct hashtable_item_ast_node *)node; - - if (item->n_key) { - ast_iterator_enqueue(it, item->n_key); - } - - if (item->n_value) { - ast_iterator_enqueue(it, item->n_value); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition hashtable_item_ast_node = { - .def_id = AST_HASHTABLE_ITEM, - .def_node_size = sizeof(struct hashtable_item_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/hashtable.c b/bshell/ast/hashtable.c deleted file mode 100644 index ab2f612..0000000 --- a/bshell/ast/hashtable.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct hashtable_ast_node *hashtable - = (struct hashtable_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&hashtable->n_items); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition hashtable_ast_node = { - .def_id = AST_HASHTABLE, - .def_node_size = sizeof(struct hashtable_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/if-branch.c b/bshell/ast/if-branch.c deleted file mode 100644 index d121bb7..0000000 --- a/bshell/ast/if-branch.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct if_branch_ast_node *if_branch - = (struct if_branch_ast_node *)node; - if (if_branch->n_cond) { - ast_iterator_enqueue(it, if_branch->n_cond); - } - - if (if_branch->n_body) { - ast_iterator_enqueue(it, if_branch->n_body); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition if_branch_ast_node = { - .def_id = AST_IF_BRANCH, - .def_node_size = sizeof(struct if_branch_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/if.c b/bshell/ast/if.c deleted file mode 100644 index db44b86..0000000 --- a/bshell/ast/if.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct if_ast_node *if_group = (struct if_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&if_group->n_branches); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition if_ast_node = { - .def_id = AST_IF, - .def_node_size = sizeof(struct if_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/int.c b/bshell/ast/int.c deleted file mode 100644 index 60eeca3..0000000 --- a/bshell/ast/int.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -#include - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - struct int_ast_node *i = (struct int_ast_node *)node; - fx_value_to_string(&i->n_value->tok_number, (fx_stream *)out, NULL); -} - -struct ast_node_definition int_ast_node = { - .def_id = AST_INT, - .def_node_size = sizeof(struct int_ast_node), - .def_to_string = to_string, -}; diff --git a/bshell/ast/null.c b/bshell/ast/null.c deleted file mode 100644 index e3f3b76..0000000 --- a/bshell/ast/null.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -struct ast_node_definition null_ast_node = { - .def_id = AST_NULL, - .def_node_size = sizeof(struct null_ast_node), -}; diff --git a/bshell/ast/op.c b/bshell/ast/op.c deleted file mode 100644 index 1c3023b..0000000 --- a/bshell/ast/op.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "../operator.h" -#include "../parse/token.h" -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct op_ast_node *op = (struct op_ast_node *)node; - - if (op->n_left) { - ast_iterator_enqueue(it, op->n_left); - } - - if (op->n_right) { - ast_iterator_enqueue(it, op->n_right); - } - - return BSHELL_SUCCESS; -} - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - const struct op_ast_node *op = (const struct op_ast_node *)node; - fx_bstr_write_fmt( - out, - NULL, - "%s", - operator_id_to_string(op->n_op->op_id)); -} - -struct ast_node_definition op_ast_node = { - .def_id = AST_OP, - .def_node_size = sizeof(struct op_ast_node), - .def_collect_children = collect_children, - .def_to_string = to_string, -}; diff --git a/bshell/ast/pipeline.c b/bshell/ast/pipeline.c deleted file mode 100644 index 25f432b..0000000 --- a/bshell/ast/pipeline.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&pipeline->n_stages); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition pipeline_ast_node = { - .def_id = AST_PIPELINE, - .def_node_size = sizeof(struct pipeline_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/stmt-list.c b/bshell/ast/stmt-list.c deleted file mode 100644 index bd98255..0000000 --- a/bshell/ast/stmt-list.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "ast.h" - -static enum bshell_status collect_children( - struct ast_node *node, - struct ast_iterator *it) -{ - struct stmt_list_ast_node *stmt_list - = (struct stmt_list_ast_node *)node; - fx_queue_entry *cur = fx_queue_first(&stmt_list->n_statements); - while (cur) { - struct ast_node *child - = fx_unbox(struct ast_node, cur, n_entry); - ast_iterator_enqueue(it, child); - cur = fx_queue_next(cur); - } - - return BSHELL_SUCCESS; -} - -struct ast_node_definition stmt_list_ast_node = { - .def_id = AST_STMT_LIST, - .def_node_size = sizeof(struct stmt_list_ast_node), - .def_collect_children = collect_children, -}; diff --git a/bshell/ast/string.c b/bshell/ast/string.c deleted file mode 100644 index dba76e4..0000000 --- a/bshell/ast/string.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - const struct string_ast_node *string - = (const struct string_ast_node *)node; - fx_bstr_write_fmt(out, NULL, "%s", string->n_value->tok_str); -} - -struct ast_node_definition string_ast_node = { - .def_id = AST_STRING, - .def_node_size = sizeof(struct string_ast_node), - .def_to_string = to_string, -}; diff --git a/bshell/ast/var.c b/bshell/ast/var.c deleted file mode 100644 index 75d7401..0000000 --- a/bshell/ast/var.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - const struct var_ast_node *var = (const struct var_ast_node *)node; - fx_bstr_write_fmt(out, NULL, "%s", var->n_ident->tok_str); -} - -struct ast_node_definition var_ast_node = { - .def_id = AST_VAR, - .def_node_size = sizeof(struct var_ast_node), - .def_to_string = to_string, -}; diff --git a/bshell/ast/word.c b/bshell/ast/word.c deleted file mode 100644 index af57db3..0000000 --- a/bshell/ast/word.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "../parse/token.h" -#include "ast.h" - -static void to_string(const struct ast_node *node, fx_bstr *out) -{ - const struct word_ast_node *word = (const struct word_ast_node *)node; - fx_bstr_write_fmt(out, NULL, "%s", word->n_value->tok_str); -} - -struct ast_node_definition word_ast_node = { - .def_id = AST_WORD, - .def_node_size = sizeof(struct word_ast_node), - .def_to_string = to_string, -}; diff --git a/bshell/compile.h b/bshell/compile.h deleted file mode 100644 index 28205ce..0000000 --- a/bshell/compile.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef COMPILE_H_ -#define COMPILE_H_ - -#include "script-block.h" - -struct ast_node; - -extern enum bshell_status bshell_compile( - struct ast_node *src, - bshell_scriptblock *dest); - -#endif diff --git a/bshell/compile/normal.c b/bshell/compile/normal.c deleted file mode 100644 index 4c52cd1..0000000 --- a/bshell/compile/normal.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "compile-node.h" - -static const compile_node_impl node_compilers[] = { - [AST_INT] = compile_int, - [AST_DOUBLE] = compile_double, - [AST_STRING] = compile_string, - [AST_WORD] = compile_word, - [AST_OP] = compile_op, - [AST_VAR] = compile_var, - [AST_FSTRING] = compile_fstring, - [AST_ARRAY] = compile_array, - [AST_HASHTABLE] = compile_hashtable, - [AST_HASHTABLE_ITEM] = compile_hashtable_item, - [AST_CMDCALL] = compile_cmdcall, - [AST_PIPELINE] = compile_pipeline, - [AST_BLOCK] = compile_block, -}; -static const size_t nr_node_compilers = sizeof node_compilers - / sizeof node_compilers[0]; - -const struct compile_state_type normal_state = { - .s_size = sizeof(struct compile_state), - .s_compile_node = node_compilers, - .s_nr_compile_node = nr_node_compilers, -}; diff --git a/bshell/compile/op.c b/bshell/compile/op.c deleted file mode 100644 index dc78062..0000000 --- a/bshell/compile/op.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "../operator.h" -#include "compile-node.h" - -static enum bshell_opcode opcode_for_op(enum operator_id op) -{ - switch (op) { - case OP_ADD: - return OPCODE_ADD; - case OP_SUBTRACT: - return OPCODE_SUB; - case OP_MULTIPLY: - return OPCODE_MUL; - case OP_DIVIDE: - return OPCODE_DIV; - case OP_MODULO: - return OPCODE_MOD; - case OP_INCREMENT: - return OPCODE_INC; - case OP_DECREMENT: - return OPCODE_DEC; - case OP_LEFT_SHIFT: - return OPCODE_SHL; - case OP_RIGHT_SHIFT: - return OPCODE_SHR; - case OP_BINARY_AND: - return OPCODE_BAND; - case OP_BINARY_OR: - return OPCODE_BOR; - case OP_BINARY_XOR: - return OPCODE_BXOR; - case OP_BINARY_NOT: - return OPCODE_BNOT; - case OP_LESS_THAN: - return OPCODE_CMP_LT; - case OP_GREATER_THAN: - return OPCODE_CMP_GT; - case OP_EQUAL: - return OPCODE_CMP_EQ; - case OP_NOT_EQUAL: - return OPCODE_CMP_NE; - case OP_LESS_EQUAL: - return OPCODE_CMP_LE; - case OP_GREATER_EQUAL: - return OPCODE_CMP_GE; - case OP_LOGICAL_AND: - return OPCODE_LAND; - case OP_LOGICAL_OR: - return OPCODE_LOR; - case OP_LOGICAL_XOR: - return OPCODE_LXOR; - case OP_LOGICAL_NOT: - return OPCODE_LNOT; - case OP_RANGE: - return OPCODE_RANGE; - case OP_MATCH: - return OPCODE_MATCH; - case OP_REPLACE: - return OPCODE_REPLACE; - case OP_LIKE: - return OPCODE_LIKE; - case OP_IN: - return OPCODE_IN; - case OP_FORMAT: - return OPCODE_FMT; - case OP_CONTAINS: - return OPCODE_CONTAINS; - case OP_USPLIT: - return OPCODE_SPLIT; - case OP_BSPLIT: - return OPCODE_SPLIT; - case OP_UJOIN: - return OPCODE_JOIN; - case OP_BJOIN: - return OPCODE_JOIN; - case OP_IS: - return OPCODE_IS; - case OP_AS: - return OPCODE_AS; - case OP_ACCESS: - return OPCODE_LDPROP; - default: - return OPCODE_NOP; - } -} - -enum bshell_status op_load(struct compile_ctx *ctx, struct compile_value *value) -{ - enum bshell_opcode opcode = opcode_for_op(value->v_op); - if (opcode != OPCODE_NOP) { - compile_value_load(ctx, value->v_right); - compile_value_load(ctx, value->v_left); - bshell_scriptblock_push_instruction( - ctx->c_block, - opcode_for_op(value->v_op), - 0); - return BSHELL_SUCCESS; - } - - switch (value->v_op) { - case OP_ASSIGN: - compile_value_load(ctx, value->v_right); - compile_value_store(ctx, value->v_left); - break; - default: - return BSHELL_ERR_NOT_SUPPORTED; - } - - return BSHELL_SUCCESS; -} - -static const struct compile_value_type op_type = { - .v_load = op_load, -}; - -struct compile_result compile_op(struct compile_ctx *ctx, struct ast_node *src) -{ - struct op_ast_node *op = (struct op_ast_node *)src; - struct compile_value *left = NULL, *right = NULL; - left = compile_pop_value(ctx); - right = compile_pop_value(ctx); - compile_push_op(ctx, src, &op_type, op->n_op->op_id, left, right); - return COMPILE_OK(0); -} diff --git a/bshell/debug.c b/bshell/debug.c index ffca468..aeaf8a8 100644 --- a/bshell/debug.c +++ b/bshell/debug.c @@ -1,15 +1,14 @@ #include "debug.h" -#include "ast/ast.h" -#include "parse/token.h" -#include "runtime/opcode.h" -#include "script-block.h" - +#include +#include +#include +#include #include #include #include -extern void print_lex_token(struct lex_token *tok) +extern void print_lex_token(struct bshell_lex_token *tok) { printf("[%lu:%lu - %lu:%lu] ", tok->tok_start.c_row, @@ -18,59 +17,60 @@ extern void print_lex_token(struct lex_token *tok) tok->tok_end.c_col); switch (tok->tok_type) { - case TOK_KEYWORD: + case BSHELL_TOK_KEYWORD: fx_puts("[magenta]"); break; - case TOK_SYMBOL: + case BSHELL_TOK_SYMBOL: fx_puts("[blue]"); break; - case TOK_INT: - case TOK_DOUBLE: - case TOK_VAR: - case TOK_VAR_SPLAT: + case BSHELL_TOK_INT: + case BSHELL_TOK_DOUBLE: + case BSHELL_TOK_VAR: + case BSHELL_TOK_VAR_SPLAT: fx_puts("[yellow]"); break; - case TOK_OPERATOR: + case BSHELL_TOK_OPERATOR: fx_puts("[red]"); break; - case TOK_WORD: - case TOK_WORD_START: - case TOK_WORD_END: + case BSHELL_TOK_WORD: + case BSHELL_TOK_WORD_START: + case BSHELL_TOK_WORD_END: fx_puts("[cyan]"); break; - case TOK_STRING: - case TOK_STR_START: - case TOK_STR_END: + case BSHELL_TOK_STRING: + case BSHELL_TOK_STR_START: + case BSHELL_TOK_STR_END: fx_puts("[green]"); break; - case TOK_LINEFEED: + case BSHELL_TOK_LINEFEED: fx_puts("[dark_grey]"); break; default: break; } - fx_puts(token_type_to_string(tok->tok_type)); + fx_puts(bshell_token_type_to_string(tok->tok_type)); switch (tok->tok_type) { - case TOK_WORD: - case TOK_FLAG: - case TOK_STRING: - case TOK_VAR: - case TOK_VAR_SPLAT: + case BSHELL_TOK_WORD: + case BSHELL_TOK_FLAG: + case BSHELL_TOK_STRING: + case BSHELL_TOK_VAR: + case BSHELL_TOK_VAR_SPLAT: printf("(%s)", tok->tok_str); break; - case TOK_OPERATOR: - printf("(%s)", token_operator_to_string(tok->tok_operator)); + case BSHELL_TOK_OPERATOR: + printf("(%s)", + bshell_lex_operator_to_string(tok->tok_operator)); break; - case TOK_SYMBOL: - printf("(%s)", token_symbol_to_string(tok->tok_symbol)); + case BSHELL_TOK_SYMBOL: + printf("(%s)", bshell_lex_symbol_to_string(tok->tok_symbol)); break; - case TOK_KEYWORD: - printf("(%s)", token_keyword_to_string(tok->tok_keyword)); + case BSHELL_TOK_KEYWORD: + printf("(%s)", bshell_lex_keyword_to_string(tok->tok_keyword)); break; - case TOK_INT: - case TOK_DOUBLE: + case BSHELL_TOK_INT: + case BSHELL_TOK_DOUBLE: printf("("); fx_value_to_string(&tok->tok_number, fx_stdout, NULL); printf(")"); @@ -82,54 +82,54 @@ extern void print_lex_token(struct lex_token *tok) fx_puts("[reset]\n"); } -void print_ast_node(struct ast_node *node) +void print_ast_node(struct bshell_ast_node *node) { for (unsigned long i = 0; i < node->n_it.e_depth; i++) { fx_puts(" "); } switch (node->n_type) { - case AST_IF: - case AST_IF_BRANCH: - case AST_BLOCK: - case AST_FUNC: - case AST_STMT_LIST: + case BSHELL_AST_IF: + case BSHELL_AST_IF_BRANCH: + case BSHELL_AST_BLOCK: + case BSHELL_AST_FUNC: + case BSHELL_AST_STMT_LIST: fx_puts("[magenta]"); break; - case AST_REDIRECTION: - case AST_PIPELINE: - case AST_OP: - case AST_ARRAY: - case AST_HASHTABLE: - case AST_HASHTABLE_ITEM: + case BSHELL_AST_REDIRECTION: + case BSHELL_AST_PIPELINE: + case BSHELL_AST_OP: + case BSHELL_AST_ARRAY: + case BSHELL_AST_HASHTABLE: + case BSHELL_AST_HASHTABLE_ITEM: fx_puts("[blue]"); break; - case AST_CMDCALL: - case AST_NULL: + case BSHELL_AST_CMDCALL: + case BSHELL_AST_NULL: fx_puts("[red]"); break; - case AST_INT: - case AST_DOUBLE: - case AST_VAR: + case BSHELL_AST_INT: + case BSHELL_AST_DOUBLE: + case BSHELL_AST_VAR: fx_puts("[yellow]"); break; - case AST_WORD: + case BSHELL_AST_WORD: fx_puts("[cyan]"); break; - case AST_STRING: - case AST_FSTRING: + case BSHELL_AST_STRING: + case BSHELL_AST_FSTRING: fx_puts("[green]"); break; default: break; } - fx_printf("%s", ast_node_type_to_string(node->n_type)); + fx_printf("%s", bshell_ast_node_type_to_string(node->n_type)); char s[128] = {0}; fx_bstr str; fx_bstr_begin(&str, s, sizeof s); - ast_node_to_string(node, &str); + bshell_ast_node_to_string(node, &str); if (fx_bstr_get_size(&str)) { fx_printf("(%s)", fx_bstr_end(&str)); @@ -138,19 +138,19 @@ void print_ast_node(struct ast_node *node) fx_printf("[reset]\n"); } -void print_ast_node_recursive(struct ast_node *node) +void print_ast_node_recursive(struct bshell_ast_node *node) { - struct ast_iterator it = {0}; - ast_iterator_enqueue(&it, node); + struct bshell_ast_iterator it = {0}; + bshell_ast_iterator_enqueue(&it, node); while (1) { - node = ast_iterator_peek(&it); + node = bshell_ast_iterator_peek(&it); if (!node) { break; } print_ast_node(node); - ast_iterator_dequeue(&it); + bshell_ast_iterator_dequeue(&it); } } @@ -188,10 +188,10 @@ void print_instruction( fx_printf("%08x [blue]", instr); switch (opcode) { - case OPCODE_LDC_INT: + case BSHELL_OPCODE_LDC_INT: fx_printf("ldc.int [yellow]#0x%02x", arg); break; - case OPCODE_LDC_FP: + case BSHELL_OPCODE_LDC_FP: pool_value = bshell_scriptblock_get_pool_value( container, arg, @@ -205,7 +205,7 @@ void print_instruction( } break; - case OPCODE_LDC_STR: + case BSHELL_OPCODE_LDC_STR: pool_value = bshell_scriptblock_get_pool_value( container, arg, @@ -225,10 +225,10 @@ void print_instruction( } break; - case OPCODE_LDGLOBAL: + case BSHELL_OPCODE_LDGLOBAL: fx_printf("ldglobal [cyan]@0x%02x", arg); break; - case OPCODE_LDBLOCK: + case BSHELL_OPCODE_LDBLOCK: pool_value = bshell_scriptblock_get_pool_value( container, arg, @@ -243,7 +243,7 @@ void print_instruction( } break; - case OPCODE_LDLOCAL: + case BSHELL_OPCODE_LDLOCAL: pool_value = bshell_scriptblock_get_pool_value( container, arg, @@ -263,25 +263,25 @@ void print_instruction( } break; - case OPCODE_LDENV: + case BSHELL_OPCODE_LDENV: fx_printf("ldenv [cyan]@0x%02x", arg); break; - case OPCODE_LDSTATIC: + case BSHELL_OPCODE_LDSTATIC: fx_printf("ldstatic [cyan]@0x%02x", arg); break; - case OPCODE_LDARG: + case BSHELL_OPCODE_LDARG: fx_printf("ldarg [cyan]@0x%02x", arg); break; - case OPCODE_LDPROP: + case BSHELL_OPCODE_LDPROP: fx_printf("ldprop"); break; - case OPCODE_LDELEM: + case BSHELL_OPCODE_LDELEM: fx_printf("ldelem [cyan]@0x%02x", arg); break; - case OPCODE_LDELEM_C: + case BSHELL_OPCODE_LDELEM_C: fx_printf("ldelem.c [cyan]@0x%02x", arg); break; - case OPCODE_STLOCAL: + case BSHELL_OPCODE_STLOCAL: pool_value = bshell_scriptblock_get_pool_value( container, arg, @@ -301,151 +301,151 @@ void print_instruction( } break; - case OPCODE_STPROP: + case BSHELL_OPCODE_STPROP: fx_printf("stprop [cyan]@0x%02x", arg); break; - case OPCODE_STELEM: + case BSHELL_OPCODE_STELEM: fx_printf("stelem [cyan]@0x%02x", arg); break; - case OPCODE_LDCMD: + case BSHELL_OPCODE_LDCMD: fx_printf("ldcmd [yellow]#0x%02x", arg); break; - case OPCODE_PEXEC: + case BSHELL_OPCODE_PEXEC: fx_printf("pexec [yellow]#0x%02x", arg); break; - case OPCODE_CALL: + case BSHELL_OPCODE_CALL: fx_printf("call"); break; - case OPCODE_MK_STR: + case BSHELL_OPCODE_MK_STR: fx_printf("mk.str [yellow]#0x%02x", arg); break; - case OPCODE_MK_ARRAY: + case BSHELL_OPCODE_MK_ARRAY: fx_printf("mk.array [yellow]#0x%02x", arg); break; - case OPCODE_MK_HTAB: + case BSHELL_OPCODE_MK_HTAB: fx_printf("mk.htab [yellow]#0x%02x", arg); break; - case OPCODE_POP: + case BSHELL_OPCODE_POP: fx_printf("pop"); break; - case OPCODE_ADD: + case BSHELL_OPCODE_ADD: fx_printf("add"); break; - case OPCODE_SUB: + case BSHELL_OPCODE_SUB: fx_printf("sub"); break; - case OPCODE_MUL: + case BSHELL_OPCODE_MUL: fx_printf("mul"); break; - case OPCODE_DIV: + case BSHELL_OPCODE_DIV: fx_printf("div"); break; - case OPCODE_ADD_IP: + case BSHELL_OPCODE_ADD_IP: fx_printf("add.ip"); break; - case OPCODE_MOD: + case BSHELL_OPCODE_MOD: fx_printf("mod"); break; - case OPCODE_INC: + case BSHELL_OPCODE_INC: fx_printf("inc"); break; - case OPCODE_DEC: + case BSHELL_OPCODE_DEC: fx_printf("dec"); break; - case OPCODE_SHL: + case BSHELL_OPCODE_SHL: fx_printf("shl"); break; - case OPCODE_SHR: + case BSHELL_OPCODE_SHR: fx_printf("shr"); break; - case OPCODE_BAND: + case BSHELL_OPCODE_BAND: fx_printf("band"); break; - case OPCODE_BOR: + case BSHELL_OPCODE_BOR: fx_printf("bor"); break; - case OPCODE_BXOR: + case BSHELL_OPCODE_BXOR: fx_printf("bxor"); break; - case OPCODE_BNOT: + case BSHELL_OPCODE_BNOT: fx_printf("bnot"); break; - case OPCODE_CMP_NULL: + case BSHELL_OPCODE_CMP_NULL: fx_printf("cmp.null"); break; - case OPCODE_CMP_EQ: + case BSHELL_OPCODE_CMP_EQ: fx_printf("cmp.eq"); break; - case OPCODE_CMP_NE: + case BSHELL_OPCODE_CMP_NE: fx_printf("cmp.ne"); break; - case OPCODE_CMP_LT: + case BSHELL_OPCODE_CMP_LT: fx_printf("cmp.lt"); break; - case OPCODE_CMP_GT: + case BSHELL_OPCODE_CMP_GT: fx_printf("cmp.gt"); break; - case OPCODE_CMP_LE: + case BSHELL_OPCODE_CMP_LE: fx_printf("cmp.le"); break; - case OPCODE_CMP_GE: + case BSHELL_OPCODE_CMP_GE: fx_printf("cmp.ge"); break; - case OPCODE_LAND: + case BSHELL_OPCODE_LAND: fx_printf("land"); break; - case OPCODE_LOR: + case BSHELL_OPCODE_LOR: fx_printf("lor"); break; - case OPCODE_LXOR: + case BSHELL_OPCODE_LXOR: fx_printf("lxor"); break; - case OPCODE_LNOT: + case BSHELL_OPCODE_LNOT: fx_printf("lnot"); break; - case OPCODE_BR: + case BSHELL_OPCODE_BR: fx_printf( "br [yellow]#0x%04x [=%04llx]", arg, (long long)arg + (long long)offset); break; - case OPCODE_BR_TRUE: + case BSHELL_OPCODE_BR_TRUE: fx_printf( "br.true [yellow]#0x%04x [=%04llx]", arg, (long long)arg + (long long)offset); break; - case OPCODE_RANGE: + case BSHELL_OPCODE_RANGE: fx_printf("range"); break; - case OPCODE_MATCH: + case BSHELL_OPCODE_MATCH: fx_printf("match"); break; - case OPCODE_REPLACE: + case BSHELL_OPCODE_REPLACE: fx_printf("replace"); break; - case OPCODE_LIKE: + case BSHELL_OPCODE_LIKE: fx_printf("like"); break; - case OPCODE_IN: + case BSHELL_OPCODE_IN: fx_printf("in"); break; - case OPCODE_FMT: + case BSHELL_OPCODE_FMT: fx_printf("fmt"); break; - case OPCODE_CONTAINS: + case BSHELL_OPCODE_CONTAINS: fx_printf("contains"); break; - case OPCODE_SPLIT: + case BSHELL_OPCODE_SPLIT: fx_printf("split"); break; - case OPCODE_JOIN: + case BSHELL_OPCODE_JOIN: fx_printf("join"); break; - case OPCODE_IS: + case BSHELL_OPCODE_IS: fx_printf("is"); break; - case OPCODE_AS: + case BSHELL_OPCODE_AS: fx_printf("as"); break; default: diff --git a/bshell/debug.h b/bshell/debug.h index 30b4bf4..0473192 100644 --- a/bshell/debug.h +++ b/bshell/debug.h @@ -1,17 +1,16 @@ #ifndef DEBUG_H_ #define DEBUG_H_ -#include "runtime/opcode.h" -#include "script-block.h" - +#include +#include #include -struct ast_node; -struct lex_token; +struct bshell_ast_node; +struct bshell_lex_token; -extern void print_lex_token(struct lex_token *tok); -extern void print_ast_node(struct ast_node *node); -extern void print_ast_node_recursive(struct ast_node *node); +extern void print_lex_token(struct bshell_lex_token *tok); +extern void print_ast_node(struct bshell_ast_node *node); +extern void print_ast_node_recursive(struct bshell_ast_node *node); extern void print_scriptblock(bshell_scriptblock *block, size_t depth); extern void print_instruction( size_t offset, diff --git a/bshell/file.h b/bshell/file.h deleted file mode 100644 index bbb5d81..0000000 --- a/bshell/file.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef FILE_H_ -#define FILE_H_ - -#include "line-source.h" - -#include -#include - -struct file { - struct line_source f_base; - fx_array *f_lines; - char *f_path; - fx_stream *f_strp; - FILE *f_fp; -}; - -extern enum bshell_status file_open(const char *path, struct file **out); -extern void file_close(struct file *file); - -#endif diff --git a/bshell/format/command.c b/bshell/format/command.c deleted file mode 100644 index 10c45b7..0000000 --- a/bshell/format/command.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "format.h" - -static struct table_format_column command_table_columns[] = { - TABLE_COLUMN("command_type", "command_type", 13), - TABLE_COLUMN("name", "name", COL_WIDTH_INFINITE), - TABLE_COLUMN("version", "version", 12), - TABLE_COLUMN("source", "source", 35), -}; - -struct table_format command_table_format = { - .fmt_columns = command_table_columns, - .fmt_column_count = sizeof command_table_columns - / sizeof command_table_columns[0], -}; diff --git a/bshell/format/hashtable.c b/bshell/format/hashtable.c deleted file mode 100644 index 61c7885..0000000 --- a/bshell/format/hashtable.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "format.h" - -static struct table_format_column hashtable_table_columns[] = { - TABLE_COLUMN("key", "key", 37), - TABLE_COLUMN("value", "value", COL_WIDTH_INFINITE), -}; - -struct table_format hashtable_table_format = { - .fmt_columns = hashtable_table_columns, - .fmt_column_count = sizeof hashtable_table_columns - / sizeof hashtable_table_columns[0], -}; diff --git a/bshell/line-ed/line-ed.c b/bshell/line-ed/line-ed.c index 1afdce5..f2687c4 100644 --- a/bshell/line-ed/line-ed.c +++ b/bshell/line-ed/line-ed.c @@ -19,7 +19,7 @@ - offsetof(struct line_ed, l_line_source))) static enum bshell_status readline( - struct line_source *src, + struct bshell_line_source *src, fx_stringstream *out) { struct line_ed *ed = LINE_ED_FROM_LEX_SOURCE(src); diff --git a/bshell/line-ed/line-ed.h b/bshell/line-ed/line-ed.h index 68daeb1..211900e 100644 --- a/bshell/line-ed/line-ed.h +++ b/bshell/line-ed/line-ed.h @@ -3,8 +3,7 @@ #define LINE_MAX 4096 -#include "../line-source.h" - +#include #include #include #include @@ -58,7 +57,7 @@ struct line_ed { /* the number of line continuations that have been inputted */ unsigned int l_continuations; - struct line_source l_line_source; + struct bshell_line_source l_line_source; /* pointer to tty interface */ fx_tty *l_tty; @@ -99,7 +98,8 @@ extern void line_ed_remove_hook(struct line_ed *ed, struct line_ed_hook *hook); extern size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out); -static inline struct line_source *line_ed_to_line_source(struct line_ed *ed) +static inline struct bshell_line_source *line_ed_to_line_source( + struct line_ed *ed) { return &ed->l_line_source; } diff --git a/bshell/line-source.h b/bshell/line-source.h deleted file mode 100644 index 537dfb7..0000000 --- a/bshell/line-source.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef LINE_SOURCE_H_ -#define LINE_SOURCE_H_ - -#include "status.h" - -#include -#include - -struct line_source { - enum bshell_status ( - *s_get_name)(struct line_source *, char *, size_t, size_t *); - enum bshell_status ( - *s_readline)(struct line_source *, fx_stringstream *); - enum bshell_status (*s_get_row)( - struct line_source *, - size_t, - char *, - size_t, - size_t *); -}; - -extern enum bshell_status line_source_get_name( - struct line_source *src, - char *buf, - size_t count, - size_t *nr_read); -extern enum bshell_status line_source_readline( - struct line_source *src, - fx_stringstream *out); -extern enum bshell_status line_source_get_row( - struct line_source *src, - size_t row, - char *buf, - size_t count, - size_t *nr_read); - -#endif diff --git a/bshell/main.c b/bshell/main.c index 4aba04d..df15209 100644 --- a/bshell/main.c +++ b/bshell/main.c @@ -1,63 +1,76 @@ -#include "ast/ast.h" -#include "compile.h" #include "debug.h" -#include "file.h" -#include "format/format.h" #include "line-ed/line-ed.h" -#include "parse/lex.h" -#include "parse/parse.h" -#include "parse/token.h" -#include "runtime/runtime.h" -#include "verb.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +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 print_token_queue(fx_queue *q) { fx_queue_entry *cur = fx_queue_first(q); while (cur) { - struct lex_token *tok = fx_unbox( - struct lex_token, - cur, - tok_entry); + struct bshell_lex_token *tok + = fx_unbox(struct bshell_lex_token, cur, tok_entry); print_lex_token(tok); cur = fx_queue_next(cur); } } -static void lex_only(struct lex_ctx *lex) +static void lex_only(struct bshell_lex_ctx *lex) { while (1) { - struct lex_token *tok = lex_ctx_peek(lex); + struct bshell_lex_token *tok = bshell_lex_ctx_peek(lex); if (!tok) { break; } - lex_ctx_discard(lex); + bshell_lex_ctx_discard(lex); } } -static void lex_and_parse(struct parse_ctx *parse) +static void lex_and_parse(struct bshell_parse_ctx *parse) { } +static void lex_token_scanned( + struct bshell_lex_ctx *ctx, + struct bshell_lex_token *tok) +{ + print_lex_token(tok); +} + extern int compare_token_types(unsigned int a, unsigned int b); int main(int argc, const char **argv) { printf("B Shell " BSHELL_VERSION "\n"); - bshell_init_all_verbs(); - table_format_init(); + bshell_assembly_get(); + bshell_runtime_assembly_get(); + bshell_core_assembly_get(); - struct file *file = NULL; + bshell_init_all_verbs(); + bshell_table_init(); + + struct bshell_file *file = NULL; struct line_ed *ed = NULL; - struct line_source *linesrc = NULL; + struct bshell_line_source *linesrc = NULL; enum bshell_status status = BSHELL_SUCCESS; if (argc > 1) { - status = file_open(argv[1], &file); + status = bshell_file_open(argv[1], &file); linesrc = &file->f_base; } else { #if BSHELL_INTERACTIVE == 1 @@ -69,10 +82,11 @@ int main(int argc, const char **argv) #endif } - struct lex_ctx lex = {0}; - lex_ctx_init(&lex, LEX_PRINT_TOKENS, linesrc); - struct parse_ctx parse = {0}; - parse_ctx_init(&parse, &lex); + struct bshell_lex_ctx lex = {0}; + bshell_lex_ctx_init(&lex, LEX_PRINT_TOKENS, linesrc); + lex.lex_token_scanned = lex_token_scanned; + struct bshell_parse_ctx parse = {0}; + bshell_parse_ctx_init(&parse, &lex); #if 0 lex_only(&lex); @@ -83,7 +97,8 @@ int main(int argc, const char **argv) struct bshell_runtime *rt = bshell_runtime_create(); while (1) { - struct ast_node *node = parse_ctx_read_node(&parse); + struct bshell_ast_node *node + = bshell_parse_ctx_read_node(&parse); if (!node) { break; } @@ -101,8 +116,8 @@ int main(int argc, const char **argv) } } - parse_ctx_cleanup(&parse); - lex_ctx_cleanup(&lex); + bshell_parse_ctx_cleanup(&parse); + bshell_lex_ctx_cleanup(&lex); #if BSHELL_INTERACTIVE == 1 if (ed) { @@ -111,7 +126,7 @@ int main(int argc, const char **argv) #endif if (file) { - file_close(file); + bshell_file_close(file); } return 0; diff --git a/bshell/operator.c b/bshell/operator.c deleted file mode 100644 index cbabb9c..0000000 --- a/bshell/operator.c +++ /dev/null @@ -1,268 +0,0 @@ -#include "operator.h" - -#include "parse/token.h" - -#define OP(id, p, a, l, u) \ - [OP_##id] = { \ - .op_id = (OP_##id), \ - .op_precedence = (PRECEDENCE_##p), \ - .op_associativity = (ASSOCIATIVITY_##a), \ - .op_location = (OPL_##l), \ - .op_arity = (OPA_##u), \ - } - -#define TOK_OP(id, tok) [TOK_##tok - __TOK_INDEX_BASE] = &operators[OP_##id] -#define SYM_OP(id, sym) [SYM_##sym - __SYM_INDEX_BASE] = &operators[OP_##id] -#define KW_OP(id, kw) [KW_##kw - __KW_INDEX_BASE] = &operators[OP_##id] -#define TKOP_OP(id, kw) [TKOP_##kw - __TKOP_INDEX_BASE] = &operators[OP_##id] - -/* clang-format off */ -static const struct operator_info operators[] = { - OP(ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY), - OP(CONDITIONAL_ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY), - OP(STATIC_ACCESS, STATIC_ACCESS, LEFT, INFIX, BINARY), - OP(SUBSCRIPT, SUBSCRIPT, LEFT, INFIX, BINARY), - OP(CONDITIONAL_SUBSCRIPT, SUBSCRIPT, LEFT, INFIX, BINARY), - OP(CAST, CAST, LEFT, PREFIX, UNARY), - OP(USPLIT, SPLIT, LEFT, PREFIX, UNARY), - OP(UJOIN, JOIN, LEFT, PREFIX, UNARY), - OP(ARRAY_DELIMITER, ARRAY, LEFT, INFIX, BINARY), - OP(INCREMENT, INCREMENT, LEFT, INFIX, BINARY), - OP(LOGICAL_NOT, NOT, LEFT, PREFIX, UNARY), - OP(RANGE, RANGE, LEFT, INFIX, BINARY), - OP(FORMAT, FORMAT, LEFT, INFIX, BINARY), - OP(MULTIPLY, MULTIPLICATION, LEFT, INFIX, BINARY), - OP(DIVIDE, MULTIPLICATION, LEFT, INFIX, BINARY), - OP(MODULO, MULTIPLICATION, LEFT, INFIX, BINARY), - OP(ADD, ADDITION, LEFT, INFIX, BINARY), - OP(SUBTRACT, ADDITION, LEFT, INFIX, BINARY), - - OP(BSPLIT, COMPARISON, LEFT, INFIX, BINARY), - OP(BJOIN, COMPARISON, LEFT, INFIX, BINARY), - OP(IS, COMPARISON, LEFT, INFIX, BINARY), - OP(ISNOT, COMPARISON, LEFT, INFIX, BINARY), - OP(AS, COMPARISON, LEFT, INFIX, BINARY), - OP(EQUAL, COMPARISON, LEFT, INFIX, BINARY), - OP(NOT_EQUAL, COMPARISON, LEFT, INFIX, BINARY), - OP(GREATER_THAN, COMPARISON, LEFT, INFIX, BINARY), - OP(LESS_THAN, COMPARISON, LEFT, INFIX, BINARY), - OP(GREATER_EQUAL, COMPARISON, LEFT, INFIX, BINARY), - OP(LESS_EQUAL, COMPARISON, LEFT, INFIX, BINARY), - OP(LIKE, COMPARISON, LEFT, INFIX, BINARY), - OP(NOTLIKE, COMPARISON, LEFT, INFIX, BINARY), - OP(MATCH, COMPARISON, LEFT, INFIX, BINARY), - OP(NOTMATCH, COMPARISON, LEFT, INFIX, BINARY), - OP(IN, COMPARISON, LEFT, INFIX, BINARY), - OP(NOTIN, COMPARISON, LEFT, INFIX, BINARY), - OP(CONTAINS, COMPARISON, LEFT, INFIX, BINARY), - OP(NOTCONTAINS, COMPARISON, LEFT, INFIX, BINARY), - OP(REPLACE, COMPARISON, LEFT, INFIX, BINARY), - - OP(LOGICAL_AND, LOGICAL, LEFT, INFIX, BINARY), - OP(LOGICAL_OR, LOGICAL, LEFT, INFIX, BINARY), - OP(LOGICAL_XOR, LOGICAL, LEFT, INFIX, BINARY), - - OP(BINARY_AND, BITWISE, LEFT, INFIX, BINARY), - OP(BINARY_OR, BITWISE, LEFT, INFIX, BINARY), - OP(BINARY_NOT, BITWISE, LEFT, INFIX, BINARY), - OP(BINARY_XOR, BITWISE, LEFT, INFIX, BINARY), - OP(LEFT_SHIFT, BITWISE, LEFT, INFIX, BINARY), - OP(RIGHT_SHIFT, BITWISE, LEFT, INFIX, BINARY), - - OP(ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), - OP(ADD_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), - OP(SUBTRACT_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), - OP(MULTIPLY_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), - OP(DIVIDE_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), - OP(MODULO_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY), - - /* these are not real operators, and are just used internally by the - * parser. */ - OP(SUBEXPR, PARENTHESIS, LEFT, PREFIX, UNARY), - OP(ARRAY_START, PARENTHESIS, LEFT, PREFIX, UNARY), - OP(PAREN, PARENTHESIS, LEFT, PREFIX, UNARY), - OP(HASHTABLE_START, PARENTHESIS, LEFT, PREFIX, UNARY), - OP(SCRIPTBLOCK, PARENTHESIS, LEFT, PREFIX, UNARY), -}; -static const size_t nr_operators = sizeof operators / sizeof operators[0]; - -static const struct operator_info *operator_symbols[] = { - SYM_OP(LOGICAL_NOT, BANG), - SYM_OP(ASSIGN, EQUAL), - SYM_OP(ADD, PLUS), - SYM_OP(SUBTRACT, HYPHEN), - SYM_OP(MULTIPLY, ASTERISK), - SYM_OP(DIVIDE, FORWARD_SLASH), - SYM_OP(MODULO, PERCENT), - SYM_OP(ADD_ASSIGN, PLUS_EQUAL), - SYM_OP(SUBTRACT_ASSIGN, HYPHEN_EQUAL), - SYM_OP(MULTIPLY_ASSIGN, ASTERISK_EQUAL), - SYM_OP(DIVIDE_ASSIGN, FORWARD_SLASH_EQUAL), - SYM_OP(MODULO_ASSIGN, PERCENT_EQUAL), - SYM_OP(RANGE, DOT_DOT), - SYM_OP(SUBSCRIPT, LEFT_BRACKET), - SYM_OP(CONDITIONAL_SUBSCRIPT, QUESTION_LEFT_BRACKET), - - SYM_OP(ACCESS, DOT), - SYM_OP(CONDITIONAL_ACCESS, QUESTION_DOT), - SYM_OP(STATIC_ACCESS, COLON_COLON), - - /* parser-internal pseudo-operators. */ - - /* CAST uses the same symbol as SUBSCRIPT */ - /* SYM_OP(CAST, LEFT_BRACKET), */ - SYM_OP(SUBEXPR, DOLLAR_LEFT_PAREN), - SYM_OP(PAREN, LEFT_PAREN), - SYM_OP(ARRAY_START, AT_LEFT_PAREN), - SYM_OP(HASHTABLE_START, AT_LEFT_BRACE), -}; -static const size_t nr_operator_symbols = sizeof operator_symbols / sizeof operator_symbols[0]; - -static const struct operator_info *operator_token_ops[] = { - TKOP_OP(FORMAT, F), - TKOP_OP(BINARY_AND, BAND), - TKOP_OP(BINARY_OR, BOR), - TKOP_OP(BINARY_XOR, BXOR), - TKOP_OP(BINARY_NOT, BNOT), - TKOP_OP(LEFT_SHIFT, SHL), - TKOP_OP(RIGHT_SHIFT, SHR), - TKOP_OP(EQUAL, EQ), - TKOP_OP(NOT_EQUAL, NE), - TKOP_OP(GREATER_THAN, GT), - TKOP_OP(LESS_THAN, LT), - TKOP_OP(GREATER_EQUAL, GE), - TKOP_OP(LESS_EQUAL, LE), - TKOP_OP(MATCH, MATCH), - TKOP_OP(NOTMATCH, NOTMATCH), - TKOP_OP(REPLACE, REPLACE), - TKOP_OP(LIKE, LIKE), - TKOP_OP(NOTLIKE, NOTLIKE), - TKOP_OP(IN, IN), - TKOP_OP(NOTIN, NOTIN), - TKOP_OP(CONTAINS, CONTAINS), - TKOP_OP(NOTCONTAINS, NOTCONTAINS), - TKOP_OP(LOGICAL_AND, AND), - TKOP_OP(LOGICAL_OR, OR), - TKOP_OP(LOGICAL_XOR, XOR), - TKOP_OP(LOGICAL_NOT, NOT), - /* there are also unary versions of these operators */ - TKOP_OP(BSPLIT, SPLIT), - TKOP_OP(BJOIN, JOIN), - - TKOP_OP(IS, IS), - TKOP_OP(ISNOT, ISNOT), - TKOP_OP(AS, AS), -}; -static const size_t nr_operator_token_ops = sizeof operator_token_ops / sizeof operator_token_ops[0]; - -/* clang-format on */ - -const struct operator_info *operator_get_by_token(unsigned int token) -{ - const struct operator_info **op_list = NULL; - size_t base = 0; - size_t op_list_size = 0; - - if (token > __TKOP_INDEX_BASE && token < __TKOP_INDEX_LIMIT) { - op_list = operator_token_ops; - base = __TKOP_INDEX_BASE; - op_list_size = nr_operator_token_ops; - } else if (token > __SYM_INDEX_BASE && token < __SYM_INDEX_LIMIT) { - op_list = operator_symbols; - base = __SYM_INDEX_BASE; - op_list_size = nr_operator_symbols; - } else { - return NULL; - } - - if (token - base >= op_list_size) { - return NULL; - } - - return op_list[token - base]; -} - -const struct operator_info *operator_get_by_id(enum operator_id id) -{ - if (id >= nr_operators) { - return NULL; - } - - const struct operator_info *op = &operators[id]; - if (op->op_id != id) { - return NULL; - } - - return op; -} - -#define ENUM_STR(x) \ - case x: \ - return #x - -const char *operator_id_to_string(enum operator_id op) -{ - switch (op) { - ENUM_STR(OP_NONE); - ENUM_STR(OP_ADD); - ENUM_STR(OP_SUBTRACT); - ENUM_STR(OP_MULTIPLY); - ENUM_STR(OP_DIVIDE); - ENUM_STR(OP_MODULO); - ENUM_STR(OP_INCREMENT); - ENUM_STR(OP_DECREMENT); - ENUM_STR(OP_LEFT_SHIFT); - ENUM_STR(OP_RIGHT_SHIFT); - ENUM_STR(OP_BINARY_AND); - ENUM_STR(OP_BINARY_OR); - ENUM_STR(OP_BINARY_XOR); - ENUM_STR(OP_BINARY_NOT); - ENUM_STR(OP_LESS_THAN); - ENUM_STR(OP_GREATER_THAN); - ENUM_STR(OP_EQUAL); - ENUM_STR(OP_NOT_EQUAL); - ENUM_STR(OP_LESS_EQUAL); - ENUM_STR(OP_GREATER_EQUAL); - ENUM_STR(OP_ASSIGN); - ENUM_STR(OP_ADD_ASSIGN); - ENUM_STR(OP_SUBTRACT_ASSIGN); - ENUM_STR(OP_MULTIPLY_ASSIGN); - ENUM_STR(OP_DIVIDE_ASSIGN); - ENUM_STR(OP_MODULO_ASSIGN); - ENUM_STR(OP_LOGICAL_AND); - ENUM_STR(OP_LOGICAL_OR); - ENUM_STR(OP_LOGICAL_XOR); - ENUM_STR(OP_LOGICAL_NOT); - ENUM_STR(OP_RANGE); - ENUM_STR(OP_MATCH); - ENUM_STR(OP_NOTMATCH); - ENUM_STR(OP_REPLACE); - ENUM_STR(OP_LIKE); - ENUM_STR(OP_NOTLIKE); - ENUM_STR(OP_IN); - ENUM_STR(OP_NOTIN); - ENUM_STR(OP_FORMAT); - ENUM_STR(OP_CONTAINS); - ENUM_STR(OP_NOTCONTAINS); - ENUM_STR(OP_USPLIT); - ENUM_STR(OP_BSPLIT); - ENUM_STR(OP_UJOIN); - ENUM_STR(OP_BJOIN); - ENUM_STR(OP_IS); - ENUM_STR(OP_ISNOT); - ENUM_STR(OP_AS); - ENUM_STR(OP_SUBSCRIPT); - ENUM_STR(OP_CONDITIONAL_SUBSCRIPT); - ENUM_STR(OP_ARRAY_DELIMITER); - ENUM_STR(OP_ACCESS); - ENUM_STR(OP_STATIC_ACCESS); - ENUM_STR(OP_CONDITIONAL_ACCESS); - ENUM_STR(OP_CAST); - ENUM_STR(OP_SUBEXPR); - ENUM_STR(OP_PAREN); - ENUM_STR(OP_ARRAY_START); - ENUM_STR(OP_HASHTABLE_START); - default: - return ""; - } -} diff --git a/bshell/operator.h b/bshell/operator.h deleted file mode 100644 index e3411fc..0000000 --- a/bshell/operator.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef OPERATOR_H_ -#define OPERATOR_H_ - -enum operator_precedence { - PRECEDENCE_MINIMUM = 0, - PRECEDENCE_ASSIGN, - PRECEDENCE_PIPELINE, - PRECEDENCE_LOGICAL, - PRECEDENCE_BITWISE, - PRECEDENCE_COMPARISON, - PRECEDENCE_ADDITION, - PRECEDENCE_MULTIPLICATION, - PRECEDENCE_NEGATE, - PRECEDENCE_FORMAT, - PRECEDENCE_RANGE, - PRECEDENCE_NOT, - PRECEDENCE_INCREMENT, - PRECEDENCE_ARRAY, - PRECEDENCE_JOIN, - PRECEDENCE_SPLIT, - PRECEDENCE_CAST, - PRECEDENCE_SUBSCRIPT, - PRECEDENCE_STATIC_ACCESS, - PRECEDENCE_MEMBER_ACCESS, - PRECEDENCE_PARENTHESIS, -}; - -enum operator_associativity { - ASSOCIATIVITY_LEFT, - ASSOCIATIVITY_RIGHT, -}; - -enum operator_location { - OPL_PREFIX, - OPL_INFIX, - OPL_POSTFIX, -}; - -enum operator_arity { - OPA_UNARY, - OPA_BINARY, -}; - -enum operator_id { - OP_NONE = 0, - OP_ADD, - OP_SUBTRACT, - OP_MULTIPLY, - OP_DIVIDE, - OP_MODULO, - OP_INCREMENT, - OP_DECREMENT, - OP_LEFT_SHIFT, - OP_RIGHT_SHIFT, - OP_BINARY_AND, - OP_BINARY_OR, - OP_BINARY_XOR, - OP_BINARY_NOT, - OP_LESS_THAN, - OP_GREATER_THAN, - OP_EQUAL, - OP_NOT_EQUAL, - OP_LESS_EQUAL, - OP_GREATER_EQUAL, - OP_ASSIGN, - OP_ADD_ASSIGN, - OP_SUBTRACT_ASSIGN, - OP_MULTIPLY_ASSIGN, - OP_DIVIDE_ASSIGN, - OP_MODULO_ASSIGN, - OP_LOGICAL_AND, - OP_LOGICAL_OR, - OP_LOGICAL_XOR, - OP_LOGICAL_NOT, - OP_RANGE, - OP_MATCH, - OP_NOTMATCH, - OP_REPLACE, - OP_LIKE, - OP_NOTLIKE, - OP_IN, - OP_NOTIN, - OP_FORMAT, - OP_CONTAINS, - OP_NOTCONTAINS, - OP_USPLIT, - OP_BSPLIT, - OP_UJOIN, - OP_BJOIN, - OP_IS, - OP_ISNOT, - OP_AS, - - OP_SUBSCRIPT, - OP_CONDITIONAL_SUBSCRIPT, - - OP_ARRAY_DELIMITER, - OP_ACCESS, - OP_STATIC_ACCESS, - OP_CONDITIONAL_ACCESS, - - /* these are not real operators, and are just used internally by the - * parser. */ - OP_CAST, - OP_SUBEXPR, - OP_PAREN, - OP_SCRIPTBLOCK, - OP_ARRAY_START, - OP_HASHTABLE_START, -}; - -struct operator_info { - enum operator_id op_id; - enum operator_precedence op_precedence; - enum operator_associativity op_associativity; - enum operator_location op_location; - enum operator_arity op_arity; -}; - -extern const struct operator_info *operator_get_by_id(enum operator_id id); -extern const struct operator_info *operator_get_by_token(unsigned int token); -extern const char *operator_id_to_string(enum operator_id op); - -#endif diff --git a/bshell/parse/lex.h b/bshell/parse/lex.h deleted file mode 100644 index 7e77021..0000000 --- a/bshell/parse/lex.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef LEX_H_ -#define LEX_H_ - -#include "../status.h" -#include "token.h" - -#include -#include -#include - -#define LEX_STATE_MAX_TERMINATORS 16 - -struct line_source; - -enum lex_flags { - LEX_PRINT_TOKENS = 0x01u, -}; - -enum lex_token_flags { - /* a token with this flag not only interrupts the word currently being - * scanned, but also stops multi-words */ - LEX_TOKEN_TERMINATES_WORD = 0x01u, - /* a token with this flag can appear at the start of an arithmetic - * expression. a statement that encounters this token as its first char - * will switch to arithmetic mode */ - LEX_TOKEN_UNARY_ARITHMETIC = 0x02u, - /* if a token has this flag defined, the lexer will - * switch to command mode after encountering it. */ - LEX_TOKEN_COMMAND_MODE = 0x08u, - /* if a token has this flag defined, the lexer will - * switch to statement mode after encountering it. */ - LEX_TOKEN_STATEMENT_MODE = 0x10u, -}; - -enum lex_state_type_id { - LEX_STATE_STATEMENT = 0x01u, - LEX_STATE_COMMAND = 0x02u, - LEX_STATE_ARITHMETIC = 0x04u, - LEX_STATE_STRING = 0x08u, - LEX_STATE_WORD = 0x10u, - LEX_STATE_HASHTABLE = 0x20u, -}; - -struct lex_token_def { - int id; - const char *name; - uint64_t name_hash; - enum lex_state_type_id enabled_states; - enum lex_token_flags flags; -}; - -struct lex_symbol_node { - char s_char; - struct lex_token_def *s_def; - - fx_queue_entry s_entry; - fx_queue s_children; -}; - -struct lex_state { - const struct lex_state_type *s_type; - unsigned int s_terminators[LEX_STATE_MAX_TERMINATORS]; - unsigned int s_nr_terminators; - unsigned int s_paren_depth; - fx_queue_entry s_entry; - fx_string *s_tempstr; - unsigned int s_flags; -}; - -struct lex_ctx { - enum lex_flags lex_flags; - fx_queue lex_tokens; - struct line_source *lex_src; - fx_stringstream *lex_buf; - fx_string *lex_tmp; - fx_wchar lex_ch; - fx_queue lex_state; - enum token_type lex_prev_token; - struct char_cell lex_cursor, lex_start, lex_end; - struct lex_symbol_node *lex_sym_tree; - enum bshell_status lex_status; -}; - -extern enum bshell_status lex_ctx_init( - struct lex_ctx *ctx, - enum lex_flags flags, - struct line_source *src); -extern enum bshell_status lex_ctx_cleanup(struct lex_ctx *ctx); - -extern struct lex_token *lex_ctx_peek(struct lex_ctx *ctx); -extern struct lex_token *lex_ctx_claim(struct lex_ctx *ctx); -extern void lex_ctx_discard(struct lex_ctx *ctx); - -#endif diff --git a/bshell/parse/lex/arithmetic.c b/bshell/parse/lex/arithmetic.c deleted file mode 100644 index ec8f6ef..0000000 --- a/bshell/parse/lex/arithmetic.c +++ /dev/null @@ -1,232 +0,0 @@ -#include "lex-internal.h" - -static enum bshell_status arithmetic_hyphen(struct lex_ctx *ctx) -{ - fx_wchar c = peek_char(ctx); - if (!fx_wchar_is_alnum(c)) { - push_symbol(ctx, SYM_HYPHEN); - handle_lex_state_transition(ctx, SYM_HYPHEN); - return BSHELL_SUCCESS; - } - - struct lex_token *tok = NULL; - enum bshell_status status = read_word( - ctx, - READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN, - &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - unsigned int token_type = TOK_WORD; - if (convert_word_to_number(tok)) { - token_type = tok->tok_type; - - /* because of APPEND_HYPHEN (which is needed to ensure operator - * tokens are detected properly), the resulting number will be - * negative. - * this token will be preceded by a HYPHEN token, so the number - * must be positive */ - fx_value neg = FX_INT(-1); - fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number); - push_symbol(ctx, SYM_HYPHEN); - } else if (convert_word_to_operator(ctx, tok)) { - token_type = tok->tok_operator; - } - - enqueue_token(ctx, tok); - return BSHELL_SUCCESS; -} - -static enum bshell_status arithmetic_symbol(struct lex_ctx *ctx) -{ - const struct lex_token_def *sym = NULL; - enum bshell_status status = read_symbol(ctx, &sym); - - if (status != BSHELL_SUCCESS) { - return status; - } - - handle_lex_state_transition(ctx, sym->id); - - struct lex_token *tok = NULL; - switch (sym->id) { - case SYM_DQUOTE: - return BSHELL_SUCCESS; - case SYM_SQUOTE: - status = read_literal_string(ctx, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - enqueue_token(ctx, tok); - return BSHELL_SUCCESS; - case SYM_HYPHEN: - return arithmetic_hyphen(ctx); - case SYM_HASH: - return read_line_comment(ctx); - case SYM_DOLLAR: - status = read_var(ctx, TOK_VAR, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - enqueue_token(ctx, tok); - return status; - case SYM_AT: - status = read_var(ctx, TOK_VAR_SPLAT, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - enqueue_token(ctx, tok); - return status; - case SYM_DOLLAR_LEFT_BRACE: - status = read_braced_var(ctx, TOK_VAR, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - enqueue_token(ctx, tok); - return status; - default: - break; - } - - push_symbol(ctx, sym->id); - - return BSHELL_SUCCESS; -} - -static enum bshell_status arithmetic_word(struct lex_ctx *ctx) -{ - struct lex_token *word = NULL; - enum bshell_status status = read_word(ctx, 0, &word); - if (status != BSHELL_SUCCESS) { - return status; - } - - unsigned int token_type = TOK_WORD; - bool kw = false, number = false; - if (convert_word_to_keyword(word)) { - token_type = word->tok_keyword; - } else if (convert_word_to_number(word)) { - token_type = word->tok_type; - } - - handle_lex_state_transition(ctx, token_type); - - enqueue_token(ctx, word); - return BSHELL_SUCCESS; -} - -static enum bshell_status arithmetic_pump_token(struct lex_ctx *ctx) -{ - fx_wchar c = peek_char(ctx); - bool newline = false; - - set_token_start(ctx); - while (fx_wchar_is_space(c)) { - if (c == '\n') { - newline = true; - } - - set_token_end(ctx); - advance_char_noread(ctx); - c = peek_char_noread(ctx); - } - - if (newline) { - struct lex_token *tok = lex_token_create(TOK_LINEFEED); - enqueue_token(ctx, tok); - handle_lex_state_transition(ctx, TOK_LINEFEED); - return BSHELL_SUCCESS; - } - - if (char_can_begin_symbol(ctx, c)) { - return arithmetic_symbol(ctx); - } - - return arithmetic_word(ctx); -} - -static const struct lex_state_link links[] = { - LINK_CHANGE(SYM_EQUAL, LEX_STATE_STATEMENT), - LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0), - LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0), - LINK_POP(SYM_RIGHT_PAREN), - LINK_CHANGE(SYM_SEMICOLON, LEX_STATE_STATEMENT), - LINK_CHANGE(TOK_LINEFEED, LEX_STATE_STATEMENT), - LINK_CHANGE(SYM_PIPE, LEX_STATE_STATEMENT), - LINK_PUSH(SYM_AT_LEFT_BRACE, LEX_STATE_HASHTABLE, 0), - LINK_PUSH( - SYM_LEFT_PAREN, - LEX_STATE_STATEMENT, - STATEMENT_F_DISABLE_KEYWORDS), - LINK_END, -}; - -static const unsigned int keywords[] = { - KW_IF, - KW_ELSEIF, - KW_ELSE, - KW_NONE, -}; - -static const unsigned int operators[] = { - TKOP_F, TKOP_BAND, TKOP_BOR, TKOP_BXOR, - TKOP_BNOT, TKOP_SHL, TKOP_SHR, TKOP_EQ, - TKOP_NE, TKOP_GT, TKOP_LT, TKOP_GE, - TKOP_LE, TKOP_MATCH, TKOP_NOTMATCH, TKOP_REPLACE, - TKOP_LIKE, TKOP_NOTLIKE, TKOP_IN, TKOP_NOTIN, - TKOP_CONTAINS, TKOP_NOTCONTAINS, TKOP_AND, TKOP_OR, - TKOP_XOR, TKOP_NOT, TKOP_SPLIT, TKOP_JOIN, - TKOP_IS, TKOP_ISNOT, TKOP_AS, TKOP_NONE, -}; - -static const unsigned int symbols[] = { - SYM_BANG, - SYM_PLUS, - SYM_HYPHEN, - SYM_FORWARD_SLASH, - SYM_ASTERISK, - SYM_AMPERSAND, - SYM_PERCENT, - SYM_SQUOTE, - SYM_DQUOTE, - SYM_HASH, - SYM_DOLLAR, - SYM_DOLLAR_LEFT_PAREN, - SYM_DOLLAR_LEFT_BRACE, - SYM_AT, - SYM_AT_LEFT_BRACE, - SYM_PIPE, - SYM_COMMA, - SYM_SEMICOLON, - SYM_LEFT_PAREN, - SYM_RIGHT_PAREN, - SYM_LEFT_BRACE, - SYM_RIGHT_BRACE, - SYM_LEFT_BRACKET, - SYM_RIGHT_BRACKET, - SYM_QUESTION_DOT, - SYM_QUESTION_LEFT_BRACKET, - SYM_EQUAL, - SYM_PLUS_EQUAL, - SYM_HYPHEN_EQUAL, - SYM_FORWARD_SLASH_EQUAL, - SYM_ASTERISK_EQUAL, - SYM_PERCENT_EQUAL, - SYM_DOT, - SYM_DOT_DOT, - SYM_COLON_COLON, - SYM_NONE, -}; - -const struct lex_state_type lex_arithmetic_state = { - .s_id = LEX_STATE_ARITHMETIC, - .s_pump_token = arithmetic_pump_token, - .s_links = links, - .s_keywords = keywords, - .s_operators = operators, - .s_symbols = symbols, -}; diff --git a/bshell/parse/lex/lex-internal.h b/bshell/parse/lex/lex-internal.h deleted file mode 100644 index 215ee32..0000000 --- a/bshell/parse/lex/lex-internal.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef PARSE_LEX_INTERNAL_H_ -#define PARSE_LEX_INTERNAL_H_ - -#include "../../status.h" -#include "../lex.h" -#include "../token.h" - -struct lex_ctx; - -enum state_flags { - /* statement: don't convert matching words to keywords */ - STATEMENT_F_DISABLE_KEYWORDS = 0x01u, - /* arithmetic: don't switch back to statement mode even when - * encountering a token that would otherwise require it. */ - ARITHMETIC_F_DISABLE_STATEMENTS = 0x01u, -}; - -enum read_flags { - READ_APPEND_HYPHEN = 0x01u, - READ_NO_SET_TOKEN_START = 0x02u, - READ_NO_NUMBER_RECOGNITION = 0x04u, -}; - -enum link_flags { - LINK_ALLOW_RECURSION = 0x01u, -}; - -#define LINK_PUSH(tok, target, flags) \ - ((struct lex_state_link) { \ - .l_token = (tok), \ - .l_type = LEX_STATE_LINK_PUSH, \ - .l_target = (target), \ - .l_target_flags = (flags), \ - }) -#define LINK_PUSH_WITH_TERM(tok, target, flags, ...) \ - ((struct lex_state_link) { \ - .l_token = (tok), \ - .l_type = LEX_STATE_LINK_PUSH, \ - .l_target = (target), \ - .l_target_flags = (flags), \ - .l_terminators = {__VA_ARGS__, TOK_NONE}, \ - }) -#define LINK_CHANGE(tok, target) \ - ((struct lex_state_link) { \ - .l_token = (tok), \ - .l_type = LEX_STATE_LINK_CHANGE, \ - .l_target = (target), \ - }) -#define LINK_POP(tok) \ - ((struct lex_state_link) { \ - .l_token = (tok), \ - .l_type = LEX_STATE_LINK_POP, \ - }) -#define LINK_POP2(tok, flags) \ - ((struct lex_state_link) { \ - .l_token = (tok), \ - .l_type = LEX_STATE_LINK_POP, \ - .l_flags = (flags), \ - }) -#define LINK_NONE(tok) \ - ((struct lex_state_link) { \ - .l_token = (tok), \ - .l_type = LEX_STATE_LINK_NONE, \ - }) -#define LINK_END ((struct lex_state_link) {}) - -struct lex_state_link { - unsigned int l_token; - enum { - LEX_STATE_LINK_NONE, - LEX_STATE_LINK_PUSH, - LEX_STATE_LINK_CHANGE, - LEX_STATE_LINK_POP, - } l_type; - enum link_flags l_flags; - enum lex_state_type_id l_target; - enum state_flags l_target_flags; - unsigned int l_terminators[LEX_STATE_MAX_TERMINATORS]; -}; - -typedef enum bshell_status (*lex_state_pump_token)(struct lex_ctx *); -typedef enum bshell_status (*lex_state_begin)(struct lex_ctx *); -typedef enum bshell_status (*lex_state_end)(struct lex_ctx *); - -struct lex_state_type { - enum lex_state_type_id s_id; - lex_state_pump_token s_pump_token; - lex_state_begin s_begin; - lex_state_end s_end; - - const unsigned int *s_keywords; - const unsigned int *s_operators; - const unsigned int *s_symbols; - const struct lex_state_link *s_links; -}; - -extern enum bshell_status pump_token_statement(struct lex_ctx *ctx); -extern enum bshell_status pump_token_expression(struct lex_ctx *ctx); -extern enum bshell_status pump_token_command(struct lex_ctx *ctx); -extern enum bshell_status pump_token_arithmetic(struct lex_ctx *ctx); -extern enum bshell_status pump_token_string(struct lex_ctx *ctx); - -extern void set_token_start(struct lex_ctx *ctx); -extern void set_token_end(struct lex_ctx *ctx); - -extern struct lex_state *lex_state_push( - struct lex_ctx *ctx, - enum lex_state_type_id state_type, - enum state_flags flags); -extern void lex_state_pop(struct lex_ctx *ctx); -extern struct lex_state *lex_state_get(struct lex_ctx *ctx); -extern void lex_state_change(struct lex_ctx *ctx, enum lex_state_type_id type); -extern fx_string *lex_state_get_tempstr(struct lex_ctx *ctx); -extern void lex_state_add_terminator(struct lex_state *state, unsigned int tok); -extern bool lex_state_terminates_at_token( - struct lex_ctx *ctx, - unsigned int tok); - -extern fx_wchar peek_char(struct lex_ctx *ctx); -extern fx_wchar peek_char_noread(struct lex_ctx *ctx); -extern fx_wchar peek2_char(struct lex_ctx *ctx); -extern fx_wchar peek2_char_noread(struct lex_ctx *ctx); -extern void advance_char(struct lex_ctx *ctx); -extern void advance_char_noread(struct lex_ctx *ctx); - -extern bool string_is_valid_number( - const char *s, - fx_value *out, - enum token_type *out_type); -extern bool convert_word_to_number(struct lex_token *tok); -extern bool convert_word_to_keyword(struct lex_token *tok); -extern bool convert_word_to_operator( - struct lex_ctx *ctx, - struct lex_token *tok); - -extern void enqueue_token(struct lex_ctx *ctx, struct lex_token *tok); -extern void enqueue_token_with_coordinates( - struct lex_ctx *ctx, - struct lex_token *tok, - const struct char_cell *start, - const struct char_cell *end); - -extern enum bshell_status read_word( - struct lex_ctx *ctx, - enum read_flags flags, - struct lex_token **out); -extern enum bshell_status read_symbol( - struct lex_ctx *ctx, - const struct lex_token_def **out); -extern enum bshell_status read_literal_string( - struct lex_ctx *ctx, - struct lex_token **out); -extern enum bshell_status read_line_comment(struct lex_ctx *lex); -extern enum bshell_status read_var( - struct lex_ctx *ctx, - enum token_type type, - struct lex_token **out); -extern enum bshell_status read_braced_var( - struct lex_ctx *ctx, - enum token_type type, - struct lex_token **out); - -extern enum bshell_status push_symbol( - struct lex_ctx *ctx, - enum token_symbol sym); - -extern bool char_can_begin_symbol(struct lex_ctx *ctx, char c); -extern bool char_can_begin_symbol_in_state( - struct lex_ctx *ctx, - char c, - enum lex_state_type_id state_type); -extern bool char_has_flags( - struct lex_ctx *ctx, - char c, - enum lex_token_flags flags); -extern bool keyword_has_flags( - struct lex_ctx *ctx, - enum token_keyword kw, - enum lex_token_flags flags); -extern enum lex_token_flags keyword_get_flags( - struct lex_ctx *ctx, - enum token_keyword kw); -extern bool symbol_has_flags( - struct lex_ctx *ctx, - enum token_symbol sym, - enum lex_token_flags flags); -extern enum lex_token_flags symbol_get_flags( - struct lex_ctx *ctx, - enum token_symbol sym); -extern enum token_operator get_operator_with_string( - struct lex_ctx *ctx, - const char *s); - -extern void handle_lex_state_transition( - struct lex_ctx *ctx, - unsigned int token); - -#endif diff --git a/bshell/parse/lex/statement.c b/bshell/parse/lex/statement.c deleted file mode 100644 index b43fbc4..0000000 --- a/bshell/parse/lex/statement.c +++ /dev/null @@ -1,254 +0,0 @@ -#include "lex-internal.h" - -static enum bshell_status statement_hyphen(struct lex_ctx *ctx) -{ - fx_wchar c = peek_char(ctx); - if (!fx_wchar_is_alnum(c)) { - push_symbol(ctx, SYM_HYPHEN); - handle_lex_state_transition(ctx, SYM_HYPHEN); - return BSHELL_SUCCESS; - } - - struct lex_token *tok = NULL; - enum bshell_status status = read_word( - ctx, - READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN, - &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - unsigned int token_type = TOK_WORD; - - if (convert_word_to_number(tok)) { - token_type = tok->tok_type; - - /* because of APPEND_HYPHEN (which is needed to ensure operator - * tokens are detected properly), the resulting number will be - * negative. - * this token will be preceded by a HYPHEN token, so the number - * must be positive */ - fx_value neg = FX_INT(-1); - fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number); - push_symbol(ctx, SYM_HYPHEN); - } else if (convert_word_to_operator(ctx, tok)) { - token_type = tok->tok_operator; - } - - handle_lex_state_transition(ctx, token_type); - enqueue_token(ctx, tok); - - return BSHELL_SUCCESS; -} - -static enum bshell_status statement_symbol(struct lex_ctx *ctx) -{ - const struct lex_token_def *sym = NULL; - enum bshell_status status = read_symbol(ctx, &sym); - - if (status != BSHELL_SUCCESS) { - return status; - } - - handle_lex_state_transition(ctx, sym->id); - - struct lex_token *tok = NULL; - switch (sym->id) { - case SYM_DQUOTE: - return BSHELL_SUCCESS; - case SYM_HYPHEN: - return statement_hyphen(ctx); - case SYM_SQUOTE: - status = read_literal_string(ctx, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - enqueue_token(ctx, tok); - return BSHELL_SUCCESS; - - case SYM_HASH: - return read_line_comment(ctx); - case SYM_DOLLAR: - status = read_var(ctx, TOK_VAR, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - enqueue_token(ctx, tok); - return status; - case SYM_AT: - status = read_var(ctx, TOK_VAR_SPLAT, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - enqueue_token(ctx, tok); - return status; - case SYM_DOLLAR_LEFT_BRACE: - status = read_braced_var(ctx, TOK_VAR, &tok); - if (status != BSHELL_SUCCESS) { - return status; - } - - enqueue_token(ctx, tok); - return status; - default: - break; - } - - push_symbol(ctx, sym->id); - return BSHELL_SUCCESS; -} - -static enum bshell_status statement_word(struct lex_ctx *ctx) -{ - struct lex_token *word = NULL; - enum bshell_status status = read_word(ctx, 0, &word); - if (status != BSHELL_SUCCESS) { - return status; - } - - struct lex_state *state = lex_state_get(ctx); - - bool enable_keywords = !(state->s_flags & STATEMENT_F_DISABLE_KEYWORDS); - unsigned int token = TOK_WORD; - - if (enable_keywords && convert_word_to_keyword(word)) { - token = word->tok_keyword; - } else if (convert_word_to_number(word)) { - token = word->tok_type; - } - - handle_lex_state_transition(ctx, token); - - enqueue_token(ctx, word); - return BSHELL_SUCCESS; -} - -static enum bshell_status statement_pump_token(struct lex_ctx *ctx) -{ - fx_wchar c = peek_char(ctx); - bool newline = false; - - set_token_start(ctx); - while (fx_wchar_is_space(c)) { - if (c == '\n') { - newline = true; - } - - set_token_end(ctx); - advance_char_noread(ctx); - c = peek_char_noread(ctx); - } - - if (newline) { - struct lex_token *tok = lex_token_create(TOK_LINEFEED); - enqueue_token(ctx, tok); - handle_lex_state_transition(ctx, TOK_LINEFEED); - return BSHELL_SUCCESS; - } - - if (char_can_begin_symbol(ctx, c)) { - return statement_symbol(ctx); - } - - if (char_has_flags(ctx, c, LEX_TOKEN_UNARY_ARITHMETIC)) { - lex_state_change(ctx, LEX_STATE_ARITHMETIC); - return BSHELL_SUCCESS; - } - - return statement_word(ctx); -} - -static const struct lex_state_link links[] = { - LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0), - /* arithmetic tokens */ - LINK_CHANGE(TOK_KEYWORD, LEX_STATE_ARITHMETIC), - LINK_CHANGE(SYM_SQUOTE, LEX_STATE_ARITHMETIC), - LINK_CHANGE(TOK_INT, LEX_STATE_ARITHMETIC), - LINK_CHANGE(TOK_DOUBLE, LEX_STATE_ARITHMETIC), - LINK_PUSH(SYM_DOLLAR, LEX_STATE_ARITHMETIC, 0), - LINK_PUSH_WITH_TERM( - SYM_DOLLAR_LEFT_BRACE, - LEX_STATE_ARITHMETIC, - 0, - SYM_RIGHT_BRACE), - LINK_CHANGE(SYM_AT_LEFT_BRACE, LEX_STATE_ARITHMETIC), - LINK_CHANGE(SYM_AT_LEFT_PAREN, LEX_STATE_ARITHMETIC), - LINK_PUSH_WITH_TERM( - SYM_AT_LEFT_BRACE, - LEX_STATE_HASHTABLE, - 0, - SYM_RIGHT_BRACE), - LINK_PUSH(SYM_AT, LEX_STATE_ARITHMETIC, 0), - LINK_CHANGE(SYM_LEFT_PAREN, LEX_STATE_ARITHMETIC), - LINK_CHANGE(SYM_LEFT_BRACKET, LEX_STATE_ARITHMETIC), - LINK_CHANGE(SYM_BANG, LEX_STATE_ARITHMETIC), - LINK_PUSH_WITH_TERM( - SYM_LEFT_PAREN, - LEX_STATE_STATEMENT, - STATEMENT_F_DISABLE_KEYWORDS, - SYM_RIGHT_PAREN), - - /* statement tokens */ - LINK_PUSH_WITH_TERM( - SYM_LEFT_BRACE, - LEX_STATE_STATEMENT, - 0, - SYM_RIGHT_BRACE), - LINK_PUSH_WITH_TERM( - SYM_DOLLAR_LEFT_PAREN, - LEX_STATE_STATEMENT, - 0, - SYM_RIGHT_PAREN), - - /* command tokens */ - LINK_CHANGE(KW_FUNC, LEX_STATE_COMMAND), - LINK_CHANGE(SYM_AMPERSAND, LEX_STATE_COMMAND), - LINK_CHANGE(TOK_WORD, LEX_STATE_COMMAND), - LINK_END, -}; - -static const unsigned int keywords[] = { - KW_FUNC, - KW_IF, - KW_ELSEIF, - KW_ELSE, - KW_NONE, -}; - -static const unsigned int operators[] = { - TKOP_BNOT, - TKOP_NOT, - TKOP_NONE, -}; - -static const unsigned int symbols[] = { - SYM_AMPERSAND, - SYM_BANG, - SYM_SQUOTE, - SYM_DQUOTE, - SYM_HASH, - SYM_AT, - SYM_AT_LEFT_PAREN, - SYM_AT_LEFT_BRACE, - SYM_PIPE, - SYM_COMMA, - SYM_SEMICOLON, - SYM_LEFT_BRACE, - SYM_RIGHT_BRACE, - SYM_LEFT_BRACKET, - SYM_RIGHT_BRACKET, - SYM_LEFT_PAREN, - SYM_RIGHT_PAREN, - SYM_NONE, -}; - -const struct lex_state_type lex_statement_state = { - .s_id = LEX_STATE_STATEMENT, - .s_pump_token = statement_pump_token, - .s_links = links, - .s_keywords = keywords, - .s_operators = operators, - .s_symbols = symbols, -}; diff --git a/bshell/parse/parse.c b/bshell/parse/parse.c deleted file mode 100644 index d199e6f..0000000 --- a/bshell/parse/parse.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "parse.h" - -#include "../ast/ast.h" -#include "../debug.h" -#include "lex.h" -#include "syntax.h" -#include "token.h" - -#include -#include - -enum bshell_status parse_ctx_init(struct parse_ctx *ctx, struct lex_ctx *src) -{ - memset(ctx, 0x0, sizeof *ctx); - - ctx->p_src = src; - - return BSHELL_SUCCESS; -} - -void parse_ctx_cleanup(struct parse_ctx *ctx) -{ -} - -struct ast_node *parse_ctx_read_node(struct parse_ctx *ctx) -{ - parse_symbol(ctx, SYM_SEMICOLON); - parse_linefeed(ctx); - - struct ast_node *result = NULL; - bool ok = parse_statement(ctx, &result); - - return ok ? result : NULL; -} - -void report_error(struct parse_ctx *ctx, const char *format, ...) -{ - ctx->p_status = BSHELL_ERR_BAD_SYNTAX; - fprintf(stderr, "PARSE: "); - - va_list arg; - va_start(arg, format); - vfprintf(stderr, format, arg); - va_end(arg); - - fprintf(stderr, "\n"); - - struct lex_token *tok = peek_token(ctx); - fprintf(stderr, " peek_token = "); - if (tok) { - print_lex_token(tok); - } else { - fprintf(stderr, " EOF\n"); - } -} diff --git a/bshell/parse/parse.h b/bshell/parse/parse.h deleted file mode 100644 index 867fe4c..0000000 --- a/bshell/parse/parse.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef PARSE_H_ -#define PARSE_H_ - -#include "../status.h" - -struct lex_ctx; -struct ast_node; - -struct parse_ctx { - struct lex_ctx *p_src; - enum bshell_status p_status; -}; - -extern enum bshell_status parse_ctx_init( - struct parse_ctx *ctx, - struct lex_ctx *src); -extern void parse_ctx_cleanup(struct parse_ctx *ctx); - -extern struct ast_node *parse_ctx_read_node(struct parse_ctx *ctx); - -#endif diff --git a/bshell/parse/syntax.h b/bshell/parse/syntax.h deleted file mode 100644 index fc8ebcd..0000000 --- a/bshell/parse/syntax.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef PARSE_SYNTAX_H_ -#define PARSE_SYNTAX_H_ - -#include "../ast/ast.h" -#include "../operator.h" -#include "lex.h" -#include "parse.h" -#include "token.h" - -#include -#include - -extern void report_error(struct parse_ctx *ctx, const char *format, ...); - -extern struct lex_token *peek_token(struct parse_ctx *ctx); -extern enum token_type peek_token_type(struct parse_ctx *ctx); -extern enum token_keyword peek_unknown_keyword(struct parse_ctx *ctx); -extern enum token_symbol peek_unknown_symbol(struct parse_ctx *ctx); - -extern struct lex_token *claim_token(struct parse_ctx *ctx); -extern void discard_token(struct parse_ctx *ctx); - -extern bool peek_linefeed(struct parse_ctx *ctx); -extern bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym); -extern bool peek_word(struct parse_ctx *ctx, struct lex_token **out); -extern bool peek_int(struct parse_ctx *ctx); - -extern bool parse_linefeed(struct parse_ctx *ctx); -extern bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym); -extern bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw); -extern bool parse_word(struct parse_ctx *ctx, struct lex_token **out); -extern bool parse_var(struct parse_ctx *ctx, struct lex_token **out); -extern bool parse_flag(struct parse_ctx *ctx, struct lex_token **out); - -extern bool peek_arith_expr(struct parse_ctx *ctx); -extern bool parse_arith_value(struct parse_ctx *ctx, struct ast_node **out); -extern bool parse_arith_expr( - struct parse_ctx *ctx, - enum operator_precedence minimum_precedence, - struct ast_node **out); - -extern bool peek_keyword_expr(struct parse_ctx *ctx); -extern bool parse_keyword_expr(struct parse_ctx *ctx, struct ast_node **out); - -extern bool parse_if(struct parse_ctx *ctx, struct ast_node **out); -extern bool parse_func(struct parse_ctx *ctx, struct ast_node **out); - -extern bool parse_fstring(struct parse_ctx *ctx, struct ast_node **out); - -extern bool parse_block(struct parse_ctx *ctx, struct ast_node **out); - -extern bool peek_command(struct parse_ctx *ctx); -extern bool parse_pipeline( - struct parse_ctx *ctx, - struct ast_node *first_item, - struct ast_node **out); -extern bool parse_command(struct parse_ctx *ctx, struct ast_node **out); -extern bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out); -extern bool parse_redirect(struct parse_ctx *ctx, struct ast_node **out); - -extern bool parse_expr(struct parse_ctx *ctx, struct ast_node **out); -extern bool peek_statement(struct parse_ctx *ctx); -extern bool parse_statement(struct parse_ctx *ctx, struct ast_node **out); -extern bool parse_statement_list(struct parse_ctx *ctx, struct ast_node **out); - -#endif diff --git a/bshell/parse/syntax/block.c b/bshell/parse/syntax/block.c deleted file mode 100644 index 998aa0f..0000000 --- a/bshell/parse/syntax/block.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "../syntax.h" - -bool parse_block(struct parse_ctx *ctx, struct ast_node **out) -{ - if (!parse_symbol(ctx, SYM_LEFT_BRACE)) { - return false; - } - - parse_linefeed(ctx); - - struct block_ast_node *block - = (struct block_ast_node *)ast_node_create(AST_BLOCK); - - bool ok = true; - while (1) { - if (parse_symbol(ctx, SYM_RIGHT_BRACE)) { - break; - } - - parse_linefeed(ctx); - - struct ast_node *stmt = NULL; - if (!parse_statement(ctx, &stmt)) { - ok = false; - break; - } - - fx_queue_push_back(&block->n_statements, &stmt->n_entry); - - if (parse_symbol(ctx, SYM_RIGHT_BRACE)) { - break; - } - - if (!parse_linefeed(ctx) && !parse_symbol(ctx, SYM_SEMICOLON)) { - report_error( - ctx, - "expected `;`, `}`, or linefeed after " - "statement"); - ok = false; - break; - } - } - - if (!ok) { - ast_node_destroy((struct ast_node *)block); - block = NULL; - } - - *out = (struct ast_node *)block; - return true; -} diff --git a/bshell/parse/syntax/generic.c b/bshell/parse/syntax/generic.c deleted file mode 100644 index 0b0a848..0000000 --- a/bshell/parse/syntax/generic.c +++ /dev/null @@ -1,157 +0,0 @@ -#include "../lex.h" -#include "../parse.h" -#include "../syntax.h" -#include "../token.h" - -struct lex_token *claim_token(struct parse_ctx *ctx) -{ - return lex_ctx_claim(ctx->p_src); -} - -void discard_token(struct parse_ctx *ctx) -{ - return lex_ctx_discard(ctx->p_src); -} - -struct lex_token *peek_token(struct parse_ctx *ctx) -{ - return lex_ctx_peek(ctx->p_src); -} - -enum token_type peek_token_type(struct parse_ctx *ctx) -{ - struct lex_token *tok = peek_token(ctx); - return tok ? tok->tok_type : TOK_NONE; -} - -enum token_symbol peek_unknown_symbol(struct parse_ctx *ctx) -{ - struct lex_token *tok = peek_token(ctx); - return (tok && tok->tok_type == TOK_SYMBOL) ? tok->tok_symbol - : SYM_NONE; -} - -enum token_keyword peek_unknown_keyword(struct parse_ctx *ctx) -{ - struct lex_token *tok = peek_token(ctx); - return (tok && tok->tok_type == TOK_KEYWORD) ? tok->tok_keyword - : KW_NONE; -} - -bool peek_word(struct parse_ctx *ctx, struct lex_token **out) -{ - struct lex_token *tok = peek_token(ctx); - if (tok && tok->tok_type == TOK_WORD) { - *out = tok; - return true; - } - - return false; -} - -bool peek_linefeed(struct parse_ctx *ctx) -{ - struct lex_token *tok = peek_token(ctx); - if (tok && tok->tok_type == TOK_LINEFEED) { - return true; - } - - return false; -} - -bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym) -{ - struct lex_token *tok = peek_token(ctx); - if (!tok) { - return false; - } - - if (tok->tok_type != TOK_SYMBOL) { - return false; - } - - if (tok->tok_symbol != sym) { - return false; - } - - return true; -} - -bool parse_linefeed(struct parse_ctx *ctx) -{ - struct lex_token *tok = peek_token(ctx); - if (tok && tok->tok_type == TOK_LINEFEED) { - discard_token(ctx); - return true; - } - - return false; -} - -bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym) -{ - struct lex_token *tok = peek_token(ctx); - if (!tok) { - return false; - } - - if (tok->tok_type != TOK_SYMBOL) { - return false; - } - - if (tok->tok_symbol != sym) { - return false; - } - - discard_token(ctx); - return true; -} - -bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw) -{ - struct lex_token *tok = peek_token(ctx); - if (!tok) { - return false; - } - - if (tok->tok_type != TOK_KEYWORD) { - return false; - } - - if (tok->tok_keyword != kw) { - return false; - } - - discard_token(ctx); - return true; -} - -bool parse_word(struct parse_ctx *ctx, struct lex_token **out) -{ - struct lex_token *tok = peek_token(ctx); - if (!tok) { - return false; - } - - if (tok->tok_type != TOK_WORD) { - return false; - } - - *out = claim_token(ctx); - return true; -} - -bool parse_var(struct parse_ctx *ctx, struct lex_token **out) -{ - struct lex_token *tok = peek_token(ctx); - if (!tok) { - return false; - } - - if (tok->tok_type != TOK_VAR) { - return false; - } - - *out = claim_token(ctx); - return true; -} diff --git a/bshell/parse/syntax/if-else.c b/bshell/parse/syntax/if-else.c deleted file mode 100644 index dae787d..0000000 --- a/bshell/parse/syntax/if-else.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "../syntax.h" - -static bool add_branch( - struct if_ast_node *group, - struct ast_node *cond, - struct ast_node *body) -{ - struct if_branch_ast_node *branch = (struct if_branch_ast_node *) - ast_node_create(AST_IF_BRANCH); - if (!branch) { - return false; - } - - branch->n_cond = cond; - branch->n_body = body; - fx_queue_push_back(&group->n_branches, &branch->n_base.n_entry); - - return true; -} - -bool parse_if(struct parse_ctx *ctx, struct ast_node **out) -{ - if (!parse_keyword(ctx, KW_IF)) { - return false; - } - - if (!parse_symbol(ctx, SYM_LEFT_PAREN)) { - report_error(ctx, "expected `(` after `if`"); - return false; - } - - struct ast_node *if_cond = NULL, *if_body = NULL; - if (!parse_expr(ctx, &if_cond)) { - report_error(ctx, "invalid if condition"); - return false; - } - - if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) { - report_error(ctx, "expected `)` after if-condition"); - ast_node_destroy(if_cond); - return false; - } - - if (!parse_block(ctx, &if_body)) { - report_error(ctx, "invalid if body"); - ast_node_destroy(if_cond); - return false; - } - - struct if_ast_node *if_group = (struct if_ast_node *)ast_node_create( - AST_IF); - if (!if_group) { - ctx->p_status = BSHELL_ERR_NO_MEMORY; - ast_node_destroy(if_cond); - ast_node_destroy(if_body); - return false; - } - - if (!add_branch(if_group, if_cond, if_body)) { - ctx->p_status = BSHELL_ERR_NO_MEMORY; - ast_node_destroy(if_cond); - ast_node_destroy(if_body); - ast_node_destroy((struct ast_node *)if_group); - return false; - } - - bool done = false; - while (!done) { - struct ast_node *cond = NULL, *body = NULL; - if (parse_keyword(ctx, KW_ELSE)) { - done = true; - } else if (parse_keyword(ctx, KW_ELSEIF)) { - if (!parse_symbol(ctx, SYM_LEFT_PAREN)) { - report_error( - ctx, - "expected `(` after `elseif`"); - return false; - } - - if (!parse_expr(ctx, &cond)) { - report_error( - ctx, - "invalid conditional expression"); - ast_node_destroy((struct ast_node *)if_group); - return false; - } - - if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) { - report_error( - ctx, - "expected `)` after elseif-condition"); - ast_node_destroy(if_cond); - return false; - } - } else { - done = true; - break; - } - - if (!parse_block(ctx, &body)) { - report_error(ctx, "invalid conditional body"); - if (cond) { - ast_node_destroy(cond); - } - - ast_node_destroy((struct ast_node *)if_group); - return false; - } - - if (!add_branch(if_group, cond, body)) { - report_error(ctx, "failed to add branch to if-group"); - if (cond) { - ast_node_destroy(cond); - } - - ast_node_destroy(body); - ast_node_destroy((struct ast_node *)if_group); - return false; - } - } - - *out = (struct ast_node *)if_group; - - return true; -} diff --git a/bshell/parse/syntax/keyword.c b/bshell/parse/syntax/keyword.c deleted file mode 100644 index 3c285e1..0000000 --- a/bshell/parse/syntax/keyword.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "../syntax.h" - -bool peek_keyword_expr(struct parse_ctx *ctx) -{ - return peek_unknown_keyword(ctx) != KW_NONE; -} - -bool parse_keyword_expr(struct parse_ctx *ctx, struct ast_node **out) -{ - switch (peek_unknown_keyword(ctx)) { - case KW_NONE: - return false; - case KW_IF: - return parse_if(ctx, out); - case KW_FUNC: - return parse_func(ctx, out); - default: - ctx->p_status = BSHELL_ERR_BAD_SYNTAX; - return false; - } -} diff --git a/bshell/parse/token.c b/bshell/parse/token.c deleted file mode 100644 index ae2b19f..0000000 --- a/bshell/parse/token.c +++ /dev/null @@ -1,213 +0,0 @@ -#include "token.h" - -#include -#include -#include - -struct lex_token *lex_token_create(enum token_type type) -{ - struct lex_token *out = malloc(sizeof *out); - if (!out) { - return NULL; - } - - memset(out, 0x0, sizeof *out); - - out->tok_type = type; - - return out; -} - -struct lex_token *lex_token_create_with_string( - enum token_type type, - const char *s) -{ - struct lex_token *tok = lex_token_create(type); - if (!tok) { - return NULL; - } - - tok->tok_str = fx_strdup(s); - if (!tok->tok_str) { - free(tok); - return NULL; - } - - return tok; -} - -void lex_token_destroy(struct lex_token *tok) -{ - switch (tok->tok_type) { - case TOK_WORD: - case TOK_FLAG: - case TOK_STRING: - if (tok->tok_str) { - free(tok->tok_str); - } - - break; - default: - break; - } - - free(tok); -} - -struct lex_token *lex_token_change_type( - struct lex_token *tok, - enum token_type new_type) -{ - switch (tok->tok_type) { - case TOK_WORD: - case TOK_FLAG: - case TOK_STRING: - if (tok->tok_str) { - free(tok->tok_str); - tok->tok_str = NULL; - } - break; - default: - break; - } - - tok->tok_type = new_type; - return tok; -} - -void lex_token_change_string(struct lex_token *tok, const char *s) -{ - if (!lex_token_has_string_value(tok)) { - return; - } - - if (tok->tok_str) { - free(tok->tok_str); - } - - tok->tok_str = fx_strdup(s); -} - -#define ENUM_STR(x) \ - case x: \ - return #x - -const char *token_type_to_string(enum token_type type) -{ - switch (type) { - ENUM_STR(TOK_NONE); - ENUM_STR(TOK_KEYWORD); - ENUM_STR(TOK_SYMBOL); - ENUM_STR(TOK_INT); - ENUM_STR(TOK_DOUBLE); - ENUM_STR(TOK_WORD); - ENUM_STR(TOK_WORD_START); - ENUM_STR(TOK_WORD_END); - ENUM_STR(TOK_OPERATOR); - ENUM_STR(TOK_VAR); - ENUM_STR(TOK_VAR_SPLAT); - ENUM_STR(TOK_FLAG); - ENUM_STR(TOK_STRING); - ENUM_STR(TOK_STR_START); - ENUM_STR(TOK_STR_END); - ENUM_STR(TOK_LINEFEED); - default: - return ""; - } -} - -const char *token_keyword_to_string(enum token_keyword keyword) -{ - switch (keyword) { - ENUM_STR(KW_NONE); - ENUM_STR(KW_FUNC); - ENUM_STR(KW_IF); - ENUM_STR(KW_ELSEIF); - ENUM_STR(KW_ELSE); - default: - return ""; - } -} - -const char *token_symbol_to_string(enum token_symbol sym) -{ - switch (sym) { - ENUM_STR(SYM_NONE); - ENUM_STR(SYM_PLUS); - ENUM_STR(SYM_HYPHEN); - ENUM_STR(SYM_FORWARD_SLASH); - ENUM_STR(SYM_ASTERISK); - ENUM_STR(SYM_AMPERSAND); - ENUM_STR(SYM_PERCENT); - ENUM_STR(SYM_SQUOTE); - ENUM_STR(SYM_DQUOTE); - ENUM_STR(SYM_HASH); - ENUM_STR(SYM_COLON_COLON); - ENUM_STR(SYM_SEMICOLON); - ENUM_STR(SYM_COMMA); - ENUM_STR(SYM_DOLLAR); - ENUM_STR(SYM_DOLLAR_LEFT_PAREN); - ENUM_STR(SYM_DOLLAR_LEFT_BRACE); - ENUM_STR(SYM_DOT); - ENUM_STR(SYM_DOT_DOT); - ENUM_STR(SYM_PIPE); - ENUM_STR(SYM_AT); - ENUM_STR(SYM_AT_LEFT_PAREN); - ENUM_STR(SYM_AT_LEFT_BRACE); - ENUM_STR(SYM_LEFT_BRACE); - ENUM_STR(SYM_RIGHT_BRACE); - ENUM_STR(SYM_LEFT_BRACKET); - ENUM_STR(SYM_RIGHT_BRACKET); - ENUM_STR(SYM_LEFT_PAREN); - ENUM_STR(SYM_RIGHT_PAREN); - ENUM_STR(SYM_EQUAL); - ENUM_STR(SYM_PLUS_EQUAL); - ENUM_STR(SYM_HYPHEN_EQUAL); - ENUM_STR(SYM_ASTERISK_EQUAL); - ENUM_STR(SYM_FORWARD_SLASH_EQUAL); - ENUM_STR(SYM_PERCENT_EQUAL); - ENUM_STR(SYM_QUESTION_DOT); - ENUM_STR(SYM_QUESTION_LEFT_BRACKET); - default: - return ""; - } -} - -const char *token_operator_to_string(enum token_operator op) -{ - switch (op) { - ENUM_STR(TKOP_BAND); - ENUM_STR(TKOP_BOR); - ENUM_STR(TKOP_BXOR); - ENUM_STR(TKOP_BNOT); - ENUM_STR(TKOP_SHL); - ENUM_STR(TKOP_SHR); - ENUM_STR(TKOP_EQ); - ENUM_STR(TKOP_NE); - ENUM_STR(TKOP_GT); - ENUM_STR(TKOP_LT); - ENUM_STR(TKOP_GE); - ENUM_STR(TKOP_LE); - ENUM_STR(TKOP_MATCH); - ENUM_STR(TKOP_NOTMATCH); - ENUM_STR(TKOP_REPLACE); - ENUM_STR(TKOP_LIKE); - ENUM_STR(TKOP_NOTLIKE); - ENUM_STR(TKOP_IN); - ENUM_STR(TKOP_F); - ENUM_STR(TKOP_NOTIN); - ENUM_STR(TKOP_CONTAINS); - ENUM_STR(TKOP_NOTCONTAINS); - ENUM_STR(TKOP_AND); - ENUM_STR(TKOP_OR); - ENUM_STR(TKOP_XOR); - ENUM_STR(TKOP_NOT); - ENUM_STR(TKOP_SPLIT); - ENUM_STR(TKOP_JOIN); - ENUM_STR(TKOP_IS); - ENUM_STR(TKOP_ISNOT); - ENUM_STR(TKOP_AS); - default: - return ""; - } -} diff --git a/bshell/parse/token.h b/bshell/parse/token.h deleted file mode 100644 index 1bf4f07..0000000 --- a/bshell/parse/token.h +++ /dev/null @@ -1,184 +0,0 @@ -#ifndef IVY_LANG_LEX_H_ -#define IVY_LANG_LEX_H_ - -#include -#include -#include - -struct char_cell { - unsigned long c_row, c_col; -}; - -enum token_type { - TOK_NONE = 0, - __TOK_INDEX_BASE = 100, - TOK_KEYWORD, - TOK_SYMBOL, - TOK_INT, - TOK_DOUBLE, - TOK_WORD, - TOK_WORD_START, - TOK_WORD_END, - TOK_FLAG, - TOK_OPERATOR, - TOK_VAR, - TOK_VAR_SPLAT, - TOK_STRING, - TOK_STR_START, - TOK_STR_END, - TOK_LINEFEED, - __TOK_INDEX_LIMIT, -}; - -enum token_keyword { - KW_NONE = 0, - __KW_INDEX_BASE = 200, - KW_FUNC, - KW_IF, - KW_ELSEIF, - KW_ELSE, - __KW_INDEX_LIMIT, -}; - -enum token_operator { - TKOP_NONE = 0, - __TKOP_INDEX_BASE = 300, - TKOP_F, - TKOP_BAND, - TKOP_BOR, - TKOP_BXOR, - TKOP_BNOT, - TKOP_SHL, - TKOP_SHR, - TKOP_EQ, - TKOP_NE, - TKOP_GT, - TKOP_LT, - TKOP_GE, - TKOP_LE, - TKOP_MATCH, - TKOP_NOTMATCH, - TKOP_REPLACE, - TKOP_LIKE, - TKOP_NOTLIKE, - TKOP_IN, - TKOP_NOTIN, - TKOP_CONTAINS, - TKOP_NOTCONTAINS, - TKOP_AND, - TKOP_OR, - TKOP_XOR, - TKOP_NOT, - TKOP_SPLIT, - TKOP_JOIN, - TKOP_IS, - TKOP_ISNOT, - TKOP_AS, - __TKOP_INDEX_LIMIT, -}; - -enum token_symbol { - SYM_NONE = 0, - __SYM_INDEX_BASE = 400, - SYM_BANG, - SYM_PLUS, - SYM_HYPHEN, - SYM_FORWARD_SLASH, - SYM_ASTERISK, - SYM_AMPERSAND, - SYM_PERCENT, - SYM_SQUOTE, - SYM_DQUOTE, - SYM_HASH, - SYM_COLON_COLON, - SYM_SEMICOLON, - SYM_COMMA, - SYM_DOLLAR, - SYM_DOLLAR_LEFT_PAREN, - SYM_DOLLAR_LEFT_BRACE, - SYM_DOT, - SYM_DOT_DOT, - SYM_PIPE, - SYM_AT, - SYM_AT_LEFT_PAREN, - SYM_AT_LEFT_BRACE, - SYM_LEFT_BRACE, - SYM_RIGHT_BRACE, - SYM_LEFT_BRACKET, - SYM_RIGHT_BRACKET, - SYM_LEFT_PAREN, - SYM_RIGHT_PAREN, - SYM_EQUAL, - SYM_PLUS_EQUAL, - SYM_HYPHEN_EQUAL, - SYM_ASTERISK_EQUAL, - SYM_FORWARD_SLASH_EQUAL, - SYM_PERCENT_EQUAL, - SYM_QUESTION_DOT, - SYM_QUESTION_LEFT_BRACKET, - __SYM_INDEX_LIMIT, -}; - -struct lex_token { - enum token_type tok_type; - - struct char_cell tok_start, tok_end; - - fx_queue_entry tok_entry; - - union { - enum token_keyword tok_keyword; - enum token_symbol tok_symbol; - enum token_operator tok_operator; - fx_value tok_number; - char *tok_str; - }; -}; - -extern struct lex_token *lex_token_create(enum token_type type); -extern struct lex_token *lex_token_create_with_string( - enum token_type type, - const char *s); -extern void lex_token_destroy(struct lex_token *tok); - -extern struct lex_token *lex_token_change_type( - struct lex_token *tok, - enum token_type new_type); -extern void lex_token_change_string(struct lex_token *tok, const char *s); - -static inline bool lex_token_is_symbol( - struct lex_token *tok, - enum token_symbol sym) -{ - return (tok->tok_type == TOK_SYMBOL && tok->tok_symbol == sym); -} -static inline bool lex_token_is_keyword( - struct lex_token *tok, - enum token_keyword kw) -{ - return (tok->tok_type == TOK_KEYWORD && tok->tok_keyword == kw); -} -static inline bool lex_token_type_has_string_value(enum token_type type) -{ - switch (type) { - case TOK_WORD: - case TOK_STRING: - case TOK_FLAG: - case TOK_VAR: - case TOK_VAR_SPLAT: - return true; - default: - return false; - } -} -static inline bool lex_token_has_string_value(const struct lex_token *tok) -{ - return lex_token_type_has_string_value(tok->tok_type); -} - -extern const char *token_type_to_string(enum token_type type); -extern const char *token_keyword_to_string(enum token_keyword keyword); -extern const char *token_symbol_to_string(enum token_symbol sym); -extern const char *token_operator_to_string(enum token_operator op); - -#endif diff --git a/bshell/runtime/opcode.h b/bshell/runtime/opcode.h deleted file mode 100644 index f6df813..0000000 --- a/bshell/runtime/opcode.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef RUNTIME_OPCODE_H_ -#define RUNTIME_OPCODE_H_ - -#include - -#define BSHELL_INSTRUCTION_INVALID 0xFFFFFFFF - -typedef uint32_t bshell_instruction; - -enum bshell_opcode { - OPCODE_NOP = 0, - OPCODE_LDC_INT, - OPCODE_LDC_STR, - OPCODE_LDC_FP, - OPCODE_LDGLOBAL, - OPCODE_LDLOCAL, - OPCODE_LDBLOCK, - OPCODE_LDENV, - OPCODE_LDSTATIC, - OPCODE_LDARG, - OPCODE_LDPROP, - OPCODE_LDELEM, - OPCODE_LDELEM_C, - OPCODE_STLOCAL, - OPCODE_STPROP, - OPCODE_STELEM, - OPCODE_LDCMD, - OPCODE_PEXEC, - OPCODE_CALL, - OPCODE_MK_STR, - OPCODE_MK_ARRAY, - OPCODE_MK_HTAB, - OPCODE_POP, - OPCODE_ADD, - OPCODE_SUB, - OPCODE_MUL, - OPCODE_DIV, - OPCODE_ADD_IP, - OPCODE_MOD, - OPCODE_INC, - OPCODE_DEC, - OPCODE_SHL, - OPCODE_SHR, - OPCODE_BAND, - OPCODE_BOR, - OPCODE_BXOR, - OPCODE_BNOT, - OPCODE_CMP_NULL, - OPCODE_CMP_EQ, - OPCODE_CMP_NE, - OPCODE_CMP_LT, - OPCODE_CMP_GT, - OPCODE_CMP_LE, - OPCODE_CMP_GE, - OPCODE_LAND, - OPCODE_LOR, - OPCODE_LXOR, - OPCODE_LNOT, - OPCODE_BR, - OPCODE_BR_TRUE, - OPCODE_RANGE, - OPCODE_MATCH, - OPCODE_REPLACE, - OPCODE_LIKE, - OPCODE_IN, - OPCODE_FMT, - OPCODE_CONTAINS, - OPCODE_SPLIT, - OPCODE_JOIN, - OPCODE_IS, - OPCODE_AS, -}; - -extern bshell_instruction bshell_instruction_encode( - enum bshell_opcode opcode, - uint32_t arg); -extern void bshell_instruction_decode( - bshell_instruction instr, - enum bshell_opcode *out_opcode, - uint32_t *out_arg); - -#endif