lang: ast: implement parsing of complex messages
This commit is contained in:
195
lang/ast/expr.c
195
lang/ast/expr.c
@@ -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). */
|
||||
|
||||
Reference in New Issue
Block a user