b45e00ea2fe4126890ba97ac89b07823d4c2f26f
[m6w6/ext-psi] / src / types / number.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 "calc.h"
32 #include "call.h"
33 #include "parser.h"
34
35 struct psi_number *psi_number_init(token_t t, void *num, unsigned flags)
36 {
37 struct psi_number *exp = calloc(1, sizeof(*exp));
38
39 exp->flags = flags;
40 switch (exp->type = t) {
41 case PSI_T_INT8:
42 exp->data.ival.i8 = *(int8_t *) num;
43 break;
44 case PSI_T_UINT8:
45 exp->data.ival.u8 = *(uint8_t *) num;
46 break;
47 case PSI_T_INT16:
48 exp->data.ival.i16 = *(int16_t *) num;
49 break;
50 case PSI_T_UINT16:
51 exp->data.ival.u16 = *(uint16_t *) num;
52 break;
53 case PSI_T_INT32:
54 exp->data.ival.i32 = *(int32_t *) num;
55 break;
56 case PSI_T_UINT32:
57 exp->data.ival.u32 = *(uint32_t *) num;
58 break;
59 case PSI_T_INT64:
60 exp->data.ival.i64 = *(int64_t *) num;
61 break;
62 case PSI_T_UINT64:
63 exp->data.ival.u64 = *(uint64_t *) num;
64 break;
65 case PSI_T_FLOAT:
66 exp->data.ival.dval = *(float *) num;
67 exp->type = PSI_T_DOUBLE;
68 break;
69 case PSI_T_DOUBLE:
70 exp->data.ival.dval = *(double *) num;
71 break;
72 #if HAVE_LONG_DOUBLE
73 case PSI_T_LONG_DOUBLE:
74 exp->data.ival.ldval = *(long double *) num;
75 break;
76 #endif
77 case PSI_T_QUOTED_CHAR:
78 case PSI_T_NUMBER:
79 case PSI_T_NSNAME:
80 case PSI_T_DEFINE:
81 exp->data.numb = strdup(num);
82 break;
83 case PSI_T_NAME:
84 exp->data.dvar = num;
85 break;
86 case PSI_T_FUNCTION:
87 exp->data.call = num;
88 break;
89 case PSI_T_SIZEOF:
90 exp->data.dtyp = num;
91 break;
92 default:
93 assert(0);
94 }
95
96 return exp;
97 }
98
99 struct psi_number *psi_number_copy(struct psi_number *exp)
100 {
101 struct psi_number *num = calloc(1, sizeof(*num));
102
103 *num = *exp;
104
105 if (num->token) {
106 num->token = psi_token_copy(num->token);
107 }
108 switch (num->type) {
109 case PSI_T_INT8:
110 case PSI_T_UINT8:
111 case PSI_T_INT16:
112 case PSI_T_UINT16:
113 case PSI_T_INT32:
114 case PSI_T_UINT32:
115 case PSI_T_INT64:
116 case PSI_T_UINT64:
117 case PSI_T_DOUBLE:
118 #if HAVE_LONG_DOUBLE
119 case PSI_T_LONG_DOUBLE:
120 #endif
121 case PSI_T_ENUM:
122 case PSI_T_CONST:
123 break;
124 case PSI_T_NUMBER:
125 case PSI_T_NSNAME:
126 case PSI_T_DEFINE:
127 case PSI_T_QUOTED_CHAR:
128 num->data.numb = strdup(num->data.numb);
129 break;
130 case PSI_T_NAME:
131 num->data.dvar = psi_decl_var_copy(num->data.dvar);
132 break;
133 case PSI_T_FUNCTION:
134 num->data.call = psi_cpp_macro_call_copy(num->data.call);
135 break;
136 case PSI_T_SIZEOF:
137 num->data.dtyp = psi_decl_type_copy(num->data.dtyp);
138 break;
139 default:
140 assert(0);
141 }
142 return num;
143 }
144
145 void psi_number_free(struct psi_number **exp_ptr)
146 {
147 if (*exp_ptr) {
148 struct psi_number *exp = *exp_ptr;
149
150 *exp_ptr = NULL;
151 if (exp->token) {
152 free(exp->token);
153 }
154 switch (exp->type) {
155 case PSI_T_INT8:
156 case PSI_T_UINT8:
157 case PSI_T_INT16:
158 case PSI_T_UINT16:
159 case PSI_T_INT32:
160 case PSI_T_UINT32:
161 case PSI_T_INT64:
162 case PSI_T_UINT64:
163 case PSI_T_DOUBLE:
164 #if HAVE_LONG_DOUBLE
165 case PSI_T_LONG_DOUBLE:
166 #endif
167 case PSI_T_ENUM:
168 case PSI_T_CONST:
169 break;
170 case PSI_T_FUNCTION:
171 psi_cpp_macro_call_free(&exp->data.call);
172 break;
173 case PSI_T_NSNAME:
174 case PSI_T_NUMBER:
175 case PSI_T_DEFINE:
176 case PSI_T_QUOTED_CHAR:
177 free(exp->data.numb);
178 break;
179 case PSI_T_NAME:
180 psi_decl_var_free(&exp->data.dvar);
181 break;
182 case PSI_T_SIZEOF:
183 psi_decl_type_free(&exp->data.dtyp);
184 break;
185 default:
186 assert(0);
187 }
188 free(exp);
189 }
190 }
191
192 void psi_number_dump(int fd, struct psi_number *exp)
193 {
194 switch (exp->type) {
195 case PSI_T_INT8:
196 dprintf(fd, "%" PRId8, exp->data.ival.i8);
197 break;
198 case PSI_T_UINT8:
199 dprintf(fd, "%" PRIu8, exp->data.ival.u8);
200 break;
201 case PSI_T_INT16:
202 dprintf(fd, "%" PRId16, exp->data.ival.i16);
203 break;
204 case PSI_T_UINT16:
205 dprintf(fd, "%" PRIu16, exp->data.ival.u16);
206 break;
207 case PSI_T_INT32:
208 dprintf(fd, "%" PRId32, exp->data.ival.i32);
209 break;
210 case PSI_T_UINT32:
211 dprintf(fd, "%" PRIu32, exp->data.ival.u32);
212 break;
213 case PSI_T_INT64:
214 dprintf(fd, "%" PRId64, exp->data.ival.i64);
215 break;
216 case PSI_T_UINT64:
217 dprintf(fd, "%" PRIu64, exp->data.ival.u64);
218 break;
219 case PSI_T_FLOAT:
220 dprintf(fd, "%" PRIfval, exp->data.ival.dval);
221 break;
222 case PSI_T_DOUBLE:
223 dprintf(fd, "%" PRIdval, exp->data.ival.dval);
224 break;
225 #if HAVE_LONG_DOUBLE
226 case PSI_T_LONG_DOUBLE:
227 dprintf(fd, "%" PRIldval, exp->data.ival.ldval);
228 break;
229 #endif
230 case PSI_T_NUMBER:
231 case PSI_T_NSNAME:
232 case PSI_T_DEFINE:
233 case PSI_T_QUOTED_CHAR:
234 dprintf(fd, "%s", exp->data.numb);
235 break;
236 case PSI_T_FUNCTION:
237 psi_cpp_macro_call_dump(fd, exp->data.call);
238 break;
239 case PSI_T_CONST:
240 dprintf(fd, "%s", exp->data.cnst->name);
241 break;
242 case PSI_T_ENUM:
243 dprintf(fd, "%s", exp->data.enm->name);
244 break;
245 case PSI_T_NAME:
246 psi_decl_var_dump(fd, exp->data.dvar);
247 break;
248 case PSI_T_SIZEOF:
249 psi_decl_type_dump(fd, exp->data.dtyp, 0);
250 break;
251 default:
252 assert(0);
253 }
254 }
255
256 static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
257 struct psi_decl_enum *enm)
258 {
259 size_t i = 0;
260 struct psi_decl_enum_item *itm;
261
262 while (psi_plist_get(enm->items, i++, &itm)) {
263 if (!strcmp(itm->name, exp->data.dvar->name)) {
264 psi_decl_var_free(&exp->data.dvar);
265 exp->type = PSI_T_ENUM;
266 exp->data.enm = itm;
267 return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
268 }
269 }
270
271 return false;
272 }
273
274 static inline token_t validate_char(char *numb, impl_val *res, unsigned *lvl)
275 {
276 char *endptr;
277 token_t typ = PSI_T_INT8;
278
279 res->i8 = numb[0];
280 endptr = &numb[1];
281
282 switch(res->i8) {
283 case '\\':
284 res->i8 = numb[1];
285 endptr = &numb[2];
286
287 switch(res->i8) {
288 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
289 res->i8 = strtol(&numb[1], &endptr, 8);
290 break;
291
292 case 'x':
293 res->i8 = strtol(&numb[2], &endptr, 16);
294 break;
295
296 case 'a':
297 res->i8 = '\a';
298 break;
299 case 'b':
300 res->i8 = '\b';
301 break;
302 case 'f':
303 res->i8 = '\f';
304 break;
305 case 'n':
306 res->i8 = '\n';
307 break;
308 case 'r':
309 res->i8 = '\r';
310 break;
311 case 't':
312 res->i8 = '\t';
313 break;
314 case 'v':
315 res->i8 = '\v';
316 break;
317 default:
318 break;
319 }
320 break;
321 default:
322 break;
323 }
324
325 /* more to grok? */
326 if (*endptr) {
327 impl_val tmp_val = {0};
328 token_t tmp_typ = validate_char(endptr, &tmp_val, lvl);
329
330 if (!tmp_typ) {
331 return 0;
332 }
333
334 res->i32 = res->i8 << (8 * *lvl);
335 typ = psi_calc_add(PSI_T_INT32, res, tmp_typ, &tmp_val, res);
336 }
337
338 ++(*lvl);
339
340 return typ;
341 }
342 static inline bool psi_number_validate_char(struct psi_data *data, struct psi_number *exp)
343 {
344 impl_val val = {0};
345 unsigned lvl = 1;
346 token_t typ = validate_char(exp->data.numb, &val, &lvl);
347
348 if (!typ) {
349 return false;
350 }
351
352 free(exp->data.numb);
353 exp->type = typ;
354 exp->data.ival = val;
355 return true;
356 }
357
358 static inline bool psi_number_validate_number(struct psi_data *data, struct psi_number *exp)
359 {
360 impl_val tmp = {0};
361
362 if (exp->flags) {
363 switch (exp->flags & 0x0f) {
364 case PSI_NUMBER_INT:
365 switch (exp->flags & 0x0f00) {
366 case PSI_NUMBER_L:
367 default:
368 tmp.i64 = strtol(exp->data.numb, NULL, 0);
369 free(exp->data.numb);
370 exp->type = PSI_T_INT64;
371 exp->data.ival.i64 = tmp.i64;
372 break;
373 case PSI_NUMBER_LL:
374 tmp.i64 = strtoll(exp->data.numb, NULL, 0);
375 free(exp->data.numb);
376 exp->type = PSI_T_INT64;
377 exp->data.ival.i64 = tmp.i64;
378 break;
379 case PSI_NUMBER_U:
380 case PSI_NUMBER_UL:
381 tmp.u64 = strtoul(exp->data.numb, NULL, 0);
382 free(exp->data.numb);
383 exp->type = PSI_T_UINT64;
384 exp->data.ival.u64 = tmp.u64;
385 break;
386 case PSI_NUMBER_ULL:
387 tmp.u64 = strtoull(exp->data.numb, NULL, 0);
388 free(exp->data.numb);
389 exp->type = PSI_T_UINT64;
390 exp->data.ival.u64 = tmp.u64;
391 break;
392 }
393 return true;
394
395 case PSI_NUMBER_FLT:
396 switch (exp->flags & 0x0ff00) {
397 case PSI_NUMBER_F:
398 case PSI_NUMBER_DF:
399 tmp.fval = strtof(exp->data.numb, NULL);
400 free(exp->data.numb);
401 exp->type = PSI_T_FLOAT;
402 exp->data.ival.fval = tmp.fval;
403 break;
404 case PSI_NUMBER_L:
405 case PSI_NUMBER_DL:
406 #if HAVE_LONG_DOUBLE
407 tmp.ldval = strtold(exp->data.numb, NULL);
408 free(exp->data.numb);
409 exp->type = PSI_T_LONG_DOUBLE;
410 exp->data.ival.ldval = tmp.ldval;
411 break;
412 #endif
413 case PSI_NUMBER_DD:
414 default:
415 tmp.dval = strtod(exp->data.numb, NULL);
416 free(exp->data.numb);
417 exp->type = PSI_T_DOUBLE;
418 exp->data.ival.dval = tmp.dval;
419 break;
420 }
421 return true;
422 default:
423 assert(0);
424 break;
425 }
426 } else {
427 switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 1)) {
428 case IS_LONG:
429 free(exp->data.numb);
430 exp->type = PSI_T_INT64;
431 exp->data.ival.i64 = tmp.zend.lval;
432 return true;
433
434 case IS_DOUBLE:
435 free(exp->data.numb);
436 exp->type = PSI_T_DOUBLE;
437 exp->data.ival.dval = tmp.dval;
438 return true;
439 }
440 }
441 data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
442 return false;
443
444 }
445 bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
446 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
447 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
448 {
449 size_t i = 0;
450 struct psi_const *cnst;
451 struct psi_decl_enum *enm;
452
453 switch (exp->type) {
454 case PSI_T_CONST:
455 case PSI_T_INT8:
456 case PSI_T_UINT8:
457 case PSI_T_INT16:
458 case PSI_T_UINT16:
459 case PSI_T_INT32:
460 case PSI_T_UINT32:
461 case PSI_T_INT64:
462 case PSI_T_UINT64:
463 case PSI_T_DOUBLE:
464 #if HAVE_LONG_DOUBLE
465 case PSI_T_LONG_DOUBLE:
466 #endif
467 case PSI_T_ENUM:
468 case PSI_T_DEFINE:
469 case PSI_T_FUNCTION:
470 return true;
471
472 case PSI_T_NAME:
473 if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
474 return true;
475 }
476 while (psi_plist_get(data->enums, i++, &enm)) {
477 if (psi_number_validate_enum(data, exp, enm)) {
478 return true;
479 }
480 }
481 if (exp->data.dvar->arg) {
482 return true;
483 }
484 if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
485 current_let, current_set)) {
486 return true;
487 }
488 if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
489 return true;
490 }
491 data->error(data, exp->token, PSI_WARNING,
492 "Unknown variable '%s' in numeric expression",
493 exp->data.dvar->name);
494 return false;
495
496 case PSI_T_SIZEOF:
497 if (psi_decl_type_validate(data, exp->data.dtyp, 0, NULL)) {
498 struct psi_decl_type *dtyp = exp->data.dtyp;
499
500 exp->type = PSI_T_UINT64;
501 exp->data.ival.u64 = psi_decl_type_get_size(dtyp, NULL);
502 return true;
503 }
504 break;
505
506 case PSI_T_NSNAME:
507 while (psi_plist_get(data->consts, i++, &cnst)) {
508 if (!strcmp(cnst->name, exp->data.numb)) {
509 free(exp->data.numb);
510 exp->type = PSI_T_CONST;
511 exp->data.cnst = cnst;
512 return true;
513 }
514 }
515 data->error(data, exp->token, PSI_WARNING,
516 "Unknown constant '%s' in numeric expression",
517 exp->data.numb);
518 return false;
519
520 case PSI_T_NUMBER:
521 return psi_number_validate_number(data, exp);
522
523 case PSI_T_QUOTED_CHAR:
524 return psi_number_validate_char(data, exp);
525
526 default:
527 assert(0);
528 }
529
530 return false;
531 }
532
533 #include "Zend/zend_constants.h"
534
535 static inline token_t psi_number_eval_constant(struct psi_number *exp,
536 impl_val *res, struct psi_call_frame *frame)
537 {
538 switch (exp->data.cnst->type->type) {
539 case PSI_T_INT:
540 res->i64 = zend_get_constant_str(exp->data.cnst->name,
541 strlen(exp->data.cnst->name))->value.lval;
542 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
543 return PSI_T_INT64;
544 case PSI_T_FLOAT:
545 res->dval = zend_get_constant_str(exp->data.cnst->name,
546 strlen(exp->data.cnst->name))->value.dval;
547 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
548 return PSI_T_DOUBLE;
549 default:
550 if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%d)", exp->data.cnst->type->type);
551 return 0;
552 }
553 }
554
555
556 static inline token_t psi_number_eval_decl_var(struct psi_number *exp,
557 impl_val *res, struct psi_call_frame *frame)
558 {
559 impl_val *ref;
560 struct psi_call_frame_symbol *sym;
561 struct psi_decl_type *real;
562 size_t size;
563
564 real = psi_decl_type_get_real(exp->data.dvar->arg->type);
565 size = psi_decl_arg_get_size(exp->data.dvar->arg);
566 sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar);
567 ref = deref_impl_val(sym->ptr, exp->data.dvar);
568
569 memcpy(res, ref, size);
570
571 return real->type;
572 }
573
574 static inline token_t psi_number_eval_define(struct psi_number *exp,
575 impl_val *res, HashTable *defs)
576 {
577 struct psi_cpp_macro_decl *macro = zend_hash_str_find_ptr(defs, exp->data.numb, strlen(exp->data.numb));
578
579 assert(!macro);
580
581 res->u8 = 0;
582 return PSI_T_UINT8;
583 }
584
585 token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame, HashTable *defs)
586 {
587 switch (exp->type) {
588 case PSI_T_INT8:
589 *res = exp->data.ival;
590 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
591 return PSI_T_INT8;
592 case PSI_T_UINT8:
593 *res = exp->data.ival;
594 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu8, res->u8);
595 return PSI_T_UINT8;
596 case PSI_T_INT16:
597 *res = exp->data.ival;
598 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
599 return PSI_T_INT16;
600 case PSI_T_UINT16:
601 *res = exp->data.ival;
602 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu16, res->u16);
603 return PSI_T_UINT16;
604 case PSI_T_INT32:
605 *res = exp->data.ival;
606 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
607 return PSI_T_INT32;
608 case PSI_T_UINT32:
609 *res = exp->data.ival;
610 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu32, res->u32);
611 return PSI_T_UINT32;
612 case PSI_T_INT64:
613 *res = exp->data.ival;
614 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
615 return PSI_T_INT64;
616 case PSI_T_UINT64:
617 *res = exp->data.ival;
618 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu64, res->u64);
619 return PSI_T_UINT64;
620
621 case PSI_T_DOUBLE:
622 *res = exp->data.ival;
623 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
624 return exp->type;
625
626 #if HAVE_LONG_DOUBLE
627 case PSI_T_LONG_DOUBLE:
628 *res = exp->data.ival;
629 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIldval, res->ldval);
630 return exp->type;
631 #endif
632
633 case PSI_T_ENUM:
634 res->i64 = exp->data.enm->val;
635 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
636 return PSI_T_INT64;
637
638 case PSI_T_NUMBER:
639 res->i64 = atol(exp->data.numb);
640 return PSI_T_INT64;
641
642 case PSI_T_CONST:
643 return psi_number_eval_constant(exp, res, frame);
644
645 case PSI_T_NAME:
646 return psi_number_eval_decl_var(exp, res, frame);
647
648 case PSI_T_DEFINE:
649 return psi_number_eval_define(exp, res, defs);
650
651 case PSI_T_FUNCTION:
652 res->u8 = 0;
653 return PSI_T_UINT8;
654
655 default:
656 assert(0);
657 }
658 return 0;
659 }