Skip to content

Commit aa967c4

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 66090c8 commit aa967c4

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
@@ -1970,6 +1970,25 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
19701970
}
19711971

19721972
case ZEND_AST_CONST_DECL:
1973+
zend_ast_list *ast_list = (zend_ast_list *)ast;
1974+
// Attributes are stored at the end of the list if present;
1975+
if (ast_list->child[ast_list->children - 1]->kind == ZEND_AST_ATTRIBUTE_LIST) {
1976+
zend_ast_export_attributes(
1977+
str,
1978+
ast_list->child[ast_list->children - 1],
1979+
indent,
1980+
1
1981+
);
1982+
// So that the list printing doesn't try to print the attributes,
1983+
// decrease the number of children; since we need to increase it
1984+
// afterwards, instead of jumping to simple_list we need to
1985+
// put the zend_ast_export_list() call here
1986+
ast_list->children--;
1987+
smart_str_appends(str, "const ");
1988+
zend_ast_export_list(str, ast_list, 1, 20, indent);
1989+
ast_list->children++;
1990+
break;
1991+
}
19731992
smart_str_appends(str, "const ");
19741993
goto simple_list;
19751994
case ZEND_AST_CLASS_CONST_GROUP:
@@ -2708,6 +2727,9 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
27082727
ast->child[1] = attr;
27092728
break;
27102729
case ZEND_AST_CONST_DECL:
2730+
// Since constants are already stored in a list, just add the attributes
2731+
// to that list instead of storing them elsewhere;
2732+
// zend_compile_const_decl() checks the kind of the list elements
27112733
zend_ast_list_add(ast, attr);
27122734
break;
27132735
EMPTY_SWITCH_DEFAULT_CASE()

ext/zend_test/test.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,3 +1520,22 @@ static PHP_FUNCTION(zend_test_create_throwing_resource)
15201520
zend_resource *res = zend_register_resource(NULL, le_throwing_resource);
15211521
ZVAL_RES(return_value, res);
15221522
}
1523+
1524+
static PHP_FUNCTION(zend_test_compile_to_ast)
1525+
{
1526+
zend_string *str;
1527+
1528+
ZEND_PARSE_PARAMETERS_START(1, 1)
1529+
Z_PARAM_STR(str)
1530+
ZEND_PARSE_PARAMETERS_END();
1531+
1532+
zend_arena *ast_arena;
1533+
zend_ast *ast = zend_compile_string_to_ast(str, &ast_arena, ZSTR_EMPTY_ALLOC());
1534+
1535+
zend_string *result = zend_ast_export("", ast, "");
1536+
1537+
zend_ast_destroy(ast);
1538+
zend_arena_destroy(ast_arena);
1539+
1540+
RETVAL_STR(result);
1541+
}

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)