cpp
[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_DOUBLE:
211 dprintf(fd, "%F", exp->data.ival.dval);
212 break;
213 #if HAVE_LONG_DOUBLE
214 case PSI_T_LONG_DOUBLE:
215 dprintf(fd, "%lF", exp->data.ival.ldval);
216 break;
217 #endif
218 case PSI_T_NUMBER:
219 case PSI_T_NSNAME:
220 case PSI_T_DEFINE:
221 case PSI_T_QUOTED_CHAR:
222 dprintf(fd, "%s", exp->data.numb);
223 break;
224 case PSI_T_CONST:
225 dprintf(fd, "%s", exp->data.cnst->name);
226 break;
227 case PSI_T_ENUM:
228 dprintf(fd, "%s", exp->data.enm->name);
229 break;
230 case PSI_T_NAME:
231 psi_decl_var_dump(fd, exp->data.dvar);
232 break;
233 default:
234 assert(0);
235 }
236 }
237
238 static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
239 struct psi_decl_enum *enm)
240 {
241 size_t i = 0;
242 struct psi_decl_enum_item *itm;
243
244 while (psi_plist_get(enm->items, i++, &itm)) {
245 if (!strcmp(itm->name, exp->data.dvar->name)) {
246 psi_decl_var_free(&exp->data.dvar);
247 exp->type = PSI_T_ENUM;
248 exp->data.enm = itm;
249 return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
250 }
251 }
252
253 return false;
254 }
255
256 static inline bool psi_number_validate_char(struct psi_data *data, struct psi_number *exp)
257 {
258 impl_val tmp = {0};
259 /* FIXME L */
260 tmp.i8 = exp->data.numb[1 + (*exp->data.numb == 'L')];
261 switch(tmp.i8) {
262 case '\\':
263 tmp.i8 = exp->data.numb[2 + (*exp->data.numb == 'L')];
264 switch(tmp.i8) {
265 case 'x':
266 tmp.i8 = strtol(&exp->data.numb[3 + (*exp->data.numb == 'L')], NULL, 16);
267 free(exp->data.numb);
268 exp->type = PSI_T_INT8;
269 exp->data.ival.i8 = tmp.i8;
270 return true;
271 case '\'':
272 free(exp->data.numb);
273 exp->type = PSI_T_INT8;
274 exp->data.ival.i8 = '\'';
275 return true;
276 case 'a':
277 free(exp->data.numb);
278 exp->type = PSI_T_INT8;
279 exp->data.ival.i8 = '\a';
280 return true;
281 case 'b':
282 free(exp->data.numb);
283 exp->type = PSI_T_INT8;
284 exp->data.ival.i8 = '\b';
285 return true;
286 case 'f':
287 free(exp->data.numb);
288 exp->type = PSI_T_INT8;
289 exp->data.ival.i8 = '\f';
290 return true;
291 case 'n':
292 free(exp->data.numb);
293 exp->type = PSI_T_INT8;
294 exp->data.ival.i8 = '\n';
295 return true;
296 case 'r':
297 free(exp->data.numb);
298 exp->type = PSI_T_INT8;
299 exp->data.ival.i8 = '\r';
300 return true;
301 case 't':
302 free(exp->data.numb);
303 exp->type = PSI_T_INT8;
304 exp->data.ival.i8 = '\t';
305 return true;
306 case 'v':
307 free(exp->data.numb);
308 exp->type = PSI_T_INT8;
309 exp->data.ival.i8 = '\v';
310 return true;
311 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
312 tmp.i8 = strtol(&exp->data.numb[2 + (*exp->data.numb == 'L')], NULL, 8);
313 free(exp->data.numb);
314 exp->type = PSI_T_INT8;
315 exp->data.ival.i8 = tmp.i8;
316 return true;
317 default:
318 free(exp->data.numb);
319 exp->type = PSI_T_INT8;
320 exp->data.ival.i8 = tmp.i8;
321 return true;
322 }
323 break;
324 default:
325 free(exp->data.numb);
326 exp->type = PSI_T_INT8;
327 exp->data.ival.i8 = tmp.i8;
328 return true;
329 }
330 }
331
332 static inline bool psi_number_validate_number(struct psi_data *data, struct psi_number *exp)
333 {
334 impl_val tmp = {0};
335
336 if (exp->flags) {
337 switch (exp->flags & 0x0f) {
338 case PSI_NUMBER_INT:
339 switch (exp->flags & 0x0f00) {
340 case PSI_NUMBER_L:
341 default:
342 tmp.i64 = strtol(exp->data.numb, NULL, 0);
343 free(exp->data.numb);
344 exp->type = PSI_T_INT64;
345 exp->data.ival.i64 = tmp.i64;
346 break;
347 case PSI_NUMBER_LL:
348 tmp.i64 = strtoll(exp->data.numb, NULL, 0);
349 free(exp->data.numb);
350 exp->type = PSI_T_INT64;
351 exp->data.ival.i64 = tmp.i64;
352 break;
353 case PSI_NUMBER_U:
354 case PSI_NUMBER_UL:
355 tmp.u64 = strtoul(exp->data.numb, NULL, 0);
356 free(exp->data.numb);
357 exp->type = PSI_T_UINT64;
358 exp->data.ival.u64 = tmp.u64;
359 break;
360 case PSI_NUMBER_ULL:
361 tmp.u64 = strtoull(exp->data.numb, NULL, 0);
362 free(exp->data.numb);
363 exp->type = PSI_T_UINT64;
364 exp->data.ival.u64 = tmp.u64;
365 break;
366 }
367 return true;
368
369 case PSI_NUMBER_FLT:
370 switch (exp->flags & 0x0ff00) {
371 case PSI_NUMBER_F:
372 case PSI_NUMBER_DF:
373 tmp.fval = strtof(exp->data.numb, NULL);
374 free(exp->data.numb);
375 exp->type = PSI_T_FLOAT;
376 exp->data.ival.fval = tmp.fval;
377 break;
378 case PSI_NUMBER_L:
379 case PSI_NUMBER_DL:
380 #if HAVE_LONG_DOUBLE
381 tmp.ldval = strtold(exp->data.numb, NULL);
382 free(exp->data.numb);
383 exp->type = PSI_T_LONG_DOUBLE;
384 exp->data.ival.ldval = tmp.ldval;
385 break;
386 #endif
387 case PSI_NUMBER_DD:
388 default:
389 tmp.dval = strtod(exp->data.numb, NULL);
390 free(exp->data.numb);
391 exp->type = PSI_T_DOUBLE;
392 exp->data.ival.dval = tmp.dval;
393 break;
394 }
395 return true;
396 default:
397 assert(0);
398 break;
399 }
400 } else {
401 switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 1)) {
402 case IS_LONG:
403 free(exp->data.numb);
404 exp->type = PSI_T_INT64;
405 exp->data.ival.i64 = tmp.zend.lval;
406 return true;
407
408 case IS_DOUBLE:
409 free(exp->data.numb);
410 exp->type = PSI_T_DOUBLE;
411 exp->data.ival.dval = tmp.dval;
412 return true;
413 }
414 }
415 data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
416 return false;
417
418 }
419 bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
420 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
421 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
422 {
423 size_t i = 0;
424 struct psi_const *cnst;
425 struct psi_decl_enum *enm;
426
427 switch (exp->type) {
428 case PSI_T_CONST:
429 case PSI_T_INT8:
430 case PSI_T_UINT8:
431 case PSI_T_INT16:
432 case PSI_T_UINT16:
433 case PSI_T_INT32:
434 case PSI_T_UINT32:
435 case PSI_T_INT64:
436 case PSI_T_UINT64:
437 case PSI_T_DOUBLE:
438 #if HAVE_LONG_DOUBLE
439 case PSI_T_LONG_DOUBLE:
440 #endif
441 case PSI_T_ENUM:
442 case PSI_T_DEFINE:
443 case PSI_T_FUNCTION:
444 return true;
445
446 case PSI_T_NAME:
447 if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
448 return true;
449 }
450 while (psi_plist_get(data->enums, i++, &enm)) {
451 if (psi_number_validate_enum(data, exp, enm)) {
452 return true;
453 }
454 }
455 if (exp->data.dvar->arg) {
456 return true;
457 }
458 if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
459 current_let, current_set)) {
460 return true;
461 }
462 if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
463 return true;
464 }
465 data->error(data, exp->token, PSI_WARNING,
466 "Unknown variable '%s' in numeric expression",
467 exp->data.dvar->name);
468 return false;
469
470 case PSI_T_NSNAME:
471 while (psi_plist_get(data->consts, i++, &cnst)) {
472 if (!strcmp(cnst->name, exp->data.numb)) {
473 free(exp->data.numb);
474 exp->type = PSI_T_CONST;
475 exp->data.cnst = cnst;
476 return true;
477 }
478 }
479 data->error(data, exp->token, PSI_WARNING,
480 "Unknown constant '%s' in numeric expression",
481 exp->data.numb);
482 return false;
483
484 case PSI_T_NUMBER:
485 return psi_number_validate_number(data, exp);
486
487 case PSI_T_QUOTED_CHAR:
488 return psi_number_validate_char(data, exp);
489
490 default:
491 assert(0);
492 }
493
494 return false;
495 }
496
497 #include "Zend/zend_constants.h"
498
499 static inline token_t psi_number_eval_constant(struct psi_number *exp,
500 impl_val *res, struct psi_call_frame *frame)
501 {
502 switch (exp->data.cnst->type->type) {
503 case PSI_T_INT:
504 res->i64 = zend_get_constant_str(exp->data.cnst->name,
505 strlen(exp->data.cnst->name))->value.lval;
506 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
507 return PSI_T_INT64;
508 case PSI_T_FLOAT:
509 res->dval = zend_get_constant_str(exp->data.cnst->name,
510 strlen(exp->data.cnst->name))->value.dval;
511 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
512 return PSI_T_DOUBLE;
513 default:
514 if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%d)", exp->data.cnst->type->type);
515 return 0;
516 }
517 }
518
519
520 static inline token_t psi_number_eval_decl_var(struct psi_number *exp,
521 impl_val *res, struct psi_call_frame *frame)
522 {
523 impl_val *ref;
524 struct psi_call_frame_symbol *sym;
525 struct psi_decl_type *real;
526 size_t size;
527
528 real = psi_decl_type_get_real(exp->data.dvar->arg->type);
529 size = psi_decl_arg_get_size(exp->data.dvar->arg);
530 sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar);
531 ref = deref_impl_val(sym->ptr, exp->data.dvar);
532
533 memcpy(res, ref, size);
534
535 return real->type;
536 }
537
538 static inline token_t psi_number_eval_define(struct psi_number *exp,
539 impl_val *res, HashTable *defs)
540 {
541 struct psi_cpp_macro_decl *macro = zend_hash_str_find_ptr(defs, exp->data.numb, strlen(exp->data.numb));
542
543 assert(!macro);
544
545 res->u8 = 0;
546 return PSI_T_UINT8;
547 }
548
549 token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame, HashTable *defs)
550 {
551 switch (exp->type) {
552 case PSI_T_INT8:
553 *res = exp->data.ival;
554 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
555 return PSI_T_INT8;
556 case PSI_T_UINT8:
557 *res = exp->data.ival;
558 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu8, res->u8);
559 return PSI_T_UINT8;
560 case PSI_T_INT16:
561 *res = exp->data.ival;
562 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
563 return PSI_T_INT16;
564 case PSI_T_UINT16:
565 *res = exp->data.ival;
566 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu16, res->u16);
567 return PSI_T_UINT16;
568 case PSI_T_INT32:
569 *res = exp->data.ival;
570 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
571 return PSI_T_INT32;
572 case PSI_T_UINT32:
573 *res = exp->data.ival;
574 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu32, res->u32);
575 return PSI_T_UINT32;
576 case PSI_T_INT64:
577 *res = exp->data.ival;
578 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
579 return PSI_T_INT64;
580 case PSI_T_UINT64:
581 *res = exp->data.ival;
582 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIu64, res->u64);
583 return PSI_T_UINT64;
584
585 case PSI_T_DOUBLE:
586 *res = exp->data.ival;
587 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
588 return exp->type;
589
590 #if HAVE_LONG_DOUBLE
591 case PSI_T_LONG_DOUBLE:
592 *res = exp->data.ival;
593 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
594 return exp->type;
595 #endif
596
597 case PSI_T_ENUM:
598 res->i64 = exp->data.enm->val;
599 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
600 return PSI_T_INT64;
601
602 case PSI_T_CONST:
603 return psi_number_eval_constant(exp, res, frame);
604
605 case PSI_T_NAME:
606 return psi_number_eval_decl_var(exp, res, frame);
607
608 case PSI_T_DEFINE:
609 return psi_number_eval_define(exp, res, defs);
610
611 case PSI_T_FUNCTION:
612 res->u8 = 0;
613 return PSI_T_UINT8;
614
615 default:
616 assert(0);
617 }
618 return 0;
619 }