diff --git a/bshell/ast/ast.c b/bshell/ast/ast.c index 32aef93..f887a17 100644 --- a/bshell/ast/ast.c +++ b/bshell/ast/ast.c @@ -26,7 +26,7 @@ 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_defintions[] = { +static const struct ast_node_definition *ast_node_definitions[] = { [AST_NULL] = &null_ast_node, [AST_INT] = &int_ast_node, [AST_DOUBLE] = &double_ast_node, @@ -47,14 +47,14 @@ static const struct ast_node_definition *ast_node_defintions[] = { [AST_HASHTABLE_ITEM] = &hashtable_item_ast_node, [AST_OP] = &op_ast_node, }; -static const size_t nr_ast_node_definitions - = sizeof ast_node_defintions / sizeof ast_node_defintions[0]; +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_defintions[type]; + const struct ast_node_definition *def = ast_node_definitions[type]; struct ast_node *out = malloc(def->def_node_size); if (!out) { return NULL; @@ -80,8 +80,8 @@ void ast_node_destroy(struct ast_node *node) break; } - const struct ast_node_definition *def - = ast_node_defintions[node->n_type]; + const struct ast_node_definition *def = ast_node_definitions + [node->n_type]; if (def->def_cleanup) { def->def_cleanup(node); @@ -92,15 +92,10 @@ void ast_node_destroy(struct ast_node *node) } } -void ast_node_iterate(struct ast_node *node, struct ast_iterator *it) -{ - ast_iterator_enqueue(it, node); -} - void ast_node_to_string(const struct ast_node *node, fx_bstr *out) { - const struct ast_node_definition *def - = ast_node_defintions[node->n_type]; + const struct ast_node_definition *def = ast_node_definitions + [node->n_type]; if (def->def_to_string) { def->def_to_string(node, out); } @@ -158,8 +153,8 @@ struct ast_node *ast_iterator_dequeue(struct ast_iterator *it) } struct ast_node *node = fx_unbox(struct ast_node, cur, n_it.e_entry); - const struct ast_node_definition *def - = ast_node_defintions[node->n_type]; + const struct ast_node_definition *def = ast_node_definitions + [node->n_type]; it->it_insert_after = cur; if (def->def_collect_children) { @@ -176,8 +171,10 @@ void ast_iterator_enqueue(struct ast_iterator *it, struct ast_node *node) 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); + struct ast_node *cur_node = fx_unbox( + struct ast_node, + cur, + n_it.e_entry); new_depth = cur_node->n_it.e_depth + 1; } @@ -194,3 +191,80 @@ void ast_iterator_enqueue(struct ast_iterator *it, struct ast_node *node) 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 index 826cb3c..447aabb 100644 --- a/bshell/ast/ast.h +++ b/bshell/ast/ast.h @@ -8,6 +8,12 @@ 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, @@ -170,6 +176,27 @@ struct ast_iterator { 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; @@ -182,8 +209,12 @@ struct ast_node_definition { 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_iterate(struct ast_node *node, struct ast_iterator *it); 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);