From 1e7e73db21f7f960b94faad39cd9a7d852f53393 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sun, 24 Nov 2024 20:50:12 +0000 Subject: [PATCH] lang: ast: implement ast iteration iteration is implementing without recursion, instead using type-specific callbacks to construct a queue of nodes to iterate through. ast priting is implemented using this functionality. --- lang/ast/iterate.c | 48 +++++++++++++++++++ lang/ast/iterate.h | 9 ++++ lang/ast/node.c | 91 ++++++++++++++++++++++++++++++++++++- lang/ast/node.h | 2 + lang/ast/unit-package.c | 18 ++++++++ lang/ast/unit.c | 11 ++++- lang/include/ivy/lang/ast.h | 16 +++++-- 7 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 lang/ast/iterate.c create mode 100644 lang/ast/iterate.h diff --git a/lang/ast/iterate.c b/lang/ast/iterate.c new file mode 100644 index 0000000..1248409 --- /dev/null +++ b/lang/ast/iterate.c @@ -0,0 +1,48 @@ +#include +#include "node.h" + +enum ivy_status ivy_ast_node_iterate( + struct ivy_ast_node *node, + struct ivy_ast_node_iterator *it, + ivy_ast_node_iteration_callback callback) +{ + memset(it, 0x0, sizeof *it); + 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); + struct ivy_ast_node_iterator_entry *it_entry = b_unbox(struct ivy_ast_node_iterator_entry, entry, it_entry); + node = b_unbox(struct ivy_ast_node, it_entry, n_it); + + 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); + } + + return IVY_OK; +} + +void ast_node_iterator_enqueue_node( + struct ivy_ast_node_iterator *it, + struct ivy_ast_node *parent, + struct ivy_ast_node *node) +{ + if (it->it_insert_after) { + b_queue_insert_after(&it->it_queue, &node->n_it.it_entry, it->it_insert_after); + } 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; +} \ No newline at end of file diff --git a/lang/ast/iterate.h b/lang/ast/iterate.h new file mode 100644 index 0000000..44d5cb0 --- /dev/null +++ b/lang/ast/iterate.h @@ -0,0 +1,9 @@ +#ifndef _AST_ITERATE_H_ +#define _AST_ITERATE_H_ + +extern void ast_node_iterator_enqueue_node( + struct ivy_ast_node_iterator *it, + struct ivy_ast_node *parent, + struct ivy_ast_node *node); + +#endif \ No newline at end of file diff --git a/lang/ast/node.c b/lang/ast/node.c index c37b381..f9b84df 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -3,6 +3,7 @@ #include #include #include +#include extern struct ast_node_type unit_node_ops; extern struct ast_node_type unit_package_node_ops; @@ -79,10 +80,98 @@ enum ivy_status ast_node_add_child( return add_child(parent, child); } +static enum ivy_status node_print(struct ivy_ast_node *node, struct ivy_ast_node_iterator *it) +{ + for (unsigned int i = 0; i < node->n_it.it_depth; i++) { + fputs(" ", stdout); + } + + const struct ast_node_type *type = get_ast_node_type(node->n_type); + if (type && type->n_print) { + type->n_print(node); + } else { + printf("%s\n", ivy_ast_node_type_to_string(node->n_type)); + } + + return IVY_OK; +} + void ivy_ast_node_print(struct ivy_ast_node *node) { + struct ivy_ast_node_iterator it = {0}; + ivy_ast_node_iterate(node, &it, node_print); } void ivy_ast_node_destroy(struct ivy_ast_node *node) { -} \ No newline at end of file +} + +#define ENUM_STR(x) \ + case x: \ + return #x + +const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v) +{ + switch (v) { + ENUM_STR(IVY_AST_NONE); + ENUM_STR(IVY_AST_UNIT); + ENUM_STR(IVY_AST_OP); + ENUM_STR(IVY_AST_MSG); + ENUM_STR(IVY_AST_CLASS); + ENUM_STR(IVY_AST_MSGH); + ENUM_STR(IVY_AST_PROPERTY); + ENUM_STR(IVY_AST_LAMBDA); + ENUM_STR(IVY_AST_UNIT_PACKAGE); + ENUM_STR(IVY_AST_UNIT_IMPORT); + ENUM_STR(IVY_AST_INT); + ENUM_STR(IVY_AST_DOUBLE); + ENUM_STR(IVY_AST_STRING); + ENUM_STR(IVY_AST_FSTRING); + ENUM_STR(IVY_AST_ATOM); + ENUM_STR(IVY_AST_IDENT); + ENUM_STR(IVY_AST_FOR_LOOP); + ENUM_STR(IVY_AST_WHILE_LOOP); + ENUM_STR(IVY_AST_COND_GROUP); + ENUM_STR(IVY_AST_COND); + ENUM_STR(IVY_AST_TUPLE); + ENUM_STR(IVY_AST_DO); + ENUM_STR(IVY_AST_TYPE_COUNT); + default: + return ""; + } +} + +const char *ivy_ast_op_to_string(enum ivy_ast_op v) +{ + switch (v) { + ENUM_STR(IVY_OP_NONE); + ENUM_STR(IVY_OP_ASSIGN); + ENUM_STR(IVY_OP_ADD); + ENUM_STR(IVY_OP_SUBTRACT); + ENUM_STR(IVY_OP_MULTIPLY); + ENUM_STR(IVY_OP_DIVIDE); + ENUM_STR(IVY_OP_LESS_THAN); + ENUM_STR(IVY_OP_GREATER_THAN); + ENUM_STR(IVY_OP_EQUAL); + ENUM_STR(IVY_OP_NOT_EQUAL); + ENUM_STR(IVY_OP_LESS_EQUAL); + ENUM_STR(IVY_OP_GREATER_EQUAL); + ENUM_STR(IVY_OP_AND); + ENUM_STR(IVY_OP_OR); + ENUM_STR(IVY_OP_IS); + ENUM_STR(IVY_OP_NOT); + default: + return ""; + } +} + +const char *ivy_ast_msgh_recipient_type_to_string(enum ivy_ast_op v) +{ + switch (v) { + ENUM_STR(IVY_AST_MSGH_NONE); + ENUM_STR(IVY_AST_MSGH_OBJECT); + ENUM_STR(IVY_AST_MSGH_CLASS); + default: + return ""; + } +} diff --git a/lang/ast/node.h b/lang/ast/node.h index 52ee06c..f049293 100644 --- a/lang/ast/node.h +++ b/lang/ast/node.h @@ -17,6 +17,8 @@ struct ast_node_type { struct ivy_ast_node *, struct ivy_ast_node *); void (*n_print)(struct ivy_ast_node *); void (*n_init_state)(struct parser_state *); + void (*n_collect_children)(struct ivy_ast_node *, struct ivy_ast_node_iterator *); + size_t n_state_size; size_t n_node_size; diff --git a/lang/ast/unit-package.c b/lang/ast/unit-package.c index 95aad18..baaf418 100644 --- a/lang/ast/unit-package.c +++ b/lang/ast/unit-package.c @@ -1,3 +1,5 @@ +#include +#include #include "unit-package.h" #include "ctx.h" @@ -54,6 +56,22 @@ static enum ivy_status add_child( static void print(struct ivy_ast_node *node) { + struct ivy_ast_unit_package_node *unit_package = (struct ivy_ast_unit_package_node *)node; + b_string *str = b_string_create(); + + b_queue_iterator it = {0}; + b_queue_foreach (&it, &unit_package->n_ident) { + struct ivy_token *tok = b_unbox(struct ivy_token, it.entry, t_entry); + + if (b_string_get_size(str, B_STRLEN_NORMAL) > 0) { + b_string_append_cstr(str, "."); + } + + b_string_append_cstr(str, tok->t_str); + } + + printf("%s(%s)\n", ivy_ast_node_type_to_string(node->n_type), b_string_ptr(str)); + b_string_release(str); } static void init_state(struct parser_state *sp) diff --git a/lang/ast/unit.c b/lang/ast/unit.c index 7df5dae..2c50e5d 100644 --- a/lang/ast/unit.c +++ b/lang/ast/unit.c @@ -2,6 +2,7 @@ #include "ctx.h" #include "node.h" #include "unit-package.h" +#include "iterate.h" static enum ivy_status parse_package_keyword( struct ivy_parser *ctx, struct ivy_token *tok) @@ -18,13 +19,19 @@ static enum ivy_status add_child( return IVY_OK; } -static void print(struct ivy_ast_node *node) +static void collect_children(struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { + struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)node; + b_queue_iterator it = {0}; + b_queue_foreach (&it, &unit->n_children) { + struct ivy_ast_node *child = b_unbox(struct ivy_ast_node, it.entry, n_entry); + ast_node_iterator_enqueue_node(iterator, node, child); + } } struct ast_node_type unit_node_ops = { .n_add_child = add_child, - .n_print = print, + .n_collect_children = collect_children, .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_unit_node), .n_keyword_parsers = { diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index 5f52c17..6d7240b 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -59,17 +59,22 @@ enum ivy_ast_msgh_recipient_type { IVY_AST_MSGH_CLASS, }; -struct ivy_ast_node_iterable { +struct ivy_ast_node_iterator { + b_queue it_queue; + b_queue_entry *it_insert_after; +}; + +struct ivy_ast_node_iterator_entry { b_queue_entry it_entry; unsigned int it_depth; }; -typedef enum ivy_status(*ivy_ast_node_iteration_callback)(struct ivy_ast_node *, unsigned int); +typedef enum ivy_status(*ivy_ast_node_iteration_callback)(struct ivy_ast_node *, struct ivy_ast_node_iterator *); struct ivy_ast_node { enum ivy_ast_node_type n_type; b_queue_entry n_entry; - struct ivy_ast_node_iterable n_it; + struct ivy_ast_node_iterator_entry n_it; }; struct ivy_ast_unit_node { @@ -245,7 +250,10 @@ IVY_API struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser); IVY_API enum ivy_status ivy_parser_push_token( struct ivy_parser *parser, struct ivy_token *tok); -IVY_API void ivy_ast_node_iterate(struct ivy_ast_node *node); +IVY_API enum ivy_status ivy_ast_node_iterate( + struct ivy_ast_node *node, + struct ivy_ast_node_iterator *it, + ivy_ast_node_iteration_callback callback); IVY_API void ivy_ast_node_print(struct ivy_ast_node *node); IVY_API void ivy_ast_node_destroy(struct ivy_ast_node *node);