package.xml0000664000175000017500000003773013567500533012330 0ustar tysontyson ast pecl.php.net Extension exposing PHP 7 abstract syntax tree php-ast exports the AST internally used by PHP 7. php-ast is significantly faster than PHP-Parser, because the AST construction is implemented in C. However, php-ast may only parse code that is syntactically valid on the version of PHP it runs on. Nikita Popov nikic nikic@php.net yes Tyson Andre tandre tandre@php.net yes 2019-11-27 1.0.5 1.0.5 stable stable BSD-3-Clause - Add ast\flags\TYPE_FALSE to support PHP 8.0 Union Types. 7.0.0 1.10.0 ast 2019-11-10 1.0.4 1.0.4 stable stable BSD-3-Clause - Add AST_TYPE_UNION to support PHP 8.0 Union Types. 2019-07-27 1.0.3 1.0.3 stable stable BSD-3-Clause - Fix build error in php 7.4.0alpha3. - Add `DIM_ALTERNATIVE_SYNTAX` as a flag of `AST_DIM` for `$x{'offset'}` (for php 7.4+) - Add `PARENTHESIZED_CONDITIONAL` as a flag of `AST_CONDITIONAL` for `($a ? $b : $c)` (for php 7.4+) - Bugfix: Make `ast\kind_uses_flags(ast\AST_ARROW_FUNC)` true in php 7.3 and lower. 2019-06-30 1.0.2 1.0.2 stable stable BSD-3-Clause - Fix compatibility with (currently) PHP 7.4 and PHP 8.0. - Support AST_ARROW_FUNC for PHP 7.4. - Make $version a required parameter for `ast\parse_*`. Previously, the absence would throw a LogicException. - Make AST version 70 the current version. 2019-02-11 1.0.1 1.0.1 stable stable BSD-3-Clause - Fix compatibility with (currently) PHP 7.4 and PHP 8.0. - Support BINARY_COALESCE as a flag of AST_ASSIGN_OP for the `??=` operator added in PHP 7.4. - Add AST version 70 (experimental): - Version 70 adds AST_PROP_GROUP with type information for property groups. - Version 70 adds AST_CLASS_NAME for `Foo::class`. Previously this used AST_CLASS_CONST 2018-10-21 1.0.0 1.0.0 stable stable BSD-3-Clause This release is the same as version 0.1.7 with obsolete and deprecated functionality removed. - Removed AST versions prior to version 50. - Removed ast\Node\Decl class, which is no longer used. - Removed AST kinds AST_AND, AST_COALESCE, AST_GREATER, AST_GREATER_EQUAL, AST_OR, AST_SILENCE, AST_UNARY_MINUS, and AST_UNARY_PLUS, which are no longer used. - Removed ASSIGN_* AST flags, which are no longer used. 2018-10-06 0.1.7 0.1.7 stable stable BSD-3-Clause - Added AST version 60 with the following changes: - `AST_FUNC_DECL` and `AST_METHOD` no longer generate a `uses` child. Previously this child was always `null`. - `AST_CONST_ELEM` now always has a `docComment` child. Previously it was absent on PHP 7.0. On PHP 7.0 the value is always `null`. - Added `ARRAY_ELEM_REF` flag, which is used by `AST_ARRAY_ELEM` for by-reference array elements and (since PHP 7.3) for by-reference destructuring. Previously this flag was represented simply by the value `1`. - Deprecated AST versions 40 and 45. - Fix build against PHP 7.4-dev. 2017-10-08 0.1.6 0.1.6 stable stable BSD-3-Clause - Added ast\get_metadata() function, which returns an array of ast\Metadata objects, one for each AST kind. The metadata contains information such as the supported flags for the kind. - Added ast\get_supported_versions() function, which provides an array of currently supported AST versions. 2017-07-19 0.1.5 0.1.5 stable stable BSD-3-Clause - Fix issue #51: Make nullable array/callable have a flag of 0 in inner element, in version 40. - Added a constructor for the ast\Node class. - Added ast\flags\FUNC_GENERATOR constant, which is used since PHP 7.1. - Added ast\flags\FUNC_RETURNS_REF constant, intended to supersede ast\flags\RETURNS_REF. - Added ast\flags\CLOSURE_USE_REF constant, used by AST_CLOSURE_VAR nodes. Previously "1" was used. - Added version 45 with the following changes (PHP 7.2 support): - An `object` type annotation now returns an `AST_TYPE` with `TYPE_OBJECT` flag, rather than treating `object` as a class name. - Added version 50 with the following changes: - `ast\Node\Decl` nodes are no longer generated. AST kinds `AST_FUNCTION`, `AST_METHOD`, `AST_CLOSURE` and `AST_CLASS` now also use the normal `ast\Node` class. The `name` and `docComment` properties are now represented as children. The `endLineno` is still represented as an (undeclared) property. - An integer `__declId` has been added to declaration nodes of kind `AST_FUNCTION`, `AST_METHOD`, `AST_CLOSURE` and `AST_CLASS`. The `__declId` uniquely identifies a declaration within the parsed code and will remain the same if the code is parsed again. This is useful to distinguish closures declared on the same line, or multiple conditional declarations using the same name. The ID is not unique across different codes/files. - `\ast\parse_file` will now consistently return an empty statement list (similar to `\ast\parse_code`) if it is was passed a zero-byte file. Previously, it would return `null`. 2017-01-25 0.1.4 0.1.4 BSD-3-Clause 0.1.4 release 2017-01-18 0.1.3 0.1.3 BSD-3-Clause 0.1.3 release 2017-08-04 0.1.2 0.1.2 BSD-3-Clause 0.1.2 release 2017-12-04 0.1.1 0.1.1 BSD-3-Clause 0.1.1 release 2017-12-04 0.1.0 0.1.0 BSD-3-Clause 0.1.0 release ast-1.0.5/tests/001.phpt0000664000175000017500000000424613567500533013774 0ustar tysontyson--TEST-- ast_dump() test --SKIPIF-- --FILE-- foo); } else { return $arg->bar; } } PHP; echo ast_dump(ast\parse_code($code, $version=50)); --EXPECT-- AST_STMT_LIST 0: AST_FUNC_DECL flags: 0 name: "test" docComment: "/** Test function */" params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NAME flags: NAME_NOT_FQ (1) name: "Type" name: "arg" default: AST_CONST name: AST_NAME flags: NAME_NOT_FQ (1) name: "XYZ" uses: null stmts: AST_STMT_LIST 0: AST_IF 0: AST_IF_ELEM cond: AST_INSTANCEOF expr: AST_VAR name: "arg" class: AST_NAME flags: NAME_NOT_FQ (1) name: "Foo\Bar" stmts: AST_STMT_LIST 0: AST_RETURN expr: AST_CALL expr: AST_NAME flags: NAME_NOT_FQ (1) name: "test" args: AST_ARG_LIST 0: AST_PROP expr: AST_VAR name: "arg" prop: "foo" 1: AST_IF_ELEM cond: null stmts: AST_STMT_LIST 0: AST_RETURN expr: AST_PROP expr: AST_VAR name: "arg" prop: "bar" returnType: AST_NAME flags: NAME_NOT_FQ (1) name: "Ret" __declId: 0 ast-1.0.5/tests/array_destructuring_old.phpt0000664000175000017500000000166313567500533020432 0ustar tysontyson--TEST-- Array destructuring (using unkeyed list()) --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_LIST (1) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: null 1: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "b" key: null expr: AST_VAR name: "x" 1: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_LIST (1) 0: null 1: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "b" key: null expr: AST_VAR name: "x" ast-1.0.5/tests/array_destructuring.phpt0000664000175000017500000000405713567500533017574 0ustar tysontyson--TEST-- Array destructuring --SKIPIF-- = 7.1 only'); ?> --FILE-- $a, 'bar' => $b) = $x; [$a, $b] = $x; ['foo' => $a, 'bar' => $b] = $x; [, [$a]] = $x; PHP; echo ast_dump(ast\parse_code($code, $version=50)); ?> --EXPECT-- AST_STMT_LIST 0: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_LIST (1) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: "foo" 1: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "b" key: "bar" expr: AST_VAR name: "x" 1: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: null 1: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "b" key: null expr: AST_VAR name: "x" 2: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: "foo" 1: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "b" key: "bar" expr: AST_VAR name: "x" 3: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: null 1: AST_ARRAY_ELEM flags: 0 value: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: null key: null expr: AST_VAR name: "x" ast-1.0.5/tests/assign_ops.phpt0000664000175000017500000000374113567500533015640 0ustar tysontyson--TEST-- Assign op flags --FILE-- >= $b; PHP; echo ast_dump(ast\parse_code($code, $version=50)), "\n"; ?> --EXPECTF-- AST_STMT_LIST 0: AST_ASSIGN_OP flags: BINARY_BITWISE_OR (9) var: AST_VAR name: "a" expr: AST_VAR name: "b" 1: AST_ASSIGN_OP flags: BINARY_BITWISE_AND (10) var: AST_VAR name: "a" expr: AST_VAR name: "b" 2: AST_ASSIGN_OP flags: BINARY_BITWISE_XOR (11) var: AST_VAR name: "a" expr: AST_VAR name: "b" 3: AST_ASSIGN_OP flags: BINARY_CONCAT (8) var: AST_VAR name: "a" expr: AST_VAR name: "b" 4: AST_ASSIGN_OP flags: BINARY_ADD (1) var: AST_VAR name: "a" expr: AST_VAR name: "b" 5: AST_ASSIGN_OP flags: BINARY_SUB (2) var: AST_VAR name: "a" expr: AST_VAR name: "b" 6: AST_ASSIGN_OP flags: BINARY_MUL (3) var: AST_VAR name: "a" expr: AST_VAR name: "b" 7: AST_ASSIGN_OP flags: BINARY_DIV (4) var: AST_VAR name: "a" expr: AST_VAR name: "b" 8: AST_ASSIGN_OP flags: BINARY_MOD (5) var: AST_VAR name: "a" expr: AST_VAR name: "b" 9: AST_ASSIGN_OP flags: BINARY_POW (%d) var: AST_VAR name: "a" expr: AST_VAR name: "b" 10: AST_ASSIGN_OP flags: BINARY_SHIFT_LEFT (6) var: AST_VAR name: "a" expr: AST_VAR name: "b" 11: AST_ASSIGN_OP flags: BINARY_SHIFT_RIGHT (7) var: AST_VAR name: "a" expr: AST_VAR name: "b" ast-1.0.5/tests/ast_dump_with_linenos.phpt0000664000175000017500000000175513567500533020074 0ustar tysontyson--TEST-- ast_dump() with AST_DUMP_LINENOS --SKIPIF-- = 70000 && PHP_VERSION_ID < 70018) print "skip buggy PHP version"; if (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70104) print "skip buggy PHP version"; ?> --FILE-- --EXPECT-- AST_STMT_LIST @ 1 0: AST_FUNC_DECL @ 2-9 flags: 0 name: "test" docComment: null params: AST_PARAM_LIST @ 4 uses: null stmts: AST_STMT_LIST @ 5 0: AST_CALL @ 6 expr: AST_NAME @ 6 flags: NAME_NOT_FQ (1) name: "var_dump" args: AST_ARG_LIST @ 7 0: AST_VAR @ 7 name: "foo" returnType: null __declId: 0 ast-1.0.5/tests/binary_ops.phpt0000664000175000017500000000153613567500533015640 0ustar tysontyson--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=50)), "\n"; ?> --EXPECT-- AST_STMT_LIST 0: AST_BINARY_OP flags: BINARY_IS_GREATER (256) left: AST_VAR name: "a" right: AST_VAR name: "b" 1: AST_BINARY_OP flags: BINARY_IS_GREATER_OR_EQUAL (257) left: AST_VAR name: "a" right: AST_VAR name: "b" 2: AST_BINARY_OP flags: BINARY_BOOL_AND (259) left: AST_VAR name: "a" right: AST_VAR name: "b" 3: AST_BINARY_OP flags: BINARY_BOOL_OR (258) left: AST_VAR name: "a" right: AST_VAR name: "b" ast-1.0.5/tests/by_ref_destructuring.phpt0000664000175000017500000000313513567500533017720 0ustar tysontyson--TEST-- By-reference array destructuring (PHP 7.3) --SKIPIF-- = 7.3 only'); ?> --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_LIST (1) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: null 1: AST_ARRAY_ELEM flags: ARRAY_ELEM_REF (1) value: AST_VAR name: "b" key: null expr: AST_VAR name: "c" 1: AST_ASSIGN var: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: null 1: AST_ARRAY_ELEM flags: ARRAY_ELEM_REF (1) value: AST_VAR name: "b" key: null expr: AST_VAR name: "c" 2: AST_ASSIGN var: AST_VAR name: "c" expr: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "a" key: null 1: AST_ARRAY_ELEM flags: ARRAY_ELEM_REF (1) value: AST_VAR name: "b" key: null ast-1.0.5/tests/class_consts.phpt0000664000175000017500000000350413567500533016166 0ustar tysontyson--TEST-- Class constants --SKIPIF-- = 7.1 only'); ?> --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: "Test" docComment: null extends: null implements: null stmts: AST_STMT_LIST 0: AST_CLASS_CONST_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_CONST_ELEM name: "A" value: 1 docComment: "/** Doc A */" 1: AST_CLASS_CONST_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_CONST_ELEM name: "B" value: 2 docComment: null 2: AST_CLASS_CONST_DECL flags: MODIFIER_PROTECTED (%d) 0: AST_CONST_ELEM name: "C" value: 3 docComment: null 3: AST_CLASS_CONST_DECL flags: MODIFIER_PRIVATE (%d) 0: AST_CONST_ELEM name: "D" value: 4 docComment: null 4: AST_CLASS_CONST_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_CONST_ELEM name: "E" value: 5 docComment: "/** Doc E */" 1: AST_CONST_ELEM name: "F" value: 6 docComment: "/** Doc F */" __declId: 0 ast-1.0.5/tests/class_name_version_50.phpt0000664000175000017500000000154113567500533017645 0ustar tysontyson--TEST-- Class properties in AST version 50 --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_NAMESPACE name: "Foo" stmts: null 1: AST_ECHO expr: AST_CLASS_CONST class: AST_NAME flags: NAME_NOT_FQ (1) name: "Bar" const: "class" 2: AST_ECHO expr: AST_CLASS_CONST class: AST_NAME flags: NAME_RELATIVE (2) name: "Bat" const: "class" 3: AST_ECHO expr: AST_CLASS_CONST class: AST_NAME flags: NAME_FQ (0) name: "Baz" const: "class" ast-1.0.5/tests/class_name_version_70.phpt0000664000175000017500000000314313567500533017647 0ustar tysontyson--TEST-- Class properties in AST version 70 --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_NAMESPACE name: "Foo" stmts: null 1: AST_ECHO expr: AST_CLASS_NAME class: AST_NAME flags: NAME_NOT_FQ (%d) name: "Bar" 2: AST_ECHO expr: AST_CLASS_NAME class: AST_NAME flags: NAME_RELATIVE (%d) name: "Bat" 3: AST_ECHO expr: AST_CLASS_CONST class: AST_NAME flags: NAME_NOT_FQ (%d) name: "Bat" const: "class_" 4: AST_ECHO expr: AST_CLASS_NAME class: AST_NAME flags: NAME_FQ (%d) name: "Baz" 5: AST_ECHO expr: AST_CLASS_NAME class: AST_ARRAY flags: %s 6: AST_ECHO expr: AST_CLASS_NAME class: AST_NAME flags: NAME_FQ (%d) name: "foo" 7: AST_ECHO expr: AST_CLASS_NAME class: AST_NEW class: AST_NAME flags: NAME_FQ (0) name: "stdClass" args: AST_ARG_LIST ast-1.0.5/tests/class.phpt0000664000175000017500000000400113567500533014566 0ustar tysontyson--TEST-- Test parse and dump of class --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: "A" docComment: null extends: AST_NAME flags: NAME_NOT_FQ (1) name: "B" implements: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) name: "D" 1: AST_NAME flags: NAME_NOT_FQ (1) name: "E" stmts: AST_STMT_LIST 0: AST_USE_TRAIT traits: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) name: "T" 1: AST_NAME flags: NAME_NOT_FQ (1) name: "S" adaptations: null 1: AST_CLASS_CONST_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_CONST_ELEM name: "X" value: "Y" docComment: null 1: AST_CONST_ELEM name: "Y" value: "X" docComment: null 2: AST_PROP_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_PROP_ELEM name: "foo" default: null docComment: null 1: AST_PROP_ELEM name: "bar" default: null docComment: null 3: AST_METHOD flags: MODIFIER_PUBLIC | MODIFIER_ABSTRACT (%d) name: "test" docComment: null params: AST_PARAM_LIST stmts: null returnType: null __declId: 0 __declId: 1 ast-1.0.5/tests/class_types.phpt0000664000175000017500000000271313567500533016022 0ustar tysontyson--TEST-- Different class types --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: "A" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 0 1: AST_CLASS flags: CLASS_ABSTRACT (%d) name: "B" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 1 2: AST_CLASS flags: CLASS_FINAL (%d) name: "C" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 2 3: AST_CLASS flags: CLASS_TRAIT (%d) name: "D" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 3 4: AST_CLASS flags: CLASS_INTERFACE (%d) name: "E" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 4 5: AST_NEW class: AST_CLASS flags: CLASS_ANONYMOUS (%d) name: null docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 5 args: AST_ARG_LIST ast-1.0.5/tests/closure_use_vars.phpt0000664000175000017500000000220613567500533017051 0ustar tysontyson--TEST-- Closure uses should parse to CLOSURE_USE_VAR nodes --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "fn" expr: AST_CLOSURE flags: MODIFIER_STATIC | FUNC_RETURNS_REF (%d) name: "{closure}" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: null name: "a" default: null 1: AST_PARAM flags: PARAM_REF (1) type: null name: "b" default: null uses: AST_CLOSURE_USES 0: AST_CLOSURE_VAR flags: 0 name: "c" 1: AST_CLOSURE_VAR flags: CLOSURE_USE_REF (1) name: "d" stmts: AST_STMT_LIST returnType: null __declId: 0 ast-1.0.5/tests/coalesce.phpt0000664000175000017500000000054313567500533015246 0ustar tysontyson--TEST-- Null-coalesce operator --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_BINARY_OP flags: BINARY_COALESCE (260) left: AST_VAR name: "a" right: AST_VAR name: "b" ast-1.0.5/tests/concat.phpt0000664000175000017500000000167413567500533014745 0ustar tysontyson--TEST-- AST_CONCAT with/without parenthesis --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_INCLUDE_OR_EVAL flags: EXEC_REQUIRE_ONCE (%d) expr: AST_BINARY_OP flags: BINARY_CONCAT (%d) left: AST_MAGIC_CONST flags: MAGIC_DIR (%d) right: "/first.php" 1: AST_INCLUDE_OR_EVAL flags: EXEC_REQUIRE_ONCE (%d) expr: AST_BINARY_OP flags: BINARY_CONCAT (%d) left: AST_MAGIC_CONST flags: MAGIC_DIR (%d) right: "/second.php" ast-1.0.5/tests/constructor.phpt0000664000175000017500000000141413567500533016053 0ustar tysontyson--TEST-- ast\Node has a __construct method --FILE-- 'FOO'], 2), AST_DUMP_LINENOS) . "\n"; ?> ===DONE=== --EXPECT-- object(ast\Node)#1 (4) { ["kind"]=> NULL ["flags"]=> NULL ["lineno"]=> NULL ["children"]=> NULL } object(ast\Node)#1 (4) { ["kind"]=> NULL ["flags"]=> NULL ["lineno"]=> NULL ["children"]=> NULL } AST_NAME @ 2 flags: NAME_NOT_FQ (1) name: "FOO" ===DONE=== ast-1.0.5/tests/decl_ids.phpt0000664000175000017500000000535513567500533015244 0ustar tysontyson--TEST-- Closures should have unique identifiers within parsed code in version 50 --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 0 1: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 1 2: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 2 3: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 3 4: AST_CLASS flags: 0 name: "Test" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 4 5: AST_CLASS flags: 0 name: "Test" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 5 AST_STMT_LIST 0: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 0 1: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 1 2: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 2 3: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 3 4: AST_CLASS flags: 0 name: "Test" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 4 5: AST_CLASS flags: 0 name: "Test" docComment: null extends: null implements: null stmts: AST_STMT_LIST __declId: 5 ast-1.0.5/tests/decl_normalization.phpt0000664000175000017500000000426413567500533017351 0ustar tysontyson--TEST-- As of version 50 Decl is no more --SKIPIF-- --FILE-- children)); echo ast_dump($ast) . "\n"; ?> --EXPECTF-- array(4) { [0]=> string(8) "ast\Node" [1]=> string(8) "ast\Node" [2]=> string(8) "ast\Node" [3]=> string(8) "ast\Node" } AST_STMT_LIST 0: AST_CLASS flags: 0 name: "A" docComment: "/** A */" extends: null implements: null stmts: AST_STMT_LIST 0: AST_CLASS_CONST_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_CONST_ELEM name: "B" value: 0 docComment: "/** B */" 1: AST_PROP_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_PROP_ELEM name: "c" default: null docComment: "/** c */" 2: AST_METHOD flags: MODIFIER_PUBLIC (%d) name: "d" docComment: "/** d */" params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 0 __declId: 1 1: AST_CONST_DECL 0: AST_CONST_ELEM name: "E" value: 0 docComment: "/** E */" 2: AST_FUNC_DECL flags: 0 name: "f" docComment: "/** f */" params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 2 3: AST_CLOSURE flags: 0 name: "{closure}" docComment: "/** g */" params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 3 ast-1.0.5/tests/empty_file.php0000664000175000017500000000000013567500533015425 0ustar tysontysonast-1.0.5/tests/empty_file_parse.phpt0000664000175000017500000000061313567500533017015 0ustar tysontyson--TEST-- ast\parse_file() with empty file --FILE-- --EXPECT-- bool(true) AST_STMT_LIST bool(true) AST_STMT_LIST ast-1.0.5/tests/eval_include.phpt0000664000175000017500000000133713567500533016124 0ustar tysontyson--TEST-- eval() and include parsing --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_INCLUDE_OR_EVAL flags: EXEC_EVAL (1) expr: "echo "hello";" 1: AST_INCLUDE_OR_EVAL flags: EXEC_INCLUDE (2) expr: "foo.php" 2: AST_INCLUDE_OR_EVAL flags: EXEC_INCLUDE_ONCE (4) expr: "foo.php" 3: AST_INCLUDE_OR_EVAL flags: EXEC_REQUIRE (8) expr: "foo.php" 4: AST_INCLUDE_OR_EVAL flags: EXEC_REQUIRE_ONCE (16) expr: "foo.php" ast-1.0.5/tests/functions_dont_use.phpt0000664000175000017500000000215413567500533017400 0ustar tysontyson--TEST-- Uses only make sense on closures --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 0 1: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 1 AST_STMT_LIST 0: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST returnType: null __declId: 0 1: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST stmts: AST_STMT_LIST returnType: null __declId: 1 ast-1.0.5/tests/generator_flag.phpt0000664000175000017500000000116313567500533016446 0ustar tysontyson--TEST-- Flag on generator functions in PHP 7.1 --SKIPIF-- --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_FUNC_DECL flags: FUNC_GENERATOR (%d) name: "gen" docComment: null params: AST_PARAM_LIST uses: null stmts: AST_STMT_LIST 0: AST_YIELD value: null key: null returnType: null __declId: 0 ast-1.0.5/tests/get_kind_name.phpt0000644000175000017500000000062113567500533016247 0ustar tysontyson--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 ast-1.0.5/tests/get_supported_versions.phpt0000664000175000017500000000045013567500533020301 0ustar tysontyson--TEST-- ast\get_supported_versions() function --FILE-- --EXPECT-- array(3) { [0]=> int(50) [1]=> int(60) [2]=> int(70) } array(3) { [0]=> int(50) [1]=> int(60) [2]=> int(70) } ast-1.0.5/tests/invalid_file.php0000644000175000017500000000002613567500533015723 0ustar tysontyson --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) ast-1.0.5/tests/metadata.phpt0000664000175000017500000001135313567500533015251 0ustar tysontyson--TEST-- AST metadata --FILE-- flags as $flag) { $flags[] = substr($flag, strrpos($flag, '\\') + 1); } $metadataHasFlags = count($flags) > 0; $kindUsesFlags = ast\kind_uses_flags($data->kind); if ($metadataHasFlags != $kindUsesFlags) { echo "kind_uses_flags for $data->name is unexpectedly " . var_export($kindUsesFlags, true) . "\n"; } echo "$data->name: "; if ($data->flagsCombinable) { echo "(combinable) "; } echo "[", implode(", ", $flags), "]\n"; } ?> --EXPECT-- AST_ARG_LIST: [] AST_LIST: [] AST_ARRAY: [ARRAY_SYNTAX_LIST, ARRAY_SYNTAX_LONG, ARRAY_SYNTAX_SHORT] AST_ENCAPS_LIST: [] AST_EXPR_LIST: [] AST_STMT_LIST: [] AST_IF: [] AST_SWITCH_LIST: [] AST_CATCH_LIST: [] AST_PARAM_LIST: [] AST_CLOSURE_USES: [] AST_PROP_DECL: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL] AST_CONST_DECL: [] AST_CLASS_CONST_DECL: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE] AST_NAME_LIST: [] AST_TRAIT_ADAPTATIONS: [] AST_USE: [USE_NORMAL, USE_FUNCTION, USE_CONST] AST_TYPE_UNION: [] AST_NAME: [NAME_FQ, NAME_NOT_FQ, NAME_RELATIVE] AST_CLOSURE_VAR: [CLOSURE_USE_REF] AST_NULLABLE_TYPE: [] AST_FUNC_DECL: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR] AST_CLOSURE: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR] AST_METHOD: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR] AST_ARROW_FUNC: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR] AST_CLASS: [CLASS_ABSTRACT, CLASS_FINAL, CLASS_TRAIT, CLASS_INTERFACE, CLASS_ANONYMOUS] AST_MAGIC_CONST: [MAGIC_LINE, MAGIC_FILE, MAGIC_DIR, MAGIC_NAMESPACE, MAGIC_FUNCTION, MAGIC_METHOD, MAGIC_CLASS, MAGIC_TRAIT] AST_TYPE: [TYPE_NULL, TYPE_FALSE, TYPE_BOOL, TYPE_LONG, TYPE_DOUBLE, TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT, TYPE_CALLABLE, TYPE_VOID, TYPE_ITERABLE] AST_VAR: [] AST_CONST: [] AST_UNPACK: [] AST_CAST: [TYPE_NULL, TYPE_FALSE, TYPE_BOOL, TYPE_LONG, TYPE_DOUBLE, TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT, TYPE_CALLABLE, TYPE_VOID, TYPE_ITERABLE] AST_EMPTY: [] AST_ISSET: [] AST_SHELL_EXEC: [] AST_CLONE: [] AST_EXIT: [] AST_PRINT: [] AST_INCLUDE_OR_EVAL: [EXEC_EVAL, EXEC_INCLUDE, EXEC_INCLUDE_ONCE, EXEC_REQUIRE, EXEC_REQUIRE_ONCE] AST_UNARY_OP: [UNARY_BOOL_NOT, UNARY_BITWISE_NOT, UNARY_MINUS, UNARY_PLUS, UNARY_SILENCE] AST_PRE_INC: [] AST_PRE_DEC: [] AST_POST_INC: [] AST_POST_DEC: [] AST_YIELD_FROM: [] AST_GLOBAL: [] AST_UNSET: [] AST_RETURN: [] AST_LABEL: [] AST_REF: [] AST_HALT_COMPILER: [] AST_ECHO: [] AST_THROW: [] AST_GOTO: [] AST_BREAK: [] AST_CONTINUE: [] AST_CLASS_NAME: [] AST_DIM: (combinable) [DIM_ALTERNATIVE_SYNTAX] AST_PROP: [] AST_STATIC_PROP: [] AST_CALL: [] AST_CLASS_CONST: [] AST_ASSIGN: [] AST_ASSIGN_REF: [] AST_ASSIGN_OP: [BINARY_BITWISE_OR, BINARY_BITWISE_AND, BINARY_BITWISE_XOR, BINARY_CONCAT, BINARY_ADD, BINARY_SUB, BINARY_MUL, BINARY_DIV, BINARY_MOD, BINARY_POW, BINARY_SHIFT_LEFT, BINARY_SHIFT_RIGHT, BINARY_COALESCE] AST_BINARY_OP: [BINARY_BITWISE_OR, BINARY_BITWISE_AND, BINARY_BITWISE_XOR, BINARY_CONCAT, BINARY_ADD, BINARY_SUB, BINARY_MUL, BINARY_DIV, BINARY_MOD, BINARY_POW, BINARY_SHIFT_LEFT, BINARY_SHIFT_RIGHT, BINARY_COALESCE, BINARY_BOOL_AND, BINARY_BOOL_OR, BINARY_BOOL_XOR, BINARY_IS_IDENTICAL, BINARY_IS_NOT_IDENTICAL, BINARY_IS_EQUAL, BINARY_IS_NOT_EQUAL, BINARY_IS_SMALLER, BINARY_IS_SMALLER_OR_EQUAL, BINARY_IS_GREATER, BINARY_IS_GREATER_OR_EQUAL, BINARY_SPACESHIP] AST_ARRAY_ELEM: [ARRAY_ELEM_REF] AST_NEW: [] AST_INSTANCEOF: [] AST_YIELD: [] AST_STATIC: [] AST_WHILE: [] AST_DO_WHILE: [] AST_IF_ELEM: [] AST_SWITCH: [] AST_SWITCH_CASE: [] AST_DECLARE: [] AST_PROP_ELEM: [] AST_PROP_GROUP: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL] AST_CONST_ELEM: [] AST_USE_TRAIT: [] AST_TRAIT_PRECEDENCE: [] AST_METHOD_REFERENCE: [] AST_NAMESPACE: [] AST_USE_ELEM: [USE_NORMAL, USE_FUNCTION, USE_CONST] AST_TRAIT_ALIAS: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL] AST_GROUP_USE: [USE_NORMAL, USE_FUNCTION, USE_CONST] AST_METHOD_CALL: [] AST_STATIC_CALL: [] AST_CONDITIONAL: (combinable) [PARENTHESIZED_CONDITIONAL] AST_TRY: [] AST_CATCH: [] AST_PARAM: (combinable) [PARAM_REF, PARAM_VARIADIC] AST_FOR: [] AST_FOREACH: [] ast-1.0.5/tests/multi_catch.phpt0000664000175000017500000000140313567500533015760 0ustar tysontyson--TEST-- Multi catch --SKIPIF-- = 7.1 only'); ?> --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_TRY try: AST_STMT_LIST catches: AST_CATCH_LIST 0: AST_CATCH class: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) name: "A" 1: AST_NAME flags: NAME_NOT_FQ (1) name: "B" var: AST_VAR name: "b" stmts: AST_STMT_LIST finally: null ast-1.0.5/tests/multiple_final_modifiers.phpt0000664000175000017500000000064613567500533020541 0ustar tysontyson--TEST-- Multiple final multipliers should generate CompileError, not a fatal error --SKIPIF-- --FILE-- getMessage(), "\n"; } ?> --EXPECT-- Multiple final modifiers are not allowed ast-1.0.5/tests/named_children.phpt0000664000175000017500000000201013567500533016413 0ustar tysontyson--TEST-- Named child nodes --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "fn" expr: AST_CLOSURE flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST uses: AST_CLOSURE_USES 0: AST_CLOSURE_VAR flags: CLOSURE_USE_REF (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 __declId: 0 ast-1.0.5/tests/name_node.phpt0000664000175000017500000000131013567500533015406 0ustar tysontyson--TEST-- Name nodes --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_CALL expr: AST_NAME flags: NAME_NOT_FQ (1) name: "foo" args: AST_ARG_LIST 1: AST_CALL expr: AST_NAME flags: NAME_FQ (0) name: "foo" args: AST_ARG_LIST 2: AST_CALL expr: AST_NAME flags: NAME_FQ (0) name: "foo" args: AST_ARG_LIST 3: AST_CALL expr: AST_NAME flags: NAME_FQ (0) name: "foo" args: AST_ARG_LIST ast-1.0.5/tests/nested_stmt_lists.phpt0000664000175000017500000000102113567500533017227 0ustar tysontyson--TEST-- Nested statement lists --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_VAR name: "a" 1: AST_VAR name: "b" 2: AST_VAR name: "c" 3: AST_VAR name: "d" 4: AST_VAR name: "e" 5: AST_VAR name: "f" 6: AST_VAR name: "g" ast-1.0.5/tests/nop_statements.phpt0000664000175000017500000000041213567500533016526 0ustar tysontyson--TEST-- Nop statements --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_VAR name: "a" 1: AST_VAR name: "b" ast-1.0.5/tests/nullable_types.phpt0000664000175000017500000000367613567500533016524 0ustar tysontyson--TEST-- Nullable types --SKIPIF-- = 7.1 only'); ?> --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NULLABLE_TYPE type: AST_NAME flags: NAME_NOT_FQ (1) name: "Foo" name: "foo" default: null uses: null stmts: AST_STMT_LIST returnType: AST_NULLABLE_TYPE type: AST_NAME flags: NAME_NOT_FQ (1) name: "Bar" __declId: 0 1: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_LONG (4) name: "foo" default: null uses: null stmts: AST_STMT_LIST returnType: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_LONG (4) __declId: 1 2: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_ARRAY (7) name: "foo" default: null uses: null stmts: AST_STMT_LIST returnType: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_ARRAY (7) __declId: 2 ast-1.0.5/tests/object_type.phpt0000664000175000017500000000121013567500533015767 0ustar tysontyson--TEST-- The object type is recognized --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_OBJECT (8) name: "obj" default: null stmts: AST_STMT_LIST returnType: AST_TYPE flags: TYPE_OBJECT (8) __declId: 0 ast-1.0.5/tests/params.phpt0000664000175000017500000000357013567500533014756 0ustar tysontyson--TEST-- Function parameters --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: null name: "a" default: null 1: AST_PARAM flags: PARAM_VARIADIC (2) type: null name: "b" default: null uses: null stmts: AST_STMT_LIST returnType: null __declId: 0 1: AST_FUNC_DECL flags: 0 name: "test2" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: PARAM_REF (1) type: null name: "a" default: null 1: AST_PARAM flags: PARAM_REF | PARAM_VARIADIC (3) type: null name: "b" default: null uses: null stmts: AST_STMT_LIST returnType: null __declId: 1 2: AST_FUNC_DECL flags: 0 name: "test3" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: PARAM_REF (1) type: AST_TYPE flags: TYPE_ARRAY (7) name: "a" default: null 1: AST_PARAM flags: PARAM_REF | PARAM_VARIADIC (3) type: AST_TYPE flags: TYPE_ARRAY (7) name: "b" default: null uses: null stmts: AST_STMT_LIST returnType: null __declId: 2 ast-1.0.5/tests/parse_code_parse_error.phpt0000664000175000017500000000110213567500533020167 0ustar tysontyson--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', %d) #1 {main} ParseError: syntax error, unexpected '&', expecting end of file in file.php:1 Stack trace: #0 %s(%d): ast\parse_code('%s', %d, 'file.php') #1 {main} ast-1.0.5/tests/parse_file_not_existing.phpt0000664000175000017500000000061413567500533020372 0ustar tysontyson--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', %d) #1 {main} ast-1.0.5/tests/parse_file_parse_error.phpt0000664000175000017500000000051213567500533020200 0ustar tysontyson--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', %d) #1 {main} ast-1.0.5/tests/parse_file.phpt0000664000175000017500000000036213567500533015600 0ustar tysontyson--TEST-- ast\parse_file() on valid file --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_RETURN expr: 123 ast-1.0.5/tests/php74_ast_assign_coalesce.phpt0000664000175000017500000000161513567500533020504 0ustar tysontyson--TEST-- '??=' operator in PHP 7.4 --SKIPIF-- = 7.4 only'); ?> --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_ASSIGN_OP flags: BINARY_COALESCE (%d) var: AST_VAR name: "x" expr: 2 1: AST_ASSIGN_OP flags: BINARY_COALESCE (%d) var: AST_DIM flags: 0 expr: AST_STATIC_PROP class: AST_NAME flags: NAME_NOT_FQ (%d) name: "Foo" prop: "prop" dim: "offset" expr: AST_ASSIGN_OP flags: BINARY_COALESCE (%d) var: AST_VAR name: "other" expr: "value" ast-1.0.5/tests/php74_dim_alternative_syntax.phpt0000664000175000017500000000115313567500533021265 0ustar tysontyson--TEST-- '$x{"offset"}' flag in PHP 7.4 --SKIPIF-- = 7.4 only'); ?> --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_CALL expr: AST_NAME flags: NAME_NOT_FQ (1) name: "var_export" args: AST_ARG_LIST 0: AST_DIM flags: DIM_ALTERNATIVE_SYNTAX (2) expr: AST_VAR name: "x" dim: "offset" ast-1.0.5/tests/php74_ordinary_class.phpt0000664000175000017500000000421113567500533017522 0ustar tysontyson--TEST-- Class properties in AST version 70 (php 7.0+) --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_NAMESPACE name: "Foo" stmts: null 1: AST_CLASS flags: 0 name: "test" docComment: null extends: null implements: null stmts: AST_STMT_LIST 0: AST_PROP_GROUP flags: MODIFIER_PUBLIC (%d) type: null props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "i" default: 2 docComment: null 1: AST_PROP_ELEM name: "j" default: null docComment: null 1: AST_PROP_GROUP flags: MODIFIER_PROTECTED (%d) type: null props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "row" default: null docComment: null 2: AST_PROP_GROUP flags: MODIFIER_PUBLIC (%d) type: null props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "o" default: null docComment: null 3: AST_PROP_GROUP flags: MODIFIER_PRIVATE | MODIFIER_STATIC (%d) type: null props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "normal" default: AST_CONST name: AST_NAME flags: NAME_NOT_FQ (1) name: "null" docComment: null __declId: 0 ast-1.0.5/tests/php74_parenthesized_conditional.phpt0000664000175000017500000000231013567500533021734 0ustar tysontyson--TEST-- parenthesized conditionals in PHP 7.4 --SKIPIF-- = 7.4 only'); ?> --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_RETURN expr: AST_CONDITIONAL flags: 0 cond: AST_CONDITIONAL flags: 0 cond: AST_VAR name: "a" true: AST_VAR name: "b" false: AST_VAR name: "c" true: AST_VAR name: "d" false: AST_VAR name: "e" 1: AST_RETURN expr: AST_CONDITIONAL flags: 0 cond: AST_VAR name: "a" true: AST_VAR name: "b" false: AST_CONDITIONAL flags: PARENTHESIZED_CONDITIONAL (1) cond: AST_VAR name: "c" true: AST_VAR name: "d" false: AST_VAR name: "e" ast-1.0.5/tests/php74_type_hints.phpt0000664000175000017500000001252013567500533016676 0ustar tysontyson--TEST-- Property type hints in PHP 7.4 --SKIPIF-- = 7.4 only'); ?> --FILE-- --EXPECTF-- The type property should not be set in version 60 AST_STMT_LIST 0: AST_NAMESPACE name: "Foo" stmts: null 1: AST_CLASS flags: 0 name: "test" docComment: null extends: null implements: null stmts: AST_STMT_LIST 0: AST_PROP_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_PROP_ELEM name: "i" default: 2 docComment: null 1: AST_PROP_ELEM name: "j" default: null docComment: null 1: AST_PROP_DECL flags: MODIFIER_PUBLIC | MODIFIER_STATIC (%d) 0: AST_PROP_ELEM name: "s" default: null docComment: null 2: AST_PROP_DECL flags: MODIFIER_PRIVATE (%d) 0: AST_PROP_ELEM name: "it" default: null docComment: null 3: AST_PROP_DECL flags: MODIFIER_PROTECTED (%d) 0: AST_PROP_ELEM name: "row" default: null docComment: null 4: AST_PROP_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_PROP_ELEM name: "o" default: null docComment: null 5: AST_PROP_DECL flags: MODIFIER_PRIVATE | MODIFIER_STATIC (%d) 0: AST_PROP_ELEM name: "normal" default: AST_CONST name: AST_NAME flags: NAME_NOT_FQ (1) name: "null" docComment: null __declId: 0 But the type property should be set in version 70 AST_STMT_LIST 0: AST_NAMESPACE name: "Foo" stmts: null 1: AST_CLASS flags: 0 name: "test" docComment: null extends: null implements: null stmts: AST_STMT_LIST 0: AST_PROP_GROUP flags: MODIFIER_PUBLIC (%d) type: AST_TYPE flags: TYPE_LONG (4) props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "i" default: 2 docComment: null 1: AST_PROP_ELEM name: "j" default: null docComment: null 1: AST_PROP_GROUP flags: MODIFIER_PUBLIC | MODIFIER_STATIC (%d) type: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_STRING (6) props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "s" default: null docComment: null 2: AST_PROP_GROUP flags: MODIFIER_PRIVATE (%d) type: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_ITERABLE (%d) props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "it" default: null docComment: null 3: AST_PROP_GROUP flags: MODIFIER_PROTECTED (%d) type: AST_NAME flags: NAME_NOT_FQ (1) name: "Row" props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "row" default: null docComment: null 4: AST_PROP_GROUP flags: MODIFIER_PUBLIC (%d) type: AST_NAME flags: NAME_FQ (0) name: "stdClass" props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "o" default: null docComment: null 5: AST_PROP_GROUP flags: MODIFIER_PRIVATE | MODIFIER_STATIC (%d) type: null props: AST_PROP_DECL flags: 0 0: AST_PROP_ELEM name: "normal" default: AST_CONST name: AST_NAME flags: NAME_NOT_FQ (1) name: "null" docComment: null __declId: 0 ast-1.0.5/tests/php80_union_types.phpt0000664000175000017500000001032413567500533017061 0ustar tysontyson--TEST-- Union types in PHP 8.0 --SKIPIF-- = 8.0 only'); ?> --FILE-- = 8.0 only'); ?> --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_CLASS flags: 0 name: "A" docComment: null extends: null implements: null stmts: AST_STMT_LIST 0: AST_PROP_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_PROP_ELEM name: "a" default: null docComment: "/** docComment $a */" 1: AST_PROP_DECL flags: MODIFIER_PUBLIC (%d) 0: AST_PROP_ELEM name: "b" default: null docComment: "/** docComment $b */" 1: AST_PROP_ELEM name: "c" default: null docComment: "/** docComment $c */" __declId: 0 ast-1.0.5/tests/short_arrow_function.phpt0000664000175000017500000000552513567500533017753 0ustar tysontyson--TEST-- Arrow functions ('fn($x) => $x') in PHP 7.4 --SKIPIF-- = 7.4 only'); ?> --FILE-- $x * $y; $b = static fn() => 1; $c = /** doc comment */ static fn(?int... $args): array => $args; $fn = fn() => yield 123; PHP; $node = ast\parse_code($code, $version=70); $version_70_repr = ast_dump($node); echo $version_70_repr . "\n"; $node50 = ast\parse_code($code, $version=50); $version_50_repr = ast_dump($node50); echo "Same representation in version 50/70: "; var_export($version_50_repr == $version_70_repr); echo "\n"; ?> --EXPECTF-- AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "y" expr: 1 1: AST_ASSIGN var: AST_VAR name: "a" expr: AST_ARROW_FUNC flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: null name: "x" default: null stmts: AST_RETURN expr: AST_BINARY_OP flags: BINARY_MUL (3) left: AST_VAR name: "x" right: AST_VAR name: "y" returnType: null __declId: 0 2: AST_ASSIGN var: AST_VAR name: "b" expr: AST_ARROW_FUNC flags: MODIFIER_STATIC (16) name: "{closure}" docComment: null params: AST_PARAM_LIST stmts: AST_RETURN expr: 1 returnType: null __declId: 1 3: AST_ASSIGN var: AST_VAR name: "c" expr: AST_ARROW_FUNC flags: MODIFIER_STATIC (16) name: "{closure}" docComment: "/** doc comment */" params: AST_PARAM_LIST 0: AST_PARAM flags: PARAM_VARIADIC (2) type: AST_NULLABLE_TYPE type: AST_TYPE flags: TYPE_LONG (4) name: "args" default: null stmts: AST_RETURN expr: AST_VAR name: "args" returnType: AST_TYPE flags: TYPE_ARRAY (7) __declId: 2 4: AST_ASSIGN var: AST_VAR name: "fn" expr: AST_ARROW_FUNC flags: FUNC_GENERATOR (16777216) name: "{closure}" docComment: null params: AST_PARAM_LIST stmts: AST_RETURN expr: AST_YIELD value: 123 key: null returnType: null __declId: 3 Same representation in version 50/70: trueast-1.0.5/tests/short_arrow_function_return.phpt0000664000175000017500000000523713567500533021352 0ustar tysontyson--TEST-- Arrow functions and types ('fn($x) => $x') in PHP 7.4 --SKIPIF-- = 7.4 only'); ?> --FILE-- 1; fn(iterable $i) : array => [$i]; fn(stdClass $param) : \stdClass => $param; fn(\stdClass $param) : stdClass => $param; PHP; $node = ast\parse_code($code, $version=70); $version_70_repr = ast_dump($node); echo $version_70_repr . "\n"; $node50 = ast\parse_code($code, $version=50); $version_50_repr = ast_dump($node50); echo "Same representation in version 50/70: "; var_export($version_50_repr == $version_70_repr); echo "\n"; ?> --EXPECTF-- AST_STMT_LIST 0: AST_ARROW_FUNC flags: MODIFIER_STATIC (16) name: "{closure}" docComment: null params: AST_PARAM_LIST stmts: AST_RETURN expr: 1 returnType: AST_TYPE flags: TYPE_LONG (4) __declId: 0 1: AST_ARROW_FUNC flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_ITERABLE (%d) name: "i" default: null stmts: AST_RETURN expr: AST_ARRAY flags: ARRAY_SYNTAX_SHORT (3) 0: AST_ARRAY_ELEM flags: 0 value: AST_VAR name: "i" key: null returnType: AST_TYPE flags: TYPE_ARRAY (7) __declId: 1 2: AST_ARROW_FUNC flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NAME flags: NAME_NOT_FQ (1) name: "stdClass" name: "param" default: null stmts: AST_RETURN expr: AST_VAR name: "param" returnType: AST_NAME flags: NAME_FQ (0) name: "stdClass" __declId: 2 3: AST_ARROW_FUNC flags: 0 name: "{closure}" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NAME flags: NAME_FQ (0) name: "stdClass" name: "param" default: null stmts: AST_RETURN expr: AST_VAR name: "param" returnType: AST_NAME flags: NAME_NOT_FQ (1) name: "stdClass" __declId: 3 Same representation in version 50/70: trueast-1.0.5/tests/stmt_list.phpt0000664000175000017500000000202613567500533015510 0ustar tysontyson--TEST-- Statement list normalization --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_WHILE cond: AST_VAR name: "a" stmts: AST_STMT_LIST 1: AST_WHILE cond: AST_VAR name: "a" stmts: AST_STMT_LIST 0: AST_VAR name: "b" 2: AST_WHILE cond: AST_VAR name: "a" stmts: AST_STMT_LIST 0: AST_VAR name: "b" 3: AST_DECLARE declares: AST_CONST_DECL 0: AST_CONST_ELEM name: "ticks" value: 1 docComment: null stmts: null 4: AST_DECLARE declares: AST_CONST_DECL 0: AST_CONST_ELEM name: "ticks" value: 1 docComment: null stmts: AST_STMT_LIST ast-1.0.5/tests/try_catch_finally.phpt0000664000175000017500000000237213567500533017170 0ustar tysontyson--TEST-- try / catch / finally --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_TRY try: AST_STMT_LIST 0: AST_ECHO expr: "try" catches: AST_CATCH_LIST 0: AST_CATCH class: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) name: "Exception" var: AST_VAR name: "e" stmts: AST_STMT_LIST 0: AST_ECHO expr: "catch 1" 1: AST_CATCH class: AST_NAME_LIST 0: AST_NAME flags: NAME_NOT_FQ (1) name: "bar\FooException" var: AST_VAR name: "e2" stmts: AST_STMT_LIST 0: AST_ECHO expr: "catch 2" finally: AST_STMT_LIST 0: AST_ECHO expr: "finally" ast-1.0.5/tests/type_hints.phpt0000664000175000017500000000374013567500533015660 0ustar tysontyson--TEST-- Type hints --FILE-- --EXPECTF-- AST_STMT_LIST 0: AST_FUNC_DECL flags: 0 name: "test" docComment: null params: AST_PARAM_LIST 0: AST_PARAM flags: 0 type: AST_NAME flags: NAME_NOT_FQ (1) name: "A" name: "a" default: null 1: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_ARRAY (7) name: "b" default: null 2: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_CALLABLE (%d) name: "c" default: null 3: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_LONG (4) name: "d" default: null 4: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_DOUBLE (5) name: "e" default: null 5: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_STRING (6) name: "f" default: null 6: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_BOOL (%d) name: "g" default: null 7: AST_PARAM flags: 0 type: AST_TYPE flags: TYPE_ITERABLE (%d) name: "h" default: null uses: null stmts: AST_STMT_LIST returnType: AST_TYPE flags: TYPE_VOID (%d) __declId: 0 ast-1.0.5/tests/unary_ops.phpt0000664000175000017500000000077113567500533015512 0ustar tysontyson--TEST-- Convert unary ops AST_(SILENCE|UNARY_(PLUS|MINUS)) to flags of ZEND_AST_UNARY_OP --FILE-- --EXPECT-- AST_STMT_LIST 0: AST_UNARY_OP flags: UNARY_SILENCE (260) expr: AST_VAR name: "a" 1: AST_UNARY_OP flags: UNARY_PLUS (261) expr: 1 2: AST_UNARY_OP flags: UNARY_MINUS (262) expr: 1 ast-1.0.5/tests/use_declarations.phpt0000664000175000017500000000241713567500533017016 0ustar tysontyson--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 name: "Foo\Bar" alias: "Baz" 1: AST_USE flags: USE_FUNCTION (%d) 0: AST_USE_ELEM flags: 0 name: "foo\bar" alias: "baz" 2: AST_GROUP_USE flags: 0 prefix: "Foo" uses: AST_USE flags: 0 0: AST_USE_ELEM flags: USE_NORMAL (%d) name: "Bar" alias: null 1: AST_USE_ELEM flags: USE_FUNCTION (%d) name: "bar" alias: null 3: AST_GROUP_USE flags: USE_FUNCTION (%d) prefix: "foo" uses: AST_USE flags: 0 0: AST_USE_ELEM flags: 0 name: "bar" alias: null 1: AST_USE_ELEM flags: 0 name: "baz" alias: null ast-1.0.5/tests/valid_file.php0000644000175000017500000000002313567500533015371 0ustar tysontysongetMessage(), "\n"; } try { ast\parse_code('getMessage(), "\n"; } ?> --EXPECTF-- No version specified. Current version is %d. All versions (including experimental): {%d, %s} Unknown version 100. Current version is %d. All versions (including experimental): {%d, %s} ast-1.0.5/tests/zpp_errors.phpt0000644000175000017500000000115713567500533015675 0ustar tysontyson--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 ast-1.0.5/config.m40000664000175000017500000000034113567500533013134 0ustar tysontysondnl 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 ast-1.0.5/config.w320000664000175000017500000000020713567500533013230 0ustar tysontyson// vim:ft=javascript ARG_ENABLE("ast", "enable ast support", "no"); if (PHP_AST != "no") { EXTENSION("ast", "ast.c ast_data.c"); } ast-1.0.5/util.php0000664000175000017500000000445313567500533013123 0ustar tysontysonflags)) { continue; } $flagMap = []; foreach ($data->flags as $fullName) { $shortName = substr($fullName, strrpos($fullName, '\\') + 1); $flagMap[constant($fullName)] = $shortName; } $info[(int) $data->flagsCombinable][$data->kind] = $flagMap; } return $info; } 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) || $ast->flags != 0) { $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; } } ast-1.0.5/ast.c0000664000175000017500000012071613567500533012371 0ustar tysontyson#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)[3 * 0] #define AST_CACHE_SLOT_FLAGS &AST_G(cache_slots)[3 * 1] #define AST_CACHE_SLOT_LINENO &AST_G(cache_slots)[3 * 2] #define AST_CACHE_SLOT_CHILDREN &AST_G(cache_slots)[3 * 3] #define AST_CURRENT_VERSION 70 /* 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 #define AST_BINARY_COALESCE 260 /* 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 /* Define some compatibility constants */ #if PHP_VERSION_ID < 70100 # define IS_VOID 18 # define IS_ITERABLE 19 # define ZEND_TYPE_NULLABLE (1<<8) # define ZEND_ARRAY_SYNTAX_LIST 1 # define ZEND_ARRAY_SYNTAX_LONG 2 # define ZEND_ARRAY_SYNTAX_SHORT 3 #endif #if PHP_VERSION_ID < 70300 # define ZEND_BIND_REF 1 #endif #if PHP_VERSION_ID < 70400 # define ZEND_DIM_ALTERNATIVE_SYNTAX (1<<1) # define ZEND_PARENTHESIZED_CONDITIONAL 1 #endif /* This contains state of the ast Node creator. */ typedef struct ast_state_info { zend_long version; zend_long declIdCounter; } ast_state_info_t; typedef struct _ast_flag_info { uint16_t ast_kind; zend_bool combinable; const char **flags; } ast_flag_info; ZEND_DECLARE_MODULE_GLOBALS(ast) ast_str_globals str_globals; static zend_class_entry *ast_node_ce; static zend_class_entry *ast_metadata_ce; #define AST_FLAG(name) "ast\\flags\\" #name static const char *name_flags[] = { AST_FLAG(NAME_FQ), AST_FLAG(NAME_NOT_FQ), AST_FLAG(NAME_RELATIVE), NULL }; static const char *class_flags[] = { AST_FLAG(CLASS_ABSTRACT), AST_FLAG(CLASS_FINAL), AST_FLAG(CLASS_TRAIT), AST_FLAG(CLASS_INTERFACE), AST_FLAG(CLASS_ANONYMOUS), NULL }; static const char *param_flags[] = { AST_FLAG(PARAM_REF), AST_FLAG(PARAM_VARIADIC), NULL }; static const char *type_flags[] = { AST_FLAG(TYPE_NULL), AST_FLAG(TYPE_FALSE), AST_FLAG(TYPE_BOOL), AST_FLAG(TYPE_LONG), AST_FLAG(TYPE_DOUBLE), AST_FLAG(TYPE_STRING), AST_FLAG(TYPE_ARRAY), AST_FLAG(TYPE_OBJECT), AST_FLAG(TYPE_CALLABLE), AST_FLAG(TYPE_VOID), AST_FLAG(TYPE_ITERABLE), NULL }; static const char *unary_op_flags[] = { AST_FLAG(UNARY_BOOL_NOT), AST_FLAG(UNARY_BITWISE_NOT), AST_FLAG(UNARY_MINUS), AST_FLAG(UNARY_PLUS), AST_FLAG(UNARY_SILENCE), NULL }; #define AST_SHARED_BINARY_OP_FLAGS \ AST_FLAG(BINARY_BITWISE_OR), \ AST_FLAG(BINARY_BITWISE_AND), \ AST_FLAG(BINARY_BITWISE_XOR), \ AST_FLAG(BINARY_CONCAT), \ AST_FLAG(BINARY_ADD), \ AST_FLAG(BINARY_SUB), \ AST_FLAG(BINARY_MUL), \ AST_FLAG(BINARY_DIV), \ AST_FLAG(BINARY_MOD), \ AST_FLAG(BINARY_POW), \ AST_FLAG(BINARY_SHIFT_LEFT), \ AST_FLAG(BINARY_SHIFT_RIGHT), \ AST_FLAG(BINARY_COALESCE) \ static const char *binary_op_flags[] = { AST_SHARED_BINARY_OP_FLAGS, AST_FLAG(BINARY_BOOL_AND), AST_FLAG(BINARY_BOOL_OR), AST_FLAG(BINARY_BOOL_XOR), AST_FLAG(BINARY_IS_IDENTICAL), AST_FLAG(BINARY_IS_NOT_IDENTICAL), AST_FLAG(BINARY_IS_EQUAL), AST_FLAG(BINARY_IS_NOT_EQUAL), AST_FLAG(BINARY_IS_SMALLER), AST_FLAG(BINARY_IS_SMALLER_OR_EQUAL), AST_FLAG(BINARY_IS_GREATER), AST_FLAG(BINARY_IS_GREATER_OR_EQUAL), AST_FLAG(BINARY_SPACESHIP), NULL }; static const char *assign_op_flags[] = { AST_SHARED_BINARY_OP_FLAGS, NULL }; static const char *magic_const_flags[] = { AST_FLAG(MAGIC_LINE), AST_FLAG(MAGIC_FILE), AST_FLAG(MAGIC_DIR), AST_FLAG(MAGIC_NAMESPACE), AST_FLAG(MAGIC_FUNCTION), AST_FLAG(MAGIC_METHOD), AST_FLAG(MAGIC_CLASS), AST_FLAG(MAGIC_TRAIT), NULL }; static const char *use_flags[] = { AST_FLAG(USE_NORMAL), AST_FLAG(USE_FUNCTION), AST_FLAG(USE_CONST), NULL }; static const char *include_flags[] = { AST_FLAG(EXEC_EVAL), AST_FLAG(EXEC_INCLUDE), AST_FLAG(EXEC_INCLUDE_ONCE), AST_FLAG(EXEC_REQUIRE), AST_FLAG(EXEC_REQUIRE_ONCE), NULL }; static const char *array_flags[] = { AST_FLAG(ARRAY_SYNTAX_LIST), AST_FLAG(ARRAY_SYNTAX_LONG), AST_FLAG(ARRAY_SYNTAX_SHORT), NULL }; static const char *array_elem_flags[] = { AST_FLAG(ARRAY_ELEM_REF), NULL }; static const char *closure_use_flags[] = { AST_FLAG(CLOSURE_USE_REF), NULL }; #define AST_VISIBILITY_FLAGS \ AST_FLAG(MODIFIER_PUBLIC), \ AST_FLAG(MODIFIER_PROTECTED), \ AST_FLAG(MODIFIER_PRIVATE) #define AST_MODIFIER_FLAGS \ AST_VISIBILITY_FLAGS, \ AST_FLAG(MODIFIER_STATIC), \ AST_FLAG(MODIFIER_ABSTRACT), \ AST_FLAG(MODIFIER_FINAL) static const char *visibility_flags[] = { AST_VISIBILITY_FLAGS, NULL }; static const char *modifier_flags[] = { AST_MODIFIER_FLAGS, NULL }; static const char *func_flags[] = { AST_MODIFIER_FLAGS, AST_FLAG(FUNC_RETURNS_REF), AST_FLAG(FUNC_GENERATOR), NULL }; // Flags of AST_DIM are marked as combinable in case any other flags get added in the future. static const char *dim_flags[] = { AST_FLAG(DIM_ALTERNATIVE_SYNTAX), NULL }; // Flags of AST_CONDITIONAL are marked as combinable in case any other flags get added in the future. static const char *conditional_flags[] = { AST_FLAG(PARENTHESIZED_CONDITIONAL), NULL }; static const ast_flag_info flag_info[] = { { AST_NAME, 0, name_flags }, { ZEND_AST_CLASS, 0, class_flags }, { ZEND_AST_PARAM, 1, param_flags }, { ZEND_AST_TYPE, 0, type_flags }, { ZEND_AST_CAST, 0, type_flags }, { ZEND_AST_UNARY_OP, 0, unary_op_flags }, { ZEND_AST_BINARY_OP, 0, binary_op_flags }, { ZEND_AST_ASSIGN_OP, 0, assign_op_flags }, { ZEND_AST_MAGIC_CONST, 0, magic_const_flags }, { ZEND_AST_USE, 0, use_flags }, { ZEND_AST_GROUP_USE, 0, use_flags }, { ZEND_AST_USE_ELEM, 0, use_flags }, { ZEND_AST_INCLUDE_OR_EVAL, 0, include_flags }, { ZEND_AST_ARRAY, 0, array_flags }, { ZEND_AST_ARRAY_ELEM, 0, array_elem_flags }, { AST_CLOSURE_VAR, 0, closure_use_flags }, { ZEND_AST_METHOD, 1, func_flags }, { ZEND_AST_FUNC_DECL, 1, func_flags }, { ZEND_AST_CLOSURE, 1, func_flags }, { ZEND_AST_ARROW_FUNC, 1, func_flags }, { ZEND_AST_PROP_DECL, 1, modifier_flags }, { ZEND_AST_PROP_GROUP, 1, modifier_flags }, { ZEND_AST_CLASS_CONST_DECL, 1, visibility_flags }, { ZEND_AST_TRAIT_ALIAS, 1, modifier_flags }, { ZEND_AST_DIM, 1, dim_flags }, { ZEND_AST_CONDITIONAL, 1, conditional_flags }, }; static inline void ast_update_property(zval *object, zend_string *name, zval *value, void **cache_slot) { #if PHP_VERSION_ID < 80000 zval name_zv; ZVAL_STR(&name_zv, name); Z_OBJ_HT_P(object)->write_property(object, &name_zv, value, cache_slot); #else Z_OBJ_HT_P(object)->write_property(Z_OBJ_P(object), name, value, cache_slot); #endif } static inline void ast_update_property_long(zval *object, zend_string *name, zend_long value_raw, void **cache_slot) { zval value_zv; ZVAL_LONG(&value_zv, value_raw); ast_update_property(object, name, &value_zv, cache_slot); } 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_PROP_GROUP || kind == ZEND_AST_GROUP_USE || kind == ZEND_AST_USE_ELEM || kind == AST_NAME || kind == AST_CLOSURE_VAR || kind == ZEND_AST_CLASS_CONST_DECL || kind == ZEND_AST_ARRAY || kind == ZEND_AST_DIM || kind == ZEND_AST_CONDITIONAL; } 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_ARROW_FUNC || 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) { return 0; } if (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 PHP_VERSION_ID >= 80000 if (parent->kind == ZEND_AST_TYPE_UNION) { return 1; } #endif 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 || parent->kind == ZEND_AST_PROP_GROUP || parent->kind == ZEND_AST_CLASS_NAME ; } if (i == 1) { return parent->kind == ZEND_AST_INSTANCEOF; } if (i == 3) { return parent->kind == ZEND_AST_FUNC_DECL || parent->kind == ZEND_AST_CLOSURE #if PHP_VERSION_ID >= 70400 || parent->kind == ZEND_AST_ARROW_FUNC #endif || parent->kind == ZEND_AST_METHOD; } return 0; } /* Assumes that ast_is_name is already true */ static inline zend_bool ast_is_type(zend_ast *ast, zend_ast *parent, uint32_t i) { #if PHP_VERSION_ID >= 80000 if (parent->kind == ZEND_AST_TYPE_UNION) { return 1; } #endif if (i == 0) { return parent->kind == ZEND_AST_PARAM #if PHP_VERSION_ID >= 70400 || parent->kind == ZEND_AST_PROP_GROUP #endif ; } if (i == 3) { return parent->kind == ZEND_AST_CLOSURE || parent->kind == ZEND_AST_FUNC_DECL #if PHP_VERSION_ID >= 70400 || parent->kind == ZEND_AST_ARROW_FUNC #endif || 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); } /* Whether this node may need statement list normalization */ static inline zend_bool ast_should_normalize_list(zend_ast *ast, zend_ast *parent, uint32_t i) { if (ast && ast->kind == ZEND_AST_STMT_LIST) { return 0; } if (i == 0) { return parent->kind == ZEND_AST_DO_WHILE; } if (i == 1) { if (parent->kind == ZEND_AST_DECLARE) { /* declare(); and declare() {} are not the same */ return ast != NULL; } return parent->kind == ZEND_AST_IF_ELEM || parent->kind == ZEND_AST_WHILE; } if (i == 2) { return parent->kind == ZEND_AST_CATCH; } if (i == 3) { return parent->kind == ZEND_AST_FOR || parent->kind == ZEND_AST_FOREACH; } return 0; } /* Adopted from zend_compile.c */ typedef struct _builtin_type_info { const char* name; const size_t name_len; const zend_uchar type; } builtin_type_info; static const builtin_type_info builtin_types[] = { {ZEND_STRL("int"), IS_LONG}, {ZEND_STRL("float"), IS_DOUBLE}, {ZEND_STRL("string"), IS_STRING}, {ZEND_STRL("bool"), _IS_BOOL}, {ZEND_STRL("void"), IS_VOID}, {ZEND_STRL("iterable"), IS_ITERABLE}, {ZEND_STRL("object"), IS_OBJECT}, {ZEND_STRL("null"), IS_NULL}, /* Null and false for php 8.0 union types */ {ZEND_STRL("false"), IS_FALSE}, {NULL, 0, IS_UNDEF} }; static inline zend_uchar lookup_builtin_type(const zend_string *name) { const builtin_type_info *info = &builtin_types[0]; for (; info->name; ++info) { if (ZSTR_LEN(name) == info->name_len && !zend_binary_strcasecmp(ZSTR_VAL(name), ZSTR_LEN(name), info->name, info->name_len) ) { return info->type; } } return 0; } #if PHP_VERSION_ID < 70400 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() } } #endif 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_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state); static void ast_create_virtual_node_ex( zval *zv, zend_ast_kind kind, zend_ast_attr attr, uint32_t lineno, ast_state_info_t *state, uint32_t num_children, ...) { zval tmp_zv; va_list va; uint32_t i; object_init_ex(zv, ast_node_ce); ast_update_property_long(zv, AST_STR(str_kind), kind, AST_CACHE_SLOT_KIND); ast_update_property_long(zv, AST_STR(str_flags), attr, AST_CACHE_SLOT_FLAGS); ast_update_property_long(zv, AST_STR(str_lineno), lineno, AST_CACHE_SLOT_LINENO); array_init(&tmp_zv); Z_DELREF(tmp_zv); ast_update_property(zv, AST_STR(str_children), &tmp_zv, AST_CACHE_SLOT_CHILDREN); va_start(va, num_children); for (i = 0; i < num_children; i++) { zval *child_zv = va_arg(va, zval *); zend_string *child_name = ast_kind_child_name(kind, i); if (child_name) { zend_hash_add_new(Z_ARRVAL(tmp_zv), child_name, child_zv); } else { zend_hash_next_index_insert(Z_ARRVAL(tmp_zv), child_zv); } } va_end(va); } static void ast_create_virtual_node( zval *zv, zend_ast_kind kind, zend_ast_attr attr, zend_ast *child, ast_state_info_t *state) { zval child_zv; ast_to_zval(&child_zv, child, state); ast_create_virtual_node_ex( zv, kind, attr, zend_ast_get_lineno(child), state, 1, &child_zv); } static inline void ast_name_to_zval(zend_ast *child, zend_ast *ast, zval *child_zv, int i, ast_state_info_t *state) { zend_uchar type; zend_bool is_nullable = 0; if (child->attr & ZEND_TYPE_NULLABLE) { is_nullable = 1; child->attr &= ~ZEND_TYPE_NULLABLE; } if (child->attr == ZEND_NAME_FQ) { /* Ensure there is no leading \ for fully-qualified names. This can happen if * something like ('\bar')() is used. */ zval *name = zend_ast_get_zval(child); if (Z_STRVAL_P(name)[0] == '\\') { zend_string *new_name = zend_string_init( Z_STRVAL_P(name) + 1, Z_STRLEN_P(name) - 1, 0); zend_string_release(Z_STR_P(name)); Z_STR_P(name) = new_name; } } if (child->attr == ZEND_NAME_NOT_FQ && ast_is_type(child, ast, i) && (type = lookup_builtin_type(zend_ast_get_str(child))) ) { /* Convert "int" etc typehints to TYPE nodes */ ast_create_virtual_node_ex( child_zv, ZEND_AST_TYPE, type, zend_ast_get_lineno(child), state, 0); } else { ast_create_virtual_node(child_zv, AST_NAME, child->attr, child, state); } if (is_nullable) { /* Create explicit AST_NULLABLE_TYPE node */ zval tmp; ZVAL_COPY_VALUE(&tmp, child_zv); ast_create_virtual_node_ex( child_zv, AST_NULLABLE_TYPE, 0, zend_ast_get_lineno(child), state, 1, &tmp); } } static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, ast_state_info_t *state) { uint32_t i, count; zend_bool is_list = zend_ast_is_list(ast); zend_ast **children = ast_get_children(ast, &count); const zend_ast_kind ast_kind = ast->kind; for (i = 0; i < count; ++i) { zend_ast *child = children[i]; zend_string *child_name = !is_list ? ast_kind_child_name(ast_kind, i) : NULL; zval child_zv; if (ast_kind == ZEND_AST_STMT_LIST) { if (child != NULL && child->kind == ZEND_AST_STMT_LIST) { ast_fill_children_ht(ht, child, state); continue; } if (child == NULL) { continue; } } /* This AST_CATCH check should occur before ast_is_name() */ #if PHP_VERSION_ID < 70100 if (ast_kind == ZEND_AST_CATCH && i == 0) { /* Emulate PHP 7.1 format (name list) */ zval tmp; ast_create_virtual_node(&tmp, AST_NAME, child->attr, child, state); ast_create_virtual_node_ex( &child_zv, ZEND_AST_NAME_LIST, 0, zend_ast_get_lineno(child), state, 1, &tmp); } else #endif if (ast_is_name(child, ast, i)) { ast_name_to_zval(child, ast, &child_zv, i, state); } else if (child && child->kind == ZEND_AST_TYPE && (child->attr & ZEND_TYPE_NULLABLE)) { child->attr &= ~ZEND_TYPE_NULLABLE; ast_create_virtual_node(&child_zv, AST_NULLABLE_TYPE, 0, child, state); } else if (ast_kind == ZEND_AST_CLOSURE_USES) { ast_create_virtual_node(&child_zv, AST_CLOSURE_VAR, child->attr, child, state); } else if (ast_is_var_name(child, ast, i)) { ast_create_virtual_node(&child_zv, ZEND_AST_VAR, 0, child, state); } else if (ast_should_normalize_list(child, ast, i)) { if (child) { zval tmp; ast_to_zval(&tmp, child, state); ast_create_virtual_node_ex( &child_zv, ZEND_AST_STMT_LIST, 0, zend_ast_get_lineno(child), state, 1, &tmp); } else { ast_create_virtual_node_ex( &child_zv, ZEND_AST_STMT_LIST, 0, zend_ast_get_lineno(ast), state, 0); } } else if (state->version >= 60 && i == 1 && (ast_kind == ZEND_AST_FUNC_DECL || ast_kind == ZEND_AST_METHOD)) { /* Skip "uses" child, it is only relevant for closures */ continue; #if PHP_VERSION_ID >= 70400 } else if (i == 1 && ast_kind == ZEND_AST_ARROW_FUNC) { /* Skip "uses" child since it is always empty */ continue; #endif #if PHP_VERSION_ID >= 70100 } else if (ast_kind == ZEND_AST_LIST && child != NULL) { /* Emulate simple variable list */ ast_to_zval(&child_zv, child->child[0], state); #else } else if (ast_kind == ZEND_AST_ARRAY && ast->attr == ZEND_ARRAY_SYNTAX_LIST && child != NULL) { /* Emulate ARRAY_ELEM list */ zval ch0, ch1; ast_to_zval(&ch0, child, state); ZVAL_NULL(&ch1); ast_create_virtual_node_ex( &child_zv, ZEND_AST_ARRAY_ELEM, 0, zend_ast_get_lineno(child), state, 2, &ch0, &ch1); #endif } else { ast_to_zval(&child_zv, child, state); } if (child_name) { zend_hash_add_new(ht, child_name, &child_zv); } else { zend_hash_next_index_insert(ht, &child_zv); } } #if PHP_VERSION_ID < 70100 /* Emulate docComment on constants, which is not available in PHP 7.0 */ if (state->version >= 60 && ast_kind == ZEND_AST_CONST_ELEM) { zval tmp; ZVAL_NULL(&tmp); zend_hash_add_new(ht, AST_STR(str_docComment), &tmp); } #endif if (ast_kind_is_decl(ast_kind)) { zval id_zval; ZVAL_LONG(&id_zval, state->declIdCounter); state->declIdCounter++; zend_hash_add_new(ht, AST_STR(str___declId), &id_zval); } } static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state) { zval tmp_zv, children_zv; if (ast == NULL) { ZVAL_NULL(zv); return; } if (ast->kind == ZEND_AST_ZVAL) { ZVAL_COPY(zv, zend_ast_get_zval(ast)); return; } switch (ast->kind) { #if PHP_VERSION_ID < 70400 case ZEND_AST_ASSIGN_OP: ast->attr = ast_assign_op_to_binary_op(ast->attr); break; #endif 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_COALESCE: ast->kind = ZEND_AST_BINARY_OP; ast->attr = AST_BINARY_COALESCE; 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; #if PHP_VERSION_ID >= 70400 case ZEND_AST_PROP_GROUP: if (state->version < 70) { // In versions less than 70, just omit property type information entirely. // ast->child is [type_ast, prop_ast] ast_to_zval(zv, ast->child[1], state); // The property visibility is on the AST_PROP_GROUP node. // Add it to the AST_PROP_DECL node for old ast_update_property_long(zv, AST_STR(str_flags), ast->attr, AST_CACHE_SLOT_FLAGS); return; } break; case ZEND_AST_ASSIGN_COALESCE: ast->kind = ZEND_AST_ASSIGN_OP; ast->attr = AST_BINARY_COALESCE; break; case ZEND_AST_CLASS_NAME: if (state->version < 70) { zval name_zval; ast_to_zval(&name_zval, ast->child[0], state); zval class_name_zval; ast_create_virtual_node_ex( &class_name_zval, AST_NAME, ast->child[0]->attr, zend_ast_get_lineno(ast), state, 1, &name_zval); zval const_zval; ZVAL_STR_COPY(&const_zval, AST_STR(str_class)); ast_create_virtual_node_ex( zv, ZEND_AST_CLASS_CONST, 0, zend_ast_get_lineno(ast), state, 2, &class_name_zval, &const_zval); return; } break; #ifdef ZEND_PARENTHESIZED_CONCAT case ZEND_AST_BINARY_OP: if (ast->attr == ZEND_PARENTHESIZED_CONCAT) { ast->attr = ZEND_CONCAT; } break; #endif #else case ZEND_AST_CLASS_CONST: if (state->version >= 70) { // Convert to an AST_CLASS_NAME instead. This is the opposite of the work done in the ZEND_AST_CLASS_NAME case. zend_ast *const_name_ast = ast->child[1]; zend_string *str = zend_ast_get_str(const_name_ast); if (zend_string_equals_ci(AST_STR(str_class), str)) { zend_ast *class_name_ast = ast->child[0]; zval class_name_zval; if (class_name_ast->kind == ZEND_AST_ZVAL) { // e.g. Foo::class zval class_name_raw_zval; ZVAL_COPY(&class_name_raw_zval, zend_ast_get_zval(class_name_ast)); ast_create_virtual_node_ex( &class_name_zval, AST_NAME, class_name_ast->attr, zend_ast_get_lineno(class_name_ast), state, 1, &class_name_raw_zval); } else { // e.g. []::class (not a parse error, but a runtime error) ast_to_zval(&class_name_zval, class_name_ast, state); } ast_create_virtual_node_ex( zv, ZEND_AST_CLASS_NAME, 0, zend_ast_get_lineno(ast), state, 1, &class_name_zval); return; } } break; #endif } #if PHP_VERSION_ID < 70100 /* Normalize to PHP 7.1 format */ if (ast->kind == ZEND_AST_LIST) { ast->kind = ZEND_AST_ARRAY; ast->attr = ZEND_ARRAY_SYNTAX_LIST; } #endif object_init_ex(zv, ast_node_ce); ast_update_property_long(zv, AST_STR(str_kind), ast->kind, AST_CACHE_SLOT_KIND); ast_update_property_long(zv, AST_STR(str_lineno), zend_ast_get_lineno(ast), AST_CACHE_SLOT_LINENO); array_init(&children_zv); Z_DELREF(children_zv); ast_update_property(zv, AST_STR(str_children), &children_zv, AST_CACHE_SLOT_CHILDREN); if (ast_kind_is_decl(ast->kind)) { zend_ast_decl *decl = (zend_ast_decl *) ast; ast_update_property_long(zv, AST_STR(str_flags), decl->flags, AST_CACHE_SLOT_FLAGS); ast_update_property_long(zv, AST_STR(str_endLineno), decl->end_lineno, NULL); if (decl->name) { ZVAL_STR(&tmp_zv, decl->name); } else { ZVAL_NULL(&tmp_zv); } Z_TRY_ADDREF(tmp_zv); zend_hash_add_new(Z_ARRVAL(children_zv), AST_STR(str_name), &tmp_zv); if (decl->doc_comment) { ZVAL_STR(&tmp_zv, decl->doc_comment); } else { ZVAL_NULL(&tmp_zv); } Z_TRY_ADDREF(tmp_zv); zend_hash_add_new(Z_ARRVAL(children_zv), AST_STR(str_docComment), &tmp_zv); } else { #if PHP_VERSION_ID < 70100 if (ast->kind == ZEND_AST_CLASS_CONST_DECL) { ast->attr = ZEND_ACC_PUBLIC; } #endif ast_update_property_long(zv, AST_STR(str_flags), ast->attr, AST_CACHE_SLOT_FLAGS); } ast_fill_children_ht(Z_ARRVAL(children_zv), ast, state); #if PHP_VERSION_ID < 70400 if (ast->kind == ZEND_AST_PROP_DECL && state->version >= 70) { zval type_zval; zval prop_group_zval = *zv; ZVAL_NULL(&type_zval); // For version 70, create an AST_PROP_GROUP wrapping the created AST_PROP_DECL. ast_create_virtual_node_ex( zv, ZEND_AST_PROP_GROUP, ast->attr, zend_ast_get_lineno(ast), state, 2, &type_zval, &prop_group_zval); ast_update_property_long(&prop_group_zval, AST_STR(str_flags), 0, AST_CACHE_SLOT_FLAGS); } #endif } static const zend_long versions[] = {50, 60, 70}; static const size_t versions_count = sizeof(versions)/sizeof(versions[0]); static inline zend_bool ast_version_deprecated(zend_long version) { /* Currently no deprecated versions */ return 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 inline zend_bool ast_version_known(zend_long version) { size_t i; for (i = 0; i < versions_count; ++i) { if (version == versions[i]) { return 1; } } return 0; } static int ast_check_version(zend_long version) { zend_string *version_info; if (ast_version_known(version)) { if (ast_version_deprecated(version)) { php_error_docref(NULL, E_DEPRECATED, "Version " ZEND_LONG_FMT " is deprecated", version); } 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; ast_state_info_t state; 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) { /* php_stream_copy_to_mem will return NULL if the file is empty, strangely. */ code = ZSTR_EMPTY_ALLOC(); } ast = get_ast(code, &arena, filename->val); if (!ast) { zend_string_free(code); return; } state.version = version; state.declIdCounter = 0; ast_to_zval(return_value, ast, &state); 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; ast_state_info_t state; 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; } state.version = version; state.declIdCounter = 0; ast_to_zval(return_value, ast, &state); 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 " ZEND_LONG_FMT, 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)); } static inline const ast_flag_info *ast_get_flag_info(uint16_t ast_kind) { size_t i, flag_info_count = sizeof(flag_info)/sizeof(ast_flag_info); for (i = 0; i < flag_info_count; i++) { const ast_flag_info *info = &flag_info[i]; if (info->ast_kind == ast_kind) { return info; } } return NULL; } static void ast_build_metadata(zval *result) { size_t i; array_init(result); for (i = 0; i < ast_kinds_count; i++) { zend_ast_kind kind = ast_kinds[i]; const ast_flag_info *flag_info = ast_get_flag_info(kind); zval info_zv, tmp_zv; object_init_ex(&info_zv, ast_metadata_ce); /* kind */ ast_update_property_long(&info_zv, AST_STR(str_kind), kind, NULL); /* name */ ZVAL_STRING(&tmp_zv, ast_kind_to_name(kind)); Z_TRY_DELREF(tmp_zv); ast_update_property(&info_zv, AST_STR(str_name), &tmp_zv, NULL); /* flags */ array_init(&tmp_zv); if (flag_info) { const char **flag; for (flag = flag_info->flags; *flag; flag++) { add_next_index_string(&tmp_zv, *flag); } } Z_TRY_DELREF(tmp_zv); ast_update_property(&info_zv, AST_STR(str_flags), &tmp_zv, NULL); /* flagsCombinable */ ZVAL_BOOL(&tmp_zv, flag_info && flag_info->combinable); ast_update_property(&info_zv, AST_STR(str_flagsCombinable), &tmp_zv, NULL); add_index_zval(result, kind, &info_zv); } } PHP_FUNCTION(get_metadata) { if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "") == FAILURE) { return; } if (Z_ISUNDEF(AST_G(metadata))) { ast_build_metadata(&AST_G(metadata)); } ZVAL_COPY(return_value, &AST_G(metadata)); } PHP_FUNCTION(get_supported_versions) { zend_bool exclude_deprecated = 0; size_t i; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|b", &exclude_deprecated) == FAILURE) { return; } array_init(return_value); for (i = 0; i < versions_count; i++) { zend_long version = versions[i]; if (!exclude_deprecated || !ast_version_deprecated(version)) { add_next_index_long(return_value, version); } } } PHP_METHOD(ast_Node, __construct) { int num_args = ZEND_NUM_ARGS(); if (num_args == 0) { /* If arguments aren't passed, leave them as their default values. */ return; } zend_long kind; zend_long flags; zval *children; zend_long lineno; zend_bool kindNull, flagsNull, linenoNull; ZEND_PARSE_PARAMETERS_START(0, 4) Z_PARAM_OPTIONAL Z_PARAM_LONG_EX(kind, kindNull, 1, 0) Z_PARAM_LONG_EX(flags, flagsNull, 1, 0) Z_PARAM_ARRAY_EX(children, 1, 0) Z_PARAM_LONG_EX(lineno, linenoNull, 1, 0) ZEND_PARSE_PARAMETERS_END(); zval *zv = getThis(); switch (num_args) { case 4: if (!linenoNull) { ast_update_property_long(zv, AST_STR(str_lineno), lineno, AST_CACHE_SLOT_LINENO); } /* break missing intentionally */ case 3: if (children != NULL) { ast_update_property(zv, AST_STR(str_children), children, AST_CACHE_SLOT_CHILDREN); } /* break missing intentionally */ case 2: if (!flagsNull) { ast_update_property_long(zv, AST_STR(str_flags), flags, AST_CACHE_SLOT_FLAGS); } /* break missing intentionally */ case 1: if (!kindNull) { ast_update_property_long(zv, AST_STR(str_kind), kind, AST_CACHE_SLOT_KIND); } /* break missing intentionally */ case 0: break; } } ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_file, 0, 0, 2) ZEND_ARG_INFO(0, filename) ZEND_ARG_INFO(0, version) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_code, 0, 0, 2) 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() ZEND_BEGIN_ARG_INFO_EX(arginfo_get_metadata, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_get_supported_versions, 0, 0, 0) ZEND_ARG_INFO(0, exclude_deprecated) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_node_construct, 0, 0, 0) ZEND_ARG_INFO(0, kind) ZEND_ARG_INFO(0, flags) ZEND_ARG_ARRAY_INFO(0, children, 1) ZEND_ARG_INFO(0, lineno) 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) ZEND_NS_FE("ast", get_metadata, arginfo_get_metadata) ZEND_NS_FE("ast", get_supported_versions, arginfo_get_supported_versions) PHP_FE_END }; const zend_function_entry ast_node_functions[] = { PHP_ME(ast_Node, __construct, arginfo_node_construct, ZEND_ACC_PUBLIC) PHP_FE_END }; PHP_MINFO_FUNCTION(ast) { zend_string *info = ast_version_info(); php_info_print_table_start(); php_info_print_table_row(2, "ast support", "enabled"); php_info_print_table_row(2, "extension version", PHP_AST_VERSION); php_info_print_table_row(2, "AST version", ZSTR_VAL(info)); php_info_print_table_end(); zend_string_release(info); } PHP_RINIT_FUNCTION(ast) { memset(AST_G(cache_slots), 0, sizeof(void *) * AST_NUM_CACHE_SLOTS); ZVAL_UNDEF(&AST_G(metadata)); return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(ast) { zval_ptr_dtor(&AST_G(metadata)); return SUCCESS; } PHP_MINIT_FUNCTION(ast) { zend_class_entry tmp_ce; zval zv_null; ZVAL_NULL(&zv_null); #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("FUNC_RETURNS_REF", ZEND_ACC_RETURN_REFERENCE); ast_register_flag_constant("FUNC_GENERATOR", ZEND_ACC_GENERATOR); ast_register_flag_constant("ARRAY_ELEM_REF", 1); ast_register_flag_constant("CLOSURE_USE_REF", ZEND_BIND_REF); 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_FALSE", IS_FALSE); 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("TYPE_VOID", IS_VOID); ast_register_flag_constant("TYPE_ITERABLE", IS_ITERABLE); 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("BINARY_COALESCE", AST_BINARY_COALESCE); 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); #if PHP_VERSION_ID >= 70200 ast_register_flag_constant("USE_NORMAL", ZEND_SYMBOL_CLASS); ast_register_flag_constant("USE_FUNCTION", ZEND_SYMBOL_FUNCTION); ast_register_flag_constant("USE_CONST", ZEND_SYMBOL_CONST); #else ast_register_flag_constant("USE_NORMAL", T_CLASS); ast_register_flag_constant("USE_FUNCTION", T_FUNCTION); ast_register_flag_constant("USE_CONST", T_CONST); #endif 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); ast_register_flag_constant("ARRAY_SYNTAX_LIST", ZEND_ARRAY_SYNTAX_LIST); ast_register_flag_constant("ARRAY_SYNTAX_LONG", ZEND_ARRAY_SYNTAX_LONG); ast_register_flag_constant("ARRAY_SYNTAX_SHORT", ZEND_ARRAY_SYNTAX_SHORT); ast_register_flag_constant("DIM_ALTERNATIVE_SYNTAX", ZEND_DIM_ALTERNATIVE_SYNTAX); ast_register_flag_constant("PARENTHESIZED_CONDITIONAL", ZEND_PARENTHESIZED_CONDITIONAL); INIT_CLASS_ENTRY(tmp_ce, "ast\\Node", ast_node_functions); ast_node_ce = zend_register_internal_class(&tmp_ce); ast_declare_property(ast_node_ce, AST_STR(str_kind), &zv_null); ast_declare_property(ast_node_ce, AST_STR(str_flags), &zv_null); ast_declare_property(ast_node_ce, AST_STR(str_lineno), &zv_null); ast_declare_property(ast_node_ce, AST_STR(str_children), &zv_null); INIT_CLASS_ENTRY(tmp_ce, "ast\\Metadata", NULL); ast_metadata_ce = zend_register_internal_class(&tmp_ce); ast_declare_property(ast_metadata_ce, AST_STR(str_kind), &zv_null); ast_declare_property(ast_metadata_ce, AST_STR(str_name), &zv_null); ast_declare_property(ast_metadata_ce, AST_STR(str_flags), &zv_null); ast_declare_property(ast_metadata_ce, AST_STR(str_flagsCombinable), &zv_null); 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), PHP_RSHUTDOWN(ast), 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 ast-1.0.5/ast_data.c0000664000175000017500000006405313567500533013363 0ustar tysontyson#include "php_ast.h" const zend_ast_kind ast_kinds[] = { 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_TYPE_UNION, AST_NAME, AST_CLOSURE_VAR, AST_NULLABLE_TYPE, ZEND_AST_FUNC_DECL, ZEND_AST_CLOSURE, ZEND_AST_METHOD, ZEND_AST_ARROW_FUNC, ZEND_AST_CLASS, ZEND_AST_MAGIC_CONST, ZEND_AST_TYPE, ZEND_AST_VAR, ZEND_AST_CONST, ZEND_AST_UNPACK, ZEND_AST_CAST, ZEND_AST_EMPTY, ZEND_AST_ISSET, 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_CLASS_NAME, 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_ARRAY_ELEM, ZEND_AST_NEW, ZEND_AST_INSTANCEOF, ZEND_AST_YIELD, 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_PROP_ELEM, ZEND_AST_PROP_GROUP, 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_FOR, ZEND_AST_FOREACH, }; const size_t ast_kinds_count = sizeof(ast_kinds) / sizeof(ast_kinds[0]); const char *ast_kind_to_name(zend_ast_kind kind) { switch (kind) { 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_TYPE_UNION: return "AST_TYPE_UNION"; case AST_NAME: return "AST_NAME"; case AST_CLOSURE_VAR: return "AST_CLOSURE_VAR"; case AST_NULLABLE_TYPE: return "AST_NULLABLE_TYPE"; 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_ARROW_FUNC: return "AST_ARROW_FUNC"; case ZEND_AST_CLASS: return "AST_CLASS"; 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_CAST: return "AST_CAST"; case ZEND_AST_EMPTY: return "AST_EMPTY"; case ZEND_AST_ISSET: return "AST_ISSET"; 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_CLASS_NAME: return "AST_CLASS_NAME"; 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_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_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_PROP_ELEM: return "AST_PROP_ELEM"; case ZEND_AST_PROP_GROUP: return "AST_PROP_GROUP"; 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_FOR: return "AST_FOR"; case ZEND_AST_FOREACH: return "AST_FOREACH"; } 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 AST_NULLABLE_TYPE: switch (child) { case 0: return AST_STR(str_type); } 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_ARROW_FUNC: 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_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_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_CLASS_NAME: switch (child) { case 0: return AST_STR(str_class); } 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_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_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); case 2: return AST_STR(str_docComment); } return NULL; case ZEND_AST_PROP_GROUP: switch (child) { case 0: return AST_STR(str_type); case 1: return AST_STR(str_props); } return NULL; case ZEND_AST_CONST_ELEM: switch (child) { case 0: return AST_STR(str_name); case 1: return AST_STR(str_value); case 2: return AST_STR(str_docComment); } 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_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_TYPE_UNION", ZEND_AST_TYPE_UNION, 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); REGISTER_NS_LONG_CONSTANT("ast", "AST_NULLABLE_TYPE", AST_NULLABLE_TYPE, CONST_CS | CONST_PERSISTENT); 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_ARROW_FUNC", ZEND_AST_ARROW_FUNC, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS", ZEND_AST_CLASS, 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_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_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_CLASS_NAME", ZEND_AST_CLASS_NAME, 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_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_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_PROP_ELEM", ZEND_AST_PROP_ELEM, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_PROP_GROUP", ZEND_AST_PROP_GROUP, 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_FOR", ZEND_AST_FOR, CONST_CS | CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("ast", "AST_FOREACH", ZEND_AST_FOREACH, CONST_CS | CONST_PERSISTENT); } ast-1.0.5/ast_str_defs.h0000664000175000017500000000125413567500533014262 0ustar tysontyson#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(__declId) \ X(flagsCombinable) \ X(type) \ X(params) \ X(uses) \ X(stmts) \ X(returnType) \ X(extends) \ X(implements) \ X(expr) \ X(var) \ X(offset) \ X(label) \ X(depth) \ X(class) \ X(dim) \ X(prop) \ X(args) \ X(const) \ X(left) \ X(right) \ X(value) \ X(key) \ X(default) \ X(cond) \ X(declares) \ X(props) \ X(traits) \ X(adaptations) \ X(method) \ X(insteadof) \ X(alias) \ X(prefix) \ X(true) \ X(false) \ X(try) \ X(catches) \ X(finally) \ X(init) \ X(loop) \ #endif ast-1.0.5/ast_stub.php0000664000175000017500000001751413567500533013774 0ustar tysontyson * @author Nikita Popov */ // AST KIND CONSTANTS namespace ast; const AST_ARG_LIST = 128; const AST_LIST = 255; const AST_ARRAY = 129; const AST_ENCAPS_LIST = 130; const AST_EXPR_LIST = 131; const AST_STMT_LIST = 132; const AST_IF = 133; const AST_SWITCH_LIST = 134; const AST_CATCH_LIST = 135; const AST_PARAM_LIST = 136; const AST_CLOSURE_USES = 137; const AST_PROP_DECL = 138; const AST_CONST_DECL = 139; const AST_CLASS_CONST_DECL = 140; const AST_NAME_LIST = 141; const AST_TRAIT_ADAPTATIONS = 142; const AST_USE = 143; const AST_TYPE_UNION = 144; const AST_NAME = 2048; const AST_CLOSURE_VAR = 2049; const AST_NULLABLE_TYPE = 2050; const AST_FUNC_DECL = 67; const AST_CLOSURE = 68; const AST_METHOD = 69; const AST_ARROW_FUNC = 71; const AST_CLASS = 70; const AST_MAGIC_CONST = 0; const AST_TYPE = 1; const AST_VAR = 256; const AST_CONST = 257; const AST_UNPACK = 258; const AST_CAST = 261; const AST_EMPTY = 262; const AST_ISSET = 263; const AST_SHELL_EXEC = 265; const AST_CLONE = 266; const AST_EXIT = 267; const AST_PRINT = 268; const AST_INCLUDE_OR_EVAL = 269; const AST_UNARY_OP = 270; const AST_PRE_INC = 271; const AST_PRE_DEC = 272; const AST_POST_INC = 273; const AST_POST_DEC = 274; const AST_YIELD_FROM = 275; const AST_GLOBAL = 277; const AST_UNSET = 278; const AST_RETURN = 279; const AST_LABEL = 280; const AST_REF = 281; const AST_HALT_COMPILER = 282; const AST_ECHO = 283; const AST_THROW = 284; const AST_GOTO = 285; const AST_BREAK = 286; const AST_CONTINUE = 287; const AST_CLASS_NAME = 276; const AST_DIM = 512; const AST_PROP = 513; const AST_STATIC_PROP = 514; const AST_CALL = 515; const AST_CLASS_CONST = 516; const AST_ASSIGN = 517; const AST_ASSIGN_REF = 518; const AST_ASSIGN_OP = 519; const AST_BINARY_OP = 520; const AST_ARRAY_ELEM = 525; const AST_NEW = 526; const AST_INSTANCEOF = 527; const AST_YIELD = 528; const AST_STATIC = 531; const AST_WHILE = 532; const AST_DO_WHILE = 533; const AST_IF_ELEM = 534; const AST_SWITCH = 535; const AST_SWITCH_CASE = 536; const AST_DECLARE = 537; const AST_PROP_ELEM = 774; const AST_PROP_GROUP = 545; const AST_CONST_ELEM = 775; const AST_USE_TRAIT = 538; const AST_TRAIT_PRECEDENCE = 539; const AST_METHOD_REFERENCE = 540; const AST_NAMESPACE = 541; const AST_USE_ELEM = 542; const AST_TRAIT_ALIAS = 543; const AST_GROUP_USE = 544; const AST_METHOD_CALL = 768; const AST_STATIC_CALL = 769; const AST_CONDITIONAL = 770; const AST_TRY = 771; const AST_CATCH = 772; const AST_PARAM = 773; const AST_FOR = 1024; const AST_FOREACH = 1025; // END AST KIND CONSTANTS // AST FLAG CONSTANTS namespace ast\flags; const NAME_FQ = 0; const NAME_NOT_FQ = 1; const NAME_RELATIVE = 2; const MODIFIER_PUBLIC = 1; const MODIFIER_PROTECTED = 2; const MODIFIER_PRIVATE = 4; const MODIFIER_STATIC = 16; const MODIFIER_ABSTRACT = 64; const MODIFIER_FINAL = 32; const RETURNS_REF = 4096; const FUNC_RETURNS_REF = 4096; const FUNC_GENERATOR = 16777216; const ARRAY_ELEM_REF = 1; const CLOSURE_USE_REF = 1; const CLASS_ABSTRACT = 64; const CLASS_FINAL = 32; const CLASS_TRAIT = 2; const CLASS_INTERFACE = 1; const CLASS_ANONYMOUS = 4; const PARAM_REF = 1; const PARAM_VARIADIC = 2; const TYPE_NULL = 1; const TYPE_FALSE = 2; const TYPE_BOOL = 18; const TYPE_LONG = 4; const TYPE_DOUBLE = 5; const TYPE_STRING = 6; const TYPE_ARRAY = 7; const TYPE_OBJECT = 8; const TYPE_CALLABLE = 12; const TYPE_VOID = 14; const TYPE_ITERABLE = 13; const UNARY_BOOL_NOT = 14; const UNARY_BITWISE_NOT = 13; const UNARY_SILENCE = 260; const UNARY_PLUS = 261; const UNARY_MINUS = 262; const BINARY_BOOL_AND = 259; const BINARY_BOOL_OR = 258; const BINARY_BOOL_XOR = 15; const BINARY_BITWISE_OR = 9; const BINARY_BITWISE_AND = 10; const BINARY_BITWISE_XOR = 11; const BINARY_CONCAT = 8; const BINARY_ADD = 1; const BINARY_SUB = 2; const BINARY_MUL = 3; const BINARY_DIV = 4; const BINARY_MOD = 5; const BINARY_POW = 12; const BINARY_SHIFT_LEFT = 6; const BINARY_SHIFT_RIGHT = 7; const BINARY_IS_IDENTICAL = 16; const BINARY_IS_NOT_IDENTICAL = 17; const BINARY_IS_EQUAL = 18; const BINARY_IS_NOT_EQUAL = 19; const BINARY_IS_SMALLER = 20; const BINARY_IS_SMALLER_OR_EQUAL = 21; const BINARY_IS_GREATER = 256; const BINARY_IS_GREATER_OR_EQUAL = 257; const BINARY_SPACESHIP = 170; const BINARY_COALESCE = 260; const EXEC_EVAL = 1; const EXEC_INCLUDE = 2; const EXEC_INCLUDE_ONCE = 4; const EXEC_REQUIRE = 8; const EXEC_REQUIRE_ONCE = 16; const USE_NORMAL = 1; const USE_FUNCTION = 2; const USE_CONST = 4; const MAGIC_LINE = 373; const MAGIC_FILE = 374; const MAGIC_DIR = 375; const MAGIC_NAMESPACE = 392; const MAGIC_FUNCTION = 379; const MAGIC_METHOD = 378; const MAGIC_CLASS = 376; const MAGIC_TRAIT = 377; const ARRAY_SYNTAX_LIST = 1; const ARRAY_SYNTAX_LONG = 2; const ARRAY_SYNTAX_SHORT = 3; const DIM_ALTERNATIVE_SYNTAX = 2; const PARENTHESIZED_CONDITIONAL = 1; // END AST FLAG CONSTANTS namespace ast; /** * Parses code file and returns AST root node. * * @param string $filename Code file to parse * @param int $version AST version * @return Node Root node of AST * * @see https://github.com/nikic/php-ast for version information */ function parse_file($filename, $version) { } /** * Parses code string and returns AST root node. * * @param string $code Code string to parse * @param int $version AST version * @param string $filename Optional filename for use in parse errors * @return Node Root node of AST * * @see https://github.com/nikic/php-ast for version information */ function parse_code($code, $version, $filename = "string code") { } /** * @param int $kind AST_* constant value defining the kind of an AST node * @return string String representation of AST kind value */ function get_kind_name($kind) { } /** * @param int $kind AST_* constant value defining the kind of an AST node * @return bool Returns true if AST kind uses flags */ function kind_uses_flags($kind) { } /** * Provides metadata for the AST kinds. * * The returned array is a map from AST kind to a Metadata object. * * @return Metadata[] Metadata about AST kinds */ function get_metadata() { } /** * Returns currently supported AST versions. * * @param bool $exclude_deprecated Whether to exclude deprecated versions * @return int[] Array of supported AST versions */ function get_supported_versions($exclude_deprecated = false) { } /** * This class describes a single node in a PHP AST. */ class Node { /** @var int AST Node Kind. Values are one of ast\AST_* constants. */ public $kind; /** * @var int AST Flags. * Certain node kinds have flags that can be set. * These will be a bitfield of ast\flags\* constants. */ public $flags; /** @var int Line the node starts in */ public $lineno; /** @var array Child nodes (may be empty) */ public $children; /** * A constructor which validates data types but not the values themselves. * For backwards compatibility reasons, all values are optional and properties default to null */ public function __construct(int $kind = null, int $flags = null, array $children = null, int $lineno = null) { $this->kind = $kind; $this->flags = $flags; $this->children = $children; $this->lineno = $lineno; } } /** * Metadata entry for a single AST kind, as returned by ast\get_metadata(). */ class Metadata { /** @var int AST node kind (one of the ast\AST_* constants). */ public $kind; /** @var string Name of the node kind (e.g. "AST_NAME"). */ public $name; /** * @var string[] Array of supported flags. The flags are given as names of constants, such as * "ast\flags\TYPE_STRING". */ public $flags; /** * @var bool Whether the flags are exclusive or combinable. Exclusive flags should be checked * using ===, while combinable flags should be checked using &. */ public $flagsCombinable; } ast-1.0.5/LICENSE0000644000175000017500000000272313567500533012436 0ustar tysontysonCopyright (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. ast-1.0.5/php_ast.h0000664000175000017500000000400213567500533013232 0ustar tysontyson#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 "1.0.5" #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 // PHP 7.4 added a 3rd cache slot for property_info // and expects cache_slot[2] to be null. #define AST_NUM_CACHE_SLOTS (3 * 4) ZEND_BEGIN_MODULE_GLOBALS(ast) void *cache_slots[AST_NUM_CACHE_SLOTS]; zval metadata; ZEND_END_MODULE_GLOBALS(ast) ZEND_EXTERN_MODULE_GLOBALS(ast) #define AST_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(ast, v) typedef struct _ast_str_globals { #define X(str) zend_string *str_ ## str; AST_STR_DEFS #undef X } ast_str_globals; extern ast_str_globals str_globals; #define AST_STR(str) str_globals.str /* Custom ast kind for names */ #define AST_NAME 2048 #define AST_CLOSURE_VAR 2049 #define AST_NULLABLE_TYPE 2050 // 544 is already taken by ZEND_AST_GROUP_USE #if PHP_VERSION_ID < 70400 // NOTE: The first hex digit is the number of child nodes a given kind has # define ZEND_AST_CLASS_NAME 0x1ff # define ZEND_AST_PROP_GROUP 0x2ff # define ZEND_AST_ARROW_FUNC 0x5ff #endif #if PHP_VERSION_ID < 80000 /* NOTE: For list nodes, the first set bit is 0x80 */ # define ZEND_AST_TYPE_UNION ((1 << (ZEND_AST_IS_LIST_SHIFT + 1)) - 2) #endif /* Pretend it still exists */ #if PHP_VERSION_ID >= 70100 # define ZEND_AST_LIST ((1 << (ZEND_AST_IS_LIST_SHIFT + 1)) - 1) #endif 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 */ ast-1.0.5/README.md0000664000175000017500000004463613567500533012723 0ustar tysontysonphp-ast ======= This extension exposes the abstract syntax tree generated by PHP 7. **This is the documentation for version 1.0.x. See also [documentation for version 0.1.x][v0_1_x].** Table of Contents ----------------- * [Installation](#installation) * [API overview](#api-overview) * [Basic usage](#basic-usage) * [Example](#example) * [Metadata](#metadata) * [Flags](#flags) * [AST node kinds](#ast-node-kinds) * [AST versioning](#ast-versioning) * [Differences to PHP-Parser](#differences-to-php-parser) Installation ------------ **Windows**: Download a [prebuilt Windows DLL](http://windows.php.net/downloads/pecl/releases/ast/) and move it into the `ext/` directory of your PHP installation. Furthermore add `extension=php_ast.dll` to your `php.ini` file. **Unix (PECL)**: Run `pecl install ast` and add `extension=ast.so` to your `php.ini`. **Unix (Compile)**: Compile and install the extension as follows. ```sh phpize ./configure make sudo make install ``` Additionally add `extension=ast.so` to your `php.ini` file. API overview ------------ Defines: * `ast\Node` class * `ast\Metadata` class * `ast\AST_*` kind constants * `ast\flags\*` flag constants * `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)` * `ast\get_metadata()` * `ast\get_supported_versions(bool $exclude_deprecated = false)` Basic 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 50. ```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(2) ["children"]=> array(2) { ["var"]=> object(ast\Node)#3 (4) { ["kind"]=> int(256) ["flags"]=> int(0) ["lineno"]=> int(2) ["children"]=> array(1) { ["name"]=> string(3) "var" } } ["expr"]=> 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_NAME (exclusive) ast\flags\NAME_FQ (= 0) // example: \Foo\Bar ast\flags\NAME_NOT_FQ // example: Foo\Bar ast\flags\NAME_RELATIVE // example: namespace\Foo\Bar // Used by ast\AST_METHOD, ast\AST_PROP_DECL, ast\AST_CLASS_CONST_DECL, // ast\AST_PROP_GROUP and ast\AST_TRAIT_ALIAS (combinable) ast\flags\MODIFIER_PUBLIC ast\flags\MODIFIER_PROTECTED ast\flags\MODIFIER_PRIVATE ast\flags\MODIFIER_STATIC ast\flags\MODIFIER_ABSTRACT ast\flags\MODIFIER_FINAL // Used by ast\AST_CLOSURE, ast\AST_ARROW_FUNC (combinable) ast\flags\MODIFIER_STATIC // Used by ast\AST_FUNC_DECL, ast\AST_METHOD, ast\AST_CLOSURE, ast\AST_ARROW_FUNC (combinable) ast\flags\FUNC_RETURNS_REF // legacy alias: ast\flags\RETURNS_REF ast\flags\FUNC_GENERATOR // used only in PHP >= 7.1 // Used by ast\AST_CLOSURE_VAR ast\flags\CLOSURE_USE_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 (cominable) ast\flags\PARAM_REF ast\flags\PARAM_VARIADIC // Used by ast\AST_TYPE (exclusive) ast\flags\TYPE_ARRAY ast\flags\TYPE_CALLABLE ast\flags\TYPE_VOID ast\flags\TYPE_BOOL ast\flags\TYPE_LONG ast\flags\TYPE_DOUBLE ast\flags\TYPE_STRING ast\flags\TYPE_ITERABLE ast\flags\TYPE_OBJECT // 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 ast\flags\UNARY_PLUS ast\flags\UNARY_SILENCE // Used by ast\AST_BINARY_OP and ast\AST_ASSIGN_OP (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 ast\flags\BINARY_COALESCE // Used by ast\AST_BINARY_OP (exclusive) ast\flags\BINARY_BOOL_AND ast\flags\BINARY_BOOL_OR 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 ast\flags\BINARY_IS_GREATER_OR_EQUAL ast\flags\BINARY_SPACESHIP // 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 // Used by ast\AST_ARRAY (exclusive), since PHP 7.1 ast\flags\ARRAY_SYNTAX_SHORT ast\flags\ARRAY_SYNTAX_LONG ast\flags\ARRAY_SYNTAX_LIST // Used by ast\AST_ARRAY_ELEM (exclusive) ast\flags\ARRAY_ELEM_REF // Used by ast\AST_DIM (combinable), since PHP 7.4 ast\flags\DIM_ALTERNATIVE_SYNTAX // Used by ast\AST_CONDITIONAL (combinable), since PHP 7.4 ast\flags\PARENTHESIZED_CONDITIONAL ``` AST node kinds -------------- This section lists the AST node kinds that are supported and the names of their child nodes. ``` AST_ARRAY_ELEM: value, key AST_ARROW_FUNC: name, docComment, params, stmts, returnType AST_ASSIGN: var, expr AST_ASSIGN_OP: var, expr AST_ASSIGN_REF: var, expr AST_BINARY_OP: left, right AST_BREAK: depth AST_CALL: expr, args AST_CAST: expr AST_CATCH: class, var, stmts AST_CLASS: name, docComment, extends, implements, stmts AST_CLASS_CONST: class, const AST_CLASS_NAME: class // version 70+ AST_CLONE: expr AST_CLOSURE: name, docComment, params, uses, stmts, returnType AST_CLOSURE_VAR: name AST_CONDITIONAL: cond, true, false AST_CONST: name AST_CONST_ELEM: name, value, docComment AST_CONTINUE: depth AST_DECLARE: declares, stmts AST_DIM: expr, dim AST_DO_WHILE: stmts, cond AST_ECHO: expr AST_EMPTY: expr AST_EXIT: expr AST_FOR: init, cond, loop, stmts AST_FOREACH: expr, value, key, stmts AST_FUNC_DECL: name, docComment, params, stmts, returnType uses // prior to version 60 AST_GLOBAL: var AST_GOTO: label AST_GROUP_USE: prefix, uses AST_HALT_COMPILER: offset AST_IF_ELEM: cond, stmts AST_INCLUDE_OR_EVAL: expr AST_INSTANCEOF: expr, class AST_ISSET: var AST_LABEL: name AST_MAGIC_CONST: AST_METHOD: name, docComment, params, stmts, returnType uses // prior to version 60 AST_METHOD_CALL: expr, method, args AST_METHOD_REFERENCE: class, method AST_NAME: name AST_NAMESPACE: name, stmts AST_NEW: class, args AST_NULLABLE_TYPE: type // Used only since PHP 7.1 AST_PARAM: type, name, default AST_POST_DEC: var AST_POST_INC: var AST_PRE_DEC: var AST_PRE_INC: var AST_PRINT: expr AST_PROP: expr, prop AST_PROP_ELEM: name, default, docComment AST_PROP_GROUP: type, props // version 70+ AST_REF: var // only used in foreach ($a as &$v) AST_RETURN: expr AST_SHELL_EXEC: expr AST_STATIC: var, default AST_STATIC_CALL: class, method, args AST_STATIC_PROP: class, prop AST_SWITCH: cond, stmts AST_SWITCH_CASE: cond, stmts AST_THROW: expr AST_TRAIT_ALIAS: method, alias AST_TRAIT_PRECEDENCE: method, insteadof AST_TRY: try, catches, finally AST_TYPE: AST_UNARY_OP: expr AST_UNPACK: expr AST_UNSET: var AST_USE_ELEM: name, alias AST_USE_TRAIT: traits, adaptations AST_VAR: name AST_WHILE: cond, stmts AST_YIELD: value, key AST_YIELD_FROM: expr // List nodes (numerically indexed children): AST_ARG_LIST AST_ARRAY AST_CATCH_LIST AST_CLASS_CONST_DECL AST_CLOSURE_USES AST_CONST_DECL AST_ENCAPS_LIST // interpolated string: "foo$bar" AST_EXPR_LIST AST_IF AST_LIST AST_NAME_LIST AST_PARAM_LIST AST_PROP_DECL AST_STMT_LIST AST_SWITCH_LIST AST_TRAIT_ADAPTATIONS AST_USE AST_TYPE_UNION // php 8.0+ union types ``` AST Versioning -------------- The `ast\parse_code()` and `ast\parse_file()` functions each accept a required AST `$version` argument. The idea behind the AST version is that we may need to change the format of the AST to account for new features in newer PHP versions, or to improve it in other ways. Such changes will always be made under a new AST version, while previous formats continue to be supported for some time. Old AST versions may be deprecated and subsequently removed. However, AST versions will only be removed in conjunction with a version increase of the AST extension from 0.x to 0.(x+1). A list of currently supported versions is available through `ast\get_supported_versions()`. The function accepts a boolean argument that determines whether deprecated versions should be excluded. In the following the changes in the respective AST versions, as well as their current support state, are listed. ### 70 (current) Supported since 1.0.1 (2019-02-11). * `AST_PROP_GROUP` was added to support PHP 7.4's typed properties. The property visibility modifiers are now part of `AST_PROP_GROUP` instead of `AST_PROP_DECL`. Note that property group type information is only available with AST versions 70+. * `AST_CLASS_NAME` is created instead of `AST_CLASS_CONST` for `SomeClass::class`. ### 60 (stable) Supported since 0.1.7 (2018-10-06). * `AST_FUNC_DECL` and `AST_METHOD` no longer generate a `uses` child. Previously this child was always `null`. * `AST_CONST_ELEM` now always has a `docComment` child. Previously it was absent on PHP 7.0. On PHP 7.0 the value is always `null`. ### 50 (stable) Supported since 0.1.5 (2017-07-19). This is the oldest AST version available in 1.0.0. See the [0.1.x AST version changelog][v0_1_x_versions] for information on changes prior to this version. Differences to PHP-Parser ------------------------- Next to php-ast I also maintain the [PHP-Parser][php-parser] library, which has some overlap with this extension. This section summarizes the main differences between php-ast and PHP-Parser so you may decide which is preferable for your use-case. The primary difference is that php-ast is a PHP extension (written in C) which exports the AST internally used by PHP 7. PHP-Parser on the other hand is library written in PHP. This has a number of consequences: * php-ast is significantly faster than PHP-Parser, because the AST construction is implemented in C. * php-ast needs to be installed as an extension, on Linux either by compiling it manually or retrieving it from a package manager, on Windows by loading a DLL. PHP-Parser is installed as a Composer dependency. * php-ast only runs on PHP >= 7.0, as prior versions did not use an internal AST. PHP-Parser supports PHP >= 5.5. * php-ast may only parse code that is syntactically valid on the version of PHP it runs on. This means that it's not possible to parse code using features of newer versions (e.g. PHP 7.1 code while running on PHP 7.0). Similarly, it is not possible to parse code that is no longer syntactically valid on the used version (e.g. some PHP 5 code may no longer be parsed -- however most code will work). PHP-Parser supports parsing both newer and older (up to PHP 5.2) versions. * php-ast can only parse code which is syntactically valid, while PHP-Parser can provide a partial AST for code that contains errors (e.g., because it is currently being edited). * php-ast only provides the starting line number (and for declarations the ending line number) of nodes, because this is the only part that PHP itself stores. PHP-Parser provides precise file offsets. There are a number of differences in the AST representation and available support code: * The PHP-Parser library uses a separate class for every node type, with child nodes stored as type-annotated properties. php-ast uses one class for everything, with children stored as arrays. The former approach is friendlier to developers because it has very good IDE integration. The php-ast extension does not use separate classes, because registering hundreds of classes was judged a no-go for a bundled extension. * The PHP-Parser library contains various support code for working with the AST, while php-ast only handles AST construction. The reason for this is that implementing this support code in C is extremely complicated and there is little other benefit to implementing it in C. The main components that PHP-Parser offers that may be of interest are: * Node dumper (human readable representation): While the php-ast extension does not directly implement this, a `ast_dump` function is provided in the `util.php` file. * Pretty printer (converting the AST back to PHP code): This is not provided natively, but the [php-ast-reverter][php-ast-reverter] package implements this functionality. * Name resolution (resolving namespace prefixes and aliases): There is currently no standalone package for this. * AST traversal / visitation: There is currently no standalone package for this either, but implementing a recursive AST walk is easy. The [tolerant-php-parser-to-php-ast][tolerant-php-parser-to-php-ast] project can convert the AST produced by [tolerant-php-parser][tolerant-php-parser] (Another pure PHP parser library) into the format used by the php-ast extension. This can be used as a slow fallback in case the php-ast extension is not available. It may also be used to produce a partial php-ast output for code with syntax errors. [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-parser]: https://github.com/nikic/PHP-Parser [php-ast-reverter]: https://github.com/tpunt/php-ast-reverter [tolerant-php-parser]: https://github.com/Microsoft/tolerant-php-parser [tolerant-php-parser-to-php-ast]: https://github.com/tysonandre/tolerant-php-parser-to-php-ast [v0_1_x]: https://github.com/nikic/php-ast/tree/v0.1.x#php-ast [v0_1_x_versions]: https://github.com/nikic/php-ast/tree/v0.1.x#ast-versioning ast-1.0.5/php_ast.h0000664000175000017500000000400213567500533013232 0ustar tysontyson#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 "1.0.5" #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 // PHP 7.4 added a 3rd cache slot for property_info // and expects cache_slot[2] to be null. #define AST_NUM_CACHE_SLOTS (3 * 4) ZEND_BEGIN_MODULE_GLOBALS(ast) void *cache_slots[AST_NUM_CACHE_SLOTS]; zval metadata; ZEND_END_MODULE_GLOBALS(ast) ZEND_EXTERN_MODULE_GLOBALS(ast) #define AST_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(ast, v) typedef struct _ast_str_globals { #define X(str) zend_string *str_ ## str; AST_STR_DEFS #undef X } ast_str_globals; extern ast_str_globals str_globals; #define AST_STR(str) str_globals.str /* Custom ast kind for names */ #define AST_NAME 2048 #define AST_CLOSURE_VAR 2049 #define AST_NULLABLE_TYPE 2050 // 544 is already taken by ZEND_AST_GROUP_USE #if PHP_VERSION_ID < 70400 // NOTE: The first hex digit is the number of child nodes a given kind has # define ZEND_AST_CLASS_NAME 0x1ff # define ZEND_AST_PROP_GROUP 0x2ff # define ZEND_AST_ARROW_FUNC 0x5ff #endif #if PHP_VERSION_ID < 80000 /* NOTE: For list nodes, the first set bit is 0x80 */ # define ZEND_AST_TYPE_UNION ((1 << (ZEND_AST_IS_LIST_SHIFT + 1)) - 2) #endif /* Pretend it still exists */ #if PHP_VERSION_ID >= 70100 # define ZEND_AST_LIST ((1 << (ZEND_AST_IS_LIST_SHIFT + 1)) - 1) #endif 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 */