diff --git a/Zend/tests/clone/ast.phpt b/Zend/tests/clone/ast.phpt index 89a1a0a481000..e482854a94482 100644 --- a/Zend/tests/clone/ast.phpt +++ b/Zend/tests/clone/ast.phpt @@ -18,6 +18,60 @@ try { echo $e->getMessage(), PHP_EOL; } +try { + assert(false && $y = clone($x, )); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone($x, [ "foo" => $foo, "bar" => $bar ])); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone($x, $array)); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone($x, $array, $extraParameter, $trailingComma, )); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone(object: $x, withProperties: [ "foo" => $foo, "bar" => $bar ])); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone($x, withProperties: [ "foo" => $foo, "bar" => $bar ])); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone(object: $x)); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone(object: $x, [ "foo" => $foo, "bar" => $bar ])); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone(...["object" => $x, "withProperties" => [ "foo" => $foo, "bar" => $bar ]])); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + try { assert(false && $y = clone(...)); } catch (Error $e) { @@ -28,4 +82,13 @@ try { --EXPECT-- assert(false && ($y = \clone($x))) assert(false && ($y = \clone($x))) +assert(false && ($y = \clone($x))) +assert(false && ($y = \clone($x, ['foo' => $foo, 'bar' => $bar]))) +assert(false && ($y = \clone($x, $array))) +assert(false && ($y = \clone($x, $array, $extraParameter, $trailingComma))) +assert(false && ($y = \clone(object: $x, withProperties: ['foo' => $foo, 'bar' => $bar]))) +assert(false && ($y = \clone($x, withProperties: ['foo' => $foo, 'bar' => $bar]))) +assert(false && ($y = \clone(object: $x))) +assert(false && ($y = \clone(object: $x, ['foo' => $foo, 'bar' => $bar]))) +assert(false && ($y = \clone(...['object' => $x, 'withProperties' => ['foo' => $foo, 'bar' => $bar]]))) assert(false && ($y = \clone(...))) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 016c6e5c9d098..127f63794db53 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -259,7 +259,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type unprefixed_use_declarations const_decl inner_statement %type expr optional_expr while_statement for_statement foreach_variable %type foreach_statement declare_statement finally_statement unset_variable variable -%type extends_from parameter optional_type_without_static argument global_var +%type extends_from parameter optional_type_without_static argument argument_no_expr global_var %type static_var class_statement trait_adaptation trait_precedence trait_alias %type absolute_trait_method_reference trait_method_reference property echo_expr %type new_dereferenceable new_non_dereferenceable anonymous_class class_name class_name_reference simple_variable @@ -287,7 +287,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type enum_declaration_statement enum_backing_type enum_case enum_case_expr %type function_name non_empty_member_modifiers %type property_hook property_hook_list optional_property_hook_list hooked_property property_hook_body -%type optional_parameter_list +%type optional_parameter_list clone_argument_list non_empty_clone_argument_list %type returns_ref function fn is_reference is_variadic property_modifiers property_hook_modifiers %type method_modifiers class_const_modifiers member_modifier optional_cpp_modifiers @@ -914,13 +914,33 @@ non_empty_argument_list: { $$ = zend_ast_list_add($1, $3); } ; -argument: - expr { $$ = $1; } - | identifier ':' expr +clone_argument_list: + '(' ')' { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } + | '(' non_empty_clone_argument_list possible_comma ')' { $$ = $2; } + | '(' expr ',' ')' { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $2); } + | '(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); } +; + +non_empty_clone_argument_list: + expr ',' argument + { $$ = zend_ast_create_list(2, ZEND_AST_ARG_LIST, $1, $3); } + | argument_no_expr + { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1); } + | non_empty_clone_argument_list ',' argument + { $$ = zend_ast_list_add($1, $3); } +; + +argument_no_expr: + identifier ':' expr { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3); } | T_ELLIPSIS expr { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } ; +argument: + expr { $$ = $1; } + | argument_no_expr { $$ = $1; } +; + global_var_list: global_var_list ',' global_var { $$ = zend_ast_list_add($1, $3); } | global_var { $$ = zend_ast_create_list(1, ZEND_AST_STMT_LIST, $1); } @@ -1228,10 +1248,10 @@ expr: { $$ = zend_ast_create(ZEND_AST_ASSIGN, $1, $3); } | variable '=' ampersand variable { $$ = zend_ast_create(ZEND_AST_ASSIGN_REF, $1, $4); } - | T_CLONE '(' T_ELLIPSIS ')' { + | T_CLONE clone_argument_list { zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE)); name->attr = ZEND_NAME_FQ; - $$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_fcc()); + $$ = zend_ast_create(ZEND_AST_CALL, name, $2); } | T_CLONE expr { zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE));