#include "ctx.h" #include "iterate.h" #include "node.h" #include #include #include struct class_parser_state { struct parser_state s_base; enum { AREA_IDENT, AREA_BODY, } s_current_area; int s_prev_token; }; static struct token_parse_result 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 PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } parser_push_state(ctx, IVY_AST_PROPERTY, 0); return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result 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 PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } parser_push_state(ctx, IVY_AST_MSGH, 0); 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; return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } static struct token_parse_result 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 PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } parser_push_state(ctx, IVY_AST_MSGH, 0); 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; return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } static struct token_parse_result parse_ident( struct ivy_parser *ctx, struct ivy_token *tok) { struct class_parser_state *state = parser_get_state(ctx, struct class_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 PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev_token == IVY_TOK_IDENT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } node->n_ident = tok; state->s_prev_token = IVY_TOK_IDENT; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_end( struct ivy_parser *ctx, struct ivy_token *tok) { struct class_parser_state *state = parser_get_state(ctx, struct class_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 PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_linefeed( 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_IDENT) { return PARSE_RESULT(IVY_OK, 0); } if (state->s_prev_token != IVY_TOK_IDENT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev_token = IVY_TOK_LINEFEED; state->s_current_area = AREA_BODY; return PARSE_RESULT(IVY_OK, 0); } static enum ivy_status add_child( struct parser_state *state, struct ivy_ast_node *child) { struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)state->s_node; 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 to_string(struct ivy_ast_node *node, b_string *str) { struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)node; b_string_append_cstrf(str, "%s (%s)", ivy_ast_node_type_to_string(node->n_type), c->n_ident->t_str); } static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) { struct class_parser_state *state = (struct class_parser_state *)sp; state->s_prev_token = IVY_KW_CLASS; state->s_current_area = AREA_IDENT; } static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)node; b_queue_iterator it = {0}; b_queue_foreach (&it, &c->n_properties) { struct ivy_ast_node *child = b_unbox(struct ivy_ast_node, it.entry, n_entry); ast_node_iterator_enqueue_node(iterator, node, child); } b_queue_foreach (&it, &c->n_msg_handlers) { 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 class_node_ops = { .n_add_child = add_child, .n_to_string = to_string, .n_init_state = init_state, .n_collect_children = collect_children, .n_state_size = sizeof(struct class_parser_state), .n_node_size = sizeof(struct ivy_ast_class_node), .n_symbol_parsers = { SYM_PARSER(DOLLAR, parse_dollar), SYM_PARSER(HYPHEN, parse_hyphen), SYM_PARSER(PLUS, parse_plus), }, .n_token_parsers = { TOK_PARSER(IDENT, parse_ident), TOK_PARSER(LINEFEED, parse_linefeed), }, .n_keyword_parsers = { KW_PARSER(END, parse_end), }, };