fix float formats; fix sime defval edge cases
[m6w6/ext-psi] / src / types / impl_def_val.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 #include "data.h"
28
29 #include "zend_smart_str.h"
30
31 #include <assert.h>
32 #include <math.h>
33
34 #define PSI_IMPL_DEF_VAL_DEBUG 0
35
36 struct psi_impl_def_val *psi_impl_def_val_init(token_t t, void *data)
37 {
38 struct psi_impl_def_val *def = pecalloc(1, sizeof(*def), 1);
39
40 switch ((def->type = t)) {
41 case PSI_T_TRUE:
42 def->ival.zend.bval = 1;
43 /* no break */
44 case PSI_T_FALSE:
45 def->ityp = PSI_T_UINT8;
46 /* no break */
47 case PSI_T_NULL:
48 break;
49 case PSI_T_QUOTED_STRING:
50 /* immediate upgrade */
51 def->type = PSI_T_STRING;
52 /* no break */
53 case PSI_T_STRING:
54 if (data) {
55 def->ival.zend.str = zend_string_copy(data);
56 }
57 break;
58
59 case PSI_T_NUMBER:
60 def->data.num = data;
61 break;
62
63 default:
64 assert(0);
65 }
66
67 return def;
68 }
69
70 void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr)
71 {
72 if (*def_ptr) {
73 struct psi_impl_def_val *def = *def_ptr;
74
75 *def_ptr = NULL;
76 psi_token_free(&def->token);
77 switch (def->type) {
78 case PSI_T_NUMBER:
79 psi_num_exp_free(&def->data.num);
80 break;
81
82 case PSI_T_STRING:
83 if (def->ival.zend.str) {
84 zend_string_release(def->ival.zend.str);
85 }
86 break;
87 default:
88 break;
89 }
90 free(def);
91 }
92 }
93
94 void psi_impl_def_val_get_zval(struct psi_impl_def_val *val, token_t typ, zval *zv)
95 {
96 impl_val tmp = val->ival;
97
98 /* c->val has already been forced to the type of the containing constant or impl_arg */
99 switch (typ) {
100 case PSI_T_BOOL:
101 ZVAL_BOOL(zv, tmp.zend.bval);
102 break;
103 case PSI_T_INT:
104 ZVAL_LONG(zv, tmp.zend.lval);
105 break;
106 case PSI_T_FLOAT:
107 case PSI_T_DOUBLE:
108 is_double: ;
109 ZVAL_DOUBLE(zv, tmp.dval);
110 break;
111 case PSI_T_STRING:
112 is_string: ;
113 ZVAL_NEW_STR(zv, zend_string_copy(tmp.zend.str));
114 if (ZSTR_IS_INTERNED(Z_STR_P(zv))) {
115 Z_TYPE_FLAGS_P(zv) = 0;
116 }
117 break;
118 case PSI_T_MIXED:
119 switch (val->type) {
120 case PSI_T_NULL:
121 ZVAL_NULL(zv);
122 break;
123 case PSI_T_TRUE:
124 ZVAL_TRUE(zv);
125 break;
126 case PSI_T_FALSE:
127 ZVAL_FALSE(zv);
128 break;
129 case PSI_T_STRING:
130 goto is_string;
131 break;
132 case PSI_T_NUMBER:
133 switch (val->ityp) {
134 case PSI_T_INT8:
135 case PSI_T_UINT8:
136 case PSI_T_INT16:
137 case PSI_T_UINT16:
138 case PSI_T_INT32:
139 case PSI_T_UINT32:
140 psi_calc_cast(val->ityp, &tmp, PSI_T_INT64, &tmp);
141 /* no break */
142 case PSI_T_INT64:
143 ZVAL_LONG(zv, tmp.i64);
144 break;
145 case PSI_T_UINT64:
146 ZVAL_LONG_DOUBLE_STR(zv, tmp.u64, is_signed=false;persistent=true);
147 break;
148 #if HAVE_INT128
149 case PSI_T_INT128:
150 ZVAL_LONG_DOUBLE_STR(zv, tmp.i128, is_signed=true;persistent=true);
151 break;
152 case PSI_T_UINT128:
153 ZVAL_LONG_DOUBLE_STR(zv, tmp.u128, is_signed=false;persistent=true);
154 #endif
155 break;
156 case PSI_T_FLOAT:
157 ZVAL_DOUBLE(zv, tmp.fval);
158 break;
159 case PSI_T_DOUBLE:
160 goto is_double;
161 break;
162 #if HAVE_LONG_DOUBLE
163 case PSI_T_LONG_DOUBLE:
164 ZVAL_DOUBLE(zv, tmp.ldval);
165 break;
166 #endif
167 default:
168 assert(0);
169 }
170 break;
171 default:
172 assert(0);
173 break;
174 }
175 break;
176 default:
177 assert(0);
178 break;
179 }
180
181 }
182
183 static inline bool psi_impl_def_val_validate_impl_type(struct psi_data *data,
184 struct psi_impl_def_val *val, struct psi_impl_type *type,
185 struct psi_validate_scope *scope)
186 {
187 switch (type->type) {
188 case PSI_T_BOOL:
189 switch (val->type) {
190 case PSI_T_TRUE:
191 case PSI_T_FALSE:
192 return true;
193 case PSI_T_STRING:
194 if (val->ival.zend.str) {
195 zend_string *tmp = val->ival.zend.str;
196
197 val->ival.zend.bval = (*tmp->val && *tmp->val != '0');
198 zend_string_release(tmp);
199 }
200 val->ityp = PSI_T_UINT8;
201 val->type = PSI_T_BOOL;
202 return true;
203 default:
204 assert(0);
205 break;
206 }
207 break;
208 case PSI_T_INT:
209 if (val->type == PSI_T_STRING) {
210 zend_string *str = val->ival.zend.str;
211 switch (is_numeric_str_function(str, &val->ival.zend.lval, &val->ival.dval)) {
212 case IS_DOUBLE:
213 val->ival.zend.lval = zend_dval_to_lval_cap(val->ival.dval);
214 /* no break */
215 case IS_LONG:
216 break;
217 default:
218 val->ival.zend.lval = 0;
219 }
220 zend_string_release(str);
221 val->ityp = PSI_T_INT64;
222 return true;
223 }
224 psi_calc_cast(val->ityp, &val->ival, PSI_T_INT64, &val->ival);
225 val->type = PSI_T_INT;
226 val->ityp = PSI_T_INT64;
227 return true;
228 case PSI_T_FLOAT:
229 case PSI_T_DOUBLE:
230 if (val->type == PSI_T_STRING) {
231 zend_string *str = val->ival.zend.str;
232 switch (is_numeric_str_function(str, &val->ival.zend.lval, &val->ival.dval)) {
233 case IS_LONG:
234 val->ival.dval = val->ival.zend.lval;
235 /* no break */
236 case IS_DOUBLE:
237 break;
238 default:
239 val->ival.dval = 0;
240 }
241 zend_string_release(str);
242 val->type = val->ityp = PSI_T_DOUBLE;
243 return true;
244 }
245 psi_calc_cast(val->ityp, &val->ival, PSI_T_DOUBLE, &val->ival);
246 val->ityp = PSI_T_DOUBLE;
247 return true;
248 case PSI_T_STRING:
249 if (val->type == PSI_T_STRING) {
250 return true;
251 } else {
252 smart_str str = {0};
253 struct psi_dump dump = {{.hn = &str},
254 .fun = (psi_dump_cb) smart_str_append_printf};
255
256 switch (val->ityp) {
257 CASE_IMPLVAL_NUM_DUMP(&dump, val->ival, false);
258 default:
259 assert(0);
260 }
261 val->ival.zend.str = smart_str_extract(&str);
262 val->type = PSI_T_STRING;
263 return true;
264 }
265 break;
266 default:
267 data->error(data, val->token, PSI_WARNING,
268 "Invalid default value type '%s', "
269 "expected one of bool, int, float/double or string.",
270 type->name->val);
271
272 }
273 return false;
274 }
275
276 bool psi_impl_def_val_validate(struct psi_data *data,
277 struct psi_impl_def_val *val, struct psi_impl_type *type,
278 struct psi_validate_scope *scope)
279 {
280 /* NULL can be anything */
281 if (val->type == PSI_T_NULL) {
282 return true;
283 }
284
285 /* a number can be anything */
286 if (val->type == PSI_T_NUMBER) {
287 if (!psi_num_exp_validate(data, val->data.num, scope)) {
288 return false;
289 }
290 val->ityp = psi_num_exp_exec(val->data.num, &val->ival, NULL, scope->cpp);
291 }
292
293 /* forced type, like `const <type> foo`, or function param `<type> $xyz` */
294 if (type) {
295 return psi_impl_def_val_validate_impl_type(data, val, type, scope);
296 }
297
298 switch (val->type) {
299 case PSI_T_NUMBER:
300 case PSI_T_NULL:
301 case PSI_T_TRUE:
302 case PSI_T_FALSE:
303 case PSI_T_STRING:
304 return true;
305 default:
306 assert(0);
307 break;
308 }
309
310 return false;
311 }
312
313 void psi_impl_def_val_dump(struct psi_dump *dump, struct psi_impl_def_val *val) {
314 switch (val->type) {
315 case PSI_T_NULL:
316 PSI_DUMP(dump, "NULL");
317 break;
318 case PSI_T_TRUE:
319 PSI_DUMP(dump, "true");
320 break;
321 case PSI_T_FALSE:
322 PSI_DUMP(dump, "false");
323 break;
324 case PSI_T_BOOL:
325 PSI_DUMP(dump, "%s", val->ival.zend.bval ? "true" : "false");
326 break;
327 case PSI_T_INT:
328 PSI_DUMP(dump, ZEND_LONG_FMT, val->ival.zend.lval);
329 break;
330 case PSI_T_FLOAT:
331 case PSI_T_DOUBLE:
332 if (isinf(val->ival.dval)) {
333 PSI_DUMP(dump, "\\INF");
334 } else if (isnan(val->ival.dval)) {
335 PSI_DUMP(dump, "\\NAN");
336 } else {
337 PSI_DUMP(dump, "%" PRIdval, val->ival.dval);
338 }
339 break;
340 case PSI_T_STRING:
341 PSI_DUMP(dump, "\"%s\"", val->ival.zend.str->val);
342 break;
343 case PSI_T_NUMBER:
344 psi_num_exp_dump(dump, val->data.num);
345 break;
346 default:
347 assert(0);
348 }
349 #if 0
350 PSI_DUMP(dump, "\t/* impl_def_val.type=%d */ ", val->type);
351 #endif
352 }