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
)) {
288 if (zend_get_constant_str(c
->name
, strlen(c
->name
))) {
292 zc
.name
= zend_string_init(c
->name
+ (c
->name
[0] == '\\'), strlen(c
->name
) - (c
->name
[0] == '\\'), 1);
294 switch (c
->type
->type
) {
296 ZVAL_BOOL(&zc
.value
, c
->val
->ival
.zend
.bval
);
299 ZVAL_LONG(&zc
.value
, c
->val
->ival
.zend
.lval
);
302 ZVAL_DOUBLE(&zc
.value
, c
->val
->ival
.dval
);
305 case PSI_T_QUOTED_STRING
:
306 ZVAL_NEW_STR(&zc
.value
, zend_string_init(c
->val
->text
, strlen(c
->val
->text
), 1));
313 zend_register_constant(&zc
);
319 struct psi_decl_enum
*e
;
321 while (psi_plist_get(C
->enums
, i
++, &e
)) {
323 struct psi_decl_enum_item
*item
;
325 while (psi_plist_get(e
->items
, j
++, &item
)) {
326 zend_string
*name
= strpprintf(0, "psi\\%s\\%s", e
->name
, item
->name
);
328 zc
.name
= zend_string_dup(name
, 1);
329 ZVAL_LONG(&zc
.value
, psi_long_num_exp(item
->num
, NULL
));
330 zend_register_constant(&zc
);
331 zend_string_release(name
);
336 return C
->closures
= C
->ops
->compile(C
);
340 ZEND_RESULT_CODE
psi_context_call(struct psi_context
*C
, zend_execute_data
*execute_data
, zval
*return_value
, struct psi_impl
*impl
)
342 struct psi_call_frame
*frame
;
344 frame
= psi_call_frame_init(C
, impl
->decl
, impl
);
346 if (SUCCESS
!= psi_call_frame_parse_args(frame
, execute_data
)) {
347 psi_call_frame_free(frame
);
352 psi_call_frame_enter(frame
);
354 if (SUCCESS
!= psi_call_frame_do_let(frame
)) {
355 psi_call_frame_do_return(frame
, return_value
);
356 psi_call_frame_free(frame
);
361 psi_call_frame_do_call(frame
);
362 psi_call_frame_do_return(frame
, return_value
);
363 psi_call_frame_do_set(frame
);
364 psi_call_frame_do_free(frame
);
365 psi_call_frame_free(frame
);
371 void psi_context_dtor(struct psi_context
*C
)
374 zend_function_entry
*zfe
;
380 psi_data_dtor(PSI_DATA(C
));
383 for (i
= 0; i
< C
->count
; ++i
) {
384 psi_data_dtor(&C
->data
[i
]);
390 for (zfe
= C
->closures
; zfe
->fname
; ++zfe
) {
391 free((void *) zfe
->arg_info
);
397 void psi_context_free(struct psi_context
**C
)
400 psi_context_dtor(*C
);
406 bool psi_context_add_data(struct psi_context
*C
, struct psi_data
*P
)
410 C
->data
= realloc(C
->data
, (C
->count
+ 1) * sizeof(*C
->data
));
411 D
= psi_data_exchange(&C
->data
[C
->count
++], P
);
413 return psi_data_validate(PSI_DATA(C
), D
);
416 void psi_context_dump(struct psi_context
*C
, int fd
)
419 dprintf(fd
, "// psi.engine=%s\n",
420 (char *) C
->ops
->query(C
, PSI_CONTEXT_QUERY_SELF
, NULL
));
422 psi_data_dump(fd
, PSI_DATA(C
));
425 // dprintf(fd, "/* parsed\n");
426 // for (i = 0; i < C->count; ++i) {
427 // psi_data_dump(fd, &C->data[i]);
429 // dprintf(fd, "*/\n");