@@ -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
@@ -413,7 +417,7 @@ private function PartialBlockStatement(PartialBlockStatement $statement): string
413417 }
414418
415419 $ name = $ statement ->name ;
416- $ body = $ this ->compileProgram ($ statement ->program , true );
420+ $ body = $ this ->compileProgram ($ statement ->program );
417421
418422 if ($ name instanceof PathExpression) {
419423 $ partialName = $ name ->original ;
@@ -441,19 +445,18 @@ private function PartialBlockStatement(PartialBlockStatement $statement): string
441445
442446 if (!$ found ) {
443447 // Register fallback body as the partial
444- $ func = "function ( \$cx, \$in, \$ sp ) {return $ body;} " ;
448+ $ func = "function ( \$cx, \$in) {return $ body;} " ;
445449 $ this ->context ->usedPartial [$ partialName ] = '' ;
446450 $ this ->context ->partialCode [$ partialName ] = self ::quote ($ partialName ) . " => $ func " ;
447451 }
448452 }
449453
450454 $ vars = $ this ->compilePartialParams ($ statement ->params , $ statement ->hash );
451- $ sp = "'' " ;
452455
453456 return $ hoisted
454457 . "'. "
455- . self ::getRuntimeFunc ('in ' , "\$cx, '@partial-block $ pid', function( \$cx, \$in, \$ sp ) {return $ body;} " ) . ". "
456- . self ::getRuntimeFunc ('p ' , "\$cx, $ p, $ vars, $ pid, $ sp " ) . ".' " ;
458+ . self ::getRuntimeFunc ('in ' , "\$cx, '@partial-block $ pid', function( \$cx, \$in) {return $ body;} " ) . ". "
459+ . self ::getRuntimeFunc ('p ' , "\$cx, $ p, $ vars, $ pid, '' " ) . ".' " ;
457460 }
458461
459462 private function MustacheStatement (MustacheStatement $ mustache ): string
@@ -751,7 +754,8 @@ private function resolveAndCompilePartial(string $name): void
751754 return ;
752755 }
753756
754- throw new \Exception ("The partial $ name could not be found " );
757+ // Partial not found at compile time; will be resolved at runtime.
758+ $ this ->context ->usedPartial [$ name ] = '' ;
755759 }
756760
757761 /**
@@ -785,7 +789,7 @@ private function compilePartialTemplate(string $name, string $template): void
785789 $ code = (new Compiler ($ this ->parser ))->compile ($ program , $ tmpContext );
786790 $ this ->context ->merge ($ tmpContext );
787791
788- $ func = "function ( \$cx, \$in, \$ sp ) {return '$ code';} " ;
792+ $ func = "function ( \$cx, \$in) {return ' $ code';} " ;
789793 $ this ->context ->partialCode [$ name ] = self ::quote ($ name ) . " => $ func " ;
790794 }
791795
@@ -885,12 +889,12 @@ private function compileElseClause(BlockStatement $block): string
885889 * Compile a block program, pushing/popping block params around the compilation.
886890 * @param string[] $bp
887891 */
888- private function compileProgramWithBlockParams (Program $ program , array $ bp, bool $ withSp = false ): string
892+ private function compileProgramWithBlockParams (Program $ program , array $ bp ): string
889893 {
890894 if ($ bp ) {
891895 array_unshift ($ this ->blockParamValues , $ bp );
892896 }
893- $ body = $ this ->compileProgram ($ program, $ withSp );
897+ $ body = $ this ->compileProgram ($ program );
894898 if ($ bp ) {
895899 array_shift ($ this ->blockParamValues );
896900 }
@@ -967,9 +971,9 @@ private function getProgramBlockParams(?Program $program): array
967971 return [$ bp , $ bs ];
968972 }
969973
970- private function compileProgramOrEmpty (?Program $ program, bool $ withSp = false ): string
974+ private function compileProgramOrEmpty (?Program $ program ): string
971975 {
972- return $ program ? $ this ->compileProgram ($ program, $ withSp ) : "'' " ;
976+ return $ program ? $ this ->compileProgram ($ program ) : "'' " ;
973977 }
974978
975979 /**
0 commit comments