11<?php namespace lang \ast \emit ;
22
3- use lang \ast \nodes \Placeholder ;
3+ use lang \ast \nodes \{ Placeholder , Variable , UnpackExpression } ;
44
55/**
66 * Rewrites partial function application as follows:
77 *
88 * ```php
99 * // Input:
10- * $f= str_replace('test', result() , ?);
10+ * $f= str_replace('test', 'ok' , ?);
1111 *
12+ * // Output:
13+ * $f= fn($arg) => str_replace('test', 'ok', $arg);
14+ *
15+ * // Input:
16+ * $f= str_replace('test', result(), ?);
17+ *
1218 * // Ouput:
1319 * $f= [
14- * $a0= 'test',
15- * $a1= result(),
16- * fn($arg) => str_replace($a0, $a1, $arg)
17- * ][2];
20+ * $temp= result(),
21+ * fn($arg) => str_replace('test', $temp, $arg)
22+ * ][1];
1823 * ```
1924 *
2025 * @see https://wiki.php.net/rfc/partial_function_application_v2
@@ -23,31 +28,43 @@ trait RewritePartialFunctionApplications {
2328
2429 protected function emitCallable ($ result , $ callable ) {
2530 if ([Placeholder::$ VARIADIC ] !== $ callable ->arguments ) {
26- $ sig = $ pass = '' ;
27- $ offset = 0 ;
28- $ result ->out ->write ('[ ' );
31+ $ sig = '' ;
32+ $ pass = $ init = [];
2933 foreach ($ callable ->arguments as $ argument ) {
30- $ t = $ result ->temp ();
3134 if (Placeholder::$ VARIADIC === $ argument ) {
35+ $ t = $ result ->temp ();
3236 $ sig .= ',... ' .$ t ;
33- $ pass.= ' ,... ' . $ t ;
37+ $ pass[]= new UnpackExpression ( new Variable ( substr ( $ t , 1 ))) ;
3438 } else if (Placeholder::$ ARGUMENT === $ argument ) {
39+ $ t = $ result ->temp ();
3540 $ sig .= ', ' .$ t ;
36- $ pass .= ', ' .$ t ;
41+ $ pass []= new Variable (substr ($ t , 1 ));
42+ } else if ($ this ->isConstant ($ result , $ argument )) {
43+ $ pass []= $ argument ;
3744 } else {
38- $ pass .= ', ' .$ t ;
45+ $ t = $ result ->temp ();
46+ $ pass []= new Variable (substr ($ t , 1 ));
47+ $ init [$ t ]= $ argument ;
48+ }
49+ }
50+
51+ // Initialize any non-constant expressions in place
52+ if ($ init ) {
53+ $ result ->out ->write ('[ ' );
54+ foreach ($ init as $ t => $ argument ) {
3955 $ result ->out ->write ($ t .'= ' );
4056 $ this ->emitOne ($ result , $ argument );
4157 $ result ->out ->write (', ' );
42- $ offset ++;
4358 }
4459 }
4560
61+ // Emit closure invoking the callable expression
4662 $ result ->out ->write ('fn( ' .substr ($ sig , 1 ).')=> ' );
4763 $ this ->emitOne ($ result , $ callable ->expression );
48- $ result ->out ->write ('( ' .substr ($ pass , 1 ).') ' );
49-
50- $ result ->out ->write ('][ ' .$ offset .'] ' );
64+ $ result ->out ->write ('( ' );
65+ $ this ->emitArguments ($ result , $ pass );
66+ $ result ->out ->write (') ' );
67+ $ init && $ result ->out ->write ('][ ' .sizeof ($ init ).'] ' );
5168 } else {
5269 parent ::emitCallable ($ result , $ callable );
5370 }
0 commit comments