1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace MewesK\TwigSpreadsheetBundle\Twig\TokenParser; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Class BaseTokenParser. |
7
|
|
|
*/ |
8
|
|
|
abstract class BaseTokenParser extends \Twig_TokenParser |
9
|
|
|
{ |
10
|
|
|
/** |
11
|
|
|
* @var int |
12
|
|
|
*/ |
13
|
|
|
const PARAMETER_TYPE_ARRAY = 0; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @var int |
17
|
|
|
*/ |
18
|
|
|
const PARAMETER_TYPE_VALUE = 1; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @param \Twig_Token $token |
22
|
|
|
* |
23
|
|
|
* @return array |
24
|
|
|
*/ |
25
|
|
|
public function configureParameters(\Twig_Token $token): array |
26
|
|
|
{ |
27
|
|
|
return []; |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @return array |
32
|
|
|
*/ |
33
|
|
|
public function getAttributes(): array |
34
|
|
|
{ |
35
|
|
|
return []; |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @return string |
40
|
|
|
*/ |
41
|
|
|
abstract public function getNode(): string; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @return bool |
45
|
|
|
*/ |
46
|
|
|
public function hasBody(): bool |
47
|
|
|
{ |
48
|
|
|
return true; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @param \Twig_Token $token |
53
|
|
|
* |
54
|
|
|
* @throws \Twig_Error_Syntax |
55
|
|
|
* @throws \InvalidArgumentException |
56
|
|
|
* |
57
|
|
|
* @return \Twig_node |
58
|
|
|
*/ |
59
|
|
|
public function parse(\Twig_Token $token) |
60
|
|
|
{ |
61
|
|
|
// parse attributes |
62
|
|
|
$nodes = $this->parseParameters($this->configureParameters($token)); |
63
|
|
|
|
64
|
|
|
// parse body |
65
|
|
|
if ($this->hasBody()) { |
66
|
|
|
$nodes['body'] = $this->parseBody(); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
// return node |
70
|
|
|
$nodeClass = $this->getNode(); |
71
|
|
|
|
72
|
|
|
return new $nodeClass($nodes, $this->getAttributes(), $token->getLine(), $this->getTag()); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param array $parameterConfiguration |
77
|
|
|
* |
78
|
|
|
* @throws \InvalidArgumentException |
79
|
|
|
* @throws \Twig_Error_Syntax |
80
|
|
|
* |
81
|
|
|
* @return \Twig_Node_Expression[] |
82
|
|
|
*/ |
83
|
|
|
private function parseParameters(array $parameterConfiguration = []): array |
84
|
|
|
{ |
85
|
|
|
// parse expressions |
86
|
|
|
$expressions = []; |
87
|
|
|
while (!$this->parser->getStream()->test(\Twig_Token::BLOCK_END_TYPE)) { |
88
|
|
|
$expressions[] = $this->parser->getExpressionParser()->parseExpression(); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
// end of expressions |
92
|
|
|
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); |
93
|
|
|
|
94
|
|
|
// map expressions to parameters |
95
|
|
|
$parameters = []; |
96
|
|
|
foreach ($parameterConfiguration as $parameterName => $parameterOptions) { |
97
|
|
|
// try mapping expression |
98
|
|
|
$expression = reset($expressions); |
99
|
|
|
if ($expression !== false) { |
100
|
|
|
switch ($parameterOptions['type']) { |
101
|
|
|
case self::PARAMETER_TYPE_ARRAY: |
102
|
|
|
// check if expression is valid array |
103
|
|
|
$valid = $expression instanceof \Twig_Node_Expression_Array; |
104
|
|
|
break; |
105
|
|
|
case self::PARAMETER_TYPE_VALUE: |
106
|
|
|
// check if expression is valid value |
107
|
|
|
$valid = !($expression instanceof \Twig_Node_Expression_Array); |
108
|
|
|
break; |
109
|
|
|
default: |
110
|
|
|
throw new \InvalidArgumentException('Invalid parameter type'); |
111
|
|
|
break; |
|
|
|
|
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
if ($valid) { |
115
|
|
|
// set expression as parameter and remove it from expressions list |
116
|
|
|
$parameters[$parameterName] = array_shift($expressions); |
117
|
|
|
continue; |
118
|
|
|
} |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
// set default as parameter otherwise or throw exception if default is false |
122
|
|
|
if ($parameterOptions['default'] === false) { |
123
|
|
|
throw new \Twig_Error_Syntax('A required parameter is missing'); |
124
|
|
|
} |
125
|
|
|
$parameters[$parameterName] = $parameterOptions['default']; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
if (count($expressions) > 0) { |
129
|
|
|
throw new \Twig_Error_Syntax('Too many parameters'); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
return $parameters; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @return \Twig_Node |
137
|
|
|
*/ |
138
|
|
|
private function parseBody(): \Twig_Node |
139
|
|
|
{ |
140
|
|
|
// parse body |
141
|
|
|
$body = $this->parser->subparse(function (\Twig_Token $token) { |
142
|
|
|
return $token->test('end'.$this->getTag()); |
143
|
|
|
}, |
144
|
|
|
true |
145
|
|
|
); |
146
|
|
|
|
147
|
|
|
// end of body |
148
|
|
|
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); |
149
|
|
|
|
150
|
|
|
return $body; |
151
|
|
|
} |
152
|
|
|
} |
153
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.