#include "block.h" #include "ctx.h" #include "expr/expr.h" #include "iterate.h" #include "node.h" #include #include enum package_type { PACKAGE_NONE = 0, /* package constructed using a list of key-value pairs. */ PACKAGE_STATIC, /* package constructed using an (X for X in Y if Z) pattern. */ PACKAGE_DYNAMIC, }; struct package_parser_state { struct parser_state s_base; enum package_type s_type; struct ivy_ast_node *s_prev_node; unsigned int s_prev; /* only used for PACKAGE_STATIC */ b_queue s_items; struct ivy_ast_node *s_next_index; unsigned int s_next_implicit_index; /* only used for PACKAGE_DYNAMIC */ struct ivy_ast_node *s_transform; struct ivy_ast_node *s_item; struct ivy_ast_node *s_source; struct ivy_ast_node *s_cond; }; static enum ivy_status add_package_item(struct package_parser_state *state, struct ivy_ast_node *index, struct ivy_ast_node *value) { struct ivy_ast_pkg_static_item_node *item = (struct ivy_ast_pkg_static_item_node *)ast_node_create(IVY_AST_PKG_ITEM); if (!item) { return IVY_ERR_NO_MEMORY; } item->n_value = value; if (index) { item->n_index = index; } else { item->n_implicit_index = state->s_next_implicit_index++; } b_queue_push_back(&state->s_items, &item->n_base.n_entry); state->s_next_index = NULL; state->s_prev_node = NULL; return IVY_OK; } static struct ivy_ast_node *finalise_package(struct package_parser_state *state) { struct ivy_ast_pkg_static_node *s = NULL; struct ivy_ast_pkg_dynamic_node *d = NULL; switch (state->s_type) { case PACKAGE_STATIC: s = (struct ivy_ast_pkg_static_node *)ast_node_create(IVY_AST_PKG_STATIC); if (!s) { return NULL; } s->n_items = state->s_items; state->s_items = B_QUEUE_INIT; return (struct ivy_ast_node *)s; case PACKAGE_DYNAMIC: d = (struct ivy_ast_pkg_dynamic_node *)ast_node_create(IVY_AST_PKG_DYNAMIC); if (!d) { return NULL; } d->n_transform = state->s_transform; d->n_item = state->s_item; d->n_source = state->s_source; d->n_cond = state->s_cond; state->s_transform = NULL; state->s_item = NULL; state->s_source = NULL; state->s_cond = NULL; return (struct ivy_ast_node *)d; default: return NULL; } } static struct token_parse_result parse_equal_right_angle( struct ivy_parser *ctx, struct ivy_token *tok) { struct package_parser_state *state = parser_get_state(ctx, struct package_parser_state); if (state->s_type == PACKAGE_NONE) { state->s_type = PACKAGE_STATIC; } if (state->s_type != PACKAGE_STATIC) { /* this token cannot be used in this context. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA) { /* token unexpected at this time. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (!state->s_prev_node) { /* empty index expression. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev = IVY_SYM_EQUAL_RIGHT_ANGLE; state->s_next_index = state->s_prev_node; state->s_prev_node = NULL; struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR, 0); expr_add_terminator(expr, IVY_SYM_COMMA); expr->s_subexpr_depth = 1; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_comma( struct ivy_parser *ctx, struct ivy_token *tok) { struct package_parser_state *state = parser_get_state(ctx, struct package_parser_state); if (state->s_type == PACKAGE_NONE) { state->s_type = PACKAGE_STATIC; } if (state->s_type != PACKAGE_STATIC) { /* this token cannot be used in this context. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA && state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) { /* token unexpected at this time. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (!state->s_prev_node) { /* empty value expression. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } enum ivy_status status = add_package_item(state, state->s_next_index, state->s_prev_node); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } state->s_prev = IVY_SYM_COMMA; struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR, 0); expr_add_terminator(expr, IVY_SYM_EQUAL_RIGHT_ANGLE); expr->s_subexpr_depth = 1; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_right_brace( struct ivy_parser *ctx, struct ivy_token *tok) { struct package_parser_state *state = parser_get_state(ctx, struct package_parser_state); if (state->s_type == PACKAGE_NONE) { state->s_type = PACKAGE_STATIC; } enum ivy_status status = IVY_OK; switch (state->s_type) { case PACKAGE_STATIC: if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA && state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) { /* token unexpected at this time. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev_node) { status = add_package_item(state, state->s_next_index, state->s_prev_node); } break; case PACKAGE_DYNAMIC: if (!state->s_prev_node) { /* empty expression */ status = IVY_ERR_BAD_SYNTAX; break; } switch (state->s_prev) { case IVY_KW_IN: state->s_source = state->s_prev_node; break; case IVY_KW_IF: state->s_cond = state->s_prev_node; break; default: /* token unexpected at this time. */ status = IVY_ERR_BAD_SYNTAX; break; } break; default: /* not sure how we got here. */ status = IVY_ERR_INTERNAL_FAILURE; break; } if (status != IVY_OK) { return PARSE_RESULT(status, 0); } struct ivy_ast_node *pkg = finalise_package(state); if (!pkg) { return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); } parser_replace_current_node(ctx, pkg); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_for( struct ivy_parser *ctx, struct ivy_token *tok) { struct package_parser_state *state = parser_get_state(ctx, struct package_parser_state); if (state->s_type == PACKAGE_NONE) { state->s_type = PACKAGE_DYNAMIC; } if (state->s_type != PACKAGE_DYNAMIC) { /* this token cannot be used in this context. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev != IVY_SYM_LEFT_BRACE) { /* token unexpected at this time. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (!state->s_prev_node) { /* empty expression. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev = IVY_KW_FOR; state->s_transform = state->s_prev_node; state->s_prev_node = NULL; struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR, 0); expr_add_terminator(expr, IVY_KW_IN); expr->s_subexpr_depth = 1; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_in( struct ivy_parser *ctx, struct ivy_token *tok) { struct package_parser_state *state = parser_get_state(ctx, struct package_parser_state); if (state->s_type != PACKAGE_DYNAMIC) { /* this token cannot be used in this context. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev != IVY_KW_FOR) { /* token unexpected at this time. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (!state->s_prev_node) { /* empty expression. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev = IVY_KW_IN; state->s_item = state->s_prev_node; state->s_prev_node = NULL; struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR, 0); expr_add_terminator(expr, IVY_KW_IF); expr->s_subexpr_depth = 1; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_if( struct ivy_parser *ctx, struct ivy_token *tok) { struct package_parser_state *state = parser_get_state(ctx, struct package_parser_state); if (state->s_type != PACKAGE_DYNAMIC) { /* this token cannot be used in this context. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev != IVY_KW_IN) { /* token unexpected at this time. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (!state->s_prev_node) { /* empty expression. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev = IVY_KW_IF; state->s_source = state->s_prev_node; state->s_prev_node = NULL; struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR, 0); expr_add_terminator(expr, IVY_SYM_RIGHT_BRACE); expr->s_subexpr_depth = 1; return PARSE_RESULT(IVY_OK, 0); } static enum ivy_status add_child( struct parser_state *parent, struct ivy_ast_node *child) { struct package_parser_state *state = (struct package_parser_state *)parent; if (state->s_prev_node) { return IVY_ERR_BAD_SYNTAX; } state->s_prev_node = child; return IVY_OK; } static void pkg_static_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { struct ivy_ast_pkg_static_node *pkg = (struct ivy_ast_pkg_static_node *)node; b_queue_iterator it = {0}; b_queue_foreach (&it, &pkg->n_items) { struct ivy_ast_node *item = b_unbox(struct ivy_ast_node, it.entry, n_entry); ast_node_iterator_enqueue_node(iterator, node, item); } } static void pkg_static_item_to_string(struct ivy_ast_node *node, b_string *str) { struct ivy_ast_pkg_static_item_node *item = (struct ivy_ast_pkg_static_item_node *)node; b_string_append_cstr(str, ivy_ast_node_type_to_string(node->n_type)); if (!item->n_index) { b_string_append_cstrf(str, " (%u)", item->n_implicit_index); } } static void pkg_static_item_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { struct ivy_ast_pkg_static_item_node *item = (struct ivy_ast_pkg_static_item_node *)node; if (item->n_index) { ast_node_iterator_enqueue_node(iterator, node, item->n_index); } if (item->n_value) { ast_node_iterator_enqueue_node(iterator, node, item->n_value); } } static void pkg_dynamic_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { struct ivy_ast_pkg_dynamic_node *pkg = (struct ivy_ast_pkg_dynamic_node *)node; if (pkg->n_transform) { ast_node_iterator_enqueue_node(iterator, node, pkg->n_transform); } if (pkg->n_item) { ast_node_iterator_enqueue_node(iterator, node, pkg->n_item); } if (pkg->n_source) { ast_node_iterator_enqueue_node(iterator, node, pkg->n_source); } if (pkg->n_cond) { ast_node_iterator_enqueue_node(iterator, node, pkg->n_cond); } } static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) { struct package_parser_state *state = (struct package_parser_state *)sp; state->s_type = PACKAGE_NONE; state->s_prev = IVY_SYM_LEFT_BRACE; state->s_next_implicit_index = 0; struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR, 0); expr_add_terminator(expr, IVY_KW_FOR); expr->s_subexpr_depth = 1; } struct ast_node_type pkg_node_ops = { .n_init_state = init_state, .n_add_child = add_child, .n_state_size = sizeof(struct package_parser_state), /* placeholder node, will be replaced with either ivy_ast_pkg_static_node * or ivy_ast_pkg_dynamic_node when finished. */ .n_node_size = sizeof(struct ivy_ast_node), .n_keyword_parsers = { KW_PARSER(FOR, parse_for), KW_PARSER(IN, parse_in), KW_PARSER(IF, parse_if), }, .n_symbol_parsers = { SYM_PARSER(COMMA, parse_comma), SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_equal_right_angle), SYM_PARSER(RIGHT_BRACE, parse_right_brace), }, }; struct ast_node_type pkg_static_node_ops = { .n_collect_children = pkg_static_collect_children, .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_pkg_static_node), }; struct ast_node_type pkg_static_item_node_ops = { .n_to_string = pkg_static_item_to_string, .n_collect_children = pkg_static_item_collect_children, .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_pkg_static_item_node), }; struct ast_node_type pkg_dynamic_node_ops = { .n_collect_children = pkg_dynamic_collect_children, .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_pkg_dynamic_node), };