types refactoring
[m6w6/ext-psi] / src / types / set_value.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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <stdio.h>
34
35 #include "data.h"
36 #include "marshal.h"
37
38 set_value *init_set_value(set_func *func, decl_vars *vars) {
39 set_value *val = calloc(1, sizeof(*val));
40 val->func = func;
41 val->vars = vars;
42 return val;
43 }
44
45 set_value *add_inner_set_value(set_value *val, set_value *inner) {
46 val->inner = add_set_value(val->inner, inner);
47 inner->outer.set = val;
48 return val;
49 }
50
51 void free_set_value(set_value *val) {
52 if (val->func) {
53 free_set_func(val->func);
54 }
55 if (val->vars) {
56 free_decl_vars(val->vars);
57 }
58 if (val->inner
59 && (!val->outer.set || val->outer.set->inner != val->inner)) {
60 free_set_values(val->inner);
61 }
62 if (val->num) {
63 free_num_exp(val->num);
64 }
65 free(val);
66 }
67
68 void dump_set_value(int fd, set_value *set, unsigned level, int last) {
69 size_t i;
70
71 if (level > 1) {
72 /* only if not directly after `set ...` */
73 dprintf(fd, "%s", psi_t_indent(level));
74 }
75
76 if (set->func->type == PSI_T_ELLIPSIS) {
77 dprintf(fd, "%s(", set->outer.set->func->name);
78 } else {
79 dprintf(fd, "%s(", set->func->name);
80 }
81
82 for (i = 0; i < set->vars->count; ++i) {
83 decl_var *svar = set->vars->vars[i];
84 if (i) {
85 dprintf(fd, ", ");
86 }
87 dump_decl_var(fd, svar);
88 }
89
90 if (set->func->type == PSI_T_ELLIPSIS) {
91 dprintf(fd, ", ...");
92 }
93 if (set->num) {
94 dprintf(fd, ", ");
95 dump_num_exp(fd, set->num);
96 }
97 if (set->inner && set->inner->vals && set->func->type != PSI_T_ELLIPSIS) {
98 dprintf(fd, ",\n");
99 for (i = 0; i < set->inner->count; ++i) {
100 dump_set_value(fd, set->inner->vals[i], level+1, i == (set->inner->count - 1));
101 }
102 /* only if inner stmts, i.e. with new lines, were dumped */
103 dprintf(fd, "%s", psi_t_indent(level));
104 }
105 if (level > 1) {
106 dprintf(fd, ")%s\n", last ? "" : ",");
107 } else {
108 dprintf(fd, ");");
109 }
110 }
111
112 static inline void decl_var_arg_v(decl_args *args, va_list argp) {
113 int argc;
114 decl_arg **argv;
115
116 memset(args, 0, sizeof(*args));
117
118 while ((argc = va_arg(argp, int))) {
119 argv = va_arg(argp, decl_arg **);
120 while (argc--) {
121 add_decl_arg(args, *argv++);
122 }
123 }
124 }
125
126 static inline int validate_set_value_handler(set_value *set) {
127 switch (set->func->type) {
128 case PSI_T_TO_BOOL: set->func->handler = psi_to_bool; break;
129 case PSI_T_TO_INT: set->func->handler = psi_to_int; break;
130 case PSI_T_TO_FLOAT: set->func->handler = psi_to_double; break;
131 case PSI_T_TO_STRING: set->func->handler = psi_to_string; break;
132 case PSI_T_TO_ARRAY: set->func->handler = psi_to_array; break;
133 case PSI_T_TO_OBJECT: set->func->handler = psi_to_object; break;
134 case PSI_T_VOID: set->func->handler = psi_to_void; break;
135 case PSI_T_ZVAL: set->func->handler = psi_to_zval; break;
136 case PSI_T_ELLIPSIS:
137 if (set->outer.set && set->outer.set->func->type == PSI_T_TO_ARRAY) {
138 set->func->handler = psi_to_recursive;
139 set->inner = set->outer.set->inner;
140 break;
141 }
142 /* no break */
143 default:
144 return 0;
145 }
146 return 1;
147 }
148
149 int validate_set_value(struct psi_data *data, set_value *set, ...) {
150 va_list argp;
151 decl_args args = {0};
152 int check;
153
154 va_start(argp, set);
155 decl_var_arg_v(&args, argp);
156 va_end(argp);
157
158 check = validate_set_value_ex(data, set, NULL, &args);
159 if (args.args) {
160 free(args.args);
161 }
162 return check;
163 }
164
165 int validate_set_value_ex(struct psi_data *data, set_value *set, decl_arg *ref, decl_args *ref_list) {
166 size_t i;
167 decl_type *ref_type;
168 decl_var *set_var = set->vars->vars[0];
169
170 if (!validate_set_value_handler(set)) {
171 data->error(data, set->func->token, PSI_WARNING, "Invalid cast '%s' in `set` statement", set->func->name);
172 return 0;
173 }
174
175 for (i = 0; i < set->vars->count; ++i) {
176 decl_var *svar = set->vars->vars[i];
177 if (!svar->arg && !locate_decl_var_arg(svar, ref_list, NULL)) {
178 data->error(data, svar->token, PSI_WARNING, "Unknown variable '%s' in `set` statement", svar->name);
179 return 0;
180 }
181 }
182
183 if (!ref) {
184 ref = set_var->arg;
185 }
186 ref_type = real_decl_type(ref->type);
187
188 if (set->inner && set->inner->count) {
189 int is_to_array = (set->func->type == PSI_T_TO_ARRAY);
190 int is_pointer_to_struct = (ref_type->type == PSI_T_STRUCT && ref->var->pointer_level);
191
192 if (!is_to_array && !is_pointer_to_struct) {
193 data->error(data, set->func->token, E_WARNING, "Inner `set` statement casts only work with "
194 "to_array() casts on structs or pointers: %s(%s...", set->func->name, set->vars->vars[0]->name);
195 return 0;
196 }
197 }
198 if (set->num) {
199 if (!validate_num_exp(data, set->num, ref_list, ref, NULL)) {
200 return 0;
201 }
202 }
203
204 if (set->inner && (ref_type->type == PSI_T_STRUCT || ref_type->type == PSI_T_UNION)) {
205 /* to_array(struct, to_...) */
206 if (!set->outer.set || set->outer.set->inner->vals != set->inner->vals) {
207 for (i = 0; i < set->inner->count; ++i) {
208 decl_var *sub_var = set->inner->vals[i]->vars->vars[0];
209 decl_arg *sub_ref;
210
211 switch (ref_type->type) {
212 case PSI_T_STRUCT:
213 sub_ref = locate_decl_struct_member(ref_type->real.strct, sub_var);
214 break;
215 case PSI_T_UNION:
216 sub_ref = locate_decl_union_member(ref_type->real.unn, sub_var);
217 break;
218 }
219
220 if (sub_ref) {
221 if (!validate_set_value_ex(data, set->inner->vals[i], sub_ref, ref_type->real.strct->args)) {
222 return 0;
223 }
224 }
225 }
226 }
227 } else if (set->inner && set->inner->count == 1) {
228 /* to_array(ptr, to_string(*ptr)) */
229 decl_var *sub_var = set->inner->vals[0]->vars->vars[0];
230 decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref);
231
232 if (sub_ref) {
233 if (strcmp(sub_var->name, set_var->name)) {
234 data->error(data, sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable");
235 return 0;
236 }
237 if (!validate_set_value_ex(data, set->inner->vals[0], sub_ref, ref_list)) {
238 return 0;
239 }
240 }
241 } else if (set->inner && set->inner->count > 1) {
242 data->error(data, set->func->token, E_WARNING,
243 "Inner `set` statement casts on pointers may only occur once, "
244 "unless the outer type is a struct or union, got '%s%s'",
245 ref_type->name, psi_t_indirection(ref->var->pointer_level));
246 return 0;
247 }
248
249 return 1;
250 }
251