From 4c237c53d023e0db149375fb0a68f88acf6b5935 Mon Sep 17 00:00:00 2001 From: Jean Herail Date: Sat, 10 Jan 2026 17:15:16 +0100 Subject: [PATCH] feat(execution): Basic AST execution, with forks and all --- src/execution/execution.c | 135 ++++++++++++++++++++++++++++++++++++++ src/execution/execution.h | 11 ++++ 2 files changed, 146 insertions(+) diff --git a/src/execution/execution.c b/src/execution/execution.c index e69de29..3f6b1a3 100644 --- a/src/execution/execution.c +++ b/src/execution/execution.c @@ -0,0 +1,135 @@ +#include "execution.h" + +#include +#include +#include +#include +#include + +#include "../utils/ast/ast.h" + +/** + * @brief converts a linked list of command arguments to an argv array. Don't + * forget to free the result + * + * @param cmd_list Linked list of command arguments + * @return char** Array of command arguments suitable for execvp. Terminated by + * NULL + */ +static char **list_to_argv(struct list *cmd_list) +{ + size_t len = 0; + struct list *cur = cmd_list; + + while (cur) + { + len++; + cur = cur->next; + } + + char **argv = calloc(len + 1, sizeof(char *)); + if (!argv) + { + return NULL; + } + cur = cmd_list; + + for (size_t i = 0; i < len; i++) + { + argv[i] = (char *)cur->data; + cur = cur->next; + } + + argv[len] = NULL; + return argv; +} + +/** + * @brief Executes a command represented by an ast_cmd structure + * + * @param cmd The command to execute + * @return int The exit status of the command + */ +static int exec_command(struct ast_cmd *cmd) +{ + if (!cmd || !(cmd->cmd)) + { + return -1; + } + + char **argv = list_to_argv(cmd->cmd); + + if (!argv || !(argv[0])) + { + free(argv); + return -1; + } + + pid_t pid = fork(); + + if (pid < 0) // Fork failed + { + perror("fork"); + free(argv); + return -1; + } + + if (pid == 0) // If child process + { + execvp(argv[0], argv); + perror("execvp"); // If execvp returns, there was an error + exit(EXIT_FAILURE); // Exit child process + } + + int status = 0; + waitpid(pid, &status, 0); + free(argv); + + if (WIFEXITED(status)) + { + return WEXITSTATUS(status); + } + + return -1; // Should not happen +} + +/** + * @brief Executes the AST returned by the parser + * + * @param ast The AST to execute + * @return int The exit status of the last executed command. + */ +int execution(struct ast *ast) +{ + if (!ast) + { + return 0; + } + + switch (ast->type) + { + case AST_END: { + return 0; + } + case AST_CMD: { + struct ast_cmd *cmd = ast->data->ast_cmd; // Cast implicit + return exec_command(cmd); // It's recursive + } + case AST_IF: { + struct ast_if *if_node = + ast->data->ast_if; // We cast the union to ast_if + int cond = execution(if_node->condition); + if (cond == 0) // True + { + return execution(if_node->then_clause); + } + else // False + { + return execution(if_node->else_clause); + } + } + default: { + return -1; // Should not happen + } + } +} diff --git a/src/execution/execution.h b/src/execution/execution.h index e773de0..aacacc3 100644 --- a/src/execution/execution.h +++ b/src/execution/execution.h @@ -1,4 +1,15 @@ #ifndef EXECUTION_H #define EXECUTION_H +#include "../utils/ast/ast.h" +#include "../utils/lists/lists.h" + +/** + * @brief Execute the AST + * + * @param ast Pointer to the AST structure + * @return int Execution status code of the last command + */ +int execution(struct ast *ast); + #endif /* ! EXECUTION_H */