Skip to content

Commit bd1e66b

Browse files
authored
Merge pull request #10 from koolkode/PrintAst
AST Export / External Linkage
2 parents 55e6e75 + a9d94bb commit bd1e66b

File tree

6 files changed

+168
-41
lines changed

6 files changed

+168
-41
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Attributes AST can be exported.
3+
--FILE--
4+
<?php
5+
6+
assert(0 && ($a = <<A1>><<A2>> function ($a, <<A3(1)>> $b) { }));
7+
8+
assert(0 && ($a = <<A1(1, 2, 1 + 2)>> fn () => 1));
9+
10+
assert(0 && ($a = new <<A1>> class() {
11+
<<A1>><<A2>> const FOO = 'foo';
12+
<<A2>> public $x;
13+
<<A3>> function a() { }
14+
}));
15+
16+
assert(0 && ($a = function () {
17+
<<A1>> class Test1 { }
18+
<<A2>> interface Test2 { }
19+
<<A3>> trait Test3 { }
20+
}));
21+
22+
?>
23+
--EXPECTF--
24+
Warning: assert(): assert(0 && ($a = <<A1>> <<A2>> function ($a, <<A3(1)>> $b) {
25+
})) failed in %s on line %d
26+
27+
Warning: assert(): assert(0 && ($a = <<A1(1, 2, 1 + 2)>> fn() => 1)) failed in %s on line %d
28+
29+
Warning: assert(): assert(0 && ($a = new <<A1>> class {
30+
<<A1>>
31+
<<A2>>
32+
const FOO = 'foo';
33+
<<A2>>
34+
public $x;
35+
<<A3>>
36+
public function a() {
37+
}
38+
39+
})) failed in %s on line %d
40+
41+
Warning: assert(): assert(0 && ($a = function () {
42+
<<A1>>
43+
class Test1 {
44+
}
45+
46+
<<A2>>
47+
interface Test2 {
48+
}
49+
50+
<<A3>>
51+
trait Test3 {
52+
}
53+
54+
})) failed in %s on line %d

Zend/zend_ast.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,41 @@ static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_d
13171317
smart_str_appends(str, "}");
13181318
}
13191319

1320+
static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
1321+
zend_ast_list *list = zend_ast_get_list(ast);
1322+
uint32_t i;
1323+
1324+
for (i = 0; i < list->children; i++) {
1325+
zend_ast *attr = list->child[i];
1326+
1327+
smart_str_appends(str, "<<");
1328+
smart_str_append(str, zend_ast_get_str(attr->child[0]));
1329+
1330+
if (attr->child[1]) {
1331+
zend_ast_list *args = zend_ast_get_list(attr->child[1]);
1332+
uint32_t j;
1333+
1334+
smart_str_appendc(str, '(');
1335+
for (j = 0; j < args->children; j++) {
1336+
if (j) {
1337+
smart_str_appends(str, ", ");
1338+
}
1339+
zend_ast_export_ex(str, args->child[j], 0, indent);
1340+
}
1341+
smart_str_appendc(str, ')');
1342+
}
1343+
1344+
smart_str_appends(str, ">>");
1345+
1346+
if (newlines) {
1347+
smart_str_appendc(str, '\n');
1348+
zend_ast_export_indent(str, indent);
1349+
} else {
1350+
smart_str_appendc(str, ' ');
1351+
}
1352+
}
1353+
}
1354+
13201355
static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int indent) {
13211356
if (ast->kind == ZEND_AST_TYPE_UNION) {
13221357
zend_ast_list *list = zend_ast_get_list(ast);
@@ -1410,6 +1445,10 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
14101445
case ZEND_AST_ARROW_FUNC:
14111446
case ZEND_AST_METHOD:
14121447
decl = (zend_ast_decl *) ast;
1448+
if (decl->attributes) {
1449+
zend_bool newlines = (ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC) ? 0 : 1;
1450+
zend_ast_export_attributes(str, decl->attributes, indent, newlines);
1451+
}
14131452
if (decl->flags & ZEND_ACC_PUBLIC) {
14141453
smart_str_appends(str, "public ");
14151454
} else if (decl->flags & ZEND_ACC_PROTECTED) {
@@ -1466,6 +1505,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
14661505
break;
14671506
case ZEND_AST_CLASS:
14681507
decl = (zend_ast_decl *) ast;
1508+
if (decl->attributes) {
1509+
zend_ast_export_attributes(str, decl->attributes, indent, 1);
1510+
}
14691511
if (decl->flags & ZEND_ACC_INTERFACE) {
14701512
smart_str_appends(str, "interface ");
14711513
} else if (decl->flags & ZEND_ACC_TRAIT) {
@@ -1521,6 +1563,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
15211563
zend_ast *type_ast = ast->child[0];
15221564
zend_ast *prop_ast = ast->child[1];
15231565

1566+
if (ast->child[2]) {
1567+
zend_ast_export_attributes(str, ast->child[2], indent, 1);
1568+
}
15241569
if (ast->attr & ZEND_ACC_PUBLIC) {
15251570
smart_str_appends(str, "public ");
15261571
} else if (ast->attr & ZEND_ACC_PROTECTED) {
@@ -1546,6 +1591,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
15461591
smart_str_appends(str, "const ");
15471592
goto simple_list;
15481593
case ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES:
1594+
zend_ast_export_attributes(str, ast->child[1], indent, 1);
15491595
zend_ast_export_ex(str, ast->child[0], 0, indent);
15501596
break;
15511597
case ZEND_AST_NAME_LIST:
@@ -1789,13 +1835,17 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
17891835
case ZEND_AST_NEW:
17901836
smart_str_appends(str, "new ");
17911837
if (ast->child[0]->kind == ZEND_AST_CLASS) {
1838+
zend_ast_decl *decl = (zend_ast_decl *) ast->child[0];
1839+
if (decl->attributes) {
1840+
zend_ast_export_attributes(str, decl->attributes, indent, 0);
1841+
}
17921842
smart_str_appends(str, "class");
17931843
if (zend_ast_get_list(ast->child[1])->children) {
17941844
smart_str_appendc(str, '(');
17951845
zend_ast_export_ex(str, ast->child[1], 0, indent);
17961846
smart_str_appendc(str, ')');
17971847
}
1798-
zend_ast_export_class_no_header(str, (zend_ast_decl *) ast->child[0], indent);
1848+
zend_ast_export_class_no_header(str, decl, indent);
17991849
} else {
18001850
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
18011851
smart_str_appendc(str, '(');
@@ -2006,6 +2056,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
20062056
zend_ast_export_indent(str, indent);
20072057
break;
20082058
case ZEND_AST_PARAM:
2059+
if (ast->child[3]) {
2060+
zend_ast_export_attributes(str, ast->child[3], indent, 0);
2061+
}
20092062
if (ast->child[0]) {
20102063
zend_ast_export_type(str, ast->child[0], indent);
20112064
smart_str_appendc(str, ' ');

Zend/zend_attributes.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#include "zend_API.h"
33
#include "zend_attributes.h"
44

5+
ZEND_API zend_class_entry *zend_ce_php_attribute;
6+
ZEND_API zend_class_entry *zend_ce_php_compiler_attribute;
7+
8+
static HashTable internal_validators;
9+
510
void zend_attribute_validate_phpattribute(zend_attribute *attr, int target)
611
{
712
if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
@@ -14,9 +19,22 @@ void zend_attribute_validate_phpcompilerattribute(zend_attribute *attr, int targ
1419
zend_error(E_COMPILE_ERROR, "The PhpCompilerAttribute can only be used by internal classes, use PhpAttribute instead");
1520
}
1621

22+
ZEND_API zend_attributes_internal_validator zend_attribute_get_validator(zend_string *lcname)
23+
{
24+
return zend_hash_find_ptr(&internal_validators, lcname);
25+
}
26+
27+
ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator)
28+
{
29+
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
30+
31+
zend_hash_update_ptr(&internal_validators, lcname, validator);
32+
zend_string_release(lcname);
33+
}
34+
1735
void zend_register_attribute_ce(void)
1836
{
19-
zend_hash_init(&zend_attributes_internal_validators, 8, NULL, NULL, 1);
37+
zend_hash_init(&internal_validators, 8, NULL, NULL, 1);
2038

2139
zend_class_entry ce;
2240

@@ -32,12 +50,3 @@ void zend_register_attribute_ce(void)
3250

3351
zend_compiler_attribute_register(zend_ce_php_compiler_attribute, zend_attribute_validate_phpcompilerattribute);
3452
}
35-
36-
void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator)
37-
{
38-
zend_string *attribute_name = zend_string_tolower_ex(ce->name, 1);
39-
40-
zend_hash_update_ptr(&zend_attributes_internal_validators, attribute_name, validator);
41-
42-
zend_string_release(attribute_name);
43-
}

Zend/zend_attributes.h

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
#define ZEND_ATTRIBUTE_TARGET_PARAMETER 32
1010
#define ZEND_ATTRIBUTE_TARGET_ALL 63
1111

12-
zend_class_entry *zend_ce_php_attribute;
13-
zend_class_entry *zend_ce_php_compiler_attribute;
14-
1512
#define ZEND_ATTRIBUTE_SIZE(argc) (sizeof(zend_attribute) + sizeof(zval) * (argc) - sizeof(zval))
1613

14+
BEGIN_EXTERN_C()
15+
16+
extern ZEND_API zend_class_entry *zend_ce_php_attribute;
17+
extern ZEND_API zend_class_entry *zend_ce_php_compiler_attribute;
18+
1719
typedef struct _zend_attribute {
1820
zend_string *name;
1921
zend_string *lcname;
@@ -22,7 +24,9 @@ typedef struct _zend_attribute {
2224
zval argv[1];
2325
} zend_attribute;
2426

25-
static zend_always_inline void zend_attribute_release(zend_attribute *attr)
27+
typedef void (*zend_attributes_internal_validator)(zend_attribute *attr, int target);
28+
29+
static zend_always_inline void zend_attribute_free(zend_attribute *attr)
2630
{
2731
uint32_t i;
2832

@@ -36,37 +40,43 @@ static zend_always_inline void zend_attribute_release(zend_attribute *attr)
3640
efree(attr);
3741
}
3842

39-
static zend_always_inline zend_bool zend_has_attribute(HashTable *attributes, zend_string *name, uint32_t offset)
43+
static zend_always_inline zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *name, uint32_t offset)
4044
{
4145
if (attributes) {
4246
zend_attribute *attr;
4347

4448
ZEND_HASH_FOREACH_PTR(attributes, attr) {
4549
if (attr->offset == offset && zend_string_equals(attr->lcname, name)) {
46-
return 1;
50+
return attr;
4751
}
4852
} ZEND_HASH_FOREACH_END();
4953
}
5054

51-
return 0;
55+
return NULL;
5256
}
5357

54-
static zend_always_inline zend_bool zend_has_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
58+
static zend_always_inline zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
5559
{
56-
zend_bool result = 0;
57-
5860
if (attributes) {
59-
zend_string *name = zend_string_init(str, len, 0);
60-
result = zend_has_attribute(attributes, name, offset);
61-
zend_string_release(name);
61+
zend_attribute *attr;
62+
63+
ZEND_HASH_FOREACH_PTR(attributes, attr) {
64+
if (attr->offset == offset && ZSTR_LEN(attr->lcname) == len) {
65+
if (0 == memcmp(ZSTR_VAL(attr->lcname), str, len)) {
66+
return attr;
67+
}
68+
}
69+
} ZEND_HASH_FOREACH_END();
6270
}
6371

64-
return result;
72+
return NULL;
6573
}
6674

67-
typedef void (*zend_attributes_internal_validator)(zend_attribute *attr, int target);
68-
HashTable zend_attributes_internal_validators;
75+
ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator);
76+
ZEND_API zend_attributes_internal_validator zend_attribute_get_validator(zend_string *lcname);
6977

70-
void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator);
7178
void zend_register_attribute_ce(void);
79+
80+
END_EXTERN_C()
81+
7282
#endif

Zend/zend_compile.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5743,10 +5743,11 @@ static zend_attribute *zend_compile_attribute(zend_ast *ast, uint32_t offset) /*
57435743
}
57445744
/* }}} */
57455745

5746-
static void attribute_ptr_dtor(zval *v)
5746+
static void attribute_ptr_dtor(zval *v) /* {{{ */
57475747
{
5748-
zend_attribute_release((zend_attribute *) Z_PTR_P(v));
5748+
zend_attribute_free((zend_attribute *) Z_PTR_P(v));
57495749
}
5750+
/* }}} */
57505751

57515752
static zend_always_inline HashTable *create_attribute_array(uint32_t size) /* {{{ */
57525753
{
@@ -5772,7 +5773,7 @@ static void zend_compile_attributes(HashTable *attributes, zend_ast *ast, uint32
57725773
zend_attribute *attr = zend_compile_attribute(list->child[i], offset);
57735774

57745775
// Validate internal attribute
5775-
zend_attributes_internal_validator validator = zend_hash_find_ptr(&zend_attributes_internal_validators, attr->lcname);
5776+
zend_attributes_internal_validator validator = zend_attribute_get_validator(attr->lcname);
57765777

57775778
if (validator != NULL) {
57785779
validator(attr, target);

0 commit comments

Comments
 (0)