Skip to content

Commit

Permalink
order wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 4, 2022
1 parent 7aacbc5 commit f22e118
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 22 deletions.
66 changes: 55 additions & 11 deletions src/Latte/Compiler/TemplateParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ final class TemplateParser
/** @var array<string, callable(Tag, self): (Node|\Generator|void)> */
private array $tagParsers = [];

/** @var array<string, callable(Tag, self): (Node|\Generator|void)> */
private array $attrParsers = [];
/** @var array<string, \stdClass> */
private array $attrParsersInfo = [];

private TemplateParserHtml $html;
private ?TokenStream $stream = null;
Expand All @@ -50,18 +50,17 @@ final class TemplateParser
private $lastResolver;


/** @param array<string, callable(Tag, self): (Node|\Generator|void)> $parsers */
/** @param array<string, \stdClass|callable(Tag, self): (Node|\Generator|void)> $parsers */
public function addTags(array $parsers): static
{
foreach ($parsers as $name => $parser) {
foreach ($parsers as $name => $info) {
$info = $info instanceof \stdClass ? $info : (object) ['parser' => $info];
if (str_starts_with($name, 'n:')) {
$this->attrParsers[substr($name, 2)] = $parser;
$this->attrParsersInfo[substr($name, 2)] = $info;
} else {
$this->tagParsers[$name] = $parser;
if (Helpers::toReflection($parser)->isGenerator()) {
$this->attrParsers[$name] = $parser;
$this->attrParsers[Tag::PrefixInner . '-' . $name] = $parser;
$this->attrParsers[Tag::PrefixTag . '-' . $name] = $parser;
$this->tagParsers[$name] = $info->parser;
if ($info->generator = Helpers::toReflection($info->parser)->isGenerator()) {
$this->attrParsersInfo[$name] = $info;
}
}
}
Expand All @@ -77,7 +76,7 @@ public function addTags(array $parsers): static
public function parse(string $template, TemplateLexer $lexer): Nodes\TemplateNode
{
$this->lexer = $lexer;
$this->html = new TemplateParserHtml($this, $this->attrParsers);
$this->html = new TemplateParserHtml($this, $this->sortAttrParsers());
$this->stream = new TokenStream($lexer->tokenize($template, $this->contentType));

$headLength = 0;
Expand Down Expand Up @@ -320,6 +319,51 @@ private function getTagParser(string $name, Position $pos): callable
}


private function sortAttrParsers(): array
{
$list = $this->attrParsersInfo;

foreach ($list as $name => $info) {
if (!($info->before ?? $info->after ?? null)) {
continue;
}

unset($list[$name]);
$names = array_keys($list);
$best = null;

foreach ((array) $info->after as $target) {
if (isset($list[$target])) {
$pos = array_search($target, $names, true);
$best = min($pos - 1, $best ?? $pos);
}
}

foreach ((array) ($info->before ?? null) as $target) {
if (isset($list[$target])) {
$pos = array_search($target, $names, true);
$best = max($pos + 1, $best);
}
}

$list = array_slice($list, 0, $best, true)
+ [$name => $info]
+ array_slice($list, $best, null, true);
}

$parsers = [];
foreach ($list as $name => $info) {
$parsers[$name] = $info->parser;
if ($info->generator ?? false) {
$parsers[Tag::PrefixInner . '-' . $name] = $info->parser;
$parsers[Tag::PrefixTag . '-' . $name] = $info->parser;
}
}

return $parsers;
}


private function checkEndTag(Tag $start, ?Tag $end): void
{
if (!$end) {
Expand Down
10 changes: 5 additions & 5 deletions src/Latte/Compiler/TemplateParserHtml.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private function parseElement(): Node

$stream = $this->parser->getStream();
$void = $this->resolveVoidness($elem);
$attrs = $this->prepareNAttributes($elem->nAttributes, $void);
$attrs = $this->prepareNAttrs($elem->nAttributes, $void);
$outerNodes = $this->openNAttrNodes($attrs[Tag::PrefixNone] ?? []);
$tagNodes = $this->openNAttrNodes($attrs[Tag::PrefixTag] ?? []);
$elem->tagNode = $this->finishNAttrNodes($elem->tagNode, $tagNodes);
Expand Down Expand Up @@ -412,10 +412,10 @@ private function isClosingTag(string $name): bool
}


private function prepareNAttributes(array $attrs, bool $void): array
private function prepareNAttrs(array $attrs, bool $void): array
{
$res = [];
foreach ($this->attrParsers as $name => $parser) {
foreach ($this->attrParsers as $name => $foo) {
if ($tag = $attrs[$name] ?? null) {
$prefix = substr($name, 0, (int) strpos($name, '-'));
if (!$prefix || !$void) {
Expand Down Expand Up @@ -443,7 +443,7 @@ private function openNAttrNodes(array $toOpen): array
{
$toClose = [];
foreach ($toOpen as $tag) {
$parser = $this->getTagParser($tag->name, $tag->position);
$parser = $this->getAttrParser($tag->name, $tag->position);
$this->parser->pushTag($tag);
$res = $parser($tag, $this->parser);
if ($res instanceof \Generator && $res->valid()) {
Expand Down Expand Up @@ -484,7 +484,7 @@ private function finishNAttrNodes(AreaNode $node, array $toClose): AreaNode


/** @return callable(Tag, TemplateParser): (Node|\Generator|void) */
private function getTagParser(string $name, Position $pos): callable
private function getAttrParser(string $name, Position $pos): callable
{
if (!isset($this->attrParsers[$name])) {
$hint = ($t = Helpers::getSuggestion(array_keys($this->attrParsers), $name))
Expand Down
10 changes: 5 additions & 5 deletions src/Latte/Engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ public function compile(string $name): string
foreach ($this->extensions as $extension) {
$extension->beforeCompile($this);
$parser->addTags($extension->getTags());
foreach ($extension->getPasses() as $priority => $pass) {
$passes[] = [$pass, $priority];
foreach ($extension->getPasses() as $pass) {
$passes[] = $pass instanceof \stdClass ? $pass : (object) ['pass' => $pass];
}
}

Expand All @@ -148,9 +148,9 @@ public function compile(string $name): string

$context->setContentType($parser->getContentType());

usort($passes, fn($a, $b) => $a[1] <=> $b[1]);
foreach ($passes as [$pass]) {
$pass($node, $context);
usort($passes, fn($a, $b) => ($a->order ?? 0) <=> ($b->order ?? 0));
foreach ($passes as $pass) {
($pass->pass)($node, $context);
}

$code = $generator->generate(
Expand Down
12 changes: 12 additions & 0 deletions src/Latte/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,16 @@ public function getProviders(): array
public function beforeRender(Engine $engine): void
{
}


public static function tag($parser, array|string $before = [], array|string $after = []): \stdClass
{
return (object) get_defined_vars();
}


public static function pass($pass, int $order): \stdClass
{
return (object) get_defined_vars();
}
}
2 changes: 1 addition & 1 deletion src/Latte/Sandbox/SandboxExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function getTags(): array
public function getPasses(): array
{
return $this->policy
? [-10 => [$this, 'processPass']]
? [self::pass([$this, 'processPass'], order: -10)]
: [];
}

Expand Down

0 comments on commit f22e118

Please sign in to comment.