parse: implement parsing of if-statements

This commit is contained in:
2026-05-12 22:57:31 +01:00
parent 26e2a63200
commit 7d2e45edcb
+110
View File
@@ -0,0 +1,110 @@
#include "../syntax.h"
static bool add_branch(
struct if_ast_node *group,
struct ast_node *cond,
struct ast_node *body)
{
struct if_branch_ast_node *branch
= (struct if_branch_ast_node *)ast_node_create(AST_IF_BRANCH);
if (!branch) {
return false;
}
branch->n_cond = cond;
branch->n_body = body;
fx_queue_push_back(&group->n_branches, &branch->n_base.n_entry);
return true;
}
bool parse_if(struct parse_ctx *ctx, struct ast_node **out)
{
if (!parse_keyword(ctx, KW_IF)) {
return false;
}
if (!parse_symbol(ctx, SYM_LEFT_PAREN)) {
report_error(ctx, "expected `(` after `if`");
return false;
}
struct ast_node *if_cond = NULL, *if_body = NULL;
if (!parse_expr(ctx, &if_cond)) {
report_error(ctx, "invalid if condition");
return false;
}
if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) {
report_error(ctx, "expected `)` after if-condition");
ast_node_destroy(if_cond);
return false;
}
if (!parse_block(ctx, &if_body)) {
report_error(ctx, "invalid if body");
ast_node_destroy(if_cond);
return false;
}
struct if_ast_node *if_group
= (struct if_ast_node *)ast_node_create(AST_IF);
if (!if_group) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
ast_node_destroy(if_cond);
ast_node_destroy(if_body);
return false;
}
if (!add_branch(if_group, if_cond, if_body)) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
ast_node_destroy(if_cond);
ast_node_destroy(if_body);
ast_node_destroy((struct ast_node *)if_group);
return false;
}
bool done = false;
while (!done) {
struct ast_node *cond = NULL, *body = NULL;
if (parse_keyword(ctx, KW_ELSE)) {
done = true;
} else if (parse_keyword(ctx, KW_ELSEIF)) {
if (!parse_expr(ctx, &cond)) {
report_error(
ctx,
"invalid conditional expression");
ast_node_destroy((struct ast_node *)if_group);
return false;
}
} else {
done = true;
break;
}
if (!parse_block(ctx, &body)) {
report_error(ctx, "invalid conditional body");
if (cond) {
ast_node_destroy(cond);
}
ast_node_destroy((struct ast_node *)if_group);
return false;
}
if (!add_branch(if_group, cond, body)) {
report_error(ctx, "failed to add branch to if-group");
if (cond) {
ast_node_destroy(cond);
}
ast_node_destroy(body);
ast_node_destroy((struct ast_node *)if_group);
return false;
}
}
*out = (struct ast_node *)if_group;
return true;
}