diff options
Diffstat (limited to 'Zend/zend_ast.c')
-rw-r--r-- | Zend/zend_ast.c | 152 |
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 - */ |