@@ -33,7 +33,7 @@ final class Compiler
3333 /**
3434 * Compile-time stack of block param name arrays, innermost first.
3535 * Only populated for constructs that push to $cx->blParam at runtime (currently #each).
36- * @var list<list< string> >
36+ * @var list<string[] >
3737 */
3838 private array $ blockParamValues = [];
3939
@@ -51,12 +51,15 @@ public function compile(Program $program, Context $context): string
5151 {
5252 $ this ->context = $ context ;
5353 $ this ->blockParamValues = [];
54- $ code = '' ;
54+ return $ this ->compileBody ($ program );
55+ }
5556
57+ private function compileBody (Program $ program ): string
58+ {
59+ $ code = '' ;
5660 foreach ($ program ->body as $ statement ) {
5761 $ code .= $ this ->accept ($ statement );
5862 }
59-
6063 return $ code ;
6164 }
6265
@@ -98,14 +101,7 @@ public function composePHPRender(string $code): string
98101
99102 private function compileProgram (Program $ program , bool $ withSp = false ): string
100103 {
101- $ code = '' ;
102-
103- foreach ($ program ->body as $ statement ) {
104- $ code .= $ this ->accept ($ statement );
105- }
106-
107- $ quoted = "' " . $ code . "' " ;
108-
104+ $ quoted = "' " . $ this ->compileBody ($ program ) . "' " ;
109105 return $ withSp ? "\$sp. $ quoted " : $ quoted ;
110106 }
111107
@@ -192,7 +188,7 @@ private function BlockStatement(BlockStatement $block): string
192188 // Regular section: {{#"foo"}}...{{/"foo"}}
193189 $ body = $ this ->compileProgram ($ block ->program , true );
194190 $ else = $ this ->compileElseClause ($ block );
195- return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, null , \$in, false, function( \$cx, \$in) use (& \$sp) {return $ body;} $ else " ) . ".' " ;
191+ return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, [] , \$in, false, function( \$cx, \$in) use (& \$sp) {return $ body;} $ else " ) . ".' " ;
196192 }
197193
198194 // Inverted section: {{^var}}...{{/var}}
@@ -216,6 +212,9 @@ private function BlockStatement(BlockStatement $block): string
216212
217213 private function compileDynamicBlockHelper (BlockStatement $ block ): string
218214 {
215+ if (!$ block ->program ) {
216+ throw new \Exception ('Dynamic block program must not be empty ' );
217+ }
219218 $ varPath = $ this ->compileExpression ($ block ->path );
220219 $ bp = $ block ->program ->blockParams ;
221220 $ params = $ this ->compileParams ($ block ->params , $ block ->hash , $ bp ?: null );
@@ -310,7 +309,7 @@ private function compileSection(BlockStatement $block): string
310309 return "'. " . self ::getRuntimeFunc ('hbbch ' , "\$cx, 'blockHelperMissing', [[ $ var],[]], \$in, false, function( \$cx, \$in) use (& \$sp) {return $ body;} $ else, $ escapedName " ) . ".' " ;
311310 }
312311
313- return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, null , \$in, false, function( \$cx, \$in) use (& \$sp) {return $ body;} $ else " ) . ".' " ;
312+ return "'. " . self ::getRuntimeFunc ('sec ' , "\$cx, $ var, [] , \$in, false, function( \$cx, \$in) use (& \$sp) {return $ body;} $ else " ) . ".' " ;
314313 }
315314
316315 private function compileInvertedSection (BlockStatement $ block ): string
@@ -323,8 +322,8 @@ private function compileInvertedSection(BlockStatement $block): string
323322
324323 private function compileBlockHelper (BlockStatement $ block , string $ helperName , ?string $ missingName = null ): string
325324 {
326- $ bp = $ block ->program ->blockParams ?? $ block ->inverse ->blockParams ?? null ;
327- $ params = $ this ->compileParams ($ block ->params , $ block ->hash , $ bp ?: null );
325+ $ bp = $ block ->program ->blockParams ?? $ block ->inverse ->blockParams ?? [] ;
326+ $ params = $ this ->compileParams ($ block ->params , $ block ->hash , $ bp );
328327 $ escapedName = $ missingName === null ? 'null ' : self ::quote ($ missingName );
329328
330329 if ($ block ->program === null ) {
@@ -485,7 +484,7 @@ private function MustacheStatement(MustacheStatement $mustache): string
485484 return $ this ->compileLog ($ mustache );
486485 }
487486
488- if (count ( $ mustache ->params ) !== 0 ) {
487+ if ($ mustache ->params ) {
489488 // Non-simple path with params (data var or pathed expression): invoke via dv()
490489 if ($ helperName === null ) {
491490 $ varPath = $ this ->PathExpression ($ path );
@@ -528,7 +527,7 @@ private function MustacheStatement(MustacheStatement $mustache): string
528527 return "'. " . self ::getRuntimeFunc ($ fn , $ call ) . ".' " ;
529528 }
530529
531- if (count ( $ mustache ->params ) !== 0 ) {
530+ if ($ mustache ->params ) {
532531 throw new \Exception ('Missing helper: " ' . $ literalKey . '" ' );
533532 }
534533
@@ -570,7 +569,7 @@ private function SubExpression(SubExpression $expression): string
570569
571570 // Built-in: lookup (as subexpression)
572571 if ($ helperName === 'lookup ' ) {
573- return $ this ->compileLookupExpr ($ expression ->params );
572+ return $ this ->getWithLookup ($ expression ->params [ 0 ], $ expression -> params [ 1 ] );
574573 }
575574
576575 if ($ helperName !== null ) {
@@ -861,19 +860,13 @@ private static function scopedId(PathExpression $path): bool
861860 */
862861 private function getSimpleHelperName (PathExpression |Literal $ path ): ?string
863862 {
864- if (!$ path instanceof PathExpression) {
865- return null ;
866- }
867-
868- if ($ path ->data || $ path ->depth > 0 || self ::scopedId ($ path )) {
869- return null ;
870- }
871-
872- if (count ($ path ->parts ) !== 1 ) {
873- return null ;
874- }
875-
876- if (!is_string ($ path ->parts [0 ])) {
863+ if (!$ path instanceof PathExpression
864+ || $ path ->data
865+ || $ path ->depth > 0
866+ || self ::scopedId ($ path )
867+ || count ($ path ->parts ) !== 1
868+ || !is_string ($ path ->parts [0 ])
869+ ) {
877870 return null ;
878871 }
879872
@@ -954,18 +947,11 @@ private static function quote(string $string): string
954947
955948 /**
956949 * Get string presentation for a string list
957- * @param array< string> $list
950+ * @param string[] $list
958951 */
959952 private static function listString (array $ list ): string
960953 {
961- $ string = '[ ' ;
962- foreach ($ list as $ item ) {
963- $ string .= self ::quote ($ item ) . ', ' ;
964- }
965- if ($ list ) {
966- $ string = substr ($ string , 0 , -1 );
967- }
968- return $ string . '] ' ;
954+ return '[ ' . implode (', ' , array_map (self ::quote (...), $ list )) . '] ' ;
969955 }
970956
971957 private function missValue (string $ key ): string
@@ -975,11 +961,11 @@ private function missValue(string $key): string
975961 : 'null ' ;
976962 }
977963
978- /** @return array{list< string> , string} [$bp, $bs] */
964+ /** @return array{string[] , string} [$bp, $bs] */
979965 private function getProgramBlockParams (?Program $ program ): array
980966 {
981967 $ bp = $ program ? $ program ->blockParams : [];
982- $ bs = $ bp ? self ::listString ($ bp ) : ' null ' ;
968+ $ bs = self ::listString ($ bp );
983969 return [$ bp , $ bs ];
984970 }
985971
@@ -990,7 +976,7 @@ private function compileProgramOrEmpty(?Program $program, bool $withSp = false):
990976
991977 /**
992978 * Return only the string parts of a mixed parts array, re-indexed.
993- * @param list <string|SubExpression> $parts
979+ * @param array <string|SubExpression> $parts
994980 * @return list<string>
995981 */
996982 private static function stringPartsOf (array $ parts ): array
@@ -1031,20 +1017,6 @@ private function compileLookup(MustacheStatement $mustache, bool $raw): string
10311017 return "'. " . self ::getRuntimeFunc ($ fn , $ varCode ) . ".' " ;
10321018 }
10331019
1034- /**
1035- * Compile lookup as a sub-expression argument.
1036- *
1037- * @param Expression[] $params
1038- */
1039- private function compileLookupExpr (array $ params ): string
1040- {
1041- $ itemsExpr = $ params [0 ];
1042- $ idxExpr = $ params [1 ];
1043- $ varCode = $ this ->getWithLookup ($ itemsExpr , $ idxExpr );
1044-
1045- return self ::getRuntimeFunc ('raw ' , "$ varCode, 1 " );
1046- }
1047-
10481020 /**
10491021 * Compile a path with an additional dynamic lookup segment.
10501022 */
0 commit comments