Skip to content

Commit ae71ecc

Browse files
TysonAndrenikic
authored andcommitted
Support AST_ARROW_FUNC, add tests
1 parent 0e7ef05 commit ae71ecc

File tree

7 files changed

+129
-2
lines changed

7 files changed

+129
-2
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,10 @@ ast\flags\MODIFIER_STATIC
236236
ast\flags\MODIFIER_ABSTRACT
237237
ast\flags\MODIFIER_FINAL
238238
239-
// Used by ast\AST_CLOSURE (combinable)
239+
// Used by ast\AST_CLOSURE, ast\AST_ARROW_FUNC (combinable)
240240
ast\flags\MODIFIER_STATIC
241241
242-
// Used by ast\AST_FUNC_DECL, ast\AST_METHOD, ast\AST_CLOSURE (combinable)
242+
// Used by ast\AST_FUNC_DECL, ast\AST_METHOD, ast\AST_CLOSURE, ast\AST_ARROW_FUNC (combinable)
243243
ast\flags\FUNC_RETURNS_REF // legacy alias: ast\flags\RETURNS_REF
244244
ast\flags\FUNC_GENERATOR // used only in PHP >= 7.1
245245
@@ -351,6 +351,7 @@ This section lists the AST node kinds that are supported and the names of their
351351

352352
```
353353
AST_ARRAY_ELEM: value, key
354+
AST_ARROW_FUNC: name, docComment, params, stmts, returnType
354355
AST_ASSIGN: var, expr
355356
AST_ASSIGN_OP: var, expr
356357
AST_ASSIGN_REF: var, expr

ast.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ static const ast_flag_info flag_info[] = {
252252
{ ZEND_AST_METHOD, 1, func_flags },
253253
{ ZEND_AST_FUNC_DECL, 1, func_flags },
254254
{ ZEND_AST_CLOSURE, 1, func_flags },
255+
{ ZEND_AST_ARROW_FUNC, 1, func_flags },
255256
{ ZEND_AST_PROP_DECL, 1, modifier_flags },
256257
{ ZEND_AST_PROP_GROUP, 1, modifier_flags },
257258
{ ZEND_AST_CLASS_CONST_DECL, 1, visibility_flags },
@@ -323,6 +324,9 @@ static inline zend_bool ast_kind_uses_attr(zend_ast_kind kind) {
323324

324325
static inline zend_bool ast_kind_is_decl(zend_ast_kind kind) {
325326
return kind == ZEND_AST_FUNC_DECL || kind == ZEND_AST_CLOSURE
327+
#if PHP_VERSION_ID >= 70400
328+
|| kind == ZEND_AST_ARROW_FUNC
329+
#endif
326330
|| kind == ZEND_AST_METHOD || kind == ZEND_AST_CLASS;
327331
}
328332

@@ -614,6 +618,11 @@ static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, ast_state_info_t
614618
&& (ast->kind == ZEND_AST_FUNC_DECL || ast->kind == ZEND_AST_METHOD)) {
615619
/* Skip "uses" child, it is only relevant for closures */
616620
continue;
621+
#if PHP_VERSION_ID >= 70400
622+
} else if (i == 1 && ast->kind == ZEND_AST_ARROW_FUNC) {
623+
/* Skip "uses" child since it is always empty */
624+
continue;
625+
#endif
617626
#if PHP_VERSION_ID >= 70100
618627
} else if (ast->kind == ZEND_AST_LIST && child != NULL) {
619628
/* Emulate simple variable list */

ast_data.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const zend_ast_kind ast_kinds[] = {
2424
ZEND_AST_FUNC_DECL,
2525
ZEND_AST_CLOSURE,
2626
ZEND_AST_METHOD,
27+
ZEND_AST_ARROW_FUNC,
2728
ZEND_AST_CLASS,
2829
ZEND_AST_MAGIC_CONST,
2930
ZEND_AST_TYPE,
@@ -123,6 +124,7 @@ const char *ast_kind_to_name(zend_ast_kind kind) {
123124
case ZEND_AST_FUNC_DECL: return "AST_FUNC_DECL";
124125
case ZEND_AST_CLOSURE: return "AST_CLOSURE";
125126
case ZEND_AST_METHOD: return "AST_METHOD";
127+
case ZEND_AST_ARROW_FUNC: return "AST_ARROW_FUNC";
126128
case ZEND_AST_CLASS: return "AST_CLASS";
127129
case ZEND_AST_MAGIC_CONST: return "AST_MAGIC_CONST";
128130
case ZEND_AST_TYPE: return "AST_TYPE";
@@ -239,6 +241,14 @@ zend_string *ast_kind_child_name(zend_ast_kind kind, uint32_t child) {
239241
case 3: return AST_STR(str_returnType);
240242
}
241243
return NULL;
244+
case ZEND_AST_ARROW_FUNC:
245+
switch (child) {
246+
case 0: return AST_STR(str_params);
247+
case 1: return AST_STR(str_uses);
248+
case 2: return AST_STR(str_stmts);
249+
case 3: return AST_STR(str_returnType);
250+
}
251+
return NULL;
242252
case ZEND_AST_CLASS:
243253
switch (child) {
244254
case 0: return AST_STR(str_extends);
@@ -664,6 +674,7 @@ void ast_register_kind_constants(INIT_FUNC_ARGS) {
664674
REGISTER_NS_LONG_CONSTANT("ast", "AST_FUNC_DECL", ZEND_AST_FUNC_DECL, CONST_CS | CONST_PERSISTENT);
665675
REGISTER_NS_LONG_CONSTANT("ast", "AST_CLOSURE", ZEND_AST_CLOSURE, CONST_CS | CONST_PERSISTENT);
666676
REGISTER_NS_LONG_CONSTANT("ast", "AST_METHOD", ZEND_AST_METHOD, CONST_CS | CONST_PERSISTENT);
677+
REGISTER_NS_LONG_CONSTANT("ast", "AST_ARROW_FUNC", ZEND_AST_ARROW_FUNC, CONST_CS | CONST_PERSISTENT);
667678
REGISTER_NS_LONG_CONSTANT("ast", "AST_CLASS", ZEND_AST_CLASS, CONST_CS | CONST_PERSISTENT);
668679
REGISTER_NS_LONG_CONSTANT("ast", "AST_MAGIC_CONST", ZEND_AST_MAGIC_CONST, CONST_CS | CONST_PERSISTENT);
669680
REGISTER_NS_LONG_CONSTANT("ast", "AST_TYPE", ZEND_AST_TYPE, CONST_CS | CONST_PERSISTENT);

php_ast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern ast_str_globals str_globals;
5454
// NOTE: The first hex digit is the number of child nodes a given kind has
5555
# define ZEND_AST_CLASS_NAME 0x1ff
5656
# define ZEND_AST_PROP_GROUP 0x2ff
57+
# define ZEND_AST_ARROW_FUNC 0x5ff
5758
#endif
5859

5960
/* Pretend it still exists */

scripts/generate_ast_data.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
'ZEND_AST_FUNC_DECL' => $funcNames,
5858
'ZEND_AST_CLOSURE' => $funcNames,
5959
'ZEND_AST_METHOD' => $funcNames,
60+
'ZEND_AST_ARROW_FUNC' => $funcNames,
6061
'ZEND_AST_CLASS' => ['extends', 'implements', 'stmts'],
6162

6263
/* 0 child nodes */

tests/metadata.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ AST_NULLABLE_TYPE: []
4141
AST_FUNC_DECL: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR]
4242
AST_CLOSURE: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR]
4343
AST_METHOD: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR]
44+
AST_ARROW_FUNC: (combinable) [MODIFIER_PUBLIC, MODIFIER_PROTECTED, MODIFIER_PRIVATE, MODIFIER_STATIC, MODIFIER_ABSTRACT, MODIFIER_FINAL, FUNC_RETURNS_REF, FUNC_GENERATOR]
4445
AST_CLASS: [CLASS_ABSTRACT, CLASS_FINAL, CLASS_TRAIT, CLASS_INTERFACE, CLASS_ANONYMOUS]
4546
AST_MAGIC_CONST: [MAGIC_LINE, MAGIC_FILE, MAGIC_DIR, MAGIC_NAMESPACE, MAGIC_FUNCTION, MAGIC_METHOD, MAGIC_CLASS, MAGIC_TRAIT]
4647
AST_TYPE: [TYPE_NULL, TYPE_BOOL, TYPE_LONG, TYPE_DOUBLE, TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT, TYPE_CALLABLE, TYPE_VOID, TYPE_ITERABLE]

tests/short_arrow_function.phpt

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
--TEST--
2+
Arrow functions ('fn($x) => $x') in PHP 7.4
3+
--SKIPIF--
4+
<?php if (PHP_VERSION_ID < 70400) die('skip PHP >= 7.4 only'); ?>
5+
--FILE--
6+
<?php
7+
8+
require __DIR__ . '/../util.php';
9+
10+
$code = <<<'PHP'
11+
<?php
12+
$y = 1;
13+
$a = fn($x) => $x * $y;
14+
$b = static fn() => 1;
15+
$c = /** doc comment */ static fn(?int... $args): array => $args;
16+
$fn = fn() => yield 123;
17+
PHP;
18+
19+
$node = ast\parse_code($code, $version=70);
20+
$version_70_repr = ast_dump($node);
21+
echo $version_70_repr . "\n";
22+
$node50 = ast\parse_code($code, $version=50);
23+
$version_50_repr = ast_dump($node50);
24+
echo "Same representation in version 50/70: ";
25+
var_export($version_50_repr == $version_70_repr);
26+
echo "\n";
27+
?>
28+
--EXPECTF--
29+
AST_STMT_LIST
30+
0: AST_ASSIGN
31+
var: AST_VAR
32+
name: "y"
33+
expr: 1
34+
1: AST_ASSIGN
35+
var: AST_VAR
36+
name: "a"
37+
expr: AST_ARROW_FUNC
38+
flags: 0
39+
name: "{closure}"
40+
docComment: null
41+
params: AST_PARAM_LIST
42+
0: AST_PARAM
43+
flags: 0
44+
type: null
45+
name: "x"
46+
default: null
47+
stmts: AST_RETURN
48+
expr: AST_BINARY_OP
49+
flags: BINARY_MUL (3)
50+
left: AST_VAR
51+
name: "x"
52+
right: AST_VAR
53+
name: "y"
54+
returnType: null
55+
__declId: 0
56+
2: AST_ASSIGN
57+
var: AST_VAR
58+
name: "b"
59+
expr: AST_ARROW_FUNC
60+
flags: MODIFIER_STATIC (16)
61+
name: "{closure}"
62+
docComment: null
63+
params: AST_PARAM_LIST
64+
stmts: AST_RETURN
65+
expr: 1
66+
returnType: null
67+
__declId: 1
68+
3: AST_ASSIGN
69+
var: AST_VAR
70+
name: "c"
71+
expr: AST_ARROW_FUNC
72+
flags: MODIFIER_STATIC (16)
73+
name: "{closure}"
74+
docComment: "/** doc comment */"
75+
params: AST_PARAM_LIST
76+
0: AST_PARAM
77+
flags: PARAM_VARIADIC (2)
78+
type: AST_NULLABLE_TYPE
79+
type: AST_TYPE
80+
flags: TYPE_LONG (4)
81+
name: "args"
82+
default: null
83+
stmts: AST_RETURN
84+
expr: AST_VAR
85+
name: "args"
86+
returnType: AST_TYPE
87+
flags: TYPE_ARRAY (7)
88+
__declId: 2
89+
4: AST_ASSIGN
90+
var: AST_VAR
91+
name: "fn"
92+
expr: AST_ARROW_FUNC
93+
flags: FUNC_GENERATOR (16777216)
94+
name: "{closure}"
95+
docComment: null
96+
params: AST_PARAM_LIST
97+
stmts: AST_RETURN
98+
expr: AST_YIELD
99+
value: 123
100+
key: null
101+
returnType: null
102+
__declId: 3
103+
Same representation in version 50/70: true

0 commit comments

Comments
 (0)