build administrativa
[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
251 temp_arg = psi_call_frame_fetch_symbol(frame, let_temp->exp->var);
252 frame_sym->temp_val = *deref_impl_val(temp_arg->ptr, val->data.var);
253 }
254 break;
255
256 case PSI_LET_CALLOC:
257 {
258 zend_long n = psi_num_exp_get_long(val->data.alloc->nmemb, frame, NULL);
259 zend_long s = psi_num_exp_get_long(val->data.alloc->size, frame, NULL);
260 void *tmp;
261
262 if (val->data.alloc->static_memory) {
263 tmp = safe_pemalloc(n, s, sizeof(void *), 1);
264 } else {
265 tmp = *psi_call_frame_push_auto(frame, safe_emalloc(n, s, sizeof(void *)));
266 }
267
268 memset(tmp, 0, n * s + sizeof(void *));
269 frame_sym->temp_val.ptr = tmp;
270 }
271 break;
272
273 case PSI_LET_NUMEXP:
274 {
275 impl_val res;
276 token_t val_type = psi_decl_type_get_real(val->var->arg->type)->type;
277 token_t res_type = psi_num_exp_exec(val->data.num, &res, frame, NULL);
278
279 if (val_type == res_type) {
280 frame_sym->temp_val = res;
281 } else {
282 psi_calc_cast(res_type, &res, val_type, &frame_sym->temp_val);
283 }
284 }
285 break;
286
287 case PSI_LET_CALLBACK:
288 frame_sym->temp_val.ptr = val->data.callback->decl->sym;
289 break;
290
291 case PSI_LET_FUNC:
292 if (!psi_let_func_exec(val, val->data.func, darg, frame)) {
293 return NULL;
294 }
295 break;
296 }
297
298 if (val->is_reference) {
299 frame_sym->ptr = &frame_sym->ival_ptr;
300 } else {
301 frame_sym->ptr = frame_sym->ival_ptr;
302 }
303
304 if (actual_location) {
305 assert(!val->is_reference || actual_size == SIZEOF_VOID_P);
306 memcpy(actual_location, frame_sym->ptr, actual_size);
307 frame_sym->ptr = actual_location;
308 }
309
310 return frame_sym->ptr;
311 }
312
313 struct psi_let_func* psi_let_exp_get_func(struct psi_let_exp* exp)
314 {
315 if (exp) {
316 switch (exp->kind) {
317 case PSI_LET_CALLBACK:
318 return exp->data.callback->func;
319 case PSI_LET_FUNC:
320 return exp->data.func;
321 default:
322 break;
323 }
324 }
325 return NULL;
326 }
327
328 struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val)
329 {
330 if (!val->var) {
331 zend_string *name = psi_let_exp_get_decl_var_name(val);
332
333 if (name) {
334 val->var = psi_decl_var_init(name, 0, 0);
335 zend_string_release(name);
336 }
337 }
338 return val->var;
339 }
340
341 struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *val)
342 {
343 struct psi_let_func* fn = psi_let_exp_get_func(val);
344 return fn ? fn->var : NULL;
345 }
346
347 zend_string *psi_let_exp_get_decl_var_name(struct psi_let_exp* val)
348 {
349 struct psi_impl_var* var;
350
351 if (val->var) {
352 return zend_string_copy(val->var->name);
353 }
354
355 var = psi_let_exp_get_impl_var(val);
356 if (var) {
357 smart_str name = {0};
358
359 smart_str_appendl_ex(&name, &var->name->val[1], var->name->len - 1, 1);
360
361 return smart_str_extract(&name);
362 }
363
364 return NULL;
365 }