bison
[m6w6/ext-psi] / src / types / decl_arg.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 #include <assert.h>
28
29 #include "data.h"
30
31 struct psi_decl_arg *psi_decl_arg_init(struct psi_decl_type *type,
32 struct psi_decl_var *var)
33 {
34 struct psi_decl_arg *arg = calloc(1, sizeof(*arg));
35 arg->token = var->token;
36 arg->type = type;
37 arg->var = var;
38 var->arg = arg;
39 return arg;
40 }
41
42 void psi_decl_arg_free(struct psi_decl_arg **arg_ptr)
43 {
44 if (*arg_ptr) {
45 struct psi_decl_arg *arg = *arg_ptr;
46
47 *arg_ptr = NULL;
48 if (arg->token && arg->token != arg->var->token) {
49 free(arg->token);
50 }
51 psi_decl_type_free(&arg->type);
52 psi_decl_var_free(&arg->var);
53 if (arg->layout) {
54 psi_layout_free(&arg->layout);
55 }
56 free(arg);
57 }
58 }
59
60 void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level)
61 {
62 if (arg->type->type == PSI_T_FUNCTION) {
63 psi_decl_type_dump(fd, arg->type->real.func->func->type, level);
64 dprintf(fd, " %s(*%s)",
65 psi_t_indirection(arg->var->pointer_level - !! arg->var->array_size),
66 arg->var->name);
67 dprintf(fd, "(");
68 if (arg->type->real.func->args) {
69 size_t j = 0;
70 struct psi_decl_arg *farg;
71
72 ++level;
73 while (psi_plist_get(arg->type->real.func->args, j++, &farg)) {
74 if (j > 1) {
75 dprintf(fd, ", ");
76 }
77 psi_decl_arg_dump(fd, farg, level);
78 }
79 --level;
80 if (arg->type->real.func->varargs) {
81 dprintf(fd, ", ...");
82 }
83 }
84 dprintf(fd, ")");
85 if (arg->var->array_size) {
86 dprintf(fd, "[%u]", arg->var->array_size);
87 }
88 } else {
89 psi_decl_type_dump(fd, arg->type, level);
90 dprintf(fd, " ");
91 psi_decl_var_dump(fd, arg->var);
92 }
93 }
94
95 bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg)
96 {
97 if (!psi_decl_type_validate(data, arg->type, NULL)) {
98 data->error(data, arg->type->token, PSI_WARNING,
99 "Cannot use '%s' as type for '%s': %s", arg->type->name,
100 arg->var->name, data->last_error);
101 return false;
102 }
103 return true;
104 }
105
106 bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def)
107 {
108 if (!psi_decl_type_validate(data, def->type, def)) {
109 const char *pre;
110
111 switch (def->type->type) {
112 case PSI_T_STRUCT:
113 pre = "struct ";
114 break;
115 case PSI_T_UNION:
116 pre = "union ";
117 break;
118 case PSI_T_ENUM:
119 pre = "enum ";
120 break;
121 default:
122 pre = "";
123 break;
124 }
125 data->error(data, def->token, PSI_WARNING,
126 "Type '%s' cannot be aliased to '%s%s': %s", def->var->name, pre,
127 def->type->name, data->last_error);
128 return false;
129 }
130 if (def->type->type == PSI_T_VOID) {
131 if (def->var->pointer_level) {
132 def->type->type = PSI_T_POINTER;
133 } else {
134 data->error(data, def->token, PSI_WARNING,
135 "Type '%s' cannot be aliased to 'void'", def->type->name);
136 return false;
137 }
138 }
139
140 return true;
141 }
142
143 size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len)
144 {
145 size_t align = psi_decl_arg_get_align(darg);
146
147 assert(align > 0);
148
149 *len = psi_decl_arg_get_size(darg);
150 *pos = psi_align(align, *pos);
151
152 return align;
153 }
154
155 size_t psi_decl_arg_get_align(struct psi_decl_arg *darg)
156 {
157 size_t align;
158
159 if (darg->var->pointer_level
160 && (!darg->var->array_size || darg->var->pointer_level > 2)) {
161 align = psi_t_alignment(PSI_T_POINTER);
162 } else {
163 align = psi_decl_type_get_align(darg->type);
164 }
165
166 return align;
167 }
168
169 size_t psi_decl_arg_get_size(struct psi_decl_arg *darg)
170 {
171 size_t size;
172 struct psi_decl_type *real = psi_decl_type_get_real(darg->type);
173
174 if (darg->var->array_size) {
175 if (darg->var->pointer_level > 2) {
176 size = psi_t_size(PSI_T_POINTER) * darg->var->array_size;
177 } else {
178 size = psi_t_size(real->type) * darg->var->array_size;
179 }
180 } else if (darg->var->pointer_level) {
181 size = psi_t_size(PSI_T_POINTER);
182 } else {
183 switch (real->type) {
184 case PSI_T_UNION:
185 size = real->real.unn->size;
186 break;
187 case PSI_T_STRUCT:
188 size = real->real.strct->size;
189 break;
190 case PSI_T_ENUM:
191 default:
192 size = psi_t_size(real->type);
193 break;
194 }
195 }
196
197 return size;
198 }
199
200 struct psi_decl_arg *psi_decl_arg_get_by_name(struct psi_plist *args,
201 const char *name)
202 {
203 size_t i = 0;
204 struct psi_decl_arg *arg;
205
206 if (args)
207 while (psi_plist_get(args, i++, &arg)) {
208 if (!strcmp(name, arg->var->name)) {
209 return arg;
210 }
211 }
212
213 return NULL;
214 }
215
216 struct psi_decl_arg *psi_decl_arg_get_by_var(struct psi_decl_var *var,
217 struct psi_plist *args, struct psi_decl_arg *func)
218 {
219 struct psi_decl_arg *arg = psi_decl_arg_get_by_name(args, var->name);
220
221 if (arg) {
222 assert(!var->arg || var->arg == arg);
223
224 return var->arg = arg;
225 }
226
227 if (func && !strcmp(var->name, func->var->name)) {
228 return var->arg = func;
229 }
230
231 return NULL;
232 }