configure: generate less files, and do that in build dir
[m6w6/ext-psi] / src / context.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 "php.h"
29
30 #ifdef HAVE_DIRENT_H
31 # include <dirent.h>
32 # define NAMLEN(dirent) strlen ((dirent)->d_name)
33 #else
34 # define dirent direct
35 # define NAMLEN(dirent) ((dirent)->d_namlen)
36 # ifdef HAVE_SYS_NDIR_H
37 # include <sys/ndir.h>
38 # endif
39 # ifdef HAVE_SYS_DIR_H
40 # include <sys/dir.h>
41 # endif
42 # ifdef HAVE_NDIR_H
43 # include <ndir.h>
44 # endif
45 #endif
46
47 #include <fnmatch.h>
48
49 #include "php_scandir.h"
50 #include "php_psi.h"
51 #include "calc.h"
52 #include "call.h"
53 #include "libjit.h"
54 #include "libffi.h"
55
56 #include "token.h"
57 #include "parser.h"
58
59 #define PSI_PREDEF_TYPES
60 #define PSI_PREDEF_CONSTS
61 #define PSI_PREDEF_COMPOSITES
62 #define PSI_PREDEF_DECLS
63 #include "php_psi_posix.h"
64
65 struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_ops *ops, psi_error_cb error, unsigned flags)
66 {
67 struct psi_data T;
68 struct psi_predef_type *predef_type;
69 struct psi_predef_const *predef_const;
70 struct psi_predef_composite *predef_composite;
71 struct psi_predef_decl *predef_decl;
72
73 if (!C) {
74 C = malloc(sizeof(*C));
75 }
76 memset(C, 0, sizeof(*C));
77
78 psi_data_ctor(PSI_DATA(C), error, flags);
79 C->ops = ops;
80
81 if (ops->init) {
82 ops->init(C);
83 }
84
85 assert(ops->call != NULL);
86 assert(ops->compile != NULL);
87
88 /* build up predefs in a temporary PSI_Data for validation */
89 memset(&T, 0, sizeof(T));
90 psi_data_ctor_with_dtors(&T, error, flags);
91
92 for (predef_type = &psi_predef_types[0]; predef_type->type_tag; ++predef_type) {
93 struct psi_decl_type *type = psi_decl_type_init(predef_type->type_tag, predef_type->type_name);
94 struct psi_decl_var *var = psi_decl_var_init(predef_type->alias, 0, 0); /* FIXME: indirection */
95 struct psi_decl_arg *def = psi_decl_arg_init(type, var);
96
97 T.types = psi_plist_add(T.types, &def);
98 }
99 for (predef_const = &psi_predef_consts[0]; predef_const->type_tag; ++predef_const) {
100 struct psi_impl_def_val *val = psi_impl_def_val_init(predef_const->val_type_tag, predef_const->val_text);
101 struct psi_const_type *type = psi_const_type_init(predef_const->type_tag, predef_const->type_name);
102 struct psi_const *constant = psi_const_init(type, predef_const->var_name, val);
103
104 T.consts = psi_plist_add(T.consts, &constant);
105 }
106 for (predef_composite = &psi_predef_composites[0]; predef_composite->type_tag; ++predef_composite) {
107 struct psi_predef_composite *member;
108 struct psi_decl_struct *dstruct;
109 struct psi_decl_union *dunion;
110 struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
111
112 switch (predef_composite->type_tag) {
113 case PSI_T_STRUCT:
114 dstruct = psi_decl_struct_init(predef_composite->var_name, dargs);
115 dstruct->size = predef_composite->size;
116 dstruct->align = predef_composite->offset;
117 break;
118 case PSI_T_UNION:
119 dunion = psi_decl_union_init(predef_composite->var_name, dargs);
120 dunion->size = predef_composite->size;
121 dunion->align = predef_composite->offset;
122 break;
123 default:
124 assert(0);
125 }
126 for (member = &predef_composite[1]; member->type_tag; ++member) {
127 struct psi_decl_type *type;
128 struct psi_decl_var *dvar;
129 struct psi_decl_arg *darg;
130
131 type = psi_decl_type_init(member->type_tag, member->type_name);
132 dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
133 darg = psi_decl_arg_init(type, dvar);
134 darg->layout = psi_layout_init(member->offset, member->size);
135
136 switch (predef_composite->type_tag) {
137 case PSI_T_STRUCT:
138 dstruct->args = psi_plist_add(dstruct->args, &darg);
139 break;
140 case PSI_T_UNION:
141 dunion->args = psi_plist_add(dunion->args, &darg);
142 break;
143 default:
144 assert(0);
145 }
146 }
147 switch (predef_composite->type_tag) {
148 case PSI_T_STRUCT:
149 T.structs = psi_plist_add(T.structs, &dstruct);
150 break;
151 case PSI_T_UNION:
152 T.unions = psi_plist_add(T.unions, &dunion);
153 break;
154 default:
155 assert(0);
156 }
157
158 predef_composite = member;
159 }
160 for (predef_decl = &psi_predef_decls[0]; predef_decl->type_tag; ++predef_decl) {
161 struct psi_predef_decl *farg;
162 struct psi_decl_type *dtype, *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
163 struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
164 struct psi_decl_arg *tdef, *func = psi_decl_arg_init(ftype, fname);
165 struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
166 struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
167
168 for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
169 struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
170 struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
171 struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
172 decl->args = psi_plist_add(decl->args, &darg);
173 }
174
175 switch (predef_decl->kind) {
176 case DECL_KIND_VARARG:
177 decl->varargs = 1;
178 /* no break */
179 case DECL_KIND_STD:
180 T.decls = psi_plist_add(T.decls, &decl);
181 break;
182 case DECL_KIND_FUNCTOR:
183 dtype = psi_decl_type_init(PSI_T_FUNCTION, fname->name);
184 dtype->real.func = decl;
185 tdef = psi_decl_arg_init(dtype, psi_decl_var_copy(fname));
186 T.types = psi_plist_add(T.types, &tdef);
187 break;
188 default:
189 assert(0);
190 }
191
192 predef_decl = farg;
193 }
194
195 psi_context_add_data(C, &T);
196
197 return C;
198 }
199
200 static int psi_select_dirent(const struct dirent *entry)
201 {
202 #ifndef FNM_CASEFOLD
203 # define FNM_CASEFOLD 0
204 #endif
205 return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
206 }
207
208 void psi_context_build(struct psi_context *C, const char *paths)
209 {
210 int i, n;
211 char *sep = NULL, *cpy = strdup(paths), *ptr = cpy;
212 struct dirent **entries;
213
214 do {
215 sep = strchr(ptr, ':');
216
217 if (sep) {
218 *sep = 0;
219 }
220
221 entries = NULL;
222 n = php_scandir(ptr, &entries, psi_select_dirent, alphasort);
223
224 if (n > 0) {
225 for (i = 0; i < n; ++i) {
226 char psi[MAXPATHLEN];
227 struct psi_parser P;
228
229 if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", ptr, entries[i]->d_name)) {
230 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
231 ptr, entries[i]->d_name);
232 }
233 if (!psi_parser_init(&P, C->error, C->flags)) {
234 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
235 psi, strerror(errno));
236 continue;
237 }
238 if (!psi_parser_open_file(&P, psi)) {
239 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to open PSI file (%s): %s",
240 psi, strerror(errno));
241 continue;
242 }
243
244 while (0 < psi_parser_scan(&P)) {
245 psi_parser_parse(&P, psi_token_alloc(&P));
246 if (P.num == PSI_T_EOF) {
247 break;
248 }
249 }
250
251 psi_parser_parse(&P, NULL);
252 psi_context_add_data(C, PSI_DATA(&P));
253 psi_parser_dtor(&P);
254 }
255 }
256
257 if (entries) {
258 for (i = 0; i < n; ++i) {
259 free(entries[i]);
260 }
261 free(entries);
262 }
263
264 ptr = sep + 1;
265 } while (sep);
266
267
268 if (psi_context_compile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
269 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to register functions!");
270 }
271
272 free(cpy);
273 }
274
275 zend_function_entry *psi_context_compile(struct psi_context *C)
276 {
277 zend_constant zc;
278
279 zc.flags = CONST_PERSISTENT|CONST_CS;
280 zc.module_number = EG(current_module)->module_number;
281
282 if (C->consts) {
283 size_t i = 0;
284 struct psi_const *c;
285
286 while (psi_plist_get(C->consts, i++, &c)) {
287 zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1);
288
289 if (zend_get_constant(zc.name)) {
290 zend_string_release(zc.name);
291 continue;
292 }
293
294 ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1));
295
296 switch (c->type->type) {
297 case PSI_T_BOOL:
298 convert_to_boolean(&zc.value);
299 break;
300 case PSI_T_INT:
301 convert_to_long(&zc.value);
302 break;
303 case PSI_T_FLOAT:
304 convert_to_double(&zc.value);
305 break;
306 case PSI_T_STRING:
307 case PSI_T_QUOTED_STRING:
308 break;
309 default:
310 assert(0);
311 }
312 zend_register_constant(&zc);
313 }
314 }
315 if (C->enums) {
316 size_t i = 0;
317 struct psi_decl_enum *e;
318
319 while (psi_plist_get(C->enums, i++, &e)) {
320 size_t j = 0;
321 struct psi_decl_enum_item *item;
322
323 while (psi_plist_get(e->items, j++, &item)) {
324 zend_string *name = strpprintf(0, "psi\\%s\\%s", e->name, item->name);
325
326 zc.name = zend_string_dup(name, 1);
327 ZVAL_LONG(&zc.value, psi_long_num_exp(item->num, NULL));
328 zend_register_constant(&zc);
329 zend_string_release(name);
330 }
331 }
332 }
333
334 return C->closures = C->ops->compile(C);
335 }
336
337
338 ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl)
339 {
340 struct psi_call_frame *frame;
341
342 frame = psi_call_frame_init(C, impl->decl, impl);
343
344 if (SUCCESS != psi_call_frame_parse_args(frame, execute_data)) {
345 psi_call_frame_free(frame);
346
347 return FAILURE;
348 }
349
350 psi_call_frame_enter(frame);
351
352 if (SUCCESS != psi_call_frame_do_let(frame)) {
353 psi_call_frame_do_return(frame, return_value);
354 psi_call_frame_free(frame);
355
356 return FAILURE;
357 }
358
359 psi_call_frame_do_call(frame);
360 psi_call_frame_do_return(frame, return_value);
361 psi_call_frame_do_set(frame);
362 psi_call_frame_do_free(frame);
363 psi_call_frame_free(frame);
364
365 return SUCCESS;
366 }
367
368
369 void psi_context_dtor(struct psi_context *C)
370 {
371 size_t i;
372 zend_function_entry *zfe;
373
374 if (C->ops->dtor) {
375 C->ops->dtor(C);
376 }
377
378 psi_data_dtor(PSI_DATA(C));
379
380 if (C->data) {
381 for (i = 0; i < C->count; ++i) {
382 psi_data_dtor(&C->data[i]);
383 }
384 free(C->data);
385 }
386
387 if (C->closures) {
388 for (zfe = C->closures; zfe->fname; ++zfe) {
389 free((void *) zfe->arg_info);
390 }
391 free(C->closures);
392 }
393 }
394
395 void psi_context_free(struct psi_context **C)
396 {
397 if (*C) {
398 psi_context_dtor(*C);
399 free(*C);
400 *C = NULL;
401 }
402 }
403
404 bool psi_context_add_data(struct psi_context *C, struct psi_data *P)
405 {
406 struct psi_data *D;
407
408 C->data = realloc(C->data, (C->count + 1) * sizeof(*C->data));
409 D = psi_data_exchange(&C->data[C->count++], P);
410
411 return psi_data_validate(PSI_DATA(C), D);
412 }
413
414 void psi_context_dump(struct psi_context *C, int fd)
415 {
416
417 dprintf(fd, "// psi.engine=%s\n",
418 (char *) C->ops->query(C, PSI_CONTEXT_QUERY_SELF, NULL));
419
420 psi_data_dump(fd, PSI_DATA(C));
421
422 // size_t i;
423 // dprintf(fd, "/* parsed\n");
424 // for (i = 0; i < C->count; ++i) {
425 // psi_data_dump(fd, &C->data[i]);
426 // }
427 // dprintf(fd, "*/\n");
428
429 }