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,
};
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 {
EXPR_CMP_NONE = 0,
EXPR_CMP_OPERATOR,
@@ -43,15 +55,15 @@ struct expr_parser_state {
unsigned int s_terminator;
/* all sub-expressions (i.e. those conatained within brackets,
* keyword-messages and keyword-message args, etc) will have this set
* to true */
bool s_subexpr;
* keyword-messages and keyword-message args, etc) will have this set/ */
enum expr_subtype s_subexpr;
b_queue s_output_queue;
b_queue s_operator_stack;
/* these variables are for keyword-message expressions */
struct ivy_ast_node *s_recipient;
struct ivy_ast_msg_node *s_msg;
b_queue s_labels;
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) {
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)
{
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;
}
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) {
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);
}
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);
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);
}
b_queue_push_back(&state->s_operator_stack, &node->n_entry);
}
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);
// print_expr_queues(state);
state->s_prev_component = EXPR_CMP_OPERAND;
state->s_prev_token = tok->t_type;
return PARSE_RESULT(IVY_OK, 0);
}
@@ -455,15 +493,16 @@ static struct token_parse_result parse_operator(
state->s_prev_token = tok->t_keyword;
break;
default:
state->s_prev_token = tok->t_type;
break;
}
const struct ivy_operator *op = get_operator(tok);
struct ivy_ast_node *op = create_operator_node_from_token(tok);
if (!op) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
push_operator(state, tok);
push_operator(state, op);
state->s_prev_component = EXPR_CMP_OPERATOR;
print_expr_queues(state);
@@ -502,6 +541,28 @@ static struct token_parse_result parse_left_paren(
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 parser state */
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;
}
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(
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);
}
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);
}
if (state->s_recipient) {
if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG) {
/* this is the end of a keyword-message */
struct ivy_ast_msg_node *msg = finalise_keyword_msg(state);
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);
}
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. */
struct ivy_ast_node *expr = NULL;
enum ivy_status status
@@ -584,7 +683,7 @@ static struct token_parse_result parse_right_paren(
parser_replace_current_node(ctx, expr);
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;
}
@@ -626,7 +725,7 @@ static struct token_parse_result parse_dot(
parser_replace_current_node(ctx, expr);
int flags = 0;
if (state->s_subexpr) {
if (state->s_subexpr != EXPR_SUBTYPE_NONE) {
/* if we are currently parsing a subexpression (such as a
* keyword-message argument), the dot needs to be propagated to
* 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) {
/* we are currently parsing a keyword-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. */
/* 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
= 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);
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 */
struct expr_parser_state *msg_expr
= (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_subexpr = true;
msg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_MSG;
msg_expr->s_type = EXPR_TYPE_ARITH;
state = msg_expr;
}
/* we 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);
if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG
|| state->s_subexpr == 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);
arg_expr->s_terminator = IVY_TOK_LABEL;
arg_expr->s_subexpr = true;
struct expr_parser_state *arg_expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR);
arg_expr->s_terminator = IVY_TOK_LABEL;
arg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_ARG;
}
return PARSE_RESULT(IVY_OK, 0);
}
@@ -701,9 +813,12 @@ static enum ivy_status add_child(
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 */
b_queue_push_back(&state->s_args, &child->n_entry);
} else if (child->n_type == IVY_AST_MSG) {
push_operator(state, child);
} else {
/* treat the child node as a sub-expression enclosed in
* parentheses (i.e. an operand). */