Skip to content

Commit a8bd2f3

Browse files
committed
RootNode
1 parent 97caf14 commit a8bd2f3

6 files changed

Lines changed: 76 additions & 26 deletions

File tree

src/Latte/Compiler/Compiler.php

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class Compiler
8181
/** @var HtmlNode|null */
8282
private $htmlNode;
8383

84-
/** @var MacroNode|null */
84+
/** @var Node|null */
8585
private $macroNode;
8686

8787
/** @var string */
@@ -173,7 +173,8 @@ private function buildClassBody(array $tokens): string
173173
$output = '';
174174
$this->output = &$output;
175175
$this->inHead = true;
176-
$this->htmlNode = $this->macroNode = $this->context = $this->paramsExtraction = null;
176+
$this->macroNode = new RootNode;
177+
$this->htmlNode = $this->context = $this->paramsExtraction = null;
177178
$this->placeholders = $this->properties = $this->constants = [];
178179
$this->methods = ['main' => null, 'prepare' => null];
179180

@@ -205,8 +206,8 @@ private function buildClassBody(array $tokens): string
205206
$this->htmlNode = $this->htmlNode->parentNode;
206207
}
207208

208-
while ($this->macroNode) {
209-
if ($this->macroNode->parentNode) {
209+
while (!$this->macroNode instanceof RootNode) {
210+
if ($this->macroNode->parentNode instanceof MacroNode) {
210211
throw new CompileException('Missing {/' . $this->macroNode->name . '}');
211212
}
212213
if (~$this->flags[$this->macroNode->name] & Macro::AUTO_CLOSE) {
@@ -280,7 +281,7 @@ public function getContentType(): string
280281
}
281282

282283

283-
public function getMacroNode(): ?MacroNode
284+
public function getMacroNode(): Node
284285
{
285286
return $this->macroNode;
286287
}
@@ -540,7 +541,7 @@ private function processHtmlAttributeBegin(Token $token): void
540541
if (isset($this->htmlNode->macroAttrs[$name])) {
541542
throw new CompileException("Found multiple attributes {$token->name}.");
542543

543-
} elseif ($this->macroNode && $this->macroNode->htmlNode === $this->htmlNode) {
544+
} elseif ($this->macroNode instanceof MacroNode && $this->macroNode->htmlNode === $this->htmlNode) {
544545
throw new CompileException("n:attribute must not appear inside tags; found {$token->name} inside {{$this->macroNode->name}}.");
545546
}
546547
$this->htmlNode->macroAttrs[$name] = $token->value;
@@ -648,7 +649,7 @@ public function closeMacro(
648649
$node = $this->macroNode;
649650

650651
if (
651-
!$node
652+
!($node instanceof MacroNode)
652653
|| ($node->name !== $name && $name !== '')
653654
|| $modifiers
654655
|| ($args !== '' && $node->args !== '' && !Helpers::startsWith($node->args . ' ', $args . ' '))
@@ -657,7 +658,7 @@ public function closeMacro(
657658
$name = $nPrefix
658659
? "</{$this->htmlNode->name}> for " . Parser::N_PREFIX . implode(' and ' . Parser::N_PREFIX, array_keys($this->htmlNode->macroAttrs))
659660
: '{/' . $name . ($args ? ' ' . $args : '') . $modifiers . '}';
660-
throw new CompileException("Unexpected $name" . ($node ? ', expecting ' . self::printEndTag($node->prefix ? $this->htmlNode : $node) : ''));
661+
throw new CompileException("Unexpected $name" . ($node instanceof MacroNode ? ', expecting ' . self::printEndTag($node->prefix ? $this->htmlNode : $node) : ''));
661662
}
662663

663664
if ($name === '') {

src/Latte/Compiler/MacroNode.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* Macro element node.
1818
*/
19-
class MacroNode
19+
class MacroNode implements Node
2020
{
2121
use Strict;
2222

@@ -37,6 +37,9 @@ class MacroNode
3737
/** @var string raw arguments */
3838
public $args;
3939

40+
/** @var Node[] */
41+
public $children = [];
42+
4043
/** @var string raw modifier */
4144
public $modifiers;
4245

@@ -49,7 +52,7 @@ class MacroNode
4952
/** @var MacroTokens */
5053
public $tokenizer;
5154

52-
/** @var MacroNode|null */
55+
/** @var Node|null */
5356
public $parentNode;
5457

5558
/** @var string */
@@ -94,7 +97,7 @@ public function __construct(
9497
string $name,
9598
string $args = '',
9699
string $modifiers = '',
97-
self $parentNode = null,
100+
Node $parentNode = null,
98101
HtmlNode $htmlNode = null,
99102
string $prefix = null
100103
) {
@@ -109,6 +112,14 @@ public function __construct(
109112
}
110113

111114

115+
public function getParentMacroNode(): ?self
116+
{
117+
return $this->parentNode instanceof self
118+
? $this->parentNode
119+
: null;
120+
}
121+
122+
112123
public function setArgs(string $args): void
113124
{
114125
$this->args = $args;
@@ -129,12 +140,12 @@ public function getNotation(): string
129140
*/
130141
public function closest(array $names, callable $condition = null): ?self
131142
{
132-
$node = $this->parentNode;
143+
$node = $this->getParentMacroNode();
133144
while ($node && (
134145
!in_array($node->name, $names, true)
135146
|| ($condition && !$condition($node))
136147
)) {
137-
$node = $node->parentNode;
148+
$node = $node->getParentMacroNode();
138149
}
139150
return $node;
140151
}
@@ -147,7 +158,7 @@ public function closest(array $names, callable $condition = null): ?self
147158
*/
148159
public function validate($arguments, array $parents = [], bool $modifiers = false): void
149160
{
150-
if ($parents && (!$this->parentNode || !in_array($this->parentNode->name, $parents, true))) {
161+
if ($parents && (!$this->getParentMacroNode() || !in_array($this->parentNode->name, $parents, true))) {
151162
throw new CompileException('Tag ' . $this->getNotation() . ' is unexpected here.');
152163

153164
} elseif ($this->modifiers !== '' && !$modifiers) {

src/Latte/Compiler/Node.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Latte (https://latte.nette.org)
5+
* Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Latte\Compiler;
11+
12+
13+
14+
interface Node
15+
{
16+
}

src/Latte/Compiler/RootNode.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Latte (https://latte.nette.org)
5+
* Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Latte\Compiler;
11+
12+
13+
14+
class RootNode implements Node
15+
{
16+
/** @var Node[] */
17+
public $children = [];
18+
}

src/Latte/Macros/BlockMacros.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ public function macroImport(MacroNode $node, PhpWriter $writer): string
206206
if ($this->getCompiler()->isInHead()) {
207207
$this->imports[] = $code;
208208
return '';
209-
} elseif ($node->parentNode && $node->parentNode->name === 'embed') {
209+
} elseif ($node->getParentMacroNode() && $node->parentNode->name === 'embed') {
210210
return "} $code if (false) {";
211211
} else {
212212
return $code;
@@ -220,7 +220,7 @@ public function macroImport(MacroNode $node, PhpWriter $writer): string
220220
public function macroExtends(MacroNode $node, PhpWriter $writer): void
221221
{
222222
$node->validate(true);
223-
if ($node->parentNode) {
223+
if ($node->getParentMacroNode()) {
224224
throw new CompileException($node->getNotation() . ' must not be inside other tags.');
225225
} elseif ($this->extends !== null) {
226226
throw new CompileException('Multiple ' . $node->getNotation() . ' declarations are not allowed.');
@@ -281,7 +281,7 @@ public function macroBlock(MacroNode $node, PhpWriter $writer)
281281
throw new CompileException("Block name must start with letter a-z, '$data->name' given.");
282282
}
283283

284-
$extendsCheck = $this->blocks[Template::LAYER_TOP] || count($this->blocks) > 1 || $node->parentNode;
284+
$extendsCheck = $this->blocks[Template::LAYER_TOP] || count($this->blocks) > 1 || $node->getParentMacroNode();
285285
$block = $this->addBlock($node, $layer);
286286

287287
$data->after = function () use ($node, $block) {
@@ -344,7 +344,7 @@ public function macroDefine(MacroNode $node, PhpWriter $writer): string
344344
}
345345
}
346346

347-
$extendsCheck = $this->blocks[Template::LAYER_TOP] || count($this->blocks) > 1 || $node->parentNode;
347+
$extendsCheck = $this->blocks[Template::LAYER_TOP] || count($this->blocks) > 1 || $node->getParentMacroNode();
348348
$block = $this->addBlock($node, $layer);
349349
$block->hasParameters = (bool) $params;
350350

src/Latte/Macros/CoreMacros.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public function macroElse(MacroNode $node, PhpWriter $writer): string
187187
}
188188
$node->validate(false, ['if', 'ifset', 'foreach', 'ifchanged', 'try', 'first', 'last', 'sep']);
189189

190-
$parent = $node->parentNode;
190+
$parent = $node->getParentMacroNode();
191191
if (isset($parent->data->else)) {
192192
throw new CompileException('Tag ' . $parent->getNotation() . ' may only contain one {else} clause.');
193193
}
@@ -220,7 +220,7 @@ public function macroElse(MacroNode $node, PhpWriter $writer): string
220220
public function macroElseIf(MacroNode $node, PhpWriter $writer): string
221221
{
222222
$node->validate(true, ['if', 'ifset']);
223-
if (isset($node->parentNode->data->else) || !empty($node->parentNode->data->capture)) {
223+
if (isset($node->getParentMacroNode()->data->else) || !empty($node->getParentMacroNode()->data->capture)) {
224224
throw new CompileException('Tag ' . $node->getNotation() . ' is unexpected here.');
225225
}
226226

@@ -547,8 +547,8 @@ public function macroBreakContinueIf(MacroNode $node, PhpWriter $writer): string
547547
}
548548
$node->validate('condition');
549549

550-
if ($node->parentNode->prefix === $node::PREFIX_NONE) {
551-
return $writer->write("if (%node.args) %node.line { echo \"</{$node->parentNode->htmlNode->name}>\\n\"; $cmd; }");
550+
if ($node->getParentMacroNode()->prefix === $node::PREFIX_NONE) {
551+
return $writer->write("if (%node.args) %node.line { echo \"</{$node->getParentMacroNode()->htmlNode->name}>\\n\"; $cmd; }");
552552
}
553553
return $writer->write("if (%node.args) %node.line $cmd;");
554554
}
@@ -651,7 +651,7 @@ public function macroDebugbreak(MacroNode $node, PhpWriter $writer): string
651651
public function macroCase(MacroNode $node, PhpWriter $writer): string
652652
{
653653
$node->validate(true, ['switch']);
654-
if (isset($node->parentNode->data->default)) {
654+
if (isset($node->getParentMacroNode()->data->default)) {
655655
throw new CompileException('Tag {default} must follow after {case} clause.');
656656
}
657657
return $writer->write('} elseif (in_array($ʟ_switch, %node.array, true)) %node.line {');
@@ -665,12 +665,16 @@ public function macroCase(MacroNode $node, PhpWriter $writer): string
665665
*/
666666
public function macroVar(MacroNode $node, PhpWriter $writer): string
667667
{
668-
if ($node->name === 'default' && $node->parentNode && $node->parentNode->name === 'switch') {
668+
if (
669+
$node->name === 'default'
670+
&& $node->getParentMacroNode()
671+
&& $node->getParentMacroNode()->name === 'switch'
672+
) {
669673
$node->validate(false, ['switch']);
670-
if (isset($node->parentNode->data->default)) {
674+
if (isset($node->getParentMacroNode()->data->default)) {
671675
throw new CompileException('Tag {switch} may only contain one {default} clause.');
672676
}
673-
$node->parentNode->data->default = true;
677+
$node->getParentMacroNode()->data->default = true;
674678
return $writer->write('} else %node.line {');
675679

676680
} elseif ($node->modifiers) {

0 commit comments

Comments
 (0)