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
);
93 if (psi_check_env("PSI_SKIP"))
97 for (predef_type
= &psi_predef_types
[0]; predef_type
->type_tag
; ++predef_type
) {
98 struct psi_decl_type
*type
= psi_decl_type_init(predef_type
->type_tag
, predef_type
->type_name
);
99 struct psi_decl_var
*var
= psi_decl_var_init(predef_type
->alias
, 0, 0); /* FIXME: indirection */
100 struct psi_decl_arg
*def
= psi_decl_arg_init(type
, var
);
102 T
.types
= psi_plist_add(T
.types
, &def
);
104 for (predef_const
= &psi_predef_consts
[0]; predef_const
->type_tag
; ++predef_const
) {
105 struct psi_const_type
*type
= psi_const_type_init(predef_const
->type_tag
, predef_const
->type_name
);
106 struct psi_impl_def_val
*val
;
107 struct psi_const
*constant
;
109 switch (type
->type
) {
111 val
= psi_impl_def_val_init(PSI_T_INT
, NULL
);
112 val
->ival
.zend
.lval
= predef_const
->value
.zend
.lval
;
115 val
= psi_impl_def_val_init(PSI_T_STRING
, NULL
);
116 val
->ival
.zend
.str
= zend_string_init(predef_const
->value
.ptr
, strlen(predef_const
->value
.ptr
), 1);
123 constant
= psi_const_init(type
, predef_const
->var_name
, val
);
124 T
.consts
= psi_plist_add(T
.consts
, &constant
);
126 for (predef_composite
= &psi_predef_composites
[0]; predef_composite
->type_tag
; ++predef_composite
) {
127 struct psi_predef_composite
*member
;
128 struct psi_decl_struct
*dstruct
;
129 struct psi_decl_union
*dunion
;
130 struct psi_plist
*dargs
= psi_plist_init((psi_plist_dtor
) psi_decl_arg_free
);
132 switch (predef_composite
->type_tag
) {
134 dstruct
= psi_decl_struct_init(predef_composite
->var_name
, dargs
);
135 dstruct
->size
= predef_composite
->size
;
136 dstruct
->align
= predef_composite
->offset
;
139 dunion
= psi_decl_union_init(predef_composite
->var_name
, dargs
);
140 dunion
->size
= predef_composite
->size
;
141 dunion
->align
= predef_composite
->offset
;
146 for (member
= &predef_composite
[1]; member
->type_tag
; ++member
) {
147 struct psi_decl_type
*type
;
148 struct psi_decl_var
*dvar
;
149 struct psi_decl_arg
*darg
;
151 type
= psi_decl_type_init(member
->type_tag
, member
->type_name
);
152 dvar
= psi_decl_var_init(member
->var_name
, member
->pointer_level
, member
->array_size
);
153 darg
= psi_decl_arg_init(type
, dvar
);
154 darg
->layout
= psi_layout_init(member
->offset
, member
->size
, NULL
);
156 switch (predef_composite
->type_tag
) {
158 dstruct
->args
= psi_plist_add(dstruct
->args
, &darg
);
161 dunion
->args
= psi_plist_add(dunion
->args
, &darg
);
167 switch (predef_composite
->type_tag
) {
169 T
.structs
= psi_plist_add(T
.structs
, &dstruct
);
172 T
.unions
= psi_plist_add(T
.unions
, &dunion
);
178 predef_composite
= member
;
180 for (predef_decl
= &psi_predef_decls
[0]; predef_decl
->type_tag
; ++predef_decl
) {
181 struct psi_predef_decl
*farg
;
182 struct psi_decl_type
*dtype
, *ftype
= psi_decl_type_init(predef_decl
->type_tag
, predef_decl
->type_name
);
183 struct psi_decl_var
*fname
= psi_decl_var_init(predef_decl
->var_name
, predef_decl
->pointer_level
, predef_decl
->array_size
);
184 struct psi_decl_arg
*tdef
, *func
= psi_decl_arg_init(ftype
, fname
);
185 struct psi_plist
*args
= psi_plist_init((psi_plist_dtor
) psi_decl_arg_free
);
186 struct psi_decl
*decl
= psi_decl_init(func
, args
);
188 for (farg
= &predef_decl
[1]; farg
->type_tag
; ++farg
) {
189 struct psi_decl_type
*arg_type
= psi_decl_type_init(farg
->type_tag
, farg
->type_name
);
190 struct psi_decl_var
*arg_var
= psi_decl_var_init(farg
->var_name
, farg
->pointer_level
, farg
->array_size
);
191 struct psi_decl_arg
*darg
= psi_decl_arg_init(arg_type
, arg_var
);
192 decl
->args
= psi_plist_add(decl
->args
, &darg
);
195 switch (predef_decl
->kind
) {
196 case DECL_KIND_VARARG
:
200 T
.decls
= psi_plist_add(T
.decls
, &decl
);
202 case DECL_KIND_FUNCTOR
:
203 dtype
= psi_decl_type_init(PSI_T_FUNCTION
, fname
->name
);
204 dtype
->real
.func
= decl
;
205 tdef
= psi_decl_arg_init(dtype
, psi_decl_var_copy(fname
));
206 T
.types
= psi_plist_add(T
.types
, &tdef
);
219 psi_context_add_data(C
, &T
);
224 static int psi_select_dirent(const struct dirent
*entry
)
227 # define FNM_CASEFOLD 0
229 return 0 == fnmatch("*.psi", entry
->d_name
, FNM_CASEFOLD
);
232 void psi_context_build(struct psi_context
*C
, const char *paths
)
235 char *sep
= NULL
, *cpy
= strdup(paths
), *ptr
= cpy
;
236 struct dirent
**entries
;
239 sep
= strchr(ptr
, ':');
246 n
= php_scandir(ptr
, &entries
, psi_select_dirent
, alphasort
);
249 for (i
= 0; i
< n
; ++i
) {
250 char psi
[MAXPATHLEN
];
252 struct psi_parser_input
*I
;
254 if (MAXPATHLEN
<= slprintf(psi
, MAXPATHLEN
, "%s/%s", ptr
, entries
[i
]->d_name
)) {
255 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Path to PSI file too long: %s/%s",
256 ptr
, entries
[i
]->d_name
);
258 if (!psi_parser_init(&P
, C
->error
, C
->flags
)) {
259 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Failed to init PSI parser (%s): %s",
260 psi
, strerror(errno
));
263 if (!(I
= psi_parser_open_file(&P
, psi
, true))) {
264 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Failed to open PSI file (%s): %s",
265 psi
, strerror(errno
));
268 psi_parser_parse(&P
, I
);
269 psi_context_add_data(C
, PSI_DATA(&P
));
276 for (i
= 0; i
< n
; ++i
) {
286 if (psi_context_compile(C
) && SUCCESS
!= zend_register_functions(NULL
, C
->closures
, NULL
, MODULE_PERSISTENT
)) {
287 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Failed to register functions!");
293 zend_function_entry
*psi_context_compile(struct psi_context
*C
)
297 zc
.flags
= CONST_PERSISTENT
|CONST_CS
;
298 zc
.module_number
= EG(current_module
)->module_number
;
304 while (psi_plist_get(C
->consts
, i
++, &c
)) {
306 if (zend_get_constant_str(c
->name
, strlen(c
->name
))) {
310 zc
.name
= zend_string_init(c
->name
, strlen(c
->name
), 1);
312 switch (c
->type
->type
) {
314 ZVAL_BOOL(&zc
.value
, c
->val
->ival
.zend
.bval
);
317 ZVAL_LONG(&zc
.value
, c
->val
->ival
.zend
.lval
);
320 ZVAL_DOUBLE(&zc
.value
, c
->val
->ival
.dval
);
323 case PSI_T_QUOTED_STRING
:
324 ZVAL_NEW_STR(&zc
.value
, zend_string_copy(c
->val
->ival
.zend
.str
));
331 zend_register_constant(&zc
);
337 struct psi_decl_enum
*e
;
339 while (psi_plist_get(C
->enums
, i
++, &e
)) {
341 struct psi_decl_enum_item
*item
;
343 while (psi_plist_get(e
->items
, j
++, &item
)) {
346 if (psi_decl_type_is_anon(e
->name
, "enum")) {
347 name
= strpprintf(0, "psi\\%s", item
->name
);
349 name
= strpprintf(0, "psi\\%s\\%s", e
->name
, item
->name
);
352 if (zend_get_constant(name
)) {
353 zend_string_release(name
);
357 zc
.name
= zend_string_dup(name
, 1);
358 ZVAL_LONG(&zc
.value
, psi_long_num_exp(item
->num
, NULL
, NULL
));
359 zend_register_constant(&zc
);
360 zend_string_release(name
);
365 return C
->closures
= C
->ops
->compile(C
);
369 ZEND_RESULT_CODE
psi_context_call(struct psi_context
*C
, zend_execute_data
*execute_data
, zval
*return_value
, struct psi_impl
*impl
)
371 struct psi_call_frame
*frame
;
373 frame
= psi_call_frame_init(C
, impl
->decl
, impl
);
375 if (SUCCESS
!= psi_call_frame_parse_args(frame
, execute_data
)) {
376 psi_call_frame_free(frame
);
381 psi_call_frame_enter(frame
);
383 if (SUCCESS
!= psi_call_frame_do_let(frame
)) {
384 psi_call_frame_do_return(frame
, return_value
);
385 psi_call_frame_free(frame
);
390 if (SUCCESS
!= psi_call_frame_do_assert(frame
, PSI_ASSERT_PRE
)) {
391 psi_call_frame_do_return(frame
, return_value
);
392 psi_call_frame_free(frame
);
399 if (SUCCESS
!= psi_call_frame_do_assert(frame
, PSI_ASSERT_POST
)) {
400 psi_call_frame_do_return(frame
, return_value
);
401 psi_call_frame_free(frame
);
406 psi_call_frame_do_return(frame
, return_value
);
407 psi_call_frame_do_set(frame
);
408 psi_call_frame_do_free(frame
);
409 psi_call_frame_free(frame
);
415 void psi_context_dtor(struct psi_context
*C
)
418 zend_function_entry
*zfe
;
424 psi_data_dtor(PSI_DATA(C
));
427 for (i
= 0; i
< C
->count
; ++i
) {
428 psi_data_dtor(&C
->data
[i
]);
434 for (zfe
= C
->closures
; zfe
->fname
; ++zfe
) {
435 free((void *) zfe
->arg_info
);
441 void psi_context_free(struct psi_context
**C
)
444 psi_context_dtor(*C
);
450 bool psi_context_add_data(struct psi_context
*C
, struct psi_data
*P
)
454 C
->data
= realloc(C
->data
, (C
->count
+ 1) * sizeof(*C
->data
));
455 D
= psi_data_exchange(&C
->data
[C
->count
++], P
);
457 return psi_data_validate(PSI_DATA(C
), D
);
460 void psi_context_dump(struct psi_context
*C
, int fd
)
463 dprintf(fd
, "// psi.engine=%s\n",
464 (char *) C
->ops
->query(C
, PSI_CONTEXT_QUERY_SELF
, NULL
));
466 psi_data_dump(fd
, PSI_DATA(C
));
469 // dprintf(fd, "/* parsed\n");
470 // for (i = 0; i < C->count; ++i) {
471 // psi_data_dump(fd, &C->data[i]);
473 // dprintf(fd, "*/\n");