8b2d37b6029cf39f2aea10949179b0e8b9af7694
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
29 #include "zend_smart_str.h"
34 #define PSI_IMPL_DEF_VAL_DEBUG 0
36 struct psi_impl_def_val
*psi_impl_def_val_init(token_t t
, void *data
)
38 struct psi_impl_def_val
*def
= pecalloc(1, sizeof(*def
), 1);
40 switch ((def
->type
= t
)) {
42 def
->ival
.zend
.bval
= 1;
45 def
->ityp
= PSI_T_UINT8
;
49 case PSI_T_QUOTED_STRING
:
50 /* immediate upgrade */
51 def
->type
= PSI_T_STRING
;
55 def
->ival
.zend
.str
= zend_string_copy(data
);
70 void psi_impl_def_val_free(struct psi_impl_def_val
**def_ptr
)
73 struct psi_impl_def_val
*def
= *def_ptr
;
76 psi_token_free(&def
->token
);
79 psi_num_exp_free(&def
->data
.num
);
83 if (def
->ival
.zend
.str
) {
84 zend_string_release(def
->ival
.zend
.str
);
94 void psi_impl_def_val_get_zval(struct psi_impl_def_val
*val
, token_t typ
, zval
*zv
)
96 impl_val tmp
= val
->ival
;
98 /* c->val has already been forced to the type of the containing constant or impl_arg */
101 ZVAL_BOOL(zv
, tmp
.zend
.bval
);
104 ZVAL_LONG(zv
, tmp
.zend
.lval
);
109 ZVAL_DOUBLE(zv
, tmp
.dval
);
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;
140 psi_calc_cast(val
->ityp
, &tmp
, PSI_T_INT64
, &tmp
);
143 ZVAL_LONG(zv
, tmp
.i64
);
146 ZVAL_LONG_DOUBLE_STR(zv
, tmp
.u64
, is_signed
=false;persistent
=true);
150 ZVAL_LONG_DOUBLE_STR(zv
, tmp
.i128
, is_signed
=true;persistent
=true);
153 ZVAL_LONG_DOUBLE_STR(zv
, tmp
.u128
, is_signed
=false;persistent
=true);
157 ZVAL_DOUBLE(zv
, tmp
.fval
);
163 case PSI_T_LONG_DOUBLE
:
164 ZVAL_DOUBLE(zv
, tmp
.ldval
);
183 token_t psi_impl_def_val_get_zend(struct psi_impl_def_val *val, impl_val *res)
190 res->zend.bval = val->ival.zend.bval;
193 res->zend.str = val->ival.zend.str
194 ? zend_string_copy(val->ival.zend.str)
200 res->dval = val->ival.fval;
203 res->dval = val->ival.dval;
206 case PSI_T_LONG_DOUBLE:
207 res->dval = val->ival.ldval;
211 psi_calc_cast(val->ityp, &val->ival, PSI_T_INT64, res);
222 static inline bool psi_impl_def_val_validate_impl_type(struct psi_data
*data
,
223 struct psi_impl_def_val
*val
, struct psi_impl_type
*type
,
224 struct psi_validate_scope
*scope
)
226 switch (type
->type
) {
233 if (val
->ival
.zend
.str
234 && *val
->ival
.zend
.str
->val
235 && *val
->ival
.zend
.str
->val
!= '0') {
236 zend_string_release(val
->ival
.zend
.str
);
237 val
->ival
.zend
.bval
= 1;
239 if (val
->ival
.zend
.str
) {
240 zend_string_release(val
->ival
.zend
.str
);
242 val
->ival
.zend
.bval
= 0;
244 val
->ityp
= PSI_T_UINT8
;
252 if (val
->type
== PSI_T_STRING
) {
253 zend_string
*str
= val
->ival
.zend
.str
;
254 switch (is_numeric_str_function(str
, &val
->ival
.zend
.lval
, &val
->ival
.dval
)) {
256 val
->ival
.zend
.lval
= zend_dval_to_lval_cap(val
->ival
.dval
);
261 val
->ival
.zend
.lval
= 0;
263 zend_string_release(str
);
264 val
->ityp
= PSI_T_INT64
;
267 psi_calc_cast(val
->ityp
, &val
->ival
, PSI_T_INT64
, &val
->ival
);
268 val
->type
= val
->ityp
= PSI_T_INT64
;
272 if (val
->type
== PSI_T_STRING
) {
273 zend_string
*str
= val
->ival
.zend
.str
;
274 switch (is_numeric_str_function(str
, &val
->ival
.zend
.lval
, &val
->ival
.dval
)) {
276 val
->ival
.dval
= val
->ival
.zend
.lval
;
283 zend_string_release(str
);
284 val
->type
= val
->ityp
= PSI_T_DOUBLE
;
287 psi_calc_cast(val
->ityp
, &val
->ival
, PSI_T_DOUBLE
, &val
->ival
);
288 val
->ityp
= PSI_T_DOUBLE
;
291 if (val
->type
== PSI_T_STRING
) {
297 CASE_IMPLVAL_NUM_PRINTF(smart_str_append_printf
, &str
, val
->ival
, false);
301 val
->ival
.zend
.str
= smart_str_extract(&str
);
302 val
->type
= PSI_T_STRING
;
307 data
->error(data
, val
->token
, PSI_WARNING
,
308 "Invalid default value type '%s', "
309 "expected one of bool, int, float/double or string.",
316 bool psi_impl_def_val_validate(struct psi_data
*data
,
317 struct psi_impl_def_val
*val
, struct psi_impl_type
*type
,
318 struct psi_validate_scope
*scope
)
320 /* NULL can be anything */
321 if (val
->type
== PSI_T_NULL
) {
325 /* a number can be anything */
326 if (val
->type
== PSI_T_NUMBER
) {
327 if (!psi_num_exp_validate(data
, val
->data
.num
, scope
)) {
330 val
->ityp
= psi_num_exp_exec(val
->data
.num
, &val
->ival
, NULL
, scope
->cpp
);
333 /* forced type, like `const <type> foo`, or function param `<type> $xyz` */
335 return psi_impl_def_val_validate_impl_type(data
, val
, type
, scope
);
352 switch (type ? type->type : PSI_T_MIXED) {
354 val->ival.zend.bval = val->type == PSI_T_TRUE ? 1 : 0;
360 if (val->type == PSI_T_NUMBER) {
361 token_t typ = psi_num_exp_exec(val->data.num, &val->ival, NULL, scope->cpp);
365 val->ival.dval = val->ival.fval;
368 val->type = PSI_T_FLOAT;
369 type->type = PSI_T_FLOAT;
370 zend_string_release(type->name);
371 type->name = zend_string_init_interned(ZEND_STRL("float"), 1);
374 if (val->ival.u64 > ZEND_LONG_MAX) {
375 data->error(data, val->token, PSI_WARNING,
376 "Integer too big for signed representation: '%" PRIu64 "'",
380 // FIXME big integers
381 val->type = PSI_T_INT;
382 type->type = PSI_T_INT;
383 zend_string_release(type->name);
384 type->name = zend_string_init_interned(ZEND_STRL("int"), 1);
387 psi_num_exp_free(&val->data.num);
393 if (val->type == PSI_T_NUMBER) {
394 val->type = PSI_T_INT;
395 val->ival.zend.lval = psi_num_exp_get_long(val->data.num, NULL, scope->cpp);
396 #if PSI_IMPL_DEF_VAL_DEBUG
397 PSI_DEBUG_PRINT(data, "PSI: NUMBER (long) %" PRIi64 " from ", val->ival.zend.lval);
398 PSI_DEBUG_DUMP(data, psi_num_exp_dump, val->data.num);
399 PSI_DEBUG_PRINT(data, "\n");
401 psi_num_exp_free(&val->data.num);
403 if (val->type == PSI_T_INT) {
410 if (val->type == PSI_T_NUMBER) {
411 val->type = PSI_T_DOUBLE;
412 val->ival.dval = psi_num_exp_get_double(val->data.num, NULL, scope->cpp);
413 #if PSI_IMPL_DEF_VAL_DEBUG
414 PSI_DEBUG_PRINT(data, "PSI: NUMBER (double) %" PRIdval " from ", val->ival.dval);
415 PSI_DEBUG_DUMP(data, psi_num_exp_dump, val->data.num);
416 PSI_DEBUG_PRINT(data, "\n");
418 psi_num_exp_free(&val->data.num);
420 if (val->type == PSI_T_DOUBLE) {
426 if (val->type == PSI_T_STRING) {
427 return true; data->error(data, val->token, PSI_WARNING,
428 "Invalid default value type '%s', "
429 "expected one of bool, int, float, string.",
430 type ? type->name->val : "mixed");
444 void psi_impl_def_val_dump(struct psi_dump
*dump
, struct psi_impl_def_val
*val
) {
447 PSI_DUMP(dump
, "NULL");
450 PSI_DUMP(dump
, "true");
453 PSI_DUMP(dump
, "false");
456 PSI_DUMP(dump
, "%s", val
->ival
.zend
.bval
? "true" : "false");
459 PSI_DUMP(dump
, ZEND_LONG_FMT
, val
->ival
.zend
.lval
);
463 if (isinf(val
->ival
.dval
)) {
464 PSI_DUMP(dump
, "\\INF");
465 } else if (isnan(val
->ival
.dval
)) {
466 PSI_DUMP(dump
, "\\NAN");
468 PSI_DUMP(dump
, "%" PRIdval
, val
->ival
.dval
);
472 PSI_DUMP(dump
, "\"%s\"", val
->ival
.zend
.str
->val
);
475 psi_num_exp_dump(dump
, val
->data
.num
);
480 PSI_DUMP(dump
, "\t/* t=%d */ ", val
->type
);