cpp
[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 #include "parser.h"
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 case PSI_T_DEFINE:
73 exp->data.numb = strdup(num);
74 break;
75 case PSI_T_NAME:
76 exp->data.dvar = num;
77 break;
78 case PSI_T_FUNCTION:
79 exp->data.call = num;
80 break;
81 default:
82 assert(0);
83 }
84
85 return exp;
86 }
87
88 struct psi_number *psi_number_copy(struct psi_number *exp)
89 {
90 struct psi_number *num = calloc(1, sizeof(*num));
91
92 *num = *exp;
93
94 if (num->token) {
95 num->token = psi_token_copy(num->token);
96 }
97 switch (num->type) {
98 case PSI_T_INT64:
99 case PSI_T_DOUBLE:
100 case PSI_T_ENUM:
101 case PSI_T_CONST:
102 break;
103 case PSI_T_NUMBER:
104 case PSI_T_NSNAME:
105 case PSI_T_DEFINE:
106 num->data.numb = strdup(num->data.numb);
107 break;
108 case PSI_T_NAME:
109 num->data.dvar = psi_decl_var_copy(num->data.dvar);
110 break;
111 case PSI_T_FUNCTION:
112 num->data.call = psi_cpp_macro_call_copy(num->data.call);
113 break;
114 default:
115 assert(0);
116 }
117 return num;
118 }
119
120 void psi_number_free(struct psi_number **exp_ptr)
121 {
122 if (*exp_ptr) {
123 struct psi_number *exp = *exp_ptr;
124
125 *exp_ptr = NULL;
126 if (exp->token) {
127 free(exp->token);
128 }
129 switch (exp->type) {
130 case PSI_T_INT64:
131 case PSI_T_DOUBLE:
132 case PSI_T_ENUM:
133 case PSI_T_CONST:
134 break;
135 case PSI_T_FUNCTION:
136 psi_cpp_macro_call_free(&exp->data.call);
137 break;
138 case PSI_T_NSNAME:
139 case PSI_T_NUMBER:
140 case PSI_T_DEFINE:
141 free(exp->data.numb);
142 break;
143 case PSI_T_NAME:
144 psi_decl_var_free(&exp->data.dvar);
145 break;
146 default:
147 assert(0);
148 }
149 free(exp);
150 }
151 }
152
153 void psi_number_dump(int fd, struct psi_number *exp)
154 {
155 switch (exp->type) {
156 case PSI_T_INT64:
157 dprintf(fd, "%" PRId64, exp->data.ival.i64);
158 break;
159 case PSI_T_DOUBLE:
160 dprintf(fd, "%F", exp->data.ival.dval);
161 break;
162 case PSI_T_NUMBER:
163 case PSI_T_NSNAME:
164 case PSI_T_DEFINE:
165 dprintf(fd, "%s", exp->data.numb);
166 break;
167 case PSI_T_CONST:
168 dprintf(fd, "%s", exp->data.cnst->name);
169 break;
170 case PSI_T_ENUM:
171 dprintf(fd, "%s", exp->data.enm->name);
172 break;
173 case PSI_T_NAME:
174 psi_decl_var_dump(fd, exp->data.dvar);
175 break;
176 default:
177 assert(0);
178 }
179 }
180
181 static inline bool psi_number_validate_enum(struct psi_data *data, struct psi_number *exp,
182 struct psi_decl_enum *enm)
183 {
184 size_t i = 0;
185 struct psi_decl_enum_item *itm;
186
187 while (psi_plist_get(enm->items, i++, &itm)) {
188 if (!strcmp(itm->name, exp->data.dvar->name)) {
189 psi_decl_var_free(&exp->data.dvar);
190 exp->type = PSI_T_ENUM;
191 exp->data.enm = itm;
192 return psi_number_validate(data, exp, NULL, NULL, NULL, NULL, enm);
193 }
194 }
195
196 return false;
197 }
198
199 bool psi_number_validate(struct psi_data *data, struct psi_number *exp,
200 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
201 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
202 {
203 size_t i = 0;
204 impl_val tmp = {0};
205 struct psi_const *cnst;
206 struct psi_decl_enum *enm;
207
208 switch (exp->type) {
209 case PSI_T_CONST:
210 case PSI_T_INT64:
211 case PSI_T_DOUBLE:
212 case PSI_T_ENUM:
213 case PSI_T_DEFINE:
214 case PSI_T_FUNCTION:
215 return true;
216
217 case PSI_T_NAME:
218 if (current_enum && psi_number_validate_enum(data, exp, current_enum)) {
219 return true;
220 }
221 while (psi_plist_get(data->enums, i++, &enm)) {
222 if (psi_number_validate_enum(data, exp, enm)) {
223 return true;
224 }
225 }
226 if (exp->data.dvar->arg) {
227 return true;
228 }
229 if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL,
230 current_let, current_set)) {
231 return true;
232 }
233 if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) {
234 return true;
235 }
236 data->error(data, exp->token, PSI_WARNING,
237 "Unknown variable '%s' in numeric expression",
238 exp->data.dvar->name);
239 return false;
240
241 case PSI_T_NSNAME:
242 while (psi_plist_get(data->consts, i++, &cnst)) {
243 if (!strcmp(cnst->name, exp->data.numb)) {
244 free(exp->data.numb);
245 exp->type = PSI_T_CONST;
246 exp->data.cnst = cnst;
247 return true;
248 }
249 }
250 data->error(data, exp->token, PSI_WARNING,
251 "Unknown constant '%s' in numeric expression",
252 exp->data.numb);
253 return false;
254
255 case PSI_T_NUMBER:
256 switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 0)) {
257 case IS_LONG:
258 free(exp->data.numb);
259 exp->type = PSI_T_INT64;
260 exp->data.ival.i64 = tmp.zend.lval;
261 return true;
262
263 case IS_DOUBLE:
264 free(exp->data.numb);
265 exp->type = PSI_T_DOUBLE;
266 exp->data.ival.dval = tmp.dval;
267 return true;
268 }
269 data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
270 return false;
271
272 default:
273 assert(0);
274 }
275
276 return false;
277 }
278
279 #include "Zend/zend_constants.h"
280
281 static inline token_t psi_number_eval_constant(struct psi_number *exp,
282 impl_val *res, struct psi_call_frame *frame)
283 {
284 switch (exp->data.cnst->type->type) {
285 case PSI_T_INT:
286 res->i64 = zend_get_constant_str(exp->data.cnst->name,
287 strlen(exp->data.cnst->name))->value.lval;
288 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
289 return PSI_T_INT64;
290 case PSI_T_FLOAT:
291 res->dval = zend_get_constant_str(exp->data.cnst->name,
292 strlen(exp->data.cnst->name))->value.dval;
293 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
294 return PSI_T_DOUBLE;
295 default:
296 if (frame) PSI_DEBUG_PRINT(frame->context, " ?(t=%d)", exp->data.cnst->type->type);
297 return 0;
298 }
299 }
300
301
302 static inline token_t psi_number_eval_decl_var(struct psi_number *exp,
303 impl_val *res, struct psi_call_frame *frame)
304 {
305 impl_val *ref;
306 struct psi_call_frame_symbol *sym;
307 struct psi_decl_type *real;
308 size_t size;
309
310 real = psi_decl_type_get_real(exp->data.dvar->arg->type);
311 size = psi_decl_arg_get_size(exp->data.dvar->arg);
312 sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar);
313 ref = deref_impl_val(sym->ptr, exp->data.dvar);
314
315 memcpy(res, ref, size);
316
317 return real->type;
318 }
319
320 static inline token_t psi_number_eval_define(struct psi_number *exp,
321 impl_val *res, HashTable *defs)
322 {
323 struct psi_cpp_macro_decl *macro = zend_hash_str_find_ptr(defs, exp->data.numb, strlen(exp->data.numb));
324
325 //WHATT?
326
327 res->u8 = 0;
328 return PSI_T_UINT8;
329 }
330
331 token_t psi_number_eval(struct psi_number *exp, impl_val *res, struct psi_call_frame *frame, HashTable *defs)
332 {
333 switch (exp->type) {
334 case PSI_T_INT64:
335 *res = exp->data.ival;
336 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
337 return PSI_T_INT64;
338
339 case PSI_T_DOUBLE:
340 *res = exp->data.ival;
341 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
342 return exp->type;
343
344 case PSI_T_ENUM:
345 res->i64 = exp->data.enm->val;
346 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
347 return PSI_T_INT64;
348
349 case PSI_T_CONST:
350 return psi_number_eval_constant(exp, res, frame);
351
352 case PSI_T_NAME:
353 return psi_number_eval_decl_var(exp, res, frame);
354
355 case PSI_T_DEFINE:
356 return psi_number_eval_define(exp, res, defs);
357
358 case PSI_T_FUNCTION:
359 res->u8 = 0;
360 return PSI_T_UINT8;
361
362 default:
363 assert(0);
364 }
365 return 0;
366 }