#ifndef AST_H #define AST_H #include #include "ast/ast_redirect.h" #include "lexer/token.h" #include "utils/libstring.h" /** * @brief Each node type represent a class of elements from the SCL grammar. */ enum ast_node { // STEP 1 AST_COMMAND, AST_IF, AST_LOGICAL, AST_LIST, // STEP 2 AST_PIPELINE, AST_REDIRECTION, AST_WHILE, AST_ASSIGN, AST_FOR, // STEP 3 AST_FUNCTION, AST_SUBSHELL }; /** * @brief Base struct for the AST implementation. */ struct ast { enum ast_node type; /**< Type of the targeted AST. Used for inheritance. */ }; /** * @brief AST which represent any kind of `command`. * It can be a `shell command` or a `simple command`. * Both are evaluated the same. */ struct ast_command { struct ast base; /**< Base struct for the AST implementation. */ struct string **args; /**< `args` used to call the given command. */ }; /** * @brief AST which represent a `if/then/elif/else` block. * An `if` statement may not contain an `elif` or an `else` block. * If the `if` statement contains an `elif` block, it is stored as an * `ast_if` in the `else_body`. */ struct ast_if { struct ast base; /**< Base struct for the AST implementation. */ struct ast *condition; /**< Contains the AST to evaluate as a condition. */ struct ast *then_body; /**< Contains the AST of the `then` block. */ struct ast *else_body; /**< Contains the AST of the `else` block. */ }; /** * @brief AST which represent a shell list. * A list can be either a `list` or a `compound list`. * @note Although this struct contains a `nb_children` value, * it is parsed as a binary tree, thus `nb_children` never exceeds 2. */ struct ast_list { struct ast base; /**< Base struct for the AST implementation. */ size_t nb_children; /**< Number of elements in the list */ struct ast ** children; /** Array of ASTs which represents the elements of the list */ }; /** * @brief AST which represents any logical block. * A logical block can be either a `not` block, a `and` block or a `or` block. * The type of the logical block is determined by the `type` value. * The `type` value can be either `TOKEN_AND`, `TOKEN_OR` or `TOKEN_NEG`. * The binary logical operators are evaluated following the lazy method. * @note If the `type` value is not one of the listed above, the evaluation * of the tree will always exit this the code 1 and write to `stderr`. */ struct ast_logical { struct ast base; /**< Base struct for the AST implementation. */ enum token_type type; /**< Type of the logical operator. */ struct ast *left; /**< First block to be evaluated (always evaluated). */ struct ast *right; /**< Second block to be evaluated (may not be evaluated, see `note`). */ }; /** * @brief AST which represents a pipeline. * The pipeline evaluation creates a context in which the output of * `left` is redirected to the input of `right`. */ struct ast_pipeline { struct ast base; /**< Base struct for the AST implementation. */ struct ast *left; /**< The output of this AST is given to `right`. */ struct ast *right; /**< This AST gets its input from `left`. */ }; /** * @brief AST used to represent redirections * Redirect is a struct used to store info about this redirection * Expr is the expression who the output shall be redirected */ struct ast_redirection { struct ast base; /**< Base struct for the AST implementation. */ struct redirect redirect; struct ast *expr; }; /** * @brief AST used to represent the while loops (and also the until loops) * Cond is the condition used to know if the loop shall still iterate * Body is the tree to execute while the condition is still valid */ struct ast_while { struct ast base; struct ast *cond; struct ast *body; }; /** * @brief Struct used for variable assignment * Name is the name of the variable * Val is the value of said variable */ struct ast_assign { struct ast base; struct string *name; struct string *val; }; /** * @brief Left contains the args (the `in { WORD }` part). * Right contains the body to execute. */ struct ast_for { struct ast base; struct ast *left; struct ast *right; struct string *var; }; /** * @brief AST used for function definition. * Name contains the name of the function * Body contains the actual ast that will be executed each time * the function is called */ struct ast_function { struct ast base; struct string *name; struct ast *body; }; /** * @brief AST used for subshell * Body just contains the compound list to be executed in the subshell */ struct ast_subshell { struct ast base; struct ast *body; }; union ast_caster { struct ast *ast; struct ast_command *ast_c; struct ast_if *ast_i; struct ast_list *ast_l; struct ast_logical *ast_lo; struct ast_pipeline *ast_p; struct ast_redirection *ast_r; struct ast_while *ast_w; struct ast_assign *ast_a; struct ast_for *ast_f; struct ast_function *ast_func; struct ast_subshell *ast_sub; }; /** * @brief Creates a heap-allocated AST of the size of ast_`type`. * The AST is returned as a `struct ast*` but it can be casted into the right * ast type struct. * @param type The type of the AST to be created. */ struct ast *ast_create(enum ast_node type); /** * @brief Recursively frees the given AST. Any heap-allocated can be passed. * @param ast The AST to be freed. * @note This method does not exit when `ast` is `NULL`. */ void ast_free(struct ast *ast); /** * @brief Creates a file named `ast.dot` in the current folder which * contains the DOT representation of the given AST. * @param ast The AST to represent. * @note This function is called only when the program is called with * the `--pretty-print` flag. */ void pretty_print(struct ast *ast); #endif /* ! AST_H */