ast: implement post-order ast traversal
This commit is contained in:
+91
-17
@@ -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 if_branch_ast_node;
|
||||||
extern struct ast_node_definition op_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_NULL] = &null_ast_node,
|
||||||
[AST_INT] = &int_ast_node,
|
[AST_INT] = &int_ast_node,
|
||||||
[AST_DOUBLE] = &double_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_HASHTABLE_ITEM] = &hashtable_item_ast_node,
|
||||||
[AST_OP] = &op_ast_node,
|
[AST_OP] = &op_ast_node,
|
||||||
};
|
};
|
||||||
static const size_t nr_ast_node_definitions
|
static const size_t nr_ast_node_definitions = sizeof ast_node_definitions
|
||||||
= sizeof ast_node_defintions / sizeof ast_node_defintions[0];
|
/ sizeof ast_node_definitions[0];
|
||||||
|
|
||||||
struct ast_node *ast_node_create(enum ast_node_type type)
|
struct ast_node *ast_node_create(enum ast_node_type type)
|
||||||
{
|
{
|
||||||
assert(type < nr_ast_node_definitions);
|
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);
|
struct ast_node *out = malloc(def->def_node_size);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -80,8 +80,8 @@ void ast_node_destroy(struct ast_node *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct ast_node_definition *def
|
const struct ast_node_definition *def = ast_node_definitions
|
||||||
= ast_node_defintions[node->n_type];
|
[node->n_type];
|
||||||
|
|
||||||
if (def->def_cleanup) {
|
if (def->def_cleanup) {
|
||||||
def->def_cleanup(node);
|
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)
|
void ast_node_to_string(const struct ast_node *node, fx_bstr *out)
|
||||||
{
|
{
|
||||||
const struct ast_node_definition *def
|
const struct ast_node_definition *def = ast_node_definitions
|
||||||
= ast_node_defintions[node->n_type];
|
[node->n_type];
|
||||||
if (def->def_to_string) {
|
if (def->def_to_string) {
|
||||||
def->def_to_string(node, out);
|
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);
|
struct ast_node *node = fx_unbox(struct ast_node, cur, n_it.e_entry);
|
||||||
const struct ast_node_definition *def
|
const struct ast_node_definition *def = ast_node_definitions
|
||||||
= ast_node_defintions[node->n_type];
|
[node->n_type];
|
||||||
|
|
||||||
it->it_insert_after = cur;
|
it->it_insert_after = cur;
|
||||||
if (def->def_collect_children) {
|
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);
|
fx_queue_entry *cur = fx_queue_first(&it->it_queue);
|
||||||
if (cur) {
|
if (cur) {
|
||||||
struct ast_node *cur_node
|
struct ast_node *cur_node = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, cur, n_it.e_entry);
|
struct ast_node,
|
||||||
|
cur,
|
||||||
|
n_it.e_entry);
|
||||||
new_depth = cur_node->n_it.e_depth + 1;
|
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);
|
||||||
it->it_insert_after = &node->n_it.e_entry;
|
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
@@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
struct lex_token;
|
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 {
|
enum ast_node_type {
|
||||||
AST_NONE = 0x00u,
|
AST_NONE = 0x00u,
|
||||||
AST_NULL,
|
AST_NULL,
|
||||||
@@ -170,6 +176,27 @@ struct ast_iterator {
|
|||||||
fx_queue_entry *it_insert_after;
|
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 {
|
struct ast_node_definition {
|
||||||
enum ast_node_type def_id;
|
enum ast_node_type def_id;
|
||||||
size_t def_node_size;
|
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 struct ast_node *ast_node_create(enum ast_node_type type);
|
||||||
extern void ast_node_destroy(struct ast_node *node);
|
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 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 const char *ast_node_type_to_string(enum ast_node_type type);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user