summaryrefslogtreecommitdiff
path: root/Zend/zend_ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_ast.c')
-rw-r--r--Zend/zend_ast.c286
1 files changed, 231 insertions, 55 deletions
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index 338ff09f76..cb61bec5d7 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -114,7 +114,7 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast *
ZEND_API zend_ast *zend_ast_create_decl(
zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
- zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3
+ zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4
) {
zend_ast_decl *ast;
@@ -131,6 +131,7 @@ ZEND_API zend_ast *zend_ast_create_decl(
ast->child[1] = child1;
ast->child[2] = child2;
ast->child[3] = child3;
+ ast->child[4] = child4;
return (zend_ast *) ast;
}
@@ -163,7 +164,6 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_1(zend_ast_kind kind, zend_ast
lineno = CG(zend_lineno);
}
ast->lineno = lineno;
- ast->lineno = lineno;
return ast;
}
@@ -243,6 +243,37 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_4(zend_ast_kind kind, zend_ast
return ast;
}
+ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_5(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4, zend_ast *child5) {
+ zend_ast *ast;
+ uint32_t lineno;
+
+ ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 5);
+ ast = zend_ast_alloc(zend_ast_size(5));
+ ast->kind = kind;
+ ast->attr = 0;
+ ast->child[0] = child1;
+ ast->child[1] = child2;
+ ast->child[2] = child3;
+ ast->child[3] = child4;
+ ast->child[4] = child5;
+ if (child1) {
+ lineno = zend_ast_get_lineno(child1);
+ } else if (child2) {
+ lineno = zend_ast_get_lineno(child2);
+ } else if (child3) {
+ lineno = zend_ast_get_lineno(child3);
+ } else if (child4) {
+ lineno = zend_ast_get_lineno(child4);
+ } else if (child5) {
+ lineno = zend_ast_get_lineno(child5);
+ } else {
+ lineno = CG(zend_lineno);
+ }
+ ast->lineno = lineno;
+
+ return ast;
+}
+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_0(zend_ast_kind kind) {
zend_ast *ast;
zend_ast_list *list;
@@ -406,14 +437,14 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *ast, zend_ast *op)
return (zend_ast *) list;
}
-static int zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
+static zend_result zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
{
switch (Z_TYPE_P(offset)) {
case IS_UNDEF:
if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), expr)) {
- zend_error(E_WARNING,
+ zend_throw_error(NULL,
"Cannot add element to the array as the next element is already occupied");
- zval_ptr_dtor_nogc(expr);
+ return FAILURE;
}
break;
case IS_STRING:
@@ -436,17 +467,17 @@ static int zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
zend_hash_index_update(Z_ARRVAL_P(result), zend_dval_to_lval(Z_DVAL_P(offset)), expr);
break;
case IS_RESOURCE:
- zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
+ zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset));
zend_hash_index_update(Z_ARRVAL_P(result), Z_RES_HANDLE_P(offset), expr);
break;
default:
- zend_throw_error(NULL, "Illegal offset type");
+ zend_type_error("Illegal offset type");
return FAILURE;
}
return SUCCESS;
}
-static int zend_ast_add_unpacked_element(zval *result, zval *expr) {
+static zend_result zend_ast_add_unpacked_element(zval *result, zval *expr) {
if (EXPECTED(Z_TYPE_P(expr) == IS_ARRAY)) {
HashTable *ht = Z_ARRVAL_P(expr);
zval *val;
@@ -458,8 +489,9 @@ static int zend_ast_add_unpacked_element(zval *result, zval *expr) {
return FAILURE;
} else {
if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), val)) {
- zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
- break;
+ zend_throw_error(NULL,
+ "Cannot add element to the array as the next element is already occupied");
+ return FAILURE;
}
Z_TRY_ADDREF_P(val);
}
@@ -472,10 +504,10 @@ static int zend_ast_add_unpacked_element(zval *result, zval *expr) {
return FAILURE;
}
-ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
+ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
{
zval op1, op2;
- int ret = SUCCESS;
+ zend_result ret = SUCCESS;
switch (ast->kind) {
case ZEND_AST_BINARY_OP:
@@ -530,8 +562,7 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
if (UNEXPECTED(zv == NULL)) {
ZVAL_UNDEF(result);
- ret = zend_use_undefined_constant(name, ast->attr, result);
- break;
+ return FAILURE;
}
ZVAL_COPY_OR_DUP(result, zv);
break;
@@ -718,6 +749,9 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
zval_ptr_dtor_nogc(&op1);
zval_ptr_dtor_nogc(&op2);
+ if (UNEXPECTED(EG(exception))) {
+ return FAILURE;
+ }
}
break;
default:
@@ -814,7 +848,7 @@ ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast)
ref = emalloc(tree_size);
zend_ast_tree_copy(ast, GC_AST(ref));
GC_SET_REFCOUNT(ref, 1);
- GC_TYPE_INFO(ref) = IS_CONSTANT_AST;
+ GC_TYPE_INFO(ref) = GC_CONSTANT_AST;
return ref;
}
@@ -860,7 +894,8 @@ tail_call:
zend_ast_destroy(decl->child[0]);
zend_ast_destroy(decl->child[1]);
zend_ast_destroy(decl->child[2]);
- ast = decl->child[3];
+ zend_ast_destroy(decl->child[3]);
+ ast = decl->child[4];
goto tail_call;
}
}
@@ -910,8 +945,9 @@ ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn) {
* 160 left &
* 170 non-associative == != === !==
* 180 non-associative < <= > >= <=>
+ * 185 left .
* 190 left << >>
- * 200 left + - .
+ * 200 left + -
* 210 left * / %
* 220 right !
* 230 non-associative instanceof
@@ -1022,7 +1058,7 @@ static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int
zend_ast_export_ex(str, ast, priority, indent);
}
-static ZEND_COLD int zend_ast_valid_var_char(char ch)
+static ZEND_COLD bool zend_ast_valid_var_char(char ch)
{
unsigned char c = (unsigned char)ch;
@@ -1035,7 +1071,7 @@ static ZEND_COLD int zend_ast_valid_var_char(char ch)
return 1;
}
-static ZEND_COLD int zend_ast_valid_var_name(const char *s, size_t len)
+static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len)
{
unsigned char c;
size_t i;
@@ -1061,7 +1097,7 @@ static ZEND_COLD int zend_ast_valid_var_name(const char *s, size_t len)
return 1;
}
-static ZEND_COLD int zend_ast_var_needs_braces(char ch)
+static ZEND_COLD bool zend_ast_var_needs_braces(char ch)
{
return ch == '[' || zend_ast_valid_var_char(ch);
}
@@ -1084,7 +1120,7 @@ static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int pri
smart_str_appendc(str, '}');
}
-static ZEND_COLD void zend_ast_export_list(smart_str *str, zend_ast_list *list, int separator, int priority, int indent)
+static ZEND_COLD void zend_ast_export_list(smart_str *str, zend_ast_list *list, bool separator, int priority, int indent)
{
uint32_t i = 0;
@@ -1312,6 +1348,78 @@ static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_d
smart_str_appends(str, "}");
}
+static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) {
+ zend_ast_list *list = zend_ast_get_list(ast);
+ uint32_t i, j;
+
+ for (i = 0; i < list->children; i++) {
+ zend_ast *attr = list->child[i];
+
+ if (i) {
+ smart_str_appends(str, ", ");
+ }
+ zend_ast_export_ns_name(str, attr->child[0], 0, indent);
+
+ if (attr->child[1]) {
+ zend_ast_list *args = zend_ast_get_list(attr->child[1]);
+
+ smart_str_appendc(str, '(');
+ for (j = 0; j < args->children; j++) {
+ if (j) {
+ smart_str_appends(str, ", ");
+ }
+ zend_ast_export_ex(str, args->child[j], 0, indent);
+ }
+ smart_str_appendc(str, ')');
+ }
+ }
+}
+
+static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, zend_bool newlines) {
+ zend_ast_list *list = zend_ast_get_list(ast);
+ uint32_t i;
+
+ for (i = 0; i < list->children; i++) {
+ smart_str_appends(str, "#[");
+ zend_ast_export_attribute_group(str, list->child[i], indent);
+ smart_str_appends(str, "]");
+
+ if (newlines) {
+ smart_str_appendc(str, '\n');
+ zend_ast_export_indent(str, indent);
+ } else {
+ smart_str_appendc(str, ' ');
+ }
+ }
+}
+
+static ZEND_COLD void zend_ast_export_visibility(smart_str *str, uint32_t flags) {
+ if (flags & ZEND_ACC_PUBLIC) {
+ smart_str_appends(str, "public ");
+ } else if (flags & ZEND_ACC_PROTECTED) {
+ smart_str_appends(str, "protected ");
+ } else if (flags & ZEND_ACC_PRIVATE) {
+ smart_str_appends(str, "private ");
+ }
+}
+
+static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int indent) {
+ if (ast->kind == ZEND_AST_TYPE_UNION) {
+ zend_ast_list *list = zend_ast_get_list(ast);
+ for (uint32_t i = 0; i < list->children; i++) {
+ if (i != 0) {
+ smart_str_appendc(str, '|');
+ }
+ zend_ast_export_type(str, list->child[i], indent);
+ }
+ return;
+ }
+ if (ast->attr & ZEND_TYPE_NULLABLE) {
+ smart_str_appendc(str, '?');
+ }
+ zend_ast_export_ns_name(str, ast, 0, indent);
+}
+
#define BINARY_OP(_op, _p, _pl, _pr) do { \
op = _op; \
p = _p; \
@@ -1379,7 +1487,7 @@ tail_call:
break;
case ZEND_AST_ZNODE:
/* This AST kind is only used for temporary nodes during compilation */
- ZEND_ASSERT(0);
+ ZEND_UNREACHABLE();
break;
/* declaration nodes */
@@ -1388,13 +1496,13 @@ tail_call:
case ZEND_AST_ARROW_FUNC:
case ZEND_AST_METHOD:
decl = (zend_ast_decl *) ast;
- if (decl->flags & ZEND_ACC_PUBLIC) {
- smart_str_appends(str, "public ");
- } else if (decl->flags & ZEND_ACC_PROTECTED) {
- smart_str_appends(str, "protected ");
- } else if (decl->flags & ZEND_ACC_PRIVATE) {
- smart_str_appends(str, "private ");
+ if (decl->child[4]) {
+ zend_bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC);
+ zend_ast_export_attributes(str, decl->child[4], indent, newlines);
}
+
+ zend_ast_export_visibility(str, decl->flags);
+
if (decl->flags & ZEND_ACC_STATIC) {
smart_str_appends(str, "static ");
}
@@ -1421,10 +1529,7 @@ tail_call:
zend_ast_export_ex(str, decl->child[1], 0, indent);
if (decl->child[3]) {
smart_str_appends(str, ": ");
- if (decl->child[3]->attr & ZEND_TYPE_NULLABLE) {
- smart_str_appendc(str, '?');
- }
- zend_ast_export_ns_name(str, decl->child[3], 0, indent);
+ zend_ast_export_type(str, decl->child[3], indent);
}
if (decl->child[2]) {
if (decl->kind == ZEND_AST_ARROW_FUNC) {
@@ -1447,6 +1552,9 @@ tail_call:
break;
case ZEND_AST_CLASS:
decl = (zend_ast_decl *) ast;
+ if (decl->child[3]) {
+ zend_ast_export_attributes(str, decl->child[3], indent, 1);
+ }
if (decl->flags & ZEND_ACC_INTERFACE) {
smart_str_appends(str, "interface ");
} else if (decl->flags & ZEND_ACC_TRAIT) {
@@ -1491,6 +1599,7 @@ simple_list:
break;
case ZEND_AST_SWITCH_LIST:
case ZEND_AST_CATCH_LIST:
+ case ZEND_AST_MATCH_ARM_LIST:
zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
break;
case ZEND_AST_CLOSURE_USES:
@@ -1502,23 +1611,18 @@ simple_list:
zend_ast *type_ast = ast->child[0];
zend_ast *prop_ast = ast->child[1];
- if (ast->attr & ZEND_ACC_PUBLIC) {
- smart_str_appends(str, "public ");
- } else if (ast->attr & ZEND_ACC_PROTECTED) {
- smart_str_appends(str, "protected ");
- } else if (ast->attr & ZEND_ACC_PRIVATE) {
- smart_str_appends(str, "private ");
+ if (ast->child[2]) {
+ zend_ast_export_attributes(str, ast->child[2], indent, 1);
}
+
+ zend_ast_export_visibility(str, ast->attr);
+
if (ast->attr & ZEND_ACC_STATIC) {
smart_str_appends(str, "static ");
}
if (type_ast) {
- if (type_ast->attr & ZEND_TYPE_NULLABLE) {
- smart_str_appendc(str, '?');
- }
- zend_ast_export_ns_name(
- str, type_ast, 0, indent);
+ zend_ast_export_type(str, type_ast, indent);
smart_str_appendc(str, ' ');
}
@@ -1527,9 +1631,19 @@ simple_list:
}
case ZEND_AST_CONST_DECL:
- case ZEND_AST_CLASS_CONST_DECL:
smart_str_appends(str, "const ");
goto simple_list;
+ case ZEND_AST_CLASS_CONST_GROUP:
+ if (ast->child[1]) {
+ zend_ast_export_attributes(str, ast->child[1], indent, 1);
+ }
+
+ zend_ast_export_visibility(str, ast->attr);
+ smart_str_appends(str, "const ");
+
+ ast = ast->child[0];
+
+ goto simple_list;
case ZEND_AST_NAME_LIST:
zend_ast_export_name_list(str, (zend_ast_list*)ast, indent);
break;
@@ -1560,6 +1674,8 @@ simple_list:
switch (ast->attr & ~ZEND_TYPE_NULLABLE) {
case IS_ARRAY: APPEND_STR("array");
case IS_CALLABLE: APPEND_STR("callable");
+ case IS_STATIC: APPEND_STR("static");
+ case IS_MIXED: APPEND_STR("mixed");
EMPTY_SWITCH_DEFAULT_CASE();
}
break;
@@ -1685,8 +1801,9 @@ simple_list:
smart_str_appendc(str, ']');
break;
case ZEND_AST_PROP:
+ case ZEND_AST_NULLSAFE_PROP:
zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, "->");
+ smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_PROP ? "?->" : "->");
zend_ast_export_var(str, ast->child[1], 0, indent);
break;
case ZEND_AST_STATIC_PROP:
@@ -1738,8 +1855,7 @@ simple_list:
case ZEND_MOD: BINARY_OP(" % ", 210, 210, 211);
case ZEND_SL: BINARY_OP(" << ", 190, 190, 191);
case ZEND_SR: BINARY_OP(" >> ", 190, 190, 191);
- case ZEND_PARENTHESIZED_CONCAT: /* fallthrough */
- case ZEND_CONCAT: BINARY_OP(" . ", 200, 200, 201);
+ case ZEND_CONCAT: BINARY_OP(" . ", 185, 185, 186);
case ZEND_BW_OR: BINARY_OP(" | ", 140, 140, 141);
case ZEND_BW_AND: BINARY_OP(" & ", 160, 160, 161);
case ZEND_BW_XOR: BINARY_OP(" ^ ", 150, 150, 151);
@@ -1771,13 +1887,17 @@ simple_list:
case ZEND_AST_NEW:
smart_str_appends(str, "new ");
if (ast->child[0]->kind == ZEND_AST_CLASS) {
+ zend_ast_decl *decl = (zend_ast_decl *) ast->child[0];
+ if (decl->child[3]) {
+ zend_ast_export_attributes(str, decl->child[3], indent, 0);
+ }
smart_str_appends(str, "class");
if (zend_ast_get_list(ast->child[1])->children) {
smart_str_appendc(str, '(');
zend_ast_export_ex(str, ast->child[1], 0, indent);
smart_str_appendc(str, ')');
}
- zend_ast_export_class_no_header(str, (zend_ast_decl *) ast->child[0], indent);
+ zend_ast_export_class_no_header(str, decl, indent);
} else {
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
smart_str_appendc(str, '(');
@@ -1858,6 +1978,25 @@ simple_list:
}
zend_ast_export_stmt(str, ast->child[1], indent + 1);
break;
+ case ZEND_AST_MATCH:
+ smart_str_appends(str, "match (");
+ zend_ast_export_ex(str, ast->child[0], 0, indent);
+ smart_str_appends(str, ") {\n");
+ zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
+ zend_ast_export_indent(str, indent);
+ smart_str_appendc(str, '}');
+ break;
+ case ZEND_AST_MATCH_ARM:
+ zend_ast_export_indent(str, indent);
+ if (ast->child[0]) {
+ zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
+ smart_str_appends(str, " => ");
+ } else {
+ smart_str_appends(str, "default => ");
+ }
+ zend_ast_export_ex(str, ast->child[1], 0, 0);
+ smart_str_appends(str, ",\n");
+ break;
case ZEND_AST_DECLARE:
smart_str_appends(str, "declare(");
ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_CONST_DECL);
@@ -1934,11 +2073,17 @@ simple_list:
zend_ast_export_name(str, ast->child[1], 0, indent);
}
break;
+ case ZEND_AST_NAMED_ARG:
+ smart_str_append(str, zend_ast_get_str(ast->child[0]));
+ smart_str_appends(str, ": ");
+ ast = ast->child[1];
+ goto tail_call;
/* 3 child nodes */
case ZEND_AST_METHOD_CALL:
+ case ZEND_AST_NULLSAFE_METHOD_CALL:
zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, "->");
+ smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL ? "?->" : "->");
zend_ast_export_var(str, ast->child[1], 0, indent);
smart_str_appendc(str, '(');
zend_ast_export_ex(str, ast->child[2], 0, indent);
@@ -1981,18 +2126,20 @@ simple_list:
case ZEND_AST_CATCH:
smart_str_appends(str, "} catch (");
zend_ast_export_catch_name_list(str, zend_ast_get_list(ast->child[0]), indent);
- smart_str_appends(str, " $");
- zend_ast_export_var(str, ast->child[1], 0, indent);
+ if (ast->child[1]) {
+ smart_str_appends(str, " $");
+ zend_ast_export_var(str, ast->child[1], 0, indent);
+ }
smart_str_appends(str, ") {\n");
zend_ast_export_stmt(str, ast->child[2], indent + 1);
zend_ast_export_indent(str, indent);
break;
case ZEND_AST_PARAM:
+ if (ast->child[3]) {
+ zend_ast_export_attributes(str, ast->child[3], indent, 0);
+ }
if (ast->child[0]) {
- if (ast->child[0]->attr & ZEND_TYPE_NULLABLE) {
- smart_str_appendc(str, '?');
- }
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
+ zend_ast_export_type(str, ast->child[0], indent);
smart_str_appendc(str, ' ');
}
if (ast->attr & ZEND_PARAM_REF) {
@@ -2103,3 +2250,32 @@ ZEND_API ZEND_COLD zend_string *zend_ast_export(const char *prefix, zend_ast *as
smart_str_0(&str);
return str.s;
}
+
+zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
+{
+ ZEND_ASSERT(attr->kind == ZEND_AST_ATTRIBUTE_LIST);
+
+ switch (ast->kind) {
+ case ZEND_AST_FUNC_DECL:
+ case ZEND_AST_CLOSURE:
+ case ZEND_AST_METHOD:
+ case ZEND_AST_ARROW_FUNC:
+ ((zend_ast_decl *) ast)->child[4] = attr;
+ break;
+ case ZEND_AST_CLASS:
+ ((zend_ast_decl *) ast)->child[3] = attr;
+ break;
+ case ZEND_AST_PROP_GROUP:
+ ast->child[2] = attr;
+ break;
+ case ZEND_AST_PARAM:
+ ast->child[3] = attr;
+ break;
+ case ZEND_AST_CLASS_CONST_GROUP:
+ ast->child[1] = attr;
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+
+ return ast;
+}