4545 OffsetExpression ,
4646 Parameter ,
4747 PipeExpression ,
48+ Placeholder ,
4849 Property ,
4950 ReturnStatement ,
5051 ScopeExpression ,
@@ -151,15 +152,18 @@ public function __construct() {
151152 $ scope = $ left instanceof Literal ? $ parse ->scope ->resolve ($ left ->expression ) : $ left ;
152153 $ expr = $ this ->member ($ parse );
153154
155+ // Wrap self::member() into an invoke expression
154156 if ('( ' === $ parse ->token ->value ) {
155157 $ parse ->expecting ('( ' , 'invoke expression ' );
158+ [$ arguments , $ callable ]= $ this ->arguments ($ parse );
159+ $ parse ->expecting (') ' , 'invoke expression ' );
156160
157- if ($ this ->callable ($ parse )) {
158- return new CallableExpression (new ScopeExpression ($ scope , $ expr , $ token ->line ), $ token ->line );
159- }
161+ if ($ callable ) return new CallableExpression (
162+ new ScopeExpression ($ scope , $ expr , $ token ->line ),
163+ $ arguments ,
164+ $ token ->line
165+ );
160166
161- $ arguments = $ this ->arguments ($ parse );
162- $ parse ->expecting (') ' , 'invoke expression ' );
163167 $ expr = new InvokeExpression ($ expr , $ arguments , $ token ->line );
164168 }
165169
@@ -177,16 +181,14 @@ public function __construct() {
177181 });
178182
179183 $ this ->infix ('( ' , 100 , function ($ parse , $ token , $ left ) {
184+ [$ arguments , $ callable ]= $ this ->arguments ($ parse );
185+ $ parse ->expecting (') ' , 'invoke expression ' );
180186
181- // Resolve ambiguity by looking ahead: `func(...)` which is a first-class
182- // callable reference vs. `func(...$it)` - a call with an unpacked argument
183- if ( $ this -> callable ( $ parse )) {
184- return new CallableExpression ($ left , $ token ->line );
187+ if ( $ callable ) {
188+ return new CallableExpression ( $ left , $ arguments , $ token -> line );
189+ } else {
190+ return new InvokeExpression ($ left , $ arguments , $ left ->line );
185191 }
186-
187- $ arguments = $ this ->arguments ($ parse );
188- $ parse ->expecting (') ' , 'invoke expression ' );
189- return new InvokeExpression ($ left , $ arguments , $ left ->line );
190192 });
191193
192194 $ this ->infix ('[ ' , 100 , function ($ parse , $ token , $ left ) {
@@ -281,12 +283,14 @@ public function __construct() {
281283 // clone $x vs. clone($x) or clone($x, ["id" => 6100])
282284 if ('( ' === $ parse ->token ->value ) {
283285 $ parse ->forward ();
284- if ($ this ->callable ($ parse )) {
285- return new CallableExpression (new Literal ('clone ' , $ token ->line ), $ token ->line );
286- }
287-
288- $ arguments = $ this ->arguments ($ parse );
286+ [$ arguments , $ callable ]= $ this ->arguments ($ parse );
289287 $ parse ->expecting (') ' , 'clone arguments ' );
288+
289+ if ($ callable ) return new CallableExpression (
290+ new Literal ('clone ' , $ token ->line ),
291+ $ arguments ,
292+ $ token ->line
293+ );
290294 } else {
291295 $ arguments = [$ this ->expression ($ parse , 90 )];
292296 }
@@ -336,10 +340,12 @@ public function __construct() {
336340 }
337341
338342 $ parse ->expecting ('( ' , 'new arguments ' );
343+ [$ arguments , $ callable ]= $ this ->arguments ($ parse );
344+ $ parse ->expecting (') ' , 'new arguments ' );
339345
340346 // Resolve ambiguity by looking ahead: `new T(...)` which is a first-class
341347 // callable reference vs. `new T(...$it)` - a call with an unpacked argument
342- if ($ this -> callable ( $ parse ) ) {
348+ if ($ callable ) {
343349 if (null === $ type ) {
344350 $ class = $ this ->class ($ parse , null );
345351 $ class ->annotations = $ annotations ;
@@ -348,12 +354,9 @@ public function __construct() {
348354 $ new = new NewExpression ($ type , null , $ token ->line );
349355 }
350356
351- return new CallableNewExpression ($ new , $ token ->line );
357+ return new CallableNewExpression ($ new , $ arguments , $ token ->line );
352358 }
353359
354- $ arguments = $ this ->arguments ($ parse );
355- $ parse ->expecting (') ' , 'new arguments ' );
356-
357360 if (null === $ type ) {
358361 $ class = $ this ->class ($ parse , null );
359362 $ class ->annotations = $ annotations ;
@@ -1465,7 +1468,8 @@ private function annotations($parse, $context) {
14651468
14661469 if ('( ' === $ parse ->token ->value ) {
14671470 $ parse ->expecting ('( ' , $ context );
1468- $ annotations ->add (new Annotation ($ name , $ this ->arguments ($ parse ), $ parse ->token ->line ));
1471+ [$ arguments , $ callable ]= $ this ->arguments ($ parse );
1472+ $ annotations ->add (new Annotation ($ name , $ arguments , $ parse ->token ->line ));
14691473 $ parse ->expecting (') ' , $ context );
14701474 } else {
14711475 $ annotations ->add (new Annotation ($ name , [], $ parse ->token ->line ));
@@ -1722,24 +1726,9 @@ public function class($parse, $name, $comment= null, $modifiers= []) {
17221726 return $ decl ;
17231727 }
17241728
1725- public function callable ($ parse ) {
1726- if ('... ' === $ parse ->token ->value ) {
1727- $ dots = $ parse ->token ;
1728- $ parse ->forward ();
1729- if (') ' === $ parse ->token ->value ) {
1730- $ parse ->forward ();
1731- return true ;
1732- }
1733-
1734- // Not first-class callable syntax but unpack
1735- array_unshift ($ parse ->queue , $ parse ->token );
1736- $ parse ->token = $ dots ;
1737- }
1738- return false ;
1739- }
1740-
17411729 public function arguments ($ parse ) {
17421730 $ arguments = [];
1731+ $ callable = false ;
17431732 while (') ' !== $ parse ->token ->value ) {
17441733
17451734 // Named arguments (name: <argument>) vs. positional arguments
@@ -1748,14 +1737,32 @@ public function arguments($parse) {
17481737 $ parse ->forward ();
17491738 if (': ' === $ parse ->token ->value ) {
17501739 $ parse ->forward ();
1751- $ arguments [ $ token -> value ] = $ this -> expression ( $ parse , 0 ) ;
1740+ $ offset = $ token -> value ;
17521741 } else {
17531742 array_unshift ($ parse ->queue , $ parse ->token );
17541743 $ parse ->token = $ token ;
1755- $ arguments []= $ this ->expression ($ parse , 0 );
1744+ $ offset = sizeof ($ arguments );
1745+ }
1746+ } else {
1747+ $ offset = sizeof ($ arguments );
1748+ }
1749+
1750+ if ('? ' === $ parse ->token ->value ) {
1751+ $ callable = true ;
1752+ $ arguments [$ offset ]= Placeholder::$ ARGUMENT ;
1753+ $ parse ->forward ();
1754+ } else if ('... ' === $ parse ->token ->value ) {
1755+ $ parse ->forward ();
1756+
1757+ // Resolve ambiguity between unpack and variadic placeholder at the end of arguments
1758+ if (') ' === $ parse ->token ->value || ', ' === $ parse ->token ->value ) {
1759+ $ callable = true ;
1760+ $ arguments [$ offset ]= Placeholder::$ VARIADIC ;
1761+ } else {
1762+ $ arguments [$ offset ]= new UnpackExpression ($ this ->expression ($ parse , 0 ), $ parse ->token ->line );
17561763 }
17571764 } else {
1758- $ arguments []= $ this ->expression ($ parse , 0 );
1765+ $ arguments [$ offset ]= $ this ->expression ($ parse , 0 );
17591766 }
17601767
17611768 if (', ' === $ parse ->token ->value ) {
@@ -1767,7 +1774,7 @@ public function arguments($parse) {
17671774 break ;
17681775 }
17691776 }
1770- return $ arguments ;
1777+ return [ $ arguments, $ callable ] ;
17711778 }
17721779
17731780 public function expressions ($ parse , $ end ) {
0 commit comments