pax_global_header00006660000000000000000000000064126303624020014510gustar00rootroot0000000000000052 comment=3b9abc7b6012d760de99e10edc99c9742dafd11a php-ast-0.1.1/000077500000000000000000000000001263036240200130635ustar00rootroot00000000000000php-ast-0.1.1/.gitignore000066400000000000000000000006141263036240200150540ustar00rootroot00000000000000.deps *.o *.lo *.la *.swp .libs acinclude.m4 aclocal.m4 autom4te.cache build config.guess config.h config.h.in config.log config.nice config.status config.sub configure configure.in include install-sh libtool ltmain.sh Makefile Makefile.fragments Makefile.global Makefile.objects missing mkinstalldirs modules run-tests.php tests/*.diff tests/*.out tests/*.php tests/*.exp tests/*.log tests/*.sh php-ast-0.1.1/.travis.yml000066400000000000000000000003771263036240200152030ustar00rootroot00000000000000language: php php: - 7.0 before_script: - phpize - ./configure - make - make install - echo "extension=ast.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini script: - REPORT_EXIT_STATUS=1 php ./run-tests.php -P -q --show-diff php-ast-0.1.1/EXPERIMENTAL000066400000000000000000000000001263036240200146710ustar00rootroot00000000000000php-ast-0.1.1/LICENSE000066400000000000000000000027231263036240200140740ustar00rootroot00000000000000Copyright (c) 2014 by Nikita Popov. Some rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. php-ast-0.1.1/README.md000066400000000000000000000204771263036240200143540ustar00rootroot00000000000000This extension exposes the abstract syntax tree generated by PHP 7. This extension is experimental and the representation of the syntax tree is not final. API overview ------------ Defines: * `ast\Node` class * `ast\Node\Decl` class * `ast\AST_*` kind constants (mirroring `zend_ast.h`) * `ast\flags\*` flags * `ast\parse_file(string $filename, int $version)` * `ast\parse_code(string $code, int $version [, string $filename = "string code"])` * `ast\get_kind_name(int $kind)` * `ast\kind_uses_flags(int $kind)` Usage ----- Code can be parsed using either `ast\parse_code()`, which accepts a code string, or `ast\parse_file()`, which accepts a file path. Additionally both functions require a `$version` argument to ensure forward-compatibility. The current version is 15. ```php $ast = ast\parse_code(' int(133) ["flags"]=> int(0) ["lineno"]=> int(1) ["children"]=> array(1) { [0]=> object(ast\Node)#2 (4) { ["kind"]=> int(517) ["flags"]=> int(0) ["lineno"]=> int(1) ["children"]=> array(2) { [0]=> object(ast\Node)#3 (4) { ["kind"]=> int(256) ["flags"]=> int(0) ["lineno"]=> int(1) ["children"]=> array(1) { [0]=> string(3) "var" } } [1]=> int(42) } } } } ``` The [`util.php`][util] file defines an `ast_dump()` function, which can be used to create a more compact and human-readable dump of the AST structure: ```php flags & ast\flags\FOO`. The "exclusive" flags are used standalone and should be checked using `$ast->flags === ast\flags\BAR`. ``` // Used by ast\AST_ARRAY_ELEM and ast\AST_CLOSURE_VAR (exclusive) 1 = by-reference // Used by ast\AST_NAME (exclusive) ast\flags\NAME_FQ (= 0) ast\flags\NAME_NOT_FQ ast\flags\NAME_RELATIVE // Used by ast\AST_METHOD, ast\AST_PROP_DECL, ast\AST_TRAIT_ALIAS (combinable) ast\flags\MODIFIER_PUBLIC ast\flags\MOFIFIER_PROTECTED ast\flags\MOFIFIER_PRIVATE ast\flags\MOFIFIER_STATIC ast\flags\MOFIFIER_ABSTRACT ast\flags\MOFIFIER_FINAL // Used by ast\AST_CLOSURE (combinable) ast\flags\MODIFIER_STATIC // Used by ast\AST_FUNC_DECL, ast\AST_METHOD, ast\AST_CLOSURE (combinable) ast\flags\RETURNS_REF // Used by ast\AST_CLASS (exclusive) ast\flags\CLASS_ABSTRACT ast\flags\CLASS_FINAL ast\flags\CLASS_TRAIT ast\flags\CLASS_INTERFACE ast\flags\CLASS_ANONYMOUS // Used by ast\AST_PARAM (exclusive) ast\flags\PARAM_REF ast\flags\PARAM_VARIADIC // Used by ast\AST_TYPE (exclusive) ast\flags\TYPE_ARRAY ast\flags\TYPE_CALLABLE // Used by ast\AST_CAST (exclusive) ast\flags\TYPE_NULL ast\flags\TYPE_BOOL ast\flags\TYPE_LONG ast\flags\TYPE_DOUBLE ast\flags\TYPE_STRING ast\flags\TYPE_ARRAY ast\flags\TYPE_OBJECT // Used by ast\AST_UNARY_OP (exclusive) ast\flags\UNARY_BOOL_NOT ast\flags\UNARY_BITWISE_NOT ast\flags\UNARY_MINUS // since version 20 ast\flags\UNARY_PLUS // since version 20 ast\flags\UNARY_SILENCE // since version 20 // Used by ast\AST_BINARY_OP and ast\AST_ASSIGN_OP in version >= 20 (exclusive) ast\flags\BINARY_BITWISE_OR ast\flags\BINARY_BITWISE_AND ast\flags\BINARY_BITWISE_XOR ast\flags\BINARY_CONCAT ast\flags\BINARY_ADD ast\flags\BINARY_SUB ast\flags\BINARY_MUL ast\flags\BINARY_DIV ast\flags\BINARY_MOD ast\flags\BINARY_POW ast\flags\BINARY_SHIFT_LEFT ast\flags\BINARY_SHIFT_RIGHT // Used by ast\AST_BINARY_OP (exclusive) ast\flags\BINARY_BOOL_AND // since version 20 ast\flags\BINARY_BOOL_OR // since version 20 ast\flags\BINARY_BOOL_XOR ast\flags\BINARY_IS_IDENTICAL ast\flags\BINARY_IS_NOT_IDENTICAL ast\flags\BINARY_IS_EQUAL ast\flags\BINARY_IS_NOT_EQUAL ast\flags\BINARY_IS_SMALLER ast\flags\BINARY_IS_SMALLER_OR_EQUAL ast\flags\BINARY_IS_GREATER // since version 20 ast\flags\BINARY_IS_GREATER_OR_EQUAL // since version 20 ast\flags\BINARY_SPACESHIP // Used by ast\AST_ASSIGN_OP in versions before 20 (exclusive) ast\flags\ASSIGN_BITWISE_OR ast\flags\ASSIGN_BITWISE_AND ast\flags\ASSIGN_BITWISE_XOR ast\flags\ASSIGN_CONCAT ast\flags\ASSIGN_ADD ast\flags\ASSIGN_SUB ast\flags\ASSIGN_MUL ast\flags\ASSIGN_DIV ast\flags\ASSIGN_MOD ast\flags\ASSIGN_POW ast\flags\ASSIGN_SHIFT_LEFT ast\flags\ASSIGN_SHIFT_RIGHT // Used by ast\AST_MAGIC_CONST (exclusive) ast\flags\MAGIC_LINE ast\flags\MAGIC_FILE ast\flags\MAGIC_DIR ast\flags\MAGIC_NAMESPACE ast\flags\MAGIC_FUNCTION ast\flags\MAGIC_METHOD ast\flags\MAGIC_CLASS ast\flags\MAGIC_TRAIT // Used by ast\AST_USE, ast\AST_GROUP_USE and ast\AST_USE_ELEM (exclusive) ast\flags\USE_NORMAL ast\flags\USE_FUNCTION ast\flags\USE_CONST // Used by ast\AST_INCLUDE_OR_EVAL (exclusive) ast\flags\EXEC_EVAL ast\flags\EXEC_INCLUDE ast\flags\EXEC_INCLUDE_ONCE ast\flags\EXEC_REQUIRE ast\flags\EXEC_REQUIRE_ONCE ``` Version changelog ----------------- ### 30 (unstable) * Use string names for child nodes of kinds with fixed length. ### 20 (current) * `AST_GREATER`, `AST_GREATER_EQUAL`, `AST_OR`, `AST_AND` nodes are now represented using `AST_BINARY_OP` with flags `BINARY_IS_GREATER`, `BINARY_IS_GREATER_OR_EQUAL`, `BINARY_BOOL_OR` and `BINARY_BOOL_AND`. * `AST_SILENCE`, `AST_UNARY_MINUS` and `AST_UNARY_PLUS` nodes are now represented using `AST_UNARY_OP` with flags `UNARY_SILENCE`, `UNARY_MINUS` and `UNARY_PLUS` * `AST_ASSIGN_OP` now uses `BINARY_*` flags instead of separate `ASSIGN_*` flags. * `AST_STATIC` and `AST_CATCH` now use an `AST_VAR` node for the static/catch variable. Previously it was a simple string containing the name. * Nested `AST_STMT_LIST`s are now flattened out. ### 15 (supported) * In line with an upstream change, the `docComment` property on `AST_PROP_DECL` has been moved to `AST_PROP_ELEM`. This means that each property in one property declaration can have its own doc comment. ### 10 (supported) Initial. [parser]: http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_language_parser.y [util]: https://github.com/nikic/php-ast/blob/master/util.php [test_dump]: https://github.com/nikic/php-ast/blob/master/tests/001.phpt php-ast-0.1.1/ast.c000066400000000000000000000514531263036240200140260ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_ast.h" #include "ext/spl/spl_exceptions.h" #include "zend_language_scanner.h" #include "zend_language_scanner_defs.h" #include "zend_language_parser.h" #include "zend_exceptions.h" #include "zend_smart_str.h" #define ast_throw_exception(exception_ce, ...) \ zend_throw_exception_ex(exception_ce, 0, __VA_ARGS__) #define ast_declare_property(ce, name, value) \ zend_declare_property_ex((ce), (name), (value), ZEND_ACC_PUBLIC, NULL) #define ast_register_flag_constant(name, value) \ REGISTER_NS_LONG_CONSTANT("ast\\flags", name, value, CONST_CS | CONST_PERSISTENT) #define AST_CACHE_SLOT_KIND &AST_G(cache_slots)[2 * 0] #define AST_CACHE_SLOT_FLAGS &AST_G(cache_slots)[2 * 1] #define AST_CACHE_SLOT_LINENO &AST_G(cache_slots)[2 * 2] #define AST_CACHE_SLOT_CHILDREN &AST_G(cache_slots)[2 * 3] #define AST_CURRENT_VERSION 20 /* Additional flags for BINARY_OP */ #define AST_BINARY_IS_GREATER 256 #define AST_BINARY_IS_GREATER_OR_EQUAL 257 #define AST_BINARY_BOOL_OR 258 #define AST_BINARY_BOOL_AND 259 /* Flags for UNARY_OP to use instead of AST_SILENCE, AST_UNARY_PLUS, AST_UNARY_MINUS */ #define AST_SILENCE 260 #define AST_PLUS 261 #define AST_MINUS 262 static inline void ast_update_property(zval *object, zend_string *name, zval *value, void **cache_slot) { zval name_zv; ZVAL_STR(&name_zv, name); Z_TRY_DELREF_P(value); Z_OBJ_HT_P(object)->write_property(object, &name_zv, value, cache_slot); } ZEND_DECLARE_MODULE_GLOBALS(ast) static zend_class_entry *ast_node_ce; static zend_class_entry *ast_decl_ce; static zend_ast *get_ast(zend_string *code, zend_arena **ast_arena, char *filename) { zval code_zv; zend_bool original_in_compilation; zend_lex_state original_lex_state; zend_ast *ast; ZVAL_STR_COPY(&code_zv, code); original_in_compilation = CG(in_compilation); CG(in_compilation) = 1; zend_save_lexical_state(&original_lex_state); if (zend_prepare_string_for_scanning(&code_zv, filename) == SUCCESS) { CG(ast) = NULL; CG(ast_arena) = zend_arena_create(1024 * 32); LANG_SCNG(yy_state) = yycINITIAL; if (zendparse() != 0) { zend_ast_destroy(CG(ast)); zend_arena_destroy(CG(ast_arena)); CG(ast) = NULL; } } /* restore_lexical_state changes CG(ast) and CG(ast_arena) */ ast = CG(ast); *ast_arena = CG(ast_arena); zend_restore_lexical_state(&original_lex_state); CG(in_compilation) = original_in_compilation; zval_dtor(&code_zv); return ast; } static inline zend_bool ast_kind_uses_attr(zend_ast_kind kind) { return kind == ZEND_AST_PARAM || kind == ZEND_AST_TYPE || kind == ZEND_AST_TRAIT_ALIAS || kind == ZEND_AST_UNARY_OP || kind == ZEND_AST_BINARY_OP || kind == ZEND_AST_ASSIGN_OP || kind == ZEND_AST_CAST || kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_ARRAY_ELEM || kind == ZEND_AST_INCLUDE_OR_EVAL || kind == ZEND_AST_USE || kind == ZEND_AST_PROP_DECL || kind == ZEND_AST_GROUP_USE || kind == ZEND_AST_USE_ELEM || kind == AST_NAME || kind == AST_CLOSURE_VAR; } static inline zend_bool ast_kind_is_decl(zend_ast_kind kind) { return kind == ZEND_AST_FUNC_DECL || kind == ZEND_AST_CLOSURE || kind == ZEND_AST_METHOD || kind == ZEND_AST_CLASS; } static inline zend_bool ast_is_name(zend_ast *ast, zend_ast *parent, uint32_t i) { if (!ast || ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(ast)) != IS_STRING) { return 0; } if (parent->kind == ZEND_AST_NAME_LIST) { return 1; } if (i == 0) { return parent->kind == ZEND_AST_CATCH || parent->kind == ZEND_AST_CLASS || parent->kind == ZEND_AST_PARAM || parent->kind == ZEND_AST_METHOD_REFERENCE || parent->kind == ZEND_AST_CALL || parent->kind == ZEND_AST_CONST || parent->kind == ZEND_AST_NEW || parent->kind == ZEND_AST_STATIC_CALL || parent->kind == ZEND_AST_CLASS_CONST || parent->kind == ZEND_AST_STATIC_PROP ; } if (i == 1) { return parent->kind == ZEND_AST_INSTANCEOF; } if (i == 3) { return parent->kind == ZEND_AST_FUNC_DECL || parent->kind == ZEND_AST_CLOSURE || parent->kind == ZEND_AST_METHOD; } return 0; } static inline zend_bool ast_is_var_name(zend_ast *ast, zend_ast *parent, uint32_t i) { return (parent->kind == ZEND_AST_STATIC && i == 0) || (parent->kind == ZEND_AST_CATCH && i == 1); } static inline zend_ast_attr ast_assign_op_to_binary_op(zend_ast_attr attr) { switch (attr) { case ZEND_ASSIGN_BW_OR: return ZEND_BW_OR; case ZEND_ASSIGN_BW_AND: return ZEND_BW_AND; case ZEND_ASSIGN_BW_XOR: return ZEND_BW_XOR; case ZEND_ASSIGN_CONCAT: return ZEND_CONCAT; case ZEND_ASSIGN_ADD: return ZEND_ADD; case ZEND_ASSIGN_SUB: return ZEND_SUB; case ZEND_ASSIGN_MUL: return ZEND_MUL; case ZEND_ASSIGN_DIV: return ZEND_DIV; case ZEND_ASSIGN_MOD: return ZEND_MOD; case ZEND_ASSIGN_POW: return ZEND_POW; case ZEND_ASSIGN_SL: return ZEND_SL; case ZEND_ASSIGN_SR: return ZEND_SR; EMPTY_SWITCH_DEFAULT_CASE() } } static inline zend_ast **ast_get_children(zend_ast *ast, uint32_t *count) { if (ast_kind_is_decl(ast->kind)) { zend_ast_decl *decl = (zend_ast_decl *) ast; *count = decl->kind == ZEND_AST_CLASS ? 3 : 4; return decl->child; } else if (zend_ast_is_list(ast)) { zend_ast_list *list = zend_ast_get_list(ast); *count = list->children; return list->child; } else { *count = zend_ast_get_num_children(ast); return ast->child; } } static void ast_create_virtual_node( zval *zv, zend_ast_kind kind, zend_ast *ast, zend_long version) { zval tmp_zv, tmp_zv2; object_init_ex(zv, ast_node_ce); ZVAL_LONG(&tmp_zv, kind); ast_update_property(zv, AST_STR(str_kind), &tmp_zv, AST_CACHE_SLOT_KIND); ZVAL_LONG(&tmp_zv, ast->attr); ast_update_property(zv, AST_STR(str_flags), &tmp_zv, AST_CACHE_SLOT_FLAGS); ZVAL_LONG(&tmp_zv, zend_ast_get_lineno(ast)); ast_update_property(zv, AST_STR(str_lineno), &tmp_zv, AST_CACHE_SLOT_LINENO); array_init(&tmp_zv); ast_update_property(zv, AST_STR(str_children), &tmp_zv, AST_CACHE_SLOT_CHILDREN); ZVAL_COPY(&tmp_zv2, zend_ast_get_zval(ast)); if (version >= 30) { zend_hash_add_new(Z_ARRVAL(tmp_zv), ast_kind_child_name(kind, 0), &tmp_zv2); } else { zend_hash_next_index_insert(Z_ARRVAL(tmp_zv), &tmp_zv2); } } static void ast_to_zval(zval *zv, zend_ast *ast, zend_long version); 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, zend_long version) { 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; } if (version >= 20) { switch (ast->kind) { case ZEND_AST_ASSIGN_OP: ast->attr = ast_assign_op_to_binary_op(ast->attr); break; case ZEND_AST_GREATER: ast->kind = ZEND_AST_BINARY_OP; ast->attr = AST_BINARY_IS_GREATER; break; case ZEND_AST_GREATER_EQUAL: ast->kind = ZEND_AST_BINARY_OP; ast->attr = AST_BINARY_IS_GREATER_OR_EQUAL; break; case ZEND_AST_OR: ast->kind = ZEND_AST_BINARY_OP; ast->attr = AST_BINARY_BOOL_OR; break; case ZEND_AST_AND: ast->kind = ZEND_AST_BINARY_OP; ast->attr = AST_BINARY_BOOL_AND; break; case ZEND_AST_SILENCE: ast->kind = ZEND_AST_UNARY_OP; ast->attr = AST_SILENCE; break; case ZEND_AST_UNARY_PLUS: ast->kind = ZEND_AST_UNARY_OP; ast->attr = AST_PLUS; break; case ZEND_AST_UNARY_MINUS: ast->kind = ZEND_AST_UNARY_OP; ast->attr = AST_MINUS; break; } } 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_STR(str_kind), &tmp_zv, AST_CACHE_SLOT_KIND); ZVAL_LONG(&tmp_zv, zend_ast_get_lineno(ast)); ast_update_property(zv, AST_STR(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_STR(str_flags), &tmp_zv, NULL); ZVAL_LONG(&tmp_zv, decl->end_lineno); ast_update_property(zv, AST_STR(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_STR(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_STR(str_docComment), &tmp_zv, NULL); } else { ZVAL_LONG(&tmp_zv, ast->attr); ast_update_property(zv, AST_STR(str_flags), &tmp_zv, AST_CACHE_SLOT_FLAGS); } if (version < 15 && ast->kind == ZEND_AST_PROP_DECL) { /* Before version 15 the first docComment was stored on the PROP_DECL */ zend_ast_list *props = zend_ast_get_list(ast); uint32_t i; for (i = 0; i < props->children; ++i) { zend_ast *prop = props->child[i]; if (prop->child[2]) { ZVAL_STR_COPY(&tmp_zv, zend_ast_get_str(prop->child[2])); ast_update_property(zv, AST_STR(str_docComment), &tmp_zv, NULL); break; } } } if (version >= 15 && ast->kind == ZEND_AST_PROP_ELEM && ast->child[2]) { ZVAL_STR_COPY(&tmp_zv, zend_ast_get_str(ast->child[2])); ast_update_property(zv, AST_STR(str_docComment), &tmp_zv, NULL); } array_init(&tmp_zv); ast_update_property(zv, AST_STR(str_children), &tmp_zv, AST_CACHE_SLOT_CHILDREN); ast_fill_children_ht(Z_ARRVAL(tmp_zv), ast, version); } static const zend_long versions[] = {10, 15, 20, 30}; static const size_t versions_count = sizeof(versions)/sizeof(versions[0]); static zend_string *ast_version_info() { smart_str str = {0}; size_t i; smart_str_appends(&str, "Current version is "); smart_str_append_long(&str, AST_CURRENT_VERSION); smart_str_appends(&str, ". All versions (including experimental): {"); for (i = 0; i < versions_count; ++i) { if (i != 0) smart_str_appends(&str, ", "); smart_str_append_long(&str, versions[i]); } smart_str_appends(&str, "}"); smart_str_0(&str); return str.s; } static int ast_check_version(zend_long version) { size_t i; zend_string *version_info; for (i = 0; i < versions_count; ++i) { if (version == versions[i]) { return SUCCESS; } } version_info = ast_version_info(); if (version != -1) { ast_throw_exception(spl_ce_LogicException, "Unknown version " ZEND_LONG_FMT ". %s", version, ZSTR_VAL(version_info)); } else { ast_throw_exception(spl_ce_LogicException, "No version specified. %s", ZSTR_VAL(version_info)); } zend_string_release(version_info); return FAILURE; } PHP_FUNCTION(parse_file) { zend_string *filename, *code; zend_long version = -1; zend_ast *ast; zend_arena *arena; php_stream *stream; zend_error_handling error_handling; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "P|l", &filename, &version) == FAILURE) { return; } if (ast_check_version(version) == FAILURE) { return; } zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling); stream = php_stream_open_wrapper_ex(filename->val, "rb", REPORT_ERRORS, NULL, NULL); if (!stream) { zend_restore_error_handling(&error_handling); return; } code = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0); php_stream_close(stream); zend_restore_error_handling(&error_handling); if (!code) { return; } ast = get_ast(code, &arena, filename->val); if (!ast) { zend_string_free(code); return; } ast_to_zval(return_value, ast, version); zend_string_free(code); zend_ast_destroy(ast); zend_arena_destroy(arena); } PHP_FUNCTION(parse_code) { zend_string *code, *filename = NULL; zend_long version = -1; zend_ast *ast; zend_arena *arena; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "S|lP", &code, &version, &filename) == FAILURE) { return; } if (ast_check_version(version) == FAILURE) { return; } ast = get_ast(code, &arena, filename ? filename->val : "string code"); if (!ast) { return; } ast_to_zval(return_value, ast, version); zend_ast_destroy(ast); zend_arena_destroy(arena); } PHP_FUNCTION(get_kind_name) { zend_long kind; const char *name; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "l", &kind) == FAILURE) { return; } name = ast_kind_to_name(kind); if (!name) { ast_throw_exception(spl_ce_LogicException, "Unknown kind %pd", kind); return; } RETURN_STRING(name); } PHP_FUNCTION(kind_uses_flags) { zend_long kind; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "l", &kind) == FAILURE) { return; } RETURN_BOOL(ast_kind_uses_attr(kind) || ast_kind_is_decl(kind)); } ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_file, 0, 0, 1) ZEND_ARG_INFO(0, filename) ZEND_ARG_INFO(0, version) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_code, 0, 0, 1) ZEND_ARG_INFO(0, code) ZEND_ARG_INFO(0, version) ZEND_ARG_INFO(0, filename) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_get_kind_name, 0, 0, 1) ZEND_ARG_INFO(0, kind) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_kind_uses_flags, 0, 0, 1) ZEND_ARG_INFO(0, kind) ZEND_END_ARG_INFO() const zend_function_entry ast_functions[] = { ZEND_NS_FE("ast", parse_file, arginfo_parse_file) ZEND_NS_FE("ast", parse_code, arginfo_parse_code) ZEND_NS_FE("ast", get_kind_name, arginfo_get_kind_name) ZEND_NS_FE("ast", kind_uses_flags, arginfo_kind_uses_flags) PHP_FE_END }; PHP_MINFO_FUNCTION(ast) { php_info_print_table_start(); php_info_print_table_header(2, "ast support", "enabled"); php_info_print_table_end(); } PHP_RINIT_FUNCTION(ast) { memset(AST_G(cache_slots), 0, sizeof(void *) * AST_NUM_CACHE_SLOTS); return SUCCESS; } PHP_MINIT_FUNCTION(ast) { zend_class_entry tmp_ce; #define X(str) \ AST_STR(str_ ## str) = zend_new_interned_string( \ zend_string_init(#str, sizeof(#str) - 1, 1)); AST_STR_DEFS #undef X ast_register_kind_constants(INIT_FUNC_ARGS_PASSTHRU); ast_register_flag_constant("NAME_FQ", ZEND_NAME_FQ); ast_register_flag_constant("NAME_NOT_FQ", ZEND_NAME_NOT_FQ); ast_register_flag_constant("NAME_RELATIVE", ZEND_NAME_RELATIVE); ast_register_flag_constant("MODIFIER_PUBLIC", ZEND_ACC_PUBLIC); ast_register_flag_constant("MODIFIER_PROTECTED", ZEND_ACC_PROTECTED); ast_register_flag_constant("MODIFIER_PRIVATE", ZEND_ACC_PRIVATE); ast_register_flag_constant("MODIFIER_STATIC", ZEND_ACC_STATIC); ast_register_flag_constant("MODIFIER_ABSTRACT", ZEND_ACC_ABSTRACT); ast_register_flag_constant("MODIFIER_FINAL", ZEND_ACC_FINAL); ast_register_flag_constant("RETURNS_REF", ZEND_ACC_RETURN_REFERENCE); ast_register_flag_constant("CLASS_ABSTRACT", ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); ast_register_flag_constant("CLASS_FINAL", ZEND_ACC_FINAL); ast_register_flag_constant("CLASS_TRAIT", ZEND_ACC_TRAIT); ast_register_flag_constant("CLASS_INTERFACE", ZEND_ACC_INTERFACE); ast_register_flag_constant("CLASS_ANONYMOUS", ZEND_ACC_ANON_CLASS); ast_register_flag_constant("PARAM_REF", ZEND_PARAM_REF); ast_register_flag_constant("PARAM_VARIADIC", ZEND_PARAM_VARIADIC); ast_register_flag_constant("TYPE_NULL", IS_NULL); ast_register_flag_constant("TYPE_BOOL", _IS_BOOL); ast_register_flag_constant("TYPE_LONG", IS_LONG); ast_register_flag_constant("TYPE_DOUBLE", IS_DOUBLE); ast_register_flag_constant("TYPE_STRING", IS_STRING); ast_register_flag_constant("TYPE_ARRAY", IS_ARRAY); ast_register_flag_constant("TYPE_OBJECT", IS_OBJECT); ast_register_flag_constant("TYPE_CALLABLE", IS_CALLABLE); ast_register_flag_constant("UNARY_BOOL_NOT", ZEND_BOOL_NOT); ast_register_flag_constant("UNARY_BITWISE_NOT", ZEND_BW_NOT); ast_register_flag_constant("UNARY_SILENCE", AST_SILENCE); ast_register_flag_constant("UNARY_PLUS", AST_PLUS); ast_register_flag_constant("UNARY_MINUS", AST_MINUS); ast_register_flag_constant("BINARY_BOOL_AND", AST_BINARY_BOOL_AND); ast_register_flag_constant("BINARY_BOOL_OR", AST_BINARY_BOOL_OR); ast_register_flag_constant("BINARY_BOOL_XOR", ZEND_BOOL_XOR); ast_register_flag_constant("BINARY_BITWISE_OR", ZEND_BW_OR); ast_register_flag_constant("BINARY_BITWISE_AND", ZEND_BW_AND); ast_register_flag_constant("BINARY_BITWISE_XOR", ZEND_BW_XOR); ast_register_flag_constant("BINARY_CONCAT", ZEND_CONCAT); ast_register_flag_constant("BINARY_ADD", ZEND_ADD); ast_register_flag_constant("BINARY_SUB", ZEND_SUB); ast_register_flag_constant("BINARY_MUL", ZEND_MUL); ast_register_flag_constant("BINARY_DIV", ZEND_DIV); ast_register_flag_constant("BINARY_MOD", ZEND_MOD); ast_register_flag_constant("BINARY_POW", ZEND_POW); ast_register_flag_constant("BINARY_SHIFT_LEFT", ZEND_SL); ast_register_flag_constant("BINARY_SHIFT_RIGHT", ZEND_SR); ast_register_flag_constant("BINARY_IS_IDENTICAL", ZEND_IS_IDENTICAL); ast_register_flag_constant("BINARY_IS_NOT_IDENTICAL", ZEND_IS_NOT_IDENTICAL); ast_register_flag_constant("BINARY_IS_EQUAL", ZEND_IS_EQUAL); ast_register_flag_constant("BINARY_IS_NOT_EQUAL", ZEND_IS_NOT_EQUAL); ast_register_flag_constant("BINARY_IS_SMALLER", ZEND_IS_SMALLER); ast_register_flag_constant("BINARY_IS_SMALLER_OR_EQUAL", ZEND_IS_SMALLER_OR_EQUAL); ast_register_flag_constant("BINARY_IS_GREATER", AST_BINARY_IS_GREATER); ast_register_flag_constant("BINARY_IS_GREATER_OR_EQUAL", AST_BINARY_IS_GREATER_OR_EQUAL); ast_register_flag_constant("BINARY_SPACESHIP", ZEND_SPACESHIP); ast_register_flag_constant("ASSIGN_BITWISE_OR", ZEND_ASSIGN_BW_OR); ast_register_flag_constant("ASSIGN_BITWISE_AND", ZEND_ASSIGN_BW_AND); ast_register_flag_constant("ASSIGN_BITWISE_XOR", ZEND_ASSIGN_BW_XOR); ast_register_flag_constant("ASSIGN_CONCAT", ZEND_ASSIGN_CONCAT); ast_register_flag_constant("ASSIGN_ADD", ZEND_ASSIGN_ADD); ast_register_flag_constant("ASSIGN_SUB", ZEND_ASSIGN_SUB); ast_register_flag_constant("ASSIGN_MUL", ZEND_ASSIGN_MUL); ast_register_flag_constant("ASSIGN_DIV", ZEND_ASSIGN_DIV); ast_register_flag_constant("ASSIGN_MOD", ZEND_ASSIGN_MOD); ast_register_flag_constant("ASSIGN_POW", ZEND_ASSIGN_POW); ast_register_flag_constant("ASSIGN_SHIFT_LEFT", ZEND_ASSIGN_SL); ast_register_flag_constant("ASSIGN_SHIFT_RIGHT", ZEND_ASSIGN_SR); ast_register_flag_constant("EXEC_EVAL", ZEND_EVAL); ast_register_flag_constant("EXEC_INCLUDE", ZEND_INCLUDE); ast_register_flag_constant("EXEC_INCLUDE_ONCE", ZEND_INCLUDE_ONCE); ast_register_flag_constant("EXEC_REQUIRE", ZEND_REQUIRE); ast_register_flag_constant("EXEC_REQUIRE_ONCE", ZEND_REQUIRE_ONCE); ast_register_flag_constant("USE_NORMAL", T_CLASS); ast_register_flag_constant("USE_FUNCTION", T_FUNCTION); ast_register_flag_constant("USE_CONST", T_CONST); ast_register_flag_constant("MAGIC_LINE", T_LINE); ast_register_flag_constant("MAGIC_FILE", T_FILE); ast_register_flag_constant("MAGIC_DIR", T_DIR); ast_register_flag_constant("MAGIC_NAMESPACE", T_NS_C); ast_register_flag_constant("MAGIC_FUNCTION", T_FUNC_C); ast_register_flag_constant("MAGIC_METHOD", T_METHOD_C); ast_register_flag_constant("MAGIC_CLASS", T_CLASS_C); ast_register_flag_constant("MAGIC_TRAIT", T_TRAIT_C); INIT_CLASS_ENTRY(tmp_ce, "ast\\Node", NULL); ast_node_ce = zend_register_internal_class(&tmp_ce); { zval zv; ZVAL_NULL(&zv); ast_declare_property(ast_node_ce, AST_STR(str_kind), &zv); ast_declare_property(ast_node_ce, AST_STR(str_flags), &zv); ast_declare_property(ast_node_ce, AST_STR(str_lineno), &zv); ast_declare_property(ast_node_ce, AST_STR(str_children), &zv); } INIT_CLASS_ENTRY(tmp_ce, "ast\\Node\\Decl", NULL); ast_decl_ce = zend_register_internal_class_ex(&tmp_ce, ast_node_ce); { zval zv; ZVAL_NULL(&zv); ast_declare_property(ast_decl_ce, AST_STR(str_endLineno), &zv); ast_declare_property(ast_decl_ce, AST_STR(str_name), &zv); ast_declare_property(ast_decl_ce, AST_STR(str_docComment), &zv); } return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(ast) { #define X(str) zend_string_release(AST_STR(str_ ## str)); AST_STR_DEFS #undef X return SUCCESS; } zend_module_entry ast_module_entry = { STANDARD_MODULE_HEADER, "ast", ast_functions, PHP_MINIT(ast), PHP_MSHUTDOWN(ast), PHP_RINIT(ast), NULL, PHP_MINFO(ast), PHP_AST_VERSION, PHP_MODULE_GLOBALS(ast), NULL, NULL, NULL, STANDARD_MODULE_PROPERTIES_EX }; #ifdef COMPILE_DL_AST ZEND_GET_MODULE(ast) #endif php-ast-0.1.1/ast_data.c000066400000000000000000000654371263036240200150260ustar00rootroot00000000000000#include "php_ast.h" const size_t ast_kinds_count = 98; const zend_ast_kind ast_kinds[] = { ZEND_AST_FUNC_DECL, ZEND_AST_CLOSURE, ZEND_AST_METHOD, ZEND_AST_CLASS, ZEND_AST_ARG_LIST, ZEND_AST_LIST, ZEND_AST_ARRAY, ZEND_AST_ENCAPS_LIST, ZEND_AST_EXPR_LIST, ZEND_AST_STMT_LIST, ZEND_AST_IF, ZEND_AST_SWITCH_LIST, ZEND_AST_CATCH_LIST, ZEND_AST_PARAM_LIST, ZEND_AST_CLOSURE_USES, ZEND_AST_PROP_DECL, ZEND_AST_CONST_DECL, ZEND_AST_CLASS_CONST_DECL, ZEND_AST_NAME_LIST, ZEND_AST_TRAIT_ADAPTATIONS, ZEND_AST_USE, ZEND_AST_MAGIC_CONST, ZEND_AST_TYPE, ZEND_AST_VAR, ZEND_AST_CONST, ZEND_AST_UNPACK, ZEND_AST_UNARY_PLUS, ZEND_AST_UNARY_MINUS, ZEND_AST_CAST, ZEND_AST_EMPTY, ZEND_AST_ISSET, ZEND_AST_SILENCE, ZEND_AST_SHELL_EXEC, ZEND_AST_CLONE, ZEND_AST_EXIT, ZEND_AST_PRINT, ZEND_AST_INCLUDE_OR_EVAL, ZEND_AST_UNARY_OP, ZEND_AST_PRE_INC, ZEND_AST_PRE_DEC, ZEND_AST_POST_INC, ZEND_AST_POST_DEC, ZEND_AST_YIELD_FROM, ZEND_AST_GLOBAL, ZEND_AST_UNSET, ZEND_AST_RETURN, ZEND_AST_LABEL, ZEND_AST_REF, ZEND_AST_HALT_COMPILER, ZEND_AST_ECHO, ZEND_AST_THROW, ZEND_AST_GOTO, ZEND_AST_BREAK, ZEND_AST_CONTINUE, ZEND_AST_DIM, ZEND_AST_PROP, ZEND_AST_STATIC_PROP, ZEND_AST_CALL, ZEND_AST_CLASS_CONST, ZEND_AST_ASSIGN, ZEND_AST_ASSIGN_REF, ZEND_AST_ASSIGN_OP, ZEND_AST_BINARY_OP, ZEND_AST_GREATER, ZEND_AST_GREATER_EQUAL, ZEND_AST_AND, ZEND_AST_OR, ZEND_AST_ARRAY_ELEM, ZEND_AST_NEW, ZEND_AST_INSTANCEOF, ZEND_AST_YIELD, ZEND_AST_COALESCE, ZEND_AST_STATIC, ZEND_AST_WHILE, ZEND_AST_DO_WHILE, ZEND_AST_IF_ELEM, ZEND_AST_SWITCH, ZEND_AST_SWITCH_CASE, ZEND_AST_DECLARE, ZEND_AST_CONST_ELEM, ZEND_AST_USE_TRAIT, ZEND_AST_TRAIT_PRECEDENCE, ZEND_AST_METHOD_REFERENCE, ZEND_AST_NAMESPACE, ZEND_AST_USE_ELEM, ZEND_AST_TRAIT_ALIAS, ZEND_AST_GROUP_USE, ZEND_AST_METHOD_CALL, ZEND_AST_STATIC_CALL, ZEND_AST_CONDITIONAL, ZEND_AST_TRY, ZEND_AST_CATCH, ZEND_AST_PARAM, ZEND_AST_PROP_ELEM, ZEND_AST_FOR, ZEND_AST_FOREACH, AST_NAME, AST_CLOSURE_VAR, }; const char *ast_kind_to_name(zend_ast_kind kind) { switch (kind) { case ZEND_AST_FUNC_DECL: return "AST_FUNC_DECL"; case ZEND_AST_CLOSURE: return "AST_CLOSURE"; case ZEND_AST_METHOD: return "AST_METHOD"; case ZEND_AST_CLASS: return "AST_CLASS"; case ZEND_AST_ARG_LIST: return "AST_ARG_LIST"; case ZEND_AST_LIST: return "AST_LIST"; case ZEND_AST_ARRAY: return "AST_ARRAY"; case ZEND_AST_ENCAPS_LIST: return "AST_ENCAPS_LIST"; case ZEND_AST_EXPR_LIST: return "AST_EXPR_LIST"; case ZEND_AST_STMT_LIST: return "AST_STMT_LIST"; case ZEND_AST_IF: return "AST_IF"; case ZEND_AST_SWITCH_LIST: return "AST_SWITCH_LIST"; case ZEND_AST_CATCH_LIST: return "AST_CATCH_LIST"; case ZEND_AST_PARAM_LIST: return "AST_PARAM_LIST"; case ZEND_AST_CLOSURE_USES: return "AST_CLOSURE_USES"; case ZEND_AST_PROP_DECL: return "AST_PROP_DECL"; case ZEND_AST_CONST_DECL: return "AST_CONST_DECL"; case ZEND_AST_CLASS_CONST_DECL: return "AST_CLASS_CONST_DECL"; case ZEND_AST_NAME_LIST: return "AST_NAME_LIST"; case ZEND_AST_TRAIT_ADAPTATIONS: return "AST_TRAIT_ADAPTATIONS"; case ZEND_AST_USE: return "AST_USE"; case ZEND_AST_MAGIC_CONST: return "AST_MAGIC_CONST"; case ZEND_AST_TYPE: return "AST_TYPE"; case ZEND_AST_VAR: return "AST_VAR"; case ZEND_AST_CONST: return "AST_CONST"; case ZEND_AST_UNPACK: return "AST_UNPACK"; case ZEND_AST_UNARY_PLUS: return "AST_UNARY_PLUS"; case ZEND_AST_UNARY_MINUS: return "AST_UNARY_MINUS"; case ZEND_AST_CAST: return "AST_CAST"; case ZEND_AST_EMPTY: return "AST_EMPTY"; case ZEND_AST_ISSET: return "AST_ISSET"; case ZEND_AST_SILENCE: return "AST_SILENCE"; case ZEND_AST_SHELL_EXEC: return "AST_SHELL_EXEC"; case ZEND_AST_CLONE: return "AST_CLONE"; case ZEND_AST_EXIT: return "AST_EXIT"; case ZEND_AST_PRINT: return "AST_PRINT"; case ZEND_AST_INCLUDE_OR_EVAL: return "AST_INCLUDE_OR_EVAL"; case ZEND_AST_UNARY_OP: return "AST_UNARY_OP"; case ZEND_AST_PRE_INC: return "AST_PRE_INC"; case ZEND_AST_PRE_DEC: return "AST_PRE_DEC"; case ZEND_AST_POST_INC: return "AST_POST_INC"; case ZEND_AST_POST_DEC: return "AST_POST_DEC"; case ZEND_AST_YIELD_FROM: return "AST_YIELD_FROM"; case ZEND_AST_GLOBAL: return "AST_GLOBAL"; case ZEND_AST_UNSET: return "AST_UNSET"; case ZEND_AST_RETURN: return "AST_RETURN"; case ZEND_AST_LABEL: return "AST_LABEL"; case ZEND_AST_REF: return "AST_REF"; case ZEND_AST_HALT_COMPILER: return "AST_HALT_COMPILER"; case ZEND_AST_ECHO: return "AST_ECHO"; case ZEND_AST_THROW: return "AST_THROW"; case ZEND_AST_GOTO: return "AST_GOTO"; case ZEND_AST_BREAK: return "AST_BREAK"; case ZEND_AST_CONTINUE: return "AST_CONTINUE"; case ZEND_AST_DIM: return "AST_DIM"; case ZEND_AST_PROP: return "AST_PROP"; case ZEND_AST_STATIC_PROP: return "AST_STATIC_PROP"; case ZEND_AST_CALL: return "AST_CALL"; case ZEND_AST_CLASS_CONST: return "AST_CLASS_CONST"; case ZEND_AST_ASSIGN: return "AST_ASSIGN"; case ZEND_AST_ASSIGN_REF: return "AST_ASSIGN_REF"; case ZEND_AST_ASSIGN_OP: return "AST_ASSIGN_OP"; case ZEND_AST_BINARY_OP: return "AST_BINARY_OP"; case ZEND_AST_GREATER: return "AST_GREATER"; case ZEND_AST_GREATER_EQUAL: return "AST_GREATER_EQUAL"; case ZEND_AST_AND: return "AST_AND"; case ZEND_AST_OR: return "AST_OR"; case ZEND_AST_ARRAY_ELEM: return "AST_ARRAY_ELEM"; case ZEND_AST_NEW: return "AST_NEW"; case ZEND_AST_INSTANCEOF: return "AST_INSTANCEOF"; case ZEND_AST_YIELD: return "AST_YIELD"; case ZEND_AST_COALESCE: return "AST_COALESCE"; case ZEND_AST_STATIC: return "AST_STATIC"; case ZEND_AST_WHILE: return "AST_WHILE"; case ZEND_AST_DO_WHILE: return "AST_DO_WHILE"; case ZEND_AST_IF_ELEM: return "AST_IF_ELEM"; case ZEND_AST_SWITCH: return "AST_SWITCH"; case ZEND_AST_SWITCH_CASE: return "AST_SWITCH_CASE"; case ZEND_AST_DECLARE: return "AST_DECLARE"; case ZEND_AST_CONST_ELEM: return "AST_CONST_ELEM"; case ZEND_AST_USE_TRAIT: return "AST_USE_TRAIT"; case ZEND_AST_TRAIT_PRECEDENCE: return "AST_TRAIT_PRECEDENCE"; case ZEND_AST_METHOD_REFERENCE: return "AST_METHOD_REFERENCE"; case ZEND_AST_NAMESPACE: return "AST_NAMESPACE"; case ZEND_AST_USE_ELEM: return "AST_USE_ELEM"; case ZEND_AST_TRAIT_ALIAS: return "AST_TRAIT_ALIAS"; case ZEND_AST_GROUP_USE: return "AST_GROUP_USE"; case ZEND_AST_METHOD_CALL: return "AST_METHOD_CALL"; case ZEND_AST_STATIC_CALL: return "AST_STATIC_CALL"; case ZEND_AST_CONDITIONAL: return "AST_CONDITIONAL"; case ZEND_AST_TRY: return "AST_TRY"; case ZEND_AST_CATCH: return "AST_CATCH"; case ZEND_AST_PARAM: return "AST_PARAM"; case ZEND_AST_PROP_ELEM: return "AST_PROP_ELEM"; case ZEND_AST_FOR: return "AST_FOR"; case ZEND_AST_FOREACH: return "AST_FOREACH"; case AST_NAME: return "AST_NAME"; case AST_CLOSURE_VAR: return "AST_CLOSURE_VAR"; } return NULL; } zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) { switch (kind) { case AST_NAME: switch (child) { case 0: return AST_STR(str_name); } return NULL; case AST_CLOSURE_VAR: switch (child) { case 0: return AST_STR(str_name); } return NULL; case ZEND_AST_FUNC_DECL: switch (child) { case 0: return AST_STR(str_params); case 1: return AST_STR(str_uses); case 2: return AST_STR(str_stmts); case 3: return AST_STR(str_returnType); } return NULL; case ZEND_AST_CLOSURE: switch (child) { case 0: return AST_STR(str_params); case 1: return AST_STR(str_uses); case 2: return AST_STR(str_stmts); case 3: return AST_STR(str_returnType); } return NULL; case ZEND_AST_METHOD: switch (child) { case 0: return AST_STR(str_params); case 1: return AST_STR(str_uses); case 2: return AST_STR(str_stmts); case 3: return AST_STR(str_returnType); } return NULL; case ZEND_AST_CLASS: switch (child) { case 0: return AST_STR(str_extends); case 1: return AST_STR(str_implements); case 2: return AST_STR(str_stmts); } return NULL; case ZEND_AST_MAGIC_CONST: return NULL; case ZEND_AST_TYPE: return NULL; case ZEND_AST_VAR: switch (child) { case 0: return AST_STR(str_name); } return NULL; case ZEND_AST_CONST: switch (child) { case 0: return AST_STR(str_name); } return NULL; case ZEND_AST_UNPACK: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_UNARY_PLUS: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_UNARY_MINUS: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_CAST: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_EMPTY: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_ISSET: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_SILENCE: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_SHELL_EXEC: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_CLONE: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_EXIT: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_PRINT: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_INCLUDE_OR_EVAL: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_UNARY_OP: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_PRE_INC: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_PRE_DEC: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_POST_INC: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_POST_DEC: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_YIELD_FROM: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_GLOBAL: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_UNSET: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_RETURN: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_LABEL: switch (child) { case 0: return AST_STR(str_name); } return NULL; case ZEND_AST_REF: switch (child) { case 0: return AST_STR(str_var); } return NULL; case ZEND_AST_HALT_COMPILER: switch (child) { case 0: return AST_STR(str_offset); } return NULL; case ZEND_AST_ECHO: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_THROW: switch (child) { case 0: return AST_STR(str_expr); } return NULL; case ZEND_AST_GOTO: switch (child) { case 0: return AST_STR(str_label); } return NULL; case ZEND_AST_BREAK: switch (child) { case 0: return AST_STR(str_depth); } return NULL; case ZEND_AST_CONTINUE: switch (child) { case 0: return AST_STR(str_depth); } return NULL; case ZEND_AST_DIM: switch (child) { case 0: return AST_STR(str_expr); case 1: return AST_STR(str_dim); } return NULL; case ZEND_AST_PROP: switch (child) { case 0: return AST_STR(str_expr); case 1: return AST_STR(str_prop); } return NULL; case ZEND_AST_STATIC_PROP: switch (child) { case 0: return AST_STR(str_class); case 1: return AST_STR(str_prop); } return NULL; case ZEND_AST_CALL: switch (child) { case 0: return AST_STR(str_expr); case 1: return AST_STR(str_args); } return NULL; case ZEND_AST_CLASS_CONST: switch (child) { case 0: return AST_STR(str_class); case 1: return AST_STR(str_const); } return NULL; case ZEND_AST_ASSIGN: switch (child) { case 0: return AST_STR(str_var); case 1: return AST_STR(str_expr); } return NULL; case ZEND_AST_ASSIGN_REF: switch (child) { case 0: return AST_STR(str_var); case 1: return AST_STR(str_expr); } return NULL; case ZEND_AST_ASSIGN_OP: switch (child) { case 0: return AST_STR(str_var); case 1: return AST_STR(str_expr); } return NULL; case ZEND_AST_BINARY_OP: switch (child) { case 0: return AST_STR(str_left); case 1: return AST_STR(str_right); } return NULL; case ZEND_AST_GREATER: switch (child) { case 0: return AST_STR(str_left); case 1: return AST_STR(str_right); } return NULL; case ZEND_AST_GREATER_EQUAL: switch (child) { case 0: return AST_STR(str_left); case 1: return AST_STR(str_right); } return NULL; case ZEND_AST_AND: switch (child) { case 0: return AST_STR(str_left); case 1: return AST_STR(str_right); } return NULL; case ZEND_AST_OR: switch (child) { case 0: return AST_STR(str_left); case 1: return AST_STR(str_right); } return NULL; case ZEND_AST_ARRAY_ELEM: switch (child) { case 0: return AST_STR(str_value); case 1: return AST_STR(str_key); } return NULL; case ZEND_AST_NEW: switch (child) { case 0: return AST_STR(str_class); case 1: return AST_STR(str_args); } return NULL; case ZEND_AST_INSTANCEOF: switch (child) { case 0: return AST_STR(str_expr); case 1: return AST_STR(str_class); } return NULL; case ZEND_AST_YIELD: switch (child) { case 0: return AST_STR(str_value); case 1: return AST_STR(str_key); } return NULL; case ZEND_AST_COALESCE: switch (child) { case 0: return AST_STR(str_left); case 1: return AST_STR(str_right); } return NULL; case ZEND_AST_STATIC: switch (child) { case 0: return AST_STR(str_var); case 1: return AST_STR(str_default); } return NULL; case ZEND_AST_WHILE: switch (child) { case 0: return AST_STR(str_cond); case 1: return AST_STR(str_stmts); } return NULL; case ZEND_AST_DO_WHILE: switch (child) { case 0: return AST_STR(str_stmts); case 1: return AST_STR(str_cond); } return NULL; case ZEND_AST_IF_ELEM: switch (child) { case 0: return AST_STR(str_cond); case 1: return AST_STR(str_stmts); } return NULL; case ZEND_AST_SWITCH: switch (child) { case 0: return AST_STR(str_cond); case 1: return AST_STR(str_stmts); } return NULL; case ZEND_AST_SWITCH_CASE: switch (child) { case 0: return AST_STR(str_cond); case 1: return AST_STR(str_stmts); } return NULL; case ZEND_AST_DECLARE: switch (child) { case 0: return AST_STR(str_declares); case 1: return AST_STR(str_stmts); } return NULL; case ZEND_AST_PROP_ELEM: switch (child) { case 0: return AST_STR(str_name); case 1: return AST_STR(str_default); } return NULL; case ZEND_AST_CONST_ELEM: switch (child) { case 0: return AST_STR(str_name); case 1: return AST_STR(str_value); } return NULL; case ZEND_AST_USE_TRAIT: switch (child) { case 0: return AST_STR(str_traits); case 1: return AST_STR(str_adaptations); } return NULL; case ZEND_AST_TRAIT_PRECEDENCE: switch (child) { case 0: return AST_STR(str_method); case 1: return AST_STR(str_insteadof); } return NULL; case ZEND_AST_METHOD_REFERENCE: switch (child) { case 0: return AST_STR(str_class); case 1: return AST_STR(str_method); } return NULL; case ZEND_AST_NAMESPACE: switch (child) { case 0: return AST_STR(str_name); case 1: return AST_STR(str_stmts); } return NULL; case ZEND_AST_USE_ELEM: switch (child) { case 0: return AST_STR(str_name); case 1: return AST_STR(str_alias); } return NULL; case ZEND_AST_TRAIT_ALIAS: switch (child) { case 0: return AST_STR(str_method); case 1: return AST_STR(str_alias); } return NULL; case ZEND_AST_GROUP_USE: switch (child) { case 0: return AST_STR(str_prefix); case 1: return AST_STR(str_uses); } return NULL; case ZEND_AST_METHOD_CALL: switch (child) { case 0: return AST_STR(str_expr); case 1: return AST_STR(str_method); case 2: return AST_STR(str_args); } return NULL; case ZEND_AST_STATIC_CALL: switch (child) { case 0: return AST_STR(str_class); case 1: return AST_STR(str_method); case 2: return AST_STR(str_args); } return NULL; case ZEND_AST_CONDITIONAL: switch (child) { case 0: return AST_STR(str_cond); case 1: return AST_STR(str_true); case 2: return AST_STR(str_false); } return NULL; case ZEND_AST_TRY: switch (child) { case 0: return AST_STR(str_try); case 1: return AST_STR(str_catches); case 2: return AST_STR(str_finally); } return NULL; case ZEND_AST_CATCH: switch (child) { case 0: return AST_STR(str_class); case 1: return AST_STR(str_var); case 2: return AST_STR(str_stmts); } return NULL; case ZEND_AST_PARAM: switch (child) { case 0: return AST_STR(str_type); case 1: return AST_STR(str_name); case 2: return AST_STR(str_default); } return NULL; case ZEND_AST_FOR: switch (child) { case 0: return AST_STR(str_init); case 1: return AST_STR(str_cond); case 2: return AST_STR(str_loop); case 3: return AST_STR(str_stmts); } return NULL; case ZEND_AST_FOREACH: switch (child) { case 0: return AST_STR(str_expr); case 1: return AST_STR(str_value); case 2: return AST_STR(str_key); case 3: return AST_STR(str_stmts); } return NULL; } return NULL; } void ast_register_kind_constants(INIT_FUNC_ARGS) { REGISTER_NS_LONG_CONSTANT("ast", "AST_FUNC_DECL", ZEND_AST_FUNC_DECL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLOSURE", ZEND_AST_CLOSURE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_METHOD", ZEND_AST_METHOD, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS", ZEND_AST_CLASS, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ARG_LIST", ZEND_AST_ARG_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_LIST", ZEND_AST_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ARRAY", ZEND_AST_ARRAY, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ENCAPS_LIST", ZEND_AST_ENCAPS_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_EXPR_LIST", ZEND_AST_EXPR_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_STMT_LIST", ZEND_AST_STMT_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_IF", ZEND_AST_IF, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_SWITCH_LIST", ZEND_AST_SWITCH_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CATCH_LIST", ZEND_AST_CATCH_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PARAM_LIST", ZEND_AST_PARAM_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLOSURE_USES", ZEND_AST_CLOSURE_USES, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PROP_DECL", ZEND_AST_PROP_DECL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CONST_DECL", ZEND_AST_CONST_DECL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS_CONST_DECL", ZEND_AST_CLASS_CONST_DECL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_NAME_LIST", ZEND_AST_NAME_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_TRAIT_ADAPTATIONS", ZEND_AST_TRAIT_ADAPTATIONS, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_USE", ZEND_AST_USE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_MAGIC_CONST", ZEND_AST_MAGIC_CONST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_TYPE", ZEND_AST_TYPE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_VAR", ZEND_AST_VAR, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CONST", ZEND_AST_CONST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_UNPACK", ZEND_AST_UNPACK, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_UNARY_PLUS", ZEND_AST_UNARY_PLUS, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_UNARY_MINUS", ZEND_AST_UNARY_MINUS, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CAST", ZEND_AST_CAST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_EMPTY", ZEND_AST_EMPTY, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ISSET", ZEND_AST_ISSET, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_SILENCE", ZEND_AST_SILENCE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_SHELL_EXEC", ZEND_AST_SHELL_EXEC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLONE", ZEND_AST_CLONE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_EXIT", ZEND_AST_EXIT, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PRINT", ZEND_AST_PRINT, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_INCLUDE_OR_EVAL", ZEND_AST_INCLUDE_OR_EVAL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_UNARY_OP", ZEND_AST_UNARY_OP, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PRE_INC", ZEND_AST_PRE_INC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PRE_DEC", ZEND_AST_PRE_DEC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_POST_INC", ZEND_AST_POST_INC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_POST_DEC", ZEND_AST_POST_DEC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_YIELD_FROM", ZEND_AST_YIELD_FROM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_GLOBAL", ZEND_AST_GLOBAL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_UNSET", ZEND_AST_UNSET, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_RETURN", ZEND_AST_RETURN, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_LABEL", ZEND_AST_LABEL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_REF", ZEND_AST_REF, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_HALT_COMPILER", ZEND_AST_HALT_COMPILER, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ECHO", ZEND_AST_ECHO, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_THROW", ZEND_AST_THROW, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_GOTO", ZEND_AST_GOTO, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_BREAK", ZEND_AST_BREAK, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CONTINUE", ZEND_AST_CONTINUE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_DIM", ZEND_AST_DIM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PROP", ZEND_AST_PROP, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_STATIC_PROP", ZEND_AST_STATIC_PROP, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CALL", ZEND_AST_CALL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS_CONST", ZEND_AST_CLASS_CONST, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ASSIGN", ZEND_AST_ASSIGN, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ASSIGN_REF", ZEND_AST_ASSIGN_REF, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ASSIGN_OP", ZEND_AST_ASSIGN_OP, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_BINARY_OP", ZEND_AST_BINARY_OP, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_GREATER", ZEND_AST_GREATER, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_GREATER_EQUAL", ZEND_AST_GREATER_EQUAL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_AND", ZEND_AST_AND, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_OR", ZEND_AST_OR, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_ARRAY_ELEM", ZEND_AST_ARRAY_ELEM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_NEW", ZEND_AST_NEW, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_INSTANCEOF", ZEND_AST_INSTANCEOF, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_YIELD", ZEND_AST_YIELD, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_COALESCE", ZEND_AST_COALESCE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_STATIC", ZEND_AST_STATIC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_WHILE", ZEND_AST_WHILE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_DO_WHILE", ZEND_AST_DO_WHILE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_IF_ELEM", ZEND_AST_IF_ELEM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_SWITCH", ZEND_AST_SWITCH, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_SWITCH_CASE", ZEND_AST_SWITCH_CASE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_DECLARE", ZEND_AST_DECLARE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CONST_ELEM", ZEND_AST_CONST_ELEM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_USE_TRAIT", ZEND_AST_USE_TRAIT, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_TRAIT_PRECEDENCE", ZEND_AST_TRAIT_PRECEDENCE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_METHOD_REFERENCE", ZEND_AST_METHOD_REFERENCE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_NAMESPACE", ZEND_AST_NAMESPACE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_USE_ELEM", ZEND_AST_USE_ELEM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_TRAIT_ALIAS", ZEND_AST_TRAIT_ALIAS, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_GROUP_USE", ZEND_AST_GROUP_USE, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_METHOD_CALL", ZEND_AST_METHOD_CALL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_STATIC_CALL", ZEND_AST_STATIC_CALL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CONDITIONAL", ZEND_AST_CONDITIONAL, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_TRY", ZEND_AST_TRY, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CATCH", ZEND_AST_CATCH, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PARAM", ZEND_AST_PARAM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PROP_ELEM", ZEND_AST_PROP_ELEM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_FOR", ZEND_AST_FOR, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_FOREACH", ZEND_AST_FOREACH, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_NAME", AST_NAME, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLOSURE_VAR", AST_CLOSURE_VAR, CONST_CS | CONST_PERSISTENT); } php-ast-0.1.1/ast_str_defs.h000066400000000000000000000011731263036240200157160ustar00rootroot00000000000000#ifndef AST_STR_DEFS_H #define AST_STR_DEFS_H #define AST_STR_DEFS \ X(kind) \ X(flags) \ X(lineno) \ X(children) \ X(name) \ X(docComment) \ X(endLineno) \ X(params) \ X(uses) \ X(stmts) \ X(returnType) \ X(extends) \ X(implements) \ X(expr) \ X(var) \ X(offset) \ X(label) \ X(depth) \ X(dim) \ X(prop) \ X(class) \ X(args) \ X(const) \ X(left) \ X(right) \ X(value) \ X(key) \ X(default) \ X(cond) \ X(declares) \ X(traits) \ X(adaptations) \ X(method) \ X(insteadof) \ X(alias) \ X(prefix) \ X(true) \ X(false) \ X(try) \ X(catches) \ X(finally) \ X(type) \ X(init) \ X(loop) \ #endif php-ast-0.1.1/config.m4000066400000000000000000000003521263036240200145720ustar00rootroot00000000000000dnl $Id$ dnl config.m4 for extension ast PHP_ARG_ENABLE(ast, whether to enable ast support, [ --enable-ast Enable ast support]) if test "$PHP_AST" != "no"; then PHP_NEW_EXTENSION(ast, ast.c ast_data.c, $ext_shared) fi php-ast-0.1.1/config.w32000066400000000000000000000002171263036240200146650ustar00rootroot00000000000000// $Id$ // vim:ft=javascript ARG_ENABLE("ast", "enable ast support", "no"); if (PHP_AST != "no") { EXTENSION("ast", "ast.c ast_data.c"); } php-ast-0.1.1/generate_ast_data.php000066400000000000000000000154101263036240200172270ustar00rootroot00000000000000 ['name'], 'AST_CLOSURE_VAR' => ['name'], /* declaration nodes */ 'ZEND_AST_FUNC_DECL' => $funcNames, 'ZEND_AST_CLOSURE' => $funcNames, 'ZEND_AST_METHOD' => $funcNames, 'ZEND_AST_CLASS' => ['extends', 'implements', 'stmts'], /* 0 child nodes */ 'ZEND_AST_MAGIC_CONST' => [], 'ZEND_AST_TYPE' => [], /* 1 child node */ 'ZEND_AST_VAR' => ['name'], 'ZEND_AST_CONST' => ['name'], 'ZEND_AST_UNPACK' => ['expr'], 'ZEND_AST_UNARY_PLUS' => ['expr'], // version < 20 'ZEND_AST_UNARY_MINUS' => ['expr'], // version < 20 'ZEND_AST_CAST' => ['expr'], 'ZEND_AST_EMPTY' => ['expr'], 'ZEND_AST_ISSET' => ['var'], 'ZEND_AST_SILENCE' => ['expr'], 'ZEND_AST_SHELL_EXEC' => ['expr'], 'ZEND_AST_CLONE' => ['expr'], 'ZEND_AST_EXIT' => ['expr'], 'ZEND_AST_PRINT' => ['expr'], 'ZEND_AST_INCLUDE_OR_EVAL' => ['expr'], 'ZEND_AST_UNARY_OP' => ['expr'], 'ZEND_AST_PRE_INC' => ['var'], 'ZEND_AST_PRE_DEC' => ['var'], 'ZEND_AST_POST_INC' => ['var'], 'ZEND_AST_POST_DEC' => ['var'], 'ZEND_AST_YIELD_FROM' => ['expr'], 'ZEND_AST_GLOBAL' => ['var'], 'ZEND_AST_UNSET' => ['var'], 'ZEND_AST_RETURN' => ['expr'], 'ZEND_AST_LABEL' => ['name'], 'ZEND_AST_REF' => ['var'], 'ZEND_AST_HALT_COMPILER' => ['offset'], 'ZEND_AST_ECHO' => ['expr'], 'ZEND_AST_THROW' => ['expr'], 'ZEND_AST_GOTO' => ['label'], 'ZEND_AST_BREAK' => ['depth'], 'ZEND_AST_CONTINUE' => ['depth'], /* 2 child nodes */ 'ZEND_AST_DIM' => ['expr', 'dim'], 'ZEND_AST_PROP' => ['expr', 'prop'], 'ZEND_AST_STATIC_PROP' => ['class', 'prop'], 'ZEND_AST_CALL' => ['expr', 'args'], 'ZEND_AST_CLASS_CONST' => ['class', 'const'], 'ZEND_AST_ASSIGN' => ['var', 'expr'], 'ZEND_AST_ASSIGN_REF' => ['var', 'expr'], 'ZEND_AST_ASSIGN_OP' => ['var', 'expr'], 'ZEND_AST_BINARY_OP' => ['left', 'right'], 'ZEND_AST_GREATER' => ['left', 'right'], // version < 20 'ZEND_AST_GREATER_EQUAL' => ['left', 'right'], // version < 20 'ZEND_AST_AND' => ['left', 'right'], // version < 20 'ZEND_AST_OR' => ['left', 'right'], // version < 20 'ZEND_AST_ARRAY_ELEM' => ['value', 'key'], 'ZEND_AST_NEW' => ['class', 'args'], 'ZEND_AST_INSTANCEOF' => ['expr', 'class'], 'ZEND_AST_YIELD' => ['value', 'key'], 'ZEND_AST_COALESCE' => ['left', 'right'], 'ZEND_AST_STATIC' => ['var', 'default'], 'ZEND_AST_WHILE' => ['cond', 'stmts'], 'ZEND_AST_DO_WHILE' => ['stmts', 'cond'], 'ZEND_AST_IF_ELEM' => ['cond', 'stmts'], 'ZEND_AST_SWITCH' => ['cond', 'stmts'], 'ZEND_AST_SWITCH_CASE' => ['cond', 'stmts'], 'ZEND_AST_DECLARE' => ['declares', 'stmts'], 'ZEND_AST_PROP_ELEM' => ['name', 'default'], 'ZEND_AST_CONST_ELEM' => ['name', 'value'], 'ZEND_AST_USE_TRAIT' => ['traits', 'adaptations'], 'ZEND_AST_TRAIT_PRECEDENCE' => ['method', 'insteadof'], 'ZEND_AST_METHOD_REFERENCE' => ['class', 'method'], 'ZEND_AST_NAMESPACE' => ['name', 'stmts'], 'ZEND_AST_USE_ELEM' => ['name', 'alias'], 'ZEND_AST_TRAIT_ALIAS' => ['method', 'alias'], 'ZEND_AST_GROUP_USE' => ['prefix', 'uses'], /* 3 child nodes */ 'ZEND_AST_METHOD_CALL' => ['expr', 'method', 'args'], 'ZEND_AST_STATIC_CALL' => ['class', 'method', 'args'], 'ZEND_AST_CONDITIONAL' => ['cond', 'true', 'false'], 'ZEND_AST_TRY' => ['try', 'catches', 'finally'], 'ZEND_AST_CATCH' => ['class', 'var', 'stmts'], 'ZEND_AST_PARAM' => ['type', 'name', 'default'], /* 4 child nodes */ 'ZEND_AST_FOR' => ['init', 'cond', 'loop', 'stmts'], 'ZEND_AST_FOREACH' => ['expr', 'value', 'key', 'stmts'], ]; if ($argc != 2) { die("Must provide input file\n"); } $inFile = $argv[1]; $outCodeFile = __DIR__ . '/ast_data.c'; $strDefsFile = __DIR__ . '/ast_str_defs.h'; if (!is_readable($inFile)) { die("Input file not readable\n"); } $inCode = file_get_contents($inFile); if (!preg_match('/enum _zend_ast_kind \{(.*?)\};/s', $inCode, $matches)) { die("Malformed input file\n"); } $data = []; $lines = explode("\n", $matches[1]); foreach ($lines as $line) { if (!preg_match('/\s*(ZEND_([A-Z_]+))/', $line, $matches)) { continue; } list(, $zend_name, $name) = $matches; if ($name == 'AST_ZNODE' || $name == 'AST_ZVAL') { continue; } $data[$zend_name] = $name; } $data['AST_NAME'] = 'AST_NAME'; $data['AST_CLOSURE_VAR'] = 'AST_CLOSURE_VAR'; $kinds = []; $strs = []; $consts = []; foreach ($data as $zend_name => $name) { $kinds[] = "\t$zend_name,"; $strs[] = "\t\tcase $zend_name: return \"$name\";"; $consts[] = "\tREGISTER_NS_LONG_CONSTANT(\"ast\", \"$name\", $zend_name," . " CONST_CS | CONST_PERSISTENT);"; } $code = str_replace('{COUNT}', count($data), $code); $code = str_replace('{KINDS}', implode("\n", $kinds), $code); $code = str_replace('{STRS}', implode("\n", $strs), $code); $code = str_replace('{CONSTS}', implode("\n", $consts), $code); $childNames = []; foreach ($names as $kind => $children) { if (empty($children)) { $childNames[] = "\t\tcase $kind:\n\t\t\treturn NULL;"; continue; } $kindChildNames = []; foreach ($children as $index => $name) { $kindChildNames[] = "\t\t\t\tcase $index: return AST_STR(str_$name);"; } $childNames[] = "\t\tcase $kind:\n\t\t\tswitch (child) {\n" . implode("\n", $kindChildNames) . "\n\t\t\t}\n\t\t\treturn NULL;"; } $code = str_replace('{CHILD_NAMES}', implode("\n", $childNames), $code); file_put_contents($outCodeFile, $code); $strings = get_possible_strings($names); $strDefs = []; foreach ($strings as $name) { $strDefs[] .= "\tX($name) \\"; } $strDefsHeader = str_replace('{STR_DEFS}', implode("\n", $strDefs), $strDefsHeader); file_put_contents($strDefsFile, $strDefsHeader); function get_possible_strings(array $spec) { $strings = array_fill_keys([ 'kind', 'flags', 'lineno', 'children', 'name', 'docComment', 'endLineno' ], true); foreach ($spec as $kind => $children) { foreach ($children as $childName) { $strings[$childName] = true; } } return array_keys($strings); } php-ast-0.1.1/php_ast.h000066400000000000000000000023431263036240200146740ustar00rootroot00000000000000#ifndef PHP_AST_H #define PHP_AST_H #include "php.h" #include "ast_str_defs.h" extern zend_module_entry ast_module_entry; #define phpext_ast_ptr &ast_module_entry #define PHP_AST_VERSION "0.1.1" #ifdef PHP_WIN32 # define PHP_AST_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_AST_API __attribute__ ((visibility("default"))) #else # define PHP_AST_API #endif #ifdef ZTS #include "TSRM.h" #endif #define AST_NUM_CACHE_SLOTS (2 * 4) ZEND_BEGIN_MODULE_GLOBALS(ast) #define X(str) zend_string *str_ ## str; AST_STR_DEFS #undef X void *cache_slots[AST_NUM_CACHE_SLOTS]; ZEND_END_MODULE_GLOBALS(ast) ZEND_EXTERN_MODULE_GLOBALS(ast) #define AST_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(ast, v) #define AST_STR(str) AST_G(str) /* Custom ast kind for names */ #define AST_NAME 2048 #define AST_CLOSURE_VAR 2049 extern const size_t ast_kinds_count; extern const zend_ast_kind ast_kinds[]; const char *ast_kind_to_name(zend_ast_kind kind); zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child); void ast_register_kind_constants(INIT_FUNC_ARGS); #endif /* PHP_AST_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ php-ast-0.1.1/tests/000077500000000000000000000000001263036240200142255ustar00rootroot00000000000000php-ast-0.1.1/tests/001.phpt000066400000000000000000000040461263036240200154260ustar00rootroot00000000000000--TEST-- ast_dump() test --SKIPIF-- --FILE-- foo); } else { return $arg->bar; } } PHP; echo ast_dump(ast\parse_code($code, $version=15)); --EXPECT-- AST_STMT_LIST 0: AST_FUNC_DECL flags: 0 name: test docComment: /** Test function */ 0: AST_PARAM_LIST 0: AST_PARAM flags: 0 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "Type" 1: "arg" 2: AST_CONST 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "XYZ" 1: null 2: AST_STMT_LIST 0: AST_IF 0: AST_IF_ELEM 0: AST_INSTANCEOF 0: AST_VAR 0: "arg" 1: AST_NAME flags: NAME_NOT_FQ (1) 0: "Foo\Bar" 1: AST_STMT_LIST 0: AST_RETURN 0: AST_CALL 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "test" 1: AST_ARG_LIST 0: AST_PROP 0: AST_VAR 0: "arg" 1: "foo" 1: AST_IF_ELEM 0: null 1: AST_STMT_LIST 0: AST_RETURN 0: AST_PROP 0: AST_VAR 0: "arg" 1: "bar" 3: AST_NAME flags: NAME_NOT_FQ (1) 0: "Ret" php-ast-0.1.1/tests/002.phpt000066400000000000000000000006261263036240200154270ustar00rootroot00000000000000--TEST-- Decl nodes use ast\Node\Decl --FILE-- kind == ast\AST_STMT_LIST); $fn = $ast->children[0]; assert($fn instanceof ast\Node); assert($fn instanceof ast\Node\Decl); assert($fn->kind == ast\AST_FUNC_DECL); ?> ===DONE=== --EXPECT-- ===DONE=== php-ast-0.1.1/tests/assign_ops.phpt000066400000000000000000000067201263036240200172740ustar00rootroot00000000000000--TEST-- Assign op flags --FILE-- >= $b; PHP; echo ast_dump(ast\parse_code($code, $version=10)), "\n"; echo ast_dump(ast\parse_code($code, $version=20)), "\n"; ?> --EXPECT-- AST_STMT_LIST 0: AST_ASSIGN_OP flags: ASSIGN_BITWISE_OR (31) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 1: AST_ASSIGN_OP flags: ASSIGN_BITWISE_AND (32) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 2: AST_ASSIGN_OP flags: ASSIGN_BITWISE_XOR (33) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 3: AST_ASSIGN_OP flags: ASSIGN_CONCAT (30) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 4: AST_ASSIGN_OP flags: ASSIGN_ADD (23) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 5: AST_ASSIGN_OP flags: ASSIGN_SUB (24) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 6: AST_ASSIGN_OP flags: ASSIGN_MUL (25) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 7: AST_ASSIGN_OP flags: ASSIGN_DIV (26) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 8: AST_ASSIGN_OP flags: ASSIGN_MOD (27) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 9: AST_ASSIGN_OP flags: ASSIGN_POW (167) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 10: AST_ASSIGN_OP flags: ASSIGN_SHIFT_LEFT (28) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 11: AST_ASSIGN_OP flags: ASSIGN_SHIFT_RIGHT (29) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" AST_STMT_LIST 0: AST_ASSIGN_OP flags: BINARY_BITWISE_OR (9) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 1: AST_ASSIGN_OP flags: BINARY_BITWISE_AND (10) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 2: AST_ASSIGN_OP flags: BINARY_BITWISE_XOR (11) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 3: AST_ASSIGN_OP flags: BINARY_CONCAT (8) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 4: AST_ASSIGN_OP flags: BINARY_ADD (1) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 5: AST_ASSIGN_OP flags: BINARY_SUB (2) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 6: AST_ASSIGN_OP flags: BINARY_MUL (3) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 7: AST_ASSIGN_OP flags: BINARY_DIV (4) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 8: AST_ASSIGN_OP flags: BINARY_MOD (5) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 9: AST_ASSIGN_OP flags: BINARY_POW (166) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 10: AST_ASSIGN_OP flags: BINARY_SHIFT_LEFT (6) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 11: AST_ASSIGN_OP flags: BINARY_SHIFT_RIGHT (7) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" php-ast-0.1.1/tests/ast_dump_with_linenos.phpt000066400000000000000000000014331263036240200215210ustar00rootroot00000000000000--TEST-- ast_dump() with AST_DUMP_LINENOS --SKIPIF-- --FILE-- --EXPECT-- AST_STMT_LIST @ 1 0: AST_FUNC_DECL @ 2-9 flags: 0 name: test 0: AST_PARAM_LIST @ 4 1: null 2: AST_STMT_LIST @ 5 0: AST_CALL @ 6 0: AST_NAME @ 6 flags: NAME_NOT_FQ (1) 0: "var_dump" 1: AST_ARG_LIST @ 8 0: AST_VAR @ 7 0: "foo" 3: null php-ast-0.1.1/tests/binary_ops.phpt000066400000000000000000000023521263036240200172710ustar00rootroot00000000000000--TEST-- AST_GREATER(_EQUAL) converted to AST_BINARY_OP --FILE-- $b; $a >= $b; $a and $b; $a or $b; PHP; echo ast_dump(ast\parse_code($code, $version=10)), "\n"; echo ast_dump(ast\parse_code($code, $version=20)), "\n"; ?> --EXPECT-- AST_STMT_LIST 0: AST_GREATER 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 1: AST_GREATER_EQUAL 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 2: AST_AND 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 3: AST_OR 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" AST_STMT_LIST 0: AST_BINARY_OP flags: BINARY_IS_GREATER (256) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 1: AST_BINARY_OP flags: BINARY_IS_GREATER_OR_EQUAL (257) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 2: AST_BINARY_OP flags: BINARY_BOOL_AND (259) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 3: AST_BINARY_OP flags: BINARY_BOOL_OR (258) 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" php-ast-0.1.1/tests/class.phpt000066400000000000000000000032111263036240200162240ustar00rootroot00000000000000--TEST-- Test parse and dump of class --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: A 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "B" 1: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "D" 1: AST_NAME flags: NAME_NOT_FQ (1) 0: "E" 2: AST_STMT_LIST 0: AST_USE_TRAIT 0: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "T" 1: AST_NAME flags: NAME_NOT_FQ (1) 0: "S" 1: null 1: AST_CLASS_CONST_DECL 0: AST_CONST_ELEM 0: "X" 1: "Y" 1: AST_CONST_ELEM 0: "Y" 1: "X" 2: AST_PROP_DECL flags: MODIFIER_PUBLIC (256) 0: AST_PROP_ELEM 0: "foo" 1: null 1: AST_PROP_ELEM 0: "bar" 1: null 3: AST_METHOD flags: MODIFIER_PUBLIC | MODIFIER_ABSTRACT (258) name: test 0: AST_PARAM_LIST 1: null 2: null 3: null php-ast-0.1.1/tests/class_types.phpt000066400000000000000000000020331263036240200174510ustar00rootroot00000000000000--TEST-- Different class types --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: A 0: null 1: null 2: AST_STMT_LIST 1: AST_CLASS flags: CLASS_ABSTRACT (32) name: B 0: null 1: null 2: AST_STMT_LIST 2: AST_CLASS flags: CLASS_FINAL (4) name: C 0: null 1: null 2: AST_STMT_LIST 3: AST_CLASS flags: CLASS_TRAIT (128) name: D 0: null 1: null 2: AST_STMT_LIST 4: AST_CLASS flags: CLASS_INTERFACE (64) name: E 0: null 1: null 2: AST_STMT_LIST 5: AST_NEW 0: AST_CLASS flags: CLASS_ANONYMOUS (256) 0: null 1: null 2: AST_STMT_LIST 1: AST_ARG_LIST php-ast-0.1.1/tests/closure_use_vars.phpt000066400000000000000000000020021263036240200204770ustar00rootroot00000000000000--TEST-- Closure uses should parse to CLOSURE_USE_VAR nodes --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_ASSIGN 0: AST_VAR 0: "fn" 1: AST_CLOSURE flags: MODIFIER_STATIC | RETURNS_REF (67108865) name: {closure} 0: AST_PARAM_LIST 0: AST_PARAM flags: 0 0: null 1: "a" 2: null 1: AST_PARAM flags: PARAM_REF (1) 0: null 1: "b" 2: null 1: AST_CLOSURE_USES 0: AST_CLOSURE_VAR flags: 0 0: "c" 1: AST_CLOSURE_VAR flags: 1 0: "d" 2: AST_STMT_LIST 3: null php-ast-0.1.1/tests/eval_include.phpt000066400000000000000000000013201263036240200175500ustar00rootroot00000000000000--TEST-- eval() and include parsing --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_INCLUDE_OR_EVAL flags: EXEC_EVAL (1) 0: "echo "hello";" 1: AST_INCLUDE_OR_EVAL flags: EXEC_INCLUDE (2) 0: "foo.php" 2: AST_INCLUDE_OR_EVAL flags: EXEC_INCLUDE_ONCE (4) 0: "foo.php" 3: AST_INCLUDE_OR_EVAL flags: EXEC_REQUIRE (8) 0: "foo.php" 4: AST_INCLUDE_OR_EVAL flags: EXEC_REQUIRE_ONCE (16) 0: "foo.php" php-ast-0.1.1/tests/get_kind_name.phpt000066400000000000000000000006211263036240200177050ustar00rootroot00000000000000--TEST-- Test ast\get_kind_name() --FILE-- getMessage(), "\n"; } ?> --EXPECT-- string(7) "AST_VAR" string(8) "AST_NAME" string(15) "AST_CLOSURE_VAR" Unknown kind 12345 php-ast-0.1.1/tests/invalid_file.php000066400000000000000000000000261263036240200173610ustar00rootroot00000000000000 --EXPECTF-- AST_STMT_LIST 0: AST_MAGIC_CONST flags: MAGIC_LINE (%d) 1: AST_MAGIC_CONST flags: MAGIC_FILE (%d) 2: AST_MAGIC_CONST flags: MAGIC_DIR (%d) 3: AST_MAGIC_CONST flags: MAGIC_NAMESPACE (%d) 4: AST_MAGIC_CONST flags: MAGIC_FUNCTION (%d) 5: AST_MAGIC_CONST flags: MAGIC_METHOD (%d) 6: AST_MAGIC_CONST flags: MAGIC_CLASS (%d) 7: AST_MAGIC_CONST flags: MAGIC_TRAIT (%d) php-ast-0.1.1/tests/named_children.phpt000066400000000000000000000016771263036240200200710ustar00rootroot00000000000000--TEST-- Named child nodes --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "fn" expr: AST_CLOSURE flags: 0 name: {closure} params: AST_PARAM_LIST uses: AST_CLOSURE_USES 0: AST_CLOSURE_VAR flags: 1 name: "var" stmts: AST_STMT_LIST 0: AST_ASSIGN_OP flags: BINARY_ADD (1) var: AST_VAR name: "var" expr: AST_CALL expr: AST_NAME flags: NAME_NOT_FQ (1) name: "func" args: AST_ARG_LIST returnType: null php-ast-0.1.1/tests/nested_stat_lists.phpt000066400000000000000000000016501263036240200206570ustar00rootroot00000000000000--TEST-- Nested statement lists --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_VAR 0: "a" 1: AST_STMT_LIST 0: AST_VAR 0: "b" 1: AST_STMT_LIST 0: AST_VAR 0: "c" 1: AST_STMT_LIST 0: AST_VAR 0: "d" 2: AST_VAR 0: "e" 2: AST_VAR 0: "f" 2: AST_VAR 0: "g" AST_STMT_LIST 0: AST_VAR 0: "a" 1: AST_VAR 0: "b" 2: AST_VAR 0: "c" 3: AST_VAR 0: "d" 4: AST_VAR 0: "e" 5: AST_VAR 0: "f" 6: AST_VAR 0: "g" php-ast-0.1.1/tests/parse_code_parse_error.phpt000066400000000000000000000011021263036240200216230ustar00rootroot00000000000000--TEST-- ast\parse_code() throwing a ParseError --FILE-- --EXPECTF-- ParseError: syntax error, unexpected '&', expecting end of file in string code:1 Stack trace: #0 %s(%d): ast\parse_code('%s', 15) #1 {main} ParseError: syntax error, unexpected '&', expecting end of file in file.php:1 Stack trace: #0 %s(%d): ast\parse_code('%s', 15, 'file.php') #1 {main} php-ast-0.1.1/tests/parse_file.phpt000066400000000000000000000005331263036240200172340ustar00rootroot00000000000000--TEST-- ast\parse_file() on valid file --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_RETURN 0: AST_ARRAY 0: AST_ARRAY_ELEM flags: 0 0: 123 1: null php-ast-0.1.1/tests/parse_file_not_existing.phpt000066400000000000000000000006141263036240200220260ustar00rootroot00000000000000--TEST-- ast\parse_file() on file that does not exist --FILE-- --EXPECTF-- RuntimeException: ast\parse_file(%stests/non_existing_file.php): failed to open stream: No such file or directory in %s:%d Stack trace: #0 %s(%d): ast\parse_file('%s', 15) #1 {main} php-ast-0.1.1/tests/parse_file_parse_error.phpt000066400000000000000000000005121263036240200216340ustar00rootroot00000000000000--TEST-- ast\parse_file() on file with parse error --FILE-- --EXPECTF-- ParseError: syntax error, unexpected ')' in %stests/invalid_file.php:3 Stack trace: #0 %s(%d): ast\parse_file('%s', 15) #1 {main} php-ast-0.1.1/tests/prop_doc_comments.phpt000066400000000000000000000032671263036240200206440ustar00rootroot00000000000000--TEST-- Doc comments on properties --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: A 0: null 1: null 2: AST_STMT_LIST 0: AST_PROP_DECL flags: MODIFIER_PUBLIC (256) docComment: /** docComment $a */ 0: AST_PROP_ELEM 0: "a" 1: null 1: AST_PROP_DECL flags: MODIFIER_PUBLIC (256) docComment: /** docComment $b */ 0: AST_PROP_ELEM 0: "b" 1: null 1: AST_PROP_ELEM 0: "c" 1: null AST_STMT_LIST 0: AST_CLASS flags: 0 name: A 0: null 1: null 2: AST_STMT_LIST 0: AST_PROP_DECL flags: MODIFIER_PUBLIC (256) 0: AST_PROP_ELEM docComment: /** docComment $a */ 0: "a" 1: null 1: AST_PROP_DECL flags: MODIFIER_PUBLIC (256) 0: AST_PROP_ELEM docComment: /** docComment $b */ 0: "b" 1: null 1: AST_PROP_ELEM docComment: /** docComment $c */ 0: "c" 1: null php-ast-0.1.1/tests/try_catch_finally.phpt000066400000000000000000000040321263036240200206170ustar00rootroot00000000000000--TEST-- try / catch / finally --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_TRY 0: AST_STMT_LIST 0: AST_STMT_LIST 0: AST_ECHO 0: "try" 1: AST_CATCH_LIST 0: AST_CATCH 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "Exception" 1: "e" 2: AST_STMT_LIST 0: AST_STMT_LIST 0: AST_ECHO 0: "catch 1" 1: AST_CATCH 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "bar\FooException" 1: "e2" 2: AST_STMT_LIST 0: AST_STMT_LIST 0: AST_ECHO 0: "catch 2" 2: AST_STMT_LIST 0: AST_STMT_LIST 0: AST_ECHO 0: "finally" AST_STMT_LIST 0: AST_TRY 0: AST_STMT_LIST 0: AST_ECHO 0: "try" 1: AST_CATCH_LIST 0: AST_CATCH 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "Exception" 1: AST_VAR 0: "e" 2: AST_STMT_LIST 0: AST_ECHO 0: "catch 1" 1: AST_CATCH 0: AST_NAME flags: NAME_NOT_FQ (1) 0: "bar\FooException" 1: AST_VAR 0: "e2" 2: AST_STMT_LIST 0: AST_ECHO 0: "catch 2" 2: AST_STMT_LIST 0: AST_ECHO 0: "finally" php-ast-0.1.1/tests/unary_ops.phpt000066400000000000000000000012641263036240200171440ustar00rootroot00000000000000--TEST-- Convert unary ops AST_(SILENCE|UNARY_(PLUS|MINUS)) to flags of ZEND_AST_UNARY_OP --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_SILENCE 0: AST_VAR 0: "a" 1: AST_UNARY_PLUS 0: 1 2: AST_UNARY_MINUS 0: 1 AST_STMT_LIST 0: AST_UNARY_OP flags: UNARY_SILENCE (260) 0: AST_VAR 0: "a" 1: AST_UNARY_OP flags: UNARY_PLUS (261) 0: 1 2: AST_UNARY_OP flags: UNARY_MINUS (262) 0: 1 php-ast-0.1.1/tests/use_declarations.phpt000066400000000000000000000023251263036240200204500ustar00rootroot00000000000000--TEST-- Test parse and dump of use declarations --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_USE flags: USE_NORMAL (%d) 0: AST_USE_ELEM flags: 0 0: "Foo\Bar" 1: "Baz" 1: AST_USE flags: USE_FUNCTION (%d) 0: AST_USE_ELEM flags: 0 0: "foo\bar" 1: "baz" 2: AST_GROUP_USE flags: 0 0: "Foo" 1: AST_USE flags: 0 0: AST_USE_ELEM flags: USE_NORMAL (%d) 0: "Bar" 1: null 1: AST_USE_ELEM flags: USE_FUNCTION (%d) 0: "bar" 1: null 3: AST_GROUP_USE flags: USE_FUNCTION (%d) 0: "foo" 1: AST_USE flags: 0 0: AST_USE_ELEM flags: 0 0: "bar" 1: null 1: AST_USE_ELEM flags: 0 0: "baz" 1: null php-ast-0.1.1/tests/valid_file.php000066400000000000000000000000251263036240200170310ustar00rootroot00000000000000getMessage(), "\n"; } try { ast\parse_code('getMessage(), "\n"; } ?> --EXPECTF-- No version specified. Current version is %d. All versions (including experimental): {10, 15, 20, %s} Unknown version 100. Current version is %d. All versions (including experimental): {10, 15, 20, %s} php-ast-0.1.1/tests/zpp_errors.phpt000066400000000000000000000011571263036240200173330ustar00rootroot00000000000000--TEST-- zpp failures throw TypeError --FILE-- getMessage(), "\n"; } try { ast\parse_file(); } catch (TypeError $e) { echo $e->getMessage(), "\n"; } try { ast\get_kind_name(); } catch (TypeError $e) { echo $e->getMessage(), "\n"; } try { ast\kind_uses_flags(); } catch (TypeError $e) { echo $e->getMessage(), "\n"; } ?> --EXPECT-- ast\parse_code() expects at least 1 parameter, 0 given ast\parse_file() expects at least 1 parameter, 0 given ast\get_kind_name() expects exactly 1 parameter, 0 given ast\kind_uses_flags() expects exactly 1 parameter, 0 given php-ast-0.1.1/util.php000066400000000000000000000157471263036240200145670ustar00rootroot00000000000000 'MODIFIER_PUBLIC', flags\MODIFIER_PROTECTED => 'MODIFIER_PROTECTED', flags\MODIFIER_PRIVATE => 'MODIFIER_PRIVATE', flags\MODIFIER_STATIC => 'MODIFIER_STATIC', flags\MODIFIER_ABSTRACT => 'MODIFIER_ABSTRACT', flags\MODIFIER_FINAL => 'MODIFIER_FINAL', flags\RETURNS_REF => 'RETURNS_REF', ]; $types = [ flags\TYPE_NULL => 'TYPE_NULL', flags\TYPE_BOOL => 'TYPE_BOOL', flags\TYPE_LONG => 'TYPE_LONG', flags\TYPE_DOUBLE => 'TYPE_DOUBLE', flags\TYPE_STRING => 'TYPE_STRING', flags\TYPE_ARRAY => 'TYPE_ARRAY', flags\TYPE_OBJECT => 'TYPE_OBJECT', flags\TYPE_CALLABLE => 'TYPE_CALLABLE', ]; $useTypes = [ flags\USE_NORMAL => 'USE_NORMAL', flags\USE_FUNCTION => 'USE_FUNCTION', flags\USE_CONST => 'USE_CONST', ]; $sharedBinaryOps = [ flags\BINARY_BITWISE_OR => 'BINARY_BITWISE_OR', flags\BINARY_BITWISE_AND => 'BINARY_BITWISE_AND', flags\BINARY_BITWISE_XOR => 'BINARY_BITWISE_XOR', flags\BINARY_CONCAT => 'BINARY_CONCAT', flags\BINARY_ADD => 'BINARY_ADD', flags\BINARY_SUB => 'BINARY_SUB', flags\BINARY_MUL => 'BINARY_MUL', flags\BINARY_DIV => 'BINARY_DIV', flags\BINARY_MOD => 'BINARY_MOD', flags\BINARY_POW => 'BINARY_POW', flags\BINARY_SHIFT_LEFT => 'BINARY_SHIFT_LEFT', flags\BINARY_SHIFT_RIGHT => 'BINARY_SHIFT_RIGHT', ]; $exclusive = [ ast\AST_NAME => [ flags\NAME_FQ => 'NAME_FQ', flags\NAME_NOT_FQ => 'NAME_NOT_FQ', flags\NAME_RELATIVE => 'NAME_RELATIVE', ], ast\AST_CLASS => [ flags\CLASS_ABSTRACT => 'CLASS_ABSTRACT', flags\CLASS_FINAL => 'CLASS_FINAL', flags\CLASS_TRAIT => 'CLASS_TRAIT', flags\CLASS_INTERFACE => 'CLASS_INTERFACE', flags\CLASS_ANONYMOUS => 'CLASS_ANONYMOUS', ], ast\AST_PARAM => [ flags\PARAM_REF => 'PARAM_REF', flags\PARAM_VARIADIC => 'PARAM_VARIADIC', ], ast\AST_TYPE => $types, ast\AST_CAST => $types, ast\AST_UNARY_OP => [ flags\UNARY_BOOL_NOT => 'UNARY_BOOL_NOT', flags\UNARY_BITWISE_NOT => 'UNARY_BITWISE_NOT', flags\UNARY_MINUS => 'UNARY_MINUS', flags\UNARY_PLUS => 'UNARY_PLUS', flags\UNARY_SILENCE => 'UNARY_SILENCE', ], ast\AST_BINARY_OP => $sharedBinaryOps + [ flags\BINARY_BOOL_AND => 'BINARY_BOOL_AND', flags\BINARY_BOOL_OR => 'BINARY_BOOL_OR', flags\BINARY_BOOL_XOR => 'BINARY_BOOL_XOR', flags\BINARY_IS_IDENTICAL => 'BINARY_IS_IDENTICAL', flags\BINARY_IS_NOT_IDENTICAL => 'BINARY_IS_NOT_IDENTICAL', flags\BINARY_IS_EQUAL => 'BINARY_IS_EQUAL', flags\BINARY_IS_NOT_EQUAL => 'BINARY_IS_NOT_EQUAL', flags\BINARY_IS_SMALLER => 'BINARY_IS_SMALLER', flags\BINARY_IS_SMALLER_OR_EQUAL => 'BINARY_IS_SMALLER_OR_EQUAL', flags\BINARY_IS_GREATER => 'BINARY_IS_GREATER', flags\BINARY_IS_GREATER_OR_EQUAL => 'BINARY_IS_GREATER_OR_EQUAL', flags\BINARY_SPACESHIP => 'BINARY_SPACESHIP', ], ast\AST_ASSIGN_OP => $sharedBinaryOps + [ // Old version 10 flags flags\ASSIGN_BITWISE_OR => 'ASSIGN_BITWISE_OR', flags\ASSIGN_BITWISE_AND => 'ASSIGN_BITWISE_AND', flags\ASSIGN_BITWISE_XOR => 'ASSIGN_BITWISE_XOR', flags\ASSIGN_CONCAT => 'ASSIGN_CONCAT', flags\ASSIGN_ADD => 'ASSIGN_ADD', flags\ASSIGN_SUB => 'ASSIGN_SUB', flags\ASSIGN_MUL => 'ASSIGN_MUL', flags\ASSIGN_DIV => 'ASSIGN_DIV', flags\ASSIGN_MOD => 'ASSIGN_MOD', flags\ASSIGN_POW => 'ASSIGN_POW', flags\ASSIGN_SHIFT_LEFT => 'ASSIGN_SHIFT_LEFT', flags\ASSIGN_SHIFT_RIGHT => 'ASSIGN_SHIFT_RIGHT', ], ast\AST_MAGIC_CONST => [ flags\MAGIC_LINE => 'MAGIC_LINE', flags\MAGIC_FILE => 'MAGIC_FILE', flags\MAGIC_DIR => 'MAGIC_DIR', flags\MAGIC_NAMESPACE => 'MAGIC_NAMESPACE', flags\MAGIC_FUNCTION => 'MAGIC_FUNCTION', flags\MAGIC_METHOD => 'MAGIC_METHOD', flags\MAGIC_CLASS => 'MAGIC_CLASS', flags\MAGIC_TRAIT => 'MAGIC_TRAIT', ], ast\AST_USE => $useTypes, ast\AST_GROUP_USE => $useTypes, ast\AST_USE_ELEM => $useTypes, ast\AST_INCLUDE_OR_EVAL => [ flags\EXEC_EVAL => 'EXEC_EVAL', flags\EXEC_INCLUDE => 'EXEC_INCLUDE', flags\EXEC_INCLUDE_ONCE => 'EXEC_INCLUDE_ONCE', flags\EXEC_REQUIRE => 'EXEC_REQUIRE', flags\EXEC_REQUIRE_ONCE => 'EXEC_REQUIRE_ONCE', ], ]; $combinable = []; $combinable[ast\AST_METHOD] = $combinable[ast\AST_FUNC_DECL] = $combinable[ast\AST_CLOSURE] = $combinable[ast\AST_PROP_DECL] = $combinable[ast\AST_TRAIT_ALIAS] = $modifiers; return [$exclusive, $combinable]; } function format_flags(int $kind, int $flags) : string { list($exclusive, $combinable) = get_flag_info(); if (isset($exclusive[$kind])) { $flagInfo = $exclusive[$kind]; if (isset($flagInfo[$flags])) { return "{$flagInfo[$flags]} ($flags)"; } } else if (isset($combinable[$kind])) { $flagInfo = $combinable[$kind]; $names = []; foreach ($flagInfo as $flag => $name) { if ($flags & $flag) { $names[] = $name; } } if (!empty($names)) { return implode(" | ", $names) . " ($flags)"; } } return (string) $flags; } /** Dumps abstract syntax tree */ function ast_dump($ast, int $options = 0) : string { if ($ast instanceof ast\Node) { $result = ast\get_kind_name($ast->kind); if ($options & AST_DUMP_LINENOS) { $result .= " @ $ast->lineno"; if (isset($ast->endLineno)) { $result .= "-$ast->endLineno"; } } if (ast\kind_uses_flags($ast->kind)) { $result .= "\n flags: " . format_flags($ast->kind, $ast->flags); } if (isset($ast->name)) { $result .= "\n name: $ast->name"; } if (isset($ast->docComment)) { $result .= "\n docComment: $ast->docComment"; } foreach ($ast->children as $i => $child) { $result .= "\n $i: " . str_replace("\n", "\n ", ast_dump($child, $options)); } return $result; } else if ($ast === null) { return 'null'; } else if (is_string($ast)) { return "\"$ast\""; } else { return (string) $ast; } }