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 #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"
65 struct psi_context
*psi_context_init(struct psi_context
*C
, struct psi_context_ops
*ops
, psi_error_cb error
, unsigned flags
)
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
;
74 C
= malloc(sizeof(*C
));
76 memset(C
, 0, sizeof(*C
));
78 psi_data_ctor(PSI_DATA(C
), error
, flags
);
85 assert(ops
->call
!= NULL
);
86 assert(ops
->compile
!= NULL
);
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
);
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
);
97 T
.types
= psi_plist_add(T
.types
, &def
);
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
);
104 T
.consts
= psi_plist_add(T
.consts
, &constant
);
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
);
112 switch (predef_composite
->type_tag
) {
114 dstruct
= psi_decl_struct_init(predef_composite
->var_name
, dargs
);
115 dstruct
->size
= predef_composite
->size
;
116 dstruct
->align
= predef_composite
->offset
;
119 dunion
= psi_decl_union_init(predef_composite
->var_name
, dargs
);
120 dunion
->size
= predef_composite
->size
;
121 dunion
->align
= predef_composite
->offset
;
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
;
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
);
136 switch (predef_composite
->type_tag
) {
138 dstruct
->args
= psi_plist_add(dstruct
->args
, &darg
);
141 dunion
->args
= psi_plist_add(dunion
->args
, &darg
);
147 switch (predef_composite
->type_tag
) {
149 T
.structs
= psi_plist_add(T
.structs
, &dstruct
);
152 T
.unions
= psi_plist_add(T
.unions
, &dunion
);
158 predef_composite
= member
;
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
);
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
);
175 switch (predef_decl
->kind
) {
176 case DECL_KIND_VARARG
:
180 T
.decls
= psi_plist_add(T
.decls
, &decl
);
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
);
195 psi_context_add_data(C
, &T
);
200 static int psi_select_dirent(const struct dirent
*entry
)
203 # define FNM_CASEFOLD 0
205 return 0 == fnmatch("*.psi", entry
->d_name
, FNM_CASEFOLD
);
208 void psi_context_build(struct psi_context
*C
, const char *paths
)
211 char *sep
= NULL
, *cpy
= strdup(paths
), *ptr
= cpy
;
212 struct dirent
**entries
;
215 sep
= strchr(ptr
, ':');
222 n
= php_scandir(ptr
, &entries
, psi_select_dirent
, alphasort
);
225 for (i
= 0; i
< n
; ++i
) {
226 char psi
[MAXPATHLEN
];
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
);
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
));
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
));
244 while (0 < psi_parser_scan(&P
)) {
245 psi_parser_parse(&P
, psi_token_alloc(&P
));
246 if (P
.num
== PSI_T_EOF
) {
251 psi_parser_parse(&P
, NULL
);
252 psi_context_add_data(C
, PSI_DATA(&P
));
258 for (i
= 0; i
< n
; ++i
) {
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!");
275 zend_function_entry
*psi_context_compile(struct psi_context
*C
)
279 zc
.flags
= CONST_PERSISTENT
|CONST_CS
;
280 zc
.module_number
= EG(current_module
)->module_number
;
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);
289 if (zend_get_constant(zc
.name
)) {
290 zend_string_release(zc
.name
);
294 ZVAL_NEW_STR(&zc
.value
, zend_string_init(c
->val
->text
, strlen(c
->val
->text
), 1));
296 switch (c
->type
->type
) {
298 convert_to_boolean(&zc
.value
);
301 convert_to_long(&zc
.value
);
304 convert_to_double(&zc
.value
);
307 case PSI_T_QUOTED_STRING
:
312 zend_register_constant(&zc
);
317 struct psi_decl_enum
*e
;
319 while (psi_plist_get(C
->enums
, i
++, &e
)) {
321 struct psi_decl_enum_item
*item
;
323 while (psi_plist_get(e
->items
, j
++, &item
)) {
324 zend_string
*name
= strpprintf(0, "psi\\%s\\%s", e
->name
, item
->name
);
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
);
334 return C
->closures
= C
->ops
->compile(C
);
338 ZEND_RESULT_CODE
psi_context_call(struct psi_context
*C
, zend_execute_data
*execute_data
, zval
*return_value
, struct psi_impl
*impl
)
340 struct psi_call_frame
*frame
;
342 frame
= psi_call_frame_init(C
, impl
->decl
, impl
);
344 if (SUCCESS
!= psi_call_frame_parse_args(frame
, execute_data
)) {
345 psi_call_frame_free(frame
);
350 psi_call_frame_enter(frame
);
352 if (SUCCESS
!= psi_call_frame_do_let(frame
)) {
353 psi_call_frame_do_return(frame
, return_value
);
354 psi_call_frame_free(frame
);
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
);
369 void psi_context_dtor(struct psi_context
*C
)
372 zend_function_entry
*zfe
;
378 psi_data_dtor(PSI_DATA(C
));
381 for (i
= 0; i
< C
->count
; ++i
) {
382 psi_data_dtor(&C
->data
[i
]);
388 for (zfe
= C
->closures
; zfe
->fname
; ++zfe
) {
389 free((void *) zfe
->arg_info
);
395 void psi_context_free(struct psi_context
**C
)
398 psi_context_dtor(*C
);
404 bool psi_context_add_data(struct psi_context
*C
, struct psi_data
*P
)
408 C
->data
= realloc(C
->data
, (C
->count
+ 1) * sizeof(*C
->data
));
409 D
= psi_data_exchange(&C
->data
[C
->count
++], P
);
411 return psi_data_validate(PSI_DATA(C
), D
);
414 void psi_context_dump(struct psi_context
*C
, int fd
)
417 dprintf(fd
, "// psi.engine=%s\n",
418 (char *) C
->ops
->query(C
, PSI_CONTEXT_QUERY_SELF
, NULL
));
420 psi_data_dump(fd
, PSI_DATA(C
));
423 // dprintf(fd, "/* parsed\n");
424 // for (i = 0; i < C->count; ++i) {
425 // psi_data_dump(fd, &C->data[i]);
427 // dprintf(fd, "*/\n");