Files
ivy/lang/ast/expr/arith.c

1183 lines
32 KiB
C

#include "../block.h"
#include "../debug.h"
#include "../node.h"
#include "expr.h"
#include <blue/object/string.h>
#include <ivy/lang/lex.h>
#include <ivy/lang/operator.h>
#include <stdio.h>
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("<keyword-msg>");
}
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("<node>");
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;
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;
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;
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;
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);
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);
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);
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;
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->op_arity == IVY_OP_BINARY) {
tmp = b_queue_pop_back(&q);
op_node->n_left
= b_unbox(struct ivy_ast_node, tmp, n_entry);
}
/* ...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_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_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);
}
switch (tok->t_type) {
case IVY_TOK_SYMBOL:
state->s_prev_token = tok->t_symbol;
break;
case IVY_TOK_KEYWORD:
state->s_prev_token = tok->t_keyword;
break;
default:
state->s_prev_token = tok->t_type;
break;
}
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 (state->s_terminator == IVY_KW_IN) {
state->s_prev_token = IVY_KW_IN;
return expr_finalise_and_return(ctx, state);
}
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 (state->s_terminator == 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 is the opening parenthesis for a complex message. */
b_queue_entry *msg_entry
= b_queue_pop_back(&state->s_operator_stack);
struct ivy_ast_node *msg
= b_unbox(struct ivy_ast_node, msg_entry, n_entry);
if (msg->n_type != IVY_AST_MSG) {
return PARSE_RESULT(IVY_ERR_INTERNAL_FAILURE, 0);
}
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;
return PARSE_RESULT(IVY_OK, 0);
}
/* a sub-expression surrounded by parentheses is parsed by creating
* a sub-expression parser state */
struct expr_parser_state *sub_expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
sub_expr->s_paren_depth = state->s_paren_depth + 1;
sub_expr->s_subexpr_depth = state->s_subexpr_depth + 1;
return PARSE_RESULT(IVY_OK, 0);
}
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;
}
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 (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);
}
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_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);
}
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_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)) {
/* tuple. */
return PARSE_RESULT(IVY_ERR_NOT_SUPPORTED, 0);
}
state->s_prev_token = IVY_SYM_DOT;
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_terminator == IVY_TOK_LABEL) {
/* 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;
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_ERR_BAD_SYNTAX, PARSE_REPEAT_TOKEN);
}
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);
} 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_KEYWORD_MSG
|| state->s_sub_type == EXPR_SUBTYPE_COMPLEX_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);
arg_expr->s_terminator = 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;
}