#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; enum ivy_keyword s_type; unsigned int s_prev_tok; enum expr_part s_prev_part; b_queue s_operand_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; state->s_prev_part = EXPR_OPERATOR; break; case IVY_TOK_KEYWORD: state->s_prev_tok = tok->t_keyword; state->s_prev_part = EXPR_OPERATOR; break; default: state->s_prev_tok = tok->t_type; state->s_prev_part = EXPR_OPERAND; break; } } static void print_token(struct ivy_token *tok) { switch (tok->t_type) { case IVY_TOK_IDENT: printf("%s", tok->t_str); break; case IVY_TOK_INT: printf("%llu", tok->t_int); break; case IVY_TOK_DOUBLE: printf("%.2lf", tok->t_double); break; case IVY_TOK_SYMBOL: printf("%s", ivy_symbol_to_string(tok->t_symbol)); break; case IVY_TOK_KEYWORD: printf("%s", ivy_keyword_to_string(tok->t_keyword)); break; case IVY_TOK_STRING: printf("\"%s\"", tok->t_str); break; default: printf(""); break; } } static enum ivy_status finalise_expr(struct expr_parser_state *state) { b_queue_iterator it = {0}; 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(" "); } print_token(operand); i++; } b_queue_foreach (&it, &state->s_operator_stack) { struct ivy_token *operator = b_unbox(struct ivy_token, it.entry, t_entry); if (i > 0) { printf(" "); } print_token(operator); i++; } printf("\n"); 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; } b_queue_push_back(&state->s_operand_queue, &tok->t_entry); set_previous(state, tok); 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; } b_queue_push_back(&state->s_operand_queue, &tok->t_entry); set_previous(state, tok); 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; } b_queue_push_back(&state->s_operand_queue, &tok->t_entry); set_previous(state, tok); 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; } b_queue_push_back(&state->s_operand_queue, &tok->t_entry); set_previous(state, tok); 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; } b_queue_push_back(&state->s_operand_queue, &tok->t_entry); set_previous(state, tok); return PARSE_RESULT(IVY_OK, 0); } static struct ivy_operator *get_operator(struct ivy_token *tok) { switch (tok->t_type) { case IVY_TOK_KEYWORD: return ivy_operator_get(tok->t_keyword); case IVY_TOK_SYMBOL: return ivy_operator_get(tok->t_symbol); default: return NULL; } } 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); } struct ivy_operator *op = ivy_operator_get(tok->t_symbol); if (!op) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } while (true) { b_queue_entry *top_entry = b_queue_last(&state->s_operator_stack); if (!top_entry) { break; } struct ivy_token *top = b_unbox(struct ivy_token, top_entry, t_entry); if (ivy_token_is_symbol(top, IVY_SYM_LEFT_PAREN)) { break; } struct ivy_operator *top_op = get_operator(top); 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_operand_queue, top_entry); } b_queue_push_back(&state->s_operator_stack, &tok->t_entry); set_previous(state, tok); return PARSE_RESULT(IVY_OK, 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; } b_queue_push_back(&state->s_operator_stack, &tok->t_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) { return PARSE_RESULT(IVY_ERR_IO_FAILURE, 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); } enum ivy_status status = finalise_expr(state); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(status, 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); } enum ivy_status status = finalise_expr(state); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(status, 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 = { [IVY_TOK_IDENT] = parse_ident, [IVY_TOK_ATOM] = parse_atom, [IVY_TOK_STRING] = parse_string, [IVY_TOK_STR_START] = parse_str_start, [IVY_TOK_STR_END] = parse_str_end, [IVY_TOK_LABEL] = parse_label, [IVY_TOK_INT] = parse_int, [IVY_TOK_DOUBLE] = parse_double, [IVY_TOK_SYMBOL] = parse_symbol, }, .n_symbol_parsers = { [IVY_SYM_BANG] = parse_bang, [IVY_SYM_DOT] = parse_dot, [IVY_SYM_LEFT_PAREN] = parse_left_paren, [IVY_SYM_RIGHT_PAREN] = parse_right_paren, }, .n_keyword_parsers = { [IVY_KW_IF] = parse_if, [IVY_KW_ELSE] = parse_else, [IVY_KW_END] = parse_end, [IVY_KW_WHILE] = parse_while, [IVY_KW_FOR] = parse_for, [IVY_KW_MATCH] = parse_match, [IVY_KW_TRY] = parse_try, [IVY_KW_CATCH] = parse_catch, [IVY_KW_THROW] = parse_throw, [IVY_KW_UNDERSTANDS] = parse_understands, [IVY_KW_IN] = parse_in, [IVY_KW_DO] = parse_do, [IVY_KW_IS] = parse_is, [IVY_KW_AND] = parse_and, [IVY_KW_OR] = parse_or, [IVY_KW_NOT] = parse_not, }, };