1472 lines
41 KiB
C
1472 lines
41 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>
|
|
#include <stdlib.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;
|
|
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;
|
|
}
|
|
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);
|
|
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);
|
|
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 */
|
|
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;
|
|
}
|