ast: implement post-order ast traversal

This commit is contained in:
2026-05-17 15:32:19 +01:00
parent e490754625
commit 1f8b9ff0d3
2 changed files with 123 additions and 18 deletions
+91 -17
View File
@@ -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;
}
+32 -1
View File
@@ -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);