From 5f5efd8d35037354855f75149b1b74e421a2fe7b Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 26 Nov 2024 13:08:39 +0000 Subject: [PATCH] lang: ast: initial implementation of msg handler and selector parsing --- lang/ast/class.c | 56 +++++++++++++- lang/ast/ctx.c | 8 +- lang/ast/msgh.c | 75 ++++++++++++++++++ lang/ast/node.h | 5 +- lang/ast/property.c | 0 lang/ast/selector.c | 147 ++++++++++++++++++++++++++++++++++++ lang/ast/unit-import.c | 20 +++-- lang/ast/unit-package.c | 20 +++-- lang/include/ivy/lang/ast.h | 5 +- 9 files changed, 312 insertions(+), 24 deletions(-) create mode 100644 lang/ast/msgh.c create mode 100644 lang/ast/property.c create mode 100644 lang/ast/selector.c diff --git a/lang/ast/class.c b/lang/ast/class.c index 8e18e77..03a866e 100644 --- a/lang/ast/class.c +++ b/lang/ast/class.c @@ -14,6 +14,55 @@ struct class_parser_state { int s_prev_token; }; +static enum ivy_status parse_dollar(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct class_parser_state); + + if (state->s_current_area != AREA_BODY) { + return IVY_ERR_BAD_SYNTAX; + } + + parser_push_state(ctx, IVY_AST_PROPERTY); + return IVY_OK; +} + +static enum ivy_status parse_plus(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct class_parser_state); + + if (state->s_current_area != AREA_BODY) { + return IVY_ERR_BAD_SYNTAX; + } + + parser_push_state(ctx, IVY_AST_MSGH); + struct parser_state *msgh_state = parser_get_state_generic(ctx); + struct ivy_ast_msgh_node *msgh + = (struct ivy_ast_msgh_node *)msgh_state->s_node; + msgh->n_recipient = IVY_AST_MSGH_CLASS; + + return IVY_OK; +} + +static enum ivy_status parse_hyphen(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct class_parser_state *state + = parser_get_state(ctx, struct class_parser_state); + + if (state->s_current_area != AREA_BODY) { + return IVY_ERR_BAD_SYNTAX; + } + + parser_push_state(ctx, IVY_AST_MSGH); + struct parser_state *msgh_state = parser_get_state_generic(ctx); + struct ivy_ast_msgh_node *msgh + = (struct ivy_ast_msgh_node *)msgh_state->s_node; + msgh->n_recipient = IVY_AST_MSGH_OBJECT; + + return IVY_OK; +} + static enum ivy_status parse_ident(struct ivy_parser *ctx, struct ivy_token *tok) { struct class_parser_state *state @@ -96,7 +145,7 @@ static void print(struct ivy_ast_node *node) c->n_ident->t_str); } -static void init_state(struct parser_state *sp) +static void init_state(struct ivy_parser *ctx, struct parser_state *sp) { struct class_parser_state *state = (struct class_parser_state *)sp; state->s_prev_token = IVY_KW_CLASS; @@ -109,6 +158,11 @@ struct ast_node_type class_node_ops = { .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_DOLLAR] = parse_dollar, + [IVY_SYM_HYPHEN] = parse_hyphen, + [IVY_SYM_PLUS] = parse_plus, + }, .n_token_parsers = { [IVY_TOK_IDENT] = parse_ident, [IVY_TOK_LINEFEED] = parse_linefeed, diff --git a/lang/ast/ctx.c b/lang/ast/ctx.c index d26efeb..8a2d56a 100644 --- a/lang/ast/ctx.c +++ b/lang/ast/ctx.c @@ -94,7 +94,7 @@ struct parser_state *parser_push_state( state->s_node = ast_node_create_with_size(type, node_type->n_node_size); if (node_type->n_init_state) { - node_type->n_init_state(state); + node_type->n_init_state(parser, state); } b_queue_push_back(&parser->p_state, &state->s_entry); @@ -134,7 +134,7 @@ struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser) { b_queue_entry *entry = b_queue_first(&parser->p_state); struct parser_state *state = b_unbox(struct parser_state, entry, s_entry); - + if (!state) { return NULL; } @@ -146,10 +146,10 @@ struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser) struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)state->s_node; entry = b_queue_pop_front(&unit->n_children); - + if (!entry) { return NULL; } return b_unbox(struct ivy_ast_node, entry, n_entry); -} \ No newline at end of file +} diff --git a/lang/ast/msgh.c b/lang/ast/msgh.c new file mode 100644 index 0000000..e306c98 --- /dev/null +++ b/lang/ast/msgh.c @@ -0,0 +1,75 @@ +#include "ctx.h" +#include "ivy/status.h" +#include "node.h" + +#include +#include + +struct msgh_parser_state { + struct parser_state s_base; + bool s_oneline; + + enum { + AREA_SELECTOR, + AREA_BODY, + } s_current_area; + + unsigned int s_i; + unsigned int s_prev; +}; + +static enum ivy_status parse_ident(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct msgh_parser_state *state + = parser_get_state(ctx, struct msgh_parser_state); + + struct ivy_ast_msgh_node *msgh + = (struct ivy_ast_msgh_node *)state->s_base.s_node; + + if (state->s_current_area == AREA_BODY) { + /* TODO expression parsing */ + return IVY_ERR_NOT_SUPPORTED; + } + + if (state->s_prev == IVY_SYM_HYPHEN) { + /* message name */ + return IVY_OK; + } + + return IVY_OK; +} + +static enum ivy_status add_child( + struct ivy_ast_node *parent, struct ivy_ast_node *child) +{ + struct ivy_ast_msgh_node *msgh = (struct ivy_ast_msgh_node *)parent; + + if (child->n_type == IVY_AST_SELECTOR && !msgh->n_sel) { + msgh->n_sel = (struct ivy_ast_selector_node *)child; + return IVY_OK; + } + + b_queue_push_back(&msgh->n_body, &child->n_entry); + return IVY_OK; +} + +static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +{ + struct msgh_parser_state *state = (struct msgh_parser_state *)sp; + state->s_oneline = false; + state->s_i = 0; + state->s_current_area = AREA_SELECTOR; + state->s_prev = IVY_SYM_HYPHEN; + + parser_push_state(ctx, IVY_AST_SELECTOR); +} + +struct ast_node_type msgh_node_ops = { + .n_add_child = add_child, + .n_init_state = init_state, + .n_state_size = sizeof(struct msgh_parser_state), + .n_node_size = sizeof(struct ivy_ast_msgh_node), + .n_token_parsers = { + [IVY_TOK_IDENT] = parse_ident, + }, +}; diff --git a/lang/ast/node.h b/lang/ast/node.h index f049293..b2e3c0e 100644 --- a/lang/ast/node.h +++ b/lang/ast/node.h @@ -16,8 +16,9 @@ struct ast_node_type { enum ivy_status (*n_add_child)( 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 *); + void (*n_init_state)(struct ivy_parser *, 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/property.c b/lang/ast/property.c new file mode 100644 index 0000000..e69de29 diff --git a/lang/ast/selector.c b/lang/ast/selector.c new file mode 100644 index 0000000..8a386e8 --- /dev/null +++ b/lang/ast/selector.c @@ -0,0 +1,147 @@ +#include "ctx.h" +#include "ivy/status.h" +#include "node.h" + +#include +#include + +struct selector_parser_state { + struct parser_state s_base; + unsigned int s_prev; +}; + +static enum ivy_status parse_ident(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct selector_parser_state *state + = parser_get_state(ctx, struct selector_parser_state); + + struct ivy_ast_selector_node *sel + = (struct ivy_ast_selector_node *)state->s_base.s_node; + + if (state->s_prev == 0) { + /* message name */ + sel->n_msg_name = tok; + state->s_prev = IVY_TOK_IDENT; + return IVY_OK; + } + + if (state->s_prev == IVY_TOK_LABEL) { + /* internal parameter name */ + b_queue_push_back(&sel->n_arg_names, &tok->t_entry); + state->s_prev = IVY_TOK_IDENT; + return IVY_OK; + } + + return IVY_ERR_BAD_SYNTAX; +} + +static enum ivy_status parse_label(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct selector_parser_state *state + = parser_get_state(ctx, struct selector_parser_state); + + struct ivy_ast_selector_node *sel + = (struct ivy_ast_selector_node *)state->s_base.s_node; + + if (state->s_prev != IVY_TOK_IDENT && state->s_prev != IVY_SYM_LEFT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + b_queue_push_back(&sel->n_arg_labels, &tok->t_entry); + return IVY_OK; +} + +static enum ivy_status parse_linefeed(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct selector_parser_state *state + = parser_get_state(ctx, struct selector_parser_state); + + struct ivy_ast_selector_node *sel + = (struct ivy_ast_selector_node *)state->s_base.s_node; + + if (!b_queue_empty(&sel->n_arg_labels) + && state->s_prev != IVY_SYM_RIGHT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_prev != IVY_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); + return IVY_OK; +} + +static enum ivy_status parse_left_paren( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct selector_parser_state *state + = parser_get_state(ctx, struct selector_parser_state); + + struct ivy_ast_selector_node *sel + = (struct ivy_ast_selector_node *)state->s_base.s_node; + + if (state->s_prev != IVY_TOK_IDENT || !b_queue_empty(&sel->n_arg_labels)) { + return IVY_ERR_BAD_SYNTAX; + } + + return IVY_OK; +} + +static enum ivy_status parse_right_paren( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct selector_parser_state *state + = parser_get_state(ctx, struct selector_parser_state); + + struct ivy_ast_selector_node *sel + = (struct ivy_ast_selector_node *)state->s_base.s_node; + + if (state->s_prev != IVY_TOK_IDENT || !b_queue_empty(&sel->n_arg_labels)) { + return IVY_ERR_BAD_SYNTAX; + } + + return IVY_OK; +} + +static enum ivy_status parse_pipe(struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct selector_parser_state *state + = parser_get_state(ctx, struct selector_parser_state); + + struct ivy_ast_selector_node *sel + = (struct ivy_ast_selector_node *)state->s_base.s_node; + + if (!b_queue_empty(&sel->n_arg_labels) + && state->s_prev != IVY_SYM_RIGHT_PAREN) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_prev != IVY_TOK_IDENT) { + return IVY_ERR_BAD_SYNTAX; + } + + parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); + return IVY_OK; +} + +static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +{ + struct selector_parser_state *state = (struct selector_parser_state *)sp; + state->s_prev = 0; +} + +struct ast_node_type msgh_node_ops = { + .n_init_state = init_state, + .n_state_size = sizeof(struct selector_parser_state), + .n_node_size = sizeof(struct ivy_ast_selector_node), + .n_token_parsers = { + [IVY_TOK_IDENT] = parse_ident, + [IVY_TOK_LABEL] = parse_label, + }, + .n_symbol_parsers = { + [IVY_SYM_LEFT_PAREN] = parse_left_paren, + [IVY_SYM_RIGHT_PAREN] = parse_right_paren, + [IVY_SYM_PIPE] = parse_pipe, + }, +}; diff --git a/lang/ast/unit-import.c b/lang/ast/unit-import.c index 3ffd0a1..8427ade 100644 --- a/lang/ast/unit-import.c +++ b/lang/ast/unit-import.c @@ -1,10 +1,10 @@ +#include "ctx.h" +#include "node.h" + #include #include #include -#include "ctx.h" -#include "node.h" - struct unit_import_parser_state { struct parser_state s_base; int s_prev_token; @@ -28,7 +28,8 @@ static enum ivy_status parse_ident(struct ivy_parser *ctx, struct ivy_token *tok struct unit_import_parser_state *state = parser_get_state(ctx, struct unit_import_parser_state); - struct ivy_ast_unit_import_node *node = (struct ivy_ast_unit_import_node *)(state->s_base.s_node); + struct ivy_ast_unit_import_node *node + = (struct ivy_ast_unit_import_node *)(state->s_base.s_node); if (state->s_prev_token == IVY_TOK_IDENT) { return IVY_ERR_BAD_SYNTAX; @@ -61,12 +62,14 @@ static enum ivy_status add_child( static void print(struct ivy_ast_node *node) { - struct ivy_ast_unit_import_node *unit_import = (struct ivy_ast_unit_import_node *)node; + struct ivy_ast_unit_import_node *unit_import + = (struct ivy_ast_unit_import_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); + 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, "."); @@ -75,11 +78,12 @@ static void print(struct ivy_ast_node *node) 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)); + 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) +static void init_state(struct ivy_parser *ctx, struct parser_state *sp) { struct unit_import_parser_state *state = (struct unit_import_parser_state *)sp; diff --git a/lang/ast/unit-package.c b/lang/ast/unit-package.c index 5c01b1f..2a00a7d 100644 --- a/lang/ast/unit-package.c +++ b/lang/ast/unit-package.c @@ -1,10 +1,10 @@ +#include "ctx.h" +#include "node.h" + #include #include #include -#include "ctx.h" -#include "node.h" - struct unit_package_parser_state { struct parser_state s_base; int s_prev_token; @@ -28,7 +28,8 @@ static enum ivy_status parse_ident(struct ivy_parser *ctx, struct ivy_token *tok struct unit_package_parser_state *state = parser_get_state(ctx, struct unit_package_parser_state); - struct ivy_ast_unit_package_node *node = (struct ivy_ast_unit_package_node *)(state->s_base.s_node); + struct ivy_ast_unit_package_node *node + = (struct ivy_ast_unit_package_node *)(state->s_base.s_node); if (state->s_prev_token == IVY_TOK_IDENT) { return IVY_ERR_BAD_SYNTAX; @@ -61,12 +62,14 @@ 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; + 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); + 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, "."); @@ -75,11 +78,12 @@ static void print(struct ivy_ast_node *node) 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)); + 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) +static void init_state(struct ivy_parser *ctx, struct parser_state *sp) { struct unit_package_parser_state *state = (struct unit_package_parser_state *)sp; diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index acf9163..562ecfc 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -15,6 +15,7 @@ enum ivy_ast_node_type { IVY_AST_MSG, IVY_AST_CLASS, IVY_AST_MSGH, + IVY_AST_SELECTOR, IVY_AST_PROPERTY, IVY_AST_LAMBDA, IVY_AST_UNIT_PACKAGE, @@ -92,7 +93,9 @@ struct ivy_ast_selector_node { /* NULL for keyword messages. */ struct ivy_token *n_msg_name; /* queue of struct ivy_token; empty for unary messages. */ - b_queue n_args; + b_queue n_arg_labels; + /* queue of struct ivy_token; empty for unary messages. */ + b_queue n_arg_names; }; struct ivy_ast_msg_node {