Skip to content

Commit

Permalink
RootNode
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Feb 4, 2021
1 parent b052d76 commit a2f3e55
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 26 deletions.
17 changes: 9 additions & 8 deletions src/Latte/Compiler/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Compiler
/** @var HtmlNode|null */
private $htmlNode;

/** @var MacroNode|null */
/** @var Node|null */
private $macroNode;

/** @var string */
Expand Down Expand Up @@ -173,7 +173,8 @@ private function buildClassBody(array $tokens): string
$output = '';
$this->output = &$output;
$this->inHead = true;
$this->htmlNode = $this->macroNode = $this->context = $this->paramsExtraction = null;
$this->macroNode = new RootNode;
$this->htmlNode = $this->context = $this->paramsExtraction = null;
$this->placeholders = $this->properties = $this->constants = [];
$this->methods = ['main' => null, 'prepare' => null];

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

while ($this->macroNode) {
if ($this->macroNode->parentNode) {
while (!$this->macroNode instanceof RootNode) {
if ($this->macroNode->parentNode instanceof MacroNode) {
throw new CompileException('Missing {/' . $this->macroNode->name . '}');
}
if (~$this->flags[$this->macroNode->name] & Macro::AUTO_CLOSE) {
Expand Down Expand Up @@ -280,7 +281,7 @@ public function getContentType(): string
}


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

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

if (
!$node
!($node instanceof MacroNode)
|| ($node->name !== $name && $name !== '')
|| $modifiers
|| ($args !== '' && $node->args !== '' && !Helpers::startsWith($node->args . ' ', $args . ' '))
Expand All @@ -657,7 +658,7 @@ public function closeMacro(
$name = $nPrefix
? "</{$this->htmlNode->name}> for " . Parser::N_PREFIX . implode(' and ' . Parser::N_PREFIX, array_keys($this->htmlNode->macroAttrs))
: '{/' . $name . ($args ? ' ' . $args : '') . $modifiers . '}';
throw new CompileException("Unexpected $name" . ($node ? ', expecting ' . self::printEndTag($node->prefix ? $this->htmlNode : $node) : ''));
throw new CompileException("Unexpected $name" . ($node instanceof MacroNode ? ', expecting ' . self::printEndTag($node->prefix ? $this->htmlNode : $node) : ''));
}

if ($name === '') {
Expand Down
23 changes: 17 additions & 6 deletions src/Latte/Compiler/MacroNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/**
* Macro element node.
*/
class MacroNode
class MacroNode implements Node
{
use Strict;

Expand All @@ -37,6 +37,9 @@ class MacroNode
/** @var string raw arguments */
public $args;

/** @var Node[] */
public $children = [];

/** @var string raw modifier */
public $modifiers;

Expand All @@ -49,7 +52,7 @@ class MacroNode
/** @var MacroTokens */
public $tokenizer;

/** @var MacroNode|null */
/** @var Node|null */
public $parentNode;

/** @var string */
Expand Down Expand Up @@ -94,7 +97,7 @@ public function __construct(
string $name,
string $args = '',
string $modifiers = '',
self $parentNode = null,
Node $parentNode = null,
HtmlNode $htmlNode = null,
string $prefix = null
) {
Expand All @@ -109,6 +112,14 @@ public function __construct(
}


public function getParentMacroNode(): ?self
{
return $this->parentNode instanceof self
? $this->parentNode
: null;
}


public function setArgs(string $args): void
{
$this->args = $args;
Expand All @@ -129,12 +140,12 @@ public function getNotation(): string
*/
public function closest(array $names, callable $condition = null): ?self
{
$node = $this->parentNode;
$node = $this->getParentMacroNode();
while ($node && (
!in_array($node->name, $names, true)
|| ($condition && !$condition($node))
)) {
$node = $node->parentNode;
$node = $node->getParentMacroNode();
}
return $node;
}
Expand All @@ -147,7 +158,7 @@ public function closest(array $names, callable $condition = null): ?self
*/
public function validate($arguments, array $parents = [], bool $modifiers = false): void
{
if ($parents && (!$this->parentNode || !in_array($this->parentNode->name, $parents, true))) {
if ($parents && (!$this->getParentMacroNode() || !in_array($this->parentNode->name, $parents, true))) {
throw new CompileException('Tag ' . $this->getNotation() . ' is unexpected here.');

} elseif ($this->modifiers !== '' && !$modifiers) {
Expand Down
16 changes: 16 additions & 0 deletions src/Latte/Compiler/Node.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?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\Compiler;



interface Node
{
}
18 changes: 18 additions & 0 deletions src/Latte/Compiler/RootNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?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\Compiler;



class RootNode implements Node
{
/** @var Node[] */
public $children = [];
}
8 changes: 4 additions & 4 deletions src/Latte/Macros/BlockMacros.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public function macroImport(MacroNode $node, PhpWriter $writer): string
if ($this->getCompiler()->isInHead()) {
$this->imports[] = $code;
return '';
} elseif ($node->parentNode && $node->parentNode->name === 'embed') {
} elseif ($node->getParentMacroNode() && $node->parentNode->name === 'embed') {
return "} $code if (false) {";
} else {
return $code;
Expand All @@ -217,7 +217,7 @@ public function macroImport(MacroNode $node, PhpWriter $writer): string
public function macroExtends(MacroNode $node, PhpWriter $writer): void
{
$node->validate(true);
if ($node->parentNode) {
if ($node->getParentMacroNode()) {
throw new CompileException($node->getNotation() . ' must not be inside other tags.');
} elseif ($this->extends !== null) {
throw new CompileException('Multiple ' . $node->getNotation() . ' declarations are not allowed.');
Expand Down Expand Up @@ -276,7 +276,7 @@ public function macroBlock(MacroNode $node, PhpWriter $writer): string
throw new CompileException("Block name must start with letter a-z, '$data->name' given.");
}

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

$data->after = function () use ($node, $block) {
Expand Down Expand Up @@ -339,7 +339,7 @@ public function macroDefine(MacroNode $node, PhpWriter $writer): string
}
}

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

Expand Down
20 changes: 12 additions & 8 deletions src/Latte/Macros/CoreMacros.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public function macroElse(MacroNode $node, PhpWriter $writer): string
}
$node->validate(false, ['if', 'ifset', 'foreach', 'ifchanged', 'try', 'first', 'last', 'sep']);

$parent = $node->parentNode;
$parent = $node->getParentMacroNode();
if (isset($parent->data->else)) {
throw new CompileException('Tag ' . $parent->getNotation() . ' may only contain one {else} clause.');
}
Expand Down Expand Up @@ -220,7 +220,7 @@ public function macroElse(MacroNode $node, PhpWriter $writer): string
public function macroElseIf(MacroNode $node, PhpWriter $writer): string
{
$node->validate(true, ['if', 'ifset']);
if (isset($node->parentNode->data->else) || !empty($node->parentNode->data->capture)) {
if (isset($node->getParentMacroNode()->data->else) || !empty($node->getParentMacroNode()->data->capture)) {
throw new CompileException('Tag ' . $node->getNotation() . ' is unexpected here.');
}

Expand Down Expand Up @@ -546,8 +546,8 @@ public function macroBreakContinueIf(MacroNode $node, PhpWriter $writer): string
}
$node->validate('condition');

if ($node->parentNode->prefix === $node::PREFIX_NONE) {
return $writer->write("if (%node.args) %node.line { echo \"</{$node->parentNode->htmlNode->name}>\\n\"; $cmd; }");
if ($node->getParentMacroNode()->prefix === $node::PREFIX_NONE) {
return $writer->write("if (%node.args) %node.line { echo \"</{$node->getParentMacroNode()->htmlNode->name}>\\n\"; $cmd; }");
}
return $writer->write("if (%node.args) %node.line $cmd;");
}
Expand Down Expand Up @@ -650,7 +650,7 @@ public function macroDebugbreak(MacroNode $node, PhpWriter $writer): string
public function macroCase(MacroNode $node, PhpWriter $writer): string
{
$node->validate(true, ['switch']);
if (isset($node->parentNode->data->default)) {
if (isset($node->getParentMacroNode()->data->default)) {
throw new CompileException('Tag {default} must follow after {case} clause.');
}
return $writer->write('} elseif (in_array($ʟ_switch, %node.array, true)) %node.line {');
Expand All @@ -664,12 +664,16 @@ public function macroCase(MacroNode $node, PhpWriter $writer): string
*/
public function macroVar(MacroNode $node, PhpWriter $writer): string
{
if ($node->name === 'default' && $node->parentNode && $node->parentNode->name === 'switch') {
if (
$node->name === 'default'
&& $node->getParentMacroNode()
&& $node->getParentMacroNode()->name === 'switch'
) {
$node->validate(false, ['switch']);
if (isset($node->parentNode->data->default)) {
if (isset($node->getParentMacroNode()->data->default)) {
throw new CompileException('Tag {switch} may only contain one {default} clause.');
}
$node->parentNode->data->default = true;
$node->getParentMacroNode()->data->default = true;
return $writer->write('} else %node.line {');

} elseif ($node->modifiers) {
Expand Down

0 comments on commit a2f3e55

Please sign in to comment.