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 *******************************************************************************/
29 # include "php_config.h"
33 #include "zend_smart_str.h"
38 #define PSI_IMPL_DEF_VAL_DEBUG 0
40 struct psi_impl_def_val
*psi_impl_def_val_init(token_t t
, void *data
)
42 struct psi_impl_def_val
*def
= pecalloc(1, sizeof(*def
), 1);
44 switch ((def
->type
= t
)) {
46 def
->ival
.zend
.bval
= 1;
49 def
->ityp
= PSI_T_UINT8
;
53 case PSI_T_QUOTED_STRING
:
54 /* immediate upgrade */
55 def
->type
= PSI_T_STRING
;
59 def
->ival
.zend
.str
= zend_string_copy(data
);
74 void psi_impl_def_val_free(struct psi_impl_def_val
**def_ptr
)
77 struct psi_impl_def_val
*def
= *def_ptr
;
80 psi_token_free(&def
->token
);
83 psi_num_exp_free(&def
->data
.num
);
87 if (def
->ival
.zend
.str
) {
88 zend_string_release(def
->ival
.zend
.str
);
98 void psi_impl_def_val_get_zval(struct psi_impl_def_val
*val
, token_t typ
, zval
*zv
)
100 impl_val tmp
= val
->ival
;
102 /* c->val has already been forced to the type of the containing constant or impl_arg */
105 ZVAL_BOOL(zv
, tmp
.zend
.bval
);
108 ZVAL_LONG(zv
, tmp
.zend
.lval
);
113 ZVAL_DOUBLE(zv
, tmp
.dval
);
117 ZVAL_NEW_STR(zv
, zend_string_copy(tmp
.zend
.str
));
118 if (ZSTR_IS_INTERNED(Z_STR_P(zv
))) {
119 Z_TYPE_FLAGS_P(zv
) = 0;
144 psi_calc_cast(val
->ityp
, &tmp
, PSI_T_INT64
, &tmp
);
147 ZVAL_LONG(zv
, tmp
.i64
);
150 ZVAL_LONG_DOUBLE_STR(zv
, tmp
.u64
, is_signed
=false;persistent
=true);
154 ZVAL_LONG_DOUBLE_STR(zv
, tmp
.i128
, is_signed
=true;persistent
=true);
157 ZVAL_LONG_DOUBLE_STR(zv
, tmp
.u128
, is_signed
=false;persistent
=true);
161 ZVAL_DOUBLE(zv
, tmp
.fval
);
167 case PSI_T_LONG_DOUBLE
:
168 ZVAL_DOUBLE(zv
, tmp
.ldval
);
187 static inline bool psi_impl_def_val_validate_impl_type(struct psi_data
*data
,
188 struct psi_impl_def_val
*val
, struct psi_impl_type
*type
,
189 struct psi_validate_scope
*scope
)
191 switch (type
->type
) {
198 if (val
->ival
.zend
.str
) {
199 zend_string
*tmp
= val
->ival
.zend
.str
;
201 val
->ival
.zend
.bval
= (*tmp
->val
&& *tmp
->val
!= '0');
202 zend_string_release(tmp
);
204 val
->ityp
= PSI_T_UINT8
;
205 val
->type
= PSI_T_BOOL
;
213 if (val
->type
== PSI_T_STRING
) {
214 zend_string
*str
= val
->ival
.zend
.str
;
215 switch (is_numeric_str_function(str
, &val
->ival
.zend
.lval
, &val
->ival
.dval
)) {
217 val
->ival
.zend
.lval
= zend_dval_to_lval_cap(val
->ival
.dval
);
222 val
->ival
.zend
.lval
= 0;
224 zend_string_release(str
);
225 val
->ityp
= PSI_T_INT64
;
228 psi_calc_cast(val
->ityp
, &val
->ival
, PSI_T_INT64
, &val
->ival
);
229 val
->type
= PSI_T_INT
;
230 val
->ityp
= PSI_T_INT64
;
234 if (val
->type
== PSI_T_STRING
) {
235 zend_string
*str
= val
->ival
.zend
.str
;
236 switch (is_numeric_str_function(str
, &val
->ival
.zend
.lval
, &val
->ival
.dval
)) {
238 val
->ival
.dval
= val
->ival
.zend
.lval
;
245 zend_string_release(str
);
246 val
->type
= val
->ityp
= PSI_T_DOUBLE
;
249 psi_calc_cast(val
->ityp
, &val
->ival
, PSI_T_DOUBLE
, &val
->ival
);
250 val
->ityp
= PSI_T_DOUBLE
;
253 if (val
->type
== PSI_T_STRING
) {
257 struct psi_dump dump
= {{.hn
= &str
},
258 .fun
= (psi_dump_cb
) smart_str_append_printf
};
261 CASE_IMPLVAL_NUM_DUMP(&dump
, val
->ival
, false);
265 val
->ival
.zend
.str
= smart_str_extract(&str
);
266 val
->type
= PSI_T_STRING
;
271 data
->error(data
, val
->token
, PSI_WARNING
,
272 "Invalid default value type '%s', "
273 "expected one of bool, int, float/double or string.",
280 bool psi_impl_def_val_validate(struct psi_data
*data
,
281 struct psi_impl_def_val
*val
, struct psi_impl_type
*type
,
282 struct psi_validate_scope
*scope
)
284 /* NULL can be anything */
285 if (val
->type
== PSI_T_NULL
) {
289 /* a number can be anything */
290 if (val
->type
== PSI_T_NUMBER
) {
291 if (!psi_num_exp_validate(data
, val
->data
.num
, scope
)) {
294 val
->ityp
= psi_num_exp_exec(val
->data
.num
, &val
->ival
, NULL
, scope
->cpp
);
297 /* forced type, like `const <type> foo`, or function param `<type> $xyz` */
299 return psi_impl_def_val_validate_impl_type(data
, val
, type
, scope
);
317 void psi_impl_def_val_dump(struct psi_dump
*dump
, struct psi_impl_def_val
*val
) {
320 PSI_DUMP(dump
, "NULL");
323 PSI_DUMP(dump
, "true");
326 PSI_DUMP(dump
, "false");
329 PSI_DUMP(dump
, "%s", val
->ival
.zend
.bval
? "true" : "false");
332 PSI_DUMP(dump
, ZEND_LONG_FMT
, val
->ival
.zend
.lval
);
336 if (isinf(val
->ival
.dval
)) {
337 PSI_DUMP(dump
, "\\INF");
338 } else if (isnan(val
->ival
.dval
)) {
339 PSI_DUMP(dump
, "\\NAN");
341 PSI_DUMP(dump
, "%" PRIdval
, val
->ival
.dval
);
345 PSI_DUMP(dump
, "\"%s\"", val
->ival
.zend
.str
->val
);
348 psi_num_exp_dump(dump
, val
->data
.num
);
354 PSI_DUMP(dump
, "\t/* impl_def_val.type=%d */ ", val
->type
);