From 50e461ce26f05e1c04617a0e2bdf567334dccf7e Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Sat, 8 Feb 2020 19:31:02 -0500 Subject: [PATCH] POC alternate callback syntax This implementation parses a new callback syntax into an AST representing the traditional array/string callback AST. * `fn::Foo::method` emits `[Foo::class,'method']` - PASS! * `fn::\Foo::method` emits `[\Foo::class,'method']` - PASS! * `fn::$foo::method` emits `[$foo,'method']` - PASS! * `fn::intval` emits `"intval"`. Works for global functions. --- Zend/tests/class_name_as_scalar.phpt | 1 + Zend/tests/fn_callbacks/basic.phpt | 80 +++++++++++++++++++ .../fn_callbacks/class_name_resolution.phpt | 54 +++++++++++++ Zend/zend_language_parser.y | 39 +++++++++ 4 files changed, 174 insertions(+) create mode 100644 Zend/tests/fn_callbacks/basic.phpt create mode 100644 Zend/tests/fn_callbacks/class_name_resolution.phpt diff --git a/Zend/tests/class_name_as_scalar.phpt b/Zend/tests/class_name_as_scalar.phpt index 72a460abaae0f..581b738771e93 100644 --- a/Zend/tests/class_name_as_scalar.phpt +++ b/Zend/tests/class_name_as_scalar.phpt @@ -2,6 +2,7 @@ class name as scalar from ::class keyword --FILE-- meth; + } + } + function baz() { + return 'Foo.Bar.baz'; + } + function qux() { + return baz(); + } + + echo "Static\n"; + var_dump(fn::One::method); // resolve in namespace + var_dump(fn::\One::mEtHod); // resolve fully qualified + + echo "Dynamic\n"; + $one = new One(); + var_dump(fn::$one->meth); + var_dump($one->getThisCallback()); + var_dump($one === $one->getThisCallback()[0]); + + echo "Function\n"; + var_dump(fn::intval); + + // TODO implement name resolution + //var_dump(fn::baz); +} + +namespace { + use function Foo\Bar\baz, Foo\Bar\qux; + var_dump(fn::iNtVal); + var_dump(fn::Foo\intval); + + // TODO implement name resolution + //var_dump(fn::baz); + //var_dump(fn::qux); +} + +?> +--EXPECT-- +Static +array(2) { + [0]=> + string(11) "Foo\Bar\One" + [1]=> + string(6) "method" +} +array(2) { + [0]=> + string(3) "One" + [1]=> + string(6) "mEtHod" +} +Dynamic +array(2) { + [0]=> + object(Foo\Bar\One)#1 (0) { + } + [1]=> + string(4) "meth" +} +array(2) { + [0]=> + object(Foo\Bar\One)#1 (0) { + } + [1]=> + string(4) "meth" +} +bool(true) +Function +string(6) "intval" +string(6) "iNtVal" +string(10) "Foo\intval" diff --git a/Zend/tests/fn_callbacks/class_name_resolution.phpt b/Zend/tests/fn_callbacks/class_name_resolution.phpt new file mode 100644 index 0000000000000..86705b1afb32f --- /dev/null +++ b/Zend/tests/fn_callbacks/class_name_resolution.phpt @@ -0,0 +1,54 @@ +--TEST-- +fn:: callback with static classname +--FILE-- + +--EXPECT-- +In NS +string(11) "Foo\Bar\Moo" +Top +string(11) "Foo\Bar\One" +string(3) "Boo" +string(7) "Bee\Bop" +string(3) "Moo" +string(11) "Foo\Bar\Two" +string(11) "Foo\Bar\Two" +string(11) "Foo\Bar\One" +string(11) "Foo\Bar\Baz" +Parent +string(11) "Foo\Bar\Two" +string(13) "Foo\Bar\Three" +string(11) "Foo\Bar\One" +string(11) "Foo\Bar\Baz" diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 078c863c4ee6f..4d4d5fc52d316 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -243,6 +243,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type exit_expr scalar backticks_expr lexical_var function_call member_name property_name %type variable_class_name dereferencable_scalar constant dereferencable %type callable_expr callable_variable static_member new_variable +%type callback callback_expr %type encaps_var encaps_var_offset isset_variables %type top_statement_list use_declarations const_list inner_statement_list if_stmt %type alt_if_stmt for_exprs switch_case_list global_var_list static_var_list @@ -884,6 +885,8 @@ new_expr: expr: variable { $$ = $1; } + | callback + { $$ = $1; } | T_LIST '(' array_pair_list ')' '=' expr { $3->attr = ZEND_ARRAY_SYNTAX_LIST; $$ = zend_ast_create(ZEND_AST_ASSIGN, $3, $6); } | '[' array_pair_list ']' '=' expr @@ -1124,6 +1127,42 @@ scalar: | constant { $$ = $1; } ; +callback: + T_FN T_PAAMAYIM_NEKUDOTAYIM callback_expr { $$ = $3; } +; + +callback_expr: + T_VARIABLE T_OBJECT_OPERATOR T_STRING { + $$ = zend_ast_list_add( + zend_ast_create_list( + 1, ZEND_AST_ARRAY, + zend_ast_create( + ZEND_AST_ARRAY_ELEM, + zend_ast_create(ZEND_AST_VAR, $1), + NULL + ) + ), + zend_ast_create(ZEND_AST_ARRAY_ELEM, $3, NULL) + ); + } + | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { + $$ = zend_ast_list_add( + zend_ast_create_list( + 1, ZEND_AST_ARRAY, + zend_ast_create( + ZEND_AST_ARRAY_ELEM, + zend_ast_create(ZEND_AST_CLASS_NAME, $1), + NULL + ) + ), + zend_ast_create(ZEND_AST_ARRAY_ELEM, $3, NULL) + ); + } + | name { + $$ = $1; + } +; + constant: name { $$ = zend_ast_create(ZEND_AST_CONST, $1); } | class_name T_PAAMAYIM_NEKUDOTAYIM identifier