@@ -86,21 +86,25 @@ public function composePHPRender(string $code): string
8686 return function (mixed \$in = null, array \$options = []) {
8787 \$helpers = $ helpers;
8888 \$partials = [ $ partials];
89+ \$partials = array_replace( \$partials, \$options['_partials'] ?? []);
90+ foreach ( \$options['partials'] ?? [] as \$name => \$p) {
91+ \$partials[ \$name] = fn(RuntimeContext \$cx, mixed \$in) => \$p( \$in, ['_partials' => \$cx->partials, 'helpers' => \$cx->helpers, 'partialId' => \$cx->partialId]);
92+ }
8993 \$cx = new RuntimeContext(
9094 helpers: isset( \$options['helpers']) ? array_merge( \$helpers, \$options['helpers']) : \$helpers,
91- partials: isset( \$ options['partials']) ? array_merge( \$ partials, \$ options['partials']) : \$partials,
95+ partials: \$partials,
9296 data: isset( \$options['data']) ? array_merge(['root' => \$in], \$options['data']) : ['root' => \$in],
97+ partialId: \$options['partialId'] ?? 0,
9398 );
9499 \$in = & \$cx->data['root'];
95100 return ' $ code';
96101 };
97102 VAREND ;
98103 }
99104
100- private function compileProgram (Program $ program, bool $ withSp = false ): string
105+ private function compileProgram (Program $ program ): string
101106 {
102- $ quoted = "' " . $ this ->compileBody ($ program ) . "' " ;
103- return $ withSp ? "\$sp. $ quoted " : $ quoted ;
107+ return "' " . $ this ->compileBody ($ program ) . "' " ;
104108 }
105109
106110 private function accept (Node $ node ): string
@@ -184,9 +188,9 @@ private function BlockStatement(BlockStatement $block): string
184188 }
185189
186190 // Regular section: {{#"foo"}}...{{/"foo"}}
187- $ body = $ this ->compileProgram ($ block ->program , true );
191+ $ body = $ this ->compileProgram ($ block ->program );
188192 $ else = $ this ->compileElseClause ($ block );
189- return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, [], \$in, false, function( \$cx, \$in) use (& \$ sp) {return $ body;} $ else " ) . ".' " ;
193+ return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, [], \$in, false, function( \$cx, \$in) {return $ body;} $ else " ) . ".' " ;
190194 }
191195
192196 // Inverted section: {{^var}}...{{/var}}
@@ -272,11 +276,11 @@ private function compileEach(BlockStatement $block): string
272276 $ var = $ this ->compileExpression ($ block ->params [0 ]);
273277 [$ bp , $ bs ] = $ this ->getProgramBlockParams ($ block ->program );
274278
275- $ body = $ block ->program ? $ this ->compileProgramWithBlockParams ($ block ->program , $ bp, true ) : "'' " ;
279+ $ body = $ block ->program ? $ this ->compileProgramWithBlockParams ($ block ->program , $ bp ) : "'' " ;
276280 $ else = $ this ->compileElseClause ($ block );
277281
278282 $ dv = self ::getRuntimeFunc ('dv ' , "$ var, \$in " );
279- return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ dv, $ bs, \$in, true, function( \$cx, \$in) use (& \$ sp) {return $ body;} $ else " ) . ".' " ;
283+ return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ dv, $ bs, \$in, true, function( \$cx, \$in) {return $ body;} $ else " ) . ".' " ;
280284 }
281285
282286 private function compileWith (BlockStatement $ block ): string
@@ -300,14 +304,14 @@ private function compileSection(BlockStatement $block): string
300304 $ var = $ this ->compileExpression ($ block ->path );
301305 $ escapedName = $ block ->path instanceof PathExpression ? self ::quote ($ block ->path ->original ) : 'null ' ;
302306
303- $ body = $ this ->compileProgramOrEmpty ($ block ->program , true );
307+ $ body = $ this ->compileProgramOrEmpty ($ block ->program );
304308 $ else = $ this ->compileElseClause ($ block );
305309
306310 if ($ this ->resolveHelper ('blockHelperMissing ' )) {
307- return "'. " . self ::getRuntimeFunc ('hbbch ' , "\$cx, 'blockHelperMissing', [[ $ var],[]], \$in, false, function( \$cx, \$in) use (& \$ sp) {return $ body;} $ else, $ escapedName " ) . ".' " ;
311+ return "'. " . self ::getRuntimeFunc ('hbbch ' , "\$cx, 'blockHelperMissing', [[ $ var],[]], \$in, false, function( \$cx, \$in) {return $ body;} $ else, $ escapedName " ) . ".' " ;
308312 }
309313
310- return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, [], \$in, false, function( \$cx, \$in) use (& \$ sp) {return $ body;} $ else " ) . ".' " ;
314+ return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, [], \$in, false, function( \$cx, \$in) {return $ body;} $ else " ) . ".' " ;
311315 }
312316
313317 private function compileInvertedSection (BlockStatement $ block ): string
@@ -352,13 +356,13 @@ private function DecoratorBlock(BlockStatement $block): string
352356 $ partialName = $ this ->getLiteralKeyName ($ firstArg );
353357 }
354358
355- $ body = $ this ->compileProgramOrEmpty ($ block ->program , true );
359+ $ body = $ this ->compileProgramOrEmpty ($ block ->program );
356360
357361 // Register in usedPartial so {{> partialName}} can compile without error.
358362 // Do NOT add to partialCode - `in()` handles runtime registration, keeping inline partials block-scoped.
359363 $ this ->context ->usedPartial [$ partialName ] = '' ;
360364
361- return "'. " . self ::getRuntimeFunc ('in ' , "\$cx, " . self ::quote ($ partialName ) . ", function( \$cx, \$in, \$ sp ) {return $ body;} " ) . ".' " ;
365+ return "'. " . self ::getRuntimeFunc ('in ' , "\$cx, " . self ::quote ($ partialName ) . ", function( \$cx, \$in) {return $ body;} " ) . ".' " ;
362366 }
363367
364368 private function Decorator (Decorator $ decorator ): never
@@ -414,7 +418,7 @@ private function PartialBlockStatement(PartialBlockStatement $statement): string
414418 }
415419 }
416420
417- $ body = $ this ->compileProgram ($ statement ->program , true );
421+ $ body = $ this ->compileProgram ($ statement ->program );
418422 $ found = false ;
419423
420424 if ($ name instanceof PathExpression) {
@@ -443,19 +447,18 @@ private function PartialBlockStatement(PartialBlockStatement $statement): string
443447
444448 if (!$ found ) {
445449 // Register fallback body as the partial
446- $ func = "function ( \$cx, \$in, \$ sp ) {return $ body;} " ;
450+ $ func = "function ( \$cx, \$in) {return $ body;} " ;
447451 $ this ->context ->usedPartial [$ partialName ] = '' ;
448452 $ this ->context ->partialCode [$ partialName ] = self ::quote ($ partialName ) . " => $ func " ;
449453 }
450454 }
451455
452456 $ vars = $ this ->compilePartialParams ($ statement ->params , $ statement ->hash );
453- $ sp = "'' " ;
454457
455458 return $ hoisted
456459 . "'. "
457- . self ::getRuntimeFunc ('in ' , "\$cx, '@partial-block $ pid', function( \$cx, \$in, \$ sp ) {return $ body;} " ) . ". "
458- . self ::getRuntimeFunc ('p ' , "\$cx, $ p, $ vars, $ pid, $ sp " ) . ".' " ;
460+ . self ::getRuntimeFunc ('in ' , "\$cx, '@partial-block $ pid', function( \$cx, \$in) {return $ body;} " ) . ". "
461+ . self ::getRuntimeFunc ('p ' , "\$cx, $ p, $ vars, $ pid, '' " ) . ".' " ;
459462 }
460463
461464 private function MustacheStatement (MustacheStatement $ mustache ): string
@@ -753,7 +756,8 @@ private function resolveAndCompilePartial(string $name): void
753756 return ;
754757 }
755758
756- throw new \Exception ("The partial $ name could not be found " );
759+ // Partial not found at compile time; will be resolved at runtime.
760+ $ this ->context ->usedPartial [$ name ] = '' ;
757761 }
758762
759763 /**
@@ -793,7 +797,7 @@ private function compilePartialTemplate(string $name, string $template): void
793797 $ code = (new Compiler ($ this ->parser ))->compile ($ program , $ tmpContext );
794798 $ this ->context ->merge ($ tmpContext );
795799
796- $ func = "function ( \$cx, \$in, \$ sp ) {return '$ code';} " ;
800+ $ func = "function ( \$cx, \$in) {return ' $ code';} " ;
797801 $ this ->context ->partialCode [$ name ] = self ::quote ($ name ) . " => $ func " ;
798802 }
799803
@@ -893,12 +897,12 @@ private function compileElseClause(BlockStatement $block): string
893897 * Compile a block program, pushing/popping block params around the compilation.
894898 * @param string[] $bp
895899 */
896- private function compileProgramWithBlockParams (Program $ program , array $ bp, bool $ withSp = false ): string
900+ private function compileProgramWithBlockParams (Program $ program , array $ bp ): string
897901 {
898902 if ($ bp ) {
899903 array_unshift ($ this ->blockParamValues , $ bp );
900904 }
901- $ body = $ this ->compileProgram ($ program, $ withSp );
905+ $ body = $ this ->compileProgram ($ program );
902906 if ($ bp ) {
903907 array_shift ($ this ->blockParamValues );
904908 }
@@ -975,9 +979,9 @@ private function getProgramBlockParams(?Program $program): array
975979 return [$ bp , $ bs ];
976980 }
977981
978- private function compileProgramOrEmpty (?Program $ program, bool $ withSp = false ): string
982+ private function compileProgramOrEmpty (?Program $ program ): string
979983 {
980- return $ program ? $ this ->compileProgram ($ program, $ withSp ) : "'' " ;
984+ return $ program ? $ this ->compileProgram ($ program ) : "'' " ;
981985 }
982986
983987 /**
0 commit comments