Skip to content

Commit 105e2d7

Browse files
committed
Simplify compiler code and tests
1 parent f72681a commit 105e2d7

4 files changed

Lines changed: 397 additions & 606 deletions

File tree

src/Compiler.php

Lines changed: 31 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ private function accept(Node $node): string
124124
$node instanceof PartialBlockStatement => $this->PartialBlockStatement($node),
125125
$node instanceof Decorator => $this->Decorator($node),
126126
$node instanceof MustacheStatement => $this->MustacheStatement($node),
127-
$node instanceof ContentStatement => $this->ContentStatement($node),
128-
$node instanceof CommentStatement => $this->CommentStatement($node),
127+
$node instanceof ContentStatement => self::quote($node->value),
128+
$node instanceof CommentStatement => '',
129129
$node instanceof SubExpression => $this->SubExpression($node),
130130
default => throw new \Exception('Unknown type: ' . (new \ReflectionClass($node))->getShortName()),
131131
};
@@ -136,11 +136,10 @@ private function compileExpression(Expression $expr): string
136136
return match (true) {
137137
$expr instanceof SubExpression => $this->SubExpression($expr),
138138
$expr instanceof PathExpression => $this->PathExpression($expr),
139-
$expr instanceof StringLiteral => $this->StringLiteral($expr),
140-
$expr instanceof NumberLiteral => $this->NumberLiteral($expr),
141-
$expr instanceof BooleanLiteral => $this->BooleanLiteral($expr),
142-
$expr instanceof NullLiteral => $this->NullLiteral($expr),
143-
$expr instanceof UndefinedLiteral => $this->UndefinedLiteral($expr),
139+
$expr instanceof StringLiteral => self::quote($expr->value),
140+
$expr instanceof NumberLiteral => (string) $expr->value,
141+
$expr instanceof BooleanLiteral => $expr->value ? 'true' : 'false',
142+
$expr instanceof NullLiteral, $expr instanceof UndefinedLiteral => 'null',
144143
default => throw new \Exception('Unknown expression type: ' . (new \ReflectionClass($expr))->getShortName()),
145144
};
146145
}
@@ -209,7 +208,7 @@ private function compileSection(BlockStatement $block, string $var, string $esca
209208
assert($block->program !== null);
210209

211210
$blockFn = $this->compileProgramWithBlockParams($block->program);
212-
$else = $this->compileElseClause($block);
211+
$else = $this->compileProgramOrNull($block->inverse);
213212

214213
if ($this->context->options->knownHelpersOnly) {
215214
return self::getRuntimeFunc('sec', "\$cx, $var, \$in, $blockFn, $else");
@@ -291,26 +290,29 @@ private function compileProgramWithBlockParams(Program $program): string
291290
private function compileBlockHelper(BlockStatement $block, string $name): string
292291
{
293292
$inverted = $block->program === null;
294-
if ($inverted) {
295-
assert($block->inverse !== null);
296-
}
297293
// For inverted blocks the fn body comes from the inverse program; for normal blocks, the program.
298-
$fnProgram = $inverted ? $block->inverse : $block->program;
294+
$fnProgram = $block->program ?? $block->inverse;
295+
assert($fnProgram !== null);
299296

300297
// Inline if/unless as ternary — eliminates hbbch dispatch and HelperOptions allocation.
301298
// Safe because if/unless don't change scope, so $cx and $in are already correct.
302299
// Negate for 'unless' in a normal block, or 'if' in an inverted block (swapped semantics).
303300
if ($this->canInlineConditional($block, $name, $fnProgram->blockParams)) {
304301
$cond = $this->compileConditionalExpr($block->params[0], $name === ($inverted ? 'if' : 'unless'));
305302
$body = $this->compileProgram($fnProgram);
306-
$elseBody = $inverted ? "''" : $this->compileProgramOrEmpty($block->inverse);
303+
$elseBody = $this->compileProgramOrEmpty($inverted ? null : $block->inverse);
307304
return "($cond ? $body : $elseBody)";
308305
}
309306

310307
$blockFn = $this->compileProgramWithBlockParams($fnProgram);
311-
[$fn, $else] = $inverted
312-
? ['null', $blockFn]
313-
: [$blockFn, $this->compileElseClause($block)];
308+
if ($inverted) {
309+
// no {{else}} clause, so there is nothing to compile for fn
310+
$fn = 'null';
311+
$else = $blockFn;
312+
} else {
313+
$fn = $blockFn;
314+
$else = $this->compileProgramOrNull($block->inverse);
315+
}
314316

315317
$outerBp = $this->outerBlockParamsExpr();
316318
$params = $this->compileParams($block->params, $block->hash);
@@ -372,7 +374,7 @@ private function compileDynamicBlockHelper(BlockStatement $block, string $name,
372374
$blockFn = $block->program !== null
373375
? $this->compileProgramWithBlockParams($block->program)
374376
: 'null';
375-
$else = $this->compileElseClause($block);
377+
$else = $this->compileProgramOrNull($block->inverse);
376378
$outerBp = $this->outerBlockParamsExpr();
377379
$helperName = self::quote($name);
378380
return self::getRuntimeFunc('dynhbbch', "\$cx, $helperName, $varPath, $params, \$in, $blockFn, $else, " . count($bp) . ", $outerBp");
@@ -385,7 +387,7 @@ private function DecoratorBlock(BlockStatement $block): string
385387
if ($helperName !== 'inline') {
386388
throw new \Exception('Unknown decorator: "' . $helperName . '"');
387389
} elseif (!$block->params) {
388-
$partialName = 'undefined';
390+
$partialName = 'undefined'; // match JS for {{#*inline}} without a name (params[0] on empty array is undefined)
389391
} else {
390392
$firstArg = $block->params[0];
391393
if (!$firstArg instanceof Literal) {
@@ -556,16 +558,6 @@ private function MustacheStatement(MustacheStatement $mustache): string
556558
return self::getRuntimeFunc($fn, "\$in[$escapedKey] ?? $miss");
557559
}
558560

559-
private function ContentStatement(ContentStatement $statement): string
560-
{
561-
return self::quote($statement->value);
562-
}
563-
564-
private function CommentStatement(CommentStatement $statement): string
565-
{
566-
return '';
567-
}
568-
569561
// ── Expressions ─────────────────────────────────────────────────
570562

571563
private function SubExpression(SubExpression $expression): string
@@ -604,7 +596,8 @@ private function PathExpression(PathExpression $expression): string
604596
$stringParts = $expression->tail;
605597
} else {
606598
$base = $this->buildBasePath($data, $depth);
607-
$stringParts = self::stringPartsOf($parts);
599+
/** @var string[] $parts */
600+
$stringParts = $parts;
608601
}
609602

610603
// `this` with no parts or empty parts
@@ -652,31 +645,6 @@ private function PathExpression(PathExpression $expression): string
652645
return $this->compileModeAwareLookup($base, $stringParts, $expression->original, $miss);
653646
}
654647

655-
private function StringLiteral(StringLiteral $literal): string
656-
{
657-
return self::quote($literal->value);
658-
}
659-
660-
private function NumberLiteral(NumberLiteral $literal): string
661-
{
662-
return (string) $literal->value;
663-
}
664-
665-
private function BooleanLiteral(BooleanLiteral $literal): string
666-
{
667-
return $literal->value ? 'true' : 'false';
668-
}
669-
670-
private function UndefinedLiteral(UndefinedLiteral $literal): string
671-
{
672-
return 'null';
673-
}
674-
675-
private function NullLiteral(NullLiteral $literal): string
676-
{
677-
return 'null';
678-
}
679-
680648
/**
681649
* Get the string key name for a literal used in path (mustache/block) position.
682650
* e.g. {{12}} looks up $in['12'], {{"foo bar"}} looks up $in['foo bar'], {{true}} looks up $in['true'].
@@ -848,18 +816,6 @@ private function getSimpleHelperName(PathExpression|Literal $path): ?string
848816
return $path->parts[0];
849817
}
850818

851-
/**
852-
* Compile the else/inverse clause of a block as a trailing closure argument, or 'null' if absent.
853-
*/
854-
private function compileElseClause(BlockStatement $block): string
855-
{
856-
if (!$block->inverse) {
857-
$this->lastCompileProgramHadDirectBpRef = false;
858-
return 'null';
859-
}
860-
return $this->compileProgramWithBlockParams($block->inverse);
861-
}
862-
863819
/**
864820
* Build the base path expression for a given data flag and depth.
865821
*/
@@ -929,6 +885,15 @@ private function missValue(string $key): string
929885
: 'null';
930886
}
931887

888+
private function compileProgramOrNull(?Program $program): string
889+
{
890+
if (!$program) {
891+
$this->lastCompileProgramHadDirectBpRef = false;
892+
return 'null';
893+
}
894+
return $this->compileProgramWithBlockParams($program);
895+
}
896+
932897
private function compileProgramOrEmpty(?Program $program): string
933898
{
934899
if (!$program) {
@@ -986,14 +951,4 @@ private function buildInlineHelperCall(string $name, array $params, ?Hash $hash)
986951
}
987952
return self::getRuntimeFunc('dynhbch', "\$cx, $helperName, $compiledParams, \$in");
988953
}
989-
990-
/**
991-
* Return only the string parts of a mixed parts array, re-indexed.
992-
* @param array<string|SubExpression> $parts
993-
* @return list<string>
994-
*/
995-
private static function stringPartsOf(array $parts): array
996-
{
997-
return array_values(array_filter($parts, fn($p) => is_string($p)));
998-
}
999954
}

0 commit comments

Comments
 (0)