199f533317ed7dfce6981ec01778a3fdfd819511
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_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
;
104 switch (type
->type
) {
106 val
= psi_impl_def_val_init(PSI_T_INT
, NULL
);
107 val
->ival
.zend
.lval
= predef_const
->value
.lval
;
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);
118 constant
= psi_const_init(type
, predef_const
->var_name
, val
);
119 T
.consts
= psi_plist_add(T
.consts
, &constant
);
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
);
127 switch (predef_composite
->type_tag
) {
129 dstruct
= psi_decl_struct_init(predef_composite
->var_name
, dargs
);
130 dstruct
->size
= predef_composite
->size
;
131 dstruct
->align
= predef_composite
->offset
;
134 dunion
= psi_decl_union_init(predef_composite
->var_name
, dargs
);
135 dunion
->size
= predef_composite
->size
;
136 dunion
->align
= predef_composite
->offset
;
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
;
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
);
151 switch (predef_composite
->type_tag
) {
153 dstruct
->args
= psi_plist_add(dstruct
->args
, &darg
);
156 dunion
->args
= psi_plist_add(dunion
->args
, &darg
);
162 switch (predef_composite
->type_tag
) {
164 T
.structs
= psi_plist_add(T
.structs
, &dstruct
);
167 T
.unions
= psi_plist_add(T
.unions
, &dunion
);
173 predef_composite
= member
;
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(psi_decl_abi_init("default"), func
, args
);
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
);
190 switch (predef_decl
->kind
) {
191 case DECL_KIND_VARARG
:
195 T
.decls
= psi_plist_add(T
.decls
, &decl
);
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
);
210 psi_context_add_data(C
, &T
);
215 static int psi_select_dirent(const struct dirent
*entry
)
218 # define FNM_CASEFOLD 0
220 return 0 == fnmatch("*.psi", entry
->d_name
, FNM_CASEFOLD
);
223 void psi_context_build(struct psi_context
*C
, const char *paths
)
226 char *sep
= NULL
, *cpy
= strdup(paths
), *ptr
= cpy
;
227 struct dirent
**entries
;
230 sep
= strchr(ptr
, ':');
237 n
= php_scandir(ptr
, &entries
, psi_select_dirent
, alphasort
);
240 for (i
= 0; i
< n
; ++i
) {
241 char psi
[MAXPATHLEN
];
244 if (MAXPATHLEN
<= slprintf(psi
, MAXPATHLEN
, "%s/%s", ptr
, entries
[i
]->d_name
)) {
245 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Path to PSI file too long: %s/%s",
246 ptr
, entries
[i
]->d_name
);
248 if (!psi_parser_init(&P
, C
->error
, C
->flags
)) {
249 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Failed to init PSI parser (%s): %s",
250 psi
, strerror(errno
));
253 if (!psi_parser_open_file(&P
, psi
)) {
254 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Failed to open PSI file (%s): %s",
255 psi
, strerror(errno
));
259 psi_parser_parse(&P
);
260 psi_context_add_data(C
, PSI_DATA(&P
));
266 for (i
= 0; i
< n
; ++i
) {
276 if (psi_context_compile(C
) && SUCCESS
!= zend_register_functions(NULL
, C
->closures
, NULL
, MODULE_PERSISTENT
)) {
277 C
->error(PSI_DATA(C
), NULL
, PSI_WARNING
, "Failed to register functions!");
283 zend_function_entry
*psi_context_compile(struct psi_context
*C
)
287 zc
.flags
= CONST_PERSISTENT
|CONST_CS
;
288 zc
.module_number
= EG(current_module
)->module_number
;
294 while (psi_plist_get(C
->consts
, i
++, &c
)) {
296 if (zend_get_constant_str(c
->name
, strlen(c
->name
))) {
300 zc
.name
= zend_string_init(c
->name
, strlen(c
->name
), 1);
302 switch (c
->type
->type
) {
304 ZVAL_BOOL(&zc
.value
, c
->val
->ival
.zend
.bval
);
307 ZVAL_LONG(&zc
.value
, c
->val
->ival
.zend
.lval
);
310 ZVAL_DOUBLE(&zc
.value
, c
->val
->ival
.dval
);
313 case PSI_T_QUOTED_STRING
:
314 ZVAL_NEW_STR(&zc
.value
, zend_string_copy(c
->val
->ival
.zend
.str
));
321 zend_register_constant(&zc
);
327 struct psi_decl_enum
*e
;
329 while (psi_plist_get(C
->enums
, i
++, &e
)) {
331 struct psi_decl_enum_item
*item
;
333 while (psi_plist_get(e
->items
, j
++, &item
)) {
334 zend_string
*name
= strpprintf(0, "psi\\%s\\%s", e
->name
, item
->name
);
336 zc
.name
= zend_string_dup(name
, 1);
337 ZVAL_LONG(&zc
.value
, psi_long_num_exp(item
->num
, NULL
, NULL
));
338 zend_register_constant(&zc
);
339 zend_string_release(name
);
344 return C
->closures
= C
->ops
->compile(C
);
348 ZEND_RESULT_CODE
psi_context_call(struct psi_context
*C
, zend_execute_data
*execute_data
, zval
*return_value
, struct psi_impl
*impl
)
350 struct psi_call_frame
*frame
;
352 frame
= psi_call_frame_init(C
, impl
->decl
, impl
);
354 if (SUCCESS
!= psi_call_frame_parse_args(frame
, execute_data
)) {
355 psi_call_frame_free(frame
);
360 psi_call_frame_enter(frame
);
362 if (SUCCESS
!= psi_call_frame_do_let(frame
)) {
363 psi_call_frame_do_return(frame
, return_value
);
364 psi_call_frame_free(frame
);
369 if (SUCCESS
!= psi_call_frame_do_assert(frame
, PSI_ASSERT_PRE
)) {
370 psi_call_frame_do_return(frame
, return_value
);
371 psi_call_frame_free(frame
);
376 psi_call_frame_do_call(frame
);
378 if (SUCCESS
!= psi_call_frame_do_assert(frame
, PSI_ASSERT_POST
)) {
379 psi_call_frame_do_return(frame
, return_value
);
380 psi_call_frame_free(frame
);
385 psi_call_frame_do_return(frame
, return_value
);
386 psi_call_frame_do_set(frame
);
387 psi_call_frame_do_free(frame
);
388 psi_call_frame_free(frame
);
394 void psi_context_dtor(struct psi_context
*C
)
397 zend_function_entry
*zfe
;
403 psi_data_dtor(PSI_DATA(C
));
406 for (i
= 0; i
< C
->count
; ++i
) {
407 psi_data_dtor(&C
->data
[i
]);
413 for (zfe
= C
->closures
; zfe
->fname
; ++zfe
) {
414 free((void *) zfe
->arg_info
);
420 void psi_context_free(struct psi_context
**C
)
423 psi_context_dtor(*C
);
429 bool psi_context_add_data(struct psi_context
*C
, struct psi_data
*P
)
433 C
->data
= realloc(C
->data
, (C
->count
+ 1) * sizeof(*C
->data
));
434 D
= psi_data_exchange(&C
->data
[C
->count
++], P
);
436 return psi_data_validate(PSI_DATA(C
), D
);
439 void psi_context_dump(struct psi_context
*C
, int fd
)
442 dprintf(fd
, "// psi.engine=%s\n",
443 (char *) C
->ops
->query(C
, PSI_CONTEXT_QUERY_SELF
, NULL
));
445 psi_data_dump(fd
, PSI_DATA(C
));
448 // dprintf(fd, "/* parsed\n");
449 // for (i = 0; i < C->count; ++i) {
450 // psi_data_dump(fd, &C->data[i]);
452 // dprintf(fd, "*/\n");