From ac851fa895cc827e74cc78ee076845421fb9a61e Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Sat, 31 Jan 2026 15:50:57 +0100 Subject: [PATCH] fix: fixed A LOT of bugs and memory leaks. Removed ast_is_* commands as they're not really useful and seems redundant with ast_get_*. Also made some changes to lists utils to make architecture clearer and some other random tweaks or fixes. --- src/execution/execution_helpers.c | 17 ++- src/parser/grammar_basic.c | 4 +- src/utils/Makefile.am | 6 +- src/utils/ast/ast.c | 7 +- src/utils/ast/ast_and_or.c | 29 ++-- src/utils/ast/ast_and_or.h | 1 - src/utils/ast/ast_assignment.c | 86 ++++++++--- src/utils/ast/ast_assignment.h | 1 - src/utils/ast/ast_command.c | 17 ++- src/utils/ast/ast_command.h | 5 - src/utils/ast/ast_if.c | 15 +- src/utils/ast/ast_if.h | 5 - src/utils/ast/ast_list.c | 20 ++- src/utils/ast/ast_list.h | 5 - src/utils/ast/ast_loop.c | 18 ++- src/utils/ast/ast_loop.h | 7 +- src/utils/ast/ast_neg.c | 32 ++-- src/utils/ast/ast_neg.h | 1 - src/utils/ast/ast_pipe.c | 33 ++-- src/utils/ast/ast_pipe.h | 1 - src/utils/ast/ast_redir.c | 38 +++-- src/utils/ast/ast_redir.h | 1 - src/utils/ast/ast_void.c | 5 - src/utils/ast/ast_void.h | 5 - src/utils/ast/ast_word.c | 30 ++-- src/utils/ast/ast_word.h | 5 - src/utils/lists/lists.h | 109 ++++++-------- .../lists/{lists2.c => lists_advanced.c} | 0 src/utils/lists/{lists1.c => lists_basic.c} | 0 .../lists/{lists3.c => lists_very_advanced.c} | 3 +- tests/unit/parser/parser_tests.c | 141 ++++++++++++++++++ 31 files changed, 411 insertions(+), 236 deletions(-) rename src/utils/lists/{lists2.c => lists_advanced.c} (100%) rename src/utils/lists/{lists1.c => lists_basic.c} (100%) rename src/utils/lists/{lists3.c => lists_very_advanced.c} (97%) create mode 100644 tests/unit/parser/parser_tests.c diff --git a/src/execution/execution_helpers.c b/src/execution/execution_helpers.c index e65c0d1..c0e1c04 100644 --- a/src/execution/execution_helpers.c +++ b/src/execution/execution_helpers.c @@ -15,6 +15,9 @@ static int open_redir_file(const struct ast_redir *redir, int *flags, int *mode) { + if (redir == NULL || flags == NULL || mode == NULL) + return -1; + *mode = 0644; if (redir->type == AST_REDIR_TYPE_GREAT || redir->type == AST_REDIR_TYPE_CLOBBER) @@ -41,6 +44,9 @@ static int set_all_redir(struct list *redir_list) { struct ast *redir_node = (struct ast *)redir_list->data; struct ast_redir *redir = ast_get_redir(redir_node); + if (redir == NULL) + return -1; // TODO log error and free + int target_fd; if (redir->io_number != -1) { @@ -126,13 +132,13 @@ static int exec_assignment(struct list *assignment_list, struct hash_map *vars) { while (assignment_list != NULL) { - if (!ast_is_assignment(assignment_list->data)) + struct ast_assignment *assignment = + ast_get_assignment(assignment_list->data); + if (assignment == NULL) { fprintf(stderr, "list of assignements contains something else"); return 1; } - struct ast_assignment *assignment = - ast_get_assignment(assignment_list->data); set_var_copy(vars, assignment->name, assignment->value); assignment_list = assignment_list->next; @@ -214,7 +220,7 @@ int exec_ast_list(struct ast_list *list_node, struct hash_map *vars) while (cur) { struct ast *child = (struct ast *)cur->data; - if (!ast_is_void(child)) + if (child->type != AST_VOID) ret = execution(child, vars); cur = cur->next; } @@ -244,6 +250,9 @@ void unset_all_redir(struct list *redir_list) { struct ast *redir_node = (struct ast *)redir_list->data; struct ast_redir *redir = ast_get_redir(redir_node); + if (redir == NULL) + return; // TODO log error and free + int target_fd; if (redir->io_number != -1) { diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index df103fc..1bfcfd6 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -302,7 +302,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) } // Get element type - if (ast_is_word(element)) + if (element->type == AST_WORD) { // Extract word struct ast_word *element_word = ast_get_word(element); @@ -311,7 +311,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) ast_free(&element); command_elements = list_append(command_elements, word); } - else if (ast_is_redir(element)) + else if (element->type == AST_REDIR) { // append redirections to the list of redirections redirections = list_append(redirections, element); diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index 085ae1b..0b4b920 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -1,9 +1,9 @@ lib_LIBRARIES = libutils.a libutils_a_SOURCES = \ - lists/lists1.c \ - lists/lists2.c \ - lists/lists3.c \ + lists/lists_basic.c \ + lists/lists_advanced.c \ + lists/lists_very_advanced.c \ hash_map/hash_map.c \ string_utils/string_utils.c \ ast/ast.c \ diff --git a/src/utils/ast/ast.c b/src/utils/ast/ast.c index 5d64f7d..60aecb2 100644 --- a/src/utils/ast/ast.c +++ b/src/utils/ast/ast.c @@ -11,8 +11,8 @@ void ast_free(struct ast **node) { if (node == NULL || *node == NULL) { - perror( - "WARNING: Internal error: failed to free AST node (NULL argument)"); + perror("[WARNING] Internal error: failed to free AST node (NULL " + "argument)"); return; } @@ -66,7 +66,10 @@ struct ast *ast_create(enum ast_type type, void *data) { struct ast *node = malloc(sizeof(struct ast)); if (!node) + { + perror("Error: could not allocate more memory"); return NULL; + } node->type = type; node->data = data; diff --git a/src/utils/ast/ast_and_or.c b/src/utils/ast/ast_and_or.c index 9dea5dd..06006a8 100644 --- a/src/utils/ast/ast_and_or.c +++ b/src/utils/ast/ast_and_or.c @@ -1,30 +1,33 @@ #include "ast_and_or.h" +#include #include -bool ast_is_and_or(struct ast *node) -{ - return node != NULL && node->type == AST_AND_OR; -} - struct ast_and_or *ast_get_and_or(struct ast *node) { - if (ast_is_and_or(node)) - return (struct ast_and_or *)node->data; + if (node != NULL && node->type == AST_AND_OR) + return node->data; return NULL; } struct ast *ast_create_and_or(struct ast *left, struct ast *right, enum ast_and_or_type type) { - struct ast_and_or *and_or = malloc(sizeof(struct ast_and_or)); - if (!and_or) + struct ast_and_or *and_or_node = malloc(sizeof(struct ast_and_or)); + if (and_or_node == NULL) + { + perror("Error: could not allocate more memory"); return NULL; - and_or->left = left; - and_or->right = right; - and_or->type = type; + } + and_or_node->left = left; + and_or_node->right = right; + and_or_node->type = type; - return ast_create(AST_AND_OR, and_or); + struct ast *result = ast_create(AST_AND_OR, and_or_node); + if (result == NULL) + free(and_or_node); + + return result; } void ast_free_and_or(struct ast_and_or *and_or) diff --git a/src/utils/ast/ast_and_or.h b/src/utils/ast/ast_and_or.h index 4813592..04e4d38 100644 --- a/src/utils/ast/ast_and_or.h +++ b/src/utils/ast/ast_and_or.h @@ -17,7 +17,6 @@ struct ast_and_or enum ast_and_or_type type; }; -bool ast_is_and_or(struct ast *node); struct ast_and_or *ast_get_and_or(struct ast *node); struct ast *ast_create_and_or(struct ast *left, struct ast *right, enum ast_and_or_type type); diff --git a/src/utils/ast/ast_assignment.c b/src/utils/ast/ast_assignment.c index 72cfdb6..534dbd7 100644 --- a/src/utils/ast/ast_assignment.c +++ b/src/utils/ast/ast_assignment.c @@ -2,55 +2,93 @@ #include "ast_assignment.h" +#include #include #include -bool ast_is_assignment(struct ast *node) +// === Static functions + +/* @brief: splits the assignement 'name=value' into 2 parts, + * and fills the fields of ast_assignment with it. + */ +static bool init_assignments(struct ast_assignment *ast_assignment, + char *assignment) { - return node != NULL && node->type == AST_ASSIGNMENT; + // Split + if (assignment == NULL) + return false; + char *split_pos = strchr(assignment, '='); + if (split_pos == NULL) + { + perror( + "Internal error: could not split assignment (no '=' token found)"); + return false; + } + *split_pos = '\0'; + split_pos++; // Points to the beginning of the second string + + // Allocate new strings + + ast_assignment->name = strdup(assignment); + if (ast_assignment->name == NULL) + { + perror("Error: could not duplicate string (is your memory full ?)"); + return false; + } + + ast_assignment->value = strdup(split_pos); + if (ast_assignment->name == NULL) + { + perror("Error: could not duplicate string (is your memory full ?)"); + free(ast_assignment->name); + return false; + } + + return true; } +// === Functions + struct ast_assignment *ast_get_assignment(struct ast *node) { if (node == NULL || node->type != AST_ASSIGNMENT) return NULL; - return (struct ast_assignment *)node->data; -} -/* @brief: splits the assignement 'name=value' into 2 parts, - * and fills the fields of ast_assignment with it. - */ -static void init_assignments(struct ast_assignment *ast_assignment, - char *assignment) -{ - if (assignment == NULL) - return; - char *split_pos = strchr(assignment, '='); - if (split_pos == NULL) - return; - - *split_pos = '\0'; - ast_assignment->name = strdup(assignment); - ast_assignment->value = strdup(split_pos + 1); + return node->data; } struct ast *ast_create_assignment(char *assignment, bool global) { struct ast_assignment *assignment_data = calloc(1, sizeof(struct ast_assignment)); - if (!assignment_data) + if (assignment_data == NULL) + { + perror("Error: could not allocate more memory"); return NULL; + } - init_assignments(assignment_data, assignment); assignment_data->global = global; - return ast_create(AST_ASSIGNMENT, assignment_data); + bool initialized = init_assignments(assignment_data, assignment); + if (initialized == false) + { + free(assignment_data); + return NULL; + } + + struct ast *result = ast_create(AST_ASSIGNMENT, assignment_data); + if (result == NULL) + free(assignment_data); + + return result; } void ast_free_assignment(struct ast_assignment *assignment_data) { if (assignment_data == NULL) return; - free(assignment_data->name); - free(assignment_data->value); + if (assignment_data->name != NULL) + free(assignment_data->name); + if (assignment_data->value != NULL) + free(assignment_data->value); free(assignment_data); } diff --git a/src/utils/ast/ast_assignment.h b/src/utils/ast/ast_assignment.h index 3ebac14..cad74ef 100644 --- a/src/utils/ast/ast_assignment.h +++ b/src/utils/ast/ast_assignment.h @@ -10,7 +10,6 @@ struct ast_assignment 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, bool global); void ast_free_assignment(struct ast_assignment *assignment_data); diff --git a/src/utils/ast/ast_command.c b/src/utils/ast/ast_command.c index 81dd10e..d2a13c1 100644 --- a/src/utils/ast/ast_command.c +++ b/src/utils/ast/ast_command.c @@ -1,6 +1,7 @@ #include "ast_command.h" #include +#include #include #include "../lists/lists.h" @@ -11,25 +12,27 @@ struct ast *ast_create_command(struct list *command, struct list *redirections, { struct ast_command *command_data = malloc(sizeof(struct ast_command)); if (!command_data) + { + perror("Error: could not allocate more memory"); return NULL; + } command_data->command = command; command_data->redirections = redirections; command_data->assignments = assignments; - return ast_create(AST_CMD, command_data); + struct ast *result = ast_create(AST_CMD, command_data); + if (result == NULL) + free(command_data); + + return result; } struct ast_command *ast_get_command(struct ast *node) { if (node == NULL || node->type != AST_CMD) return NULL; - return (struct ast_command *)node->data; -} - -bool ast_is_command(struct ast *node) -{ - return node != NULL && node->type == AST_CMD; + return node->data; } void ast_free_command(struct ast_command *command_data) diff --git a/src/utils/ast/ast_command.h b/src/utils/ast/ast_command.h index 7b24a2d..6926b8d 100644 --- a/src/utils/ast/ast_command.h +++ b/src/utils/ast/ast_command.h @@ -11,11 +11,6 @@ struct ast_command struct list *assignments; // A list of ASTs, all ast_assignment }; -/** - * Checks if the given AST node is a command. - */ -bool ast_is_command(struct ast *node); - /** * Retrieves the command data from the given AST node. * Assumes that the node is of type AST_CMD. diff --git a/src/utils/ast/ast_if.c b/src/utils/ast/ast_if.c index 6b0ff5d..9587bee 100644 --- a/src/utils/ast/ast_if.c +++ b/src/utils/ast/ast_if.c @@ -1,6 +1,7 @@ #include "ast_if.h" #include +#include #include struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, @@ -8,13 +9,20 @@ struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, { struct ast_if *if_data = malloc(sizeof(struct ast_if)); if (!if_data) + { + perror("Error: could not allocate more memory"); return NULL; + } if_data->condition = condition; if_data->then_clause = then_clause; if_data->else_clause = else_clause; - return ast_create(AST_IF, if_data); + struct ast *result = ast_create(AST_IF, if_data); + if (result == NULL) + free(if_data); + + return result; } struct ast_if *ast_get_if(struct ast *node) @@ -24,11 +32,6 @@ struct ast_if *ast_get_if(struct ast *node) return node->data; } -bool ast_is_if(struct ast *node) -{ - return node != NULL && node->type == AST_IF; -} - void ast_free_if(struct ast_if *if_data) { if (if_data == NULL) diff --git a/src/utils/ast/ast_if.h b/src/utils/ast/ast_if.h index f1842bd..16f80bc 100644 --- a/src/utils/ast/ast_if.h +++ b/src/utils/ast/ast_if.h @@ -10,11 +10,6 @@ struct ast_if struct ast *else_clause; }; -/** - * Checks if the given AST node is an if statement. - */ -bool ast_is_if(struct ast *node); - /** * Retrieves the if statement data from the given AST node. * Assumes that the node is of type AST_IF. diff --git a/src/utils/ast/ast_list.c b/src/utils/ast/ast_list.c index cb4aaa6..795e2c1 100644 --- a/src/utils/ast/ast_list.c +++ b/src/utils/ast/ast_list.c @@ -1,28 +1,32 @@ #include "ast_list.h" +#include + struct ast *ast_create_list(struct list *list) { struct ast_list *ast_list = malloc(sizeof(struct ast_list)); if (ast_list == NULL) + { + perror("Error: could not allocate more memory"); return NULL; + } ast_list->children = list; - return ast_create(AST_LIST, ast_list); + struct ast *result = ast_create(AST_LIST, ast_list); + if (result == NULL) + free(ast_list); + + return result; } struct ast_list *ast_get_list(struct ast *node) { - if (node == NULL) + if (node == NULL || node->type != AST_LIST) return NULL; return node->data; } -bool ast_is_list(struct ast *node) -{ - return node != NULL && node->type == AST_LIST; -} - void ast_free_list(struct ast_list *ast_list) { if (ast_list == NULL) @@ -40,7 +44,7 @@ void ast_list_deep_destroy(struct list *l) { next_elt = elt->next; - struct ast *node = (struct ast *)elt->data; + struct ast *node = elt->data; ast_free(&node); free(elt); elt = next_elt; diff --git a/src/utils/ast/ast_list.h b/src/utils/ast/ast_list.h index 21b24fb..1b26cc1 100644 --- a/src/utils/ast/ast_list.h +++ b/src/utils/ast/ast_list.h @@ -29,11 +29,6 @@ struct ast *ast_create_list(struct list *ast_list); */ struct ast_list *ast_get_list(struct ast *node); -/** - * Checks if the given AST node is a command. - */ -bool ast_is_list(struct ast *node); - /* @brief: frees the given ast list. * * @warning: should only be called by ast_free() function. diff --git a/src/utils/ast/ast_loop.c b/src/utils/ast/ast_loop.c index fded922..4bf66f9 100644 --- a/src/utils/ast/ast_loop.c +++ b/src/utils/ast/ast_loop.c @@ -1,30 +1,32 @@ #include "ast_loop.h" #include +#include #include struct ast *ast_create_loop(struct ast *condition, struct ast *body) { struct ast_loop *node_data = malloc(sizeof(struct ast_loop)); - if (!node_data) + if (node_data != NULL) + { + perror("Error: could not allocate more memory"); return NULL; + } node_data->condition = condition; node_data->body = body; - return ast_create(AST_LOOP, node_data); + struct ast *result = ast_create(AST_LOOP, node_data); + if (result == NULL) + free(node_data); + return result; } struct ast_loop *ast_get_loop(struct ast *node) { if (node == NULL || node->type != AST_LOOP) return NULL; - return (struct ast_loop *)node->data; -} - -bool ast_is_loop(struct ast *node) -{ - return node != NULL && node->type == AST_LOOP; + return node->data; } void ast_free_loop(struct ast_loop *loop_data) diff --git a/src/utils/ast/ast_loop.h b/src/utils/ast/ast_loop.h index 7c5ba6e..20a494d 100644 --- a/src/utils/ast/ast_loop.h +++ b/src/utils/ast/ast_loop.h @@ -10,11 +10,6 @@ struct ast_loop struct ast *body; }; -/** - * Checks if the given AST node is a loop. - */ -bool ast_is_loop(struct ast *node); - /** * Retrieves the loop data from the given AST node. * Assumes that the node is of type AST_LOOP. @@ -27,7 +22,7 @@ struct ast_loop *ast_get_loop(struct ast *node); struct ast *ast_create_loop(struct ast* condition, struct ast* body); /* - * @brief: frees the given ast_loop and sets the pointer to NULL. + * @brief frees the given ast_loop and sets the pointer to NULL. */ void ast_free_loop(struct ast_loop *loop_node); diff --git a/src/utils/ast/ast_neg.c b/src/utils/ast/ast_neg.c index 80dc4f3..7ebcfdc 100644 --- a/src/utils/ast/ast_neg.c +++ b/src/utils/ast/ast_neg.c @@ -1,34 +1,38 @@ #include "ast_neg.h" +#include #include -bool ast_is_neg(struct ast *node) -{ - return node != NULL && node->type == AST_NEG; -} - struct ast_neg *ast_get_neg(struct ast *node) { - if (ast_is_neg(node)) - return node->data; - return NULL; + if (node == NULL || node->type != AST_NEG) + return NULL; + return node->data; } struct ast *ast_create_neg(bool negation, struct ast *child) { - struct ast_neg *node = malloc(sizeof(struct ast_neg)); - if (!node) + struct ast_neg *neg_data = malloc(sizeof(struct ast_neg)); + if (neg_data == NULL) + { + perror("Error: could not allocate more memory"); return NULL; + } - node->negation = negation; - node->child = child; - return ast_create(AST_NEG, node); + neg_data->negation = negation; + neg_data->child = child; + struct ast *result = ast_create(AST_NEG, neg_data); + if (result == NULL) + free(neg_data); + + return result; } void ast_free_neg(struct ast_neg *node) { - if (!node) + if (node == NULL) return; + ast_free(&node->child); free(node); } diff --git a/src/utils/ast/ast_neg.h b/src/utils/ast/ast_neg.h index 738c246..6a0e56a 100644 --- a/src/utils/ast/ast_neg.h +++ b/src/utils/ast/ast_neg.h @@ -9,7 +9,6 @@ struct ast_neg struct ast *child; }; -bool ast_is_neg(struct ast *node); struct ast_neg *ast_get_neg(struct ast *node); struct ast *ast_create_neg(bool negation, struct ast *child); void ast_free_neg(struct ast_neg *node); diff --git a/src/utils/ast/ast_pipe.c b/src/utils/ast/ast_pipe.c index 92754cf..5cc293e 100644 --- a/src/utils/ast/ast_pipe.c +++ b/src/utils/ast/ast_pipe.c @@ -1,34 +1,39 @@ #include "ast_pipe.h" +#include #include -bool ast_is_pipe(struct ast *node) -{ - return node != NULL && node->type == AST_REDIR; -} - struct ast_pipe *ast_get_pipe(struct ast *node) { - if (ast_is_pipe(node)) - return node->data; - return NULL; + if (node == NULL || node->type != AST_REDIR) + return NULL; + return node->data; } struct ast *ast_create_pipe(struct ast *left, struct ast *right) { - struct ast_pipe *node = malloc(sizeof(struct ast_pipe)); - if (!node) + struct ast_pipe *ast_pipe = malloc(sizeof(struct ast_pipe)); + if (ast_pipe != NULL) + { + perror("Error: could not allocate more memory"); return NULL; - node->left = left; - node->right = right; + } - return ast_create(AST_PIPE, node); + ast_pipe->left = left; + ast_pipe->right = right; + + struct ast *result = ast_create(AST_PIPE, ast_pipe); + if (result == NULL) + free(ast_pipe); + + return result; } void ast_free_pipe(struct ast_pipe *node) { - if (!node) + if (node == NULL) return; + ast_free(&node->left); ast_free(&node->right); free(node); diff --git a/src/utils/ast/ast_pipe.h b/src/utils/ast/ast_pipe.h index 930cb2c..6fb1b32 100644 --- a/src/utils/ast/ast_pipe.h +++ b/src/utils/ast/ast_pipe.h @@ -10,7 +10,6 @@ struct ast_pipe // Output of left will be redirected to right stdin }; -bool ast_is_pipe(struct ast *node); struct ast_pipe *ast_get_pipe(struct ast *node); struct ast *ast_create_pipe(struct ast *left, struct ast *right); void ast_free_pipe(struct ast_pipe *node); diff --git a/src/utils/ast/ast_redir.c b/src/utils/ast/ast_redir.c index d1dcedb..bd01f9c 100644 --- a/src/utils/ast/ast_redir.c +++ b/src/utils/ast/ast_redir.c @@ -1,38 +1,44 @@ #include "ast_redir.h" +#include #include -bool ast_is_redir(struct ast *node) -{ - return node != NULL && node->type == AST_REDIR; -} - struct ast_redir *ast_get_redir(struct ast *node) { - if (ast_is_redir(node)) - return (struct ast_redir *)node->data; - return NULL; + if (node == NULL || node->type != AST_REDIR) + return NULL; + return node->data; } struct ast *ast_create_redir(char *filename, int io_number, enum ast_redir_type type) { - struct ast_redir *redir = malloc(sizeof(struct ast_redir)); - if (!redir) + struct ast_redir *redir_node = malloc(sizeof(struct ast_redir)); + if (redir_node == NULL) + { + perror("Error: could not allocate more memory"); return NULL; - redir->filename = + } + + redir_node->filename = filename; // Takes ownership? Usually yes in simple ASTs, or dup. Let's // assume pointer copy for now, but user must manage memory. - redir->io_number = io_number; - redir->type = type; + redir_node->io_number = io_number; + redir_node->type = type; - return ast_create(AST_REDIR, redir); + struct ast *result = ast_create(AST_REDIR, redir_node); + if (result == NULL) + free(redir_node); + + return result; } void ast_free_redir(struct ast_redir *redir) { - if (!redir) + if (redir == NULL) return; - free(redir->filename); + + if (redir->filename != NULL) + free(redir->filename); free(redir); } diff --git a/src/utils/ast/ast_redir.h b/src/utils/ast/ast_redir.h index 9d9a9d3..034311d 100644 --- a/src/utils/ast/ast_redir.h +++ b/src/utils/ast/ast_redir.h @@ -24,7 +24,6 @@ struct ast_redir int saved_fd; // To store the original FD for restoration (-1 before save) }; -bool ast_is_redir(struct ast *node); struct ast_redir *ast_get_redir(struct ast *node); struct ast *ast_create_redir(char *filename, int io_number, enum ast_redir_type type); diff --git a/src/utils/ast/ast_void.c b/src/utils/ast/ast_void.c index e7d2dee..20c9b68 100644 --- a/src/utils/ast/ast_void.c +++ b/src/utils/ast/ast_void.c @@ -3,11 +3,6 @@ #include #include -bool ast_is_void(struct ast *node) -{ - return node != NULL && node->type == AST_VOID; -} - struct ast *ast_create_void(void) { return ast_create(AST_VOID, NULL); diff --git a/src/utils/ast/ast_void.h b/src/utils/ast/ast_void.h index 05a5933..678e180 100644 --- a/src/utils/ast/ast_void.h +++ b/src/utils/ast/ast_void.h @@ -4,11 +4,6 @@ #include "../lists/lists.h" #include "ast_base.h" -/** - * Checks if the given AST node is of type AST_VOID. - */ -bool ast_is_void(struct ast *node); - /** * Creates a new AST node representing NOTHING * WARNING: data will be a NULL pointer diff --git a/src/utils/ast/ast_word.c b/src/utils/ast/ast_word.c index d83489c..ffb934f 100644 --- a/src/utils/ast/ast_word.c +++ b/src/utils/ast/ast_word.c @@ -2,22 +2,33 @@ #include "ast_word.h" #include +#include #include #include struct ast *ast_create_word(char *word) { - struct ast_word *ast_node = malloc(sizeof(struct ast_word)); - if (ast_node == NULL) + struct ast_word *word_node = malloc(sizeof(struct ast_word)); + if (word_node == NULL) + { + perror("Error: could not allocate more memory"); return NULL; + } - ast_node->type = AST_WORD; - ast_node->word = strdup(word); - struct ast *res = ast_create(AST_WORD, ast_node); + word_node->type = AST_WORD; + word_node->word = strdup(word); + if (word_node->word == NULL) + { + perror("Error: could not duplicate string (is your memory full ?)"); + free(word_node); + return NULL; + } + + struct ast *res = ast_create(AST_WORD, word_node); if (res == NULL) { - free(ast_node->word); - free(ast_node); + free(word_node->word); + free(word_node); return NULL; } @@ -32,11 +43,6 @@ struct ast_word *ast_get_word(struct ast *node) return node->data; } -bool ast_is_word(struct ast *node) -{ - return node && node->type == AST_WORD; -} - void ast_free_word(struct ast_word *ast_node) { if (ast_node == NULL) diff --git a/src/utils/ast/ast_word.h b/src/utils/ast/ast_word.h index a049003..f40f81c 100644 --- a/src/utils/ast/ast_word.h +++ b/src/utils/ast/ast_word.h @@ -9,11 +9,6 @@ struct ast_word char *word; }; -/** - * Checks if the given AST node is a command. - */ -bool ast_is_word(struct ast *node); - /** * Retrieves the command data from the given AST node. * Assumes that the node is of type AST_CMD. diff --git a/src/utils/lists/lists.h b/src/utils/lists/lists.h index 9f8cebb..3afadbb 100644 --- a/src/utils/lists/lists.h +++ b/src/utils/lists/lists.h @@ -10,106 +10,93 @@ struct list }; /* -** @brief Insert a node containing `value` at the beginning of the list. -** @return `NULL` if an error occured. -*/ + * @brief Insert a node containing `value` at the beginning of the list. + * @return `NULL` if an error occured. + */ struct list *list_prepend(struct list *list, void *value); /* -** Return the lenght of the list. -** Return `0` if the list is empty. -*/ + * @return the length of the list or 0 if the list is empty. + */ size_t list_length(struct list *list); /* -** Display the list contents on `stdout`. -** Nothing is displayed if the list is empty. -*/ + * @brief Display the list contents on `stdout`. + * Nothing is displayed if the list is empty. + */ void list_print(struct list *list); /* -** Release the memory used by the list. -** Does nothing if `list` is `NULL`. -*/ + * @brief Releases the memory used by the list. + * Does nothing if `list` is `NULL`. + */ void list_destroy(struct list **list); /* -** Release the memory used by the list and its content -** Does nothing if `list` is `NULL`. -*/ + * @brief Releases the memory used by the list and its content + * Does nothing if `list` is `NULL`. + */ void list_deep_destroy(struct list *l); /* -** Append a node containing `value` at the end of the list. -** Return `NULL` if an error occured. -*/ -// START PROTO list_append + * @brief Append a node containing `value` at the end of the list. + * @return The head of the list or `NULL` if an error occured. + */ struct list *list_append(struct list *list, void *value); -// END PROTO list_append /* -** Insert a node containing `value` at the index `index` in the list. -** If the index is greater than the length of the list, the behaviour is the -** same as `list_append`. -** Return `NULL` if an error occured. -*/ -// START PROTO list_insert + * @brief Insert a node containing `value` at the index `index` in the list. + * If the index is greater than the length of the list, the behaviour is the + * same as `list_append`. + * @return The head of the list or `NULL` if an error occured. + */ struct list *list_insert(struct list *list, void *value, size_t index); -// END PROTO list_insert /* -** Remove the element at the index `index`. -** Return `NULL` if an error occured. -*/ -// START PROTO list_remove + * @brief Remove the element at the index `index`. + * @return The head of the list or `NULL` if an error occured. + */ struct list *list_remove(struct list *list, size_t index); -// END PROTO list_remove /* -** Return the position of the first node containing `value`. -** Return `-1` if nothing is found. -*/ -// START PROTO list_find + * @return the position of the first node containing `value` + * or `-1` if nothing is found. + */ int list_find(struct list *list, void *value); -// END PROTO list_find + +// NOTE the following functions are commented because no other module +// needs them. Feel free to decomment one if you need but keep in +// mind the max function exports. /* -** Concatenate the list `list2` at the end of the list `list`. -** Return `list2` if `list` is `NULL`. -*/ -// START PROTO list_concat + * Concatenate the list `list2` at the end of the list `list`. + * Return `list2` if `list` is `NULL`. + */ // struct list *list_concat(struct list *list, struct list *list2); -// END PROTO list_concat /* -** Sort the elements of the list in ascending order. -** Return the new list. -*/ -// START PROTO list_sort + * Sort the elements of the list in ascending order. + * Return the new list. + */ // struct list *list_sort(struct list *list); -// END PROTO list_sort /* -** Invert the order of the elements of the list. -** Return the new list. -*/ -// START PROTO list_reverse + * Invert the order of the elements of the list. + * Return the new list. + */ // struct list *list_reverse(struct list *list); -// END PROTO list_reverse /* -** Split the list at index `index`. -** First part goes in `list` and contains the element at `index`. -** Second part is returned. -** Return `NULL` if `list` is `NULL` or `index` is invalid. -*/ -// START PROTO list_split + * Split the list at index `index`. + * First part goes in `list` and contains the element at `index`. + * Second part is returned. + * Return `NULL` if `list` is `NULL` or `index` is invalid. + */ // struct list *list_split(struct list *list, size_t index); -// END PROTO list_split -/** +/* * @brief: Folds the list from left to right using func and an accumulator. */ void list_fold(struct list *list, void *acc, void (*func)(void *, void *)); -#endif /* ! LISTS_H */ +#endif /* ! LISTS_H */ diff --git a/src/utils/lists/lists2.c b/src/utils/lists/lists_advanced.c similarity index 100% rename from src/utils/lists/lists2.c rename to src/utils/lists/lists_advanced.c diff --git a/src/utils/lists/lists1.c b/src/utils/lists/lists_basic.c similarity index 100% rename from src/utils/lists/lists1.c rename to src/utils/lists/lists_basic.c diff --git a/src/utils/lists/lists3.c b/src/utils/lists/lists_very_advanced.c similarity index 97% rename from src/utils/lists/lists3.c rename to src/utils/lists/lists_very_advanced.c index c18c7be..ede0e86 100644 --- a/src/utils/lists/lists3.c +++ b/src/utils/lists/lists_very_advanced.c @@ -110,7 +110,8 @@ void list_deep_destroy(struct list *l) while (elt != NULL) { next_elt = elt->next; - free(elt->data); + if (elt->data != NULL) + free(elt->data); free(elt); elt = next_elt; } diff --git a/tests/unit/parser/parser_tests.c b/tests/unit/parser/parser_tests.c new file mode 100644 index 0000000..c8ac087 --- /dev/null +++ b/tests/unit/parser/parser_tests.c @@ -0,0 +1,141 @@ +#include +#include +#include + +#include "io_backend/io_backend.h" +#include "lexer/lexer.h" +#include "parser/parser.h" +#include "utils/ast/ast.h" +#include "utils/ast/ast_command.h" + +TestSuite(parser); + +static void init_lexer_ctx(struct lexer_context *ctx) +{ + ctx->end_previous_token = NULL; + ctx->remaining_chars = 0; + ctx->only_digits = false; + ctx->previous_token = NULL; + ctx->current_token = NULL; +} + +Test(parser, init_success) +{ + int res = parser_init(); + cr_assert(res == true, "parser_init should return true on success"); + parser_close(); +} + +Test(parser, init_twice) +{ + parser_init(); + int res = parser_init(); + cr_assert(res == false, + "parser_init should return false when called twice"); + parser_close(); +} + +Test(parser, close_without_init) +{ + parser_close(); +} + +Test(parser, close_already_closed) +{ + parser_init(); + parser_close(); + parser_close(); +} + +Test(parser, get_ast_not_init) +{ + struct lexer_context ctx; + init_lexer_ctx(&ctx); + + struct ast *ast = get_ast(&ctx); + cr_assert_null(ast, + "get_ast should return NULL when parser is not initialized"); +} + +Test(parser, get_ast_closed) +{ + parser_init(); + parser_close(); + + struct lexer_context ctx; + init_lexer_ctx(&ctx); + + struct ast *ast = get_ast(&ctx); + cr_assert_null(ast, "get_ast should return NULL when parser is closed"); +} + +Test(parser, get_ast_null_ctx) +{ + parser_init(); + struct ast *ast = get_ast(NULL); + cr_assert_null(ast, "get_ast should return NULL when ctx is NULL"); + parser_close(); +} + +Test(parser, get_ast_simple_cmd) +{ + char command[] = "echo hello"; + struct iob_context iob_ctx = { IOB_MODE_CMD, command }; + iob_init(&iob_ctx); + + struct lexer_context ctx; + init_lexer_ctx(&ctx); + + parser_init(); + + struct ast *ast = get_ast(&ctx); + + cr_assert_not_null(ast, + "get_ast should return a valid AST for simple command"); + cr_assert(ast_is_command(ast), "AST root should be a command"); + + ast_free(&ast); + parser_close(); + iob_close(); +} + +Test(parser, get_ast_eof) +{ + char command[] = ""; + struct iob_context iob_ctx = { IOB_MODE_CMD, command }; + iob_init(&iob_ctx); + + struct lexer_context ctx; + init_lexer_ctx(&ctx); + + parser_init(); + + struct ast *ast = get_ast(&ctx); + + cr_assert_not_null(ast, + "get_ast should return AST_END node on empty input"); + cr_assert_eq(ast->type, AST_END, "AST type should be AST_END"); + + ast_free(&ast); + parser_close(); + iob_close(); +} + +Test(parser, get_ast_syntax_error) +{ + char command[] = "if true; then"; // Missing fi + struct iob_context iob_ctx = { IOB_MODE_CMD, command }; + iob_init(&iob_ctx); + + struct lexer_context ctx; + init_lexer_ctx(&ctx); + + parser_init(); + + struct ast *ast = get_ast(&ctx); + + cr_assert_null(ast, "get_ast should return NULL on syntax error"); + + parser_close(); + iob_close(); +}