don't register constants with its anon prefix
[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_const_type *type = psi_const_type_init(predef_const->type_tag, predef_const->type_name);
101 struct psi_impl_def_val *val;
102 struct psi_const *constant;
103
104 switch (type->type) {
105 case PSI_T_INT:
106 val = psi_impl_def_val_init(PSI_T_INT, NULL);
107 val->ival.zend.lval = predef_const->value.lval;
108 break;
109 case PSI_T_STRING:
110 val = psi_impl_def_val_init(PSI_T_STRING, NULL);
111 val->ival.zend.str = zend_string_init(predef_const->value.ptr, strlen(predef_const->value.ptr), 1);
112 break;
113 default:
114 assert(0);
115 break;
116 }
117
118 constant = psi_const_init(type, predef_const->var_name, val);
119 T.consts = psi_plist_add(T.consts, &constant);
120 }
121 for (predef_composite = &psi_predef_composites[0]; predef_composite->type_tag; ++predef_composite) {
122 struct psi_predef_composite *member;
123 struct psi_decl_struct *dstruct;
124 struct psi_decl_union *dunion;
125 struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
126
127 switch (predef_composite->type_tag) {
128 case PSI_T_STRUCT:
129 dstruct = psi_decl_struct_init(predef_composite->var_name, dargs);
130 dstruct->size = predef_composite->size;
131 dstruct->align = predef_composite->offset;
132 break;
133 case PSI_T_UNION:
134 dunion = psi_decl_union_init(predef_composite->var_name, dargs);
135 dunion->size = predef_composite->size;
136 dunion->align = predef_composite->offset;
137 break;
138 default:
139 assert(0);
140 }
141 for (member = &predef_composite[1]; member->type_tag; ++member) {
142 struct psi_decl_type *type;
143 struct psi_decl_var *dvar;
144 struct psi_decl_arg *darg;
145
146 type = psi_decl_type_init(member->type_tag, member->type_name);
147 dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
148 darg = psi_decl_arg_init(type, dvar);
149 darg->layout = psi_layout_init(member->offset, member->size, NULL);
150
151 switch (predef_composite->type_tag) {
152 case PSI_T_STRUCT:
153 dstruct->args = psi_plist_add(dstruct->args, &darg);
154 break;
155 case PSI_T_UNION:
156 dunion->args = psi_plist_add(dunion->args, &darg);
157 break;
158 default:
159 assert(0);
160 }
161 }
162 switch (predef_composite->type_tag) {
163 case PSI_T_STRUCT:
164 T.structs = psi_plist_add(T.structs, &dstruct);
165 break;
166 case PSI_T_UNION:
167 T.unions = psi_plist_add(T.unions, &dunion);
168 break;
169 default:
170 assert(0);
171 }
172
173 predef_composite = member;
174 }
175 for (predef_decl = &psi_predef_decls[0]; predef_decl->type_tag; ++predef_decl) {
176 struct psi_predef_decl *farg;
177 struct psi_decl_type *dtype, *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
178 struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
179 struct psi_decl_arg *tdef, *func = psi_decl_arg_init(ftype, fname);
180 struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
181 struct psi_decl *decl = psi_decl_init(func, args);
182
183 for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
184 struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
185 struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
186 struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
187 decl->args = psi_plist_add(decl->args, &darg);
188 }
189
190 switch (predef_decl->kind) {
191 case DECL_KIND_VARARG:
192 decl->varargs = 1;
193 /* no break */
194 case DECL_KIND_STD:
195 T.decls = psi_plist_add(T.decls, &decl);
196 break;
197 case DECL_KIND_FUNCTOR:
198 dtype = psi_decl_type_init(PSI_T_FUNCTION, fname->name);
199 dtype->real.func = decl;
200 tdef = psi_decl_arg_init(dtype, psi_decl_var_copy(fname));
201 T.types = psi_plist_add(T.types, &tdef);
202 break;
203 default:
204 assert(0);
205 }
206
207 predef_decl = farg;
208 }
209
210 psi_context_add_data(C, &T);
211
212 return C;
213 }
214
215 static int psi_select_dirent(const struct dirent *entry)
216 {
217 #ifndef FNM_CASEFOLD
218 # define FNM_CASEFOLD 0
219 #endif
220 return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
221 }
222
223 void psi_context_build(struct psi_context *C, const char *paths)
224 {
225 int i, n;
226 char *sep = NULL, *cpy = strdup(paths), *ptr = cpy;
227 struct dirent **entries;
228
229 do {
230 sep = strchr(ptr, ':');
231
232 if (sep) {
233 *sep = 0;
234 }
235
236 entries = NULL;
237 n = php_scandir(ptr, &entries, psi_select_dirent, alphasort);
238
239 if (n > 0) {
240 for (i = 0; i < n; ++i) {
241 char psi[MAXPATHLEN];
242 struct psi_parser P;
243 struct psi_parser_input *I;
244
245 if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", ptr, entries[i]->d_name)) {
246 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
247 ptr, entries[i]->d_name);
248 }
249 if (!psi_parser_init(&P, C->error, C->flags)) {
250 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
251 psi, strerror(errno));
252 continue;
253 }
254 if (!(I = psi_parser_open_file(&P, psi, true))) {
255 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to open PSI file (%s): %s",
256 psi, strerror(errno));
257 continue;
258 }
259 psi_parser_parse(&P, I);
260 psi_context_add_data(C, PSI_DATA(&P));
261 psi_parser_dtor(&P);
262 free(I);
263 }
264 }
265
266 if (entries) {
267 for (i = 0; i < n; ++i) {
268 free(entries[i]);
269 }
270 free(entries);
271 }
272
273 ptr = sep + 1;
274 } while (sep);
275
276
277 if (psi_context_compile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
278 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to register functions!");
279 }
280
281 free(cpy);
282 }
283
284 zend_function_entry *psi_context_compile(struct psi_context *C)
285 {
286 zend_constant zc;
287
288 zc.flags = CONST_PERSISTENT|CONST_CS;
289 zc.module_number = EG(current_module)->module_number;
290
291 if (C->consts) {
292 size_t i = 0;
293 struct psi_const *c;
294
295 while (psi_plist_get(C->consts, i++, &c)) {
296
297 if (zend_get_constant_str(c->name, strlen(c->name))) {
298 continue;
299 }
300
301 zc.name = zend_string_init(c->name, strlen(c->name), 1);
302
303 switch (c->type->type) {
304 case PSI_T_BOOL:
305 ZVAL_BOOL(&zc.value, c->val->ival.zend.bval);
306 break;
307 case PSI_T_INT:
308 ZVAL_LONG(&zc.value, c->val->ival.zend.lval);
309 break;
310 case PSI_T_FLOAT:
311 ZVAL_DOUBLE(&zc.value, c->val->ival.dval);
312 break;
313 case PSI_T_STRING:
314 case PSI_T_QUOTED_STRING:
315 ZVAL_NEW_STR(&zc.value, zend_string_copy(c->val->ival.zend.str));
316 break;
317 default:
318 assert(0);
319 break;
320 }
321
322 zend_register_constant(&zc);
323 }
324 }
325
326 if (C->enums) {
327 size_t i = 0;
328 struct psi_decl_enum *e;
329
330 while (psi_plist_get(C->enums, i++, &e)) {
331 size_t j = 0;
332 struct psi_decl_enum_item *item;
333
334 while (psi_plist_get(e->items, j++, &item)) {
335 zend_string *name;
336
337 if (psi_decl_type_is_anon(e->name, "enum")) {
338 name = strpprintf(0, "psi\\%s", item->name);
339 } else {
340 name = strpprintf(0, "psi\\%s\\%s", e->name, item->name);
341 }
342
343 zc.name = zend_string_dup(name, 1);
344 ZVAL_LONG(&zc.value, psi_long_num_exp(item->num, NULL, NULL));
345 zend_register_constant(&zc);
346 zend_string_release(name);
347 }
348 }
349 }
350
351 return C->closures = C->ops->compile(C);
352 }
353
354
355 ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl)
356 {
357 struct psi_call_frame *frame;
358
359 frame = psi_call_frame_init(C, impl->decl, impl);
360
361 if (SUCCESS != psi_call_frame_parse_args(frame, execute_data)) {
362 psi_call_frame_free(frame);
363
364 return FAILURE;
365 }
366
367 psi_call_frame_enter(frame);
368
369 if (SUCCESS != psi_call_frame_do_let(frame)) {
370 psi_call_frame_do_return(frame, return_value);
371 psi_call_frame_free(frame);
372
373 return FAILURE;
374 }
375
376 if (SUCCESS != psi_call_frame_do_assert(frame, PSI_ASSERT_PRE)) {
377 psi_call_frame_do_return(frame, return_value);
378 psi_call_frame_free(frame);
379
380 return FAILURE;
381 }
382
383 psi_call_frame_do_call(frame);
384
385 if (SUCCESS != psi_call_frame_do_assert(frame, PSI_ASSERT_POST)) {
386 psi_call_frame_do_return(frame, return_value);
387 psi_call_frame_free(frame);
388
389 return FAILURE;
390 }
391
392 psi_call_frame_do_return(frame, return_value);
393 psi_call_frame_do_set(frame);
394 psi_call_frame_do_free(frame);
395 psi_call_frame_free(frame);
396
397 return SUCCESS;
398 }
399
400
401 void psi_context_dtor(struct psi_context *C)
402 {
403 size_t i;
404 zend_function_entry *zfe;
405
406 if (C->ops->dtor) {
407 C->ops->dtor(C);
408 }
409
410 psi_data_dtor(PSI_DATA(C));
411
412 if (C->data) {
413 for (i = 0; i < C->count; ++i) {
414 psi_data_dtor(&C->data[i]);
415 }
416 free(C->data);
417 }
418
419 if (C->closures) {
420 for (zfe = C->closures; zfe->fname; ++zfe) {
421 free((void *) zfe->arg_info);
422 }
423 free(C->closures);
424 }
425 }
426
427 void psi_context_free(struct psi_context **C)
428 {
429 if (*C) {
430 psi_context_dtor(*C);
431 free(*C);
432 *C = NULL;
433 }
434 }
435
436 bool psi_context_add_data(struct psi_context *C, struct psi_data *P)
437 {
438 struct psi_data *D;
439
440 C->data = realloc(C->data, (C->count + 1) * sizeof(*C->data));
441 D = psi_data_exchange(&C->data[C->count++], P);
442
443 return psi_data_validate(PSI_DATA(C), D);
444 }
445
446 void psi_context_dump(struct psi_context *C, int fd)
447 {
448
449 dprintf(fd, "// psi.engine=%s\n",
450 (char *) C->ops->query(C, PSI_CONTEXT_QUERY_SELF, NULL));
451
452 psi_data_dump(fd, PSI_DATA(C));
453
454 // size_t i;
455 // dprintf(fd, "/* parsed\n");
456 // for (i = 0; i < C->count; ++i) {
457 // psi_data_dump(fd, &C->data[i]);
458 // }
459 // dprintf(fd, "*/\n");
460
461 }