lang: add user args to ast iterator; combine pre/post-order traversal modes
the caller can now provide a pointer arg to ivy_ast_node_iterate, which will be forwarded to the specified callback function each time it is called. the iterator now behaves similarly to fts, in that it visits each node in both pre-order and post-order, and indicates to the callback whether the current iteration is pre- or post-order.
This commit is contained in:
@@ -6,6 +6,7 @@ enum ivy_status iterate_regular(
|
||||
struct ivy_ast_node *node, struct ivy_ast_node_iterator *it,
|
||||
ivy_ast_node_iteration_callback callback)
|
||||
{
|
||||
#if 0
|
||||
b_queue_push_back(&it->it_queue, &node->n_it.it_entry);
|
||||
node->n_it.it_depth = 0;
|
||||
|
||||
@@ -33,6 +34,7 @@ enum ivy_status iterate_regular(
|
||||
|
||||
b_queue_delete(&it->it_queue, entry);
|
||||
}
|
||||
#endif
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
@@ -96,7 +98,7 @@ enum ivy_status iterate_postorder(
|
||||
return IVY_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
callback(node, it);
|
||||
// callback(node, it);
|
||||
}
|
||||
|
||||
return IVY_OK;
|
||||
@@ -104,18 +106,60 @@ enum ivy_status iterate_postorder(
|
||||
|
||||
enum ivy_status ivy_ast_node_iterate(
|
||||
struct ivy_ast_node *node, struct ivy_ast_node_iterator *it,
|
||||
enum ivy_ast_iterator_mode mode, ivy_ast_node_iteration_callback callback)
|
||||
ivy_ast_node_iteration_callback callback, void *arg)
|
||||
{
|
||||
memset(it, 0x0, sizeof *it);
|
||||
b_queue_push_back(&it->it_queue, &node->n_it.it_entry);
|
||||
node->n_it.it_depth = 0;
|
||||
|
||||
switch (mode) {
|
||||
case IVY_AST_ITERATE_REGULAR:
|
||||
return iterate_regular(node, it, callback);
|
||||
case IVY_AST_ITERATE_POSTORDER:
|
||||
return iterate_postorder(node, it, callback);
|
||||
default:
|
||||
return IVY_ERR_INVALID_VALUE;
|
||||
b_queue_iterator q_it;
|
||||
b_queue_iterator_begin(&it->it_queue, &q_it);
|
||||
|
||||
while (b_queue_iterator_is_valid(&q_it)) {
|
||||
struct ivy_ast_node_iterator_entry *it_entry = b_unbox(
|
||||
struct ivy_ast_node_iterator_entry, q_it.entry, it_entry);
|
||||
node = b_unbox(struct ivy_ast_node, it_entry, n_it);
|
||||
|
||||
if (!node) {
|
||||
/* this should never happen. */
|
||||
return IVY_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
enum ivy_status status
|
||||
= callback(node, IVY_AST_ITERATION_PRE, it, arg);
|
||||
if (status != IVY_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct ast_node_type *type = get_ast_node_type(node->n_type);
|
||||
if (type->n_collect_children) {
|
||||
it->it_insert_after = q_it.entry;
|
||||
type->n_collect_children(node, it);
|
||||
}
|
||||
|
||||
b_queue_iterator_next(&q_it);
|
||||
}
|
||||
|
||||
while (!b_queue_empty(&it->it_queue)) {
|
||||
b_queue_entry *entry = b_queue_pop_back(&it->it_queue);
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = b_unbox(struct ivy_ast_node, entry, n_it);
|
||||
|
||||
if (!node) {
|
||||
/* this should never happen. */
|
||||
return IVY_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
enum ivy_status status
|
||||
= callback(node, IVY_AST_ITERATION_POST, it, arg);
|
||||
if (status != IVY_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
void ast_node_iterator_enqueue_node(
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#ifndef _AST_ITERATE_H_
|
||||
#define _AST_ITERATE_H_
|
||||
|
||||
struct ivy_ast_node_iterator;
|
||||
struct ivy_ast_node;
|
||||
|
||||
extern void ast_node_iterator_enqueue_node(
|
||||
struct ivy_ast_node_iterator *it, struct ivy_ast_node *parent,
|
||||
struct ivy_ast_node *node);
|
||||
|
||||
Reference in New Issue
Block a user