fix leak
[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 "context.h"
32 #include "call.h"
33 #include "calc.h"
34
35
36 struct psi_num_exp *psi_num_exp_init_binary(token_t op,
37 struct psi_num_exp *lhs, struct psi_num_exp *rhs)
38 {
39 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
40
41 exp->op = op;
42 exp->data.b.lhs = lhs;
43 exp->data.b.rhs = rhs;
44
45 return exp;
46 }
47
48 struct psi_num_exp *psi_num_exp_init_unary(token_t op,
49 struct psi_num_exp *u)
50 {
51 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
52
53 exp->op = op;
54 exp->data.u = u;
55
56 return exp;
57 }
58
59 struct psi_num_exp *psi_num_exp_init_num(struct psi_number *n)
60 {
61 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
62
63 exp->data.n = n;
64
65 return exp;
66 }
67
68 struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp)
69 {
70 struct psi_num_exp *cpy;
71
72 if (!exp) {
73 return NULL;
74 }
75
76 cpy = malloc(sizeof(*cpy));
77 *cpy = *exp;
78
79 switch (exp->op) {
80 case 0:
81 cpy->data.n = psi_number_copy(exp->data.n);
82 break;
83
84 case PSI_T_NOT:
85 case PSI_T_TILDE:
86 case PSI_T_LPAREN:
87 cpy->data.u = psi_num_exp_copy(exp->data.u);
88 break;
89
90 case PSI_T_PIPE:
91 case PSI_T_CARET:
92 case PSI_T_AMPERSAND:
93 case PSI_T_LSHIFT:
94 case PSI_T_RSHIFT:
95 case PSI_T_PLUS:
96 case PSI_T_MINUS:
97 case PSI_T_ASTERISK:
98 case PSI_T_SLASH:
99 case PSI_T_MODULO:
100 cpy->data.b.lhs = psi_num_exp_copy(exp->data.b.lhs);
101 cpy->data.b.rhs = psi_num_exp_copy(exp->data.b.rhs);
102 break;
103
104 default:
105 assert(0);
106 }
107
108 if (exp->token) {
109 cpy->token = psi_token_copy(exp->token);
110 }
111
112 return cpy;
113 }
114
115 void psi_num_exp_free(struct psi_num_exp **c_ptr)
116 {
117 if (*c_ptr) {
118 struct psi_num_exp *c = *c_ptr;
119
120 *c_ptr = NULL;
121
122 switch (c->op) {
123 case 0:
124 psi_number_free(&c->data.n);
125 break;
126 case PSI_T_NOT:
127 case PSI_T_TILDE:
128 case PSI_T_LPAREN:
129 psi_num_exp_free(&c->data.u);
130 break;
131
132 case PSI_T_PIPE:
133 case PSI_T_CARET:
134 case PSI_T_AMPERSAND:
135 case PSI_T_LSHIFT:
136 case PSI_T_RSHIFT:
137 case PSI_T_PLUS:
138 case PSI_T_MINUS:
139 case PSI_T_ASTERISK:
140 case PSI_T_SLASH:
141 case PSI_T_MODULO:
142 psi_num_exp_free(&c->data.b.lhs);
143 psi_num_exp_free(&c->data.b.rhs);
144 break;
145
146 default:
147 assert(0);
148 }
149
150 if (c->token) {
151 free(c->token);
152 }
153
154 free(c);
155 }
156 }
157
158 static inline wint_t psi_num_exp_op_tok(token_t op)
159 {
160 switch (op) {
161 case PSI_T_NOT:
162 return L'!';
163 case PSI_T_TILDE:
164 return L'~';
165 case PSI_T_LPAREN:
166 return L'(';
167
168 case PSI_T_PIPE:
169 return L'|';
170 case PSI_T_CARET:
171 return L'^';
172 case PSI_T_AMPERSAND:
173 return L'&';
174
175 case PSI_T_LSHIFT:
176 return L'«';
177 case PSI_T_RSHIFT:
178 return L'»';
179
180 case PSI_T_PLUS:
181 return L'+';
182 case PSI_T_MINUS:
183 return L'-';
184
185 case PSI_T_ASTERISK:
186 return L'*';
187 case PSI_T_SLASH:
188 return L'/';
189 case PSI_T_MODULO:
190 return L'%';
191
192 default:
193 assert(0);
194 }
195 return 0;
196 }
197
198 void psi_num_exp_dump(int fd, struct psi_num_exp *exp)
199 {
200 switch (exp->op) {
201 case 0:
202 psi_number_dump(fd, exp->data.n);
203 break;
204
205 case PSI_T_NOT:
206 case PSI_T_TILDE:
207 dprintf(fd, "%lc", psi_num_exp_op_tok(exp->op));
208 psi_num_exp_dump(fd, exp->data.u);
209 break;
210
211 case PSI_T_LPAREN:
212 dprintf(fd, "(");
213 psi_num_exp_dump(fd, exp->data.u);
214 dprintf(fd, ")");
215 break;
216
217 case PSI_T_PIPE:
218 case PSI_T_CARET:
219 case PSI_T_AMPERSAND:
220 case PSI_T_LSHIFT:
221 case PSI_T_RSHIFT:
222 case PSI_T_PLUS:
223 case PSI_T_MINUS:
224 case PSI_T_ASTERISK:
225 case PSI_T_SLASH:
226 psi_num_exp_dump(fd, exp->data.b.lhs);
227 dprintf(fd, " %lc ", psi_num_exp_op_tok(exp->op));
228 psi_num_exp_dump(fd, exp->data.b.rhs);
229 break;
230
231 default:
232 assert(0);
233 }
234
235 }
236
237 bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
238 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
239 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
240 {
241 if (exp->op) {
242 switch (exp->op) {
243 case PSI_T_NOT:
244 exp->calc = psi_calc_not;
245 break;
246 case PSI_T_TILDE:
247 exp->calc = psi_calc_bin_not;
248 break;
249
250 case PSI_T_LPAREN:
251 break;
252
253 case PSI_T_PIPE:
254 exp->calc = psi_calc_bin_or;
255 break;
256 case PSI_T_CARET:
257 exp->calc = psi_calc_bin_xor;
258 break;
259 case PSI_T_AMPERSAND:
260 exp->calc = psi_calc_bin_and;
261 break;
262 case PSI_T_LSHIFT:
263 exp->calc = psi_calc_bin_lshift;
264 break;
265 case PSI_T_RSHIFT:
266 exp->calc = psi_calc_bin_rshift;
267 break;
268 case PSI_T_PLUS:
269 exp->calc = psi_calc_add;
270 break;
271 case PSI_T_MINUS:
272 exp->calc = psi_calc_sub;
273 break;
274 case PSI_T_ASTERISK:
275 exp->calc = psi_calc_mul;
276 break;
277 case PSI_T_SLASH:
278 exp->calc = psi_calc_div;
279 break;
280 case PSI_T_MODULO:
281 exp->calc = psi_calc_mod;
282 break;
283 default:
284 data->error(data, exp->token, PSI_WARNING,
285 "Unknown numeric operator (%d)", exp->op);
286 return false;
287 }
288 }
289
290 switch (exp->op) {
291 case 0:
292 return psi_number_validate(data, exp->data.n, impl, cb_decl, current_let, current_set, current_enum);
293
294 case PSI_T_NOT:
295 case PSI_T_TILDE:
296 case PSI_T_LPAREN:
297 return psi_num_exp_validate(data, exp->data.u, impl, cb_decl, current_let, current_set, current_enum);
298 break;
299
300 case PSI_T_PIPE:
301 case PSI_T_CARET:
302 case PSI_T_AMPERSAND:
303 case PSI_T_LSHIFT:
304 case PSI_T_RSHIFT:
305 case PSI_T_PLUS:
306 case PSI_T_MINUS:
307 case PSI_T_ASTERISK:
308 case PSI_T_SLASH:
309 case PSI_T_MODULO:
310 return psi_num_exp_validate(data, exp->data.b.lhs, impl, cb_decl, current_let, current_set, current_enum)
311 && psi_num_exp_validate(data, exp->data.b.rhs, impl, cb_decl, current_let, current_set, current_enum);
312 default:
313 assert(0);
314 }
315
316 return false;
317 }
318
319 static inline void psi_impl_val_dump(token_t t, impl_val *res,
320 struct psi_call_frame *frame)
321 {
322 switch (t) {
323 case PSI_T_INT8:
324 case PSI_T_UINT8:
325 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
326 break;
327 case PSI_T_INT16:
328 case PSI_T_UINT16:
329 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
330 break;
331 case PSI_T_INT32:
332 case PSI_T_UINT32:
333 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
334 break;
335 case PSI_T_INT64:
336 case PSI_T_UINT64:
337 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
338 break;
339 case PSI_T_FLOAT:
340 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIfval, res->fval);
341 break;
342 case PSI_T_DOUBLE:
343 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
344 break;
345 default:
346 assert(0);
347 }
348 }
349 static inline void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
350 {
351 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", " = ");
352 psi_impl_val_dump(t, res, frame);
353 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
354 }
355
356 static void psi_num_exp_reduce(struct psi_num_exp *exp, struct psi_plist **output_ptr,
357 struct psi_plist **input_ptr, struct psi_call_frame *frame)
358 {
359 struct psi_plist *output = *output_ptr, *input = *input_ptr;
360 struct element {
361 token_t type;
362 union {
363 impl_val value;
364 psi_calc calc;
365 } data;
366 } entry;
367
368 switch (exp->op) {
369 case 0:
370 entry.type = psi_number_eval(exp->data.n, &entry.data.value, frame);
371 output = psi_plist_add(output, &entry);
372 break;
373
374 case PSI_T_LPAREN:
375 entry.type = exp->op;
376 input = psi_plist_add(input, &entry);
377 psi_num_exp_reduce(exp->data.u, &output, &input, frame);
378 while (psi_plist_pop(input, &entry)) {
379 if (entry.type == PSI_T_LPAREN) {
380 break;
381 }
382 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
383 output = psi_plist_add(output, &entry);
384 }
385 break;
386
387 case PSI_T_NOT:
388 case PSI_T_TILDE:
389 while (psi_plist_top(input, &entry)) {
390 /* bail out if exp->op >= entry.type */
391 if (psi_num_exp_op_cmp(exp->op, entry.type) != 1) {
392 break;
393 }
394 psi_plist_pop(input, NULL);
395 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
396 output = psi_plist_add(output, &entry);
397 }
398 entry.type = exp->op;
399 entry.data.calc = exp->calc;
400 input = psi_plist_add(input, &entry);
401 psi_num_exp_reduce(exp->data.u, &output, &input, frame);
402 break;
403
404 default:
405 psi_num_exp_reduce(exp->data.b.lhs, &output, &input, frame);
406 while (psi_plist_top(input, &entry)) {
407 /* bail out if exp->op > entry.type */
408 if (psi_num_exp_op_cmp(exp->op, entry.type) == -1) {
409 break;
410 }
411 psi_plist_pop(input, NULL);
412 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
413 output = psi_plist_add(output, &entry);
414 }
415 entry.type = exp->op;
416 entry.data.calc = exp->calc;
417 input = psi_plist_add(input, &entry);
418 psi_num_exp_reduce(exp->data.b.rhs, &output, &input, frame);
419 break;
420 }
421
422 *output_ptr = output;
423 *input_ptr = input;
424 }
425
426 token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res,
427 struct psi_call_frame *frame)
428 {
429 struct psi_plist *output, *input;
430 struct element {
431 token_t type;
432 union {
433 impl_val value;
434 psi_calc calc;
435 } data;
436 } entry, lhs, rhs;
437
438 output = psi_plist_init_ex(sizeof(entry), NULL);
439 input = psi_plist_init_ex(sizeof(entry), NULL);
440
441 psi_num_exp_reduce(exp, &output, &input, frame);
442
443 while (psi_plist_pop(input, &entry)) {
444 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
445 output = psi_plist_add(output, &entry);
446 }
447 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
448
449 while (psi_plist_shift(output, &entry)) {
450 switch (entry.type) {
451 default:
452 input = psi_plist_add(input, &entry);
453 break;
454
455 case PSI_T_NOT:
456 case PSI_T_TILDE:
457 psi_plist_pop(input, &rhs);
458 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
459 psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
460
461 entry.type = entry.data.calc(rhs.type, &rhs.data.value, 0, NULL, &entry.data.value);
462 input = psi_plist_add(input, &entry);
463 psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
464 break;
465
466 case PSI_T_PIPE:
467 case PSI_T_CARET:
468 case PSI_T_AMPERSAND:
469 case PSI_T_LSHIFT:
470 case PSI_T_RSHIFT:
471 case PSI_T_MINUS:
472 case PSI_T_PLUS:
473 case PSI_T_ASTERISK:
474 case PSI_T_SLASH:
475 case PSI_T_MODULO:
476 psi_plist_pop(input, &rhs);
477 psi_plist_pop(input, &lhs);
478
479 psi_impl_val_dump(lhs.type, &lhs.data.value, frame);
480 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
481 psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
482
483 entry.type = entry.data.calc(
484 lhs.type, &lhs.data.value,
485 rhs.type, &rhs.data.value,
486 &entry.data.value);
487 input = psi_plist_add(input, &entry);
488 psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
489 break;
490 }
491
492 if (!psi_plist_count(output)) {
493 break;
494 }
495 }
496
497 psi_plist_free(output);
498 psi_plist_free(input);
499
500 *res = entry.data.value;
501 return entry.type;
502 }
503