From ed35011931e7f648134a84d89ab4b93b079eb5c4 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 23 Nov 2024 19:28:03 +0000 Subject: [PATCH] lang: ast: implement node, parser, and parser state management --- lang/ast.c | 142 +++++++++++++++++++++++++++++++++++- lang/ast.h | 12 ++- lang/include/ivy/lang/ast.h | 3 +- 3 files changed, 153 insertions(+), 4 deletions(-) diff --git a/lang/ast.c b/lang/ast.c index 1cf9846..9cff7ce 100644 --- a/lang/ast.c +++ b/lang/ast.c @@ -1,9 +1,110 @@ #include "ast.h" #include +#include #include #include +#define ast_node_create(id, type) _ast_node_create(id, sizeof(type)) +#define push_state(parser, node_type_id, node_type_struct, state_struct) _push_state(parser, node_type_id, sizeof(node_type_struct), sizeof(state_struct)) + +enum pop_state_flags { + ADD_NODE_TO_PARENT = 0x01u, +}; + +static enum ivy_status unit_add_child(struct ivy_ast_node *parent, struct ivy_ast_node *child) +{ + struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)parent; + b_queue_push_back(&unit->n_children, &child->n_entry); + + return IVY_OK; +} + +typedef enum ivy_status(*node_add_child_function)(struct ivy_ast_node *, struct ivy_ast_node *); + +static node_add_child_function node_add_child[] = { + [IVY_AST_UNIT] = unit_add_child, +}; +static const size_t nr_node_add_child = sizeof node_add_child / sizeof *node_add_child; + +static struct ivy_ast_node *_ast_node_create(enum ivy_ast_node_type type, size_t size) +{ + struct ivy_ast_node *node = malloc(size); + if (!node) { + return NULL; + } + + memset(node, 0x0, size); + + node->n_type = type; + + return node; +} + +static enum ivy_status ast_node_add_child(struct ivy_ast_node *parent, struct ivy_ast_node *child) +{ + if (parent->n_type >= nr_node_add_child) { + return IVY_ERR_NOT_SUPPORTED; + } + + node_add_child_function add_child = node_add_child[parent->n_type]; + + if (!add_child) { + return IVY_ERR_NOT_SUPPORTED; + } + + return add_child(parent, child); +} + +static struct parser_state *get_state(struct ivy_parser *parser) +{ + b_queue_entry *entry = b_queue_last(&parser->p_state); + if (!entry) { + return NULL; + } + + struct parser_state *state = b_unbox(struct parser_state, entry, s_entry); + return state; +} + +static struct parser_state *_push_state(struct ivy_parser *parser, enum ivy_ast_node_type type, size_t node_size, size_t state_size) +{ + struct parser_state *state = malloc(sizeof *state); + if (!state) { + return NULL; + } + + memset(state, 0x0, sizeof *state); + + b_queue_entry *current_state_entry = b_queue_last(&parser->p_state); + if (current_state_entry) { + struct parser_state *current_state = b_unbox(struct parser_state, current_state_entry, s_entry); + state->s_parent = current_state->s_node; + } + + state->s_node = ast_node_create(type, node_size); + + b_queue_push_back(&parser->p_state, &state->s_entry); + return state; +} + +static void pop_state(struct ivy_parser *parser, enum pop_state_flags flags) +{ + if (parser->p_state.q_first == parser->p_state.q_last) { + return; + } + + b_queue_entry *entry = b_queue_last(&parser->p_state); + struct parser_state *state = b_unbox(struct parser_state, entry, s_entry); + b_queue_pop_back(&parser->p_state); + + if (flags & ADD_NODE_TO_PARENT) { + ast_node_add_child(state->s_parent, state->s_node); + } + + free(state); +} + enum ivy_status ivy_parser_create(struct ivy_parser **parser) { struct ivy_parser *out = malloc(sizeof *out); @@ -13,6 +114,8 @@ enum ivy_status ivy_parser_create(struct ivy_parser **parser) memset(out, 0x0, sizeof *out); + push_state(out, IVY_AST_UNIT, struct ivy_ast_unit_node, struct unit_parser_state); + *parser = out; return IVY_OK; } @@ -27,9 +130,44 @@ enum ivy_status ivy_parser_get_status(struct ivy_parser *parser) return parser->p_status; } -struct ivy_ast_node *ivy_parser_read(struct ivy_parser *lex) +static enum ivy_status parse_unit_package(struct ivy_parser *parser, struct ivy_token *tok) { - return NULL; + return IVY_ERR_NOT_SUPPORTED; +} + +static enum ivy_status parse_token_in_unit(struct ivy_parser *parser, struct ivy_token *tok) +{ + if (tok->t_type == IVY_TOK_KEYWORD) { + switch (tok->t_keyword) { + case IVY_KW_PACKAGE: + return parse_unit_package(parser, tok); + default: + return IVY_ERR_BAD_SYNTAX; + } + } +} + +enum ivy_status ivy_parser_push_token(struct ivy_parser *parser, struct ivy_token *tok) +{ + struct parser_state *state = get_state(parser); + if (!state) { + parser->p_status = IVY_ERR_INTERNAL_FAILURE; + return parser->p_status; + } + + switch (state->s_node->n_type) { + case IVY_AST_UNIT: + parser->p_status = parse_token_in_unit(parser, tok); + break; + case IVY_AST_UNIT_PACKAGE: + parser->p_status = parse_unit_package(parser, tok); + break; + default: + parser->p_status = IVY_ERR_NOT_SUPPORTED; + break; + } + + return parser->p_status; } void ivy_ast_node_destroy(struct ivy_ast_node *node) diff --git a/lang/ast.h b/lang/ast.h index 7a628c3..520bc97 100644 --- a/lang/ast.h +++ b/lang/ast.h @@ -4,9 +4,14 @@ #include #include -struct ivy_parser_state { +struct parser_state { b_queue_entry s_entry; struct ivy_ast_node *s_parent; + struct ivy_ast_node *s_node; +}; + +struct unit_parser_state { + struct parser_state s_base; }; struct ivy_parser { @@ -16,4 +21,9 @@ struct ivy_parser { b_queue p_node_queue; }; +struct ast_node_ops { + enum ivy_status(*n_add_child)(struct ivy_ast_node *, struct ivy_ast_node *); + void(*n_print)(struct ivy_ast_node *); +}; + #endif diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index 7d25184..54fdc64 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -65,6 +65,7 @@ struct ivy_ast_node { struct ivy_ast_unit_node { struct ivy_ast_node n_base; + b_queue n_children; }; struct ivy_ast_op_node { @@ -229,7 +230,7 @@ IVY_API void ivy_parser_destroy(struct ivy_parser *parser); IVY_API enum ivy_status ivy_parser_get_status(struct ivy_parser *parser); -IVY_API void ivy_parser_push_token(struct ivy_parser *lex, struct ivy_token *tok); +IVY_API enum ivy_status ivy_parser_push_token(struct ivy_parser *parser, struct ivy_token *tok); IVY_API void ivy_ast_node_destroy(struct ivy_ast_node *node);