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.c152
1 files changed, 121 insertions, 31 deletions
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index d007e01480..338ff09f76 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -102,6 +102,16 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_constant(zend_string *name, ze
return (zend_ast *) ast;
}
+ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast *class_name, zend_ast *name) {
+ zend_string *name_str = zend_ast_get_str(name);
+ if (zend_string_equals_literal_ci(name_str, "class")) {
+ zend_string_release(name_str);
+ return zend_ast_create(ZEND_AST_CLASS_NAME, class_name);
+ } else {
+ return zend_ast_create(ZEND_AST_CLASS_CONST, class_name, name);
+ }
+}
+
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
@@ -436,6 +446,32 @@ static int zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
return SUCCESS;
}
+static int 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;
+ zend_string *key;
+
+ ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
+ if (key) {
+ zend_throw_error(NULL, "Cannot unpack array with string keys");
+ 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;
+ }
+ Z_TRY_ADDREF_P(val);
+ }
+ } ZEND_HASH_FOREACH_END();
+ return SUCCESS;
+ }
+
+ /* Objects or references cannot occur in a constant expression. */
+ zend_throw_error(NULL, "Only arrays and Traversables can be unpacked");
+ return FAILURE;
+}
+
ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
{
zval op1, op2;
@@ -501,13 +537,30 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
break;
}
case ZEND_AST_CONSTANT_CLASS:
- ZEND_ASSERT(EG(current_execute_data));
- if (scope && scope->name) {
+ if (scope) {
ZVAL_STR_COPY(result, scope->name);
} else {
ZVAL_EMPTY_STRING(result);
}
break;
+ case ZEND_AST_CLASS_NAME:
+ if (!scope) {
+ zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active");
+ return FAILURE;
+ }
+ if (ast->attr == ZEND_FETCH_CLASS_SELF) {
+ ZVAL_STR_COPY(result, scope->name);
+ } else if (ast->attr == ZEND_FETCH_CLASS_PARENT) {
+ if (!scope->parent) {
+ zend_throw_error(NULL,
+ "Cannot use \"parent\" when current class scope has no parent");
+ return FAILURE;
+ }
+ ZVAL_STR_COPY(result, scope->parent->name);
+ } else {
+ ZEND_ASSERT(0 && "Should have errored during compilation");
+ }
+ break;
case ZEND_AST_AND:
if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
ret = FAILURE;
@@ -615,6 +668,19 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
array_init(result);
for (i = 0; i < list->children; i++) {
zend_ast *elem = list->child[i];
+ if (elem->kind == ZEND_AST_UNPACK) {
+ if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[0], scope) != SUCCESS)) {
+ zval_ptr_dtor_nogc(result);
+ return FAILURE;
+ }
+ if (UNEXPECTED(zend_ast_add_unpacked_element(result, &op1) != SUCCESS)) {
+ zval_ptr_dtor_nogc(&op1);
+ zval_ptr_dtor_nogc(result);
+ return FAILURE;
+ }
+ zval_ptr_dtor_nogc(&op1);
+ continue;
+ }
if (elem->child[1]) {
if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[1], scope) != SUCCESS)) {
zval_ptr_dtor_nogc(result);
@@ -648,7 +714,7 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
zval_ptr_dtor_nogc(&op1);
ret = FAILURE;
} else {
- zend_fetch_dimension_const(result, &op1, &op2, (ast->attr == ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
+ zend_fetch_dimension_const(result, &op1, &op2, (ast->attr & ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
zval_ptr_dtor_nogc(&op1);
zval_ptr_dtor_nogc(&op2);
@@ -821,7 +887,7 @@ ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn) {
}
/*
- * Operator Precendence
+ * Operator Precedence
* ====================
* priority associativity operators
* ----------------------------------
@@ -1084,7 +1150,7 @@ static ZEND_COLD void zend_ast_export_var_list(smart_str *str, zend_ast_list *li
if (i != 0) {
smart_str_appends(str, ", ");
}
- if (list->child[i]->attr) {
+ if (list->child[i]->attr & ZEND_BIND_REF) {
smart_str_appendc(str, '&');
}
smart_str_appendc(str, '$');
@@ -1319,6 +1385,7 @@ tail_call:
/* declaration nodes */
case ZEND_AST_FUNC_DECL:
case ZEND_AST_CLOSURE:
+ case ZEND_AST_ARROW_FUNC:
case ZEND_AST_METHOD:
decl = (zend_ast_decl *) ast;
if (decl->flags & ZEND_ACC_PUBLIC) {
@@ -1337,11 +1404,15 @@ tail_call:
if (decl->flags & ZEND_ACC_FINAL) {
smart_str_appends(str, "final ");
}
- smart_str_appends(str, "function ");
+ if (decl->kind == ZEND_AST_ARROW_FUNC) {
+ smart_str_appends(str, "fn");
+ } else {
+ smart_str_appends(str, "function ");
+ }
if (decl->flags & ZEND_ACC_RETURN_REFERENCE) {
smart_str_appendc(str, '&');
}
- if (ast->kind != ZEND_AST_CLOSURE) {
+ if (ast->kind != ZEND_AST_CLOSURE && ast->kind != ZEND_AST_ARROW_FUNC) {
smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
}
smart_str_appendc(str, '(');
@@ -1356,6 +1427,13 @@ tail_call:
zend_ast_export_ns_name(str, decl->child[3], 0, indent);
}
if (decl->child[2]) {
+ if (decl->kind == ZEND_AST_ARROW_FUNC) {
+ ZEND_ASSERT(decl->child[2]->kind == ZEND_AST_RETURN);
+ smart_str_appends(str, " => ");
+ zend_ast_export_ex(str, decl->child[2]->child[0], 0, indent);
+ break;
+ }
+
smart_str_appends(str, " {\n");
zend_ast_export_stmt(str, decl->child[2], indent + 1);
zend_ast_export_indent(str, indent);
@@ -1420,7 +1498,10 @@ simple_list:
zend_ast_export_var_list(str, (zend_ast_list*)ast, indent);
smart_str_appendc(str, ')');
break;
- case ZEND_AST_PROP_DECL:
+ case ZEND_AST_PROP_GROUP: {
+ 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) {
@@ -1431,7 +1512,20 @@ simple_list:
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);
+ smart_str_appendc(str, ' ');
+ }
+
+ ast = prop_ast;
goto simple_list;
+ }
+
case ZEND_AST_CONST_DECL:
case ZEND_AST_CLASS_CONST_DECL:
smart_str_appends(str, "const ");
@@ -1611,25 +1705,30 @@ simple_list:
smart_str_appends(str, "::");
zend_ast_export_name(str, ast->child[1], 0, indent);
break;
+ case ZEND_AST_CLASS_NAME:
+ zend_ast_export_ns_name(str, ast->child[0], 0, indent);
+ smart_str_appends(str, "::class");
+ break;
case ZEND_AST_ASSIGN: BINARY_OP(" = ", 90, 91, 90);
case ZEND_AST_ASSIGN_REF: BINARY_OP(" =& ", 90, 91, 90);
case ZEND_AST_ASSIGN_OP:
switch (ast->attr) {
- case ZEND_ASSIGN_ADD: BINARY_OP(" += ", 90, 91, 90);
- case ZEND_ASSIGN_SUB: BINARY_OP(" -= ", 90, 91, 90);
- case ZEND_ASSIGN_MUL: BINARY_OP(" *= ", 90, 91, 90);
- case ZEND_ASSIGN_DIV: BINARY_OP(" /= ", 90, 91, 90);
- case ZEND_ASSIGN_MOD: BINARY_OP(" %= ", 90, 91, 90);
- case ZEND_ASSIGN_SL: BINARY_OP(" <<= ", 90, 91, 90);
- case ZEND_ASSIGN_SR: BINARY_OP(" >>= ", 90, 91, 90);
- case ZEND_ASSIGN_CONCAT: BINARY_OP(" .= ", 90, 91, 90);
- case ZEND_ASSIGN_BW_OR: BINARY_OP(" |= ", 90, 91, 90);
- case ZEND_ASSIGN_BW_AND: BINARY_OP(" &= ", 90, 91, 90);
- case ZEND_ASSIGN_BW_XOR: BINARY_OP(" ^= ", 90, 91, 90);
- case ZEND_ASSIGN_POW: BINARY_OP(" **= ", 90, 91, 90);
+ case ZEND_ADD: BINARY_OP(" += ", 90, 91, 90);
+ case ZEND_SUB: BINARY_OP(" -= ", 90, 91, 90);
+ case ZEND_MUL: BINARY_OP(" *= ", 90, 91, 90);
+ case ZEND_DIV: BINARY_OP(" /= ", 90, 91, 90);
+ case ZEND_MOD: BINARY_OP(" %= ", 90, 91, 90);
+ case ZEND_SL: BINARY_OP(" <<= ", 90, 91, 90);
+ case ZEND_SR: BINARY_OP(" >>= ", 90, 91, 90);
+ case ZEND_CONCAT: BINARY_OP(" .= ", 90, 91, 90);
+ case ZEND_BW_OR: BINARY_OP(" |= ", 90, 91, 90);
+ case ZEND_BW_AND: BINARY_OP(" &= ", 90, 91, 90);
+ case ZEND_BW_XOR: BINARY_OP(" ^= ", 90, 91, 90);
+ case ZEND_POW: BINARY_OP(" **= ", 90, 91, 90);
EMPTY_SWITCH_DEFAULT_CASE();
}
break;
+ case ZEND_AST_ASSIGN_COALESCE: BINARY_OP(" \?\?= ", 90, 91, 90);
case ZEND_AST_BINARY_OP:
switch (ast->attr) {
case ZEND_ADD: BINARY_OP(" + ", 200, 200, 201);
@@ -1639,6 +1738,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_BW_OR: BINARY_OP(" | ", 140, 140, 141);
case ZEND_BW_AND: BINARY_OP(" & ", 160, 160, 161);
@@ -2003,13 +2103,3 @@ ZEND_API ZEND_COLD zend_string *zend_ast_export(const char *prefix, zend_ast *as
smart_str_0(&str);
return str.s;
}
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * indent-tabs-mode: t
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */