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