From 6cdcf3f36baf8aadf500d73e45a730876050ca57 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Thu, 29 Jan 2026 20:41:45 +0100 Subject: [PATCH 01/17] fix: readded fsanitize for check_flemme.sh (linux only) --- check_flemme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_flemme.sh b/check_flemme.sh index 12398ae..0543001 100755 --- a/check_flemme.sh +++ b/check_flemme.sh @@ -32,7 +32,7 @@ run_cmd "Running autoreconf" autoreconf --force --verbose --install if [[ "$(uname)" == "Darwin" ]]; then run_cmd "Configuring for MacOS" ./configure CFLAGS='-std=c99 -Werror -Wall -Wextra -Wvla -I/opt/homebrew/include' LDFLAGS='-L/opt/homebrew/lib' else - run_cmd "Configuring for Linux" ./configure CFLAGS='-std=c99 -Werror -Wall -Wextra -Wvla -g' + run_cmd "Configuring for Linux" ./configure CFLAGS='-std=c99 -Werror -Wall -Wextra -Wvla -g -fsanitize=address' fi run_cmd "Cleaning build" make clean From e32715ce1351d659b0f2599572395ef6d6772b87 Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Thu, 29 Jan 2026 19:46:22 +0000 Subject: [PATCH 02/17] feat(execution): var assign --- src/execution/execution.c | 2 ++ src/execution/execution_helpers.c | 7 +++++++ src/execution/execution_helpers.h | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/execution/execution.c b/src/execution/execution.c index cf751f7..be3b378 100644 --- a/src/execution/execution.c +++ b/src/execution/execution.c @@ -40,6 +40,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_ASSIGNMENT: + return exec_ast_assignment(ast_get_assignment(ast), vars); default: return 127; } diff --git a/src/execution/execution_helpers.c b/src/execution/execution_helpers.c index 9e44dfa..c77c9b3 100644 --- a/src/execution/execution_helpers.c +++ b/src/execution/execution_helpers.c @@ -203,6 +203,13 @@ int exec_ast_command(struct ast_command *command, struct hash_map *vars) return 1; } + +int exec_ast_assignment(struct ast_assignment *assign, struct hash_map *vars) +{ + set_var_copy(vars, assign->name, assign->value); + return 0; +} + int exec_ast_if(struct ast_if *if_node, struct hash_map *vars) { int cond = execution(if_node->condition, vars); diff --git a/src/execution/execution_helpers.h b/src/execution/execution_helpers.h index 622c9fe..9fbe90a 100644 --- a/src/execution/execution_helpers.h +++ b/src/execution/execution_helpers.h @@ -8,7 +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_assignment(struct ast_assignment *assign, struct hash_map *vars); void unset_all_redir(struct list *redir_list); - #endif // EXECUTION_HELPERS_H From c4487762684f94134d37c73bf3484ba1effd3bef Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Thu, 29 Jan 2026 19:56:21 +0000 Subject: [PATCH 03/17] fix(execution): var update leak --- src/execution/execution.c | 2 -- src/execution/execution_helpers.c | 13 +------------ src/execution/execution_helpers.h | 1 - 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/execution/execution.c b/src/execution/execution.c index be3b378..cf751f7 100644 --- a/src/execution/execution.c +++ b/src/execution/execution.c @@ -40,8 +40,6 @@ 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_ASSIGNMENT: - return exec_ast_assignment(ast_get_assignment(ast), vars); default: return 127; } diff --git a/src/execution/execution_helpers.c b/src/execution/execution_helpers.c index c77c9b3..3166578 100644 --- a/src/execution/execution_helpers.c +++ b/src/execution/execution_helpers.c @@ -137,10 +137,7 @@ static int exec_assignment(struct list *assignment_list, struct hash_map *vars) struct ast_assignment *assignment = ast_get_assignment(assignment_list->data); - char *key = strdup(assignment->name); - char *value = strdup(assignment->value); - hash_map_insert(vars, key, value, NULL); - + set_var_copy(vars, assignment->name, assignment->value); assignment_list = assignment_list->next; } return 0; @@ -148,7 +145,6 @@ static int exec_assignment(struct list *assignment_list, struct hash_map *vars) int exec_ast_command(struct ast_command *command, struct hash_map *vars) { - (void)vars; exec_assignment(command->assignments, vars); set_all_redir(command->redirections); @@ -203,13 +199,6 @@ int exec_ast_command(struct ast_command *command, struct hash_map *vars) return 1; } - -int exec_ast_assignment(struct ast_assignment *assign, struct hash_map *vars) -{ - set_var_copy(vars, assign->name, assign->value); - return 0; -} - int exec_ast_if(struct ast_if *if_node, struct hash_map *vars) { int cond = execution(if_node->condition, vars); diff --git a/src/execution/execution_helpers.h b/src/execution/execution_helpers.h index 9fbe90a..ebf6858 100644 --- a/src/execution/execution_helpers.h +++ b/src/execution/execution_helpers.h @@ -8,7 +8,6 @@ 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_assignment(struct ast_assignment *assign, struct hash_map *vars); void unset_all_redir(struct list *redir_list); #endif // EXECUTION_HELPERS_H From e65c55f5c994779117b5e05dde85a25a0c874d40 Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Thu, 29 Jan 2026 11:18:33 +0000 Subject: [PATCH 04/17] feat(vars): unit tests --- tests/unit/utils/vars.c | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/unit/utils/vars.c diff --git a/tests/unit/utils/vars.c b/tests/unit/utils/vars.c new file mode 100644 index 0000000..73784cf --- /dev/null +++ b/tests/unit/utils/vars.c @@ -0,0 +1,85 @@ +#define _POSIX_C_SOURCE 200809L +#include "../../../src/utils/vars/vars.h" + +#include +#include +#include +#include +#include + +#include "../../../src/utils/hash_map/hash_map.h" +#include "../../../src/utils/string_utils/string_utils.h" + +TestSuite(utils_vars); + +Test(utils_vars, init_free) +{ + struct hash_map *map = vars_init(); + cr_expect_not_null(map); + hash_map_free(&map); +} + +Test(utils_vars, get_defaults) +{ + struct hash_map *map = vars_init(); + cr_expect_not_null(map); + cr_assert_str_eq(get_var(map, "?"), "0"); + char int_str[11]; + int_to_str((int)getpid(), int_str); + cr_assert_str_eq(get_var(map, "$"), int_str); + int_to_str((int)getuid(), int_str); + cr_assert_str_eq(get_var(map, "UID"), int_str); + + hash_map_free(&map); +} + +Test(utils_vars, set_vars) +{ + struct hash_map *map = vars_init(); + cr_expect_not_null(map); + set_var_copy(map, "key1", "value1"); + cr_assert_str_eq(get_var(map, "key1"), "value1"); + set_var_copy(map, "key2", "value2"); + cr_assert_str_eq(get_var(map, "key2"), "value2"); + + hash_map_free(&map); +} + +Test(utils_vars, get_env_vars) +{ + struct hash_map *map = vars_init(); + cr_expect_not_null(map); + cr_assert_eq(get_var_or_env(map, "ENV_TEST"), NULL); + setenv("ENV_TEST", "value1", 0); + cr_assert_str_eq(get_var_or_env(map, "ENV_TEST"), "value1"); + setenv("ENV_TEST", "value2", 1); + cr_assert_str_eq(get_var_or_env(map, "ENV_TEST"), "value2"); + + hash_map_free(&map); +} + +Test(utils_vars, set_vars_update) +{ + struct hash_map *map = vars_init(); + cr_expect_not_null(map); + set_var_copy(map, "key", "value1"); + cr_assert_str_eq(get_var(map, "key"), "value1"); + set_var_copy(map, "key", "value2"); + cr_assert_str_eq(get_var(map, "key"), "value2"); + + hash_map_free(&map); +} + +Test(utils_vars, set_vars_int) +{ + struct hash_map *map = vars_init(); + cr_expect_not_null(map); + set_var_int(map, "key1", 100); + cr_assert_str_eq(get_var(map, "key1"), "100"); + set_var_int(map, "key1", 200); + cr_assert_str_eq(get_var(map, "key1"), "200"); + set_var_int(map, "key2", 10); + cr_assert_str_eq(get_var(map, "key2"), "10"); + + hash_map_free(&map); +} From f0b39535fb82aa0779185813c406ce1ea17ae8bb Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Thu, 29 Jan 2026 20:35:56 +0000 Subject: [PATCH 05/17] feat(utils): lists tests --- src/utils/args/args.c | 2 +- src/utils/lists/lists.h | 2 +- src/utils/lists/lists1.c | 5 +- tests/unit/utils/lists.c | 305 +++++++++++++++++++++++++++++++++++++++ tests/unit/utils/vars.c | 1 - 5 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 tests/unit/utils/lists.c diff --git a/src/utils/args/args.c b/src/utils/args/args.c index a957382..c34599f 100644 --- a/src/utils/args/args.c +++ b/src/utils/args/args.c @@ -121,7 +121,7 @@ int args_handler(int argc, char **argv, struct args_options *options, } args_in_var(vars, args_list); - list_destroy(args_list); + list_destroy(&args_list); if (options->type == INPUT_UNDEFINED) options->type = INPUT_STDIN; diff --git a/src/utils/lists/lists.h b/src/utils/lists/lists.h index 9b5d38e..9f8cebb 100644 --- a/src/utils/lists/lists.h +++ b/src/utils/lists/lists.h @@ -31,7 +31,7 @@ void list_print(struct list *list); ** Release the memory used by the list. ** Does nothing if `list` is `NULL`. */ -void list_destroy(struct list *list); +void list_destroy(struct list **list); /* ** Release the memory used by the list and its content diff --git a/src/utils/lists/lists1.c b/src/utils/lists/lists1.c index d191bf7..521e131 100644 --- a/src/utils/lists/lists1.c +++ b/src/utils/lists/lists1.c @@ -49,9 +49,9 @@ void list_print(struct list *list) } } -void list_destroy(struct list *list) +void list_destroy(struct list **list) { - struct list *elt = list; + struct list *elt = *list; struct list *next_elt; while (elt != NULL) { @@ -59,6 +59,7 @@ void list_destroy(struct list *list) free(elt); elt = next_elt; } + *list = NULL; } struct list *list_append(struct list *list, void *value) diff --git a/tests/unit/utils/lists.c b/tests/unit/utils/lists.c new file mode 100644 index 0000000..c852803 --- /dev/null +++ b/tests/unit/utils/lists.c @@ -0,0 +1,305 @@ +#define _POSIX_C_SOURCE 200809L + +#include "../../../src/utils/lists/lists.h" + +#include +#include +#include +#include +#include +#include +#include + +TestSuite(lists); + +Test(lists, append_empty) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next == NULL); + cr_expect(list_length(lst) == 1); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, prepend_empty) +{ + struct list *lst = NULL; + lst = list_prepend(lst, (void *)1); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next == NULL); + cr_expect(list_length(lst) == 1); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, insert_empty) +{ + struct list *lst = NULL; + lst = list_insert(lst, (void *)1, 0); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next == NULL); + cr_expect(list_length(lst) == 1); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, insert_out_of_bounds) +{ + struct list *lst = NULL; + lst = list_insert(lst, (void *)1, 5); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next == NULL); + cr_expect(list_length(lst) == 1); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, remove_out_of_bounds) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_remove(lst, 5); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next == NULL); + cr_expect(list_length(lst) == 1); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, append_multiple) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_append(lst, (void *)2); + lst = list_append(lst, (void *)3); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next->data == (void *)2); + cr_expect(lst->next->next->data == (void *)3); + cr_expect(lst->next->next->next == NULL); + cr_expect(list_length(lst) == 3); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, prepend_multiple) +{ + struct list *lst = NULL; + lst = list_prepend(lst, (void *)1); + lst = list_prepend(lst, (void *)2); + lst = list_prepend(lst, (void *)3); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)3); + cr_expect(lst->next->data == (void *)2); + cr_expect(lst->next->next->data == (void *)1); + cr_expect(lst->next->next->next == NULL); + cr_expect(list_length(lst) == 3); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, insert_multiple) +{ + struct list *lst = NULL; + lst = list_insert(lst, (void *)1, 0); + lst = list_insert(lst, (void *)3, 1); + lst = list_insert(lst, (void *)2, 1); + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next->data == (void *)2); + cr_expect(lst->next->next->data == (void *)3); + cr_expect(lst->next->next->next == NULL); + cr_expect(list_length(lst) == 3); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, append) +{ + struct list *lst = NULL; + lst = list_prepend(lst, (void *)2); + lst = list_prepend(lst, (void *)1); + + lst = list_append(lst, (void *)3); + + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)1); + cr_expect(lst->next->data == (void *)2); + cr_expect(lst->next->next->data == (void *)3); + cr_expect(lst->next->next->next == NULL); + cr_expect(list_length(lst) == 3); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, prepend) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_append(lst, (void *)2); + + lst = list_prepend(lst, (void *)0); + + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)0); + cr_expect(lst->next->data == (void *)1); + cr_expect(lst->next->next->data == (void *)2); + cr_expect(lst->next->next->next == NULL); + cr_expect(list_length(lst) == 3); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, insert) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_append(lst, (void *)3); + + lst = list_insert(lst, (void *)2, 1); + lst = list_insert(lst, (void *)0, 0); + + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)0); + cr_expect(lst->next->data == (void *)1); + cr_expect(lst->next->next->data == (void *)2); + cr_expect(lst->next->next->next->data == (void *)3); + cr_expect(lst->next->next->next->next == NULL); + cr_expect(list_length(lst) == 4); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, remove) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_append(lst, (void *)2); + lst = list_append(lst, (void *)3); + lst = list_append(lst, (void *)4); + + lst = list_remove(lst, 1); // remove 2 + lst = list_remove(lst, 2); // remove 4 + lst = list_remove(lst, 0); // remove 1 + + cr_expect(lst != NULL); + cr_expect(lst->data == (void *)3); + cr_expect(lst->next == NULL); + cr_expect(list_length(lst) == 1); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, destroy_null) +{ + struct list *lst = NULL; + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, deep_destroy_null) +{ + struct list *lst = NULL; + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, deep_destroy) +{ + struct list *lst = NULL; + lst = list_append(lst, strdup("string1")); + lst = list_append(lst, strdup("string2")); + lst = list_append(lst, strdup("string3")); + + list_deep_destroy(lst); +} + +Test(lists, length_empty) +{ + struct list *lst = NULL; + cr_expect(list_length(lst) == 0); +} + +Test(lists, print_empty, .init = cr_redirect_stdout) +{ + struct list *lst = NULL; + list_print(lst); + cr_expect_stdout_eq_str(""); +} + +Test(lists, print_non_empty, .init = cr_redirect_stdout) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_append(lst, (void *)2); + lst = list_append(lst, (void *)3); + + list_print(lst); + fflush(stdout); + cr_expect_stdout_eq_str("0x1 0x2 0x3\n"); + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +Test(lists, find_empty) +{ + struct list *lst = NULL; + cr_expect(list_find(lst, (void *)1) == -1); +} + +Test(lists, find_non_empty) +{ + struct list *lst = NULL; + lst = list_append(lst, (void *)1); + lst = list_append(lst, (void *)2); + lst = list_append(lst, (void *)3); + + cr_expect(list_find(lst, (void *)1) == 0); + cr_expect(list_find(lst, (void *)2) == 1); + cr_expect(list_find(lst, (void *)3) == 2); + cr_expect(list_find(lst, (void *)4) == -1); // not found + + list_destroy(&lst); + cr_expect(lst == NULL); +} + +static void fold_func(void *acc, void *data) +{ + *(int *)acc += *(int *)data; +} + +Test(lists, fold) +{ + struct list *lst = NULL; + int v1 = 10, v2 = 20, v3 = 30; + lst = list_append(lst, &v1); + lst = list_append(lst, &v2); + lst = list_append(lst, &v3); + + int sum = 0; + list_fold(lst, &sum, fold_func); + cr_expect(sum == 60); + + list_destroy(&lst); + cr_expect(lst == NULL); +} diff --git a/tests/unit/utils/vars.c b/tests/unit/utils/vars.c index 73784cf..0c6d6ea 100644 --- a/tests/unit/utils/vars.c +++ b/tests/unit/utils/vars.c @@ -3,7 +3,6 @@ #include #include -#include #include #include From 5740195cb3ce8bbfd2b0b48828888945de85b725 Mon Sep 17 00:00:00 2001 From: matteo Date: Fri, 30 Jan 2026 12:21:29 +0100 Subject: [PATCH 06/17] fix: heap-use-after-free and memory leaks on erorr cases --- src/main.c | 7 +++---- src/parser/grammar.c | 14 +++++++++----- src/parser/grammar_basic.c | 7 +++++-- src/utils/hash_map/hash_map.c | 1 + 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main.c b/src/main.c index c8988ca..6b0f59f 100644 --- a/src/main.c +++ b/src/main.c @@ -66,8 +66,11 @@ static int main_loop(struct lexer_context *ctx, struct args_options *options, if (command_ast == NULL) return err_input(&vars); + // === free + ast_free(&command_ast); parser_close(); + hash_map_free(&vars); return return_code; } @@ -120,9 +123,5 @@ int main(int argc, char **argv) return_code = main_loop(&ctx, &options, vars); - // === free - - hash_map_free(&vars); - return return_code; } diff --git a/src/parser/grammar.c b/src/parser/grammar.c index 57d7d20..73258ea 100644 --- a/src/parser/grammar.c +++ b/src/parser/grammar.c @@ -238,16 +238,20 @@ struct ast *parse_input(struct lexer_context *ctx) } struct ast *ast = parse_list(ctx); - if (ast == NULL) - return NULL; - token = PEEK_TOKEN(); - if (token->type == TOKEN_NEWLINE || token->type == TOKEN_EOF) + + if (ast == NULL) { - if (token->type == TOKEN_NEWLINE) + if (token != NULL && token->type == TOKEN_EOF) { POP_TOKEN(); } + return NULL; + } + + if (token->type == TOKEN_NEWLINE || token->type == TOKEN_EOF) + { + POP_TOKEN(); return ast; } diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index 9b4add2..6a6839b 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -329,12 +329,13 @@ struct ast *parse_if_rule(struct lexer_context *ctx) struct ast *condition_content = parse_compound_list(ctx); // Then keyword - token = POP_TOKEN(); + token = PEEK_TOKEN(); if (token->type != TOKEN_THEN) { perror("Expected the 'then' keyword but token has different type"); return err_if_rule(&condition_content, NULL, NULL); } + POP_TOKEN(); // Then content struct ast *then_content = parse_compound_list(ctx); @@ -344,6 +345,7 @@ struct ast *parse_if_rule(struct lexer_context *ctx) } struct ast *else_content = NULL; + token = PEEK_TOKEN(); // Eventual else/elif clause(s) if (is_first(*token, RULE_ELSE_CLAUSE)) { @@ -355,12 +357,13 @@ struct ast *parse_if_rule(struct lexer_context *ctx) } // Fi keyword - token = POP_TOKEN(); + token = PEEK_TOKEN(); if (token->type != TOKEN_FI) { perror("Expected the 'fi' keyword but token has different type"); return err_if_rule(&condition_content, &then_content, &else_content); } + POP_TOKEN(); // Result struct ast *result = diff --git a/src/utils/hash_map/hash_map.c b/src/utils/hash_map/hash_map.c index 3d77734..6f9a513 100644 --- a/src/utils/hash_map/hash_map.c +++ b/src/utils/hash_map/hash_map.c @@ -117,6 +117,7 @@ void hash_map_free(struct hash_map **hash_map) free((*hash_map)->data); free(*hash_map); } + *hash_map = NULL; } void hash_map_foreach(struct hash_map *hash_map, From 52d35cf3552201ec3d6c62668ef62527b06589d6 Mon Sep 17 00:00:00 2001 From: matteo Date: Fri, 30 Jan 2026 16:51:10 +0100 Subject: [PATCH 07/17] fix: memory issues, parser errors and get_ast_if returning always NULL --- src/execution/execution_helpers.c | 2 ++ src/parser/grammar.c | 1 + src/parser/grammar_basic.c | 2 +- src/utils/ast/ast_if.c | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/execution/execution_helpers.c b/src/execution/execution_helpers.c index 3166578..9a72c10 100644 --- a/src/execution/execution_helpers.c +++ b/src/execution/execution_helpers.c @@ -201,6 +201,8 @@ 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) { + if (if_node == NULL) + return 2; int cond = execution(if_node->condition, vars); if (cond == 0) return execution(if_node->then_clause, vars); diff --git a/src/parser/grammar.c b/src/parser/grammar.c index 73258ea..b89a99e 100644 --- a/src/parser/grammar.c +++ b/src/parser/grammar.c @@ -140,6 +140,7 @@ bool grammar_init(void) // Element add_first(RULE_ELEMENT, TOKEN_WORD); + add_first(RULE_ELEMENT, TOKEN_ASSIGNMENT_WORD); add_firsts(RULE_ELEMENT, first(RULE_REDIRECTION)); // Prefix diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index 6a6839b..86ed089 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -281,7 +281,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) struct ast *parse_element(struct lexer_context *ctx) { struct token *token = PEEK_TOKEN(); - if (token->type == TOKEN_WORD) + if (token->type == TOKEN_WORD || token->type == TOKEN_ASSIGNMENT_WORD) { token = POP_TOKEN(); return ast_create_word(token->data); diff --git a/src/utils/ast/ast_if.c b/src/utils/ast/ast_if.c index 1402ff6..6b0ff5d 100644 --- a/src/utils/ast/ast_if.c +++ b/src/utils/ast/ast_if.c @@ -19,7 +19,7 @@ struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, struct ast_if *ast_get_if(struct ast *node) { - if (node == NULL || node->type == AST_IF) + if (node == NULL || node->type != AST_IF) return NULL; return node->data; } From 30e30f55e7ab47064e44a0284a993da9f76f8878 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 17:43:18 +0100 Subject: [PATCH 08/17] fix(lexer): ongoing-> recongize OR as PIPE --- src/lexer/lexer_utils.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index 3029394..d9a84dc 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -72,10 +72,6 @@ static void set_token_keyword(struct token *tok, char *begin, ssize_t size) tok->type = TOKEN_ELSE; else if (strncmp(begin, "elif", size) == 0 && size == 4) tok->type = TOKEN_ELIF; - else if (strncmp(begin, "&&", size) == 0 && size == 2) - tok->type = TOKEN_AND; - else if (strncmp(begin, "||", size) == 0 && size == 2) - tok->type = TOKEN_OR; // no keywords found. if (tok->type == TOKEN_NULL) @@ -97,7 +93,12 @@ static void set_token_operator(struct token *tok, char *begin, ssize_t size) { if (tok->type != TOKEN_NULL) return; - if (strncmp(begin, ">", size) == 0) + if (strncmp(begin, "&&", size) == 0 && size == 2) + tok->type = TOKEN_AND; + else if (strncmp(begin, "||", size) == 0 && size == 2) + tok->type = TOKEN_OR; + + else if (strncmp(begin, ">", size) == 0) { tok->type = TOKEN_REDIR_RIGHT; } @@ -231,9 +232,9 @@ struct token *new_token(char *begin, ssize_t size, struct token_info *info) set_token_assignment(tok, begin, size); else { + set_token_keyword(tok, begin, size); set_token_operator(tok, begin, size); set_token_spechar(tok, begin, size); - set_token_keyword(tok, begin, size); set_token_word(tok, begin, size); } @@ -286,10 +287,19 @@ ssize_t len_op_sepchar(char *stream, ssize_t i) if (!is_special_char(stream, i)) return -1; // should never happen - if (stream[i] != '>' && stream[i] != '<') - return 1; // special character (cannot be operator) + // OR + if (stream[i] == '|' && stream[i + 1] == '|') + return 2; - // operator + // AND + if (stream[i] == '|' && stream[i + 1] == '|') + return 2; + + // special chars + if (stream[i] != '>' && stream[i] != '<') + return 1; + + // REDIRS if (stream[i] == '<') { From fd59d63c4705cd52169508eca2ac16c8572b0550 Mon Sep 17 00:00:00 2001 From: matteo Date: Fri, 30 Jan 2026 17:47:51 +0100 Subject: [PATCH 09/17] fix(lexer): recongize OR as PIPE --- src/lexer/lexer_utils.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index d9a84dc..dee3f88 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -94,39 +94,43 @@ static void set_token_operator(struct token *tok, char *begin, ssize_t size) if (tok->type != TOKEN_NULL) return; if (strncmp(begin, "&&", size) == 0 && size == 2) + { tok->type = TOKEN_AND; + } else if (strncmp(begin, "||", size) == 0 && size == 2) + { tok->type = TOKEN_OR; + } - else if (strncmp(begin, ">", size) == 0) + else if (strncmp(begin, ">", size) == 0 && size == 1) { tok->type = TOKEN_REDIR_RIGHT; } - else if (strncmp(begin, "<", size) == 0) + else if (strncmp(begin, "<", size) == 0 && size == 1) { tok->type = TOKEN_REDIR_LEFT; } - else if (strncmp(begin, ">>", size) == 0) + else if (strncmp(begin, ">>", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_DOUBLE_RIGHT; } - else if (strncmp(begin, ">&", size) == 0) + else if (strncmp(begin, ">&", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_RIGHT_AMP; } - else if (strncmp(begin, ">|", size) == 0) + else if (strncmp(begin, ">|", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_RIGHT_PIPE; } - else if (strncmp(begin, "<&", size) == 0) + else if (strncmp(begin, "<&", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_LEFT_AMP; } - else if (strncmp(begin, "<>", size) == 0) + else if (strncmp(begin, "<>", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_LEFT_RIGHT; } - else if (strncmp(begin, "|", size) == 0) + else if (strncmp(begin, "|", size) == 0 && size == 1) { tok->type = TOKEN_PIPE; } From fcfc7fedc97b9995e82fe56bc293832284e277ae Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 18:26:56 +0100 Subject: [PATCH 10/17] fix(clang-tidy): for clang, function cannot return bool if it takes no arguments ???? --- src/parser/grammar.c | 2 +- src/parser/grammar.h | 2 +- src/parser/parser.c | 2 +- src/parser/parser.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parser/grammar.c b/src/parser/grammar.c index b89a99e..6089c18 100644 --- a/src/parser/grammar.c +++ b/src/parser/grammar.c @@ -91,7 +91,7 @@ static bool init_firsts_map(void) // === Functions -bool grammar_init(void) +int grammar_init(void) { // Initialize the firsts map bool success = init_firsts_map(); diff --git a/src/parser/grammar.h b/src/parser/grammar.h index 663d37b..020d733 100644 --- a/src/parser/grammar.h +++ b/src/parser/grammar.h @@ -64,7 +64,7 @@ struct firsts_list * @return PARSER_INIT_SUCCESS on success PARSER_INIT_ERROR on error * @warning Do not use outside the parser */ -bool grammar_init(void); +int grammar_init(void); /* * @brief Closes the grammar submodule diff --git a/src/parser/parser.c b/src/parser/parser.c index c2b8aaf..ec60b71 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -10,7 +10,7 @@ static enum parser_state state = PARSER_STATE_NOT_INITIALIZED; // === Functions -bool parser_init(void) +int parser_init(void) { if (state == PARSER_STATE_READY) { diff --git a/src/parser/parser.h b/src/parser/parser.h index a79497b..dc01a5e 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -18,7 +18,7 @@ enum parser_state * * @return Returns false on error and true on success */ -bool parser_init(void); +int parser_init(void); /* @brief Closes the parser module after use */ From bada9c6a298223499707d8ea9445a8fac591e139 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 18:35:26 +0100 Subject: [PATCH 11/17] fix: building now --- src/parser/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/parser.c b/src/parser/parser.c index ec60b71..d1f0ebc 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -15,7 +15,7 @@ int parser_init(void) if (state == PARSER_STATE_READY) { perror("Internal error: tried to initialize the parser module twice."); - return NULL; + return false; } int success = grammar_init(); if (success == false) From 115377edfe5bc36758ea7883846c7e5e0764ca64 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 19:13:27 +0100 Subject: [PATCH 12/17] feat(lexer + parser): export handling --- src/lexer/lexer_utils.c | 2 + src/lexer/lexer_utils.h | 3 +- src/parser/grammar_basic.c | 125 ++++++++++++++++++++++--------------- 3 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index dee3f88..c2265e8 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -72,6 +72,8 @@ static void set_token_keyword(struct token *tok, char *begin, ssize_t size) tok->type = TOKEN_ELSE; else if (strncmp(begin, "elif", size) == 0 && size == 4) tok->type = TOKEN_ELIF; + else if (strncmp(begin, "export", size) == 0 && size == 6) + tok->type = TOKEN_ELIF; // no keywords found. if (tok->type == TOKEN_NULL) diff --git a/src/lexer/lexer_utils.h b/src/lexer/lexer_utils.h index af64455..6f6ade2 100644 --- a/src/lexer/lexer_utils.h +++ b/src/lexer/lexer_utils.h @@ -72,7 +72,8 @@ enum token_type TOKEN_FOR, TOKEN_WHILE, TOKEN_UNTIL, - TOKEN_CASE + TOKEN_CASE, + TOKEN_EXPORT }; struct token diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index 86ed089..c3a4ea0 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -174,14 +174,33 @@ struct ast *parse_command(struct lexer_context *ctx) /* @brief: frees command_elements and redirections lists (helper func) * @return: NULL */ -static void *err_simple_command(struct list *command_elements, - struct list *redirections) +static void *err_s_com(struct list *command_elements, struct list *redirections, + struct list *assignments); { list_deep_destroy(command_elements); list_deep_destroy(redirections); + list_deep_destroy(assignments); return NULL; } +static ast *parse_export(struct lexer_context *ctx) +{ + struct token *token = PEEK_TOKEN(); + if (token->type != TOKEN_EXPORT) + { + fprintf(stderr, "expected the export keyword in parse_export"); + return NULL; + } + POP_TOKEN(); + token = PEEK_TOKEN(); + if (token->type != TOKEN_ASSIGNMENT_WORD) + { + fprintf(stderr, "in parser: export must be followed by 'x=y'"); + return NULL; + } + return ast_create_assignment(token->data, true); +} + struct ast *parse_simple_command(struct lexer_context *ctx) { struct list *command_elements = NULL; @@ -198,7 +217,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) struct ast *prefix = parse_prefix(ctx); if (prefix == NULL) { - return err_simple_command(command_elements, redirections); + return err_s_com(command_elements, redirections); } if (prefix->type == AST_ASSIGNMENT) { @@ -214,66 +233,70 @@ struct ast *parse_simple_command(struct lexer_context *ctx) if (token->type != TOKEN_WORD) { - if (!has_prefix) + if (!has_prefix && token->type != TOKEN_EXPORT) { perror("Expected a command but got a different token type"); - return err_simple_command(command_elements, redirections); + return err_s_com(command_elements, redirections, assignments); + } + if (token->type == TOKEN_EXPORT) + { + struct ast *assignment_export = parse_export(ctx); + if (assignment == NULL) + return err_s_com(command_elements, redirections, assignments); + + assignments = list_append(assignments, assignment_export); } - // else : only prefixes } - else + else // TOKEN WORD { - if (token->type == TOKEN_WORD) + char *command = strdup(token->data); + command_elements = list_append(command_elements, command); + + POP_TOKEN(); + token = PEEK_TOKEN(); + } + // Eventual elements + while (is_first(*token, RULE_ELEMENT)) + { + // Get element + struct ast *element = parse_element(ctx); + if (element == NULL) { - char *command = strdup(token->data); - command_elements = list_append(command_elements, command); - - POP_TOKEN(); - token = PEEK_TOKEN(); + return err_s_com(command_elements, redirections, assignments); } - // Eventual elements - while (is_first(*token, RULE_ELEMENT)) + + // Get element type + if (ast_is_word(element)) { - // Get element - struct ast *element = parse_element(ctx); - if (element == NULL) - { - return err_simple_command(command_elements, redirections); - } + struct ast_word *element_word = ast_get_word(element); - // Get element type - if (ast_is_word(element)) - { - struct ast_word *element_word = ast_get_word(element); - - // TODO test this fix for the memory leaks - char *word = strdup(element_word->word); - ast_free(&element); - command_elements = list_append(command_elements, word); - // end of fix - } - else if (ast_is_redir(element)) - { - // append redirections to the list of redirections - redirections = list_append(redirections, element); - } - else - { - perror("Internal error: unexpected return value from " - "parse_element in parse_simple_command"); - return err_simple_command(command_elements, redirections); - } - - // Forward - token = PEEK_TOKEN(); + // TODO test this fix for the memory leaks + char *word = strdup(element_word->word); + ast_free(&element); + command_elements = list_append(command_elements, word); + // end of fix } + else if (ast_is_redir(element)) + { + // append redirections to the list of redirections + redirections = list_append(redirections, element); + } + else + { + perror("Internal error: unexpected return value from " + "parse_element in parse_simple_command"); + return err_s_com(command_elements, redirections, assignments); + } + + // Forward + token = PEEK_TOKEN(); } struct ast *result = ast_create_command(command_elements, redirections, assignments); if (result == NULL) { - return err_simple_command(command_elements, redirections); + return err_s_com(command_elements, redirections, assignments); } return result; } @@ -290,6 +313,10 @@ struct ast *parse_element(struct lexer_context *ctx) { return parse_redirection(ctx); } + else if (token->type == TOKEN_EXPORT) + { + return parse_export(ctx); + } else { perror("Syntax error: unexpected token at parse_element"); @@ -455,8 +482,8 @@ struct ast *parse_else_clause(struct lexer_context *ctx) token = POP_TOKEN(); if (token->type != TOKEN_THEN) { - perror( - "Expected the 'then' keyword but got a different token type"); + perror("Expected the 'then' keyword but got a different token " + "type"); return NULL; } From 1367598047a3c66ab3243d92c545ed7ece25bb76 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 19:14:01 +0100 Subject: [PATCH 13/17] fix(lexer): typo on export --- src/lexer/lexer_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index c2265e8..02f0a3f 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -73,7 +73,7 @@ static void set_token_keyword(struct token *tok, char *begin, ssize_t size) else if (strncmp(begin, "elif", size) == 0 && size == 4) tok->type = TOKEN_ELIF; else if (strncmp(begin, "export", size) == 0 && size == 6) - tok->type = TOKEN_ELIF; + tok->type = TOKEN_EXPORT; // no keywords found. if (tok->type == TOKEN_NULL) From aa45e3d30f484aca1b1da991eab88421874dffc0 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 19:37:05 +0100 Subject: [PATCH 14/17] feat: export handling, except exec --- src/parser/grammar.c | 23 +++++++++++++++-------- src/parser/grammar_advanced.c | 2 +- src/parser/grammar_basic.c | 20 +++++++++++++++----- src/utils/ast/ast_assignment.c | 3 ++- src/utils/ast/ast_assignment.h | 3 ++- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/parser/grammar.c b/src/parser/grammar.c index 6089c18..0680a79 100644 --- a/src/parser/grammar.c +++ b/src/parser/grammar.c @@ -89,6 +89,18 @@ static bool init_firsts_map(void) return true; } +static void add_first_redir(void) +{ + add_first(RULE_REDIRECTION, TOKEN_IONUMBER); + add_first(RULE_REDIRECTION, TOKEN_REDIR_LEFT); + add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT); + add_first(RULE_REDIRECTION, TOKEN_REDIR_LEFT_RIGHT); + add_first(RULE_REDIRECTION, TOKEN_REDIR_DOUBLE_RIGHT); + add_first(RULE_REDIRECTION, TOKEN_REDIR_LEFT_AMP); + add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_AMP); + add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_PIPE); +} + // === Functions int grammar_init(void) @@ -128,15 +140,9 @@ int grammar_init(void) add_firsts(RULE_CASE_CLAUSE, first(RULE_CASE_ITEM)); // Redirection - add_first(RULE_REDIRECTION, TOKEN_IONUMBER); - add_first(RULE_REDIRECTION, TOKEN_REDIR_LEFT); - add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT); - add_first(RULE_REDIRECTION, TOKEN_REDIR_LEFT_RIGHT); - add_first(RULE_REDIRECTION, TOKEN_REDIR_DOUBLE_RIGHT); - add_first(RULE_REDIRECTION, TOKEN_REDIR_LEFT_AMP); - add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_AMP); - add_first(RULE_REDIRECTION, TOKEN_REDIR_RIGHT_PIPE); + add_first_redir(); // %RIP Matteo 30/01/2026 + // %RAX Guillem 30/01/2026 hehe // Element add_first(RULE_ELEMENT, TOKEN_WORD); @@ -153,6 +159,7 @@ int grammar_init(void) // 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); diff --git a/src/parser/grammar_advanced.c b/src/parser/grammar_advanced.c index d57e70e..4dd8f77 100644 --- a/src/parser/grammar_advanced.c +++ b/src/parser/grammar_advanced.c @@ -71,7 +71,7 @@ struct ast *parse_prefix(struct lexer_context *ctx) if (token->type == TOKEN_ASSIGNMENT_WORD) { token = POP_TOKEN(); - return ast_create_assignment(token->data); + return ast_create_assignment(token->data, false); } else if (is_first(*token, RULE_REDIRECTION)) return parse_redirection(ctx); diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index c3a4ea0..d2a2343 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -175,7 +175,7 @@ struct ast *parse_command(struct lexer_context *ctx) * @return: NULL */ static void *err_s_com(struct list *command_elements, struct list *redirections, - struct list *assignments); + struct list *assignments) { list_deep_destroy(command_elements); list_deep_destroy(redirections); @@ -183,7 +183,10 @@ static void *err_s_com(struct list *command_elements, struct list *redirections, return NULL; } -static ast *parse_export(struct lexer_context *ctx) +/* @brief: used when export keyword is found, and expects an assignment after. + * @return: an ast_assignment with the field [global] set to true. + */ +static struct ast *parse_export(struct lexer_context *ctx) { struct token *token = PEEK_TOKEN(); if (token->type != TOKEN_EXPORT) @@ -191,13 +194,20 @@ static ast *parse_export(struct lexer_context *ctx) fprintf(stderr, "expected the export keyword in parse_export"); return NULL; } + // export POP_TOKEN(); + token = PEEK_TOKEN(); + if (token->type != TOKEN_ASSIGNMENT_WORD) { fprintf(stderr, "in parser: export must be followed by 'x=y'"); return NULL; } + + // assignment + POP_TOKEN(); + return ast_create_assignment(token->data, true); } @@ -217,7 +227,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) struct ast *prefix = parse_prefix(ctx); if (prefix == NULL) { - return err_s_com(command_elements, redirections); + return err_s_com(command_elements, redirections, assignments); } if (prefix->type == AST_ASSIGNMENT) { @@ -241,7 +251,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) if (token->type == TOKEN_EXPORT) { struct ast *assignment_export = parse_export(ctx); - if (assignment == NULL) + if (assignment_export == NULL) return err_s_com(command_elements, redirections, assignments); assignments = list_append(assignments, assignment_export); @@ -253,8 +263,8 @@ struct ast *parse_simple_command(struct lexer_context *ctx) command_elements = list_append(command_elements, command); POP_TOKEN(); - token = PEEK_TOKEN(); } + token = PEEK_TOKEN(); // Eventual elements while (is_first(*token, RULE_ELEMENT)) { diff --git a/src/utils/ast/ast_assignment.c b/src/utils/ast/ast_assignment.c index e859912..72cfdb6 100644 --- a/src/utils/ast/ast_assignment.c +++ b/src/utils/ast/ast_assignment.c @@ -34,7 +34,7 @@ static void init_assignments(struct ast_assignment *ast_assignment, ast_assignment->value = strdup(split_pos + 1); } -struct ast *ast_create_assignment(char *assignment) +struct ast *ast_create_assignment(char *assignment, bool global) { struct ast_assignment *assignment_data = calloc(1, sizeof(struct ast_assignment)); @@ -42,6 +42,7 @@ struct ast *ast_create_assignment(char *assignment) return NULL; init_assignments(assignment_data, assignment); + assignment_data->global = global; return ast_create(AST_ASSIGNMENT, assignment_data); } diff --git a/src/utils/ast/ast_assignment.h b/src/utils/ast/ast_assignment.h index 5be56c8..3ebac14 100644 --- a/src/utils/ast/ast_assignment.h +++ b/src/utils/ast/ast_assignment.h @@ -7,11 +7,12 @@ struct ast_assignment { char *name; char *value; + bool global; }; bool ast_is_assignment(struct ast *node); struct ast_assignment *ast_get_assignment(struct ast *node); -struct ast *ast_create_assignment(char *assignment); +struct ast *ast_create_assignment(char *assignment, bool global); void ast_free_assignment(struct ast_assignment *assignment_data); #endif /* ! AST_ASSIGNMENT_H */ From 8ca7a92e7db39c26325dfbff6ad3ea6a9ce57268 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 20:00:09 +0100 Subject: [PATCH 15/17] fix(parser): removed unused old version of static function --- src/parser/grammar_basic.c | 91 +++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index 8be9ea3..17a3fb3 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -26,17 +26,6 @@ static enum ast_and_or_type and_or_tok_to_ast(enum token_type tok_type) } } -/* @brief: frees command_elements and redirections lists (helper func) - * @return: NULL - */ -static void *err_simple_command(struct list *command_elements, - struct list *redirections) -{ - list_deep_destroy(command_elements); - list_deep_destroy(redirections); - return NULL; -} - /* @brief: frees all the arguments. (helper func) * @return: NULL. */ @@ -49,6 +38,46 @@ static void *err_if_rule(struct ast **cond, struct ast **then_clause, return NULL; } +/* @brief: frees command_elements and redirections lists (helper func) + * @return: NULL + */ +static void *err_s_com(struct list *command_elements, struct list *redirections, + struct list *assignments) +{ + list_deep_destroy(command_elements); + list_deep_destroy(redirections); + list_deep_destroy(assignments); + return NULL; +} + +/* @brief: used when export keyword is found, and expects an assignment after. + * @return: an ast_assignment with the field [global] set to true. + */ +static struct ast *parse_export(struct lexer_context *ctx) +{ + struct token *token = PEEK_TOKEN(); + if (token->type != TOKEN_EXPORT) + { + fprintf(stderr, "expected the export keyword in parse_export"); + return NULL; + } + // export + POP_TOKEN(); + + token = PEEK_TOKEN(); + + if (token->type != TOKEN_ASSIGNMENT_WORD) + { + fprintf(stderr, "in parser: export must be followed by 'x=y'"); + return NULL; + } + + // assignment + POP_TOKEN(); + + return ast_create_assignment(token->data, true); +} + // === Functions struct ast *parse_list(struct lexer_context *ctx) @@ -203,46 +232,6 @@ struct ast *parse_command(struct lexer_context *ctx) return result; } -/* @brief: frees command_elements and redirections lists (helper func) - * @return: NULL - */ -static void *err_s_com(struct list *command_elements, struct list *redirections, - struct list *assignments) -{ - list_deep_destroy(command_elements); - list_deep_destroy(redirections); - list_deep_destroy(assignments); - return NULL; -} - -/* @brief: used when export keyword is found, and expects an assignment after. - * @return: an ast_assignment with the field [global] set to true. - */ -static struct ast *parse_export(struct lexer_context *ctx) -{ - struct token *token = PEEK_TOKEN(); - if (token->type != TOKEN_EXPORT) - { - fprintf(stderr, "expected the export keyword in parse_export"); - return NULL; - } - // export - POP_TOKEN(); - - token = PEEK_TOKEN(); - - if (token->type != TOKEN_ASSIGNMENT_WORD) - { - fprintf(stderr, "in parser: export must be followed by 'x=y'"); - return NULL; - } - - // assignment - POP_TOKEN(); - - return ast_create_assignment(token->data, true); -} - struct ast *parse_simple_command(struct lexer_context *ctx) { struct list *command_elements = NULL; From df367b0a3c9345cb34bd39656b53547d4fcd5092 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 20:05:48 +0100 Subject: [PATCH 16/17] feat(tests): .sh file to test and_ors --- tests/test.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 tests/test.sh diff --git a/tests/test.sh b/tests/test.sh new file mode 100755 index 0000000..c2f4cf0 --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,17 @@ +true +echo 'true =' $? + +false +echo 'false =' $? + +false && true +echo 'false && true =' $? + +true && false +echo 'true && false =' $? + +true || false +echo 'true || false =' $? + +false || true +echo 'false || true =' $? From 00fe1a471789433e0b9322e9d33ccf31256638ed Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 20:06:40 +0100 Subject: [PATCH 17/17] feat(tests): and_ors.sh renamed --- tests/{test.sh => and_ors.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test.sh => and_ors.sh} (100%) diff --git a/tests/test.sh b/tests/and_ors.sh similarity index 100% rename from tests/test.sh rename to tests/and_ors.sh