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,
|
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,
|
||||||
b_queue_push_back(&state->s_labels, &tok->t_entry);
|
* 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 *arg_expr
|
||||||
= (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR);
|
= (struct expr_parser_state *)parser_push_state(
|
||||||
arg_expr->s_terminator = IVY_TOK_LABEL;
|
ctx, IVY_AST_EXPR);
|
||||||
arg_expr->s_subexpr = true;
|
arg_expr->s_terminator = IVY_TOK_LABEL;
|
||||||
|
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). */
|
||||||
|
|||||||
Reference in New Issue
Block a user