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"
35 struct psi_number
*psi_number_init(token_t t
, void *num
)
37 struct psi_number
*exp
= calloc(1, sizeof(*exp
));
39 switch (exp
->type
= t
) {
41 exp
->data
.ival
.i64
= *(int8_t *) num
;
44 exp
->data
.ival
.i64
= *(uint8_t *) num
;
47 exp
->data
.ival
.i64
= *(int16_t *) num
;
50 exp
->data
.ival
.i64
= *(uint16_t *) num
;
53 exp
->data
.ival
.i64
= *(int32_t *) num
;
56 exp
->data
.ival
.i64
= *(uint32_t *) num
;
59 exp
->data
.ival
.i64
= *(int64_t *) num
;
62 exp
->data
.ival
.i64
= *(uint64_t *) num
;
65 exp
->data
.ival
.dval
= *(float *) num
;
68 exp
->data
.ival
.dval
= *(double *) num
;
72 exp
->data
.numb
= strdup(num
);
84 struct psi_number
*psi_number_copy(struct psi_number
*exp
)
86 struct psi_number
*num
= calloc(1, sizeof(*num
));
91 num
->token
= psi_token_copy(num
->token
);
101 num
->data
.numb
= strdup(num
->data
.numb
);
104 num
->data
.dvar
= psi_decl_var_copy(num
->data
.dvar
);
112 void psi_number_free(struct psi_number
**exp_ptr
)
115 struct psi_number
*exp
= *exp_ptr
;
129 free(exp
->data
.numb
);
132 psi_decl_var_free(&exp
->data
.dvar
);
141 void psi_number_dump(int fd
, struct psi_number
*exp
)
145 dprintf(fd
, "%" PRId64
, exp
->data
.ival
.i64
);
148 dprintf(fd
, "%F", exp
->data
.ival
.dval
);
152 dprintf(fd
, "%s", exp
->data
.numb
);
155 dprintf(fd
, "%s", exp
->data
.cnst
->name
);
158 dprintf(fd
, "%s", exp
->data
.enm
->name
);
161 psi_decl_var_dump(fd
, exp
->data
.dvar
);
168 static inline bool psi_number_validate_enum(struct psi_data
*data
, struct psi_number
*exp
,
169 struct psi_decl_enum
*enm
)
172 struct psi_decl_enum_item
*itm
;
174 while (psi_plist_get(enm
->items
, i
++, &itm
)) {
175 if (!strcmp(itm
->name
, exp
->data
.dvar
->name
)) {
176 psi_decl_var_free(&exp
->data
.dvar
);
177 exp
->type
= PSI_T_ENUM
;
179 return psi_number_validate(data
, exp
, NULL
, NULL
, NULL
, NULL
, enm
);
186 bool psi_number_validate(struct psi_data
*data
, struct psi_number
*exp
,
187 struct psi_impl
*impl
, struct psi_decl
*cb_decl
, struct psi_let_exp
*current_let
,
188 struct psi_set_exp
*current_set
, struct psi_decl_enum
*current_enum
)
192 struct psi_const
*cnst
;
193 struct psi_decl_enum
*enm
;
203 if (current_enum
&& psi_number_validate_enum(data
, exp
, current_enum
)) {
206 while (psi_plist_get(data
->enums
, i
++, &enm
)) {
207 if (psi_number_validate_enum(data
, exp
, enm
)) {
211 if (exp
->data
.dvar
->arg
) {
214 if (psi_decl_var_validate(data
, exp
->data
.dvar
, impl
? impl
->decl
: NULL
,
215 current_let
, current_set
)) {
218 if (cb_decl
&& psi_decl_var_validate(data
, exp
->data
.dvar
, cb_decl
, NULL
, NULL
)) {
221 data
->error(data
, exp
->token
, PSI_WARNING
,
222 "Unknown variable '%s' in numeric expression",
223 exp
->data
.dvar
->name
);
227 while (psi_plist_get(data
->consts
, i
++, &cnst
)) {
228 if (!strcmp(cnst
->name
, exp
->data
.numb
)) {
229 free(exp
->data
.numb
);
230 exp
->type
= PSI_T_CONST
;
231 exp
->data
.cnst
= cnst
;
235 data
->error(data
, exp
->token
, PSI_WARNING
,
236 "Unknown constant '%s' in numeric expression",
241 switch (is_numeric_string(exp
->data
.numb
, strlen(exp
->data
.numb
), (zend_long
*) &tmp
, (double *) &tmp
, 0)) {
243 free(exp
->data
.numb
);
244 exp
->type
= PSI_T_INT64
;
245 exp
->data
.ival
.i64
= tmp
.zend
.lval
;
249 free(exp
->data
.numb
);
250 exp
->type
= PSI_T_DOUBLE
;
251 exp
->data
.ival
.dval
= tmp
.dval
;
254 data
->error(data
, exp
->token
, PSI_WARNING
, "Expected numeric entity (parser error?)");
264 #include "Zend/zend_constants.h"
266 static inline token_t
psi_number_eval_constant(struct psi_number
*exp
,
267 impl_val
*res
, struct psi_call_frame
*frame
)
269 switch (exp
->data
.cnst
->type
->type
) {
271 res
->i64
= zend_get_constant_str(exp
->data
.cnst
->name
,
272 strlen(exp
->data
.cnst
->name
))->value
.lval
;
273 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
276 res
->dval
= zend_get_constant_str(exp
->data
.cnst
->name
,
277 strlen(exp
->data
.cnst
->name
))->value
.dval
;
278 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
281 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " ?(t=%d)", exp
->data
.cnst
->type
->type
);
287 static inline token_t
psi_number_eval_decl_var(struct psi_number
*exp
,
288 impl_val
*res
, struct psi_call_frame
*frame
)
291 struct psi_call_frame_symbol
*sym
;
292 struct psi_decl_type
*real
;
295 real
= psi_decl_type_get_real(exp
->data
.dvar
->arg
->type
);
296 size
= psi_decl_arg_get_size(exp
->data
.dvar
->arg
);
297 sym
= psi_call_frame_fetch_symbol(frame
, exp
->data
.dvar
);
298 ref
= deref_impl_val(sym
->ptr
, exp
->data
.dvar
);
300 memcpy(res
, ref
, size
);
305 token_t
psi_number_eval(struct psi_number
*exp
, impl_val
*res
, struct psi_call_frame
*frame
)
309 *res
= exp
->data
.ival
;
310 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
314 *res
= exp
->data
.ival
;
315 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIdval
, res
->dval
);
319 res
->i64
= exp
->data
.enm
->val
;
320 if (frame
) PSI_DEBUG_PRINT(frame
->context
, " %" PRIi64
, res
->i64
);
324 return psi_number_eval_constant(exp
, res
, frame
);
328 return psi_number_eval_decl_var(exp
, res
, frame
);