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