Skip to content

Commit

Permalink
{default} is evaluated lazily
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Aug 9, 2024
1 parent fca0a3e commit bd46751
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 28 deletions.
29 changes: 10 additions & 19 deletions src/Latte/Essential/Nodes/VarNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

use Latte\Compiler\Nodes\Php\Expression\AssignNode;
use Latte\Compiler\Nodes\Php\Expression\VariableNode;
use Latte\Compiler\Nodes\Php\ExpressionNode;
use Latte\Compiler\Nodes\Php\Scalar\NullNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
Expand Down Expand Up @@ -67,26 +66,18 @@ private static function parseAssignments(Tag $tag, bool $default): array
public function print(PrintContext $context): string
{
$res = [];
if ($this->default) {
foreach ($this->assignments as $assign) {
foreach ($this->assignments as $assign) {
if ($this->default) {
assert($assign->var instanceof VariableNode);
if ($assign->var->name instanceof ExpressionNode) {
$var = $assign->var->name->print($context);
} else {
$var = $context->encodeString($assign->var->name);
}
$res[] = $var . ' => ' . $assign->expr->print($context);
$res[] = $context->format(
'%node ??= array_key_exists(%raw, get_defined_vars()) ? null : %node',
$assign->var,
$context->encodeString($assign->var->name),
$assign->expr,
);
} else {
$res[] = $assign->print($context);
}

return $context->format(
'extract([%raw], EXTR_SKIP) %line;',
implode(', ', $res),
$this->position,
);
}

foreach ($this->assignments as $assign) {
$res[] = $assign->print($context);
}

return $context->format(
Expand Down
4 changes: 3 additions & 1 deletion tests/tags/expected/inheritance.1.parent.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public function prepare(): array
{
extract($this->params);

extract(['class' => null, 'namespace' => null, 'top' => true], EXTR_SKIP) /* line %d% */;
$class ??= array_key_exists('class', get_defined_vars()) ? null : null;
$namespace ??= array_key_exists('namespace', get_defined_vars()) ? null : null;
$top ??= array_key_exists('top', get_defined_vars()) ? null : true /* line 1 */;
return get_defined_vars();
}

Expand Down
37 changes: 29 additions & 8 deletions tests/tags/var.default.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,37 @@ test('{var ...}', function () use ($latte) {


test('{default ...}', function () use ($latte) {
Assert::contains("extract(['var' => null, 'var2' => null], EXTR_SKIP) /*", $latte->compile('{default $var, $var2}'));
Assert::contains("extract(['var' => 123], EXTR_SKIP) /*", $latte->compile('{default $var = 123}'));
Assert::contains("extract(['var1' => 123, 'var2' => 'nette framework'], EXTR_SKIP) /*", $latte->compile('{default $var1 = 123, $var2 = "nette framework"}'));
Assert::match(<<<'XX'
%A%
$var ??= array_key_exists('var', get_defined_vars()) ? null : null;
$var2 ??= array_key_exists('var2', get_defined_vars()) ? null : null /* line 1 */;
%A%
XX, $latte->compile('{default $var, $var2}'));

Assert::contains(
'$var ??= array_key_exists(\'var\', get_defined_vars()) ? null : 123 /* line 1 */;',
$latte->compile('{default $var = 123}'),
);

Assert::match(<<<'XX'
%A%
$var1 ??= array_key_exists('var1', get_defined_vars()) ? null : 123;
$var2 ??= array_key_exists('var2', get_defined_vars()) ? null : 'nette framework' /* line 1 */;
%A%
XX, $latte->compile('{default $var1 = 123, $var2 = "nette framework"}'));

// types
Assert::contains("extract(['var' => 123], EXTR_SKIP) /*", $latte->compile('{default null|int|string[] $var = 123}'));
Assert::contains("extract(['var1' => 123, 'var2' => 'nette framework'], EXTR_SKIP) /*", $latte->compile('{default int|string[] $var1 = 123, ?class $var2 = "nette framework"}'));
Assert::contains(
'$var ??= array_key_exists(\'var\', get_defined_vars()) ? null : 123 /* line 1 */;',
$latte->compile('{default null|int|string[] $var = 123}'),
);

Assert::match(<<<'XX'
%A%
$var1 ??= array_key_exists('var1', get_defined_vars()) ? null : 123;
$var2 ??= array_key_exists('var2', get_defined_vars()) ? null : 'nette framework' /* line 1 */;
%A%
XX, $latte->compile('{default int|string[] $var1 = 123, ?class $var2 = "nette framework"}'));

// errors
Assert::exception(
Expand All @@ -62,7 +86,4 @@ test('{default ...}', function () use ($latte) {
Latte\CompileException::class,
'Unexpected end in {default} (on line 1 at column 30)',
);

// preprocess
Assert::contains("extract(['var1' => true ? 'a' : null], EXTR_SKIP) /*", $latte->compile('{default $var1 = true ? a}'));
});

0 comments on commit bd46751

Please sign in to comment.