#include "../block.h" #include "../debug.h" #include "../node.h" #include "expr.h" #include #include #include #include #include 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; debug_printf("%s", ident->n_content->t_str); break; } case IVY_AST_INT: { struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)node; debug_printf("%llu", v->n_value->t_int); break; } case IVY_AST_DOUBLE: { struct ivy_ast_double_node *v = (struct ivy_ast_double_node *)node; debug_printf("%.2lf", v->n_value->t_double); break; } case IVY_AST_OP: { struct ivy_ast_op_node *v = (struct ivy_ast_op_node *)node; debug_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; if (v->n_sel->n_msg_name) { debug_printf("%s()", v->n_sel->n_msg_name->t_str); } else { debug_printf(""); } break; } case IVY_AST_STRING: { struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)node; debug_printf("\"%s\"", v->n_value->t_str); break; } default: debug_printf(""); break; } } enum ivy_status arith_push_operand( struct expr_parser_state *state, struct ivy_token *tok) { switch (tok->t_type) { 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; ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); break; } 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; ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); 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; ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); break; } case IVY_TOK_ATOM: { struct ivy_ast_atom_node *v = (struct ivy_ast_atom_node *)ast_node_create(IVY_AST_ATOM); v->n_content = tok; ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); 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; ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); break; } case IVY_TOK_SYMBOL: { if (tok->t_symbol != IVY_SYM_UNDERSCORE) { return IVY_ERR_BAD_SYNTAX; } struct ivy_ast_node *v = ast_node_create(IVY_AST_DISCARD); ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_entry); break; } case IVY_TOK_KEYWORD: { struct ivy_ast_node *v = NULL; switch (tok->t_keyword) { case IVY_KW_BREAK: v = ast_node_create(IVY_AST_LOOP_BREAK); break; case IVY_KW_CONTINUE: v = ast_node_create(IVY_AST_LOOP_REPEAT); break; case IVY_KW_TRUE: v = ast_node_create(IVY_AST_C_TRUE); break; case IVY_KW_FALSE: v = ast_node_create(IVY_AST_C_FALSE); break; case IVY_KW_NULL: v = ast_node_create(IVY_AST_C_NULL); break; default: return IVY_ERR_BAD_SYNTAX; } ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); b_queue_push_back(&state->s_output_queue, &v->n_entry); break; } default: return IVY_ERR_BAD_SYNTAX; } return IVY_OK; } static const struct ivy_operator *get_operator_from_token(struct ivy_token *tok) { switch (tok->t_type) { case IVY_TOK_SYMBOL: return ivy_operator_get_by_token(tok->t_symbol); case IVY_TOK_KEYWORD: return ivy_operator_get_by_token(tok->t_keyword); default: return ivy_operator_get_by_token(tok->t_type); } } static const struct ivy_operator *get_operator_from_node(struct ivy_ast_node *n) { switch (n->n_type) { case IVY_AST_OP: { struct ivy_ast_op_node *op = (struct ivy_ast_op_node *)n; return op->n_op; } case IVY_AST_MSG: return ivy_operator_get_by_id(IVY_OP_MSG); default: return NULL; } } static struct ivy_ast_selector_node *unary_selector_from_token(struct ivy_token *tok) { struct ivy_ast_selector_node *sel = (struct ivy_ast_selector_node *)ast_node_create(IVY_AST_SELECTOR); ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)sel, tok); sel->n_msg_name = tok; return sel; } static struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok) { const struct ivy_operator *op = get_operator_from_token(tok); if (!op) { return NULL; } if (op->op_id == IVY_OP_MSG) { struct ivy_ast_msg_node *new_msg_node = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); new_msg_node->n_sel = unary_selector_from_token(tok); ivy_ast_node_set_bounds_from_token( (struct ivy_ast_node *)new_msg_node, tok); return (struct ivy_ast_node *)new_msg_node; } struct ivy_ast_op_node *new_op_node = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP); new_op_node->n_op = op; ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)new_op_node, tok); return (struct ivy_ast_node *)new_op_node; } #ifdef IVY_LANG_DEBUG static void print_expr_queues(struct expr_parser_state *state) { b_queue_iterator it = {0}; debug_printf("operators:"); b_queue_foreach (&it, &state->s_operator_stack) { struct ivy_ast_node *n = b_unbox(struct ivy_ast_node, it.entry, n_entry); debug_printf(" "); print_operand(n); } debug_printf("\noperands:"); b_queue_foreach (&it, &state->s_output_queue) { struct ivy_ast_node *n = b_unbox(struct ivy_ast_node, it.entry, n_entry); debug_printf(" "); print_operand(n); } debug_printf("\n"); } #endif void arith_push_operator(struct expr_parser_state *state, struct ivy_ast_node *node) { const struct ivy_operator *op = get_operator_from_node(node); if (!op) { return; } while (true) { b_queue_entry *top = b_queue_last(&state->s_operator_stack); if (!top) { break; } struct ivy_ast_node *top_node = b_unbox(struct ivy_ast_node, top, n_entry); const struct ivy_operator *top_op = NULL; switch (top_node->n_type) { case IVY_AST_OP: { struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)top_node; top_op = op_node->n_op; break; } case IVY_AST_MSG: { struct ivy_ast_msg_node *msg_node = (struct ivy_ast_msg_node *)top_node; top_op = ivy_operator_get_by_id(IVY_OP_MSG); break; } default: return; } if (top_op->op_precedence < op->op_precedence || (top_op->op_precedence == op->op_precedence && op->op_associativity != IVY_ASSOCIATIVITY_LEFT)) { break; } b_queue_delete(&state->s_operator_stack, top); b_queue_push_back(&state->s_output_queue, top); } b_queue_push_back(&state->s_operator_stack, &node->n_entry); #ifdef IVY_LANG_DEBUG print_expr_queues(state); #endif } static bool op_node_is_complete(struct ivy_ast_op_node *node) { if (!node->n_op) { return false; } switch (node->n_op->op_arity) { case IVY_OP_UNARY: return node->n_right != NULL; case IVY_OP_BINARY: return (node->n_left != NULL && node->n_right != NULL); default: return false; } } enum ivy_status expr_finalise_arith( struct expr_parser_state *state, struct ivy_ast_node **expr_tree, enum ivy_operator_precedence minimum_precedence) { b_queue_iterator it = {0}; /* first, take all the operators still left on the operator stack and * add them to the output queue. * * since each set of parentheses has its own expression context, * we don't have to handle parentheses here */ 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; } const struct ivy_operator *op = NULL; switch (node->n_type) { case IVY_AST_OP: { struct ivy_ast_op_node *n = (struct ivy_ast_op_node *)node; op = n->n_op; break; } case IVY_AST_MSG: /* all unary message operators have the same pre-defined * precedence */ op = ivy_operator_get_by_id(IVY_OP_MSG); break; default: return IVY_ERR_INTERNAL_FAILURE; } /* if we aren't processing operators below a certain precedence * then leave them on the stack and stop here. */ if (op->op_precedence < minimum_precedence) { b_queue_push_back(&state->s_operator_stack, entry); break; } b_queue_push_back(&state->s_output_queue, entry); } #if 0 debug_printf("** after linearisation:\n"); print_expr_queues(state); #endif /* next, step through the output queue and build a tree of ast nodes * representing the expression. the queue is in RPM, where operators * always follow their operands, so a queue of operands is needed * for the conversion. */ 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 the node is an operand, just push it to a temporary queue * and come back to it later. */ 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; /* if the message has no recipient, it is a unary message, * and the recipient is located on the operand stack. * * if the message DOES have a recipient, it is a * self-contained keyword message, and can be pushed to * the operand queue as-is. */ if (!msg->n_recipient) { 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; /* if an operator node is already complete (i.e. it already has * all the operands it needs, it can be pushed to the operand * queue as-is */ if (op_node_is_complete(op_node)) { b_queue_push_back(&q, &item->n_entry); continue; } /* otherwise, pop the relevant operands from the operand * queue... */ 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_node->n_right) { op_node->n_right->n_parent = (struct ivy_ast_node *)op_node; ivy_ast_node_extend_bounds_recursive( (struct ivy_ast_node *)op_node, (struct ivy_ast_node *)tmp); } 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); if (op_node->n_left) { op_node->n_left->n_parent = (struct ivy_ast_node *)op_node; ivy_ast_node_extend_bounds_recursive( (struct ivy_ast_node *)op_node, (struct ivy_ast_node *)tmp); } } /* ...and push the newly-completed operator node to the operand * queue */ b_queue_push_back(&q, &op_node->n_base.n_entry); } #if 0 debug_printf("** after hierarchisation:\n"); print_expr_queues(state); #endif /* if we are not processing operators below a certain precedence, * i.e. when determining the recipient of a keyword-message), these * operators will still be on the parser state's operator stack, but * their operands have just been moved to the temporary operand stack * used above. move them back to the parser state's output queue here * so they can be used later. */ b_queue_foreach (&it, &state->s_operator_stack) { b_queue_entry *entry = b_queue_pop_front(&q); if (!entry) { return IVY_ERR_INTERNAL_FAILURE; } b_queue_push_back(&state->s_output_queue, entry); } #if 0 debug_printf("** after de-linearisation:\n"); print_expr_queues(state); ivy_ast_node_print(*expr_tree); debug_printf("------\n"); #endif /* the final node remaining on the temp operand stack is the root node * of the new expression tree */ tmp = b_queue_pop_back(&q); *expr_tree = b_unbox(struct ivy_ast_node, tmp, n_entry); return IVY_OK; } struct token_parse_result arith_parse_fstring( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type == EXPR_TYPE_STMT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev_component == EXPR_CMP_OPERAND) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_type = EXPR_TYPE_ARITH; state->s_prev_component = EXPR_CMP_OPERAND; state->s_prev_token = tok->t_type; parser_push_state(ctx, IVY_AST_FSTRING, 0); return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_operand( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type == EXPR_TYPE_STMT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* this is an unlabeled complex message arg */ if (state->s_prev_token != IVY_SYM_COMMA && state->s_prev_token != IVY_SYM_LEFT_PAREN) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } struct ivy_token *empty_label = malloc(sizeof *empty_label); if (!empty_label) { return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); } memset(empty_label, 0x0, sizeof *empty_label); empty_label->t_type = IVY_TOK_LABEL; b_queue_push_back(&state->s_labels, &empty_label->t_entry); struct expr_parser_state *arg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_copy_terminators(state, arg_expr); expr_add_terminator(arg_expr, IVY_SYM_COMMA); arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG; arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } if (state->s_prev_component == EXPR_CMP_OPERAND) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_type = EXPR_TYPE_ARITH; arith_push_operand(state, tok); // print_expr_queues(state); state->s_prev_component = EXPR_CMP_OPERAND; state->s_prev_token = tok->t_type; return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_operator( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } unsigned short tok_id = 0; switch (tok->t_type) { case IVY_TOK_SYMBOL: tok_id = tok->t_symbol; state->s_prev_token = tok->t_symbol; break; case IVY_TOK_KEYWORD: tok_id = tok->t_keyword; state->s_prev_token = tok->t_keyword; break; default: tok_id = tok->t_type; state->s_prev_token = tok->t_type; break; } if (expr_terminates_at_token(state, tok_id)) { /* treat this as a statement terminator. */ struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags |= PARSE_REPEAT_TOKEN; return result; } struct ivy_ast_node *op = create_operator_node_from_token(tok); if (!op) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } arith_push_operator(state, op); state->s_prev_component = EXPR_CMP_OPERATOR; #ifdef IVY_LANG_DEBUG print_expr_queues(state); #endif return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_in( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (expr_terminates_at_token(state, IVY_KW_IN)) { /* treat this as a statement terminator. */ struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags |= PARSE_REPEAT_TOKEN; return result; } return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } struct token_parse_result arith_parse_do( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); bool terminator = false; if (expr_terminates_at_token(state, IVY_KW_DO)) { terminator = true; } if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG || state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { terminator = true; } if (terminator) { state->s_prev_token = IVY_KW_DO; struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } /* next component will be a block. */ struct block_parser_state *block = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); /* set the sub-expression depth to be non-zero so the expression parser * doesn't consume the expression separator. */ state->s_prev_token = IVY_KW_DO; return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_ident( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); struct token_parse_result result; if (state->s_sub_type == EXPR_SUBTYPE_MSG) { if (state->s_prev_component == EXPR_CMP_MSG) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } result = arith_parse_operator(ctx, tok); state->s_prev_component = EXPR_CMP_MSG; return result; } if (state->s_prev_component == EXPR_CMP_OPERAND || state->s_prev_component == EXPR_CMP_MSG) { result = arith_parse_operator(ctx, tok); state->s_prev_component = EXPR_CMP_MSG; } else { result = arith_parse_operand(ctx, tok); } return result; } struct token_parse_result arith_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_type == EXPR_TYPE_NONE) { state->s_type = EXPR_TYPE_ARITH; } if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev_token == IVY_TOK_IDENT) { /* this might be the opening parenthesis for a complex message. */ b_queue_entry *msg_entry = b_queue_last(&state->s_operator_stack); struct ivy_ast_node *msg = b_unbox(struct ivy_ast_node, msg_entry, n_entry); if (!msg || msg->n_type != IVY_AST_MSG) { /* this is not a complex message, it's probably a * call-operator */ goto not_complex_msg; } b_queue_pop_back(&state->s_operator_stack); struct expr_parser_state *msg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_add_terminator(msg_expr, IVY_SYM_COMMA); msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG; msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; msg_expr->s_prev_token = state->s_prev_token = IVY_SYM_LEFT_PAREN; return PARSE_RESULT(IVY_OK, 0); } not_complex_msg: if (state->s_prev_component == EXPR_CMP_OPERAND) { /* this is the opening parenthesis for a call-operator */ struct ivy_ast_msg_node *msg = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); msg->n_sel = unary_selector_from_token( ivy_token_create_ident("call")); struct expr_parser_state *msg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG; msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; msg_expr->s_prev_token = state->s_prev_token = IVY_SYM_LEFT_PAREN; return PARSE_RESULT(IVY_OK, 0); } /* this is a generic parenthesis-enclosed sub-expression. * create a new sub-expr parser to handle it */ if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* this is an unlabeled complex message arg */ if (state->s_prev_token != IVY_SYM_COMMA && state->s_prev_token != IVY_SYM_LEFT_PAREN) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } struct ivy_token *empty_label = malloc(sizeof *empty_label); if (!empty_label) { return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); } memset(empty_label, 0x0, sizeof *empty_label); empty_label->t_type = IVY_TOK_LABEL; b_queue_push_back(&state->s_labels, &empty_label->t_entry); struct expr_parser_state *arg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_copy_terminators(state, arg_expr); expr_add_terminator(arg_expr, IVY_SYM_COMMA); arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG; arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } struct expr_parser_state *sub_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_copy_terminators(state, sub_expr); sub_expr->s_paren_depth = state->s_paren_depth + 1; sub_expr->s_subexpr_depth = state->s_subexpr_depth + 1; sub_expr->s_sub_type = EXPR_SUBTYPE_PAREN; return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_right_paren( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (expr_terminates_at_token(state, IVY_SYM_RIGHT_PAREN)) { struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_paren_depth == 0 && state->s_sub_type == EXPR_SUBTYPE_NONE) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev_token = IVY_SYM_RIGHT_PAREN; return expr_finalise_and_return(ctx, state); } struct token_parse_result arith_parse_left_brace( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type == EXPR_TYPE_NONE) { state->s_type = EXPR_TYPE_ARITH; } if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev_component != EXPR_CMP_OPERATOR && state->s_prev_component != EXPR_CMP_NONE) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } parser_push_state(ctx, IVY_AST_PKG, 0); return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_right_brace( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); state->s_prev_token = IVY_SYM_RIGHT_BRACE; struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } struct token_parse_result arith_parse_left_bracket( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type == EXPR_TYPE_STMT) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_prev_component == EXPR_CMP_OPERAND || state->s_prev_component == EXPR_CMP_MSG) { /* subscript operator */ state->s_prev_token = IVY_SYM_LEFT_BRACKET; struct ivy_ast_op_node *subscript = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP); subscript->n_op = ivy_operator_get_by_id(IVY_OP_SUBSCRIPT); arith_push_operator(state, (struct ivy_ast_node *)subscript); struct expr_parser_state *index = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_add_terminator(index, IVY_SYM_RIGHT_BRACKET); index->s_subexpr_depth = state->s_subexpr_depth + 1; return PARSE_RESULT(IVY_OK, 0); } /* lambda */ state->s_prev_token = IVY_SYM_LEFT_BRACKET; state->s_type = EXPR_TYPE_ARITH; parser_push_state(ctx, IVY_AST_LAMBDA, 0); return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_right_bracket( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (expr_terminates_at_token(state, IVY_SYM_RIGHT_BRACKET)) { state->s_prev_token = IVY_SYM_RIGHT_BRACKET; struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } if (state->s_prev_token == IVY_SYM_LEFT_BRACKET) { /* we've just parsed a subscript operator. nothing further to do here. */ return PARSE_RESULT(IVY_OK, 0); } state->s_prev_token = IVY_SYM_RIGHT_BRACKET; struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } static struct ivy_ast_selector_node *keyword_selector_from_label_list(b_queue *labels) { struct ivy_ast_selector_node *sel = (struct ivy_ast_selector_node *)ast_node_create(IVY_AST_SELECTOR); b_queue_iterator it = {0}; b_queue_iterator_begin(labels, &it); while (b_queue_iterator_is_valid(&it)) { struct ivy_token *label = b_unbox(struct ivy_token, it.entry, t_entry); b_queue_iterator_erase(&it); b_queue_push_back(&sel->n_arg_labels, &label->t_entry); } return sel; } static struct ivy_ast_cascade_node *expr_finalise_cascade( struct expr_parser_state *state) { struct ivy_ast_cascade_node *cascade = (struct ivy_ast_cascade_node *)ast_node_create(IVY_AST_CASCADE); cascade->n_recipient = state->s_recipient; b_queue_iterator it = {0}; b_queue_iterator_begin(&state->s_cascade_msg, &it); while (b_queue_iterator_is_valid(&it)) { struct ivy_ast_node *msg = b_unbox(struct ivy_ast_node, it.entry, n_entry); b_queue_iterator_erase(&it); b_queue_push_back(&cascade->n_msg, &msg->n_entry); } return cascade; } static struct ivy_ast_msg_node *expr_finalise_keyword_msg( struct expr_parser_state *state) { struct ivy_ast_msg_node *msg = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); msg->n_recipient = state->s_recipient; msg->n_sel = keyword_selector_from_label_list(&state->s_labels); b_queue_iterator it = {0}; b_queue_iterator_begin(&state->s_args, &it); while (b_queue_iterator_is_valid(&it)) { struct ivy_ast_node *arg = b_unbox(struct ivy_ast_node, it.entry, n_entry); b_queue_iterator_erase(&it); b_queue_push_back(&msg->n_arg, &arg->n_entry); } return msg; } static struct ivy_ast_msg_node *expr_finalise_complex_msg( struct expr_parser_state *state) { struct ivy_ast_msg_node *msg = state->s_msg; if (!msg) { return NULL; } state->s_msg = NULL; b_queue_iterator it = {0}; b_queue_iterator_begin(&state->s_labels, &it); while (b_queue_iterator_is_valid(&it)) { struct ivy_token *label = b_unbox(struct ivy_token, it.entry, t_entry); b_queue_iterator_erase(&it); b_queue_push_back(&msg->n_sel->n_arg_labels, &label->t_entry); } b_queue_iterator_begin(&state->s_args, &it); while (b_queue_iterator_is_valid(&it)) { struct ivy_ast_node *arg = b_unbox(struct ivy_ast_node, it.entry, n_entry); b_queue_iterator_erase(&it); b_queue_push_back(&msg->n_arg, &arg->n_entry); } return msg; } static enum ivy_status begin_cascade_operation(struct ivy_parser *ctx) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); /* this is the beginning of a cascade operation */ struct ivy_ast_msg_node *first_msg = NULL; if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { first_msg = expr_finalise_keyword_msg(state); parser_pop_state(ctx, 0); } else { /* we need to find who the first message in the cascade is being sent to. */ enum ivy_operator_precedence min_precedence = IVY_PRECEDENCE_CASCADE; struct ivy_ast_node *prev = b_unbox( struct ivy_ast_node, b_queue_last(&state->s_operator_stack), n_entry); if (prev && prev->n_type == IVY_AST_MSG) { /* unary complex messages (which will be found on the * operator stack) have a very high precedence (much * higher than most arithmetic operators), so the * recipient will be much narrower. this also means that * any subsequent messages in the cascade inherit this * high precedence, regardless of their type. */ min_precedence = IVY_PRECEDENCE_UNARY_MSG; } struct ivy_ast_node *expr = NULL; enum ivy_status status = expr_finalise_arith(state, &expr, min_precedence); if (status != IVY_OK) { return status; } if (expr->n_type != IVY_AST_MSG) { /* the recipient and first message of the cascade * operation is ambiguous due to operator precedence. * this is usually resolved by adding parentheses * (either around the recipient or around the cascade) * to make the recipient and first message clear. */ return IVY_ERR_BAD_SYNTAX; } first_msg = (struct ivy_ast_msg_node *)expr; } struct expr_parser_state *cascade_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); if (!first_msg) { return IVY_ERR_BAD_SYNTAX; } cascade_expr->s_recipient = first_msg->n_recipient; first_msg->n_recipient = NULL; cascade_expr->s_sub_type = EXPR_SUBTYPE_CASCADE; cascade_expr->s_type = EXPR_TYPE_ARITH; cascade_expr->s_subexpr_depth = state->s_subexpr_depth + 1; b_queue_push_back(&cascade_expr->s_cascade_msg, &first_msg->n_base.n_entry); struct expr_parser_state *msg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); msg_expr->s_sub_type = EXPR_SUBTYPE_MSG; msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; return IVY_OK; } struct token_parse_result arith_parse_semicolon( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } bool end_subexpr = false; switch (state->s_sub_type) { case EXPR_SUBTYPE_KEYWORD_ARG: case EXPR_SUBTYPE_MSG: end_subexpr = true; break; case EXPR_SUBTYPE_KEYWORD_MSG: case EXPR_SUBTYPE_CASCADE: case EXPR_SUBTYPE_COMPLEX_ARG: case EXPR_SUBTYPE_NONE: break; default: return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); break; } if (end_subexpr) { /* finish parsing this expression and let the parent context handle the semicolon. */ struct ivy_ast_node *expr = NULL; enum ivy_status status = expr_finalise_arith( state, &expr, IVY_PRECEDENCE_ASSIGN); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } parser_replace_current_node(ctx, expr); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } struct expr_parser_state *parent_state = parser_get_parent_state( ctx, IVY_AST_EXPR, struct expr_parser_state); if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { /* this is another message in a cascade series. */ struct expr_parser_state *msg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); msg_expr->s_recipient = NULL; msg_expr->s_sub_type = EXPR_SUBTYPE_MSG; msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; return PARSE_RESULT(IVY_OK, 0); } if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG && !state->s_recipient) { struct ivy_ast_msg_node *msg = expr_finalise_keyword_msg(state); if (!msg) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } parser_replace_current_node(ctx, (struct ivy_ast_node *)msg); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } enum ivy_status status = begin_cascade_operation(ctx); return PARSE_RESULT(status, 0); } static struct ivy_ast_node *create_return_node(struct ivy_ast_node *val) { struct ivy_ast_return_node *ret = (struct ivy_ast_return_node *)ast_node_create(IVY_AST_RETURN); if (!ret) { return NULL; } ret->n_val = val; return (struct ivy_ast_node *)ret; } struct token_parse_result expr_finalise( struct ivy_parser *ctx, struct expr_parser_state *state, enum ivy_operator_precedence min_precedence, struct ivy_ast_node **result) { int flags = 0; if (state->s_subexpr_depth > 0) { flags = PARSE_REPEAT_TOKEN; } if (state->s_paren_depth > 0 && state->s_prev_token == IVY_SYM_RIGHT_PAREN) { /* this is the ending right paren in a parenthesised expression, so we need to consume it. */ flags = 0; } if (state->s_sub_type == EXPR_SUBTYPE_MSG) { /* this is the end of a unary message (probably in a cascade operation). */ struct ivy_ast_node *expr = NULL; enum ivy_status status = expr_finalise_arith( state, &expr, IVY_PRECEDENCE_CASCADE); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } if (state->s_return && expr) { expr = create_return_node(expr); } *result = expr; return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { /* this is the end of a cascade operation */ struct ivy_ast_cascade_node *cascade = expr_finalise_cascade(state); if (state->s_return && cascade) { cascade = (struct ivy_ast_cascade_node *)create_return_node( (struct ivy_ast_node *)cascade); } *result = (struct ivy_ast_node *)cascade; return PARSE_RESULT(IVY_OK, flags); } if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* this is the end of a complex message */ struct ivy_ast_msg_node *msg = expr_finalise_complex_msg(state); if (state->s_return && msg) { msg = (struct ivy_ast_msg_node *)create_return_node( (struct ivy_ast_node *)msg); } *result = (struct ivy_ast_node *)msg; return PARSE_RESULT(IVY_OK, 0); } if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { /* this is the end of a keyword-message */ struct ivy_ast_msg_node *msg = expr_finalise_keyword_msg(state); if (state->s_return && msg) { msg = (struct ivy_ast_msg_node *)create_return_node( (struct ivy_ast_node *)msg); } *result = (struct ivy_ast_node *)msg; return PARSE_RESULT(IVY_OK, flags); } /* this is the end of a regular expression or sub-expression */ struct ivy_ast_node *expr = NULL; enum ivy_status status = expr_finalise_arith(state, &expr, min_precedence); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } if (expr && state->s_return) { expr = create_return_node(expr); } *result = expr; return PARSE_RESULT(IVY_OK, flags); } struct token_parse_result expr_finalise_and_return( struct ivy_parser *ctx, struct expr_parser_state *state) { struct ivy_ast_node *expr_node = NULL; struct token_parse_result result = expr_finalise(ctx, state, IVY_PRECEDENCE_ASSIGN, &expr_node); if (result.r_status != IVY_OK) { return result; } parser_replace_current_node(ctx, expr_node); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return result; } struct token_parse_result arith_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_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_paren_depth > 0) { /* end-of-expression with mismatched parentheses */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (expr_terminates_at_token(state, IVY_SYM_DOT)) { /* treat this as a statement terminator. */ struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags |= PARSE_REPEAT_TOKEN; return result; } state->s_prev_token = IVY_SYM_DOT; return expr_finalise_and_return(ctx, state); } struct token_parse_result arith_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_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_paren_depth > 0) { /* end-of-expression with mismatched parentheses */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev_token = IVY_SYM_BANG; struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } struct token_parse_result arith_parse_caret( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); /* caret must be used at the beginning of a top-level expression */ if (state->s_subexpr_depth > 0 || state->s_paren_depth > 0) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (!b_queue_empty(&state->s_operator_stack) || !b_queue_empty(&state->s_output_queue)) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } state->s_prev_token = IVY_SYM_CARET; state->s_return = true; return PARSE_RESULT(IVY_OK, 0); } struct token_parse_result arith_parse_comma( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* this is a comma separator between two complex message args */ state->s_prev_token = IVY_SYM_COMMA; return PARSE_RESULT(IVY_OK, 0); } if (expr_terminates_at_token(state, IVY_SYM_COMMA)) { struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags = PARSE_REPEAT_TOKEN; return result; } if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_paren_depth > 0 && (state->s_prev_component == EXPR_CMP_OPERAND || state->s_prev_component == EXPR_CMP_MSG)) { struct ivy_ast_node *item = NULL; struct token_parse_result result = expr_finalise(ctx, state, IVY_PRECEDENCE_ASSIGN, &item); if (result.r_status != IVY_OK) { return result; } if (!item) { /* empty tuple member expression. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_sub_type == EXPR_SUBTYPE_PAREN && b_queue_empty(&state->s_output_queue) && b_queue_empty(&state->s_operator_stack)) { parser_pop_state(ctx, 0); } else { /* the tuple parser will handle the parentheses for us. */ state->s_paren_depth--; } parser_push_state(ctx, IVY_AST_TUPLE, (uintptr_t)item); return PARSE_RESULT(IVY_OK, 0); } state->s_prev_token = IVY_SYM_COMMA; return expr_finalise_and_return(ctx, state); } extern struct token_parse_result arith_parse_equal_right_angle( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); state->s_prev_token = IVY_SYM_EQUAL_RIGHT_ANGLE; struct token_parse_result result = expr_finalise_and_return(ctx, state); result.r_flags |= PARSE_REPEAT_TOKEN; return result; } struct token_parse_result arith_parse_label( struct ivy_parser *ctx, struct ivy_token *tok) { struct expr_parser_state *state = parser_get_state(ctx, struct expr_parser_state); if (state->s_type != EXPR_TYPE_ARITH) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { /* we are currently parsing a keyword or complex message * argument, and have just encountered the label denoting the * next argument. terminate here and propagate this label to the * parent keyword-message parser context. */ struct ivy_ast_node *expr = NULL; struct token_parse_result result = expr_finalise(ctx, state, IVY_PRECEDENCE_ASSIGN, &expr); if (result.r_status != IVY_OK) { return result; } result.r_flags |= PARSE_REPEAT_TOKEN; parser_replace_current_node(ctx, expr); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return result; } if (state->s_sub_type != EXPR_SUBTYPE_KEYWORD_MSG && state->s_sub_type != EXPR_SUBTYPE_COMPLEX_MSG) { /* this is the beginning of a new keyword-message */ struct expr_parser_state *msg_expr; bool new_parser = true; if (b_queue_empty(&state->s_operator_stack) && b_queue_empty(&state->s_output_queue)) { new_parser = false; } if (new_parser) { msg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_copy_terminators(state, msg_expr); } else { msg_expr = state; } /* the only operator with a lower precedence than * keyword-messages is assignment. everything in the preceding * expression, up to but not including any un-parenthesised * assignments, is the recipient of the message. */ struct ivy_ast_node *expr = NULL; if (state->s_sub_type != EXPR_SUBTYPE_MSG) { enum ivy_status status = expr_finalise_arith( state, &expr, IVY_PRECEDENCE_KEYWORD_MSG); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } } msg_expr->s_recipient = expr; msg_expr->s_sub_type = EXPR_SUBTYPE_KEYWORD_MSG; msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_subexpr_depth = state->s_subexpr_depth; if (new_parser) { msg_expr->s_subexpr_depth++; } state = msg_expr; } if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* this label denotes the start of a complex message arg */ if (state->s_prev_token != IVY_SYM_COMMA && state->s_prev_token != IVY_SYM_LEFT_PAREN) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } b_queue_push_back(&state->s_labels, &tok->t_entry); struct expr_parser_state *arg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_copy_terminators(state, arg_expr); expr_add_terminator(arg_expr, IVY_SYM_COMMA); arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG; arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; } else if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { /* we may have just finished parsing a keyword-message argument, * and this label marks the start of a new one. store the label * and create a new argument parsing context. */ b_queue_push_back(&state->s_labels, &tok->t_entry); struct expr_parser_state *arg_expr = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); expr_copy_terminators(state, arg_expr); expr_add_terminator(arg_expr, IVY_TOK_LABEL); arg_expr->s_sub_type = EXPR_SUBTYPE_KEYWORD_ARG; arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; } return PARSE_RESULT(IVY_OK, 0); } enum ivy_status arith_add_child( struct parser_state *parent, struct ivy_ast_node *child) { struct expr_parser_state *state = (struct expr_parser_state *)parent; if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { /* treat the child node as a cascaded message */ b_queue_push_back(&state->s_cascade_msg, &child->n_entry); } else if ( state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG || state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* treat the child node as a keyword-message argument */ b_queue_push_back(&state->s_args, &child->n_entry); } else if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { /* treat the child node as a sub-expression enclosed in * parentheses (i.e. an operand). */ b_queue_push_back(&state->s_output_queue, &child->n_entry); state->s_prev_component = EXPR_CMP_OPERAND; } else if (child->n_type == IVY_AST_MSG) { arith_push_operator(state, child); state->s_prev_component = EXPR_CMP_MSG; } else { /* treat the child node as a sub-expression enclosed in * parentheses (i.e. an operand). */ b_queue_push_back(&state->s_output_queue, &child->n_entry); state->s_prev_component = EXPR_CMP_OPERAND; } return IVY_OK; }