Skip to content

Commit b5e16cd

Browse files
Fix and test ast exporting
Since attributes on constants cannot be used in expressions, the normal `assert()` testing cannot be used - instead, add a function to zend_test to compile a string to AST and then export it back to a string.
1 parent 0d0329a commit b5e16cd

File tree

5 files changed

+82
-1
lines changed

5 files changed

+82
-1
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
AST can be recreated when constants have attributes
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
#[MyAttrib]
9+
const WITH_ATTRIBUTE = true;
10+
11+
#[First]
12+
#[Second]
13+
const WITH_UNGROUPED = true;
14+
15+
#[First, Second]
16+
const WITH_GROUPED = true;
17+
18+
#[MyAttrib(5, param: "example")]
19+
const WITH_PARAMETERS = true;
20+
21+
echo zend_test_compile_to_ast( file_get_contents( __FILE__ ) );
22+
23+
?>
24+
--EXPECT--
25+
#[MyAttrib]
26+
const WITH_ATTRIBUTE = true;
27+
#[First]
28+
#[Second]
29+
const WITH_UNGROUPED = true;
30+
#[First, Second]
31+
const WITH_GROUPED = true;
32+
#[MyAttrib(5, param: 'example')]
33+
const WITH_PARAMETERS = true;
34+
echo zend_test_compile_to_ast(file_get_contents(__FILE__));

Zend/zend_ast.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,6 +2025,25 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
20252025
}
20262026

20272027
case ZEND_AST_CONST_DECL:
2028+
zend_ast_list *ast_list = (zend_ast_list *)ast;
2029+
// Attributes are stored at the end of the list if present;
2030+
if (ast_list->child[ast_list->children - 1]->kind == ZEND_AST_ATTRIBUTE_LIST) {
2031+
zend_ast_export_attributes(
2032+
str,
2033+
ast_list->child[ast_list->children - 1],
2034+
indent,
2035+
1
2036+
);
2037+
// So that the list printing doesn't try to print the attributes,
2038+
// decrease the number of children; since we need to increase it
2039+
// afterwards, instead of jumping to simple_list we need to
2040+
// put the zend_ast_export_list() call here
2041+
ast_list->children--;
2042+
smart_str_appends(str, "const ");
2043+
zend_ast_export_list(str, ast_list, 1, 20, indent);
2044+
ast_list->children++;
2045+
break;
2046+
}
20282047
smart_str_appends(str, "const ");
20292048
goto simple_list;
20302049
case ZEND_AST_CLASS_CONST_GROUP:
@@ -2729,6 +2748,9 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
27292748
ast->child[1] = attr;
27302749
break;
27312750
case ZEND_AST_CONST_DECL:
2751+
// Since constants are already stored in a list, just add the attributes
2752+
// to that list instead of storing them elsewhere;
2753+
// zend_compile_const_decl() checks the kind of the list elements
27322754
zend_ast_list_add(ast, attr);
27332755
break;
27342756
EMPTY_SWITCH_DEFAULT_CASE()

ext/zend_test/test.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,3 +1555,22 @@ static PHP_FUNCTION(zend_test_create_throwing_resource)
15551555
zend_resource *res = zend_register_resource(NULL, le_throwing_resource);
15561556
ZVAL_RES(return_value, res);
15571557
}
1558+
1559+
static PHP_FUNCTION(zend_test_compile_to_ast)
1560+
{
1561+
zend_string *str;
1562+
1563+
ZEND_PARSE_PARAMETERS_START(1, 1)
1564+
Z_PARAM_STR(str)
1565+
ZEND_PARSE_PARAMETERS_END();
1566+
1567+
zend_arena *ast_arena;
1568+
zend_ast *ast = zend_compile_string_to_ast(str, &ast_arena, ZSTR_EMPTY_ALLOC());
1569+
1570+
zend_string *result = zend_ast_export("", ast, "");
1571+
1572+
zend_ast_destroy(ast);
1573+
zend_arena_destroy(ast_arena);
1574+
1575+
RETVAL_STR(result);
1576+
}

ext/zend_test/test.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ function zend_test_cast_fread($stream): void {}
309309
function zend_test_is_zend_ptr(int $addr): bool {}
310310

311311
function zend_test_log_err_debug(string $str): void {}
312+
313+
function zend_test_compile_to_ast(string $str): string {}
312314
}
313315

314316
namespace ZendTestNS {

ext/zend_test/test_arginfo.h

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)