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 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
)
187 switch (type
->type
) {
194 if (val
->ival
.zend
.str
) {
195 zend_string
*tmp
= val
->ival
.zend
.str
;
197 val
->ival
.zend
.bval
= (*tmp
->val
&& *tmp
->val
!= '0');
198 zend_string_release(tmp
);
200 val
->ityp
= PSI_T_UINT8
;
201 val
->type
= PSI_T_BOOL
;
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
)) {
213 val
->ival
.zend
.lval
= zend_dval_to_lval_cap(val
->ival
.dval
);
218 val
->ival
.zend
.lval
= 0;
220 zend_string_release(str
);
221 val
->ityp
= PSI_T_INT64
;
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
;
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
)) {
234 val
->ival
.dval
= val
->ival
.zend
.lval
;
241 zend_string_release(str
);
242 val
->type
= val
->ityp
= PSI_T_DOUBLE
;
245 psi_calc_cast(val
->ityp
, &val
->ival
, PSI_T_DOUBLE
, &val
->ival
);
246 val
->ityp
= PSI_T_DOUBLE
;
249 if (val
->type
== PSI_T_STRING
) {
253 struct psi_dump dump
= {{.hn
= &str
},
254 .fun
= (psi_dump_cb
) smart_str_append_printf
};
257 CASE_IMPLVAL_NUM_DUMP(&dump
, val
->ival
, false);
261 val
->ival
.zend
.str
= smart_str_extract(&str
);
262 val
->type
= PSI_T_STRING
;
267 data
->error(data
, val
->token
, PSI_WARNING
,
268 "Invalid default value type '%s', "
269 "expected one of bool, int, float/double or string.",
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
)
280 /* NULL can be anything */
281 if (val
->type
== PSI_T_NULL
) {
285 /* a number can be anything */
286 if (val
->type
== PSI_T_NUMBER
) {
287 if (!psi_num_exp_validate(data
, val
->data
.num
, scope
)) {
290 val
->ityp
= psi_num_exp_exec(val
->data
.num
, &val
->ival
, NULL
, scope
->cpp
);
293 /* forced type, like `const <type> foo`, or function param `<type> $xyz` */
295 return psi_impl_def_val_validate_impl_type(data
, val
, type
, scope
);
313 void psi_impl_def_val_dump(struct psi_dump
*dump
, struct psi_impl_def_val
*val
) {
316 PSI_DUMP(dump
, "NULL");
319 PSI_DUMP(dump
, "true");
322 PSI_DUMP(dump
, "false");
325 PSI_DUMP(dump
, "%s", val
->ival
.zend
.bval
? "true" : "false");
328 PSI_DUMP(dump
, ZEND_LONG_FMT
, val
->ival
.zend
.lval
);
332 if (isinf(val
->ival
.dval
)) {
333 PSI_DUMP(dump
, "\\INF");
334 } else if (isnan(val
->ival
.dval
)) {
335 PSI_DUMP(dump
, "\\NAN");
337 PSI_DUMP(dump
, "%" PRIdval
, val
->ival
.dval
);
341 PSI_DUMP(dump
, "\"%s\"", val
->ival
.zend
.str
->val
);
344 psi_num_exp_dump(dump
, val
->data
.num
);
350 PSI_DUMP(dump
, "\t/* impl_def_val.type=%d */ ", val
->type
);