@@ -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
@@ -238,23 +236,6 @@ private function blockParamsUseVars(): string
238236 return $ this ->blockParamValues ? '$blockParams ' : '' ;
239237 }
240238
241- /**
242- * Returns the PHP expression for the outer block param stack at the current compile-time scope.
243- * '$blockParams' when inside a bp-declaring block; '[]' otherwise (top-level for this each/helper).
244- * When returning '$blockParams', marks the current bpRefStack frame so the enclosing closure
245- * captures $blockParams via use(), even if it doesn't directly access block param values.
246- */
247- private function outerBlockParamsExpr (): string
248- {
249- if (!$ this ->blockParamValues ) {
250- return '[] ' ;
251- }
252- if ($ this ->bpRefStack ) {
253- $ this ->bpRefStack [array_key_last ($ this ->bpRefStack )] = true ;
254- }
255- return '$blockParams ' ;
256- }
257-
258239 /**
259240 * Compile a block program, pushing/popping its block params around the compilation.
260241 * Returns a PHP closure string: the signature varies based on whether the program declares or
@@ -313,12 +294,9 @@ private function compileBlockHelper(BlockStatement $block, string $name): string
313294 $ else = $ this ->compileProgramOrNull ($ block ->inverse );
314295 }
315296
316- $ outerBp = $ this ->outerBlockParamsExpr ();
317- $ params = $ this ->compileParams ($ block ->params , $ block ->hash );
318297 $ helperName = self ::quote ($ name );
319- $ bpCount = count ($ fnProgram ->blockParams );
320298
321- return self :: buildHbbchCall ("\$cx->helpers[ $ helperName] " , $ helperName , $ params , $ fn , $ else, $ bpCount , $ outerBp );
299+ return $ this -> buildBlockHelperCall ("\$cx->helpers[ $ helperName] " , $ helperName , $ block , $ fn , $ else );
322300 }
323301
324302 /**
@@ -367,16 +345,13 @@ private function compileConditionalExpr(Expression $condExpr, bool $negate): str
367345
368346 private function compileDynamicBlockHelper (BlockStatement $ block , string $ name , string $ varPath ): string
369347 {
370- $ bp = $ block ->program ->blockParams ?? [];
371- $ params = $ this ->compileParams ($ block ->params , $ block ->hash );
372348 $ blockFn = $ block ->program !== null
373349 ? $ this ->compileProgramWithBlockParams ($ block ->program )
374350 : 'null ' ;
375351 $ else = $ this ->compileProgramOrNull ($ block ->inverse );
376- $ outerBp = $ this ->outerBlockParamsExpr ();
377352 $ helperName = self ::quote ($ name );
378353 $ helperExpr = self ::getRuntimeFunc ('resolveHelper ' , "\$cx, $ helperName, $ varPath, true " );
379- return self :: buildHbbchCall ($ helperExpr , $ helperName , $ params , $ blockFn , $ else, count ( $ bp ), $ outerBp );
354+ return $ this -> buildBlockHelperCall ($ helperExpr , $ helperName , $ block , $ blockFn , $ else );
380355 }
381356
382357 private function DecoratorBlock (BlockStatement $ block ): string
@@ -841,14 +816,20 @@ private static function buildKeyAccess(array $parts): string
841816 return $ n ;
842817 }
843818
844- /**
845- * Build an hbbch call with the given helper expression.
846- * Trailing bpCount/outerBp args are omitted when both are zero/empty.
847- */
848- private static function buildHbbchCall (string $ helperExpr , string $ escapedName , string $ params , string $ blockFn , string $ else , int $ bpCount , string $ outerBp ): string
819+ private function buildBlockHelperCall (string $ helperExpr , string $ escapedName , BlockStatement $ block , string $ fn , string $ else ): string
849820 {
821+ // Mark the enclosing bp-declaring closure as needing to capture $blockParams via use().
822+ if ($ this ->blockParamValues && $ this ->bpRefStack ) {
823+ $ this ->bpRefStack [array_key_last ($ this ->bpRefStack )] = true ;
824+ }
825+ $ outerBp = $ this ->blockParamValues ? '$blockParams ' : '[] ' ;
826+ $ bpCount = count (($ block ->program ?? $ block ->inverse )->blockParams ?? []);
827+ $ params = $ this ->compileParams ($ block ->params , $ block ->hash );
828+
829+ // omit trailing bpCount/outerBp args when both are zero/empty
850830 $ trailingArgs = ($ bpCount > 0 || $ outerBp !== '[] ' ) ? ", $ bpCount, $ outerBp " : '' ;
851- return self ::getRuntimeFunc ('hbbch ' , "\$cx, $ helperExpr, $ escapedName, $ params, \$in, $ blockFn, $ else$ trailingArgs " );
831+ $ args = "\$cx, $ helperExpr, $ escapedName, $ params, \$in, $ fn, $ else " ;
832+ return self ::getRuntimeFunc ('hbbch ' , $ args . $ trailingArgs );
852833 }
853834
854835 /**
0 commit comments