bed5a249c79f3da70655d7c7577b648d8295fd63
[m6w6/ext-psi] / src / types / number.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
28 #include <assert.h>
29
30 #include "data.h"
31 #include "calc.h"
32 #include "call.h"
33
34
35 struct psi_number *psi_number_init(token_t t, void *num)
36 {
37 struct psi_number *exp = calloc(1, sizeof(*exp));
38
39 switch (exp->type = t) {
40 case PSI_T_INT8:
41 exp->data.ival.i64 = *(int8_t *) num;
42 break;
43 case PSI_T_UINT8:
44 exp->data.ival.i64 = *(uint8_t *) num;
45 break;
46 case PSI_T_INT16:
47 exp->data.ival.i64 = *(int16_t *) num;
48 break;
49 case PSI_T_UINT16:
50 exp->data.ival.i64 = *(uint16_t *) num;
51 break;
52 case PSI_T_INT32:
53 exp->data.ival.i64 = *(int32_t *) num;
54 break;
55 case PSI_T_UINT32:
56 exp->data.ival.i64 = *(uint32_t *) num;
57 break;
58 case PSI_T_INT64:
59 exp->data.ival.i64 = *(int64_t *) num;
60 break;
61 case PSI_T_UINT64:
62 exp->data.ival.i64 = *(uint64_t *) num;
63 break;
64 case PSI_T_FLOAT:
65 exp->data.ival.dval = *(float *) num;
66 break;
67 case PSI_T_DOUBLE:
68 exp->data.ival.dval = *(double *) num;
69 break;
70 case PSI_T_NUMBER:
71 case PSI_T_NSNAME:
72 exp->data.numb = strdup(num);
73 break;
74 case PSI_T_NAME:
75 exp->data.dvar = num;
76 break;
77 default:
78 assert(0);
79 }
80
81 return exp;
82 }
83
84 struct psi_number *psi_number_copy(struct psi_number *exp)
85 {
86 struct psi_number *num = calloc(1, sizeof(*num));
87
88 *num = *exp;
89
90 if (num->token) {
91 num->token = psi_token_copy(num->token);
92 }
93 switch (num->type) {
94 case PSI_T_INT64:
95 case PSI_T_DOUBLE:
96 case PSI_T_ENUM:
97 case PSI_T_CONST:
98 break;
99 case PSI_T_NUMBER:
100 case PSI_T_NSNAME:
101 num->data.numb = strdup(num->data.numb);
102 break;
103 case PSI_T_NAME:
104 num->data.dvar = psi_decl_var_copy(num->data.dvar);
105 break;
106 default:
107 assert(0);
108 }
109 return num;
110 }
111
112 void psi_number_free(struct psi_number **exp_ptr)
113 {
114 if (*exp_ptr) {
115 struct psi_number *exp = *exp_ptr;
116
117 *exp_ptr = NULL;
118 if (exp->token) {
119 free(exp->token);
120 }
121 switch (exp->type) {
122 case PSI_T_INT64:
123 case PSI_T_DOUBLE:
124 case PSI_T_ENUM:
125 case PSI_T_CONST:
126 break;
127 case PSI_T_NSNAME:
128 case PSI_T_NUMBER:
129 free(exp->data.numb);
130 break;
131 case PSI_T_NAME:
132 psi_decl_var_free(&exp->data.dvar);
133 break;
134 default:
135 assert(0);
136 }
137 free(exp);
138 }
139 }
140
141 void psi_number_dump(int fd, struct psi_number *exp)
142 {
143 switch (exp->type) {
144 case PSI_T_INT64:
145 dprintf(fd, "%" PRId64, exp->data.ival.i64);
146 break;
147 case PSI_T_DOUBLE:
148 dprintf(fd, "%F", exp->data.ival.dval);
149 break;
150 case PSI_T_NUMBER:
151 case PSI_T_NSNAME:
152 dprintf(fd, "%s", exp->data.numb);
153 break;
154 case PSI_T_CONST:
155 dprintf(fd, "%s", exp->data.cnst->name);
156 break;
157 case PSI_T_ENUM:
158 dprintf(fd, "%s", exp->data.enm->name);
159 break;
160 case PSI_T_NAME:
161 psi_decl_var_dump(fd, exp->data.dvar);
162 break;
163 default:
164 assert(0);
165 }
166 }
167
168 static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
169 struct psi_decl_enum *enm)
170 {
171 size_t i = 0;
172 struct psi_decl_enum_item *itm;
173
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;
178 exp->data.enm = itm;
179 return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
180 }
181 }
182
183 return false;
184 }
185
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)
189 {
190 size_t i = 0;
191 impl_val tmp = {0};
192 struct psi_const *cnst;
193 struct psi_decl_enum *enm;
194
195 switch (exp->type) {
196 case PSI_T_CONST:
197 case PSI_T_INT64:
198 case PSI_T_DOUBLE:
199 case PSI_T_ENUM:
200 return true;
201
202 case PSI_T_NAME:
203 if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
204 return true;
205 }
206 while (psi_plist_get(data->enums, i++, &enm)) {
207 if (psi_number_validate_enum(data, exp, enm)) {
208 return true;
209 }
210 }
211 if (exp->data.dvar->arg) {
212 return true;
213 }
214 if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
215 current_let, current_set)) {
216 return true;
217 }
218 if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
219 return true;
220 }
221 data->error(data, exp->token, PSI_WARNING,
222 "Unknown variable '%s' in numeric expression",
223 exp->data.dvar->name);
224 return false;
225
226 case PSI_T_NSNAME:
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;
232 return true;
233 }
234 }
235 data->error(data, exp->token, PSI_WARNING,
236 "Unknown constant '%s' in numeric expression",
237 exp->data.numb);
238 return false;
239
240 case PSI_T_NUMBER:
241 switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 0)) {
242 case IS_LONG:
243 free(exp->data.numb);
244 exp->type = PSI_T_INT64;
245 exp->data.ival.i64 = tmp.zend.lval;
246 return true;
247
248 case IS_DOUBLE:
249 free(exp->data.numb);
250 exp->type = PSI_T_DOUBLE;
251 exp->data.ival.dval = tmp.dval;
252 return true;
253 }
254 data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
255 return false;
256
257 default:
258 assert(0);
259 }
260
261 return false;
262 }
263
264 #include "Zend/zend_constants.h"
265
266 static inline token_t psi_number_eval_constant(struct psi_number *exp,
267 impl_val *res, struct psi_call_frame *frame)
268 {
269 switch (exp->data.cnst->type->type) {
270 case PSI_T_INT:
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);
274 return PSI_T_INT64;
275 case PSI_T_FLOAT:
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);
279 return PSI_T_DOUBLE;
280 default:
281 if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%d)", exp->data.cnst->type->type);
282 return 0;
283 }
284 }
285
286
287 static inline token_t psi_number_eval_decl_var(struct psi_number *exp,
288 impl_val *res, struct psi_call_frame *frame)
289 {
290 impl_val *ref;
291 struct psi_call_frame_symbol *sym;
292 struct psi_decl_type *real;
293 size_t size;
294
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);
299
300 memcpy(res, ref, size);
301
302 return real->type;
303 }
304
305 token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame)
306 {
307 switch (exp->type) {
308 case PSI_T_INT64:
309 *res = exp->data.ival;
310 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
311 return PSI_T_INT64;
312
313 case PSI_T_DOUBLE:
314 *res = exp->data.ival;
315 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
316 return exp->type;
317
318 case PSI_T_ENUM:
319 res->i64 = exp->data.enm->val;
320 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
321 return PSI_T_INT64;
322
323 case PSI_T_CONST:
324 return psi_number_eval_constant(exp, res, frame);
325 break;
326
327 case PSI_T_NAME:
328 return psi_number_eval_decl_var(exp, res, frame);
329 break;
330
331 default:
332 assert(0);
333 }
334 return 0;
335 }