calc: boolean expressions
[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_OR:
91 case PSI_T_AND:
92
93 case PSI_T_CMP_EQ:
94 case PSI_T_CMP_NE:
95 case PSI_T_CMP_LE:
96 case PSI_T_CMP_GE:
97 case PSI_T_RCHEVR:
98 case PSI_T_LCHEVR:
99
100 case PSI_T_PIPE:
101 case PSI_T_CARET:
102 case PSI_T_AMPERSAND:
103 case PSI_T_LSHIFT:
104 case PSI_T_RSHIFT:
105 case PSI_T_PLUS:
106 case PSI_T_MINUS:
107 case PSI_T_ASTERISK:
108 case PSI_T_SLASH:
109 case PSI_T_MODULO:
110 cpy->data.b.lhs = psi_num_exp_copy(exp->data.b.lhs);
111 cpy->data.b.rhs = psi_num_exp_copy(exp->data.b.rhs);
112 break;
113
114 default:
115 assert(0);
116 }
117
118 if (exp->token) {
119 cpy->token = psi_token_copy(exp->token);
120 }
121
122 return cpy;
123 }
124
125 void psi_num_exp_free(struct psi_num_exp **c_ptr)
126 {
127 if (*c_ptr) {
128 struct psi_num_exp *c = *c_ptr;
129
130 *c_ptr = NULL;
131
132 switch (c->op) {
133 case 0:
134 psi_number_free(&c->data.n);
135 break;
136 case PSI_T_NOT:
137 case PSI_T_TILDE:
138 case PSI_T_LPAREN:
139 psi_num_exp_free(&c->data.u);
140 break;
141
142 case PSI_T_OR:
143 case PSI_T_AND:
144
145 case PSI_T_CMP_EQ:
146 case PSI_T_CMP_NE:
147 case PSI_T_CMP_LE:
148 case PSI_T_CMP_GE:
149 case PSI_T_RCHEVR:
150 case PSI_T_LCHEVR:
151
152 case PSI_T_PIPE:
153 case PSI_T_CARET:
154 case PSI_T_AMPERSAND:
155 case PSI_T_LSHIFT:
156 case PSI_T_RSHIFT:
157 case PSI_T_PLUS:
158 case PSI_T_MINUS:
159 case PSI_T_ASTERISK:
160 case PSI_T_SLASH:
161 case PSI_T_MODULO:
162 psi_num_exp_free(&c->data.b.lhs);
163 psi_num_exp_free(&c->data.b.rhs);
164 break;
165
166 default:
167 assert(0);
168 }
169
170 if (c->token) {
171 free(c->token);
172 }
173
174 free(c);
175 }
176 }
177
178 static inline wint_t psi_num_exp_op_tok(token_t op)
179 {
180 switch (op) {
181 case PSI_T_NOT:
182 return L'!';
183 case PSI_T_TILDE:
184 return L'~';
185 case PSI_T_LPAREN:
186 return L'(';
187
188 case PSI_T_PIPE:
189 return L'|';
190 case PSI_T_CARET:
191 return L'^';
192 case PSI_T_AMPERSAND:
193 return L'&';
194
195 case PSI_T_LSHIFT:
196 return L'«';
197 case PSI_T_RSHIFT:
198 return L'»';
199
200 case PSI_T_PLUS:
201 return L'+';
202 case PSI_T_MINUS:
203 return L'-';
204
205 case PSI_T_ASTERISK:
206 return L'*';
207 case PSI_T_SLASH:
208 return L'/';
209 case PSI_T_MODULO:
210 return L'%';
211
212 case PSI_T_OR:
213 return L'∨';
214 case PSI_T_AND:
215 return L'∧';
216
217 case PSI_T_CMP_EQ:
218 return L'≣';
219 case PSI_T_CMP_NE:
220 return L'≠';
221 case PSI_T_CMP_LE:
222 return L'≤';
223 case PSI_T_CMP_GE:
224 return L'≥';
225 case PSI_T_RCHEVR:
226 return L'>';
227 case PSI_T_LCHEVR:
228 return L'<';
229
230 default:
231 assert(0);
232 }
233 return 0;
234 }
235
236 void psi_num_exp_dump(int fd, struct psi_num_exp *exp)
237 {
238 switch (exp->op) {
239 case 0:
240 psi_number_dump(fd, exp->data.n);
241 break;
242
243 case PSI_T_NOT:
244 case PSI_T_TILDE:
245 dprintf(fd, "%lc", psi_num_exp_op_tok(exp->op));
246 psi_num_exp_dump(fd, exp->data.u);
247 break;
248
249 case PSI_T_LPAREN:
250 dprintf(fd, "(");
251 psi_num_exp_dump(fd, exp->data.u);
252 dprintf(fd, ")");
253 break;
254
255
256 case PSI_T_OR:
257 case PSI_T_AND:
258
259 case PSI_T_CMP_EQ:
260 case PSI_T_CMP_NE:
261 case PSI_T_CMP_LE:
262 case PSI_T_CMP_GE:
263 case PSI_T_RCHEVR:
264 case PSI_T_LCHEVR:
265
266 case PSI_T_PIPE:
267 case PSI_T_CARET:
268 case PSI_T_AMPERSAND:
269 case PSI_T_LSHIFT:
270 case PSI_T_RSHIFT:
271 case PSI_T_PLUS:
272 case PSI_T_MINUS:
273 case PSI_T_ASTERISK:
274 case PSI_T_SLASH:
275 psi_num_exp_dump(fd, exp->data.b.lhs);
276 dprintf(fd, " %lc ", psi_num_exp_op_tok(exp->op));
277 psi_num_exp_dump(fd, exp->data.b.rhs);
278 break;
279
280 default:
281 assert(0);
282 }
283
284 }
285
286 bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
287 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
288 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
289 {
290 if (exp->op) {
291 switch (exp->op) {
292 case PSI_T_NOT:
293 exp->calc = psi_calc_not;
294 break;
295 case PSI_T_TILDE:
296 exp->calc = psi_calc_bin_not;
297 break;
298
299 case PSI_T_OR:
300 exp->calc = psi_calc_or;
301 break;
302 case PSI_T_AND:
303 exp->calc = psi_calc_and;
304 break;
305 case PSI_T_CMP_EQ:
306 exp->calc = psi_calc_cmp_eq;
307 break;
308 case PSI_T_CMP_NE:
309 exp->calc = psi_calc_cmp_ne;
310 break;
311 case PSI_T_CMP_LE:
312 exp->calc = psi_calc_cmp_le;
313 break;
314 case PSI_T_CMP_GE:
315 exp->calc = psi_calc_cmp_ge;
316 break;
317 case PSI_T_LCHEVR:
318 exp->calc = psi_calc_cmp_lt;
319 break;
320 case PSI_T_RCHEVR:
321 exp->calc = psi_calc_cmp_gt;
322 break;
323
324 case PSI_T_LPAREN:
325 break;
326
327 case PSI_T_PIPE:
328 exp->calc = psi_calc_bin_or;
329 break;
330 case PSI_T_CARET:
331 exp->calc = psi_calc_bin_xor;
332 break;
333 case PSI_T_AMPERSAND:
334 exp->calc = psi_calc_bin_and;
335 break;
336 case PSI_T_LSHIFT:
337 exp->calc = psi_calc_bin_lshift;
338 break;
339 case PSI_T_RSHIFT:
340 exp->calc = psi_calc_bin_rshift;
341 break;
342 case PSI_T_PLUS:
343 exp->calc = psi_calc_add;
344 break;
345 case PSI_T_MINUS:
346 exp->calc = psi_calc_sub;
347 break;
348 case PSI_T_ASTERISK:
349 exp->calc = psi_calc_mul;
350 break;
351 case PSI_T_SLASH:
352 exp->calc = psi_calc_div;
353 break;
354 case PSI_T_MODULO:
355 exp->calc = psi_calc_mod;
356 break;
357 default:
358 data->error(data, exp->token, PSI_WARNING,
359 "Unknown numeric operator (%d)", exp->op);
360 return false;
361 }
362 }
363
364 switch (exp->op) {
365 case 0:
366 return psi_number_validate(data, exp->data.n, impl, cb_decl, current_let, current_set, current_enum);
367
368 case PSI_T_NOT:
369 case PSI_T_TILDE:
370 case PSI_T_LPAREN:
371 return psi_num_exp_validate(data, exp->data.u, impl, cb_decl, current_let, current_set, current_enum);
372 break;
373
374 case PSI_T_OR:
375 case PSI_T_AND:
376
377 case PSI_T_CMP_EQ:
378 case PSI_T_CMP_NE:
379 case PSI_T_CMP_LE:
380 case PSI_T_CMP_GE:
381 case PSI_T_RCHEVR:
382 case PSI_T_LCHEVR:
383
384 case PSI_T_PIPE:
385 case PSI_T_CARET:
386 case PSI_T_AMPERSAND:
387 case PSI_T_LSHIFT:
388 case PSI_T_RSHIFT:
389 case PSI_T_PLUS:
390 case PSI_T_MINUS:
391 case PSI_T_ASTERISK:
392 case PSI_T_SLASH:
393 case PSI_T_MODULO:
394 return psi_num_exp_validate(data, exp->data.b.lhs, impl, cb_decl, current_let, current_set, current_enum)
395 && psi_num_exp_validate(data, exp->data.b.rhs, impl, cb_decl, current_let, current_set, current_enum);
396 default:
397 assert(0);
398 }
399
400 return false;
401 }
402
403 static inline void psi_impl_val_dump(token_t t, impl_val *res,
404 struct psi_call_frame *frame)
405 {
406 switch (t) {
407 case PSI_T_INT8:
408 case PSI_T_UINT8:
409 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
410 break;
411 case PSI_T_INT16:
412 case PSI_T_UINT16:
413 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
414 break;
415 case PSI_T_INT32:
416 case PSI_T_UINT32:
417 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
418 break;
419 case PSI_T_INT64:
420 case PSI_T_UINT64:
421 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
422 break;
423 case PSI_T_FLOAT:
424 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIfval, res->fval);
425 break;
426 case PSI_T_DOUBLE:
427 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
428 break;
429 default:
430 assert(0);
431 }
432 }
433
434 static inline void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
435 {
436 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", " = ");
437 psi_impl_val_dump(t, res, frame);
438 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
439 }
440
441 static inline int psi_num_exp_op_cmp(token_t op1, token_t op2)
442 {
443 if (PSI_T_LPAREN == op2) {
444 return -1;
445 } else if (PSI_T_LPAREN == op1) {
446 return 1;
447 } else if (op1 == op2) {
448 return 0;
449 } else if (!op1) {
450 return 1;
451 } else if (!op2) {
452 return -1;
453 }
454
455 return psi_token_oper_cmp(op1, op2);
456 }
457
458 static void psi_num_exp_reduce(struct psi_num_exp *exp, struct psi_plist **output_ptr,
459 struct psi_plist **input_ptr, struct psi_call_frame *frame)
460 {
461 struct psi_plist *output = *output_ptr, *input = *input_ptr;
462 struct element {
463 token_t type;
464 union {
465 impl_val value;
466 psi_calc calc;
467 } data;
468 } entry;
469
470 switch (exp->op) {
471 case 0:
472 entry.type = psi_number_eval(exp->data.n, &entry.data.value, frame);
473 output = psi_plist_add(output, &entry);
474 break;
475
476 case PSI_T_LPAREN:
477 entry.type = exp->op;
478 input = psi_plist_add(input, &entry);
479 psi_num_exp_reduce(exp->data.u, &output, &input, frame);
480 while (psi_plist_pop(input, &entry)) {
481 if (entry.type == PSI_T_LPAREN) {
482 break;
483 }
484 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
485 output = psi_plist_add(output, &entry);
486 }
487 break;
488
489 case PSI_T_NOT:
490 case PSI_T_TILDE:
491 while (psi_plist_top(input, &entry)) {
492 /* bail out if exp->op >= entry.type */
493 if (psi_num_exp_op_cmp(exp->op, entry.type) != 1) {
494 break;
495 }
496 psi_plist_pop(input, NULL);
497 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
498 output = psi_plist_add(output, &entry);
499 }
500 entry.type = exp->op;
501 entry.data.calc = exp->calc;
502 input = psi_plist_add(input, &entry);
503 psi_num_exp_reduce(exp->data.u, &output, &input, frame);
504 break;
505
506 default:
507 psi_num_exp_reduce(exp->data.b.lhs, &output, &input, frame);
508 while (psi_plist_top(input, &entry)) {
509 /* bail out if exp->op > entry.type */
510 if (psi_num_exp_op_cmp(exp->op, entry.type) == -1) {
511 break;
512 }
513 psi_plist_pop(input, NULL);
514 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
515 output = psi_plist_add(output, &entry);
516 }
517 entry.type = exp->op;
518 entry.data.calc = exp->calc;
519 input = psi_plist_add(input, &entry);
520 psi_num_exp_reduce(exp->data.b.rhs, &output, &input, frame);
521 break;
522 }
523
524 *output_ptr = output;
525 *input_ptr = input;
526 }
527
528 token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res,
529 struct psi_call_frame *frame)
530 {
531 struct psi_plist *output, *input;
532 struct element {
533 token_t type;
534 union {
535 impl_val value;
536 psi_calc calc;
537 } data;
538 } entry, lhs, rhs;
539
540 output = psi_plist_init_ex(sizeof(entry), NULL);
541 input = psi_plist_init_ex(sizeof(entry), NULL);
542
543 psi_num_exp_reduce(exp, &output, &input, frame);
544
545 while (psi_plist_pop(input, &entry)) {
546 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
547 output = psi_plist_add(output, &entry);
548 }
549 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
550
551 while (psi_plist_shift(output, &entry)) {
552 switch (entry.type) {
553 default:
554 input = psi_plist_add(input, &entry);
555 break;
556
557 case PSI_T_NOT:
558 case PSI_T_TILDE:
559 psi_plist_pop(input, &rhs);
560 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
561 psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
562
563 entry.type = entry.data.calc(rhs.type, &rhs.data.value, 0, NULL, &entry.data.value);
564 input = psi_plist_add(input, &entry);
565 psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
566 break;
567
568 case PSI_T_OR:
569 case PSI_T_AND:
570
571 case PSI_T_CMP_EQ:
572 case PSI_T_CMP_NE:
573 case PSI_T_CMP_LE:
574 case PSI_T_CMP_GE:
575 case PSI_T_RCHEVR:
576 case PSI_T_LCHEVR:
577
578 case PSI_T_PIPE:
579 case PSI_T_CARET:
580 case PSI_T_AMPERSAND:
581 case PSI_T_LSHIFT:
582 case PSI_T_RSHIFT:
583 case PSI_T_MINUS:
584 case PSI_T_PLUS:
585 case PSI_T_ASTERISK:
586 case PSI_T_SLASH:
587 case PSI_T_MODULO:
588 psi_plist_pop(input, &rhs);
589 psi_plist_pop(input, &lhs);
590
591 psi_impl_val_dump(lhs.type, &lhs.data.value, frame);
592 if (frame) PSI_DEBUG_PRINT(frame->context, " %lc", psi_num_exp_op_tok(entry.type));
593 psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
594
595 entry.type = entry.data.calc(
596 lhs.type, &lhs.data.value,
597 rhs.type, &rhs.data.value,
598 &entry.data.value);
599 input = psi_plist_add(input, &entry);
600 psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
601 break;
602 }
603
604 if (!psi_plist_count(output)) {
605 break;
606 }
607 }
608
609 psi_plist_free(output);
610 psi_plist_free(input);
611
612 *res = entry.data.value;
613 return entry.type;
614 }
615