2024-11-24 20:50:12 +00:00
|
|
|
#include "node.h"
|
|
|
|
|
|
2025-04-14 09:44:37 +01:00
|
|
|
#include <ivy/lang/ast.h>
|
|
|
|
|
|
|
|
|
|
enum ivy_status iterate_regular(
|
|
|
|
|
struct ivy_ast_node *node, struct ivy_ast_node_iterator *it,
|
2024-11-24 20:50:12 +00:00
|
|
|
ivy_ast_node_iteration_callback callback)
|
|
|
|
|
{
|
2025-04-14 12:24:42 +01:00
|
|
|
#if 0
|
2024-11-24 20:50:12 +00:00
|
|
|
b_queue_push_back(&it->it_queue, &node->n_it.it_entry);
|
|
|
|
|
node->n_it.it_depth = 0;
|
|
|
|
|
|
|
|
|
|
while (!b_queue_empty(&it->it_queue)) {
|
|
|
|
|
b_queue_entry *entry = b_queue_first(&it->it_queue);
|
2025-04-14 09:44:37 +01:00
|
|
|
struct ivy_ast_node_iterator_entry *it_entry = b_unbox(
|
|
|
|
|
struct ivy_ast_node_iterator_entry, entry, it_entry);
|
2024-11-24 20:50:12 +00:00
|
|
|
node = b_unbox(struct ivy_ast_node, it_entry, n_it);
|
|
|
|
|
|
2024-11-25 16:50:12 +00:00
|
|
|
if (!node) {
|
|
|
|
|
/* this should never happen. */
|
|
|
|
|
return IVY_ERR_INTERNAL_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 20:50:12 +00:00
|
|
|
enum ivy_status status = callback(node, it);
|
|
|
|
|
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 = entry;
|
|
|
|
|
type->n_collect_children(node, it);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_queue_delete(&it->it_queue, entry);
|
|
|
|
|
}
|
2025-04-14 12:24:42 +01:00
|
|
|
#endif
|
2024-11-24 20:50:12 +00:00
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 09:44:37 +01:00
|
|
|
enum ivy_status iterate_postorder(
|
|
|
|
|
struct ivy_ast_node *node, struct ivy_ast_node_iterator *it,
|
|
|
|
|
ivy_ast_node_iteration_callback callback)
|
|
|
|
|
{
|
|
|
|
|
/* general iteration strategy:
|
|
|
|
|
* 1. create a queue.
|
|
|
|
|
* 2. push `node` to the end of the queue.
|
|
|
|
|
* 3. for each node N in the queue:
|
|
|
|
|
* 1. collect N's children.
|
|
|
|
|
* 2. insert the children into the queue between N and the node
|
|
|
|
|
* immediately following N.
|
|
|
|
|
* 4. the loop in step 3 continues over all nodes added within the loop,
|
|
|
|
|
* and stops when all nodes have been visited.
|
|
|
|
|
* 5. iterate over the completed queue in reverse order, calling
|
|
|
|
|
* `callback` on each one.
|
|
|
|
|
*
|
|
|
|
|
* NOTES:
|
|
|
|
|
* - not sure how this will work for package definitions.
|
|
|
|
|
* - should probably use this just for the executable parts of the AST,
|
|
|
|
|
* not for nodes defining classes, function metadata, etc.
|
|
|
|
|
*/
|
|
|
|
|
b_queue_push_back(&it->it_queue, &node->n_it.it_entry);
|
|
|
|
|
node->n_it.it_depth = 0;
|
|
|
|
|
|
2025-11-06 10:38:32 +00:00
|
|
|
b_queue_entry *entry = b_queue_first(&it->it_queue);
|
2025-04-14 09:44:37 +01:00
|
|
|
|
2025-11-06 10:38:32 +00:00
|
|
|
while (entry) {
|
2025-04-14 09:44:37 +01:00
|
|
|
struct ivy_ast_node_iterator_entry *it_entry = b_unbox(
|
2025-11-06 10:38:32 +00:00
|
|
|
struct ivy_ast_node_iterator_entry, entry, it_entry);
|
2025-04-14 09:44:37 +01:00
|
|
|
node = b_unbox(struct ivy_ast_node, it_entry, n_it);
|
|
|
|
|
|
|
|
|
|
if (!node) {
|
|
|
|
|
/* this should never happen. */
|
|
|
|
|
return IVY_ERR_INTERNAL_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct ast_node_type *type = get_ast_node_type(node->n_type);
|
|
|
|
|
if (type->n_collect_children) {
|
2025-11-06 10:38:32 +00:00
|
|
|
it->it_insert_after = entry;
|
2025-04-14 09:44:37 +01:00
|
|
|
type->n_collect_children(node, it);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-06 10:38:32 +00:00
|
|
|
entry = b_queue_next(entry);
|
2025-04-14 09:44:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 12:24:42 +01:00
|
|
|
// callback(node, it);
|
2025-04-14 09:44:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ivy_status ivy_ast_node_iterate(
|
|
|
|
|
struct ivy_ast_node *node, struct ivy_ast_node_iterator *it,
|
2025-04-14 12:24:42 +01:00
|
|
|
ivy_ast_node_iteration_callback callback, void *arg)
|
2025-04-14 09:44:37 +01:00
|
|
|
{
|
2025-04-14 12:24:42 +01:00
|
|
|
b_queue_push_back(&it->it_queue, &node->n_it.it_entry);
|
|
|
|
|
node->n_it.it_depth = 0;
|
|
|
|
|
|
2025-11-06 10:38:32 +00:00
|
|
|
b_queue_entry *entry = b_queue_first(&it->it_queue);
|
2025-04-14 12:24:42 +01:00
|
|
|
|
2025-11-06 10:38:32 +00:00
|
|
|
while (entry) {
|
2025-04-14 12:24:42 +01:00
|
|
|
struct ivy_ast_node_iterator_entry *it_entry = b_unbox(
|
2025-11-06 10:38:32 +00:00
|
|
|
struct ivy_ast_node_iterator_entry, entry, it_entry);
|
2025-04-14 12:24:42 +01:00
|
|
|
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) {
|
2025-11-06 10:38:32 +00:00
|
|
|
it->it_insert_after = entry;
|
2025-04-14 12:24:42 +01:00
|
|
|
type->n_collect_children(node, it);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-06 10:38:32 +00:00
|
|
|
entry = b_queue_next(entry);
|
2025-04-14 09:44:37 +01:00
|
|
|
}
|
2025-04-14 12:24:42 +01:00
|
|
|
|
|
|
|
|
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;
|
2025-04-14 09:44:37 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-24 20:50:12 +00:00
|
|
|
void ast_node_iterator_enqueue_node(
|
2025-04-14 09:44:37 +01:00
|
|
|
struct ivy_ast_node_iterator *it, struct ivy_ast_node *parent,
|
2024-11-24 20:50:12 +00:00
|
|
|
struct ivy_ast_node *node)
|
|
|
|
|
{
|
|
|
|
|
if (it->it_insert_after) {
|
2025-04-14 09:44:37 +01:00
|
|
|
b_queue_insert_after(
|
|
|
|
|
&it->it_queue, &node->n_it.it_entry, it->it_insert_after);
|
2024-11-24 20:50:12 +00:00
|
|
|
} else {
|
|
|
|
|
b_queue_push_back(&it->it_queue, &node->n_it.it_entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node->n_it.it_depth = parent->n_it.it_depth + 1;
|
|
|
|
|
it->it_insert_after = &node->n_it.it_entry;
|
2025-04-14 09:44:37 +01:00
|
|
|
}
|