Skip to content

Commit

Permalink
added n:else
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Nov 9, 2023
1 parent 2d0af60 commit 8b665f9
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Latte/Essential/CoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public function getTags(): array
'ifset' => [Nodes\IfNode::class, 'create'],
'ifchanged' => [Nodes\IfChangedNode::class, 'create'],
'n:ifcontent' => [Nodes\IfContentNode::class, 'create'],
'n:else' => [Nodes\NElseNode::class, 'create'],
'switch' => [Nodes\SwitchNode::class, 'create'],
];
}
Expand Down Expand Up @@ -198,6 +199,7 @@ public function getPasses(): array
'overwrittenVariables' => [Passes::class, 'overwrittenVariablesPass'],
'customFunctions' => fn(TemplateNode $node) => Passes::customFunctionsPass($node, $this->functions),
'moveTemplatePrintToHead' => [Passes::class, 'moveTemplatePrintToHeadPass'],
'nElse' => [Nodes\NElseNode::class, 'processPass'],
];
}

Expand Down
82 changes: 82 additions & 0 deletions src/Latte/Essential/Nodes/NElseNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

/**
* This file is part of the Latte (https://latte.nette.org)
* Copyright (c) 2008 David Grudl (https://davidgrudl.com)
*/

declare(strict_types=1);

namespace Latte\Essential\Nodes;

use Latte\CompileException;
use Latte\Compiler\Node;
use Latte\Compiler\Nodes;
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\Nodes\TemplateNode;
use Latte\Compiler\NodeTraverser;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;


/**
* n:else
*/
final class NElseNode extends StatementNode
{
public AreaNode $content;


/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
public static function create(Tag $tag): \Generator
{
$node = $tag->node = new static;
[$node->content] = yield;
return $node;
}


public function print(PrintContext $context): string
{
throw new \LogicException('Cannot directly print');
}


public function &getIterator(): \Generator
{
yield $this->content;
}


public static function processPass(TemplateNode $node): void
{
(new NodeTraverser)->traverse($node, function (Node $node) {
if ($node instanceof Nodes\FragmentNode) {
for ($i = count($node->children) - 1; $i >= 0; $i--) {
$child = $node->children[$i];
if (!$child instanceof self) {
continue;
}

array_splice($node->children, $i, 1);
$prev = $node->children[--$i] ?? null;
if ($prev instanceof Nodes\TextNode && trim($prev->content) === '') {
array_splice($node->children, $i, 1);
$prev = $node->children[--$i] ?? null;
}

if (!$prev instanceof IfNode && !$prev instanceof ForeachNode && !$prev instanceof TryNode) {
throw new CompileException('n:else must be immediately after n:if / n:try / n:foreach.', $child->position);
} elseif ($prev->else) {
throw new CompileException('Multiple "else" found.', $child->position);
}

$prev->else = $child->content;
}
} elseif ($node instanceof self) {
throw new CompileException('n:else must be immediately after n:if / n:try / n:foreach.', $node->position);
}
});
}
}
142 changes: 142 additions & 0 deletions tests/tags/n-else.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

/**
* n:else
*/

declare(strict_types=1);

use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


$latte = new Latte\Engine;
$latte->setLoader(new Latte\Loaders\StringLoader);

// errors
Assert::exception(
fn() => $latte->compile('<span n:else></span>'),
Latte\CompileException::class,
'n:else must be immediately after n:if / n:try / n:foreach (on line 1 at column 7)',
);

Assert::exception(
fn() => $latte->compile('<div n:if=1>in</div> ... <span n:else></span>'),
Latte\CompileException::class,
'n:else must be immediately after n:if / n:try / n:foreach (on line 1 at column 32)',
);

Assert::exception(
fn() => $latte->compile('<div n:inner-if=1>in</div> <span n:else></span>'),
Latte\CompileException::class,
'n:else must be immediately after n:if / n:try / n:foreach (on line 1 at column 34)',
);

Assert::exception(
fn() => $latte->compile('{if true}in1{else}in2{/if} <span n:else></span>'),
Latte\CompileException::class,
'Multiple "else" found (on line 1 at column 34)',
);


// n:if & n:else
Assert::match(
<<<'XX'
begin
<div>in1</div>
end
XX,
$latte->renderToString(
<<<'XX'
begin
<div n:if=1>in1</div>
<p n:else>else</p>
end
XX,
),
);

Assert::match(
<<<'XX'
begin
<p>else</p>
end
XX,
$latte->renderToString(
<<<'XX'
begin
<div n:if=0>in1</div>
<p n:else>else</p>
end
XX,
),
);


// n:foreach & n:else
Assert::match(
<<<'XX'
begin
<div>in1</div>
end
XX,
$latte->renderToString(
<<<'XX'
begin
<div n:foreach="[1] as $x">in1</div>
<p n:else>else</p>
end
XX,
),
);

Assert::match(
<<<'XX'
begin
<p>else</p>
end
XX,
$latte->renderToString(
<<<'XX'
begin
<div n:foreach="[] as $x">in1</div>
<p n:else>else</p>
end
XX,
),
);


// n:try & n:else
Assert::match(
<<<'XX'
begin
<div>in1</div>
end
XX,
$latte->renderToString(
<<<'XX'
begin
<div n:try>in1</div>
<p n:else>else</p>
end
XX,
),
);

Assert::match(
<<<'XX'
begin
<p>else</p>
end
XX,
$latte->renderToString(
<<<'XX'
begin
<div n:try>in1 {rollback} in2</div>
<p n:else>else</p>
end
XX,
),
);

0 comments on commit 8b665f9

Please sign in to comment.