lang: ast: implement parsing of complex messages

This commit is contained in:
2024-12-02 10:48:16 +00:00
parent 1c5b23d968
commit 5ec3e8fcd4

View File

@@ -16,6 +16,18 @@ enum expr_type {
EXPR_TYPE_ARITH, EXPR_TYPE_ARITH,
}; };
enum expr_subtype {
EXPR_SUBTYPE_NONE = 0,
/* generic parenthesis-enclosed arithmetic expressions */
EXPR_SUBTYPE_PAREN,
/* keyword messages */
EXPR_SUBTYPE_KEYWORD_MSG,
/* expression delimited by labels */
EXPR_SUBTYPE_KEYWORD_ARG,
/* complex messages */
EXPR_SUBTYPE_COMPLEX_MSG,
};
enum expr_component { enum expr_component {
EXPR_CMP_NONE = 0, EXPR_CMP_NONE = 0,
EXPR_CMP_OPERATOR, EXPR_CMP_OPERATOR,
@@ -43,15 +55,15 @@ struct expr_parser_state {
unsigned int s_terminator; unsigned int s_terminator;
/* all sub-expressions (i.e. those conatained within brackets, /* all sub-expressions (i.e. those conatained within brackets,
* keyword-messages and keyword-message args, etc) will have this set * keyword-messages and keyword-message args, etc) will have this set/ */
* to true */ enum expr_subtype s_subexpr;
bool s_subexpr;
b_queue s_output_queue; b_queue s_output_queue;
b_queue s_operator_stack; b_queue s_operator_stack;
/* these variables are for keyword-message expressions */ /* these variables are for keyword-message expressions */
struct ivy_ast_node *s_recipient; struct ivy_ast_node *s_recipient;
struct ivy_ast_msg_node *s_msg;
b_queue s_labels; b_queue s_labels;
b_queue s_args; b_queue s_args;
}; };
@@ -139,7 +151,7 @@ static void push_operand(struct expr_parser_state *state, struct ivy_token *tok)
} }
} }
static const struct ivy_operator *get_operator(struct ivy_token *tok) static const struct ivy_operator *get_operator_from_token(struct ivy_token *tok)
{ {
switch (tok->t_type) { switch (tok->t_type) {
case IVY_TOK_SYMBOL: case IVY_TOK_SYMBOL:
@@ -151,6 +163,20 @@ static const struct ivy_operator *get_operator(struct ivy_token *tok)
} }
} }
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) 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 *sel
@@ -159,9 +185,32 @@ static struct ivy_ast_selector_node *unary_selector_from_token(struct ivy_token
return sel; return sel;
} }
static void push_operator(struct expr_parser_state *state, struct ivy_token *tok) static struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok)
{ {
const struct ivy_operator *op = get_operator(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;
}
static void 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) { while (true) {
b_queue_entry *top = b_queue_last(&state->s_operator_stack); b_queue_entry *top = b_queue_last(&state->s_operator_stack);
@@ -200,19 +249,7 @@ static void push_operator(struct expr_parser_state *state, struct ivy_token *tok
b_queue_push_back(&state->s_output_queue, top); b_queue_push_back(&state->s_output_queue, top);
} }
if (op->op_id == IVY_OP_MSG) { b_queue_push_back(&state->s_operator_stack, &node->n_entry);
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);
b_queue_push_back(
&state->s_operator_stack, &new_msg_node->n_base.n_entry);
} else {
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;
b_queue_push_back(
&state->s_operator_stack, &new_op_node->n_base.n_entry);
}
} }
static void print_expr_queues(struct expr_parser_state *state) static void print_expr_queues(struct expr_parser_state *state)
@@ -433,6 +470,7 @@ static struct token_parse_result parse_operand(
push_operand(state, tok); push_operand(state, tok);
// print_expr_queues(state); // print_expr_queues(state);
state->s_prev_component = EXPR_CMP_OPERAND; state->s_prev_component = EXPR_CMP_OPERAND;
state->s_prev_token = tok->t_type;
return PARSE_RESULT(IVY_OK, 0); return PARSE_RESULT(IVY_OK, 0);
} }
@@ -455,15 +493,16 @@ static struct token_parse_result parse_operator(
state->s_prev_token = tok->t_keyword; state->s_prev_token = tok->t_keyword;
break; break;
default: default:
state->s_prev_token = tok->t_type;
break; break;
} }
const struct ivy_operator *op = get_operator(tok); struct ivy_ast_node *op = create_operator_node_from_token(tok);
if (!op) { if (!op) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
} }
push_operator(state, tok); push_operator(state, op);
state->s_prev_component = EXPR_CMP_OPERATOR; state->s_prev_component = EXPR_CMP_OPERATOR;
print_expr_queues(state); print_expr_queues(state);
@@ -502,6 +541,28 @@ static struct token_parse_result parse_left_paren(
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); 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);
msg_expr->s_msg = (struct ivy_ast_msg_node *)msg;
msg_expr->s_subexpr = EXPR_SUBTYPE_COMPLEX_MSG;
msg_expr->s_type = EXPR_TYPE_ARITH;
return PARSE_RESULT(IVY_OK, 0);
}
/* a sub-expression surrounded by parentheses is parsed by creating /* a sub-expression surrounded by parentheses is parsed by creating
* a sub-expression parser state */ * a sub-expression parser state */
struct expr_parser_state *sub_expr struct expr_parser_state *sub_expr
@@ -551,6 +612,36 @@ static struct ivy_ast_msg_node *finalise_keyword_msg(struct expr_parser_state *s
return msg; return msg;
} }
static struct ivy_ast_msg_node *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 struct token_parse_result parse_right_paren( static struct token_parse_result parse_right_paren(
struct ivy_parser *ctx, struct ivy_token *tok) struct ivy_parser *ctx, struct ivy_token *tok)
{ {
@@ -561,11 +652,11 @@ static struct token_parse_result parse_right_paren(
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
} }
if (state->s_paren_depth == 0 && !state->s_subexpr) { if (state->s_paren_depth == 0 && state->s_subexpr == EXPR_SUBTYPE_NONE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
} }
if (state->s_recipient) { if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG) {
/* this is the end of a keyword-message */ /* this is the end of a keyword-message */
struct ivy_ast_msg_node *msg = finalise_keyword_msg(state); struct ivy_ast_msg_node *msg = finalise_keyword_msg(state);
parser_replace_current_node(ctx, (struct ivy_ast_node *)msg); parser_replace_current_node(ctx, (struct ivy_ast_node *)msg);
@@ -573,6 +664,14 @@ static struct token_parse_result parse_right_paren(
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
} }
if (state->s_subexpr == EXPR_SUBTYPE_COMPLEX_MSG) {
/* this is the end of a keyword-message */
struct ivy_ast_msg_node *msg = finalise_complex_msg(state);
parser_replace_current_node(ctx, (struct ivy_ast_node *)msg);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
/* this is the end of a regular parentheses-surrounded sub-expression. */ /* this is the end of a regular parentheses-surrounded sub-expression. */
struct ivy_ast_node *expr = NULL; struct ivy_ast_node *expr = NULL;
enum ivy_status status enum ivy_status status
@@ -584,7 +683,7 @@ static struct token_parse_result parse_right_paren(
parser_replace_current_node(ctx, expr); parser_replace_current_node(ctx, expr);
int flags = 0; int flags = 0;
if (state->s_paren_depth == 0 && state->s_subexpr) { if (state->s_paren_depth == 0 && state->s_subexpr != EXPR_SUBTYPE_NONE) {
flags = PARSE_REPEAT_TOKEN; flags = PARSE_REPEAT_TOKEN;
} }
@@ -626,7 +725,7 @@ static struct token_parse_result parse_dot(
parser_replace_current_node(ctx, expr); parser_replace_current_node(ctx, expr);
int flags = 0; int flags = 0;
if (state->s_subexpr) { if (state->s_subexpr != EXPR_SUBTYPE_NONE) {
/* if we are currently parsing a subexpression (such as a /* if we are currently parsing a subexpression (such as a
* keyword-message argument), the dot needs to be propagated to * keyword-message argument), the dot needs to be propagated to
* the parent expression context so that it can be terminated * the parent expression context so that it can be terminated
@@ -649,15 +748,24 @@ static struct token_parse_result parse_label(
} }
if (state->s_terminator == IVY_TOK_LABEL) { if (state->s_terminator == IVY_TOK_LABEL) {
/* we are currently parsing a keyword-message argument, and /* we are currently parsing a keyword or complex message
* have just encountered the label denoting the next argument. * argument, and have just encountered the label denoting the
* terminate here and propagate this label to the parent * next argument. terminate here and propagate this label to the
* keyword-message parser context. */ * parent keyword-message parser context. */
struct ivy_ast_node *expr = NULL;
enum ivy_status status
= finalise_expr(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); parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, PARSE_REPEAT_TOKEN); return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, PARSE_REPEAT_TOKEN);
} }
if (!state->s_recipient) { if (state->s_subexpr != EXPR_SUBTYPE_KEYWORD_MSG
&& state->s_subexpr != EXPR_SUBTYPE_COMPLEX_MSG) {
/* this is the beginning of a new keyword-message */ /* this is the beginning of a new keyword-message */
struct expr_parser_state *msg_expr struct expr_parser_state *msg_expr
= (struct expr_parser_state *)parser_push_state( = (struct expr_parser_state *)parser_push_state(
@@ -675,20 +783,24 @@ static struct token_parse_result parse_label(
} }
msg_expr->s_recipient = expr; msg_expr->s_recipient = expr;
msg_expr->s_subexpr = true; msg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_MSG;
msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_type = EXPR_TYPE_ARITH;
state = msg_expr; state = msg_expr;
} }
/* we have just finished parsing a keyword-message argument, and this if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG
* label marks the start of a new one. store the label and create a || state->s_subexpr == EXPR_SUBTYPE_COMPLEX_MSG) {
* new argument parsing context. */ /* 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); b_queue_push_back(&state->s_labels, &tok->t_entry);
struct expr_parser_state *arg_expr struct expr_parser_state *arg_expr
= (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR); = (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR);
arg_expr->s_terminator = IVY_TOK_LABEL; arg_expr->s_terminator = IVY_TOK_LABEL;
arg_expr->s_subexpr = true; arg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_ARG;
}
return PARSE_RESULT(IVY_OK, 0); return PARSE_RESULT(IVY_OK, 0);
} }
@@ -701,9 +813,12 @@ static enum ivy_status add_child(
return IVY_ERR_NOT_SUPPORTED; return IVY_ERR_NOT_SUPPORTED;
} }
if (state->s_recipient) { if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG
|| state->s_subexpr == EXPR_SUBTYPE_COMPLEX_MSG) {
/* treat the child node as a keyword-message argument */ /* treat the child node as a keyword-message argument */
b_queue_push_back(&state->s_args, &child->n_entry); b_queue_push_back(&state->s_args, &child->n_entry);
} else if (child->n_type == IVY_AST_MSG) {
push_operator(state, child);
} else { } else {
/* treat the child node as a sub-expression enclosed in /* treat the child node as a sub-expression enclosed in
* parentheses (i.e. an operand). */ * parentheses (i.e. an operand). */