Revision 1852
Added by darkviper almost 12 years ago
Parser.php | ||
---|---|---|
29 | 29 |
protected $macros; |
30 | 30 |
protected $env; |
31 | 31 |
protected $reservedMacroNames; |
32 |
protected $importedFunctions; |
|
33 |
protected $tmpVarCount; |
|
32 |
protected $importedSymbols; |
|
34 | 33 |
protected $traits; |
34 |
protected $embeddedTemplates = array(); |
|
35 | 35 |
|
36 | 36 |
/** |
37 | 37 |
* Constructor. |
... | ... | |
50 | 50 |
|
51 | 51 |
public function getVarName() |
52 | 52 |
{ |
53 |
return sprintf('__internal_%s_%d', substr($this->env->getTemplateClass($this->stream->getFilename()), strlen($this->env->getTemplateClassPrefix())), ++$this->tmpVarCount);
|
|
53 |
return sprintf('__internal_%s', hash('sha1', uniqid(mt_rand(), true), false));
|
|
54 | 54 |
} |
55 | 55 |
|
56 |
public function getFilename() |
|
57 |
{ |
|
58 |
return $this->stream->getFilename(); |
|
59 |
} |
|
60 |
|
|
56 | 61 |
/** |
57 | 62 |
* Converts a token stream to a node tree. |
58 | 63 |
* |
59 |
* @param Twig_TokenStream $stream A token stream instance
|
|
64 |
* @param Twig_TokenStream $stream A token stream instance |
|
60 | 65 |
* |
61 | 66 |
* @return Twig_Node_Module A node tree |
62 | 67 |
*/ |
63 |
public function parse(Twig_TokenStream $stream) |
|
68 |
public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
|
|
64 | 69 |
{ |
65 | 70 |
// push all variables into the stack to keep the current state of the parser |
66 | 71 |
$vars = get_object_vars($this); |
67 | 72 |
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']); |
68 | 73 |
$this->stack[] = $vars; |
69 | 74 |
|
70 |
$this->tmpVarCount = 0; |
|
71 |
|
|
72 | 75 |
// tag handlers |
73 | 76 |
if (null === $this->handlers) { |
74 | 77 |
$this->handlers = $this->env->getTokenParsers(); |
... | ... | |
90 | 93 |
$this->macros = array(); |
91 | 94 |
$this->traits = array(); |
92 | 95 |
$this->blockStack = array(); |
93 |
$this->importedFunctions = array(array()); |
|
96 |
$this->importedSymbols = array(array()); |
|
97 |
$this->embeddedTemplates = array(); |
|
94 | 98 |
|
95 | 99 |
try { |
96 |
$body = $this->subparse(null);
|
|
100 |
$body = $this->subparse($test, $dropNeedle);
|
|
97 | 101 |
|
98 | 102 |
if (null !== $this->parent) { |
99 | 103 |
if (null === $body = $this->filterBodyNodes($body)) { |
... | ... | |
101 | 105 |
} |
102 | 106 |
} |
103 | 107 |
} catch (Twig_Error_Syntax $e) { |
104 |
if (null === $e->getTemplateFile()) {
|
|
105 |
$e->setTemplateFile($this->stream->getFilename());
|
|
108 |
if (!$e->getTemplateFile()) {
|
|
109 |
$e->setTemplateFile($this->getFilename()); |
|
106 | 110 |
} |
107 | 111 |
|
112 |
if (!$e->getTemplateLine()) { |
|
113 |
$e->setTemplateLine($this->stream->getCurrent()->getLine()); |
|
114 |
} |
|
115 |
|
|
108 | 116 |
throw $e; |
109 | 117 |
} |
110 | 118 |
|
111 |
$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->stream->getFilename());
|
|
119 |
$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());
|
|
112 | 120 |
|
113 | 121 |
$traverser = new Twig_NodeTraverser($this->env, $this->visitors); |
114 | 122 |
|
... | ... | |
145 | 153 |
$token = $this->getCurrentToken(); |
146 | 154 |
|
147 | 155 |
if ($token->getType() !== Twig_Token::NAME_TYPE) { |
148 |
throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->stream->getFilename());
|
|
156 |
throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename()); |
|
149 | 157 |
} |
150 | 158 |
|
151 | 159 |
if (null !== $test && call_user_func($test, $token)) { |
... | ... | |
163 | 171 |
$subparser = $this->handlers->getTokenParser($token->getValue()); |
164 | 172 |
if (null === $subparser) { |
165 | 173 |
if (null !== $test) { |
166 |
throw new Twig_Error_Syntax(sprintf('Unexpected tag name "%s" (expecting closing tag for the "%s" tag defined near line %s)', $token->getValue(), $test[0]->getTag(), $lineno), $token->getLine(), $this->stream->getFilename()); |
|
174 |
$error = sprintf('Unexpected tag name "%s"', $token->getValue()); |
|
175 |
if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) { |
|
176 |
$error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno); |
|
177 |
} |
|
178 |
|
|
179 |
throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename()); |
|
167 | 180 |
} |
168 | 181 |
|
169 | 182 |
$message = sprintf('Unknown tag name "%s"', $token->getValue()); |
... | ... | |
171 | 184 |
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); |
172 | 185 |
} |
173 | 186 |
|
174 |
throw new Twig_Error_Syntax($message, $token->getLine(), $this->stream->getFilename());
|
|
187 |
throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename()); |
|
175 | 188 |
} |
176 | 189 |
|
177 | 190 |
$this->stream->next(); |
... | ... | |
183 | 196 |
break; |
184 | 197 |
|
185 | 198 |
default: |
186 |
throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', -1, $this->stream->getFilename());
|
|
199 |
throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
|
|
187 | 200 |
} |
188 | 201 |
} |
189 | 202 |
|
... | ... | |
255 | 268 |
} |
256 | 269 |
|
257 | 270 |
if (in_array($name, $this->reservedMacroNames)) { |
258 |
throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine()); |
|
271 |
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 | 272 |
} |
260 | 273 |
|
261 | 274 |
$this->macros[$name] = $node; |
... | ... | |
271 | 284 |
return count($this->traits) > 0; |
272 | 285 |
} |
273 | 286 |
|
274 |
public function addImportedFunction($alias, $name, Twig_Node_Expression $node)
|
|
287 |
public function embedTemplate(Twig_Node_Module $template)
|
|
275 | 288 |
{ |
276 |
$this->importedFunctions[0][$alias] = array('name' => $name, 'node' => $node); |
|
289 |
$template->setIndex(mt_rand()); |
|
290 |
|
|
291 |
$this->embeddedTemplates[] = $template; |
|
277 | 292 |
} |
278 | 293 |
|
279 |
public function getImportedFunction($alias)
|
|
294 |
public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
|
|
280 | 295 |
{ |
281 |
foreach ($this->importedFunctions as $functions) { |
|
282 |
if (isset($functions[$alias])) { |
|
283 |
return $functions[$alias]; |
|
296 |
$this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node); |
|
297 |
} |
|
298 |
|
|
299 |
public function getImportedSymbol($type, $alias) |
|
300 |
{ |
|
301 |
foreach ($this->importedSymbols as $functions) { |
|
302 |
if (isset($functions[$type][$alias])) { |
|
303 |
return $functions[$type][$alias]; |
|
284 | 304 |
} |
285 | 305 |
} |
286 | 306 |
} |
287 | 307 |
|
288 | 308 |
public function isMainScope() |
289 | 309 |
{ |
290 |
return 1 === count($this->importedFunctions);
|
|
310 |
return 1 === count($this->importedSymbols);
|
|
291 | 311 |
} |
292 | 312 |
|
293 | 313 |
public function pushLocalScope() |
294 | 314 |
{ |
295 |
array_unshift($this->importedFunctions, array());
|
|
315 |
array_unshift($this->importedSymbols, array());
|
|
296 | 316 |
} |
297 | 317 |
|
298 | 318 |
public function popLocalScope() |
299 | 319 |
{ |
300 |
array_shift($this->importedFunctions);
|
|
320 |
array_shift($this->importedSymbols);
|
|
301 | 321 |
} |
302 | 322 |
|
303 | 323 |
/** |
... | ... | |
349 | 369 |
(!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) |
350 | 370 |
) { |
351 | 371 |
if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { |
352 |
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->stream->getFilename());
|
|
372 |
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()); |
|
353 | 373 |
} |
354 | 374 |
|
355 |
throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->stream->getFilename());
|
|
375 |
throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename()); |
|
356 | 376 |
} |
357 | 377 |
|
358 | 378 |
// bypass "set" nodes as they "capture" the output |
Also available in: Unified diff
updated Twig template engine to stable version 1.11.1 step2