1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
32 # define NAMLEN(dirent) strlen ((dirent)->d_name)
34 # define dirent direct
35 # define NAMLEN(dirent) ((dirent)->d_namlen)
36 # ifdef HAVE_SYS_NDIR_H
37 # include <sys/ndir.h>
39 # ifdef HAVE_SYS_DIR_H
49 #include "php_scandir.h"
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"
67 struct psi_context
*psi_context_init(struct psi_context
*C
, struct psi_context_ops
*ops
, psi_error_cb error
, unsigned flags
)
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
;
77 C
= malloc(sizeof(*C
));
79 memset(C
, 0, sizeof(*C
));
81 psi_data_ctor(PSI_DATA(C
), error
, flags
);
88 ZEND_ASSERT(ops
->call
!= NULL
);
89 ZEND_ASSERT(ops
->compile
!= NULL
);
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
);
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
);
100 T
.types
= psi_plist_add(T
.types
, &def
);
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
);
107 T
.consts
= psi_plist_add(T
.consts
, &constant
);
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
);
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
;
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
);
128 T
.structs
= psi_plist_add(T
.structs
, &dstruct
);
129 predef_struct
= member
;
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
);
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
;
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
);
150 T
.unions
= psi_plist_add(T
.unions
, &dunion
);
151 predef_union
= member
;
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
);
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
);
168 T
.decls
= psi_plist_add(T
.decls
, &decl
);
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
);
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
);
188 T
.decls
= psi_plist_add(T
.decls
, &decl
);
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
);
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
);
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
);
215 psi_context_add_data(C
, &T
);
220 static int psi_select_dirent(const struct dirent
*entry
)
223 # define FNM_CASEFOLD 0
225 return 0 == fnmatch("*.psi", entry
->d_name
, FNM_CASEFOLD
);
228 void psi_context_build(struct psi_context
*C
, const char *paths
)
231 char *sep
= NULL
, *cpy
= strdup(paths
), *ptr
= cpy
;
232 struct dirent
**entries
;
235 sep
= strchr(ptr
, ':');
242 n
= php_scandir(ptr
, &entries
, psi_select_dirent
, alphasort
);
245 for (i
= 0; i
< n
; ++i
) {
246 char psi
[MAXPATHLEN
];
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
);
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
));
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
));
264 while (0 < psi_parser_scan(&P
)) {
265 psi_parser_parse(&P
, psi_token_alloc(&P
));
266 if (P
.num
== PSI_T_EOF
) {
271 psi_parser_parse(&P
, NULL
);
272 psi_context_add_data(C
, PSI_DATA(&P
));
278 for (i
= 0; i
< n
; ++i
) {
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!");
295 zend_function_entry
*psi_context_compile(struct psi_context
*C
)
299 zc
.flags
= CONST_PERSISTENT
|CONST_CS
;
300 zc
.module_number
= EG(current_module
)->module_number
;
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));
310 switch (c
->type
->type
) {
312 convert_to_boolean(&zc
.value
);
315 convert_to_long(&zc
.value
);
318 convert_to_double(&zc
.value
);
321 case PSI_T_QUOTED_STRING
:
326 zend_register_constant(&zc
);
331 struct psi_decl_enum
*e
;
333 while (psi_plist_get(C
->enums
, i
++, &e
)) {
335 struct psi_decl_enum_item
*item
;
337 while (psi_plist_get(e
->items
, j
++, &item
)) {
338 zend_string
*name
= strpprintf(0, "psi\\%s\\%s", e
->name
, item
->name
);
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
);
348 return C
->closures
= C
->ops
->compile(C
);
352 ZEND_RESULT_CODE
psi_context_call(struct psi_context
*C
, zend_execute_data
*execute_data
, zval
*return_value
, struct psi_impl
*impl
)
354 struct psi_call_frame
*frame
;
356 frame
= psi_call_frame_init(C
, impl
->decl
, impl
);
358 if (SUCCESS
!= psi_call_frame_parse_args(frame
, execute_data
)) {
359 psi_call_frame_free(frame
);
364 psi_call_frame_enter(frame
);
366 if (SUCCESS
!= psi_call_frame_do_let(frame
)) {
367 psi_call_frame_do_return(frame
, return_value
);
368 psi_call_frame_free(frame
);
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
);
383 void psi_context_dtor(struct psi_context
*C
)
386 zend_function_entry
*zfe
;
392 psi_data_dtor(PSI_DATA(C
));
395 for (i
= 0; i
< C
->count
; ++i
) {
396 psi_data_dtor(&C
->data
[i
]);
402 for (zfe
= C
->closures
; zfe
->fname
; ++zfe
) {
403 free((void *) zfe
->arg_info
);
409 void psi_context_free(struct psi_context
**C
)
412 psi_context_dtor(*C
);
418 bool psi_context_add_data(struct psi_context
*C
, struct psi_data
*P
)
422 C
->data
= realloc(C
->data
, (C
->count
+ 1) * sizeof(*C
->data
));
423 D
= psi_data_exchange(&C
->data
[C
->count
++], P
);
425 return psi_data_validate(PSI_DATA(C
), D
);
428 void psi_context_dump(struct psi_context
*C
, int fd
)
431 dprintf(fd
, "// psi.engine=%s\n",
432 (char *) C
->ops
->query(C
, PSI_CONTEXT_QUERY_SELF
, NULL
));
434 psi_data_dump(fd
, PSI_DATA(C
));
437 // dprintf(fd, "/* parsed\n");
438 // for (i = 0; i < C->count; ++i) {
439 // psi_data_dump(fd, &C->data[i]);
441 // dprintf(fd, "*/\n");