Merge branch 'callbacks'
[m6w6/ext-psi] / src / calc.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6 #include "php_psi.h"
7 #include "calc.h"
8
9 static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
10 impl_val *ref, *tmp = NULL;
11
12 switch (exp->t) {
13 case PSI_T_NUMBER:
14 switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
15 case IS_LONG:
16 return PSI_T_INT64;
17 case IS_DOUBLE:
18 return PSI_T_DOUBLE;
19 }
20 break;
21
22 case PSI_T_NSNAME:
23 switch (exp->u.cnst->type->type) {
24 case PSI_T_INT:
25 res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
26 return PSI_T_INT64;
27 case PSI_T_FLOAT:
28 res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
29 return PSI_T_DOUBLE;
30 default:
31 return 0;
32 }
33 break;
34
35 case PSI_T_ENUM:
36 return psi_calc_num_exp(exp->u.enm->num ?: &exp->u.enm->inc, NULL, res);
37 break;
38
39 case PSI_T_NAME:
40 if (strct) {
41 ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
42 } else if (exp->u.dvar->arg->let) {
43 ref = exp->u.dvar->arg->let->ptr;
44 } else {
45 ref = exp->u.dvar->arg->ptr;
46 }
47 switch (real_decl_type(exp->u.dvar->arg->type)->type) {
48 case PSI_T_INT8:
49 case PSI_T_UINT8:
50 case PSI_T_INT16:
51 case PSI_T_UINT16:
52 case PSI_T_INT32:
53 case PSI_T_UINT32:
54 case PSI_T_INT64:
55 case PSI_T_UINT64:
56 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
57 if (tmp) {
58 free(tmp);
59 }
60 return real_decl_type(exp->u.dvar->arg->type)->type;
61
62 case PSI_T_FLOAT:
63 case PSI_T_DOUBLE:
64 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
65 if (tmp) {
66 free(tmp);
67 }
68 return real_decl_type(exp->u.dvar->arg->type)->type;
69
70 EMPTY_SWITCH_DEFAULT_CASE();
71 }
72 break;
73
74 EMPTY_SWITCH_DEFAULT_CASE();
75 }
76 return 0;
77 }
78
79 int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
80 impl_val num = {0};
81 int num_type = psi_calc_num_exp_value(exp, strct, &num);
82
83 if (exp->operand) {
84 impl_val tmp = {0};
85 int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
86
87 return exp->calculator(num_type, &num, tmp_type, &tmp, res);
88 }
89
90 memcpy(res, &num, sizeof(*res));
91 return num_type;
92 }
93
94 #define PRIfval "f"
95 #define PRIdval "lf"
96 #define PRIldval "Lf"
97
98 #define PSI_CALC_OP(var) do { \
99 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
100 res->var = PSI_CALC(v1->var, v2->var); \
101 if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
102 } while (0)
103 #define PSI_CALC_OP2(vres, var1, var2) do { \
104 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
105 res->vres = PSI_CALC(v1->var1, v2->var2); \
106 if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
107 } while(0)
108
109 #ifdef HAVE_LONG_DOUBLE
110 #define PSI_CALC_NO_LD
111 #define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
112 #define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
113 #define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
114 #else
115 #define PSI_CALC_NO_LD abort()
116 #define PSI_CALC_OP_LD PSI_CALC_NO_LD
117 #define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
118 #define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
119 #endif
120
121 #define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
122 { \
123 if (t1 == t2) { \
124 switch (t1) { \
125 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
126 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
127 case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \
128 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
129 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
130 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
131 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
132 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
133 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
134 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
135 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
136 EMPTY_SWITCH_DEFAULT_CASE(); \
137 } \
138 return t1; \
139 } else if (t1 == PSI_T_DOUBLE) { \
140 switch (t2) { \
141 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \
142 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
143 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
144 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
145 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
146 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
147 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
148 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
149 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
150 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
151 EMPTY_SWITCH_DEFAULT_CASE(); \
152 } \
153 return t1; \
154 } else if (t2 == PSI_T_DOUBLE) { \
155 switch (t1) { \
156 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \
157 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
158 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
159 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
160 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
161 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
162 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
163 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
164 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
165 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
166 EMPTY_SWITCH_DEFAULT_CASE(); \
167 } \
168 return t2; \
169 } else if (t1 == PSI_T_LONG_DOUBLE) { \
170 PSI_CALC_NO_LD; \
171 switch (t2) { \
172 case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \
173 case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \
174 case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \
175 case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \
176 case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \
177 case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \
178 case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \
179 case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \
180 case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \
181 case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \
182 EMPTY_SWITCH_DEFAULT_CASE(); \
183 } \
184 return t1; \
185 } else if (t2 == PSI_T_LONG_DOUBLE) { \
186 PSI_CALC_NO_LD; \
187 switch (t1) { \
188 case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \
189 case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \
190 case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \
191 case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \
192 case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \
193 case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \
194 case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \
195 case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \
196 case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \
197 case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \
198 EMPTY_SWITCH_DEFAULT_CASE(); \
199 } \
200 return t2; \
201 } else if (t1 == PSI_T_FLOAT) { \
202 switch (t2) { \
203 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \
204 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
205 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
206 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
207 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
208 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
209 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
210 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
211 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
212 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
213 EMPTY_SWITCH_DEFAULT_CASE(); \
214 } \
215 return t1; \
216 } else if (t2 == PSI_T_FLOAT) { \
217 switch (t1) { \
218 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \
219 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
220 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
221 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
222 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
223 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
224 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
225 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
226 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
227 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
228 EMPTY_SWITCH_DEFAULT_CASE(); \
229 } \
230 return t2; \
231 } else { \
232 int64_t sval1 = v1->i64, sval2 = v2->i64; \
233 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
234 switch (t1) { \
235 case PSI_T_INT8: sval1 >>= 8; \
236 case PSI_T_INT16: sval1 >>= 8; \
237 case PSI_T_INT32: sval1 >>= 8; \
238 case PSI_T_INT64: \
239 switch (t2) { \
240 case PSI_T_INT8: sval2 >>= 8; \
241 case PSI_T_INT16: sval2 >>= 8; \
242 case PSI_T_INT32: sval2 >>= 8; \
243 case PSI_T_INT64: \
244 res->i64 = PSI_CALC(sval1 , sval2); \
245 return PSI_T_INT64; \
246 case PSI_T_UINT8: uval2 >>= 8; \
247 case PSI_T_UINT16: uval2 >>= 8; \
248 case PSI_T_UINT32: uval2 >>= 8; \
249 case PSI_T_UINT64: \
250 res->i64 = PSI_CALC(sval1, uval2); \
251 return PSI_T_INT64; \
252 } \
253 break; \
254 case PSI_T_UINT8: uval1 >>= 8; \
255 case PSI_T_UINT16: uval1 >>= 8; \
256 case PSI_T_UINT32: uval1 >>= 8; \
257 case PSI_T_UINT64: \
258 switch (t2) { \
259 case PSI_T_INT8: sval2 >>= 8; \
260 case PSI_T_INT16: sval2 >>= 8; \
261 case PSI_T_INT32: sval2 >>= 8; \
262 case PSI_T_INT64: \
263 res->i64 = PSI_CALC(uval1, sval2); \
264 return PSI_T_INT64; \
265 case PSI_T_UINT8: uval2 >>= 8; \
266 case PSI_T_UINT16: uval2 >>= 8; \
267 case PSI_T_UINT32: uval2 >>= 8; \
268 case PSI_T_UINT64: \
269 res->u64 = PSI_CALC(uval1, uval2); \
270 return PSI_T_UINT64; \
271 } \
272 break; \
273 } \
274 } \
275 ZEND_ASSERT(0); \
276 return 0; \
277 }
278
279 #undef PSI_CALC
280 #define PSI_CALC(var1, var2) (var1) + (var2)
281 PSI_CALC_FN(add)
282 #undef PSI_CALC
283 #define PSI_CALC(var1, var2) (var1) * (var2)
284 PSI_CALC_FN(mul)
285 #undef PSI_CALC
286 #define PSI_CALC(var1, var2) (var1) - (var2)
287 PSI_CALC_FN(sub)
288 #undef PSI_CALC
289 #define PSI_CALC(var1, var2) (var1) / (var2)
290 PSI_CALC_FN(div)