Exponential 6.0.13 Exponential Enterprise Open Source CMS - PHP Class Reference

eztemplatemultipassparser.php
Go to the documentation of this file.
1 <?php
17 class eZTemplateMultiPassParser extends eZTemplateParser
18 {
19 public function __construct()
20 {
21 $this->ElementParser = eZTemplateElementParser::instance();
22 }
23
24
30 function parse( $tpl, $sourceText, &$rootElement, $rootNamespace, &$resourceData )
31 {
32 $relatedResource = $resourceData['resource'];
33 $relatedTemplateName = $resourceData['template-filename'];
34
35 $currentRoot =& $rootElement;
36 $leftDelimiter = $tpl->LDelim;
37 $rightDelimiter = $tpl->RDelim;
38 $sourceLength = strlen( $sourceText );
39 $sourcePosition = 0;
40
41 eZDebug::accumulatorStart( 'template_multi_parser_1', 'template_total', 'Template parser: create text elements' );
42 $textElements = $this->parseIntoTextElements( $tpl, $sourceText, $sourcePosition,
43 $leftDelimiter, $rightDelimiter, $sourceLength,
44 $relatedTemplateName );
45 eZDebug::accumulatorStop( 'template_multi_parser_1' );
46
47 eZDebug::accumulatorStart( 'template_multi_parser_2', 'template_total', 'Template parser: remove whitespace' );
48 $textElements = $this->parseWhitespaceRemoval( $tpl, $textElements );
49 eZDebug::accumulatorStop( 'template_multi_parser_2' );
50
51 eZDebug::accumulatorStart( 'template_multi_parser_3', 'template_total', 'Template parser: construct tree' );
52 $this->parseIntoTree( $tpl, $textElements, $currentRoot,
53 $rootNamespace, $relatedResource, $relatedTemplateName );
54 eZDebug::accumulatorStop( 'template_multi_parser_3' );
55 }
56
57 function gotoEndPosition( $text, $line, $column, &$endLine, &$endColumn )
58 {
59 $lines = preg_split( "#\r\n|\r|\n#", $text );
60 $c = count( $lines );
61 if ( $c > 0 )
62 {
63 $endLine = $line + $c - 1;
64 $lastLine = $lines[$c - 1];
65 if ( $c > 1 )
66 $endColumn = strlen( $lastLine );
67 else
68 $endColumn = $column + strlen( $lastLine );
69 }
70 else
71 {
72 $endLine = $line;
73 $endColumn = $column;
74 }
75 }
76
77 function parseIntoTextElements( $tpl, $sourceText, $sourcePosition,
78 $leftDelimiter, $rightDelimiter, $sourceLength,
79 $relatedTemplateName )
80 {
81 if ( $tpl->ShowDetails )
82 eZDebug::addTimingPoint( "Parse pass 1 (simple tag parsing)" );
83 $currentLine = 1;
84 $currentColumn = 0;
85 $textElements = array();
86 while( $sourcePosition < $sourceLength )
87 {
88 $tagPos = strpos( $sourceText, $leftDelimiter, $sourcePosition );
89 if ( $tagPos === false )
90 {
91 // No more tags
92 unset( $data );
93 $data = substr( $sourceText, $sourcePosition );
94 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
95 $textElements[] = array( "text" => $data,
96 "type" => eZTemplate::ELEMENT_TEXT,
97 'placement' => array( 'templatefile' => $relatedTemplateName,
98 'start' => array( 'line' => $currentLine,
99 'column' => $currentColumn,
100 'position' => $sourcePosition ),
101 'stop' => array( 'line' => $endLine,
102 'column' => $endColumn,
103 'position' => $sourceLength - 1 ) ) );
104 $sourcePosition = $sourceLength;
105 $currentLine = $endLine;
106 $currentColumn = $endColumn;
107 }
108 else
109 {
110 $blockStart = $tagPos;
111 $tagPos++;
112 if ( $tagPos < $sourceLength and
113 $sourceText[$tagPos] == "*" ) // Comment
114 {
115 $endPos = strpos( $sourceText, "*$rightDelimiter", $tagPos + 1 );
116 $len = $endPos - $tagPos;
117 if ( $sourcePosition < $blockStart )
118 {
119 // Add text before tag.
120 unset( $data );
121 $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition );
122 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
123 $textElements[] = array( "text" => $data,
124 "type" => eZTemplate::ELEMENT_TEXT,
125 'placement' => array( 'templatefile' => $relatedTemplateName,
126 'start' => array( 'line' => $currentLine,
127 'column' => $currentColumn,
128 'position' => $sourcePosition ),
129 'stop' => array( 'line' => $endLine,
130 'column' => $endColumn,
131 'position' => $blockStart ) ) );
132 $currentLine = $endLine;
133 $currentColumn = $endColumn;
134 }
135 if ( $endPos === false )
136 {
137 $endPos = $sourceLength;
138 $blockEnd = $sourceLength;
139 }
140 else
141 {
142 $blockEnd = $endPos + 2;
143 }
144 $comment_text = substr( $sourceText, $tagPos + 1, $endPos - $tagPos - 1 );
145 $this->gotoEndPosition( $comment_text, $currentLine, $currentColumn, $endLine, $endColumn );
146 $textElements[] = array( "text" => $comment_text,
147 "type" => eZTemplate::ELEMENT_COMMENT,
148 'placement' => array( 'templatefile' => $relatedTemplateName,
149 'start' => array( 'line' => $currentLine,
150 'column' => $currentColumn,
151 'position' => $tagPos + 1 ),
152 'stop' => array( 'line' => $endLine,
153 'column' => $endColumn,
154 'position' => $endPos - 1 ) ) );
155 if ( $sourcePosition < $blockEnd )
156 $sourcePosition = $blockEnd;
157 $currentLine = $endLine;
158 $currentColumn = $endColumn;
159 // eZDebug::writeDebug( "eZTemplate: Comment: $comment" );
160 }
161 else
162 {
163 $tmp_pos = $tagPos;
164 while( ( $endPos = strpos( $sourceText, $rightDelimiter, $tmp_pos ) ) !== false )
165 {
166 if ( $sourceText[$endPos-1] != "\\" )
167 break;
168 $tmp_pos = $endPos + 1;
169 }
170 if ( $endPos === false )
171 {
172 // Unterminated tag
173 $data = substr( $sourceText, $sourcePosition );
174 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
175 $textBefore = substr( $sourceText, $sourcePosition, $tagPos - $sourcePosition );
176 $textPortion = substr( $sourceText, $tagPos );
177 $this->gotoEndPosition( $textBefore, $currentLine, $currentColumn, $tagStartLine, $tagStartColumn );
178 $this->gotoEndPosition( $textPortion, $tagStartLine, $tagStartColumn, $tagEndLine, $tagEndColumn );
179 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" .
180 "Unterminated tag, needs a $rightDelimiter to end the tag.\n" . $leftDelimiter . $textPortion,
181 array( array( $tagStartLine, $tagStartColumn, $tagPos ),
182 array( $tagEndLine, $tagEndColumn, $sourceLength - 1 ),
183 $relatedTemplateName ) );
184 $textElements[] = array( "text" => $data,
185 "type" => eZTemplate::ELEMENT_TEXT,
186 'placement' => array( 'templatefile' => $relatedTemplateName,
187 'start' => array( 'line' => $currentLine,
188 'column' => $currentColumn,
189 'position' => $sourcePosition ),
190 'stop' => array( 'line' => $endLine,
191 'column' => $endColumn,
192 'position' => $sourceLength - 1 ) ) );
193 $sourcePosition = $sourceLength;
194 $currentLine = $endLine;
195 $currentColumn = $endColumn;
196 }
197 else
198 {
199 $blockEnd = $endPos + 1;
200 $len = $endPos - $tagPos;
201 if ( $sourcePosition < $blockStart )
202 {
203 // Add text before tag.
204 $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition );
205 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
206 $textElements[] = array( "text" => $data,
207 "type" => eZTemplate::ELEMENT_TEXT,
208 'placement' => array( 'templatefile' => $relatedTemplateName,
209 'start' => array( 'line' => $currentLine,
210 'column' => $currentColumn,
211 'position' => $sourcePosition ),
212 'stop' => array( 'line' => $endLine,
213 'column' => $endColumn,
214 'position' => $blockStart ) ) );
215 $currentLine = $endLine;
216 $currentColumn = $endColumn;
217 }
218
219 $tag = substr( $sourceText, $tagPos, $len );
220 $tag = preg_replace( "/\\\\[}]/", "}", $tag );
221 $tagTrim = trim( $tag );
222 $isEndTag = false;
223 $isSingleTag = false;
224
225 if ( $tag[0] == "/" )
226 {
227 $isEndTag = true;
228 $tag = substr( $tag, 1 );
229 }
230 else if ( $tagTrim[strlen( $tagTrim ) - 1] == "/" )
231 {
232 $isSingleTag = true;
233 $tagTrim = trim( substr( $tagTrim, 0, strlen( $tagTrim ) - 1 ) );
234 $tag = $tagTrim;
235 }
236
237 $this->gotoEndPosition( $tag, $currentLine, $currentColumn, $endLine, $endColumn );
238 if ( $tag[0] == "$" or
239 $tag[0] == "\"" or
240 $tag[0] == "'" or
241 is_numeric( $tag[0] ) or
242 ( $tag[0] == '-' and
243 isset( $tag[1] ) and
244 is_numeric( $tag[1] ) ) or
245 preg_match( "/^[a-z0-9_-]+\‍(/", $tag ) )
246 {
247 $textElements[] = array( "text" => $tag,
248 "type" => eZTemplate::ELEMENT_VARIABLE,
249 'placement' => array( 'templatefile' => $relatedTemplateName,
250 'start' => array( 'line' => $currentLine,
251 'column' => $currentColumn,
252 'position' => $blockStart + 1 ),
253 'stop' => array( 'line' => $endLine,
254 'column' => $endColumn,
255 'position' => $blockEnd - 1 ) ) );
256 }
257 else
258 {
259 $type = eZTemplate::ELEMENT_NORMAL_TAG;
260 if ( $isEndTag )
261 $type = eZTemplate::ELEMENT_END_TAG;
262 else if ( $isSingleTag )
263 $type = eZTemplate::ELEMENT_SINGLE_TAG;
264 $spacepos = strpos( $tag, " " );
265 if ( $spacepos === false )
266 $name = $tag;
267 else
268 $name = substr( $tag, 0, $spacepos );
269 if ( isset( $tpl->Literals[$name] ) )
270 {
271 $literalEndTag = "{/$name}";
272 $literalEndPos = strpos( $sourceText, $literalEndTag, $blockEnd );
273 if ( $literalEndPos === false )
274 $literalEndPos = $sourceLength;
275 $data = substr( $sourceText, $blockEnd, $literalEndPos - $blockEnd );
276 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
277 $blockEnd = $literalEndPos + strlen( $literalEndTag );
278 $textElements[] = array( "text" => $data,
279 "type" => eZTemplate::ELEMENT_TEXT,
280 'placement' => false );
281 }
282 else
283 $textElements[] = array( "text" => $tag,
284 "name" => $name,
285 "type" => $type,
286 'placement' => array( 'templatefile' => $relatedTemplateName,
287 'start' => array( 'line' => $currentLine,
288 'column' => $currentColumn,
289 'position' => $blockStart + 1 ),
290 'stop' => array( 'line' => $endLine,
291 'column' => $endColumn,
292 'position' => $blockEnd - 1 ) ) );
293 }
294
295 if ( $sourcePosition < $blockEnd )
296 $sourcePosition = $blockEnd;
297 $currentLine = $endLine;
298 $currentColumn = $endColumn;
299 }
300 }
301 }
302 }
303 return $textElements;
304 }
305
306 function parseWhitespaceRemoval( $tpl, &$textElements )
307 {
308 if ( $tpl->ShowDetails )
309 eZDebug::addTimingPoint( "Parse pass 2 (whitespace removal)" );
310 $tempTextElements = array();
311 $textElements[] = null;
312
313 $element = false;
314 foreach( $textElements as $nextElement )
315 {
316 if ( $element )
317 {
318 switch ( $element["type"] )
319 {
320 case eZTemplate::ELEMENT_COMMENT:
321 {
322 // Ignore comments
323 } break;
324
325 case eZTemplate::ELEMENT_TEXT:
326 case eZTemplate::ELEMENT_VARIABLE:
327 {
328 if ( $nextElement !== null )
329 {
330 switch ( $nextElement["type"] )
331 {
332 case eZTemplate::ELEMENT_END_TAG:
333 case eZTemplate::ELEMENT_SINGLE_TAG:
334 case eZTemplate::ELEMENT_NORMAL_TAG:
335 {
336 $text = $element["text"];
337 $text_cnt = strlen( $text );
338 if ( $text_cnt > 0 )
339 {
340 $char = $text[$text_cnt - 1];
341 if ( $char == "\n" )
342 {
343 $element["text"] = substr( $text, 0, $text_cnt - 1 );
344 }
345 }
346 } break;
347 }
348 }
349 if ( $element["text"] !== '' )
350 {
351 $tempTextElements[] = $element;
352 }
353 } break;
354
355 case eZTemplate::ELEMENT_END_TAG:
356 case eZTemplate::ELEMENT_SINGLE_TAG:
357 case eZTemplate::ELEMENT_NORMAL_TAG:
358 {
359 if ( $nextElement !== null )
360 {
361 switch ( $nextElement["type"] )
362 {
363 case eZTemplate::ELEMENT_TEXT:
364 case eZTemplate::ELEMENT_VARIABLE:
365 {
366 $text = $nextElement["text"];
367 $text_cnt = strlen( $text );
368 if ( $text_cnt > 0 )
369 {
370 $char = $text[0];
371 if ( $char == "\n" )
372 {
373 $nextElement["text"] = substr( $text, 1 );
374 }
375 }
376 } break;
377 }
378 }
379 $tempTextElements[] = $element;
380 } break;
381 }
382 }
383 $element = $nextElement;
384 }
385 return $tempTextElements;
386 }
387
388 function appendChild( &$root, &$node )
389 {
390 if ( !is_array( $root[1] ) )
391 $root[1] = array();
392 $root[1][] =& $node;
393 }
394
395 function parseIntoTree( $tpl, &$textElements, &$treeRoot,
396 $rootNamespace, $relatedResource, $relatedTemplateName )
397 {
398 $outerElseTags = array( 'else' => array( 'if', 'elseif' ), 'section-else' => array( 'section' ) );
399
400 $currentRoot =& $treeRoot;
401 if ( $tpl->ShowDetails )
402 eZDebug::addTimingPoint( "Parse pass 3 (build tree)" );
403
404 $tagStack = array();
405
406 foreach( $textElements as $elementKey => $element )
407 {
408 if ( !is_array( $element ) )
409 continue;
410 if ( is_array( $element['placement'] ) ) {
411 $elementPlacement = $element['placement'];
412 $startLine = $elementPlacement['start']['line'];
413 $startColumn = $elementPlacement['start']['column'];
414 $startPosition = $elementPlacement['start']['position'];
415 $stopLine = $elementPlacement['stop']['line'];
416 $stopColumn = $elementPlacement['stop']['column'];
417 $stopPosition = $elementPlacement['stop']['position'];
418 $templateFile = $elementPlacement['templatefile'];
419 $placement = array(array($startLine,
420 $startColumn,
421 $startPosition),
422 array($stopLine,
423 $stopColumn,
424 $stopPosition),
425 $templateFile);
426 }
427 else
428 {
429 $placement = array( array(), array(), null );
430 }
431
432 switch ( $element["type"] )
433 {
434 case eZTemplate::ELEMENT_TEXT:
435 {
436 unset( $node );
437 if ( isset( $placement ) )
438 {
439 $node = array( eZTemplate::NODE_TEXT,
440 false,
441 $element['text']
442 );
443 }
444 else
445 {
446 $node = array( eZTemplate::NODE_TEXT,
447 false,
448 $element['text'],
449 $placement );
450 }
451 $this->appendChild( $currentRoot, $node );
452 } break;
453 case eZTemplate::ELEMENT_VARIABLE:
454 {
455 $text = $element["text"];
456 $text_len = strlen( $text );
457 $var_data = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, 0, $var_end, $text_len, $rootNamespace );
458
459 unset( $node );
460 $node = array( eZTemplate::NODE_VARIABLE,
461 false,
462 $var_data,
463 $placement );
464 $this->appendChild( $currentRoot, $node );
465 if ( $var_end < $text_len )
466 {
467 $placement = $element['placement'];
468 $startLine = $placement['start']['line'];
469 $startColumn = $placement['start']['column'];
470 $subText = substr( $text, 0, $var_end );
471 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
472 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" .
473 "Extra characters found in expression, they will be ignored.\n" .
474 substr( $text, $var_end, $text_len - $var_end ) . "' (" . substr( $text, 0, $var_end ) . ")",
475 $placement );
476 }
477 } break;
478 case eZTemplate::ELEMENT_SINGLE_TAG:
479 case eZTemplate::ELEMENT_NORMAL_TAG:
480 case eZTemplate::ELEMENT_END_TAG:
481 {
482 $text = $element["text"];
483 $text_len = strlen( $text );
484 $type = $element["type"];
485
486 $ident_pos = $this->ElementParser->identifierEndPosition( $tpl, $text, 0, $text_len );
487 $tag = substr( $text, 0, $ident_pos - 0 );
488 $attr_pos = $ident_pos;
489 unset( $args );
490
491 $args = array();
492
493 // special handling for some functions having complex syntax
494 if ( $type == eZTemplate::ELEMENT_NORMAL_TAG &&
495 in_array( $tag, array( 'if', 'elseif', 'while', 'for', 'foreach', 'def', 'undef',
496 'set', 'let', 'default', 'set-block', 'append-block', 'section' ) ) )
497 {
498 $attr_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_pos, $text_len );
499
500
501 if ( $tag == 'if' || $tag == 'elseif' )
502 $this->parseUnnamedCondition( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
503 elseif ( $tag == 'while' )
504 $this->parseWhileFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
505 elseif ( $tag == 'for' )
506 $this->parseForFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
507 elseif ( $tag == 'foreach' )
508 $this->parseForeachFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
509 elseif ( $tag == 'def' || $tag == 'undef' )
510 $this->parseDefFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
511 elseif ( $tag == 'set' || $tag == 'let' || $tag == 'default' )
512 $this->parseSetFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
513 elseif ( $tag == 'set-block' || $tag == 'append-block' )
514 $this->parseBlockFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
515 elseif ( $tag == 'section' )
516 $this->parseSectionFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
517 }
518 elseif ( $type == eZTemplate::ELEMENT_END_TAG && $tag == 'do' )
519 {
520 $this->parseDoFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
521 }
522
523 // other functions having simplier syntax are parsed below
524 $lastPosition = false;
525 while ( $attr_pos < $text_len )
526 {
527 if ( $lastPosition !== false and
528 $lastPosition == $attr_pos )
529 {
530 break;
531 }
532 $lastPosition = $attr_pos;
533 $attr_pos_start = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_pos, $text_len );
534 if ( $attr_pos_start == $attr_pos and
535 $attr_pos_start < $text_len )
536 {
537 $placement = $element['placement'];
538 $startLine = $placement['start']['line'];
539 $startColumn = $placement['start']['column'];
540 $subText = substr( $text, 0, $attr_pos );
541 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
542 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" .
543 "Extra characters found, should have been a whitespace or the end of the expression\n".
544 "Characters: '" . substr( $text, $attr_pos ) . "'" );
545 break;
546 }
547 $attr_pos = $attr_pos_start;
548 $attr_name_pos = $this->ElementParser->identifierEndPosition( $tpl, $text, $attr_pos, $text_len );
549 $attr_name = substr( $text, $attr_pos, $attr_name_pos - $attr_pos );
550
551 /* Skip whitespace between here and the next one */
552 $equal_sign_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_name_pos, $text_len );
553 if ( ( $equal_sign_pos < $text_len ) && ( $text[$equal_sign_pos] == '=' ) )
554 {
555 $attr_name_pos = $equal_sign_pos;
556 }
557
558 if ( $attr_name_pos >= $text_len or
559 ( $text[$attr_name_pos] != '=' and
560 preg_match( "/[ \t\r\n]/", $text[$attr_name_pos] ) ) )
561 {
562 unset( $var_data );
563 $var_data = array();
564 $var_data[] = array( eZTemplate::TYPE_NUMERIC, // type
565 true, // content
566 false // debug
567 );
568 $args[$attr_name] = $var_data;
569 $attr_pos = $attr_name_pos;
570 continue;
571 }
572 if ( $text[$attr_name_pos] != "=" )
573 {
574 $placement = $element['placement'];
575 $startLine = $placement['start']['line'];
576 $startColumn = $placement['start']['column'];
577 $subText = substr( $text, 0, $attr_name_pos );
578 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
579 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]\n".
580 "Invalid parameter characters in function '$tag': '" .
581 substr( $text, $attr_name_pos ) . "'" );
582 break;
583 }
584 ++$attr_name_pos;
585 unset( $var_data );
586 $var_data = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $attr_name_pos, $var_end, $text_len, $rootNamespace );
587 $args[$attr_name] = $var_data;
588 $attr_pos = $var_end;
589 }
590
591 if ( $type == eZTemplate::ELEMENT_END_TAG and count( $args ) > 0 )
592 {
593 if ( $tag != 'do' )
594 {
595 $placement = $element['placement'];
596 $startLine = $placement['start']['line'];
597 $startColumn = $placement['start']['column'];
598 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
599 "End tag \"$tag\" cannot have attributes\n$tpl->LDelim/" . $text . $tpl->RDelim,
600 $element['placement'] );
601 $args = array();
602 }
603 }
604
605 if ( $type == eZTemplate::ELEMENT_NORMAL_TAG )
606 {
607 $ignoreCurrentTag = false;
608 if( in_array( $tag, array_keys($outerElseTags) ) ) // 'esle'-kind operators
609 {
610 unset( $oldTag );
611 unset( $oldTagName );
612 $oldTag = end( $tagStack );
613 $oldTagName = $oldTag["Tag"];
614
615 $ignoreCurrentTag = true;
616 if ( in_array( $oldTagName, $outerElseTags[$tag] ) )
617 {
618 $ignoreCurrentTag = false;
619 }
620 else // if there is incorrect 'else' using
621 {
622 // checking for 'if' in stack
623 $tagBackStack = $tagStack;
624 $lastIfKey = false;
625 foreach ( $tagBackStack as $prevTagKey => $prevTag )
626 {
627 if ( in_array( $prevTag['Tag'], $outerElseTags[$tag] ) )
628 {
629 $lastIfKey = $prevTagKey;
630 }
631 }
632
633 if( $lastIfKey !== false )
634 {
635 // checking for later tags (search for closing tag)
636 $laterElements = array_slice( $textElements, $elementKey + 1 );
637 $laterStack = array();
638 foreach( $laterElements as $laterElement )
639 {
640 if ( $laterElement['type'] == eZTemplate::ELEMENT_NORMAL_TAG)
641 {
642 if( !in_array( $laterElement['name'], array_keys($outerElseTags) ) )
643 {
644 $laterStack[] = $laterElement['name'];
645 }
646 else
647 {
648 if ( $laterStack === array() )
649 {
650 break; // double else (current else will be ignored)
651 }
652 }
653 }
654 elseif ( $laterElement['type'] == eZTemplate::ELEMENT_END_TAG )
655 {
656 if ( $laterStack !== array() )
657 {
658 if ( array_pop( $laterStack ) !== $laterElement['name'] )
659 {
660 break; // later tags mismatch (current else will be ignored)
661 }
662 }
663 else
664 {
665 if ( $laterElement['name'] == $oldTagName)
666 {
667 break; // previous tag correctly closed (current else will be ignored)
668 }
669 elseif ( in_array( $laterElement['name'], $outerElseTags[$tag] ) )
670 {
671 $ignoreCurrentTag = false;
672 break; // 'if' tag correctly closed (inner tags must be closed too)
673 }
674 }
675 }
676 }
677 }
678
679 $place = $element['placement'];
680 $startLine = $place['start']['line'];
681 $startColumn = $place['start']['column'];
682 if ( $ignoreCurrentTag )
683 {
684 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
685 "Unterminated tag \"$oldTagName\" does not match tag \"$tag\". \"$tag\" will be ignored.",
686 $element['placement'] );
687 }
688 else
689 {
690 unset( $currentRoot );
691 $lastIfKey++;
692 $currentRoot =& $tagStack[$lastIfKey]["Root"];
693
694 $autoTerminatedTags = array_slice( $tagStack, $lastIfKey);
695 $autoTerminatedTagNames = array();
696 foreach( $autoTerminatedTags as $autoTerminatedTag)
697 $autoTerminatedTagNames[] = $autoTerminatedTag["Tag"];
698 $tagStack = array_slice( $tagStack, 0, $lastIfKey);
699
700 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
701 "Unterminated tag \"".implode( "\", \"", $autoTerminatedTagNames)."\" does not match tag \"$tag\" and will be autoterminated.",
702 $element['placement'] );
703 unset( $autoTerminatedTags );
704 unset( $autoTerminatedTagNames );
705 }
706 unset( $lastIfKey );
707 }
708 }
709
710 if ( !$ignoreCurrentTag )
711 {
712 unset( $node );
713 $node = array( eZTemplate::NODE_FUNCTION,
714 false,
715 $tag,
716 $args,
717 $placement );
718 $this->appendChild( $currentRoot, $node );
719 $has_children = true;
720 if ( isset( $tpl->FunctionAttributes[$tag] ) )
721 {
722 if ( is_array( $tpl->FunctionAttributes[$tag] ) )
723 $tpl->loadAndRegisterFunctions( $tpl->FunctionAttributes[$tag] );
724 $has_children = $tpl->FunctionAttributes[$tag];
725 }
726 else if ( isset( $tpl->Functions[$tag] ) )
727 {
728 if ( is_array( $tpl->Functions[$tag] ) )
729 $tpl->loadAndRegisterFunctions( $tpl->Functions[$tag] );
730 $has_children = $tpl->hasChildren( $tpl->Functions[$tag], $tag );
731 }
732 if ( $has_children )
733 {
734 $tagStack[] = array( "Root" => &$currentRoot,
735 "Tag" => $tag );
736 unset( $currentRoot );
737 $currentRoot =& $node;
738 }
739 }
740 }
741 else if ( $type == eZTemplate::ELEMENT_END_TAG )
742 {
743 $has_children = true;
744 if ( isset( $tpl->FunctionAttributes[$tag] ) )
745 {
746 if ( is_array( $tpl->FunctionAttributes[$tag] ) )
747 $tpl->loadAndRegisterFunctions( $tpl->FunctionAttributes[$tag] );
748 $has_children = $tpl->FunctionAttributes[$tag];
749 }
750 else if ( isset( $tpl->Functions[$tag] ) )
751 {
752 if ( is_array( $tpl->Functions[$tag] ) )
753 $tpl->loadAndRegisterFunctions( $tpl->Functions[$tag] );
754 $has_children = $tpl->hasChildren( $tpl->Functions[$tag], $tag );
755 }
756 if ( !$has_children )
757 {
758 $placement = $element['placement'];
759 $startLine = $placement['start']['line'];
760 $startColumn = $placement['start']['column'];
761 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
762 "End tag \"$tag\" for function which does not accept children, ignoring tag",
763 $element['placement'] );
764 }
765 else
766 {
767 unset( $oldTag );
768 unset( $oldTagName );
769 $oldTag = array_pop( $tagStack );
770 $oldTagName = $oldTag["Tag"];
771 unset( $currentRoot );
772 $currentRoot =& $oldTag["Root"];
773
774 if ( $oldTagName != $tag )
775 {
776 $placement = $element['placement'];
777 $startLine = $placement['start']['line'];
778 $startColumn = $placement['start']['column'];
779 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
780 "Unterminated tag \"$oldTagName\" does not match tag \"$tag\"",
781 $element['placement'] );
782 }
783
784 // a dirty hack to pass arguments specified in {/do} to the corresponding function.
785 if ( $tag == 'do' )
786 {
787 $doOpenTag =& $currentRoot[1][count( $currentRoot[1] ) - 1];
788 $doOpenTag[3] =& $args;
789 }
790 }
791 }
792 else // eZTemplate::ELEMENT_SINGLE_TAG
793 {
794 unset( $node );
795 $node = array( eZTemplate::NODE_FUNCTION,
796 false,
797 $tag,
798 $args,
799 $placement );
800 $this->appendChild( $currentRoot, $node );
801 }
802 unset( $tag );
803
804 } break;
805 }
806 }
807
808 if ( $tpl->ShowDetails )
809 eZDebug::addTimingPoint( "Parse pass 3 done" );
810 }
811
815 function parseSequenceParameter( $parseSequenceKeyword, $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
816 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
817 {
818 if ( $parseSequenceKeyword )
819 {
820 // parse 'sequence' keyword
821 $sequenceEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
822 $sequence = substr( $text, $cur_pos, $sequenceEndPos-$cur_pos );
823 if ( $sequence != 'sequence' )
824 {
825 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
826 $funcName, "Expected keyword 'sequence' not found" );
827 return false;
828 }
829 $cur_pos = $sequenceEndPos;
830
831 // skip whitespaces
832 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
833 }
834
835 // parse sequence array
836 $args['sequence_array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
837
838 // skip whitespaces
839 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
840
841 // parse 'as' keyword
842 $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
843 $word = substr( $text, $cur_pos, $asEndPos-$cur_pos );
844 if ( $word != 'as' )
845 {
846 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
847 $funcName, "Expected keyword 'as' not found" );
848 unset( $args['sequence_array'] );
849 return false;
850 }
851 $cur_pos = $asEndPos;
852
853 // skip whitespaces
854 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
855
856 // parse sequence variable
857 $seqVar = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
858 if ( !$seqVar )
859 {
860 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
861 $funcName, "Sequence variable name cannot be empty" );
862 unset( $args['sequence_array'] );
863 return false;
864 }
865 $args['sequence_var'] = $seqVar;
866
867 return true;
868 }
869
877 function parseForFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos,
878 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
879 {
880 $firstValStartPos = $cur_pos;
881
882 // parse first value
883 $firstVal = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $firstValStartPos, $firstValEndPos, $text_len, $rootNamespace
884 /*, eZTemplate::TYPE_NUMERIC_BIT | eZTemplate::TYPE_VARIABLE_BIT*/ );
885 $args['first_val'] = $firstVal;
886
887 $toStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $firstValEndPos, $text_len );
888
889 // parse 'to'
890 $toEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $toStartPos, $text_len );
891 $to = substr( $text, $toStartPos, $toEndPos-$toStartPos );
892 if ( $to != 'to' )
893 {
894 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
895 'for', "Expected keyword 'to' not found" );
896 return;
897 }
898
899
900 $lastValStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $toEndPos, $text_len );
901
902 // parse last value
903 $args['last_val'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $lastValStartPos, $lastValEndPos, $text_len, $rootNamespace );
904
905 $asStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $lastValEndPos, $text_len );
906
907 // parse 'as'
908 $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $asStartPos, $text_len );
909 $as = substr( $text, $asStartPos, $asEndPos-$asStartPos );
910 if ( $as != 'as' )
911 {
912 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
913 'for', "Expected keyword 'as' not found" );
914 return;
915 }
916
917 $loopVarStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $asEndPos, $text_len );
918
919 // parse loop variable
920 $args['loop_var'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $loopVarStartPos, $loopVarEndPos, $text_len, $rootNamespace );
921
922 if ( $loopVarEndPos == $text_len ) // no more parameters
923 $cur_pos = $loopVarEndPos;
924 else
925 {
926 // skip whitespaces
927 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $loopVarEndPos, $text_len );
928
929 if ( ! $this->parseSequenceParameter( true, 'for',
930 $args, $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) )
931 return;
932 }
933 }
934
947 function parseForeachFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos,
948 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
949 {
950 // parse array
951 $args['array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
952
953 // skip whitespaces
954 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
955
956 // parse 'as' keyword
957 $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
958 $word = substr( $text, $cur_pos, $asEndPos-$cur_pos );
959 if ( $word != 'as' )
960 {
961 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
962 'foreach', "Expected keyword 'as' not found" );
963 return;
964 }
965 $cur_pos = $asEndPos;
966
967 // skip whitespaces
968 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
969
970 // parse variable name
971 $var1 = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
972
973 $nextTokenPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
974
975 // parse itemVar (if specified)
976 if ( $nextTokenPos <= ( $text_len-2 ) && $text[$nextTokenPos] == '=' && $text[$nextTokenPos+1] == '>' )
977 {
978 // skip whitespaces
979 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $nextTokenPos+2, $text_len );
980
981 $args['key_var'] = $var1;
982
983 // parse item variable name
984 $args['item_var'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
985 }
986 else
987 $args['item_var'] = $var1;
988
989 /*
990 * parse optional parameters
991 */
992
993 while ( $cur_pos < $text_len )
994 {
995 // skip whitespaces
996 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
997
998 $paramNameEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
999 $paramName = substr( $text, $cur_pos, $paramNameEndPos-$cur_pos );
1000 $cur_pos = $paramNameEndPos;
1001
1002 if ( $paramName == 'sequence' )
1003 {
1004 if ( ! $this->parseSequenceParameter( false, 'foreach',
1005 $args, $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) )
1006 return;
1007 }
1008 elseif ( $paramName == 'offset' )
1009 {
1010 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1011 $args['offset'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1012 }
1013 elseif ( $paramName == 'max' )
1014 {
1015 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1016 $args['max'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1017 }
1018 elseif ( $paramName == 'reverse' )
1019 {
1020 $reverseValText = '1';
1021 $args['reverse'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $reverseValText, 0, $reverseValPos, 1, $rootNamespace );
1022 }
1023 else
1024 {
1025 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1026 'foreach', "Unknown parameter '$paramName'" );
1027 return;
1028 }
1029 }
1030 }
1031
1044 function parseDoFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos,
1045 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1046 {
1047 // skip whitespaces
1048 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1049
1050 // parse while keyword
1051 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
1052 $word = substr( $text, $cur_pos, $wordEndPos-$cur_pos );
1053 if ( $word != 'while' )
1054 {
1055 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1056 'do', "Expected keyword 'while' not found in parameters" );
1057 return;
1058 }
1059 $cur_pos = $wordEndPos;
1060
1061 // skip whitespaces
1062 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1063
1064 $args['condition'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1065
1066 // skip whitespaces
1067 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1068
1069 if ( $cur_pos == $text_len ) // no more arguments
1070 return;
1071
1072 $this->parseSequenceParameter( true, 'do',
1073 $args, $tpl, $text, $text_len, $cur_pos,
1074 $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
1075 }
1076
1077
1087 function parseDefFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
1088 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1089 {
1090 if ( $cur_pos == $text_len && $funcName == 'def' ) // no more arguments
1091 {
1092 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1093 $funcName, 'Not enough arguments' );
1094 return;
1095 }
1096
1097 while ( $cur_pos < $text_len )
1098 {
1099 // parse variable name
1100 if ( $text[$cur_pos] != '$' )
1101 {
1102 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1103 $funcName, '($) expected' );
1104 return;
1105 }
1106
1107 $cur_pos++;
1108 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
1109 $varName = substr( $text, $cur_pos, $wordEndPos-$cur_pos );
1110 $cur_pos = $wordEndPos;
1111
1112 if ( !$varName )
1113 {
1114 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1115 $funcName, 'Empty variable name' );
1116 return;
1117 }
1118
1119 if ( $funcName == 'def' )
1120 {
1121 // skip whitespaces
1122 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1123
1124 // parse variable value
1125 if ( $cur_pos >= $text_len || $text[$cur_pos] != '=' )
1126 {
1127 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1128 $funcName, '(=) expected' );
1129 return;
1130 }
1131 $cur_pos++;
1132
1133 // skip whitespaces
1134 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1135
1136 $args[$varName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1137 }
1138 else
1139 {
1140 $varValueText = '1';
1141 $args[$varName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $varValueText, 0, $varValPos, 1, $rootNamespace );
1142 }
1143
1144
1145 // skip whitespaces
1146 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1147 }
1148 }
1149
1153 function parseUnnamedCondition( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
1154 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1155 {
1156 $cond = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1157 if ( !count( $cond ) )
1158 {
1159 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1160 $funcName, 'Not enough arguments' );
1161 return;
1162
1163 }
1164 $args['condition'] = $cond;
1165 }
1166
1170 function parseWhileFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos,
1171 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1172 {
1173 $cond = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1174 if ( !count( $cond ) )
1175 {
1176 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1177 'while', 'Not enough arguments' );
1178 return;
1179
1180 }
1181 $args['condition'] = $cond;
1182
1183 // skip whitespaces
1184 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1185
1186 if ( $cur_pos == $text_len ) // no more arguments
1187 return;
1188
1189 $this->parseSequenceParameter( true, 'while',
1190 $args, $tpl, $text, $text_len, $cur_pos,
1191 $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
1192 }
1193
1197 function parseSetFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
1198 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1199 {
1200 while ( $cur_pos < $text_len )
1201 {
1202 $dollarSignFound = false;
1203
1204 // skip optional dollar sign
1205 if ( $text[$cur_pos] == '$' )
1206 {
1207 $dollarSignFound = true;
1208 $cur_pos++;
1209 }
1210
1211 // parse variable name
1212 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
1213 $varName = substr( $text, $cur_pos, $wordEndPos-$cur_pos );
1214 $cur_pos = $wordEndPos;
1215
1216 if ( !$varName )
1217 {
1218 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1219 $funcName, 'Empty variable name' );
1220 return;
1221 }
1222
1223 /*
1224 * If parameter 'name' or 'scope' was passed without dollar sign
1225 * change its name to '-name' or '-scope', respectively.
1226 * In this case it is treated specially in the {set}/{let}/{default} functions.
1227 */
1228 if ( !$dollarSignFound && ( $varName == 'name' || $varName == 'scope' ) )
1229 $varName = "-$varName";
1230
1231 // skip whitespaces
1232 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1233
1234 // if no value, assume boolean true
1235 if ( $cur_pos >= $text_len or
1236 ( $text[$cur_pos] != '=' /*and preg_match( "/[ \t\r\n]/", $text[$cur_pos] )*/ ) )
1237 {
1238 unset( $var_data );
1239 $var_data = array();
1240 $args[$varName] = array( array( eZTemplate::TYPE_NUMERIC, // type
1241 true, // content
1242 false // debug
1243 ) );
1244 continue;
1245 }
1246
1247 if ( $cur_pos >= $text_len )
1248 break;
1249
1250 $cur_pos++;
1251
1252 // skip whitespaces
1253 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1254
1255 $args[$varName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1256
1257 // skip whitespaces
1258 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1259 }
1260 }
1261
1267 function parseBlockFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
1268 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1269 {
1270 while ( $cur_pos < $text_len )
1271 {
1272 // parse parameter name
1273 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
1274 $paramName = substr( $text, $cur_pos, $wordEndPos-$cur_pos );
1275 $cur_pos = $wordEndPos;
1276 if ( !$paramName )
1277 {
1278 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1279 $funcName, 'Empty parameter name' );
1280 return;
1281 }
1282
1283 // skip whitespaces
1284 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1285
1286 // skip (=)
1287 if ( $text[$cur_pos] != '=' )
1288 {
1289 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1290 $funcName, '(=) expected' );
1291 return;
1292 }
1293 $cur_pos++;
1294
1295 // skip whitespaces
1296 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1297
1298 // skip optional dollar sign
1299 if ( $paramName == 'variable' && $cur_pos < $text_len && $text[$cur_pos] == '$' )
1300 {
1301 $cur_pos++;
1302 }
1303
1304 // parse parameter value
1305 $args[$paramName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1306
1307 // skip whitespaces
1308 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1309 }
1310 }
1311
1317 function parseSectionFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
1318 $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
1319 {
1320 while ( $cur_pos < $text_len )
1321 {
1322 // parse parameter name
1323 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
1324 $paramName = substr( $text, $cur_pos, $wordEndPos-$cur_pos );
1325 $cur_pos = $wordEndPos;
1326 if ( !$paramName )
1327 {
1328 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
1329 $funcName, 'Empty parameter name' );
1330 return;
1331 }
1332
1333 // skip whitespaces
1334 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1335
1336 // skip (=)
1337 if ( $cur_pos >= $text_len || $text[$cur_pos] != '=' ) // if the parameter has no value, i.e. not followed by '=<value>'
1338 {
1339 // the parameter gets boolean true value.
1340 $args[$paramName] = array( array( eZTemplate::TYPE_NUMERIC, // type
1341 true, // content
1342 false // debug
1343 ) );
1344 continue;
1345 }
1346 $cur_pos++;
1347
1348 // skip whitespaces
1349 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1350
1351 // skip optional dollar sign that is allowed in value of 'var' parameter
1352 if ( $paramName == 'var' && $cur_pos < $text_len && $text[$cur_pos] == '$' )
1353 {
1354 $cur_pos++;
1355 }
1356
1357 // parse parameter value
1358 $args[$paramName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
1359
1360 // skip whitespaces
1361 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
1362 }
1363 }
1364
1365 function showParseErrorMessage( $tpl, &$text, $text_len, &$cur_pos, $tplName, $startLine, $startColumn, $funcName, $message )
1366 {
1367 $subText = substr( $text, 0, $cur_pos );
1368 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
1369 $tpl->error( $funcName, "parser error @ $tplName:$currentLine\n" .
1370 "$message at [" . substr( $text, $cur_pos ) . "]" );
1371 $cur_pos = $text_len;
1372 }
1373
1379 static function instance()
1380 {
1381 if ( !isset( $GLOBALS['eZTemplateMultiPassParserInstance'] ) ||
1382 !( $GLOBALS['eZTemplateMultiPassParserInstance'] instanceof eZTemplateMultiPassParser ) )
1383 {
1384 $GLOBALS['eZTemplateMultiPassParserInstance'] = new eZTemplateMultiPassParser();
1385 }
1386
1387 return $GLOBALS['eZTemplateMultiPassParserInstance'];
1388 }
1389
1391 public $ElementParser;
1392 }
1393
1394 ?>
eZDebug\addTimingPoint
static addTimingPoint( $description="")
Definition: ezdebug.php:676
eZDebug\accumulatorStart
static accumulatorStart( $key, $inGroup=false, $name=false, $recursive=false)
Definition: ezdebug.php:1361
eZDebug\accumulatorStop
static accumulatorStop( $key, $recursive=false)
Definition: ezdebug.php:1389
eZTemplateElementParser\instance
static instance()
Definition: eztemplateelementparser.php:590
eZTemplateMultiPassParser
The class eZTemplateMultiPassParser does.
Definition: eztemplatemultipassparser.php:18
eZTemplateMultiPassParser\parseForeachFunction
parseForeachFunction(&$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:947
eZTemplateMultiPassParser\parseSectionFunction
parseSectionFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:1317
eZTemplateMultiPassParser\$ElementParser
$ElementParser
Definition: eztemplatemultipassparser.php:1391
eZTemplateMultiPassParser\parseIntoTextElements
parseIntoTextElements( $tpl, $sourceText, $sourcePosition, $leftDelimiter, $rightDelimiter, $sourceLength, $relatedTemplateName)
Definition: eztemplatemultipassparser.php:77
eZTemplateMultiPassParser\parse
parse( $tpl, $sourceText, &$rootElement, $rootNamespace, &$resourceData)
Definition: eztemplatemultipassparser.php:30
eZTemplateMultiPassParser\parseWhileFunction
parseWhileFunction(&$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:1170
eZTemplateMultiPassParser\parseSetFunction
parseSetFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:1197
eZTemplateMultiPassParser\instance
static instance()
Definition: eztemplatemultipassparser.php:1379
eZTemplateMultiPassParser\__construct
__construct()
Definition: eztemplatemultipassparser.php:19
eZTemplateMultiPassParser\parseIntoTree
parseIntoTree( $tpl, &$textElements, &$treeRoot, $rootNamespace, $relatedResource, $relatedTemplateName)
Definition: eztemplatemultipassparser.php:395
eZTemplateMultiPassParser\parseDefFunction
parseDefFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:1087
eZTemplateMultiPassParser\parseWhitespaceRemoval
parseWhitespaceRemoval( $tpl, &$textElements)
Definition: eztemplatemultipassparser.php:306
eZTemplateMultiPassParser\showParseErrorMessage
showParseErrorMessage( $tpl, &$text, $text_len, &$cur_pos, $tplName, $startLine, $startColumn, $funcName, $message)
Definition: eztemplatemultipassparser.php:1365
eZTemplateMultiPassParser\parseBlockFunction
parseBlockFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:1267
eZTemplateMultiPassParser\gotoEndPosition
gotoEndPosition( $text, $line, $column, &$endLine, &$endColumn)
Definition: eztemplatemultipassparser.php:57
eZTemplateMultiPassParser\parseSequenceParameter
parseSequenceParameter( $parseSequenceKeyword, $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:815
eZTemplateMultiPassParser\parseForFunction
parseForFunction(&$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:877
eZTemplateMultiPassParser\appendChild
appendChild(&$root, &$node)
Definition: eztemplatemultipassparser.php:388
eZTemplateMultiPassParser\parseUnnamedCondition
parseUnnamedCondition( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace)
Definition: eztemplatemultipassparser.php:1153
eZTemplateParser
The class eZTemplateParser does.
Definition: eztemplateparser.php:18
eZTemplate\ELEMENT_COMMENT
const ELEMENT_COMMENT
Definition: eztemplate.php:208
eZTemplate\ELEMENT_NORMAL_TAG
const ELEMENT_NORMAL_TAG
Definition: eztemplate.php:205
eZTemplate\NODE_TEXT
const NODE_TEXT
Definition: eztemplate.php:211
eZTemplate\NODE_VARIABLE
const NODE_VARIABLE
Definition: eztemplate.php:212
eZTemplate\NODE_FUNCTION
const NODE_FUNCTION
Definition: eztemplate.php:213
eZTemplate\TYPE_NUMERIC
const TYPE_NUMERIC
Definition: eztemplate.php:248
eZTemplate\ELEMENT_TEXT
const ELEMENT_TEXT
Definition: eztemplate.php:203
eZTemplate\ELEMENT_END_TAG
const ELEMENT_END_TAG
Definition: eztemplate.php:206
eZTemplate\ELEMENT_SINGLE_TAG
const ELEMENT_SINGLE_TAG
Definition: eztemplate.php:204
eZTemplate\ELEMENT_VARIABLE
const ELEMENT_VARIABLE
Definition: eztemplate.php:207
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.