@vituum/vite-plugin-latte 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/index.js +2 -2
  2. package/latte/PlaceholderFunction.php +2 -2
  3. package/package.json +10 -11
  4. package/vendor/autoload.php +18 -0
  5. package/vendor/bin/latte-lint +16 -4
  6. package/vendor/composer/ClassLoader.php +72 -65
  7. package/vendor/composer/InstalledVersions.php +21 -12
  8. package/vendor/composer/autoload_classmap.php +14 -8
  9. package/vendor/composer/autoload_namespaces.php +1 -1
  10. package/vendor/composer/autoload_psr4.php +1 -1
  11. package/vendor/composer/autoload_real.php +3 -22
  12. package/vendor/composer/autoload_static.php +13 -7
  13. package/vendor/composer/installed.json +8 -8
  14. package/vendor/composer/installed.php +10 -10
  15. package/vendor/latte/latte/bin/latte-lint +8 -2
  16. package/vendor/latte/latte/composer.json +1 -1
  17. package/vendor/latte/latte/readme.md +6 -6
  18. package/vendor/latte/latte/src/Bridges/Tracy/BlueScreenPanel.php +1 -0
  19. package/vendor/latte/latte/src/Bridges/Tracy/LattePanel.php +3 -2
  20. package/vendor/latte/latte/src/Latte/Compiler/Block.php +0 -3
  21. package/vendor/latte/latte/src/Latte/Compiler/Escaper.php +113 -89
  22. package/vendor/latte/latte/src/Latte/Compiler/ExpressionBuilder.php +2 -1
  23. package/vendor/latte/latte/src/Latte/Compiler/Node.php +0 -4
  24. package/vendor/latte/latte/src/Latte/Compiler/NodeHelpers.php +0 -4
  25. package/vendor/latte/latte/src/Latte/Compiler/NodeTraverser.php +0 -4
  26. package/vendor/latte/latte/src/Latte/Compiler/Nodes/AuxiliaryNode.php +11 -3
  27. package/vendor/latte/latte/src/Latte/Compiler/Nodes/FragmentNode.php +10 -0
  28. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/AttributeNode.php +22 -4
  29. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/ElementNode.php +35 -12
  30. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArgumentNode.php +6 -0
  31. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ArrayItemNode.php +12 -0
  32. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ArrayNode.php +4 -31
  33. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignNode.php +15 -1
  34. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AssignOpNode.php +11 -0
  35. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/AuxiliaryNode.php +42 -0
  36. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClassConstantFetchNode.php +2 -2
  37. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ClosureNode.php +1 -1
  38. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/ConstantFetchNode.php +8 -0
  39. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/IssetNode.php +15 -1
  40. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PostOpNode.php +11 -0
  41. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/PreOpNode.php +11 -0
  42. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/{StaticCallNode.php → StaticMethodCallNode.php} +11 -1
  43. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/{StaticCallableNode.php → StaticMethodCallableNode.php} +11 -1
  44. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Expression/TemporaryNode.php +38 -0
  45. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ExpressionNode.php +24 -0
  46. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/FilterNode.php +1 -1
  47. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ListItemNode.php +48 -0
  48. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ListNode.php +56 -0
  49. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php +5 -5
  50. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/NameNode.php +11 -21
  51. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Php/Scalar/InterpolatedStringNode.php +1 -8
  52. package/vendor/latte/latte/src/Latte/Compiler/PhpHelpers.php +30 -0
  53. package/vendor/latte/latte/src/Latte/Compiler/Position.php +4 -8
  54. package/vendor/latte/latte/src/Latte/Compiler/PrintContext.php +15 -8
  55. package/vendor/latte/latte/src/Latte/Compiler/Tag.php +13 -14
  56. package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +5 -9
  57. package/vendor/latte/latte/src/Latte/Compiler/TagParser.php +52 -3
  58. package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +353 -326
  59. package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +6 -5
  60. package/vendor/latte/latte/src/Latte/Compiler/TemplateLexer.php +105 -178
  61. package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +40 -33
  62. package/vendor/latte/latte/src/Latte/Compiler/TemplateParserHtml.php +186 -126
  63. package/vendor/latte/latte/src/Latte/Compiler/Token.php +5 -9
  64. package/vendor/latte/latte/src/Latte/Compiler/TokenStream.php +6 -22
  65. package/vendor/latte/latte/src/Latte/Engine.php +136 -95
  66. package/vendor/latte/latte/src/Latte/Essential/AuxiliaryIterator.php +46 -0
  67. package/vendor/latte/latte/src/Latte/Essential/Blueprint.php +42 -27
  68. package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +0 -4
  69. package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +81 -66
  70. package/vendor/latte/latte/src/Latte/Essential/Filters.php +103 -43
  71. package/vendor/latte/latte/src/Latte/Essential/Nodes/BlockNode.php +1 -2
  72. package/vendor/latte/latte/src/Latte/Essential/Nodes/CaptureNode.php +2 -13
  73. package/vendor/latte/latte/src/Latte/Essential/Nodes/ContentTypeNode.php +8 -1
  74. package/vendor/latte/latte/src/Latte/Essential/Nodes/DefineNode.php +1 -2
  75. package/vendor/latte/latte/src/Latte/Essential/Nodes/EmbedNode.php +1 -1
  76. package/vendor/latte/latte/src/Latte/Essential/Nodes/ExtendsNode.php +0 -3
  77. package/vendor/latte/latte/src/Latte/Essential/Nodes/FirstLastSepNode.php +1 -1
  78. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForNode.php +1 -1
  79. package/vendor/latte/latte/src/Latte/Essential/Nodes/ForeachNode.php +40 -13
  80. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfChangedNode.php +1 -1
  81. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfContentNode.php +4 -1
  82. package/vendor/latte/latte/src/Latte/Essential/Nodes/IfNode.php +5 -3
  83. package/vendor/latte/latte/src/Latte/Essential/Nodes/IncludeBlockNode.php +5 -2
  84. package/vendor/latte/latte/src/Latte/Essential/Nodes/IterateWhileNode.php +6 -4
  85. package/vendor/latte/latte/src/Latte/Essential/Nodes/JumpNode.php +26 -23
  86. package/vendor/latte/latte/src/Latte/Essential/Nodes/NElseNode.php +88 -0
  87. package/vendor/latte/latte/src/Latte/Essential/Nodes/NTagNode.php +20 -28
  88. package/vendor/latte/latte/src/Latte/Essential/Nodes/PrintNode.php +7 -12
  89. package/vendor/latte/latte/src/Latte/Essential/Nodes/RollbackNode.php +1 -1
  90. package/vendor/latte/latte/src/Latte/Essential/Nodes/SpacelessNode.php +1 -1
  91. package/vendor/latte/latte/src/Latte/Essential/Nodes/SwitchNode.php +1 -1
  92. package/vendor/latte/latte/src/Latte/Essential/Nodes/TemplatePrintNode.php +25 -3
  93. package/vendor/latte/latte/src/Latte/Essential/Nodes/TranslateNode.php +1 -1
  94. package/vendor/latte/latte/src/Latte/Essential/Nodes/TryNode.php +3 -4
  95. package/vendor/latte/latte/src/Latte/Essential/Nodes/VarPrintNode.php +9 -2
  96. package/vendor/latte/latte/src/Latte/Essential/Nodes/WhileNode.php +1 -1
  97. package/vendor/latte/latte/src/Latte/Essential/Passes.php +16 -58
  98. package/vendor/latte/latte/src/Latte/Essential/RawPhpExtension.php +0 -2
  99. package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +6 -1
  100. package/vendor/latte/latte/src/Latte/Helpers.php +3 -1
  101. package/vendor/latte/latte/src/Latte/Loader.php +1 -0
  102. package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +1 -4
  103. package/vendor/latte/latte/src/Latte/Loaders/StringLoader.php +0 -2
  104. package/vendor/latte/latte/src/Latte/PositionAwareException.php +1 -1
  105. package/vendor/latte/latte/src/Latte/Runtime/Block.php +0 -4
  106. package/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php +43 -51
  107. package/vendor/latte/latte/src/Latte/Runtime/FilterInfo.php +0 -2
  108. package/vendor/latte/latte/src/Latte/Runtime/Filters.php +64 -33
  109. package/vendor/latte/latte/src/Latte/Runtime/FunctionExecutor.php +68 -0
  110. package/vendor/latte/latte/src/Latte/Runtime/Html.php +0 -4
  111. package/vendor/latte/latte/src/Latte/Runtime/Template.php +3 -5
  112. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +2 -1
  113. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/MethodCallNode.php +1 -1
  114. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/SandboxNode.php +3 -3
  115. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/{StaticCallNode.php → StaticMethodCallNode.php} +3 -3
  116. package/vendor/latte/latte/src/Latte/Sandbox/Nodes/{StaticCallableNode.php → StaticMethodCallableNode.php} +2 -2
  117. package/vendor/latte/latte/src/Latte/Sandbox/RuntimeChecker.php +0 -2
  118. package/vendor/latte/latte/src/Latte/Sandbox/SandboxExtension.php +11 -9
  119. package/vendor/latte/latte/src/Latte/Sandbox/SecurityPolicy.php +0 -2
  120. package/vendor/latte/latte/src/Latte/exceptions.php +2 -11
  121. package/vendor/latte/latte/src/Tools/Linter.php +13 -37
  122. package/vendor/latte/latte/src/Latte/Compiler/Nodes/Html/QuotedValue.php +0 -53
  123. package/vendor/latte/latte/src/Latte/Strict.php +0 -101
@@ -9,16 +9,12 @@ declare(strict_types=1);
9
9
 
10
10
  namespace Latte\Compiler;
11
11
 
12
- use Latte;
13
-
14
12
 
15
13
  final class Position
16
14
  {
17
- use Latte\Strict;
18
-
19
15
  public function __construct(
20
- public /*readonly*/ int $line,
21
- public /*readonly*/ int $column,
16
+ public /*readonly*/ int $line = 1,
17
+ public /*readonly*/ int $column = 1,
22
18
  public /*readonly*/ int $offset = 0,
23
19
  ) {
24
20
  }
@@ -42,8 +38,8 @@ final class Position
42
38
  }
43
39
 
44
40
 
45
- public function toWords(): string
41
+ public function __toString(): string
46
42
  {
47
- return "on line $this->line at column $this->column";
43
+ return "on line $this->line" . ($this->column ? " at column $this->column" : '');
48
44
  }
49
45
  }
@@ -9,7 +9,6 @@ declare(strict_types=1);
9
9
 
10
10
  namespace Latte\Compiler;
11
11
 
12
- use Latte;
13
12
  use Latte\Compiler\Nodes\Php as Nodes;
14
13
  use Latte\Compiler\Nodes\Php\Expression;
15
14
  use Latte\Compiler\Nodes\Php\Scalar;
@@ -22,8 +21,6 @@ use Latte\ContentType;
22
21
  */
23
22
  final class PrintContext
24
23
  {
25
- use Latte\Strict;
26
-
27
24
  public array $paramsExtraction = [];
28
25
  public array $blocks = [];
29
26
 
@@ -105,7 +102,7 @@ final class PrintContext
105
102
  function ($m) use ($args) {
106
103
  [, $pos, $fn, $var] = $m;
107
104
  $var = substr($var, 1, -1);
108
- /** @var Nodes\FilterNode[] $args */
105
+ /** @var Nodes\ModifierNode[] $args */
109
106
  return match ($fn) {
110
107
  'modify' => $args[$pos]->printSimple($this, $var),
111
108
  'modifyContent' => $args[$pos]->printContentAware($this, $var),
@@ -298,8 +295,8 @@ final class PrintContext
298
295
  || $expr instanceof Expression\FunctionCallableNode
299
296
  || $expr instanceof Expression\MethodCallNode
300
297
  || $expr instanceof Expression\MethodCallableNode
301
- || $expr instanceof Expression\StaticCallNode
302
- || $expr instanceof Expression\StaticCallableNode
298
+ || $expr instanceof Expression\StaticMethodCallNode
299
+ || $expr instanceof Expression\StaticMethodCallableNode
303
300
  || $expr instanceof Expression\ArrayNode
304
301
  ? $expr->print($this)
305
302
  : '(' . $expr->print($this) . ')';
@@ -320,8 +317,8 @@ final class PrintContext
320
317
  || $expr instanceof Expression\FunctionCallableNode
321
318
  || $expr instanceof Expression\MethodCallNode
322
319
  || $expr instanceof Expression\MethodCallableNode
323
- || $expr instanceof Expression\StaticCallNode
324
- || $expr instanceof Expression\StaticCallableNode
320
+ || $expr instanceof Expression\StaticMethodCallNode
321
+ || $expr instanceof Expression\StaticMethodCallableNode
325
322
  || $expr instanceof Expression\ArrayNode
326
323
  || $expr instanceof Scalar\StringNode
327
324
  || $expr instanceof Scalar\BooleanNode
@@ -331,4 +328,14 @@ final class PrintContext
331
328
  ? $expr->print($this)
332
329
  : '(' . $expr->print($this) . ')';
333
330
  }
331
+
332
+
333
+ /**
334
+ * @param Nodes\ArgumentNode[] $args
335
+ */
336
+ public function argumentsAsArray(array $args): string
337
+ {
338
+ $items = array_map(fn(Nodes\ArgumentNode $arg) => $arg->toArrayItem(), $args);
339
+ return '[' . $this->implode($items) . ']';
340
+ }
334
341
  }
@@ -9,8 +9,8 @@ declare(strict_types=1);
9
9
 
10
10
  namespace Latte\Compiler;
11
11
 
12
- use Latte;
13
12
  use Latte\CompileException;
13
+ use Latte\Compiler\Nodes\AreaNode;
14
14
  use Latte\Compiler\Nodes\Html\ElementNode;
15
15
 
16
16
 
@@ -19,8 +19,6 @@ use Latte\Compiler\Nodes\Html\ElementNode;
19
19
  */
20
20
  final class Tag
21
21
  {
22
- use Latte\Strict;
23
-
24
22
  public const
25
23
  PrefixInner = 'inner',
26
24
  PrefixTag = 'tag',
@@ -41,26 +39,27 @@ final class Tag
41
39
  public /*readonly*/ Position $position,
42
40
  public /*readonly*/ bool $void = false,
43
41
  public /*readonly*/ bool $closing = false,
44
- public /*readonly*/ int $location = 0,
42
+ public /*readonly*/ bool $inHead = false,
43
+ public /*readonly*/ bool $inTag = false,
45
44
  public /*readonly*/ ?ElementNode $htmlElement = null,
46
45
  public ?self $parent = null,
47
46
  public /*readonly*/ ?string $prefix = null,
48
- public ?\stdClass $data = null,
47
+ public ?AreaNode $node = null,
48
+ public ?AreaNode $nAttributeNode = null,
49
49
  ) {
50
- $this->data ??= new \stdClass;
51
50
  $this->parser = new TagParser($tokens);
52
51
  }
53
52
 
54
53
 
55
54
  public function isInHead(): bool
56
55
  {
57
- return $this->location === TemplateParser::LocationHead && !$this->parent;
56
+ return $this->inHead && !$this->parent;
58
57
  }
59
58
 
60
59
 
61
60
  public function isInText(): bool
62
61
  {
63
- return $this->location <= TemplateParser::LocationText;
62
+ return !$this->inTag;
64
63
  }
65
64
 
66
65
 
@@ -85,13 +84,13 @@ final class Tag
85
84
 
86
85
 
87
86
  /**
88
- * @param string[] $names
87
+ * @param class-string[] $classes
89
88
  */
90
- public function closestTag(array $names, ?callable $condition = null): ?self
89
+ public function closestTag(array $classes, ?callable $condition = null): ?self
91
90
  {
92
91
  $tag = $this->parent;
93
92
  while ($tag && (
94
- !in_array($tag->name, $names, true)
93
+ (!in_array($tag->node ? $tag->node::class : null, $classes, true) && !in_array($tag->name, $classes, true))
95
94
  || ($condition && !$condition($tag))
96
95
  )) {
97
96
  $tag = $tag->parent;
@@ -109,9 +108,9 @@ final class Tag
109
108
  }
110
109
 
111
110
 
112
- public function replaceNAttribute(Node $node): void
111
+ public function replaceNAttribute(AreaNode $node): void
113
112
  {
114
- $index = array_search($this->data->node, $this->htmlElement->attributes->children, true);
115
- $this->htmlElement->attributes->children[$index] = $node;
113
+ $index = array_search($this->nAttributeNode, $this->htmlElement->attributes->children, true);
114
+ $this->htmlElement->attributes->children[$index] = $this->nAttributeNode = $node;
116
115
  }
117
116
  }
@@ -9,9 +9,7 @@ declare(strict_types=1);
9
9
 
10
10
  namespace Latte\Compiler;
11
11
 
12
- use Latte;
13
12
  use Latte\CompileException;
14
- use Latte\RegexpException;
15
13
 
16
14
 
17
15
  /**
@@ -19,8 +17,6 @@ use Latte\RegexpException;
19
17
  */
20
18
  final class TagLexer
21
19
  {
22
- use Latte\Strict;
23
-
24
20
  private const Keywords = [
25
21
  'and' => Token::Php_LogicalAnd,
26
22
  'array' => Token::Php_Array,
@@ -57,7 +53,7 @@ final class TagLexer
57
53
  /** @return Token[] */
58
54
  public function tokenize(string $input, ?Position $position = null): array
59
55
  {
60
- $position ??= new Position(1, 1, 0);
56
+ $position ??= new Position;
61
57
  $this->tokens = $this->tokenizePartially($input, $position, 0);
62
58
  if ($this->offset !== strlen($input)) {
63
59
  $token = str_replace("\n", '\n', substr($input, $this->offset, 10));
@@ -86,8 +82,8 @@ final class TagLexer
86
82
  {
87
83
  preg_match(
88
84
  $colon
89
- ? '~ ( [./@_a-z0-9#!-] | :(?!:) | \{\$ [_a-z0-9\[\]()>-]+ })++ (?=\s+[!"\'$(\[{,\\|\~\w-] | [,|] | \s*$) ~xAi'
90
- : '~ ( [./@_a-z0-9#!-] | \{\$ [_a-z0-9\[\]()>-]+ })++ (?=\s+[!"\'$(\[{,\\|\~\w-] | [,:|] | \s*$) ~xAi',
85
+ ? '~ ( [./@_a-z0-9#!-] | :(?!:) | \{\$ [_a-z0-9\[\]()>-]+ })++ (?=\s+[!"\'$(\[{,\\\\|\~\w-] | [,|] | \s*$) ~xAi'
86
+ : '~ ( [./@_a-z0-9#!-] | \{\$ [_a-z0-9\[\]()>-]+ })++ (?=\s+[!"\'$(\[{,\\\\|\~\w-] | [,:|] | \s*$) ~xAi',
91
87
  $input,
92
88
  $match,
93
89
  offset: $position->offset - $offsetDelta,
@@ -185,7 +181,7 @@ final class TagLexer
185
181
  matchRE:
186
182
  preg_match_all($re, $this->input, $matches, PREG_SET_ORDER | PREG_UNMATCHED_AS_NULL, $this->offset);
187
183
  if (preg_last_error()) {
188
- throw new RegexpException;
184
+ throw new CompileException(preg_last_error_msg());
189
185
  }
190
186
 
191
187
  foreach ($matches as $m) {
@@ -330,7 +326,7 @@ final class TagLexer
330
326
  matchRE:
331
327
  preg_match_all($re, $this->input, $matches, PREG_SET_ORDER | PREG_UNMATCHED_AS_NULL, $this->offset);
332
328
  if (preg_last_error()) {
333
- throw new RegexpException;
329
+ throw new CompileException(preg_last_error_msg());
334
330
  }
335
331
 
336
332
  $buffer = '';
@@ -10,6 +10,7 @@ declare(strict_types=1);
10
10
  namespace Latte\Compiler;
11
11
 
12
12
  use Latte;
13
+ use Latte\CompileException;
13
14
  use Latte\Compiler\Nodes\Php as Node;
14
15
  use Latte\Compiler\Nodes\Php\Expression;
15
16
  use Latte\Compiler\Nodes\Php\ExpressionNode;
@@ -23,17 +24,19 @@ use Latte\Compiler\Nodes\Php\Scalar;
23
24
  */
24
25
  final class TagParser extends TagParserData
25
26
  {
26
- use Latte\Strict;
27
-
28
27
  private const
29
28
  SchemaExpression = 'e',
30
29
  SchemaArguments = 'a',
31
- SchemaFilters = 'm';
30
+ SchemaFilters = 'm',
31
+ SchemaForeach = 'f';
32
32
 
33
33
  private const SymbolNone = -1;
34
34
 
35
35
  public TokenStream /*readonly*/ $stream;
36
36
  public string $text;
37
+
38
+ /** @var \SplObjectStorage<Expression\ArrayNode> */
39
+ protected \SplObjectStorage $shortArrays;
37
40
  private int /*readonly*/ $offsetDelta;
38
41
 
39
42
 
@@ -116,6 +119,16 @@ final class TagParser extends TagParserData
116
119
  }
117
120
 
118
121
 
122
+ /**
123
+ * Parses variables used in foreach.
124
+ * @internal
125
+ */
126
+ public function parseForeach(): array
127
+ {
128
+ return $this->parse(self::SchemaForeach);
129
+ }
130
+
131
+
119
132
  /**
120
133
  * Consumes optional token followed by whitespace. Suitable before parseUnquotedStringOrExpression().
121
134
  */
@@ -152,6 +165,7 @@ final class TagParser extends TagParserData
152
165
  $stateStack = [$state];
153
166
  $this->semStack = []; // Semantic value stack (contains values of tokens and semantic action results)
154
167
  $stackPos = 0; // Current position in the stack(s)
168
+ $this->shortArrays = new \SplObjectStorage;
155
169
 
156
170
  do {
157
171
  if (self::ActionBase[$state] === 0) {
@@ -206,6 +220,7 @@ final class TagParser extends TagParserData
206
220
 
207
221
  do {
208
222
  if ($rule === 0) { // accept
223
+ $this->finalizeShortArrays();
209
224
  return $this->semValue;
210
225
 
211
226
  } elseif ($rule !== self::UnexpectedTokenRule) { // reduce
@@ -407,6 +422,40 @@ final class TagParser extends TagParserData
407
422
  }
408
423
 
409
424
 
425
+ public function convertArrayToList(Expression\ArrayNode $array): Node\ListNode
426
+ {
427
+ $this->shortArrays->detach($array);
428
+ $items = [];
429
+ foreach ($array->items as $item) {
430
+ $value = $item->value;
431
+ if ($item->unpack) {
432
+ throw new CompileException('Spread operator is not supported in assignments.', $value->position);
433
+ }
434
+ $value = match (true) {
435
+ $value instanceof Expression\TemporaryNode => $value->value,
436
+ $value instanceof Expression\ArrayNode && $this->shortArrays->contains($value) => $this->convertArrayToList($value),
437
+ default => $value,
438
+ };
439
+ $items[] = $value
440
+ ? new Node\ListItemNode($value, $item->key, $item->byRef, $item->position)
441
+ : null;
442
+ }
443
+ return new Node\ListNode($items, $array->position);
444
+ }
445
+
446
+
447
+ private function finalizeShortArrays(): void
448
+ {
449
+ foreach ($this->shortArrays as $node) {
450
+ foreach ($node->items as $item) {
451
+ if ($item->value instanceof Expression\TemporaryNode) {
452
+ throw new CompileException('Cannot use empty array elements or list() in arrays.', $item->position);
453
+ }
454
+ }
455
+ }
456
+ }
457
+
458
+
410
459
  /** @param Token[] $tokens */
411
460
  private function filterTokens(array $tokens): array
412
461
  {