3ac26c70d81e100dfb856f304a90ebb4c90f7d4c
[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, psi, 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
259 while (0 < psi_parser_scan(&P)) {
260 psi_parser_parse(&P, psi_token_alloc(&P));
261 if (P.num == PSI_T_EOF) {
262 break;
263 }
264 }
265
266 psi_parser_parse(&P, NULL);
267 psi_context_add_data(C, PSI_DATA(&P));
268 psi_parser_dtor(&P);
269 }
270 }
271
272 if (entries) {
273 for (i = 0; i < n; ++i) {
274 free(entries[i]);
275 }
276 free(entries);
277 }
278
279 ptr = sep + 1;
280 } while (sep);
281
282
283 if (psi_context_compile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
284 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to register functions!");
285 }
286
287 free(cpy);
288 }
289
290 zend_function_entry *psi_context_compile(struct psi_context *C)
291 {
292 zend_constant zc;
293
294 zc.flags = CONST_PERSISTENT|CONST_CS;
295 zc.module_number = EG(current_module)->module_number;
296
297 if (C->consts) {
298 size_t i = 0;
299 struct psi_const *c;
300
301 while (psi_plist_get(C->consts, i++, &c)) {
302 zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1);
303 ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1));
304
305 switch (c->type->type) {
306 case PSI_T_BOOL:
307 convert_to_boolean(&zc.value);
308 break;
309 case PSI_T_INT:
310 convert_to_long(&zc.value);
311 break;
312 case PSI_T_FLOAT:
313 convert_to_double(&zc.value);
314 break;
315 case PSI_T_STRING:
316 case PSI_T_QUOTED_STRING:
317 break;
318 default:
319 assert(0);
320 }
321 zend_register_constant(&zc);
322 }
323 }
324 if (C->enums) {
325 size_t i = 0;
326 struct psi_decl_enum *e;
327
328 while (psi_plist_get(C->enums, i++, &e)) {
329 size_t j = 0;
330 struct psi_decl_enum_item *item;
331
332 while (psi_plist_get(e->items, j++, &item)) {
333 zend_string *name = strpprintf(0, "psi\\%s\\%s", e->name, item->name);
334
335 zc.name = zend_string_dup(name, 1);
336 ZVAL_LONG(&zc.value, psi_long_num_exp(item->num, NULL));
337 zend_register_constant(&zc);
338 zend_string_release(name);
339 }
340 }
341 }
342
343 return C->closures = C->ops->compile(C);
344 }
345
346
347 ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl)
348 {
349 struct psi_call_frame *frame;
350
351 frame = psi_call_frame_init(C, impl->decl, impl);
352
353 if (SUCCESS != psi_call_frame_parse_args(frame, execute_data)) {
354 psi_call_frame_free(frame);
355
356 return FAILURE;
357 }
358
359 psi_call_frame_enter(frame);
360
361 if (SUCCESS != psi_call_frame_do_let(frame)) {
362 psi_call_frame_do_return(frame, return_value);
363 psi_call_frame_free(frame);
364
365 return FAILURE;
366 }
367
368 psi_call_frame_do_call(frame);
369 psi_call_frame_do_return(frame, return_value);
370 psi_call_frame_do_set(frame);
371 psi_call_frame_do_free(frame);
372 psi_call_frame_free(frame);
373
374 return SUCCESS;
375 }
376
377
378 void psi_context_dtor(struct psi_context *C)
379 {
380 size_t i;
381 zend_function_entry *zfe;
382
383 if (C->ops->dtor) {
384 C->ops->dtor(C);
385 }
386
387 psi_data_dtor(PSI_DATA(C));
388
389 if (C->data) {
390 for (i = 0; i < C->count; ++i) {
391 psi_data_dtor(&C->data[i]);
392 }
393 free(C->data);
394 }
395
396 if (C->closures) {
397 for (zfe = C->closures; zfe->fname; ++zfe) {
398 free((void *) zfe->arg_info);
399 }
400 free(C->closures);
401 }
402 }
403
404 void psi_context_free(struct psi_context **C)
405 {
406 if (*C) {
407 psi_context_dtor(*C);
408 free(*C);
409 *C = NULL;
410 }
411 }
412
413 bool psi_context_add_data(struct psi_context *C, struct psi_data *P)
414 {
415 struct psi_data *D;
416
417 C->data = realloc(C->data, (C->count + 1) * sizeof(*C->data));
418 D = psi_data_exchange(&C->data[C->count++], P);
419
420 return psi_data_validate(PSI_DATA(C), D);
421 }
422
423 void psi_context_dump(struct psi_context *C, int fd)
424 {
425
426 dprintf(fd, "// psi.engine=%s\n",
427 (char *) C->ops->query(C, PSI_CONTEXT_QUERY_SELF, NULL));
428
429 psi_data_dump(fd, PSI_DATA(C));
430
431 // size_t i;
432 // dprintf(fd, "/* parsed\n");
433 // for (i = 0; i < C->count; ++i) {
434 // psi_data_dump(fd, &C->data[i]);
435 // }
436 // dprintf(fd, "*/\n");
437
438 }