From 40d42ef878fc6c05b4b749b1069ca0f44e3ce243 Mon Sep 17 00:00:00 2001 From: CHU Zhaowei Date: Mon, 26 Aug 2019 15:27:37 +0800 Subject: [PATCH 1/2] spread operator in list --- Zend/zend_compile.c | 67 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 4ac3eaa670800..3335bbb081345 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2646,6 +2646,7 @@ static void zend_compile_list_assign( zend_ast_list *list = zend_ast_get_list(ast); uint32_t i; zend_bool has_elems = 0; + zend_bool has_spread_operator = 0; zend_bool is_keyed = list->children > 0 && list->child[0] != NULL && list->child[0]->child[1] != NULL; @@ -2667,16 +2668,26 @@ static void zend_compile_list_assign( continue; } } + + if (has_spread_operator) { + zend_error(E_COMPILE_ERROR, "Cannot use positional assignment after spread operator"); + } if (elem_ast->kind == ZEND_AST_UNPACK) { - zend_error(E_COMPILE_ERROR, - "Spread operator is not supported in assignments"); + has_spread_operator = 1; + var_ast = elem_ast->child[0]; + key_ast = NULL; + } else { + var_ast = elem_ast->child[0]; + key_ast = elem_ast->child[1]; } - - var_ast = elem_ast->child[0]; - key_ast = elem_ast->child[1]; has_elems = 1; + if (has_spread_operator && is_keyed) { + zend_error(E_COMPILE_ERROR, + "Spread operator is not supported in keyed array assignments"); + } + if (is_keyed) { if (key_ast == NULL) { zend_error(E_COMPILE_ERROR, @@ -2700,6 +2711,52 @@ static void zend_compile_list_assign( zend_verify_list_assign_target(var_ast, old_style); + if (elem_ast->kind == ZEND_AST_UNPACK) { + uint32_t opnum_reset, opnum_fetch; + znode value_node, reset_node, tmp_node; + uint32_t j; + + zend_emit_op_tmp(&value_node, ZEND_INIT_ARRAY, NULL, NULL); + + opnum_reset = get_next_op_number(); + zend_emit_op(&reset_node, ZEND_FE_RESET_R, expr_node, NULL); + + for (j = 0; j op2_type = IS_VAR; + opline->op2.var = get_temporary_variable(); + //save var? + //no need to deal with jmp, since those visited indexes are guaranteed to exist. + } + + zend_begin_loop(ZEND_FE_FREE, &reset_node, 0); + + opnum_fetch = get_next_op_number(); + opline = zend_emit_op(NULL, ZEND_FE_FETCH_R, &reset_node, NULL); + opline->op2_type = IS_VAR; + opline->op2.var = get_temporary_variable(); + GET_NODE(&tmp_node, opline->op2); + + opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT, + &tmp_node, NULL); + SET_NODE(opline->result, &value_node); + + CG(zend_lineno) = ast->lineno; + zend_emit_jump(opnum_fetch); + + opline = &CG(active_op_array)->opcodes[opnum_reset]; + opline->op2.opline_num = get_next_op_number(); + + opline = &CG(active_op_array)->opcodes[opnum_fetch]; + opline->extended_value = get_next_op_number(); + + zend_end_loop(opnum_fetch, &reset_node); + + opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); + zend_emit_assign_znode(var_ast, &value_node); + continue; + } + opline = zend_emit_op(&fetch_result, elem_ast->attr ? (expr_node->op_type == IS_CV ? ZEND_FETCH_DIM_W : ZEND_FETCH_LIST_W) : ZEND_FETCH_LIST_R, expr_node, &dim_node); From 9f101fb001ff5e17cf623ae3701540706c8fb27d Mon Sep 17 00:00:00 2001 From: CHU Zhaowei Date: Mon, 21 Oct 2019 07:56:53 +0000 Subject: [PATCH 2/2] bugfix --- Zend/zend_compile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 3335bbb081345..e0caf4d398438 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2648,7 +2648,8 @@ static void zend_compile_list_assign( zend_bool has_elems = 0; zend_bool has_spread_operator = 0; zend_bool is_keyed = - list->children > 0 && list->child[0] != NULL && list->child[0]->child[1] != NULL; + list->children > 0 && list->child[0] != NULL && list->child[0]->kind != ZEND_AST_UNPACK + && list->child[0]->child[1] != NULL; if (list->children && expr_node->op_type == IS_CONST && Z_TYPE(expr_node->u.constant) == IS_STRING) { zval_make_interned_string(&expr_node->u.constant);