Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Parser.php
001 <?php
002
003 /*
004 * This file is part of Twig.
005 *
006 * (c) 2009 Fabien Potencier
007 * (c) 2009 Armin Ronacher
008 *
009 * For the full copyright and license information, please view the LICENSE
010 * file that was distributed with this source code.
011 */
012
013 /**
014 * Default parser implementation.
015 *
016 * @author Fabien Potencier <fabien@symfony.com>
017 */
018 class Twig_Parser implements Twig_ParserInterface
019 {
020 protected $stack = array();
021 protected $stream;
022 protected $parent;
023 protected $handlers;
024 protected $visitors;
025 protected $expressionParser;
026 protected $blocks;
027 protected $blockStack;
028 protected $macros;
029 protected $env;
030 protected $reservedMacroNames;
031 protected $importedSymbols;
032 protected $traits;
033 protected $embeddedTemplates = array();
034
035 /**
036 * Constructor.
037 *
038 * @param Twig_Environment $env A Twig_Environment instance
039 */
040 public function __construct(Twig_Environment $env)
041 {
042 $this->env = $env;
043 }
044
045 public function getEnvironment()
046 {
047 return $this->env;
048 }
049
050 public function getVarName()
051 {
052 return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
053 }
054
055 public function getFilename()
056 {
057 return $this->stream->getFilename();
058 }
059
060 /**
061 * {@inheritdoc}
062 */
063 public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
064 {
065 // push all variables into the stack to keep the current state of the parser
066 // using get_object_vars() instead of foreach would lead to https://bugs.php.net/71336
067 $vars = array();
068 foreach ($this as $k => $v) {
069 $vars[$k] = $v;
070 }
071
072 unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']);
073 $this->stack[] = $vars;
074
075 // tag handlers
076 if (null === $this->handlers) {
077 $this->handlers = $this->env->getTokenParsers();
078 $this->handlers->setParser($this);
079 }
080
081 // node visitors
082 if (null === $this->visitors) {
083 $this->visitors = $this->env->getNodeVisitors();
084 }
085
086 if (null === $this->expressionParser) {
087 $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
088 }
089
090 $this->stream = $stream;
091 $this->parent = null;
092 $this->blocks = array();
093 $this->macros = array();
094 $this->traits = array();
095 $this->blockStack = array();
096 $this->importedSymbols = array(array());
097 $this->embeddedTemplates = array();
098
099 try {
100 $body = $this->subparse($test, $dropNeedle);
101
102 if (null !== $this->parent && null === $body = $this->filterBodyNodes($body)) {
103 $body = new Twig_Node();
104 }
105 } catch (Twig_Error_Syntax $e) {
106 if (!$e->getTemplateFile()) {
107 $e->setTemplateFile($this->getFilename());
108 }
109
110 if (!$e->getTemplateLine()) {
111 $e->setTemplateLine($this->stream->getCurrent()->getLine());
112 }
113
114 throw $e;
115 }
116
117 $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
118
119 $traverser = new Twig_NodeTraverser($this->env, $this->visitors);
120
121 $node = $traverser->traverse($node);
122
123 // restore previous stack so previous parse() call can resume working
124 foreach (array_pop($this->stack) as $key => $val) {
125 $this->$key = $val;
126 }
127
128 return $node;
129 }
130
131 public function subparse($test, $dropNeedle = false)
132 {
133 $lineno = $this->getCurrentToken()->getLine();
134 $rv = array();
135 while (!$this->stream->isEOF()) {
136 switch ($this->getCurrentToken()->getType()) {
137 case Twig_Token::TEXT_TYPE:
138 $token = $this->stream->next();
139 $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
140 break;
141
142 case Twig_Token::VAR_START_TYPE:
143 $token = $this->stream->next();
144 $expr = $this->expressionParser->parseExpression();
145 $this->stream->expect(Twig_Token::VAR_END_TYPE);
146 $rv[] = new Twig_Node_Print($expr, $token->getLine());
147 break;
148
149 case Twig_Token::BLOCK_START_TYPE:
150 $this->stream->next();
151 $token = $this->getCurrentToken();
152
153 if ($token->getType() !== Twig_Token::NAME_TYPE) {
154 throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->getFilename());
155 }
156
157 if (null !== $test && call_user_func($test, $token)) {
158 if ($dropNeedle) {
159 $this->stream->next();
160 }
161
162 if (1 === count($rv)) {
163 return $rv[0];
164 }
165
166 return new Twig_Node($rv, array(), $lineno);
167 }
168
169 $subparser = $this->handlers->getTokenParser($token->getValue());
170 if (null === $subparser) {
171 if (null !== $test) {
172 $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->getFilename());
173
174 if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
175 $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno));
176 }
177 } else {
178 $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->getFilename());
179 $e->addSuggestions($token->getValue(), array_keys($this->env->getTags()));
180 }
181
182 throw $e;
183 }
184
185 $this->stream->next();
186
187 $node = $subparser->parse($token);
188 if (null !== $node) {
189 $rv[] = $node;
190 }
191 break;
192
193 default:
194 throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
195 }
196 }
197
198 if (1 === count($rv)) {
199 return $rv[0];
200 }
201
202 return new Twig_Node($rv, array(), $lineno);
203 }
204
205 public function addHandler($name, $class)
206 {
207 $this->handlers[$name] = $class;
208 }
209
210 public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
211 {
212 $this->visitors[] = $visitor;
213 }
214
215 public function getBlockStack()
216 {
217 return $this->blockStack;
218 }
219
220 public function peekBlockStack()
221 {
222 return $this->blockStack[count($this->blockStack) - 1];
223 }
224
225 public function popBlockStack()
226 {
227 array_pop($this->blockStack);
228 }
229
230 public function pushBlockStack($name)
231 {
232 $this->blockStack[] = $name;
233 }
234
235 public function hasBlock($name)
236 {
237 return isset($this->blocks[$name]);
238 }
239
240 public function getBlock($name)
241 {
242 return $this->blocks[$name];
243 }
244
245 public function setBlock($name, Twig_Node_Block $value)
246 {
247 $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
248 }
249
250 public function hasMacro($name)
251 {
252 return isset($this->macros[$name]);
253 }
254
255 public function setMacro($name, Twig_Node_Macro $node)
256 {
257 if ($this->isReservedMacroName($name)) {
258 throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getLine(), $this->getFilename());
259 }
260
261 $this->macros[$name] = $node;
262 }
263
264 public function isReservedMacroName($name)
265 {
266 if (null === $this->reservedMacroNames) {
267 $this->reservedMacroNames = array();
268 $r = new ReflectionClass($this->env->getBaseTemplateClass());
269 foreach ($r->getMethods() as $method) {
270 $methodName = strtolower($method->getName());
271
272 if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) {
273 $this->reservedMacroNames[] = substr($methodName, 3);
274 }
275 }
276 }
277
278 return in_array(strtolower($name), $this->reservedMacroNames);
279 }
280
281 public function addTrait($trait)
282 {
283 $this->traits[] = $trait;
284 }
285
286 public function hasTraits()
287 {
288 return count($this->traits) > 0;
289 }
290
291 public function embedTemplate(Twig_Node_Module $template)
292 {
293 $template->setIndex(mt_rand());
294
295 $this->embeddedTemplates[] = $template;
296 }
297
298 public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
299 {
300 $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
301 }
302
303 public function getImportedSymbol($type, $alias)
304 {
305 foreach ($this->importedSymbols as $functions) {
306 if (isset($functions[$type][$alias])) {
307 return $functions[$type][$alias];
308 }
309 }
310 }
311
312 public function isMainScope()
313 {
314 return 1 === count($this->importedSymbols);
315 }
316
317 public function pushLocalScope()
318 {
319 array_unshift($this->importedSymbols, array());
320 }
321
322 public function popLocalScope()
323 {
324 array_shift($this->importedSymbols);
325 }
326
327 /**
328 * Gets the expression parser.
329 *
330 * @return Twig_ExpressionParser The expression parser
331 */
332 public function getExpressionParser()
333 {
334 return $this->expressionParser;
335 }
336
337 public function getParent()
338 {
339 return $this->parent;
340 }
341
342 public function setParent($parent)
343 {
344 $this->parent = $parent;
345 }
346
347 /**
348 * Gets the token stream.
349 *
350 * @return Twig_TokenStream The token stream
351 */
352 public function getStream()
353 {
354 return $this->stream;
355 }
356
357 /**
358 * Gets the current token.
359 *
360 * @return Twig_Token The current token
361 */
362 public function getCurrentToken()
363 {
364 return $this->stream->getCurrent();
365 }
366
367 protected function filterBodyNodes(Twig_NodeInterface $node)
368 {
369 // check that the body does not contain non-empty output nodes
370 if (
371 ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
372 ||
373 (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
374 ) {
375 if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
376 throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
377 }
378
379 throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
380 }
381
382 // bypass "set" nodes as they "capture" the output
383 if ($node instanceof Twig_Node_Set) {
384 return $node;
385 }
386
387 if ($node instanceof Twig_NodeOutputInterface) {
388 return;
389 }
390
391 foreach ($node as $k => $n) {
392 if (null !== $n && null === $this->filterBodyNodes($n)) {
393 $node->removeNode($k);
394 }
395 }
396
397 return $node;
398 }
399 }
400