@@ -171,18 +171,18 @@ private function BlockStatement(BlockStatement $block): string
171171 if ($ this ->context ->options ->knownHelpersOnly ) {
172172 $ this ->throwKnownHelpersOnly ($ name );
173173 }
174- // Simple/Literal path: look up the key in context. Complex path: compile the full expression.
175- $ var = $ helperName !== null
176- ? $ this ->compileModeAwareLookup ('$in ' , [$ helperName ], $ helperName )
177- : $ this ->compileExpression ($ block ->path );
178- return $ this ->compileDynamicBlockHelper ($ block , $ name , $ var );
179174 }
180175
176+ // Simple/Literal path: look up the key in context. Complex path: compile the full expression.
181177 $ var = $ helperName !== null
182178 ? $ this ->compileModeAwareLookup ('$in ' , [$ helperName ], $ helperName )
183179 : $ this ->compileExpression ($ block ->path );
184- $ escapedName = self ::quote ($ name );
185180
181+ if ($ type === SexprType::Helper) {
182+ return $ this ->compileDynamicBlockHelper ($ block , $ name , $ var );
183+ }
184+
185+ $ escapedName = self ::quote ($ name );
186186 $ inverted = $ block ->program === null ;
187187 $ fnProgram = $ block ->program ?? $ block ->inverse ?? throw new \LogicException ('Inverted section must have an inverse program ' );
188188 $ blockFn = $ this ->compileProgramWithBlockParams ($ fnProgram );
@@ -192,10 +192,8 @@ private function BlockStatement(BlockStatement $block): string
192192 if (!$ inverted && !$ this ->context ->options ->knownHelpersOnly ) {
193193 $ bp = $ block ->program ->blockParams ;
194194 if ($ block ->hash !== null || $ bp ) {
195- $ params = $ this ->compileParams ([], $ block ->hash );
196- $ outerBp = $ this ->outerBlockParamsExpr ();
197195 $ helperExpr = self ::getRuntimeFunc ('resolveHelper ' , "\$cx, $ escapedName, $ var, true " );
198- return self :: buildHbbchCall ($ helperExpr , $ escapedName , $ params , $ blockFn , $ else, count ( $ bp ), $ outerBp );
196+ return $ this -> buildBlockHelperCall ($ helperExpr , $ escapedName , $ block , $ blockFn , $ else );
199197 }
200198 }
201199
@@ -234,23 +232,6 @@ private function blockParamsUseVars(): string
234232 return $ this ->blockParamValues ? '$blockParams ' : '' ;
235233 }
236234
237- /**
238- * Returns the PHP expression for the outer block param stack at the current compile-time scope.
239- * '$blockParams' when inside a bp-declaring block; '[]' otherwise (top-level for this each/helper).
240- * When returning '$blockParams', marks the current bpRefStack frame so the enclosing closure
241- * captures $blockParams via use(), even if it doesn't directly access block param values.
242- */
243- private function outerBlockParamsExpr (): string
244- {
245- if (!$ this ->blockParamValues ) {
246- return '[] ' ;
247- }
248- if ($ this ->bpRefStack ) {
249- $ this ->bpRefStack [array_key_last ($ this ->bpRefStack )] = true ;
250- }
251- return '$blockParams ' ;
252- }
253-
254235 /**
255236 * Compile a block program, pushing/popping its block params around the compilation.
256237 * Returns a PHP closure string: the signature varies based on whether the program declares or
@@ -309,12 +290,9 @@ private function compileBlockHelper(BlockStatement $block, string $name): string
309290 $ else = $ this ->compileProgramOrNull ($ block ->inverse );
310291 }
311292
312- $ outerBp = $ this ->outerBlockParamsExpr ();
313- $ params = $ this ->compileParams ($ block ->params , $ block ->hash );
314293 $ helperName = self ::quote ($ name );
315- $ bpCount = count ($ fnProgram ->blockParams );
316294
317- return self :: buildHbbchCall ("\$cx->helpers[ $ helperName] " , $ helperName , $ params , $ fn , $ else, $ bpCount , $ outerBp );
295+ return $ this -> buildBlockHelperCall ("\$cx->helpers[ $ helperName] " , $ helperName , $ block , $ fn , $ else );
318296 }
319297
320298 /**
@@ -363,16 +341,13 @@ private function compileConditionalExpr(Expression $condExpr, bool $negate): str
363341
364342 private function compileDynamicBlockHelper (BlockStatement $ block , string $ name , string $ varPath ): string
365343 {
366- $ bp = $ block ->program ->blockParams ?? [];
367- $ params = $ this ->compileParams ($ block ->params , $ block ->hash );
368344 $ blockFn = $ block ->program !== null
369345 ? $ this ->compileProgramWithBlockParams ($ block ->program )
370346 : 'null ' ;
371347 $ else = $ this ->compileProgramOrNull ($ block ->inverse );
372- $ outerBp = $ this ->outerBlockParamsExpr ();
373348 $ helperName = self ::quote ($ name );
374349 $ helperExpr = self ::getRuntimeFunc ('resolveHelper ' , "\$cx, $ helperName, $ varPath, true " );
375- return self :: buildHbbchCall ($ helperExpr , $ helperName , $ params , $ blockFn , $ else, count ( $ bp ), $ outerBp );
350+ return $ this -> buildBlockHelperCall ($ helperExpr , $ helperName , $ block , $ blockFn , $ else );
376351 }
377352
378353 private function DecoratorBlock (BlockStatement $ block ): string
@@ -837,14 +812,20 @@ private static function buildKeyAccess(array $parts): string
837812 return $ n ;
838813 }
839814
840- /**
841- * Build an hbbch call with the given helper expression.
842- * Trailing bpCount/outerBp args are omitted when both are zero/empty.
843- */
844- private static function buildHbbchCall (string $ helperExpr , string $ escapedName , string $ params , string $ blockFn , string $ else , int $ bpCount , string $ outerBp ): string
815+ private function buildBlockHelperCall (string $ helperExpr , string $ escapedName , BlockStatement $ block , string $ fn , string $ else ): string
845816 {
817+ // Mark the enclosing bp-declaring closure as needing to capture $blockParams via use().
818+ if ($ this ->blockParamValues && $ this ->bpRefStack ) {
819+ $ this ->bpRefStack [array_key_last ($ this ->bpRefStack )] = true ;
820+ }
821+ $ outerBp = $ this ->blockParamValues ? '$blockParams ' : '[] ' ;
822+ $ bpCount = count (($ block ->program ?? $ block ->inverse )->blockParams ?? []);
823+ $ params = $ this ->compileParams ($ block ->params , $ block ->hash );
824+
825+ // omit trailing bpCount/outerBp args when both are zero/empty
846826 $ trailingArgs = ($ bpCount > 0 || $ outerBp !== '[] ' ) ? ", $ bpCount, $ outerBp " : '' ;
847- return self ::getRuntimeFunc ('hbbch ' , "\$cx, $ helperExpr, $ escapedName, $ params, \$in, $ blockFn, $ else$ trailingArgs " );
827+ $ args = "\$cx, $ helperExpr, $ escapedName, $ params, \$in, $ fn, $ else " ;
828+ return self ::getRuntimeFunc ('hbbch ' , $ args . $ trailingArgs );
848829 }
849830
850831 /**
0 commit comments