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