summaryrefslogtreecommitdiff
path: root/42sh/src/ast/ast.c
blob: 41b7a557e6111ad991fe43787d13b2dfdfecd086 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "ast/ast.h"

#include <stdio.h>
#include <stdlib.h>

#include "ast/ast_accessors.h"

static const size_t ast_size_ltable[] = {
    [AST_COMMAND] = sizeof(struct ast_command),
    [AST_IF] = sizeof(struct ast_if),
    [AST_LOGICAL] = sizeof(struct ast_logical),
    [AST_LIST] = sizeof(struct ast_list),
    [AST_REDIRECTION] = sizeof(struct ast_redirection),
    [AST_PIPELINE] = sizeof(struct ast_pipeline),
    [AST_WHILE] = sizeof(struct ast_while),
    [AST_ASSIGN] = sizeof(struct ast_assign),
    [AST_FOR] = sizeof(struct ast_for),
    [AST_FUNCTION] = sizeof(struct ast_function),
    [AST_SUBSHELL] = sizeof(struct ast_subshell)
};

struct ast *ast_create(enum ast_node type)
{
    struct ast *a = calloc(1, ast_size_ltable[type]);
    if (!a)
    {
        fprintf(stderr, "ast_create: calloc failed.\n");
        return NULL;
    }

    a->type = type;
    return a;
}

static void free_str_args(struct string **args)
{
    if (!args)
    {
        return;
    }
    size_t i = 0;
    while (args[i])
    {
        string_free(args[i]);
        i++;
    }
    free(args);
}

static void _free_ast_command(struct ast *ast)
{
    free_str_args(((struct ast_command *)ast)->args);
    free(ast);
}

static void _free_ast_if(struct ast *ast)
{
    ast_free(get_i(ast, 0));
    ast_free(get_i(ast, 1));
    ast_free(get_i(ast, 2));
    free(ast);
}

static void _free_ast_list(struct ast *ast)
{
    for (size_t i = 0; i < ((struct ast_list *)ast)->nb_children; i++)
    {
        ast_free(get_i(ast, i));
    }
    free(((struct ast_list *)ast)->children);
    free(ast);
}

static void _free_ast_logical(struct ast *ast)
{
    ast_free(((struct ast_logical *)ast)->left);
    ast_free(((struct ast_logical *)ast)->right);
    free(ast);
}

static void _free_ast_pipeline(struct ast *ast)
{
    ast_free(((struct ast_pipeline *)ast)->left);
    ast_free(((struct ast_pipeline *)ast)->right);
    free(ast);
}

static void _free_redir_struct(struct ast *ast)
{
    struct ast_redirection *ast_r = ((struct ast_redirection *)ast);
    string_free(ast_r->redirect.fd);
    string_free(ast_r->redirect.file);
    string_free(ast_r->redirect.redir);
}

static void _free_ast_redirection(struct ast *ast)
{
    ast_free(((struct ast_redirection *)ast)->expr);
    _free_redir_struct(ast);
    free(ast);
}

static void _free_ast_while(struct ast *ast)
{
    ast_free(((struct ast_while *)ast)->cond);
    ast_free(((struct ast_while *)ast)->body);
    free(ast);
}

static void _free_ast_assign(struct ast *ast)
{
    string_free(((struct ast_assign *)ast)->name);
    string_free(((struct ast_assign *)ast)->val);
    free(ast);
}

static void _free_ast_for(struct ast *ast)
{
    struct ast_for *ast_f = ((struct ast_for *)ast);
    ast_free(ast_f->left);
    ast_free(ast_f->right);
    string_free(ast_f->var);
    // Someone probably forgot to free the ast itself
    free(ast);
}

static void _free_ast_function(struct ast *ast)
{
    struct ast_function *ast_fun = ((struct ast_function *)ast);
    ast_free(ast_fun->body);
    string_free(ast_fun->name);
    free(ast);
}

static void _free_ast_subshell(struct ast *ast)
{
    ast_free(((struct ast_subshell *)ast)->body);
    free(ast);
}

typedef void (*free_fct)(struct ast *);

static const free_fct free_function_ltable[] = {
    [AST_COMMAND] = _free_ast_command,
    [AST_IF] = _free_ast_if,
    [AST_LOGICAL] = _free_ast_logical,
    [AST_LIST] = _free_ast_list,
    [AST_PIPELINE] = _free_ast_pipeline,
    [AST_REDIRECTION] = _free_ast_redirection,
    [AST_WHILE] = _free_ast_while,
    [AST_ASSIGN] = _free_ast_assign,
    [AST_FOR] = _free_ast_for,
    [AST_FUNCTION] = _free_ast_function,
    [AST_SUBSHELL] = _free_ast_subshell
};

void ast_free(struct ast *ast)
{
    if (!ast)
    {
        return;
    }
    free_function_ltable[ast->type](ast);
}