raising the head after a three-weeks refactoring
[m6w6/ext-psi] / src / types / num_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 #include "php_psi_stdinc.h"
27
28 #include <assert.h>
29
30 #include "data.h"
31 #include "call.h"
32 #include "calc.h"
33
34 struct psi_num_exp *psi_num_exp_init(token_t t, void *num)
35 {
36 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
37
38 switch (exp->type = t) {
39 case PSI_T_NUMBER:
40 case PSI_T_NSNAME:
41 exp->data.numb = strdup(num);
42 break;
43 case PSI_T_NAME:
44 exp->data.dvar = num;
45 break;
46 default:
47 assert(0);
48 }
49
50 return exp;
51 }
52
53 struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp)
54 {
55 struct psi_num_exp *num = calloc(1, sizeof(*num));
56
57 *num = *exp;
58
59 if (num->token) {
60 num->token = psi_token_copy(num->token);
61 }
62 if (num->operand) {
63 num->operand = psi_num_exp_copy(num->operand);
64 }
65
66 switch (num->type) {
67 case PSI_T_INT64:
68 case PSI_T_DOUBLE:
69 case PSI_T_ENUM:
70 case PSI_T_CONST:
71 break;
72 case PSI_T_NUMBER:
73 case PSI_T_NSNAME:
74 num->data.numb = strdup(num->data.numb);
75 break;
76 case PSI_T_NAME:
77 num->data.dvar = psi_decl_var_copy(num->data.dvar);
78 break;
79 default:
80 assert(0);
81 }
82 return num;
83 }
84
85 void psi_num_exp_free(struct psi_num_exp **exp_ptr)
86 {
87 if (*exp_ptr) {
88 struct psi_num_exp *exp = *exp_ptr;
89
90 *exp_ptr = NULL;
91 if (exp->token) {
92 free(exp->token);
93 }
94 switch (exp->type) {
95 case PSI_T_INT64:
96 case PSI_T_DOUBLE:
97 case PSI_T_ENUM:
98 case PSI_T_CONST:
99 break;
100 case PSI_T_NSNAME:
101 case PSI_T_NUMBER:
102 free(exp->data.numb);
103 break;
104 case PSI_T_NAME:
105 psi_decl_var_free(&exp->data.dvar);
106 break;
107 default:
108 assert(0);
109 }
110 if (exp->operand) {
111 psi_num_exp_free(&exp->operand);
112 }
113 free(exp);
114 }
115 }
116
117 void psi_num_exp_dump(int fd, struct psi_num_exp *exp)
118 {
119 while (exp) {
120 switch (exp->type) {
121 case PSI_T_INT64:
122 dprintf(fd, "%" PRId64, exp->data.ival.i64);
123 break;
124 case PSI_T_DOUBLE:
125 dprintf(fd, "%F", exp->data.ival.dval);
126 break;
127 case PSI_T_NUMBER:
128 case PSI_T_NSNAME:
129 dprintf(fd, "%s", exp->data.numb);
130 break;
131 case PSI_T_CONST:
132 dprintf(fd, "%s", exp->data.cnst->name);
133 break;
134 case PSI_T_ENUM:
135 dprintf(fd, "%s", exp->data.enm->name);
136 break;
137 case PSI_T_NAME:
138 psi_decl_var_dump(fd, exp->data.dvar);
139 break;
140 default:
141 assert(0);
142 }
143
144 if (exp->operand) {
145 char op;
146
147 switch (exp->op) {
148 case PSI_T_PLUS:
149 op = '+';
150 break;
151 case PSI_T_MINUS:
152 op = '-';
153 break;
154 case PSI_T_ASTERISK:
155 op = '*';
156 break;
157 case PSI_T_SLASH:
158 op = '/';
159 break;
160 default:
161 assert(0);
162 }
163 dprintf(fd, " %c ", op);
164 }
165
166 exp = exp->operand;
167 }
168 }
169
170 static inline bool psi_num_exp_validate_enum(struct psi_data *data, struct psi_num_exp *exp,
171 struct psi_decl_enum *enm)
172 {
173 size_t i = 0;
174 struct psi_decl_enum_item *itm;
175
176 while (psi_plist_get(enm->items, i++, &itm)) {
177 if (!strcmp(itm->name, exp->data.dvar->name)) {
178 psi_decl_var_free(&exp->data.dvar);
179 exp->type = PSI_T_ENUM;
180 exp->data.enm = itm;
181 return psi_num_exp_validate(data, exp, NULL, NULL, NULL, NULL, enm);
182 }
183 }
184
185 return false;
186 }
187
188 bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
189 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
190 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
191 {
192 size_t i = 0;
193 impl_val tmp = {0};
194 struct psi_const *cnst;
195 struct psi_decl_enum *enm;
196
197 if (exp->operand) {
198 switch (exp->op) {
199 case PSI_T_PLUS:
200 exp->calc = psi_calc_add;
201 break;
202 case PSI_T_MINUS:
203 exp->calc = psi_calc_sub;
204 break;
205 case PSI_T_ASTERISK:
206 exp->calc = psi_calc_mul;
207 break;
208 case PSI_T_SLASH:
209 exp->calc = psi_calc_div;
210 break;
211 default:
212 data->error(data, exp->token, PSI_WARNING,
213 "Unknown numeric operator (%d)", exp->op);
214 return false;
215 }
216 if (!psi_num_exp_validate(data, exp->operand, impl, cb_decl, current_let,
217 current_set, current_enum)) {
218 return false;
219 }
220 }
221
222 switch (exp->type) {
223 case PSI_T_CONST:
224 case PSI_T_INT64:
225 case PSI_T_DOUBLE:
226 case PSI_T_ENUM:
227 return true;
228
229 case PSI_T_NAME:
230 if (current_enum && psi_num_exp_validate_enum(data, exp, current_enum)) {
231 return true;
232 }
233 while (psi_plist_get(data->enums, i++, &enm)) {
234 if (psi_num_exp_validate_enum(data, exp, enm)) {
235 return true;
236 }
237 }
238 if (exp->data.dvar->arg) {
239 return true;
240 }
241 if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
242 current_let, current_set)) {
243 return true;
244 }
245 if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
246 return true;
247 }
248 data->error(data, exp->token, PSI_WARNING,
249 "Unknown variable '%s' in numeric expression",
250 exp->data.dvar->name);
251 return false;
252
253 case PSI_T_NSNAME:
254 while (psi_plist_get(data->consts, i++, &cnst)) {
255 if (!strcmp(cnst->name, exp->data.numb)) {
256 free(exp->data.numb);
257 exp->type = PSI_T_CONST;
258 exp->data.cnst = cnst;
259 return true;
260 }
261 }
262 data->error(data, exp->token, PSI_WARNING,
263 "Unknown constant '%s' in numeric expression",
264 exp->data.numb);
265 return false;
266
267 case PSI_T_NUMBER:
268 switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 0)) {
269 case IS_LONG:
270 free(exp->data.numb);
271 exp->type = PSI_T_INT64;
272 exp->data.ival.i64 = tmp.zend.lval;
273 return true;
274
275 case IS_DOUBLE:
276 free(exp->data.numb);
277 exp->type = PSI_T_DOUBLE;
278 exp->data.ival.dval = tmp.dval;
279 return true;
280 }
281 data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
282 return false;
283
284 default:
285 assert(0);
286 }
287
288 return false;
289 }
290
291 #include "Zend/zend_constants.h"
292
293 static inline token_t psi_num_exp_eval_constant(struct psi_num_exp *exp,
294 impl_val *res, struct psi_call_frame *frame)
295 {
296 switch (exp->data.cnst->type->type) {
297 case PSI_T_INT:
298 res->i64 = zend_get_constant_str(exp->data.cnst->name,
299 strlen(exp->data.cnst->name))->value.lval;
300 return PSI_T_INT64;
301 case PSI_T_FLOAT:
302 res->dval = zend_get_constant_str(exp->data.cnst->name,
303 strlen(exp->data.cnst->name))->value.dval;
304 return PSI_T_DOUBLE;
305 default:
306 return 0;
307 }
308 }
309
310 static inline token_t psi_num_exp_eval_decl_var(struct psi_num_exp *exp,
311 impl_val *res, struct psi_call_frame *frame)
312 {
313 impl_val *ref;
314 struct psi_call_frame_symbol *sym;
315 struct psi_decl_type *real;
316 size_t size;
317
318 real = psi_decl_type_get_real(exp->data.dvar->arg->type);
319 size = psi_decl_arg_get_size(exp->data.dvar->arg);
320 sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar);
321 ref = deref_impl_val(sym->ptr, exp->data.dvar);
322
323 memcpy(res, ref, size);
324
325 switch (real->type) {
326 case PSI_T_INT8:
327 case PSI_T_UINT8:
328 case PSI_T_INT16:
329 case PSI_T_UINT16:
330 case PSI_T_INT32:
331 case PSI_T_UINT32:
332 case PSI_T_INT64:
333 case PSI_T_UINT64:
334 case PSI_T_FLOAT:
335 case PSI_T_DOUBLE:
336 break;
337 default:
338 assert(0);
339 }
340
341 return real->type;
342 }
343
344 static inline token_t psi_num_exp_eval(struct psi_num_exp *exp, impl_val *res,
345 struct psi_call_frame *frame)
346 {
347 switch (exp->type) {
348 case PSI_T_INT64:
349 case PSI_T_DOUBLE:
350 *res = exp->data.ival;
351 return exp->type;
352
353 case PSI_T_ENUM:
354 res->i64 = exp->data.enm->val;
355 return PSI_T_INT64;
356
357 case PSI_T_CONST:
358 return psi_num_exp_eval_constant(exp, res, frame);
359 break;
360
361 case PSI_T_NAME:
362 return psi_num_exp_eval_decl_var(exp, res, frame);
363 break;
364
365 default:
366 assert(0);
367 }
368 return 0;
369 }
370
371 token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res,
372 struct psi_call_frame *frame)
373 {
374 impl_val num = {0};
375 token_t num_type = psi_num_exp_eval(exp, &num, frame);
376
377 /* FIXME operator precedence */
378 if (exp->operand) {
379 impl_val tmp = {0};
380 token_t tmp_type = psi_num_exp_exec(exp->operand, &tmp, frame);
381
382 return exp->calc(num_type, &num, tmp_type, &tmp, res);
383 }
384
385 *res = num;
386 return num_type;
387 }