travis: update
[m6w6/ext-psi] / src / types / let_exp.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31 #include "data.h"
32 #include "call.h"
33 #include "calc.h"
34
35 #include <assert.h>
36
37 #include <Zend/zend_smart_str.h>
38
39 struct psi_let_exp *psi_let_exp_init_ex(struct psi_decl_var *var,
40 enum psi_let_exp_kind kind, void *data)
41 {
42 struct psi_let_exp *val = psi_let_exp_init(kind, data);
43 val->var = var;
44 return val;
45 }
46
47 struct psi_let_exp *psi_let_exp_init(enum psi_let_exp_kind kind, void *data)
48 {
49 struct psi_let_exp *let = pecalloc(1, sizeof(*let), 1);
50 switch (let->kind = kind) {
51 case PSI_LET_NULL:
52 assert(!data);
53 break;
54 case PSI_LET_NUMEXP:
55 let->data.num = data;
56 break;
57 case PSI_LET_CALLOC:
58 let->data.alloc = data;
59 break;
60 case PSI_LET_CALLBACK:
61 let->data.callback = data;
62 break;
63 case PSI_LET_FUNC:
64 let->data.func = data;
65 break;
66 case PSI_LET_TMP:
67 let->data.var = data;
68 break;
69 default:
70 assert(0);
71 }
72 return let;
73 }
74
75 void psi_let_exp_free(struct psi_let_exp **let_ptr)
76 {
77 if (*let_ptr) {
78 struct psi_let_exp *let = *let_ptr;
79
80 *let_ptr = NULL;
81 switch (let->kind) {
82 case PSI_LET_NULL:
83 break;
84 case PSI_LET_NUMEXP:
85 psi_num_exp_free(&let->data.num);
86 break;
87 case PSI_LET_CALLOC:
88 psi_let_calloc_free(&let->data.alloc);
89 break;
90 case PSI_LET_CALLBACK:
91 psi_let_callback_free(&let->data.callback);
92 break;
93 case PSI_LET_FUNC:
94 psi_let_func_free(&let->data.func);
95 break;
96 case PSI_LET_TMP:
97 psi_decl_var_free(&let->data.var);
98 break;
99 default:
100 assert(0);
101 }
102 if (let->var) {
103 psi_decl_var_free(&let->var);
104 }
105 free(let);
106 }
107 }
108
109 void psi_let_exp_dump(struct psi_dump *dump, struct psi_let_exp *val, unsigned level, int last)
110 {
111 if (level > 1) {
112 /* only if not directly after `set ...` */
113 PSI_DUMP(dump, "%s", psi_t_indent(level));
114 }
115
116 if (val->var) {
117 if (val->var->token) {
118 psi_decl_var_dump(dump, val->var);
119 PSI_DUMP(dump, " = ");
120 }
121 }
122 if (val->is_reference) {
123 PSI_DUMP(dump, "&");
124 }
125
126 switch (val->kind) {
127 case PSI_LET_NULL:
128 PSI_DUMP(dump, "NULL");
129 break;
130 case PSI_LET_TMP:
131 psi_decl_var_dump(dump, val->data.var);
132 PSI_DUMP(dump, "\t/* fqn=%s */", val->data.var->fqn->val);
133 break;
134 case PSI_LET_CALLOC:
135 psi_let_calloc_dump(dump, val->data.alloc);
136 break;
137 case PSI_LET_CALLBACK:
138 psi_let_callback_dump(dump, val->data.callback, level);
139 break;
140 case PSI_LET_FUNC:
141 psi_let_func_dump(dump, val->data.func, level);
142 break;
143 case PSI_LET_NUMEXP:
144 psi_num_exp_dump(dump, val->data.num);
145 break;
146
147 default:
148 assert(0);
149 }
150
151 if (val->var) {
152 PSI_DUMP(dump, "\t/* fqn=%s */", val->var->fqn->val);
153 }
154
155 if (level > 1) {
156 if (!last) {
157 PSI_DUMP(dump, ",");
158 }
159 } else {
160 PSI_DUMP(dump, ";");
161 }
162 }
163
164 bool psi_let_exp_validate(struct psi_data *data, struct psi_let_exp *val,
165 struct psi_validate_scope *scope)
166 {
167 struct psi_decl_var *dvar = psi_let_exp_get_decl_var(val);
168
169 switch (val->kind) {
170 case PSI_LET_TMP:
171 if (!psi_decl_var_validate(data, val->data.var, scope)) {
172 data->error(data, dvar->token ? : **(struct psi_token ***) &val->data,
173 PSI_WARNING, "Unknown variable '%s' in temp let statment of implementation '%s'",
174 dvar->name->val, scope->impl->func->name->val);
175 return false;
176 }
177 break;
178
179 default:
180 if (!psi_decl_var_validate(data, dvar, scope)) {
181 data->error(data, dvar->token ? : **(struct psi_token ***) &val->data,
182 PSI_WARNING, "Unknown variable '%s' in let statement of implementation '%s'",
183 dvar->name->val, scope->impl->func->name->val);
184 return false;
185 }
186 break;
187 }
188 switch (val->kind) {
189 case PSI_LET_NULL:
190 break;
191 case PSI_LET_TMP:
192 /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
193 /* e.g. let foo = *bar; */
194 val->var->pointer_level = val->data.var->pointer_level;
195 val->var->arg = val->data.var->arg;
196 break;
197 case PSI_LET_NUMEXP:
198 if (!psi_num_exp_validate(data, val->data.num, scope)) {
199 return false;
200 }
201 break;
202 case PSI_LET_CALLOC:
203 if (!psi_num_exp_validate(data, val->data.alloc->nmemb, scope)) {
204 return false;
205 }
206 if (!psi_num_exp_validate(data, val->data.alloc->size, scope)) {
207 return false;
208 }
209 break;
210 case PSI_LET_CALLBACK:
211 if (!psi_let_func_validate(data, val->data.callback->func, scope)) {
212 return false;
213 }
214 if (!psi_let_callback_validate(data, val->data.callback, scope)) {
215 return false;
216 }
217 break;
218 case PSI_LET_FUNC:
219 if (!psi_let_func_validate(data, val->data.func, scope)) {
220 return false;
221 }
222 break;
223 }
224
225 return true;
226 }
227
228 void *psi_let_exp_exec(struct psi_let_exp *val, struct psi_decl_arg *darg,
229 void *actual_location, size_t actual_size, struct psi_call_frame *frame)
230 {
231 struct psi_call_frame_symbol *frame_sym;
232
233 frame_sym = psi_call_frame_fetch_symbol(frame, val->var);
234
235 switch (val->kind) {
236 case PSI_LET_NULL:
237 /* FIXME: sizeof_decl_arg */
238 if (darg && darg->var->array_size) {
239 frame_sym->temp_val.ptr = ecalloc(1, psi_decl_arg_get_size(darg));
240 } else {
241 memset(&frame_sym->temp_val, 0, sizeof(frame_sym->temp_val));
242 }
243 break;
244
245 case PSI_LET_TMP:
246 {
247 struct psi_impl *impl = psi_call_frame_get_impl(frame);
248 struct psi_let_stmt *let_temp = psi_impl_get_let(impl, val->data.var);
249 struct psi_call_frame_symbol *temp_arg;
250 impl_val *src;
251
252 temp_arg = psi_call_frame_fetch_symbol(frame, let_temp->exp->var);
253 src = deref_impl_val(temp_arg->ptr, val->data.var);
254 memcpy(&frame_sym->temp_val, src, psi_decl_var_get_size(let_temp->exp->var));
255 }
256 break;
257
258 case PSI_LET_CALLOC:
259 {
260 zend_long n = psi_num_exp_get_long(val->data.alloc->nmemb, frame, NULL);
261 zend_long s = psi_num_exp_get_long(val->data.alloc->size, frame, NULL);
262 void *tmp;
263
264 if (val->data.alloc->static_memory) {
265 tmp = safe_pemalloc(n, s, sizeof(void *), 1);
266 } else {
267 tmp = *psi_call_frame_push_auto(frame, safe_emalloc(n, s, sizeof(void *)));
268 }
269
270 memset(tmp, 0, n * s + sizeof(void *));
271 frame_sym->temp_val.ptr = tmp;
272 }
273 break;
274
275 case PSI_LET_NUMEXP:
276 {
277 impl_val res;
278 token_t val_type = psi_decl_type_get_real(val->var->arg->type)->type;
279 token_t res_type = psi_num_exp_exec(val->data.num, &res, frame, NULL);
280
281 if (val_type == res_type) {
282 frame_sym->temp_val = res;
283 } else {
284 psi_calc_cast(res_type, &res, val_type, &frame_sym->temp_val);
285 }
286 }
287 break;
288
289 case PSI_LET_CALLBACK:
290 frame_sym->temp_val.ptr = val->data.callback->decl->sym;
291 break;
292
293 case PSI_LET_FUNC:
294 if (!psi_let_func_exec(val, val->data.func, darg, frame)) {
295 return NULL;
296 }
297 break;
298 }
299
300 if (val->is_reference) {
301 frame_sym->ptr = &frame_sym->ival_ptr;
302 } else {
303 frame_sym->ptr = frame_sym->ival_ptr;
304 }
305
306 if (actual_location) {
307 assert(!val->is_reference || actual_size == SIZEOF_VOID_P);
308 memcpy(actual_location, frame_sym->ptr, actual_size);
309 frame_sym->ptr = actual_location;
310 }
311
312 return frame_sym->ptr;
313 }
314
315 struct psi_let_func* psi_let_exp_get_func(struct psi_let_exp* exp)
316 {
317 if (exp) {
318 switch (exp->kind) {
319 case PSI_LET_CALLBACK:
320 return exp->data.callback->func;
321 case PSI_LET_FUNC:
322 return exp->data.func;
323 default:
324 break;
325 }
326 }
327 return NULL;
328 }
329
330 struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val)
331 {
332 if (!val->var) {
333 zend_string *name = psi_let_exp_get_decl_var_name(val);
334
335 if (name) {
336 val->var = psi_decl_var_init(name, 0, 0);
337 zend_string_release(name);
338 }
339 }
340 return val->var;
341 }
342
343 struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *val)
344 {
345 struct psi_let_func* fn = psi_let_exp_get_func(val);
346 return fn ? fn->var : NULL;
347 }
348
349 zend_string *psi_let_exp_get_decl_var_name(struct psi_let_exp* val)
350 {
351 struct psi_impl_var* var;
352
353 if (val->var) {
354 return zend_string_copy(val->var->name);
355 }
356
357 var = psi_let_exp_get_impl_var(val);
358 if (var) {
359 smart_str name = {0};
360
361 smart_str_appendl_ex(&name, &var->name->val[1], var->name->len - 1, 1);
362
363 return smart_str_extract(&name);
364 }
365
366 return NULL;
367 }