feat: full while/until loops support, important bug fixes and more tests
This commit is contained in:
parent
9e522b2a68
commit
f31fca4204
6 changed files with 85 additions and 37 deletions
|
|
@ -1,17 +1,13 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "execution.h"
|
#include "execution.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../expansion/expansion.h"
|
#include "../expansion/expansion.h"
|
||||||
#include "../utils/ast/ast.h"
|
|
||||||
#include "../utils/hash_map/hash_map.h"
|
#include "../utils/hash_map/hash_map.h"
|
||||||
|
|
||||||
// Refactored: delegates to helpers in execution_helpers.c
|
// 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);
|
return exec_ast_list(ast_get_list(ast), vars);
|
||||||
case AST_AND_OR:
|
case AST_AND_OR:
|
||||||
return exec_ast_and_or(ast_get_and_or(ast), vars);
|
return exec_ast_and_or(ast_get_and_or(ast), vars);
|
||||||
|
case AST_LOOP:
|
||||||
|
return exec_ast_loop(ast_get_loop(ast), vars);
|
||||||
default:
|
default:
|
||||||
return 127;
|
return 127;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "execution_helpers.h"
|
#include "execution_helpers.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -9,8 +8,6 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../expansion/expansion.h"
|
|
||||||
#include "../utils/ast/ast.h"
|
|
||||||
#include "../utils/hash_map/hash_map.h"
|
#include "../utils/hash_map/hash_map.h"
|
||||||
#include "../utils/lists/lists.h"
|
#include "../utils/lists/lists.h"
|
||||||
#include "../utils/vars/vars.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 ---
|
// --- Builtins ---
|
||||||
|
|
||||||
static int builtin_echo(char **argv)
|
static int builtin_echo(char **argv)
|
||||||
|
|
|
||||||
|
|
@ -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_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_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_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);
|
void unset_all_redir(struct list *redir_list);
|
||||||
#endif // EXECUTION_HELPERS_H
|
#endif // EXECUTION_HELPERS_H
|
||||||
|
|
|
||||||
|
|
@ -101,17 +101,13 @@ static void add_first_redir(void)
|
||||||
add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_PIPE);
|
add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_PIPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Functions
|
// Adds only direct tokens to rules firsts into the firsts map
|
||||||
|
static void add_firsts_tokens(void)
|
||||||
int grammar_init(void)
|
|
||||||
{
|
{
|
||||||
// Initialize the firsts map
|
// Redirection
|
||||||
bool success = init_firsts_map();
|
add_first_redir();
|
||||||
if (success != true)
|
// %RIP Matteo 30/01/2026
|
||||||
return false;
|
// %RAX Guillem 30/01/2026 hehe
|
||||||
|
|
||||||
// Populate the firsts map
|
|
||||||
// TODO CHECK ORDER
|
|
||||||
|
|
||||||
// If
|
// If
|
||||||
add_first(RULE_IF, TOKEN_IF);
|
add_first(RULE_IF, TOKEN_IF);
|
||||||
|
|
@ -127,7 +123,7 @@ int grammar_init(void)
|
||||||
add_first(RULE_WHILE, TOKEN_WHILE);
|
add_first(RULE_WHILE, TOKEN_WHILE);
|
||||||
|
|
||||||
// Until
|
// Until
|
||||||
add_first(RULE_WHILE, TOKEN_UNTIL);
|
add_first(RULE_UNTIL, TOKEN_UNTIL);
|
||||||
|
|
||||||
// Case
|
// Case
|
||||||
add_first(RULE_CASE, TOKEN_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_LEFT_PAREN);
|
||||||
add_first(RULE_CASE_ITEM, TOKEN_WORD);
|
add_first(RULE_CASE_ITEM, TOKEN_WORD);
|
||||||
|
|
||||||
// Case clause
|
// Shell command
|
||||||
add_firsts(RULE_CASE_CLAUSE, first(RULE_CASE_ITEM));
|
add_first(RULE_SHELL_COMMAND, TOKEN_LEFT_BRACKET);
|
||||||
|
add_first(RULE_SHELL_COMMAND, TOKEN_LEFT_PAREN);
|
||||||
|
|
||||||
// Redirection
|
// Simple command
|
||||||
add_first_redir();
|
add_first(RULE_SIMPLE_COMMAND, TOKEN_WORD);
|
||||||
// %RIP Matteo 30/01/2026
|
add_first(RULE_SIMPLE_COMMAND, TOKEN_EXPORT);
|
||||||
// %RAX Guillem 30/01/2026 hehe
|
|
||||||
|
|
||||||
// Element
|
// Element
|
||||||
add_first(RULE_ELEMENT, TOKEN_WORD);
|
add_first(RULE_ELEMENT, TOKEN_WORD);
|
||||||
add_first(RULE_ELEMENT, TOKEN_ASSIGNMENT_WORD);
|
add_first(RULE_ELEMENT, TOKEN_ASSIGNMENT_WORD);
|
||||||
add_firsts(RULE_ELEMENT, first(RULE_REDIRECTION));
|
|
||||||
|
|
||||||
// Prefix
|
// Prefix
|
||||||
add_first(RULE_PREFIX, TOKEN_ASSIGNMENT_WORD);
|
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));
|
add_firsts(RULE_PREFIX, first(RULE_REDIRECTION));
|
||||||
|
|
||||||
// Shell command
|
// Shell command
|
||||||
add_firsts(RULE_SHELL_COMMAND, first(RULE_IF));
|
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
|
// Simple command
|
||||||
add_firsts(RULE_SIMPLE_COMMAND, first(RULE_PREFIX));
|
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
|
// Command
|
||||||
add_firsts(RULE_COMMAND, first(RULE_SIMPLE_COMMAND));
|
add_firsts(RULE_COMMAND, first(RULE_SIMPLE_COMMAND));
|
||||||
|
|
@ -170,23 +190,33 @@ int grammar_init(void)
|
||||||
add_firsts(RULE_COMMAND, first(RULE_FUNCDEC));
|
add_firsts(RULE_COMMAND, first(RULE_FUNCDEC));
|
||||||
|
|
||||||
// Pipeline
|
// Pipeline
|
||||||
add_first(RULE_PIPELINE, TOKEN_WORD);
|
|
||||||
add_firsts(RULE_PIPELINE, first(RULE_COMMAND));
|
add_firsts(RULE_PIPELINE, first(RULE_COMMAND));
|
||||||
|
|
||||||
// And Or
|
// And Or
|
||||||
add_firsts(RULE_AND_OR, first(RULE_PIPELINE));
|
add_firsts(RULE_AND_OR, first(RULE_PIPELINE));
|
||||||
|
|
||||||
// Compound list
|
// Compound list
|
||||||
add_first(RULE_COMPOUND_LIST, TOKEN_NEWLINE);
|
|
||||||
add_firsts(RULE_COMPOUND_LIST, first(RULE_AND_OR));
|
add_firsts(RULE_COMPOUND_LIST, first(RULE_AND_OR));
|
||||||
|
|
||||||
// List
|
// List
|
||||||
add_firsts(RULE_LIST, first(RULE_AND_OR));
|
add_firsts(RULE_LIST, first(RULE_AND_OR));
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
add_first(RULE_INPUT, TOKEN_NEWLINE);
|
|
||||||
add_first(RULE_INPUT, TOKEN_EOF);
|
|
||||||
add_firsts(RULE_INPUT, first(RULE_LIST));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,12 @@ void ast_free(struct ast **node)
|
||||||
case AST_ASSIGNMENT:
|
case AST_ASSIGNMENT:
|
||||||
ast_free_assignment(ast_get_assignment(*node));
|
ast_free_assignment(ast_get_assignment(*node));
|
||||||
break;
|
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_VOID:
|
||||||
case AST_END:
|
case AST_END:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -377,9 +377,14 @@ test_str "If with negation" "if ! false; then echo Yes; fi"
|
||||||
test_str "If faut aller niquer sa mere" "if false; ! false; then echo Embrasse moi; fi"
|
test_str "If faut aller niquer sa mere" "if false; ! false; then echo Embrasse moi; fi"
|
||||||
|
|
||||||
|
|
||||||
echo -e "\n$BBlue=== For/While ===$Color_Off"
|
echo -e "\n$BBlue=== Loops ===$Color_Off"
|
||||||
test_str "While loop" "i=0; while [ \$i -lt 3 ]; do echo \$i; i=\$((i+1)); done"
|
test_str "While false" "while false; do false; done"
|
||||||
test_str "Until loop" "i=0; until [ \$i -ge 3 ]; do echo \$i; i=\$((i+1)); done"
|
test_str "While(false) true" "while false; do true; done"
|
||||||
|
test_str "Until(true) false" "until true; do false; done"
|
||||||
|
test_str "Until true" "until true; do true; done"
|
||||||
|
# test_str "While var" "a=2; while [ \$a -eq 2 ]; do \$a=3; done"
|
||||||
|
test_str "While arithmetic" "i=0; while [ \$i -lt 3 ]; do echo \$i; i=\$((i+1)); done"
|
||||||
|
test_str "Until arithmetic" "i=0; until [ \$i -ge 3 ]; do echo \$i; i=\$((i+1)); done"
|
||||||
test_str "While break" "while true; do echo break; break; done"
|
test_str "While break" "while true; do echo break; break; done"
|
||||||
test_str "While continue" "i=0; while [ \$i -lt 3 ]; do i=\$((i+1)); if [ \$i -eq 2 ]; then continue; fi; echo \$i; done"
|
test_str "While continue" "i=0; while [ \$i -lt 3 ]; do i=\$((i+1)); if [ \$i -eq 2 ]; then continue; fi; echo \$i; done"
|
||||||
test_str "For loop basic" "for i in a b c; do echo \$i; done"
|
test_str "For loop basic" "for i in a b c; do echo \$i; done"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue