#include "ctx.h" #include "../debug.h" #include "node.h" #include #include #include #include #include #include #include #ifdef IVY_LANG_DEBUG static void print_state_stack(struct ivy_parser *parser) { b_queue_iterator it = {0}; b_queue_foreach (&it, &parser->p_state) { struct parser_state *state = b_unbox(struct parser_state, it.entry, s_entry); debug_printf( " %s\n", ivy_ast_node_type_to_string(state->s_node->n_type)); } } #endif enum ivy_status ivy_parser_create(struct ivy_parser **parser) { struct ivy_parser *out = malloc(sizeof *out); if (!out) { return IVY_ERR_NO_MEMORY; } memset(out, 0x0, sizeof *out); parser_push_state(out, IVY_AST_UNIT, 0); *parser = out; return IVY_OK; } void ivy_parser_destroy(struct ivy_parser *parser, struct ivy_ast_node **result) { struct ivy_ast_node *root = NULL; b_queue_entry *entry = b_queue_first(&parser->p_state); ; while (entry) { struct parser_state *state = b_unbox(struct parser_state, entry, s_entry); b_queue_entry *next = b_queue_next(entry); b_queue_delete(&parser->p_state, entry); if (root) { ivy_ast_node_destroy(root); } root = state->s_node; free(state); entry = next; } if (result) { *result = root; } else if (root) { ivy_ast_node_destroy(root); } free(parser); } enum ivy_status ivy_parser_set_diag_ctx( struct ivy_parser *parser, struct ivy_diag_ctx *ctx) { parser->p_diag_ctx = ctx; return IVY_OK; } enum ivy_status ivy_parser_get_status(struct ivy_parser *parser) { return parser->p_status; } enum ivy_status ivy_parser_push_token( struct ivy_parser *parser, struct ivy_token *tok) { if (!tok) { return ivy_parser_push_eof(parser); } while (true) { struct parser_state *state = parser_get_state_generic(parser); if (!state) { parser->p_status = IVY_ERR_INTERNAL_FAILURE; break; } token_parse_function func = get_token_parser(state->s_node, tok); if (func) { struct token_parse_result result = func(parser, tok); parser->p_status = result.r_status; #ifdef IVY_LANG_DEBUG debug_printf("states (after token)\n"); print_state_stack(parser); #endif if (result.r_flags & PARSE_REPEAT_TOKEN) { continue; } break; } if (tok->t_type == IVY_TOK_LINEFEED) { ivy_token_destroy(tok); parser->p_status = IVY_OK; break; } parser->p_status = IVY_ERR_BAD_SYNTAX; break; } return parser->p_status; } enum ivy_status ivy_parser_push_eof(struct ivy_parser *parser) { while (true) { struct parser_state *state = parser_get_state_generic(parser); if (!state) { parser->p_status = IVY_ERR_INTERNAL_FAILURE; break; } token_parse_function func = NULL; struct ivy_token tok = {0}; switch (state->s_node->n_type) { case IVY_AST_EXPR: case IVY_AST_COND_GROUP: case IVY_AST_FOR_LOOP: case IVY_AST_WHILE_LOOP: tok.t_type = IVY_TOK_SYMBOL; tok.t_symbol = IVY_SYM_DOT; func = get_token_parser(state->s_node, &tok); break; default: break; } if (!func) { break; } struct token_parse_result result = func(parser, &tok); parser->p_status = result.r_status; if (result.r_flags & PARSE_REPEAT_TOKEN) { continue; } #ifdef IVY_LANG_DEBUG debug_printf("states (after token)\n"); print_state_stack(parser); #endif break; } return parser->p_status; } struct parser_state *parser_get_state_generic(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; } struct parser_state *parser_get_parent_state_generic( struct ivy_parser *parser, enum ivy_ast_node_type type) { b_queue_entry *entry = b_queue_last(&parser->p_state); if (!entry) { return NULL; } entry = b_queue_prev(entry); if (!entry) { return NULL; } struct parser_state *state = b_unbox(struct parser_state, entry, s_entry); if (state->s_node->n_type != type) { return NULL; } return state; } struct parser_state *parser_push_state( struct ivy_parser *parser, enum ivy_ast_node_type type, uintptr_t arg) { const struct ast_node_type *node_type = get_ast_node_type(type); if (!node_type) { return NULL; } struct parser_state *state = malloc(node_type->n_state_size); if (!state) { return NULL; } memset(state, 0x0, node_type->n_state_size); 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); b_queue_push_back(&parser->p_state, &state->s_entry); if (node_type->n_init_state) { node_type->n_init_state(parser, state, arg); } #ifdef IVY_LANG_DEBUG debug_printf("states (after push)\n"); print_state_stack(parser); #endif return state; } void parser_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 (state && state->s_node && (flags & STATE_ADD_NODE_TO_PARENT)) { parser_add_child(parser, state->s_node); } free(state); #ifdef IVY_LANG_DEBUG debug_printf("states (after pop)\n"); print_state_stack(parser); #endif } void parser_replace_current_node( struct ivy_parser *parser, struct ivy_ast_node *new_node) { struct parser_state *state = parser_get_state_generic(parser); if (!state) { return; } ivy_ast_node_destroy(state->s_node); state->s_node = new_node; } enum ivy_status parser_add_child( struct ivy_parser *parser, struct ivy_ast_node *new_node) { struct parser_state *state = parser_get_state_generic(parser); if (!state) { return IVY_ERR_NOT_SUPPORTED; } const struct ast_node_type *node_type = get_ast_node_type(state->s_node->n_type); if (!node_type || !node_type->n_add_child) { return IVY_ERR_NOT_SUPPORTED; } return node_type->n_add_child(state, new_node); } bool ivy_parser_is_node_complete(struct ivy_parser *parser) { return (parser->p_state.q_first == parser->p_state.q_last); } struct ivy_ast_node *ivy_parser_root_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); return state ? state->s_node : NULL; } 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; } if (state->s_node->n_type != IVY_AST_UNIT) { return NULL; } 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); } struct ivy_diag *parser_push_diag( struct ivy_parser *parser, unsigned long diag_class, unsigned long msg, struct ivy_token *tok) { struct ivy_diag *diag = ivy_diag_ctx_create_diag(parser->p_diag_ctx, diag_class); if (msg != 0) { ivy_diag_push_msg(diag, msg); } if (tok) { ivy_diag_set_location(diag, tok->t_start.c_row, tok->t_start.c_col); const struct ivy_diag_highlight hl[] = { IVY_DIAG_HL( ERROR, tok->t_start.c_row, tok->t_start.c_col, tok->t_end.c_row, tok->t_end.c_col), }; const size_t nr_hl = sizeof hl / sizeof hl[0]; ivy_diag_push_snippet( diag, tok->t_start.c_row, tok->t_end.c_row, NULL, 0, hl, nr_hl); }; return diag; }