c++: ir_block::m_entries
[xonotic/gmqcc.git] / ast.cpp
1 #include <new>
2
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "gmqcc.h"
7 #include "ast.h"
8 #include "fold.h"
9 //#include "parser.h"
10
11 #include "algo.h"
12
13 /* Initialize main ast node aprts */
14 ast_node::ast_node(lex_ctx_t ctx, int node_type)
15     : m_context(ctx)
16     , m_node_type(node_type)
17     , m_keep_node(false)
18     , m_side_effects(false)
19 {
20 }
21
22 ast_node::~ast_node()
23 {
24 }
25
26 /* weight and side effects */
27 void ast_node::propagateSideEffects(const ast_node *other)
28 {
29     if (other->m_side_effects)
30         m_side_effects = true;
31 }
32
33 /* General expression initialization */
34 ast_expression::ast_expression(lex_ctx_t ctx, int nodetype, qc_type type)
35     : ast_node(ctx, nodetype)
36     , m_vtype(type)
37 {
38     if (OPTS_OPTION_BOOL(OPTION_COVERAGE))
39         m_flags |= AST_FLAG_BLOCK_COVERAGE;
40 }
41 ast_expression::ast_expression(lex_ctx_t ctx, int nodetype)
42     : ast_expression(ctx, nodetype, TYPE_VOID)
43 {}
44
45 ast_expression::~ast_expression()
46 {
47     if (m_next)
48         delete m_next;
49     if (m_varparam)
50         delete m_varparam;
51 }
52
53 ast_expression::ast_expression(ast_copy_type_t, const ast_expression &other)
54     : ast_expression(ast_copy_type, other.m_context, other)
55 {}
56
57 ast_expression::ast_expression(ast_copy_type_t, lex_ctx_t ctx, const ast_expression &other)
58     : ast_expression(ast_copy_type, TYPE_ast_expression, ctx, other)
59 {}
60
61 ast_expression::ast_expression(ast_copy_type_t, int nodetype, const ast_expression &other)
62     : ast_expression(ast_copy_type, nodetype, other.m_context, other)
63 {}
64
65 ast_expression::ast_expression(ast_copy_type_t, int nodetype, lex_ctx_t ctx, const ast_expression &other)
66     : ast_expression(ctx, nodetype)
67 {
68     m_vtype = other.m_vtype;
69     m_count = other.m_count;
70     m_flags = other.m_flags;
71     if (other.m_next)
72         m_next = new ast_expression(ast_copy_type, *other.m_next);
73     m_type_params.reserve(other.m_type_params.size());
74     for (auto &it : other.m_type_params)
75         m_type_params.emplace_back(new ast_value(ast_copy_type, *it));
76 }
77
78
79 ast_expression *ast_expression::shallowType(lex_ctx_t ctx, qc_type vtype) {
80     auto expr = new ast_expression(ctx, TYPE_ast_expression);
81     expr->m_vtype = vtype;
82     return expr;
83 }
84
85 void ast_expression::adoptType(const ast_expression &other)
86 {
87     m_vtype = other.m_vtype;
88     if (other.m_next)
89         m_next = new ast_expression(ast_copy_type, *other.m_next);
90     m_count = other.m_count;
91     m_flags = other.m_flags;
92     m_type_params.clear();
93     m_type_params.reserve(other.m_type_params.size());
94     for (auto &it : other.m_type_params)
95         m_type_params.emplace_back(new ast_value(ast_copy_type, *it));
96 }
97
98 bool ast_expression::compareType(const ast_expression &other) const
99 {
100     if (m_vtype == TYPE_NIL ||
101         other.m_vtype == TYPE_NIL)
102         return true;
103     if (m_vtype != other.m_vtype)
104         return false;
105     if (!m_next != !other.m_next)
106         return false;
107     if (m_type_params.size() != other.m_type_params.size())
108         return false;
109     if ((m_flags & AST_FLAG_TYPE_MASK) !=
110         (other.m_flags & AST_FLAG_TYPE_MASK) )
111     {
112         return false;
113     }
114     if (m_type_params.size()) {
115         size_t i;
116         for (i = 0; i < m_type_params.size(); ++i) {
117             if (!m_type_params[i]->compareType(*other.m_type_params[i]))
118                 return false;
119         }
120     }
121     if (m_next)
122         return m_next->compareType(*other.m_next);
123     return true;
124 }
125
126 bool ast_expression::codegen(ast_function*, bool, ir_value**) {
127     compile_error(m_context, "ast_expression::codegen called!");
128     abort();
129     return false;
130 }
131
132 ast_value::ast_value(ast_copy_type_t, const ast_value &other, const std::string &name)
133     : ast_value(ast_copy_type, static_cast<const ast_expression&>(other), name)
134 {
135     m_keep_node = true; // keep values, always
136     memset(&m_constval, 0, sizeof(m_constval));
137 }
138
139 ast_value::ast_value(ast_copy_type_t, const ast_value &other)
140     : ast_value(ast_copy_type, static_cast<const ast_expression&>(other), other.m_name)
141 {
142     m_keep_node = true; // keep values, always
143     memset(&m_constval, 0, sizeof(m_constval));
144 }
145
146 ast_value::ast_value(ast_copy_type_t, const ast_expression &other, const std::string &name)
147     : ast_expression(ast_copy_type, TYPE_ast_value, other)
148     , m_name(name)
149 {
150     m_keep_node = true; // keep values, always
151     memset(&m_constval, 0, sizeof(m_constval));
152 }
153
154 ast_value::ast_value(lex_ctx_t ctx, const std::string &name, qc_type t)
155     : ast_expression(ctx, TYPE_ast_value, t)
156     , m_name(name)
157 {
158     m_keep_node = true; // keep values, always
159     memset(&m_constval, 0, sizeof(m_constval));
160 }
161
162 ast_value::~ast_value()
163 {
164     if (m_argcounter)
165         mem_d((void*)m_argcounter);
166     if (m_hasvalue) {
167         switch (m_vtype)
168         {
169         case TYPE_STRING:
170             mem_d((void*)m_constval.vstring);
171             break;
172         case TYPE_FUNCTION:
173             // unlink us from the function node
174             m_constval.vfunc->m_function_type = nullptr;
175             break;
176         // NOTE: delete function? currently collected in
177         // the parser structure
178         default:
179             break;
180         }
181     }
182
183     // initlist imples an array which implies .next in the expression exists.
184     if (m_initlist.size() && m_next->m_vtype == TYPE_STRING) {
185         for (auto &it : m_initlist)
186             if (it.vstring)
187                 mem_d(it.vstring);
188     }
189 }
190
191 static size_t ast_type_to_string_impl(const ast_expression *e, char *buf, size_t bufsize, size_t pos)
192 {
193     const char *typestr;
194     size_t typelen;
195     size_t i;
196
197     if (!e) {
198         if (pos + 6 >= bufsize)
199             goto full;
200         util_strncpy(buf + pos, "(null)", 6);
201         return pos + 6;
202     }
203
204     if (pos + 1 >= bufsize)
205         goto full;
206
207     switch (e->m_vtype) {
208         case TYPE_VARIANT:
209             util_strncpy(buf + pos, "(variant)", 9);
210             return pos + 9;
211
212         case TYPE_FIELD:
213             buf[pos++] = '.';
214             return ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
215
216         case TYPE_POINTER:
217             if (pos + 3 >= bufsize)
218                 goto full;
219             buf[pos++] = '*';
220             buf[pos++] = '(';
221             pos = ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
222             if (pos + 1 >= bufsize)
223                 goto full;
224             buf[pos++] = ')';
225             return pos;
226
227         case TYPE_FUNCTION:
228             pos = ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
229             if (pos + 2 >= bufsize)
230                 goto full;
231             if (e->m_type_params.empty()) {
232                 buf[pos++] = '(';
233                 buf[pos++] = ')';
234                 return pos;
235             }
236             buf[pos++] = '(';
237             pos = ast_type_to_string_impl(e->m_type_params[0].get(), buf, bufsize, pos);
238             for (i = 1; i < e->m_type_params.size(); ++i) {
239                 if (pos + 2 >= bufsize)
240                     goto full;
241                 buf[pos++] = ',';
242                 buf[pos++] = ' ';
243                 pos = ast_type_to_string_impl(e->m_type_params[i].get(), buf, bufsize, pos);
244             }
245             if (pos + 1 >= bufsize)
246                 goto full;
247             buf[pos++] = ')';
248             return pos;
249
250         case TYPE_ARRAY:
251             pos = ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
252             if (pos + 1 >= bufsize)
253                 goto full;
254             buf[pos++] = '[';
255             pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->m_count);
256             if (pos + 1 >= bufsize)
257                 goto full;
258             buf[pos++] = ']';
259             return pos;
260
261         default:
262             typestr = type_name[e->m_vtype];
263             typelen = strlen(typestr);
264             if (pos + typelen >= bufsize)
265                 goto full;
266             util_strncpy(buf + pos, typestr, typelen);
267             return pos + typelen;
268     }
269
270 full:
271     buf[bufsize-3] = '.';
272     buf[bufsize-2] = '.';
273     buf[bufsize-1] = '.';
274     return bufsize;
275 }
276
277 void ast_type_to_string(const ast_expression *e, char *buf, size_t bufsize)
278 {
279     size_t pos = ast_type_to_string_impl(e, buf, bufsize-1, 0);
280     buf[pos] = 0;
281 }
282
283 void ast_value::addParam(ast_value *p)
284 {
285     m_type_params.emplace_back(p);
286 }
287
288 ast_binary::ast_binary(lex_ctx_t ctx, int op,
289                        ast_expression* left, ast_expression* right)
290     : ast_expression(ctx, TYPE_ast_binary)
291     , m_op(op)
292     // m_left/m_right happen after the peephole step right below
293     , m_right_first(false)
294 {
295     if (ast_istype(right, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
296         ast_unary      *unary  = ((ast_unary*)right);
297         ast_expression *normal = unary->m_operand;
298
299         /* make a-(-b) => a + b */
300         if (unary->m_op == VINSTR_NEG_F || unary->m_op == VINSTR_NEG_V) {
301             if (op == INSTR_SUB_F) {
302                 op = INSTR_ADD_F;
303                 right = normal;
304                 ++opts_optimizationcount[OPTIM_PEEPHOLE];
305             } else if (op == INSTR_SUB_V) {
306   &n