feat: full while/until loops support, important bug fixes and more tests

This commit is contained in:
Gu://em_ 2026-01-30 23:43:49 +01:00
parent 9e522b2a68
commit f31fca4204
6 changed files with 85 additions and 37 deletions

View file

@ -1,17 +1,13 @@
#define _POSIX_C_SOURCE 200809L
#include "execution.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "../expansion/expansion.h"
#include "../utils/ast/ast.h"
#include "../utils/hash_map/hash_map.h"
// Refactored: delegates to helpers in execution_helpers.c
@ -40,6 +36,8 @@ int execution(struct ast *ast, struct hash_map *vars)
return exec_ast_list(ast_get_list(ast), vars);
case AST_AND_OR:
return exec_ast_and_or(ast_get_and_or(ast), vars);
case AST_LOOP:
return exec_ast_loop(ast_get_loop(ast), vars);
default:
return 127;
}

View file

@ -1,7 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include "execution_helpers.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@ -9,8 +8,6 @@
#include <sys/wait.h>
#include <unistd.h>
#include "../expansion/expansion.h"
#include "../utils/ast/ast.h"
#include "../utils/hash_map/hash_map.h"
#include "../utils/lists/lists.h"
#include "../utils/vars/vars.h"
@ -275,6 +272,17 @@ void unset_all_redir(struct list *redir_list)
}
}
int exec_ast_loop(struct ast_loop *loop_node, struct hash_map *vars)
{
int res = 0;
while (execution(loop_node->condition, vars) == 0)
{
res = execution(loop_node->body, vars);
}
return res;
}
// --- Builtins ---
static int builtin_echo(char **argv)

View file

@ -8,6 +8,7 @@ int exec_ast_command(struct ast_command *command, struct hash_map *vars);
int exec_ast_if(struct ast_if *if_node, struct hash_map *vars);
int exec_ast_list(struct ast_list *list_node, struct hash_map *vars);
int exec_ast_and_or(struct ast_and_or *ao_node, struct hash_map *vars);
int exec_ast_loop(struct ast_loop *loop_node, struct hash_map *vars);
void unset_all_redir(struct list *redir_list);
#endif // EXECUTION_HELPERS_H

View file

@ -101,17 +101,13 @@ static void add_first_redir(void)
add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_PIPE);
}
// === Functions
int grammar_init(void)
// Adds only direct tokens to rules firsts into the firsts map
static void add_firsts_tokens(void)
{
// Initialize the firsts map
bool success = init_firsts_map();
if (success != true)
return false;
// Populate the firsts map
// TODO CHECK ORDER
// Redirection
add_first_redir();
// %RIP Matteo 30/01/2026
// %RAX Guillem 30/01/2026 hehe
// If
add_first(RULE_IF, TOKEN_IF);
@ -127,7 +123,7 @@ int grammar_init(void)
add_first(RULE_WHILE, TOKEN_WHILE);
// Until
add_first(RULE_WHILE, TOKEN_UNTIL);
add_first(RULE_UNTIL, TOKEN_UNTIL);
// Case
add_first(RULE_CASE, TOKEN_CASE);
@ -136,33 +132,57 @@ int grammar_init(void)
add_first(RULE_CASE_ITEM, TOKEN_LEFT_PAREN);
add_first(RULE_CASE_ITEM, TOKEN_WORD);
// Case clause
add_firsts(RULE_CASE_CLAUSE, first(RULE_CASE_ITEM));
// Shell command
add_first(RULE_SHELL_COMMAND, TOKEN_LEFT_BRACKET);
add_first(RULE_SHELL_COMMAND, TOKEN_LEFT_PAREN);
// Redirection
add_first_redir();
// %RIP Matteo 30/01/2026
// %RAX Guillem 30/01/2026 hehe
// Simple command
add_first(RULE_SIMPLE_COMMAND, TOKEN_WORD);
add_first(RULE_SIMPLE_COMMAND, TOKEN_EXPORT);
// Element
add_first(RULE_ELEMENT, TOKEN_WORD);
add_first(RULE_ELEMENT, TOKEN_ASSIGNMENT_WORD);
add_firsts(RULE_ELEMENT, first(RULE_REDIRECTION));
// Prefix
add_first(RULE_PREFIX, TOKEN_ASSIGNMENT_WORD);
// Pipeline
add_first(RULE_PIPELINE, TOKEN_WORD);
// Compound list
add_first(RULE_COMPOUND_LIST, TOKEN_NEWLINE);
// Input
add_first(RULE_INPUT, TOKEN_NEWLINE);
add_first(RULE_INPUT, TOKEN_EOF);
// Funcdec
add_first(RULE_FUNCDEC, TOKEN_WORD);
}
// Adds only firsts that depend on other rules to the firsts map
// WARNING order matters
static void add_firsts_rec(void)
{
// Case clause
add_firsts(RULE_CASE_CLAUSE, first(RULE_CASE_ITEM));
// Element
add_firsts(RULE_ELEMENT, first(RULE_REDIRECTION));
// Prefix
add_firsts(RULE_PREFIX, first(RULE_REDIRECTION));
// Shell command
add_firsts(RULE_SHELL_COMMAND, first(RULE_IF));
add_firsts(RULE_SHELL_COMMAND, first(RULE_FOR));
add_firsts(RULE_SHELL_COMMAND, first(RULE_WHILE));
add_firsts(RULE_SHELL_COMMAND, first(RULE_UNTIL));
add_firsts(RULE_SHELL_COMMAND, first(RULE_CASE));
// Simple command
add_firsts(RULE_SIMPLE_COMMAND, first(RULE_PREFIX));
add_first(RULE_SIMPLE_COMMAND, TOKEN_WORD);
add_first(RULE_SIMPLE_COMMAND, TOKEN_EXPORT);
// Funcdec
add_first(RULE_FUNCDEC, TOKEN_WORD);
// Command
add_firsts(RULE_COMMAND, first(RULE_SIMPLE_COMMAND));
@ -170,23 +190,33 @@ int grammar_init(void)
add_firsts(RULE_COMMAND, first(RULE_FUNCDEC));
// Pipeline
add_first(RULE_PIPELINE, TOKEN_WORD);
add_firsts(RULE_PIPELINE, first(RULE_COMMAND));
// And Or
add_firsts(RULE_AND_OR, first(RULE_PIPELINE));
// Compound list
add_first(RULE_COMPOUND_LIST, TOKEN_NEWLINE);
add_firsts(RULE_COMPOUND_LIST, first(RULE_AND_OR));
// List
add_firsts(RULE_LIST, first(RULE_AND_OR));
// Input
add_first(RULE_INPUT, TOKEN_NEWLINE);
add_first(RULE_INPUT, TOKEN_EOF);
add_firsts(RULE_INPUT, first(RULE_LIST));
}
// === Functions
int grammar_init(void)
{
// Initialize the firsts map
bool success = init_firsts_map();
if (success != true)
return false;
// Populate the firsts map
add_firsts_tokens();
add_firsts_rec();
return true;
}

View file

@ -42,6 +42,12 @@ void ast_free(struct ast **node)
case AST_ASSIGNMENT:
ast_free_assignment(ast_get_assignment(*node));
break;
case AST_NEG:
ast_free_neg(ast_get_neg(*node));
break;
case AST_LOOP:
ast_free_loop(ast_get_loop(*node));
break;
case AST_VOID:
case AST_END:
break;