-
-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
), | ||
); |