From f9b0096dd73cc83740cca61a72cec961c84c4085 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Mon, 25 Nov 2024 16:50:42 +0000 Subject: [PATCH] lang: ast: initial implementation of class parser --- lang/ast/class.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++ lang/ast/node.c | 4 ++ lang/ast/unit.c | 8 +++ 3 files changed, 160 insertions(+) create mode 100644 lang/ast/class.c diff --git a/lang/ast/class.c b/lang/ast/class.c new file mode 100644 index 0000000..ddd66f7 --- /dev/null +++ b/lang/ast/class.c @@ -0,0 +1,148 @@ +#include +#include +#include + +#include "ctx.h" +#include "node.h" + +struct class_parser_state { + struct parser_state s_base; + enum { + AREA_IDENT, + AREA_BODY, + } s_current_area; + int s_prev_token; +}; + +static enum ivy_status parse_dot(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct unit_import_parser_state); + + if (state->s_prev_token != IVY_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_SYM_DOT; + return IVY_OK; +} + +static enum ivy_status parse_ident(struct ivy_parser* ctx, struct ivy_token* tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct unit_import_parser_state); + + struct ivy_ast_class_node *node + = (struct ivy_ast_class_node *)(state->s_base.s_node); + + if (state->s_current_area != AREA_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_prev_token == IVY_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + b_queue_push_back(&node->n_ident, &tok->t_entry); + state->s_prev_token = IVY_TOK_IDENT; + return IVY_OK; +} + +static enum ivy_status parse_end(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct unit_import_parser_state); + + struct ivy_ast_class_node *node + = (struct ivy_ast_class_node *)(state->s_base.s_node); + + if (state->s_current_area == AREA_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); + return IVY_OK; +} + +static enum ivy_status parse_linefeed(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct unit_import_parser_state); + + if (state->s_current_area != AREA_IDENT) { + return IVY_OK; + } + + if (state->s_prev_token != IVY_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_TOK_LINEFEED; + state->s_current_area = AREA_BODY; + return IVY_OK; +} + +static enum ivy_status add_child( + struct ivy_ast_node *parent, struct ivy_ast_node *child) +{ + struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)parent; + + switch (child->n_type) { + case IVY_AST_MSGH: + b_queue_push_back(&c->n_msg_handlers, &child->n_entry); + break; + case IVY_AST_PROPERTY: + b_queue_push_back(&c->n_properties, &child->n_entry); + break; + default: + return IVY_ERR_NOT_SUPPORTED; + } + + return IVY_OK; +} + +static void print(struct ivy_ast_node *node) +{ + struct ivy_ast_class_node *unit_import = (struct ivy_ast_class_node *)node; + b_string *str = b_string_create(); + + b_queue_iterator it = {0}; + b_queue_foreach (&it, &unit_import->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) +{ + struct class_parser_state *state + = (struct unit_import_parser_state *)sp; + state->s_prev_token = IVY_KW_CLASS; + state->s_current_area = AREA_IDENT; +} + +struct ast_node_type class_node_ops = { + .n_add_child = add_child, + .n_print = print, + .n_init_state = init_state, + .n_state_size = sizeof(struct class_parser_state), + .n_node_size = sizeof(struct ivy_ast_class_node), + .n_symbol_parsers = { + [IVY_SYM_DOT] = parse_dot, + }, + .n_token_parsers = { + [IVY_TOK_IDENT] = parse_ident, + [IVY_TOK_LINEFEED] = parse_linefeed, + }, + .n_keyword_parsers = { + [IVY_KW_END] = parse_end, + }, +}; diff --git a/lang/ast/node.c b/lang/ast/node.c index 9a3a290..b136357 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -7,10 +7,14 @@ extern struct ast_node_type unit_node_ops; extern struct ast_node_type unit_package_node_ops; +extern struct ast_node_type unit_import_node_ops; +extern struct ast_node_type class_node_ops; static const struct ast_node_type *node_ops[] = { [IVY_AST_UNIT] = &unit_node_ops, [IVY_AST_UNIT_PACKAGE] = &unit_package_node_ops, + [IVY_AST_UNIT_IMPORT] = &unit_import_node_ops, + [IVY_AST_CLASS] = &class_node_ops, }; static const size_t nr_node_ops = sizeof node_ops / sizeof node_ops[0]; diff --git a/lang/ast/unit.c b/lang/ast/unit.c index 3dbf363..d61d1c1 100644 --- a/lang/ast/unit.c +++ b/lang/ast/unit.c @@ -17,6 +17,13 @@ static enum ivy_status parse_use_keyword( return IVY_OK; } +static enum ivy_status parse_class_keyword( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + parser_push_state(ctx, IVY_AST_CLASS); + return IVY_OK; +} + static enum ivy_status add_child( struct ivy_ast_node *parent, struct ivy_ast_node *child) { @@ -42,6 +49,7 @@ struct ast_node_type unit_node_ops = { .n_node_size = sizeof(struct ivy_ast_unit_node), .n_keyword_parsers = { [IVY_KW_PACKAGE] = parse_package_keyword, + [IVY_KW_CLASS] = parse_class_keyword, [IVY_KW_USE] = parse_use_keyword, }, };