refactor: removed duplicate code for while/until loops in parser

This commit is contained in:
Gu://em_ 2026-01-30 20:00:44 +01:00
parent 423793903d
commit 9f967dc9b4
2 changed files with 78 additions and 98 deletions

View file

@ -9,6 +9,8 @@
#include "grammar.h"
#include "grammar_basic.h"
// === Static functions
static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
{
switch (tok_type)
@ -32,6 +34,71 @@ static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
}
}
/*
* @brief parses a while/until loop starting with the condition
* (after the while/until keyword)
* @arg negate_condition Set to true for until loops, false for while loops
*/
static struct ast *parse_loop(struct lexer_context *ctx, bool negate_condition)
{
// condition
struct ast *condition = parse_compound_list(ctx);
if (condition == NULL)
return NULL;
if (negate_condition)
{
condition =
ast_create_neg(true, condition); // TODO check result (beware to not
// exceed the function lines limit)
}
struct token *token = PEEK_TOKEN();
// 'do'
if (token->type != TOKEN_DO)
{
ast_free(&condition);
perror("Syntax error: expected the 'do' keyowrd but got a different "
"token");
return NULL;
}
POP_TOKEN();
token = PEEK_TOKEN();
// body
struct ast *body = parse_compound_list(ctx);
if (body == NULL)
{
ast_free(&condition);
return NULL;
}
token = PEEK_TOKEN();
// 'done'
if (token->type != TOKEN_DONE)
{
ast_free(&condition);
perror("Syntax error: expected the 'done' keyowrd but got a different "
"token");
return NULL;
}
POP_TOKEN();
struct ast *result = ast_create_loop(condition, body);
if (result == NULL)
{
ast_free(&condition);
ast_free(&body);
perror("Internal error: could not create ast node (is your memory full "
"?)");
return NULL;
}
return result;
}
// === Functions
struct ast *parse_redirection(struct lexer_context *ctx)
{
struct token *token = PEEK_TOKEN();
@ -110,53 +177,7 @@ struct ast *parse_while(struct lexer_context *ctx)
}
POP_TOKEN();
// condition
struct ast *condition = parse_compound_list(ctx);
if (condition == NULL)
return NULL;
token = PEEK_TOKEN();
// 'do'
if (token->type != TOKEN_DO)
{
ast_free(&condition);
perror("Syntax error: expected the 'do' keyowrd but got a different "
"token");
return NULL;
}
POP_TOKEN();
token = PEEK_TOKEN();
// body
struct ast *body = parse_compound_list(ctx);
if (body == NULL)
{
ast_free(&condition);
return NULL;
}
token = PEEK_TOKEN();
// 'done'
if (token->type != TOKEN_DONE)
{
ast_free(&condition);
perror("Syntax error: expected the 'done' keyowrd but got a different "
"token");
return NULL;
}
POP_TOKEN();
struct ast *result = ast_create_loop(condition, body);
if (result == NULL)
{
ast_free(&condition);
ast_free(&body);
perror("Internal error: could not create ast node (is your memory full "
"?)");
return NULL;
}
return result;
return parse_loop(ctx, true);
}
struct ast *parse_until(struct lexer_context *ctx)
@ -172,54 +193,5 @@ struct ast *parse_until(struct lexer_context *ctx)
}
POP_TOKEN();
// condition
struct ast *condition = parse_compound_list(ctx);
if (condition == NULL)
return NULL;
condition =
ast_create_neg(true, condition); // TODO check result (beware to not
// exceed function lines limit)
token = PEEK_TOKEN();
// 'do'
if (token->type != TOKEN_DO)
{
ast_free(&condition);
perror("Syntax error: expected the 'do' keyowrd but got a different "
"token");
return NULL;
}
POP_TOKEN();
token = PEEK_TOKEN();
// body
struct ast *body = parse_compound_list(ctx);
if (body == NULL)
{
ast_free(&condition);
return NULL;
}
token = PEEK_TOKEN();
// 'done'
if (token->type != TOKEN_DONE)
{
ast_free(&condition);
perror("Syntax error: expected the 'done' keyowrd but got a different "
"token");
return NULL;
}
POP_TOKEN();
struct ast *result = ast_create_loop(condition, body);
if (result == NULL)
{
ast_free(&condition);
ast_free(&body);
perror("Internal error: could not create ast node (is your memory full "
"?)");
return NULL;
}
return result;
return parse_loop(ctx, true);
}

View file

@ -349,7 +349,15 @@ struct ast *parse_shell_command(struct lexer_context *ctx)
{
return parse_if_rule(ctx);
}
// TODO loops and case
else if (is_first(*token, RULE_WHILE))
{
return parse_while(ctx);
}
else if (is_first(*token, RULE_UNTIL))
{
return parse_until(ctx);
}
// TODO for and case
else
{
perror("Syntax error: unexpected token in parse_shell_command");