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.
This commit is contained in:
2024-11-24 20:50:12 +00:00
parent 5622073252
commit 1e7e73db21
7 changed files with 188 additions and 7 deletions

48
lang/ast/iterate.c Normal file
View File

@@ -0,0 +1,48 @@
#include <ivy/lang/ast.h>
#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;
}

9
lang/ast/iterate.h Normal file
View File

@@ -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

View File

@@ -3,6 +3,7 @@
#include <ivy/lang/ast.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
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)
{
}
}
#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 "";
}
}

View File

@@ -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;

View File

@@ -1,3 +1,5 @@
#include <blue/object/string.h>
#include <stdio.h>
#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)

View File

@@ -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 = {