From ec24e2c327be62e6a8ec948f60e1b44ed9a6fa4e Mon Sep 17 00:00:00 2001 From: Max Wash Date: Thu, 28 Nov 2024 22:06:25 +0000 Subject: [PATCH] lang: ast: convert RPN expression queue to ast and replace generic EXPR node with it --- lang/ast/ctx.c | 13 ++- lang/ast/ctx.h | 2 + lang/ast/expr.c | 220 ++++++++++++++++++++++++++++-------- lang/ast/node.c | 13 ++- lang/ast/node.h | 6 +- lang/ast/selector.c | 4 +- lang/ast/unit.c | 10 ++ lang/include/ivy/lang/ast.h | 2 +- 8 files changed, 212 insertions(+), 58 deletions(-) diff --git a/lang/ast/ctx.c b/lang/ast/ctx.c index 5ee28bc..c66c4d8 100644 --- a/lang/ast/ctx.c +++ b/lang/ast/ctx.c @@ -101,7 +101,7 @@ struct parser_state *parser_push_state( state->s_parent = current_state->s_node; } - state->s_node = ast_node_create_with_size(type, node_type->n_node_size); + state->s_node = ast_node_create(type); b_queue_push_back(&parser->p_state, &state->s_entry); if (node_type->n_init_state) { @@ -128,6 +128,17 @@ void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags) free(state); } +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; +} + bool ivy_parser_is_node_complete(struct ivy_parser *parser) { return (parser->p_state.q_first == parser->p_state.q_last); diff --git a/lang/ast/ctx.h b/lang/ast/ctx.h index 6380490..3634e98 100644 --- a/lang/ast/ctx.h +++ b/lang/ast/ctx.h @@ -30,4 +30,6 @@ extern struct parser_state *parser_push_state( extern void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags); extern struct parser_state *parser_get_state_generic(struct ivy_parser *parser); +extern void parser_replace_current_node(struct ivy_parser *parser, struct ivy_ast_node *new_node); + #endif diff --git a/lang/ast/expr.c b/lang/ast/expr.c index c3e6eb9..540710c 100644 --- a/lang/ast/expr.c +++ b/lang/ast/expr.c @@ -29,7 +29,7 @@ struct expr_parser_state { unsigned int s_type; unsigned int s_prev_tok; enum expr_part s_prev_part; - b_queue s_operand_queue; + b_queue s_output_queue; b_queue s_operator_stack; }; @@ -61,34 +61,46 @@ static void set_previous(struct expr_parser_state *state, struct ivy_token *tok) } } -static void print_token(struct ivy_token *tok) +static void print_operand(struct ivy_ast_node *node) { - switch (tok->t_type) { - case IVY_TOK_IDENT: - printf("%s", tok->t_str); + switch (node->n_type) { + case IVY_AST_IDENT: { + struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node; + printf("%s", ident->n_content->t_str); break; - case IVY_TOK_INT: - printf("%llu", tok->t_int); + } + case IVY_AST_INT: { + struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)node; + printf("%llu", v->n_value->t_int); break; - case IVY_TOK_DOUBLE: - printf("%.2lf", tok->t_double); + } + case IVY_AST_DOUBLE: { + struct ivy_ast_double_node *v = (struct ivy_ast_double_node *)node; + printf("%.2lf", v->n_value->t_double); break; - case IVY_TOK_SYMBOL: - printf("%s", ivy_symbol_to_string(tok->t_symbol)); + } + case IVY_AST_OP: { + struct ivy_ast_op_node *v = (struct ivy_ast_op_node *)node; + printf("%s", ivy_operator_id_to_string(v->n_op->op_id)); break; - case IVY_TOK_KEYWORD: - printf("%s", ivy_keyword_to_string(tok->t_keyword)); + } + case IVY_AST_MSG: { + struct ivy_ast_msg_node *v = (struct ivy_ast_msg_node *)node; + printf("%s()", v->n_sel->n_msg_name->t_str); break; - case IVY_TOK_STRING: - printf("\"%s\"", tok->t_str); + } + case IVY_AST_STRING: { + struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)node; + printf("\"%s\"", v->n_value->t_str); break; + } default: - printf(""); + printf(""); break; } } -static enum ivy_status finalise_expr(struct expr_parser_state *state) +static enum ivy_status finalise_expr(struct expr_parser_state *state, struct ivy_ast_node **root) { b_queue_iterator it = {0}; while (true) { @@ -97,33 +109,68 @@ static enum ivy_status finalise_expr(struct expr_parser_state *state) break; } - struct ivy_tokoen *tok = b_unbox(struct ivy_token, entry, t_entry); - if (!tok) { + struct ivy_ast_node *node = b_unbox(struct ivy_ast_node, entry, n_entry); + if (!node) { /* this should never happen */ return IVY_ERR_INTERNAL_FAILURE; } - if (ivy_token_is_symbol(tok, IVY_SYM_LEFT_PAREN)) { + if (node->n_type != IVY_AST_OP) { + b_queue_push_back(&state->s_output_queue, entry); + continue; + } + + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)node; + + if (op_node->n_op->op_id == IVY_OP_LEFT_PAREN) { /* mismatched parentheses */ return IVY_ERR_BAD_SYNTAX; } - b_queue_push_back(&state->s_operand_queue, entry); + b_queue_push_back(&state->s_output_queue, entry); } + b_queue q = B_QUEUE_INIT; + b_queue_entry *tmp = NULL; + b_queue_iterator_begin(&state->s_output_queue, &it); int i = 0; - b_queue_foreach (&it, &state->s_operand_queue) { - struct ivy_token *operand - = b_unbox(struct ivy_token, it.entry, t_entry); - if (i > 0) { - printf(" "); + while (b_queue_iterator_is_valid(&it)) { + struct ivy_ast_node *item + = b_unbox(struct ivy_ast_node, it.entry, n_entry); + b_queue_iterator_erase(&it); + + if (item->n_type != IVY_AST_OP && item->n_type != IVY_AST_MSG) { + /* operand */ + b_queue_push_back(&q, &item->n_entry); + continue; } - print_token(operand); - i++; + const struct ivy_operator *op = NULL; + + if (item->n_type == IVY_AST_MSG) { + struct ivy_ast_msg_node *msg = (struct ivy_ast_msg_node *)item; + tmp = b_queue_pop_back(&q); + msg->n_recipient = b_unbox(struct ivy_ast_node, tmp, n_entry); + b_queue_push_back(&q, &msg->n_base.n_entry); + continue; + } + + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)item; + op = op_node->n_op; + tmp = b_queue_pop_back(&q); + op_node->n_right = b_unbox(struct ivy_ast_node, tmp, n_entry); + + if (op->op_arity == IVY_OP_BINARY) { + tmp = b_queue_pop_back(&q); + op_node->n_left = b_unbox(struct ivy_ast_node, tmp, n_entry); + } + + b_queue_push_back(&q, &op_node->n_base.n_entry); } + tmp = b_queue_pop_back(&q); + *root = b_unbox(struct ivy_ast_node, tmp, n_entry); printf("\n"); return IVY_OK; } @@ -142,6 +189,19 @@ static const struct ivy_operator *get_operator(struct ivy_token *tok) } } +static struct ivy_ast_selector_node *create_unary_selector_from_ident(struct ivy_token *tok) +{ + struct ivy_ast_selector_node *sel = (struct ivy_ast_selector_node *)ast_node_create(IVY_AST_SELECTOR); + if (!sel) { + return NULL; + } + + sel->n_msg_name = tok; + sel->n_recipient = IVY_SELECTOR_RECIPIENT_NONE; + + return sel; +} + static enum ivy_status push_operator( struct expr_parser_state *state, struct ivy_token *tok, const struct ivy_operator *op) { @@ -170,13 +230,21 @@ static enum ivy_status push_operator( break; } - struct ivy_token *top - = b_unbox(struct ivy_token, top_entry, t_entry); - if (ivy_token_is_symbol(top, IVY_SYM_LEFT_PAREN)) { + struct ivy_ast_node *top + = b_unbox(struct ivy_ast_node, top_entry, n_entry); + + const struct ivy_operator *top_op = NULL; + if (top->n_type == IVY_AST_OP) { + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)top; + top_op = op_node->n_op; + } else if (top->n_type == IVY_AST_MSG) { + top_op = ivy_operator_get(IVY_TOK_IDENT); + } + + if (top_op->op_id == IVY_OP_LEFT_PAREN) { break; } - const struct ivy_operator *top_op = get_operator(top); if (top_op->op_precedence < op->op_precedence) { break; } @@ -187,10 +255,58 @@ static enum ivy_status push_operator( } b_queue_delete(&state->s_operator_stack, top_entry); - b_queue_push_back(&state->s_operand_queue, top_entry); + b_queue_push_back(&state->s_output_queue, top_entry); } - b_queue_push_back(&state->s_operator_stack, &tok->t_entry); + if (tok->t_type == IVY_TOK_IDENT) { + struct ivy_ast_msg_node *msg_node = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); + msg_node->n_sel = create_unary_selector_from_ident(tok); + b_queue_push_back(&state->s_operator_stack, &msg_node->n_base.n_entry); + } else { + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP); + op_node->n_op = op; + b_queue_push_back(&state->s_operator_stack, &op_node->n_base.n_entry); + } + + return IVY_OK; +} + + +static enum ivy_status push_operand( + struct expr_parser_state *state, struct ivy_token *tok) +{ + struct ivy_ast_node *node = NULL; + + switch (tok->t_type) { + case IVY_TOK_INT: { + struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)ast_node_create(IVY_AST_INT); + v->n_value = tok; + node = (struct ivy_ast_node *)v; + break; + } + case IVY_TOK_DOUBLE: { + struct ivy_ast_double_node *v = (struct ivy_ast_double_node *)ast_node_create(IVY_AST_DOUBLE); + v->n_value = tok; + node = (struct ivy_ast_node *)v; + break; + } + case IVY_TOK_STRING: { + struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)ast_node_create(IVY_AST_STRING); + v->n_value = tok; + node = (struct ivy_ast_node *)v; + break; + } + case IVY_TOK_IDENT: { + struct ivy_ast_ident_node *v = (struct ivy_ast_ident_node *)ast_node_create(IVY_AST_IDENT); + v->n_content = tok; + node = (struct ivy_ast_node *)v; + break; + } + default: + return IVY_ERR_INTERNAL_FAILURE; + } + + b_queue_push_back(&state->s_output_queue, &node->n_entry); return IVY_OK; } @@ -207,7 +323,7 @@ static struct token_parse_result parse_ident( if (state->s_prev_part == EXPR_OPERAND) { push_operator(state, tok, NULL); } else { - b_queue_push_back(&state->s_operand_queue, &tok->t_entry); + push_operand(state, tok); } set_previous(state, tok); @@ -226,7 +342,7 @@ static struct token_parse_result parse_atom( state->s_end = EXPR_END_DOT; } - b_queue_push_back(&state->s_operand_queue, &tok->t_entry); + push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; @@ -243,7 +359,7 @@ static struct token_parse_result parse_string( state->s_end = EXPR_END_DOT; } - b_queue_push_back(&state->s_operand_queue, &tok->t_entry); + push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; @@ -282,7 +398,7 @@ static struct token_parse_result parse_int( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - b_queue_push_back(&state->s_operand_queue, &tok->t_entry); + push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; @@ -303,7 +419,7 @@ static struct token_parse_result parse_double( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - b_queue_push_back(&state->s_operand_queue, &tok->t_entry); + push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; @@ -345,7 +461,9 @@ static struct token_parse_result parse_left_paren( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - b_queue_push_back(&state->s_operator_stack, &tok->t_entry); + struct ivy_ast_op_node *paren_node = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP); + paren_node->n_op = ivy_operator_get(tok->t_symbol); + b_queue_push_back(&state->s_operator_stack, &paren_node->n_base.n_entry); set_previous(state, tok); return PARSE_RESULT(IVY_OK, 0); @@ -479,11 +597,17 @@ static struct token_parse_result parse_bang( if (state->s_end != EXPR_END_DOT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } + + struct ivy_ast_node *expr_tree = NULL; + enum ivy_status status = finalise_expr(state, &expr_tree); + + if (status != IVY_OK) { + return PARSE_RESULT(status, 0); + } - enum ivy_status status = finalise_expr(state); - + parser_replace_current_node(ctx, expr_tree); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(status, PARSE_REPEAT_TOKEN); + return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } static struct token_parse_result parse_dot( @@ -496,10 +620,16 @@ static struct token_parse_result parse_dot( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - enum ivy_status status = finalise_expr(state); + struct ivy_ast_node *expr_tree = NULL; + enum ivy_status status = finalise_expr(state, &expr_tree); + + if (status != IVY_OK) { + return PARSE_RESULT(status, 0); + } + parser_replace_current_node(ctx, expr_tree); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(status, 0); + return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_caret( diff --git a/lang/ast/node.c b/lang/ast/node.c index e68dcbe..f10d54a 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -146,18 +146,21 @@ token_parse_function get_token_parser( return better_parser ? better_parser : generic_parser; } -struct ivy_ast_node *ast_node_create_with_size( - enum ivy_ast_node_type type, size_t size) +struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type) { - struct ivy_ast_node *node = malloc(size); + const struct ast_node_type *type_info = get_ast_node_type(type); + if (!type_info) { + return NULL; + } + + struct ivy_ast_node *node = malloc(type_info->n_node_size); if (!node) { return NULL; } - memset(node, 0x0, size); + memset(node, 0x0, type_info->n_node_size); node->n_type = type; - return node; } diff --git a/lang/ast/node.h b/lang/ast/node.h index 565b6f6..1f89f0f 100644 --- a/lang/ast/node.h +++ b/lang/ast/node.h @@ -4,9 +4,6 @@ #include #include -#define ast_node_create(type_id, type_struct) \ - ((type_struct *)ast_node_create_with_size(type_id, sizeof(type_struct))) - struct parser_state; #define PARSE_RESULT(status, flags) \ @@ -72,8 +69,7 @@ extern const struct ast_node_type *get_ast_node_type(enum ivy_ast_node_type type extern token_parse_function get_token_parser( struct ivy_ast_node *context, struct ivy_token *tok); extern enum token_expr_type get_token_expr_type(struct ivy_token *tok); -extern struct ivy_ast_node *ast_node_create_with_size( - enum ivy_ast_node_type type, size_t size); +extern struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type); extern enum ivy_status ast_node_add_child( struct ivy_ast_node *parent, struct ivy_ast_node *child); diff --git a/lang/ast/selector.c b/lang/ast/selector.c index 875ffb4..54e60c8 100644 --- a/lang/ast/selector.c +++ b/lang/ast/selector.c @@ -215,7 +215,9 @@ static void print(struct ivy_ast_node *node) fputc('-', stdout); break; default: - fputc('?', stdout); + /* this will occur if the selector is being used to send a + message at runtime, rather than as part of a message + handler definition. */ break; } diff --git a/lang/ast/unit.c b/lang/ast/unit.c index b51a93f..b6891a9 100644 --- a/lang/ast/unit.c +++ b/lang/ast/unit.c @@ -25,6 +25,13 @@ static struct token_parse_result parse_class_keyword( return PARSE_RESULT(IVY_OK, 0); } +static struct token_parse_result parse_expr_begin( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + parser_push_state(ctx, IVY_AST_EXPR); + return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); +} + static enum ivy_status add_child( struct ivy_ast_node *parent, struct ivy_ast_node *child) { @@ -55,4 +62,7 @@ struct ast_node_type unit_node_ops = { KW_PARSER(CLASS, parse_class_keyword), KW_PARSER(USE, parse_use_keyword), }, + .n_expr_parser = { + .expr_begin = parse_expr_begin, + }, }; diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index 69639a2..bedeb64 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -63,7 +63,7 @@ struct ivy_ast_unit_node { struct ivy_ast_op_node { struct ivy_ast_node n_base; - enum ivy_operator_id n_op; + const struct ivy_operator *n_op; struct ivy_ast_node *n_left; // NULL for unary operators. struct ivy_ast_node *n_right; };