static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, zend_long version) { uint32_t i, count; zend_bool is_list = zend_ast_is_list(ast); zend_ast **children = ast_get_children(ast, &count); for (i = 0; i < count; ++i) { zend_ast *child = children[i]; zend_string *child_name = !is_list && version >= 30 ? ast_kind_child_name(ast->kind, i) : NULL; zval child_zv; if (version >= 20 && ast->kind == ZEND_AST_STMT_LIST && child != NULL && child->kind == ZEND_AST_STMT_LIST) { ast_fill_children_ht(ht, child, version); continue; } if (ast_is_name(child, ast, i)) { ast_create_virtual_node(&child_zv, AST_NAME, child, version); } else if (ast->kind == ZEND_AST_CLOSURE_USES) { ast_create_virtual_node(&child_zv, AST_CLOSURE_VAR, child, version); } else if (version >= 20 && ast_is_var_name(child, ast, i)) { ast_create_virtual_node(&child_zv, ZEND_AST_VAR, child, version); } else if (ast->kind == ZEND_AST_PROP_ELEM && i == 2) { /* Skip docComment child -- It's handled separately */ continue; } else { ast_to_zval(&child_zv, child, version); } if (child_name) { zend_hash_add_new(ht, child_name, &child_zv); } else { zend_hash_next_index_insert(ht, &child_zv); } } }
static void ast_to_zval(zval *zv, zend_ast *ast) { zval tmp_zv; zend_bool is_decl; if (ast == NULL) { ZVAL_NULL(zv); return; } if (ast->kind == ZEND_AST_ZVAL) { ZVAL_COPY(zv, zend_ast_get_zval(ast)); return; } is_decl = ast_kind_is_decl(ast->kind); object_init_ex(zv, is_decl ? ast_decl_ce : ast_node_ce); ZVAL_LONG(&tmp_zv, ast->kind); ast_update_property(zv, AST_G(str_kind), &tmp_zv, AST_CACHE_SLOT_KIND); ZVAL_LONG(&tmp_zv, zend_ast_get_lineno(ast)); ast_update_property(zv, AST_G(str_lineno), &tmp_zv, AST_CACHE_SLOT_LINENO); if (is_decl) { zend_ast_decl *decl = (zend_ast_decl *) ast; ZVAL_LONG(&tmp_zv, decl->flags); ast_update_property(zv, AST_G(str_flags), &tmp_zv, NULL); ZVAL_LONG(&tmp_zv, decl->end_lineno); ast_update_property(zv, AST_G(str_endLineno), &tmp_zv, NULL); if (decl->name) { ZVAL_STR_COPY(&tmp_zv, decl->name); } else { ZVAL_NULL(&tmp_zv); } ast_update_property(zv, AST_G(str_name), &tmp_zv, NULL); if (decl->doc_comment) { ZVAL_STR_COPY(&tmp_zv, decl->doc_comment); } else { ZVAL_NULL(&tmp_zv); } ast_update_property(zv, AST_G(str_docComment), &tmp_zv, NULL); } else { ZVAL_LONG(&tmp_zv, ast->attr); ast_update_property(zv, AST_G(str_flags), &tmp_zv, AST_CACHE_SLOT_FLAGS); } if (ast->kind == ZEND_AST_PROP_DECL) { zend_ast_list *props = zend_ast_get_list(ast); zend_ast *last_prop = props->child[props->children - 1]; /* PROP_DECL stores the doc comment as last property */ if (last_prop->kind == ZEND_AST_ZVAL) { props->children -= 1; ZVAL_STR(&tmp_zv, zend_ast_get_str(last_prop)); ast_update_property(zv, AST_G(str_docComment), &tmp_zv, NULL); } } array_init(&tmp_zv); ast_update_property(zv, AST_G(str_children), &tmp_zv, AST_CACHE_SLOT_CHILDREN); { uint32_t i, count; zend_ast **children = ast_get_children(ast, &count); for (i = 0; i < count; ++i) { zend_ast *child = children[i]; zval child_zv; if (ast_is_name(child, ast, i)) { ast_create_virtual_node(&child_zv, AST_NAME, child); } else if (ast->kind == ZEND_AST_CLOSURE_USES) { ast_create_virtual_node(&child_zv, AST_CLOSURE_VAR, child); } else { ast_to_zval(&child_zv, child); } zend_hash_next_index_insert(Z_ARRVAL(tmp_zv), &child_zv); } } }