42
42
#define AST_PLUS 261
43
43
#define AST_MINUS 262
44
44
45
+ /* Define "void" for PHP 7.0 */
46
+ #ifndef IS_VOID
47
+ #define IS_VOID 18
48
+ #endif
49
+
45
50
static inline void ast_update_property (zval * object , zend_string * name , zval * value , void * * cache_slot ) {
46
51
zval name_zv ;
47
52
ZVAL_STR (& name_zv , name );
@@ -135,11 +140,49 @@ static inline zend_bool ast_is_name(zend_ast *ast, zend_ast *parent, uint32_t i)
135
140
return 0 ;
136
141
}
137
142
143
+ /* Assumes that ast_is_name is already true */
144
+ static inline zend_bool ast_is_type (zend_ast * ast , zend_ast * parent , uint32_t i ) {
145
+ if (i == 0 ) {
146
+ return parent -> kind == ZEND_AST_PARAM ;
147
+ }
148
+ if (i == 3 ) {
149
+ return parent -> kind == ZEND_AST_CLOSURE || parent -> kind == ZEND_AST_FUNC_DECL
150
+ || parent -> kind == ZEND_AST_METHOD ;
151
+ }
152
+ return 0 ;
153
+ }
154
+
138
155
static inline zend_bool ast_is_var_name (zend_ast * ast , zend_ast * parent , uint32_t i ) {
139
156
return (parent -> kind == ZEND_AST_STATIC && i == 0 )
140
157
|| (parent -> kind == ZEND_AST_CATCH && i == 1 );
141
158
}
142
159
160
+ /* Adopted from zend_compile.c */
161
+ typedef struct _builtin_type_info {
162
+ const char * name ;
163
+ const size_t name_len ;
164
+ const zend_uchar type ;
165
+ } builtin_type_info ;
166
+ static const builtin_type_info builtin_types [] = {
167
+ {ZEND_STRL ("int" ), IS_LONG },
168
+ {ZEND_STRL ("float" ), IS_DOUBLE },
169
+ {ZEND_STRL ("string" ), IS_STRING },
170
+ {ZEND_STRL ("bool" ), _IS_BOOL },
171
+ {ZEND_STRL ("void" ), IS_VOID },
172
+ {NULL , 0 , IS_UNDEF }
173
+ };
174
+ static inline zend_uchar lookup_builtin_type (const zend_string * name ) {
175
+ const builtin_type_info * info = & builtin_types [0 ];
176
+ for (; info -> name ; ++ info ) {
177
+ if (ZSTR_LEN (name ) == info -> name_len
178
+ && !zend_binary_strcasecmp (ZSTR_VAL (name ), ZSTR_LEN (name ), info -> name , info -> name_len )
179
+ ) {
180
+ return info -> type ;
181
+ }
182
+ }
183
+ return 0 ;
184
+ }
185
+
143
186
static inline zend_ast_attr ast_assign_op_to_binary_op (zend_ast_attr attr ) {
144
187
switch (attr ) {
145
188
case ZEND_ASSIGN_BW_OR : return ZEND_BW_OR ;
@@ -173,32 +216,42 @@ static inline zend_ast **ast_get_children(zend_ast *ast, uint32_t *count) {
173
216
}
174
217
}
175
218
176
- static void ast_create_virtual_node (
177
- zval * zv , zend_ast_kind kind , zend_ast * ast , zend_long version ) {
219
+ /* "child" may be AST_ZVAL or NULL */
220
+ static void ast_create_virtual_node_ex (
221
+ zval * zv , zend_ast_kind kind , zend_ast_attr attr , uint32_t lineno ,
222
+ zend_ast * child , zend_long version ) {
178
223
zval tmp_zv , tmp_zv2 ;
179
224
180
225
object_init_ex (zv , ast_node_ce );
181
226
182
227
ZVAL_LONG (& tmp_zv , kind );
183
228
ast_update_property (zv , AST_STR (str_kind ), & tmp_zv , AST_CACHE_SLOT_KIND );
184
229
185
- ZVAL_LONG (& tmp_zv , ast -> attr );
230
+ ZVAL_LONG (& tmp_zv , attr );
186
231
ast_update_property (zv , AST_STR (str_flags ), & tmp_zv , AST_CACHE_SLOT_FLAGS );
187
232
188
- ZVAL_LONG (& tmp_zv , zend_ast_get_lineno ( ast ) );
233
+ ZVAL_LONG (& tmp_zv , lineno );
189
234
ast_update_property (zv , AST_STR (str_lineno ), & tmp_zv , AST_CACHE_SLOT_LINENO );
190
235
191
236
array_init (& tmp_zv );
192
237
ast_update_property (zv , AST_STR (str_children ), & tmp_zv , AST_CACHE_SLOT_CHILDREN );
193
238
194
- ZVAL_COPY (& tmp_zv2 , zend_ast_get_zval (ast ));
195
- if (version >= 30 ) {
196
- zend_hash_add_new (Z_ARRVAL (tmp_zv ), ast_kind_child_name (kind , 0 ), & tmp_zv2 );
197
- } else {
198
- zend_hash_next_index_insert (Z_ARRVAL (tmp_zv ), & tmp_zv2 );
239
+ if (child ) {
240
+ ZVAL_COPY (& tmp_zv2 , zend_ast_get_zval (child ));
241
+ if (version >= 30 ) {
242
+ zend_hash_add_new (Z_ARRVAL (tmp_zv ), ast_kind_child_name (kind , 0 ), & tmp_zv2 );
243
+ } else {
244
+ zend_hash_next_index_insert (Z_ARRVAL (tmp_zv ), & tmp_zv2 );
245
+ }
199
246
}
200
247
}
201
248
249
+ static void ast_create_virtual_node (
250
+ zval * zv , zend_ast_kind kind , zend_ast * child , zend_long version ) {
251
+ return ast_create_virtual_node_ex (
252
+ zv , kind , child -> attr , zend_ast_get_lineno (child ), child , version );
253
+ }
254
+
202
255
static void ast_to_zval (zval * zv , zend_ast * ast , zend_long version );
203
256
204
257
static void ast_fill_children_ht (HashTable * ht , zend_ast * ast , zend_long version ) {
@@ -222,6 +275,7 @@ static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, zend_long version
222
275
}
223
276
224
277
if (ast_is_name (child , ast , i )) {
278
+ zend_uchar type ;
225
279
if (version >= 40 && child -> attr == ZEND_NAME_FQ ) {
226
280
/* Ensure there is no leading \ for fully-qualified names. This can happen if
227
281
* something like ('\bar')() is used. */
@@ -234,7 +288,14 @@ static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, zend_long version
234
288
}
235
289
}
236
290
237
- ast_create_virtual_node (& child_zv , AST_NAME , child , version );
291
+ if (version >= 40 && child -> attr == ZEND_NAME_NOT_FQ && ast_is_type (child , ast , i )
292
+ && (type = lookup_builtin_type (zend_ast_get_str (child )))) {
293
+ /* Convert "int" etc typehints to TYPE nodes */
294
+ ast_create_virtual_node_ex (
295
+ & child_zv , ZEND_AST_TYPE , type , zend_ast_get_lineno (child ), NULL , version );
296
+ } else {
297
+ ast_create_virtual_node (& child_zv , AST_NAME , child , version );
298
+ }
238
299
} else if (ast -> kind == ZEND_AST_CLOSURE_USES ) {
239
300
ast_create_virtual_node (& child_zv , AST_CLOSURE_VAR , child , version );
240
301
} else if (version >= 20 && ast_is_var_name (child , ast , i )) {
@@ -613,6 +674,7 @@ PHP_MINIT_FUNCTION(ast) {
613
674
ast_register_flag_constant ("TYPE_ARRAY" , IS_ARRAY );
614
675
ast_register_flag_constant ("TYPE_OBJECT" , IS_OBJECT );
615
676
ast_register_flag_constant ("TYPE_CALLABLE" , IS_CALLABLE );
677
+ ast_register_flag_constant ("TYPE_VOID" , IS_VOID );
616
678
617
679
ast_register_flag_constant ("UNARY_BOOL_NOT" , ZEND_BOOL_NOT );
618
680
ast_register_flag_constant ("UNARY_BITWISE_NOT" , ZEND_BW_NOT );
0 commit comments