#include "ctx.h" #include "node.h" #include #include #include #include enum expr_end { EXPR_END_NONE = 0, /* arithmetic expressions, terminated with a dot (.) */ EXPR_END_DOT, /* keyword expressions (if-else, while/for loops, match, etc), terminated with the end keyword. */ EXPR_END_KEYWORD, }; enum expr_part { EXPR_NONE = 0, EXPR_OPERATOR, EXPR_OPERAND, }; struct expr_parser_state { struct parser_state s_base; enum expr_end s_end; /* for a keyword-based expression (loops, conditionals, etc) this is the id of the keyword that started the expression. if this is a return expression (i.e. prefixed with a caret), this will be IVY_SYM_CARET. */ unsigned int s_type; unsigned int s_prev_tok; enum expr_part s_prev_part; b_queue s_output_queue; b_queue s_operator_stack; }; static enum ivy_status add_child( struct ivy_ast_node *parent, struct ivy_ast_node *child) { struct ivy_ast_expr_node *expr = (struct ivy_ast_expr_node *)parent; if (!expr->n_child) { expr->n_child = child; return IVY_OK; } return IVY_ERR_NOT_SUPPORTED; } static void set_previous(struct expr_parser_state *state, struct ivy_token *tok) { switch (tok->t_type) { case IVY_TOK_SYMBOL: state->s_prev_tok = tok->t_symbol; break; case IVY_TOK_KEYWORD: state->s_prev_tok = tok->t_keyword; break; default: state->s_prev_tok = tok->t_type; break; } } static void print_operand(struct ivy_ast_node *node) { 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_AST_INT: { struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)node; printf("%llu", v->n_value->t_int); break; } 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_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_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_AST_STRING: { struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)node; printf("\"%s\"", v->n_value->t_str); break; } default: printf(""); break; } } static enum ivy_status finalise_expr( struct expr_parser_state *state, struct ivy_ast_node **root) { b_queue_iterator it = {0}; while (true) { b_queue_entry *entry = b_queue_pop_back(&state->s_operator_stack); if (!entry) { break; } 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 (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_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; 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; } 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; } static const struct ivy_operator *get_operator(struct ivy_token *tok) { switch (tok->t_type) { case IVY_TOK_IDENT: return ivy_operator_get_by_token(tok->t_type); case IVY_TOK_KEYWORD: return ivy_operator_get_by_token(tok->t_keyword); case IVY_TOK_SYMBOL: return ivy_operator_get_by_token(tok->t_symbol); default: return NULL; } } 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) { if (!op) { op = get_operator(tok); } if (!op) { return IVY_ERR_BAD_SYNTAX; } if ((op->op_location == IVY_OP_INFIX || op->op_location == IVY_OP_POSTFIX) && state->s_prev_part != EXPR_OPERAND) { return IVY_ERR_BAD_SYNTAX; } if (op->op_location == IVY_OP_PREFIX && state->s_prev_part == EXPR_OPERAND) { return IVY_ERR_BAD_SYNTAX; } while (true) { b_queue_entry *top_entry = b_queue_last(&state->s_operator_stack); if (!top_entry) { break; } 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_by_token(IVY_TOK_IDENT); } if (top_op->op_id == IVY_OP_LEFT_PAREN) { break; } if (top_op->op_precedence < op->op_precedence) { break; } if (top_op->op_precedence == op->op_precedence && op->op_associativity != IVY_ASSOCIATIVITY_LEFT) { break; } b_queue_delete(&state->s_operator_stack, top_entry); b_queue_push_back(&state->s_output_queue, top_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; } static struct token_parse_result parse_ident( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_DOT; } if (state->s_prev_part == EXPR_OPERAND) { push_operator(state, tok, NULL); } else { push_operand(state, tok); } set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_atom( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_DOT; } push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_string( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_DOT; } push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_str_start( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_str_end( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_label( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_int( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_DOT; } if (state->s_prev_part == EXPR_OPERAND) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_double( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_DOT; } if (state->s_prev_part == EXPR_OPERAND) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } push_operand(state, tok); set_previous(state, tok); state->s_prev_part = EXPR_OPERAND; return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_symbol( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end != EXPR_END_DOT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } enum ivy_status status = push_operator(state, tok, NULL); set_previous(state, tok); state->s_prev_part = EXPR_OPERATOR; return PARSE_RESULT(status, 0); } static struct token_parse_result parse_left_paren( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_DOT; } if (state->s_prev_tok == IVY_TOK_IDENT) { /* this is the openning parenthesis of a complex message. */ } if (state->s_prev_part == EXPR_OPERAND) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } 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_by_token(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); } static struct token_parse_result parse_right_paren( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_if( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end == EXPR_END_NONE) { state->s_end = EXPR_END_KEYWORD; } return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_else( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_end( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_while( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_for( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_match( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_try( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_catch( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_throw( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_understands( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_in( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_do( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_is( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_and( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_or( struct ivy_parser *ctx, struct ivy_token *tok) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0); } static struct token_parse_result parse_not( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end != EXPR_END_DOT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } enum ivy_status status = push_operator(state, tok, NULL); set_previous(state, tok); return PARSE_RESULT(status, 0); } static struct token_parse_result parse_bang( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); 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); } parser_replace_current_node(ctx, expr_tree); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } static struct token_parse_result parse_dot( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); 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); } parser_replace_current_node(ctx, expr_tree); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, 0); } static struct token_parse_result parse_caret( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_end != EXPR_END_NONE || state->s_type != IVY_KW_NONE) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_type = IVY_SYM_CARET; return PARSE_RESULT(IVY_OK, 0); } struct ast_node_type expr_node_ops = { .n_add_child = add_child, .n_state_size = sizeof(struct expr_parser_state), .n_node_size = sizeof(struct ivy_ast_expr_node), .n_token_parsers = { TOK_PARSER(IDENT, parse_ident), TOK_PARSER(ATOM, parse_atom), TOK_PARSER(STRING, parse_string), TOK_PARSER(STR_START, parse_str_start), TOK_PARSER(STR_END, parse_str_end), TOK_PARSER(LABEL, parse_label), TOK_PARSER(INT, parse_int), TOK_PARSER(DOUBLE, parse_double), TOK_PARSER(SYMBOL, parse_symbol), }, .n_symbol_parsers = { SYM_PARSER(BANG, parse_bang), SYM_PARSER(DOT, parse_dot), SYM_PARSER(CARET, parse_caret), SYM_PARSER(LEFT_PAREN, parse_left_paren), SYM_PARSER(RIGHT_PAREN, parse_right_paren), }, .n_keyword_parsers = { KW_PARSER(IF, parse_if), KW_PARSER(ELSE, parse_else), KW_PARSER(END, parse_end), KW_PARSER(WHILE, parse_while), KW_PARSER(FOR, parse_for), KW_PARSER(MATCH, parse_match), KW_PARSER(TRY, parse_try), KW_PARSER(CATCH, parse_catch), KW_PARSER(THROW, parse_throw), KW_PARSER(UNDERSTANDS, parse_understands), KW_PARSER(IN, parse_in), KW_PARSER(DO, parse_do), KW_PARSER(IS, parse_is), KW_PARSER(AND, parse_and), KW_PARSER(OR, parse_or), KW_PARSER(NOT, parse_not), }, };