|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZTemplateMultiPassParser class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package lib 00009 */ 00010 00011 /*! 00012 \class eZTemplateMultiPassParser eztemplatemultipassparser.php 00013 \brief The class eZTemplateMultiPassParser does 00014 00015 */ 00016 00017 class eZTemplateMultiPassParser extends eZTemplateParser 00018 { 00019 /*! 00020 Constructor 00021 */ 00022 function eZTemplateMultiPassParser() 00023 { 00024 $this->ElementParser = eZTemplateElementParser::instance(); 00025 } 00026 00027 00028 /*! 00029 Parses the template file $sourceText. See the description of this class 00030 for more information on the parsing process. 00031 00032 */ 00033 function parse( $tpl, $sourceText, &$rootElement, $rootNamespace, &$resourceData ) 00034 { 00035 $relatedResource = $resourceData['resource']; 00036 $relatedTemplateName = $resourceData['template-filename']; 00037 00038 $currentRoot =& $rootElement; 00039 $leftDelimiter = $tpl->LDelim; 00040 $rightDelimiter = $tpl->RDelim; 00041 $sourceLength = strlen( $sourceText ); 00042 $sourcePosition = 0; 00043 00044 eZDebug::accumulatorStart( 'template_multi_parser_1', 'template_total', 'Template parser: create text elements' ); 00045 $textElements = $this->parseIntoTextElements( $tpl, $sourceText, $sourcePosition, 00046 $leftDelimiter, $rightDelimiter, $sourceLength, 00047 $relatedTemplateName ); 00048 eZDebug::accumulatorStop( 'template_multi_parser_1' ); 00049 00050 eZDebug::accumulatorStart( 'template_multi_parser_2', 'template_total', 'Template parser: remove whitespace' ); 00051 $textElements = $this->parseWhitespaceRemoval( $tpl, $textElements ); 00052 eZDebug::accumulatorStop( 'template_multi_parser_2' ); 00053 00054 eZDebug::accumulatorStart( 'template_multi_parser_3', 'template_total', 'Template parser: construct tree' ); 00055 $this->parseIntoTree( $tpl, $textElements, $currentRoot, 00056 $rootNamespace, $relatedResource, $relatedTemplateName ); 00057 eZDebug::accumulatorStop( 'template_multi_parser_3' ); 00058 } 00059 00060 function gotoEndPosition( $text, $line, $column, &$endLine, &$endColumn ) 00061 { 00062 $lines = preg_split( "#\r\n|\r|\n#", $text ); 00063 $c = count( $lines ); 00064 if ( $c > 0 ) 00065 { 00066 $endLine = $line + $c - 1; 00067 $lastLine = $lines[$c - 1]; 00068 if ( $c > 1 ) 00069 $endColumn = strlen( $lastLine ); 00070 else 00071 $endColumn = $column + strlen( $lastLine ); 00072 } 00073 else 00074 { 00075 $endLine = $line; 00076 $endColumn = $column; 00077 } 00078 } 00079 00080 function parseIntoTextElements( $tpl, $sourceText, $sourcePosition, 00081 $leftDelimiter, $rightDelimiter, $sourceLength, 00082 $relatedTemplateName ) 00083 { 00084 if ( $tpl->ShowDetails ) 00085 eZDebug::addTimingPoint( "Parse pass 1 (simple tag parsing)" ); 00086 $currentLine = 1; 00087 $currentColumn = 0; 00088 $textElements = array(); 00089 while( $sourcePosition < $sourceLength ) 00090 { 00091 $tagPos = strpos( $sourceText, $leftDelimiter, $sourcePosition ); 00092 if ( $tagPos === false ) 00093 { 00094 // No more tags 00095 unset( $data ); 00096 $data = substr( $sourceText, $sourcePosition ); 00097 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn ); 00098 $textElements[] = array( "text" => $data, 00099 "type" => eZTemplate::ELEMENT_TEXT, 00100 'placement' => array( 'templatefile' => $relatedTemplateName, 00101 'start' => array( 'line' => $currentLine, 00102 'column' => $currentColumn, 00103 'position' => $sourcePosition ), 00104 'stop' => array( 'line' => $endLine, 00105 'column' => $endColumn, 00106 'position' => $sourceLength - 1 ) ) ); 00107 $sourcePosition = $sourceLength; 00108 $currentLine = $endLine; 00109 $currentColumn = $endColumn; 00110 } 00111 else 00112 { 00113 $blockStart = $tagPos; 00114 $tagPos++; 00115 if ( $tagPos < $sourceLength and 00116 $sourceText[$tagPos] == "*" ) // Comment 00117 { 00118 $endPos = strpos( $sourceText, "*$rightDelimiter", $tagPos + 1 ); 00119 $len = $endPos - $tagPos; 00120 if ( $sourcePosition < $blockStart ) 00121 { 00122 // Add text before tag. 00123 unset( $data ); 00124 $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition ); 00125 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn ); 00126 $textElements[] = array( "text" => $data, 00127 "type" => eZTemplate::ELEMENT_TEXT, 00128 'placement' => array( 'templatefile' => $relatedTemplateName, 00129 'start' => array( 'line' => $currentLine, 00130 'column' => $currentColumn, 00131 'position' => $sourcePosition ), 00132 'stop' => array( 'line' => $endLine, 00133 'column' => $endColumn, 00134 'position' => $blockStart ) ) ); 00135 $currentLine = $endLine; 00136 $currentColumn = $endColumn; 00137 } 00138 if ( $endPos === false ) 00139 { 00140 $endPos = $sourceLength; 00141 $blockEnd = $sourceLength; 00142 } 00143 else 00144 { 00145 $blockEnd = $endPos + 2; 00146 } 00147 $comment_text = substr( $sourceText, $tagPos + 1, $endPos - $tagPos - 1 ); 00148 $this->gotoEndPosition( $comment_text, $currentLine, $currentColumn, $endLine, $endColumn ); 00149 $textElements[] = array( "text" => $comment_text, 00150 "type" => eZTemplate::ELEMENT_COMMENT, 00151 'placement' => array( 'templatefile' => $relatedTemplateName, 00152 'start' => array( 'line' => $currentLine, 00153 'column' => $currentColumn, 00154 'position' => $tagPos + 1 ), 00155 'stop' => array( 'line' => $endLine, 00156 'column' => $endColumn, 00157 'position' => $endPos - 1 ) ) ); 00158 if ( $sourcePosition < $blockEnd ) 00159 $sourcePosition = $blockEnd; 00160 $currentLine = $endLine; 00161 $currentColumn = $endColumn; 00162 // eZDebug::writeDebug( "eZTemplate: Comment: $comment" ); 00163 } 00164 else 00165 { 00166 $tmp_pos = $tagPos; 00167 while( ( $endPos = strpos( $sourceText, $rightDelimiter, $tmp_pos ) ) !== false ) 00168 { 00169 if ( $sourceText[$endPos-1] != "\\" ) 00170 break; 00171 $tmp_pos = $endPos + 1; 00172 } 00173 if ( $endPos === false ) 00174 { 00175 // Unterminated tag 00176 $data = substr( $sourceText, $sourcePosition ); 00177 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn ); 00178 $textBefore = substr( $sourceText, $sourcePosition, $tagPos - $sourcePosition ); 00179 $textPortion = substr( $sourceText, $tagPos ); 00180 $this->gotoEndPosition( $textBefore, $currentLine, $currentColumn, $tagStartLine, $tagStartColumn ); 00181 $this->gotoEndPosition( $textPortion, $tagStartLine, $tagStartColumn, $tagEndLine, $tagEndColumn ); 00182 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" . 00183 "Unterminated tag, needs a $rightDelimiter to end the tag.\n" . $leftDelimiter . $textPortion, 00184 array( array( $tagStartLine, $tagStartColumn, $tagPosition ), 00185 array( $tagEndLine, $tagEndColumn, $sourceLength - 1 ), 00186 $relatedTemplateName ) ); 00187 $textElements[] = array( "text" => $data, 00188 "type" => eZTemplate::ELEMENT_TEXT, 00189 'placement' => array( 'templatefile' => $relatedTemplateName, 00190 'start' => array( 'line' => $currentLine, 00191 'column' => $currentColumn, 00192 'position' => $sourcePosition ), 00193 'stop' => array( 'line' => $endLine, 00194 'column' => $endColumn, 00195 'position' => $sourceLength - 1 ) ) ); 00196 $sourcePosition = $sourceLength; 00197 $currentLine = $endLine; 00198 $currentColumn = $endColumn; 00199 } 00200 else 00201 { 00202 $blockEnd = $endPos + 1; 00203 $len = $endPos - $tagPos; 00204 if ( $sourcePosition < $blockStart ) 00205 { 00206 // Add text before tag. 00207 $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition ); 00208 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn ); 00209 $textElements[] = array( "text" => $data, 00210 "type" => eZTemplate::ELEMENT_TEXT, 00211 'placement' => array( 'templatefile' => $relatedTemplateName, 00212 'start' => array( 'line' => $currentLine, 00213 'column' => $currentColumn, 00214 'position' => $sourcePosition ), 00215 'stop' => array( 'line' => $endLine, 00216 'column' => $endColumn, 00217 'position' => $blockStart ) ) ); 00218 $currentLine = $endLine; 00219 $currentColumn = $endColumn; 00220 } 00221 00222 $tag = substr( $sourceText, $tagPos, $len ); 00223 $tag = preg_replace( "/\\\\[}]/", "}", $tag ); 00224 $tagTrim = trim( $tag ); 00225 $isEndTag = false; 00226 $isSingleTag = false; 00227 00228 if ( $tag[0] == "/" ) 00229 { 00230 $isEndTag = true; 00231 $tag = substr( $tag, 1 ); 00232 } 00233 else if ( $tagTrim[strlen( $tagTrim ) - 1] == "/" ) 00234 { 00235 $isSingleTag = true; 00236 $tagTrim = trim( substr( $tagTrim, 0, strlen( $tagTrim ) - 1 ) ); 00237 $tag = $tagTrim; 00238 } 00239 00240 $this->gotoEndPosition( $tag, $currentLine, $currentColumn, $endLine, $endColumn ); 00241 if ( $tag[0] == "$" or 00242 $tag[0] == "\"" or 00243 $tag[0] == "'" or 00244 is_numeric( $tag[0] ) or 00245 ( $tag[0] == '-' and 00246 isset( $tag[1] ) and 00247 is_numeric( $tag[1] ) ) or 00248 preg_match( "/^[a-z0-9_-]+\(/", $tag ) ) 00249 { 00250 $textElements[] = array( "text" => $tag, 00251 "type" => eZTemplate::ELEMENT_VARIABLE, 00252 'placement' => array( 'templatefile' => $relatedTemplateName, 00253 'start' => array( 'line' => $currentLine, 00254 'column' => $currentColumn, 00255 'position' => $blockStart + 1 ), 00256 'stop' => array( 'line' => $endLine, 00257 'column' => $endColumn, 00258 'position' => $blockEnd - 1 ) ) ); 00259 } 00260 else 00261 { 00262 $type = eZTemplate::ELEMENT_NORMAL_TAG; 00263 if ( $isEndTag ) 00264 $type = eZTemplate::ELEMENT_END_TAG; 00265 else if ( $isSingleTag ) 00266 $type = eZTemplate::ELEMENT_SINGLE_TAG; 00267 $spacepos = strpos( $tag, " " ); 00268 if ( $spacepos === false ) 00269 $name = $tag; 00270 else 00271 $name = substr( $tag, 0, $spacepos ); 00272 if ( isset( $tpl->Literals[$name] ) ) 00273 { 00274 $literalEndTag = "{/$name}"; 00275 $literalEndPos = strpos( $sourceText, $literalEndTag, $blockEnd ); 00276 if ( $literalEndPos === false ) 00277 $literalEndPos = $sourceLength; 00278 $data = substr( $sourceText, $blockEnd, $literalEndPos - $blockEnd ); 00279 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn ); 00280 $blockEnd = $literalEndPos + strlen( $literalEndTag ); 00281 $textElements[] = array( "text" => $data, 00282 "type" => eZTemplate::ELEMENT_TEXT, 00283 'placement' => false ); 00284 } 00285 else 00286 $textElements[] = array( "text" => $tag, 00287 "name" => $name, 00288 "type" => $type, 00289 'placement' => array( 'templatefile' => $relatedTemplateName, 00290 'start' => array( 'line' => $currentLine, 00291 'column' => $currentColumn, 00292 'position' => $blockStart + 1 ), 00293 'stop' => array( 'line' => $endLine, 00294 'column' => $endColumn, 00295 'position' => $blockEnd - 1 ) ) ); 00296 } 00297 00298 if ( $sourcePosition < $blockEnd ) 00299 $sourcePosition = $blockEnd; 00300 $currentLine = $endLine; 00301 $currentColumn = $endColumn; 00302 } 00303 } 00304 } 00305 } 00306 return $textElements; 00307 } 00308 00309 function parseWhitespaceRemoval( $tpl, &$textElements ) 00310 { 00311 if ( $tpl->ShowDetails ) 00312 eZDebug::addTimingPoint( "Parse pass 2 (whitespace removal)" ); 00313 $tempTextElements = array(); 00314 $textElements[] = null; 00315 00316 $element = false; 00317 foreach( $textElements as $nextElement ) 00318 { 00319 if ( $element ) 00320 { 00321 switch ( $element["type"] ) 00322 { 00323 case eZTemplate::ELEMENT_COMMENT: 00324 { 00325 // Ignore comments 00326 } break; 00327 00328 case eZTemplate::ELEMENT_TEXT: 00329 case eZTemplate::ELEMENT_VARIABLE: 00330 { 00331 if ( $nextElement !== null ) 00332 { 00333 switch ( $nextElement["type"] ) 00334 { 00335 case eZTemplate::ELEMENT_END_TAG: 00336 case eZTemplate::ELEMENT_SINGLE_TAG: 00337 case eZTemplate::ELEMENT_NORMAL_TAG: 00338 { 00339 $text = $element["text"]; 00340 $text_cnt = strlen( $text ); 00341 if ( $text_cnt > 0 ) 00342 { 00343 $char = $text[$text_cnt - 1]; 00344 if ( $char == "\n" ) 00345 { 00346 $element["text"] = substr( $text, 0, $text_cnt - 1 ); 00347 } 00348 } 00349 } break; 00350 } 00351 } 00352 if ( $element["text"] !== '' ) 00353 { 00354 $tempTextElements[] = $element; 00355 } 00356 } break; 00357 00358 case eZTemplate::ELEMENT_END_TAG: 00359 case eZTemplate::ELEMENT_SINGLE_TAG: 00360 case eZTemplate::ELEMENT_NORMAL_TAG: 00361 { 00362 if ( $nextElement !== null ) 00363 { 00364 switch ( $nextElement["type"] ) 00365 { 00366 case eZTemplate::ELEMENT_TEXT: 00367 case eZTemplate::ELEMENT_VARIABLE: 00368 { 00369 $text = $nextElement["text"]; 00370 $text_cnt = strlen( $text ); 00371 if ( $text_cnt > 0 ) 00372 { 00373 $char = $text[0]; 00374 if ( $char == "\n" ) 00375 { 00376 $nextElement["text"] = substr( $text, 1 ); 00377 } 00378 } 00379 } break; 00380 } 00381 } 00382 $tempTextElements[] = $element; 00383 } break; 00384 } 00385 } 00386 $element = $nextElement; 00387 } 00388 return $tempTextElements; 00389 } 00390 00391 function appendChild( &$root, &$node ) 00392 { 00393 if ( !is_array( $root[1] ) ) 00394 $root[1] = array(); 00395 $root[1][] =& $node; 00396 } 00397 00398 function parseIntoTree( $tpl, &$textElements, &$treeRoot, 00399 $rootNamespace, $relatedResource, $relatedTemplateName ) 00400 { 00401 $outerElseTags = array( 'else' => array( 'if', 'elseif' ), 'section-else' => array( 'section' ) ); 00402 00403 $currentRoot =& $treeRoot; 00404 if ( $tpl->ShowDetails ) 00405 eZDebug::addTimingPoint( "Parse pass 3 (build tree)" ); 00406 00407 $tagStack = array(); 00408 00409 foreach( $textElements as $elementKey => $element ) 00410 { 00411 $elementPlacement = $element['placement']; 00412 $startLine = $elementPlacement['start']['line']; 00413 $startColumn = $elementPlacement['start']['column']; 00414 $startPosition = $elementPlacement['start']['position']; 00415 $stopLine = $elementPlacement['stop']['line']; 00416 $stopColumn = $elementPlacement['stop']['column']; 00417 $stopPosition = $elementPlacement['stop']['position']; 00418 $templateFile = $elementPlacement['templatefile']; 00419 $placement = array( array( $startLine, 00420 $startColumn, 00421 $startPosition ), 00422 array( $stopLine, 00423 $stopColumn, 00424 $stopPosition ), 00425 $templateFile ); 00426 switch ( $element["type"] ) 00427 { 00428 case eZTemplate::ELEMENT_TEXT: 00429 { 00430 unset( $node ); 00431 $node = array( eZTemplate::NODE_TEXT, 00432 false, 00433 $element['text'], 00434 $placement ); 00435 $this->appendChild( $currentRoot, $node ); 00436 } break; 00437 case eZTemplate::ELEMENT_VARIABLE: 00438 { 00439 $text = $element["text"]; 00440 $text_len = strlen( $text ); 00441 $var_data = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, 0, $var_end, $text_len, $rootNamespace ); 00442 00443 unset( $node ); 00444 $node = array( eZTemplate::NODE_VARIABLE, 00445 false, 00446 $var_data, 00447 $placement ); 00448 $this->appendChild( $currentRoot, $node ); 00449 if ( $var_end < $text_len ) 00450 { 00451 $placement = $element['placement']; 00452 $startLine = $placement['start']['line']; 00453 $startColumn = $placement['start']['column']; 00454 $subText = substr( $text, 0, $var_end ); 00455 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn ); 00456 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" . 00457 "Extra characters found in expression, they will be ignored.\n" . 00458 substr( $text, $var_end, $text_len - $var_end ) . "' (" . substr( $text, 0, $var_end ) . ")", 00459 $placement ); 00460 } 00461 } break; 00462 case eZTemplate::ELEMENT_SINGLE_TAG: 00463 case eZTemplate::ELEMENT_NORMAL_TAG: 00464 case eZTemplate::ELEMENT_END_TAG: 00465 { 00466 $text = $element["text"]; 00467 $text_len = strlen( $text ); 00468 $type = $element["type"]; 00469 00470 $ident_pos = $this->ElementParser->identifierEndPosition( $tpl, $text, 0, $text_len ); 00471 $tag = substr( $text, 0, $ident_pos - 0 ); 00472 $attr_pos = $ident_pos; 00473 unset( $args ); 00474 00475 $args = array(); 00476 00477 // special handling for some functions having complex syntax 00478 if ( $type == eZTemplate::ELEMENT_NORMAL_TAG && 00479 in_array( $tag, array( 'if', 'elseif', 'while', 'for', 'foreach', 'def', 'undef', 00480 'set', 'let', 'default', 'set-block', 'append-block', 'section' ) ) ) 00481 { 00482 $attr_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_pos, $text_len ); 00483 00484 00485 if ( $tag == 'if' || $tag == 'elseif' ) 00486 $this->parseUnnamedCondition( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00487 elseif ( $tag == 'while' ) 00488 $this->parseWhileFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00489 elseif ( $tag == 'for' ) 00490 $this->parseForFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00491 elseif ( $tag == 'foreach' ) 00492 $this->parseForeachFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00493 elseif ( $tag == 'def' || $tag == 'undef' ) 00494 $this->parseDefFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00495 elseif ( $tag == 'set' || $tag == 'let' || $tag == 'default' ) 00496 $this->parseSetFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00497 elseif ( $tag == 'set-block' || $tag == 'append-block' ) 00498 $this->parseBlockFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00499 elseif ( $tag == 'section' ) 00500 $this->parseSectionFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00501 } 00502 elseif ( $type == eZTemplate::ELEMENT_END_TAG && $tag == 'do' ) 00503 { 00504 $this->parseDoFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 00505 } 00506 00507 // other functions having simplier syntax are parsed below 00508 $lastPosition = false; 00509 while ( $attr_pos < $text_len ) 00510 { 00511 if ( $lastPosition !== false and 00512 $lastPosition == $attr_pos ) 00513 { 00514 break; 00515 } 00516 $lastPosition = $attr_pos; 00517 $attr_pos_start = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_pos, $text_len ); 00518 if ( $attr_pos_start == $attr_pos and 00519 $attr_pos_start < $text_len ) 00520 { 00521 $placement = $element['placement']; 00522 $startLine = $placement['start']['line']; 00523 $startColumn = $placement['start']['column']; 00524 $subText = substr( $text, 0, $attr_pos ); 00525 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn ); 00526 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" . 00527 "Extra characters found, should have been a whitespace or the end of the expression\n". 00528 "Characters: '" . substr( $text, $attr_pos ) . "'" ); 00529 break; 00530 } 00531 $attr_pos = $attr_pos_start; 00532 $attr_name_pos = $this->ElementParser->identifierEndPosition( $tpl, $text, $attr_pos, $text_len ); 00533 $attr_name = substr( $text, $attr_pos, $attr_name_pos - $attr_pos ); 00534 00535 /* Skip whitespace between here and the next one */ 00536 $equal_sign_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_name_pos, $text_len ); 00537 if ( ( $equal_sign_pos < $text_len ) && ( $text[$equal_sign_pos] == '=' ) ) 00538 { 00539 $attr_name_pos = $equal_sign_pos; 00540 } 00541 00542 if ( $attr_name_pos >= $text_len or 00543 ( $text[$attr_name_pos] != '=' and 00544 preg_match( "/[ \t\r\n]/", $text[$attr_name_pos] ) ) ) 00545 { 00546 unset( $var_data ); 00547 $var_data = array(); 00548 $var_data[] = array( eZTemplate::TYPE_NUMERIC, // type 00549 true, // content 00550 false // debug 00551 ); 00552 $args[$attr_name] = $var_data; 00553 $attr_pos = $attr_name_pos; 00554 continue; 00555 } 00556 if ( $text[$attr_name_pos] != "=" ) 00557 { 00558 $placement = $element['placement']; 00559 $startLine = $placement['start']['line']; 00560 $startColumn = $placement['start']['column']; 00561 $subText = substr( $text, 0, $attr_name_pos ); 00562 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn ); 00563 $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]\n". 00564 "Invalid parameter characters in function '$tag': '" . 00565 substr( $text, $attr_name_pos ) . "'" ); 00566 break; 00567 } 00568 ++$attr_name_pos; 00569 unset( $var_data ); 00570 $var_data = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $attr_name_pos, $var_end, $text_len, $rootNamespace ); 00571 $args[$attr_name] = $var_data; 00572 $attr_pos = $var_end; 00573 } 00574 00575 if ( $type == eZTemplate::ELEMENT_END_TAG and count( $args ) > 0 ) 00576 { 00577 if ( $tag != 'do' ) 00578 { 00579 $placement = $element['placement']; 00580 $startLine = $placement['start']['line']; 00581 $startColumn = $placement['start']['column']; 00582 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" . 00583 "End tag \"$tag\" cannot have attributes\n$tpl->LDelim/" . $text . $tpl->RDelim, 00584 $element['placement'] ); 00585 $args = array(); 00586 } 00587 } 00588 00589 if ( $type == eZTemplate::ELEMENT_NORMAL_TAG ) 00590 { 00591 $ignoreCurrentTag = false; 00592 if( in_array( $tag, array_keys($outerElseTags) ) ) // 'esle'-kind operators 00593 { 00594 unset( $oldTag ); 00595 unset( $oldTagName ); 00596 $oldTag = end( $tagStack ); 00597 $oldTagName = $oldTag["Tag"]; 00598 00599 $ignoreCurrentTag = true; 00600 if ( in_array( $oldTagName, $outerElseTags[$tag] ) ) 00601 { 00602 $ignoreCurrentTag = false; 00603 } 00604 else // if there is incorrect 'else' using 00605 { 00606 // checking for 'if' in stack 00607 $tagBackStack = $tagStack; 00608 $lastIfKey = false; 00609 foreach ( $tagBackStack as $prevTagKey => $prevTag ) 00610 { 00611 if ( in_array( $prevTag['Tag'], $outerElseTags[$tag] ) ) 00612 { 00613 $lastIfKey = $prevTagKey; 00614 } 00615 } 00616 00617 if( $lastIfKey !== false ) 00618 { 00619 // checking for later tags (search for closing tag) 00620 $laterElements = array_slice( $textElements, $elementKey + 1 ); 00621 $laterStack = array(); 00622 foreach( $laterElements as $laterElement ) 00623 { 00624 if ( $laterElement['type'] == eZTemplate::ELEMENT_NORMAL_TAG) 00625 { 00626 if( !in_array( $laterElement['name'], array_keys($outerElseTags) ) ) 00627 { 00628 $laterStack[] = $laterElement['name']; 00629 } 00630 else 00631 { 00632 if ( $laterStack === array() ) 00633 { 00634 break; // double else (current else will be ignored) 00635 } 00636 } 00637 } 00638 elseif ( $laterElement['type'] == eZTemplate::ELEMENT_END_TAG ) 00639 { 00640 if ( $laterStack !== array() ) 00641 { 00642 if ( array_pop( $laterStack ) !== $laterElement['name'] ) 00643 { 00644 break; // later tags mismatch (current else will be ignored) 00645 } 00646 } 00647 else 00648 { 00649 if ( $laterElement['name'] == $oldTagName) 00650 { 00651 break; // previous tag correctly closed (current else will be ignored) 00652 } 00653 elseif ( in_array( $laterElement['name'], $outerElseTags[$tag] ) ) 00654 { 00655 $ignoreCurrentTag = false; 00656 break; // 'if' tag correctly closed (inner tags must be closed too) 00657 } 00658 } 00659 } 00660 } 00661 } 00662 00663 $place = $element['placement']; 00664 $startLine = $place['start']['line']; 00665 $startColumn = $place['start']['column']; 00666 if ( $ignoreCurrentTag ) 00667 { 00668 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" . 00669 "Unterminated tag \"$oldTagName\" does not match tag \"$tag\". \"$tag\" will be ignored.", 00670 $element['placement'] ); 00671 } 00672 else 00673 { 00674 unset( $currentRoot ); 00675 $lastIfKey++; 00676 $currentRoot =& $tagStack[$lastIfKey]["Root"]; 00677 00678 $autoTerminatedTags = array_slice( $tagStack, $lastIfKey); 00679 $autoTerminatedTagNames = array(); 00680 foreach( $autoTerminatedTags as $autoTerminatedTag) 00681 $autoTerminatedTagNames[] = $autoTerminatedTag["Tag"]; 00682 $tagStack = array_slice( $tagStack, 0, $lastIfKey); 00683 00684 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" . 00685 "Unterminated tag \"".implode( "\", \"", $autoTerminatedTagNames)."\" does not match tag \"$tag\" and will be autoterminated.", 00686 $element['placement'] ); 00687 unset( $autoTerminatedTags ); 00688 unset( $autoTerminatedTagNames ); 00689 } 00690 unset( $lastIfKey ); 00691 } 00692 } 00693 00694 if ( !$ignoreCurrentTag ) 00695 { 00696 unset( $node ); 00697 $node = array( eZTemplate::NODE_FUNCTION, 00698 false, 00699 $tag, 00700 $args, 00701 $placement ); 00702 $this->appendChild( $currentRoot, $node ); 00703 $has_children = true; 00704 if ( isset( $tpl->FunctionAttributes[$tag] ) ) 00705 { 00706 if ( is_array( $tpl->FunctionAttributes[$tag] ) ) 00707 $tpl->loadAndRegisterFunctions( $tpl->FunctionAttributes[$tag] ); 00708 $has_children = $tpl->FunctionAttributes[$tag]; 00709 } 00710 else if ( isset( $tpl->Functions[$tag] ) ) 00711 { 00712 if ( is_array( $tpl->Functions[$tag] ) ) 00713 $tpl->loadAndRegisterFunctions( $tpl->Functions[$tag] ); 00714 $has_children = $tpl->hasChildren( $tpl->Functions[$tag], $tag ); 00715 } 00716 if ( $has_children ) 00717 { 00718 $tagStack[] = array( "Root" => &$currentRoot, 00719 "Tag" => $tag ); 00720 unset( $currentRoot ); 00721 $currentRoot =& $node; 00722 } 00723 } 00724 } 00725 else if ( $type == eZTemplate::ELEMENT_END_TAG ) 00726 { 00727 $has_children = true; 00728 if ( isset( $tpl->FunctionAttributes[$tag] ) ) 00729 { 00730 if ( is_array( $tpl->FunctionAttributes[$tag] ) ) 00731 $tpl->loadAndRegisterFunctions( $tpl->FunctionAttributes[$tag] ); 00732 $has_children = $tpl->FunctionAttributes[$tag]; 00733 } 00734 else if ( isset( $tpl->Functions[$tag] ) ) 00735 { 00736 if ( is_array( $tpl->Functions[$tag] ) ) 00737 $tpl->loadAndRegisterFunctions( $tpl->Functions[$tag] ); 00738 $has_children = $tpl->hasChildren( $tpl->Functions[$tag], $tag ); 00739 } 00740 if ( !$has_children ) 00741 { 00742 $placement = $element['placement']; 00743 $startLine = $placement['start']['line']; 00744 $startColumn = $placement['start']['column']; 00745 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" . 00746 "End tag \"$tag\" for function which does not accept children, ignoring tag", 00747 $element['placement'] ); 00748 } 00749 else 00750 { 00751 unset( $oldTag ); 00752 unset( $oldTagName ); 00753 $oldTag = array_pop( $tagStack ); 00754 $oldTagName = $oldTag["Tag"]; 00755 unset( $currentRoot ); 00756 $currentRoot =& $oldTag["Root"]; 00757 00758 if ( $oldTagName != $tag ) 00759 { 00760 $placement = $element['placement']; 00761 $startLine = $placement['start']['line']; 00762 $startColumn = $placement['start']['column']; 00763 $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" . 00764 "Unterminated tag \"$oldTagName\" does not match tag \"$tag\"", 00765 $element['placement'] ); 00766 } 00767 00768 // a dirty hack to pass arguments specified in {/do} to the corresponding function. 00769 if ( $tag == 'do' ) 00770 { 00771 $doOpenTag =& $currentRoot[1][count( $currentRoot[1] ) - 1]; 00772 $doOpenTag[3] =& $args; 00773 } 00774 } 00775 } 00776 else // eZTemplate::ELEMENT_SINGLE_TAG 00777 { 00778 unset( $node ); 00779 $node = array( eZTemplate::NODE_FUNCTION, 00780 false, 00781 $tag, 00782 $args, 00783 $placement ); 00784 $this->appendChild( $currentRoot, $node ); 00785 } 00786 unset( $tag ); 00787 00788 } break; 00789 } 00790 } 00791 00792 if ( $tpl->ShowDetails ) 00793 eZDebug::addTimingPoint( "Parse pass 3 done" ); 00794 } 00795 00796 /*! 00797 * parse 'sequence' loop parameter: "sequence <array> as <$seqVar>" 00798 */ 00799 function parseSequenceParameter( $parseSequenceKeyword, $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, 00800 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 00801 { 00802 if ( $parseSequenceKeyword ) 00803 { 00804 // parse 'sequence' keyword 00805 $sequenceEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 00806 $sequence = substr( $text, $cur_pos, $sequenceEndPos-$cur_pos ); 00807 if ( $sequence != 'sequence' ) 00808 { 00809 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 00810 $funcName, "Expected keyword 'sequence' not found" ); 00811 return false; 00812 } 00813 $cur_pos = $sequenceEndPos; 00814 00815 // skip whitespaces 00816 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00817 } 00818 00819 // parse sequence array 00820 $args['sequence_array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 00821 00822 // skip whitespaces 00823 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00824 00825 // parse 'as' keyword 00826 $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 00827 $word = substr( $text, $cur_pos, $asEndPos-$cur_pos ); 00828 if ( $word != 'as' ) 00829 { 00830 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 00831 $funcName, "Expected keyword 'as' not found" ); 00832 unset( $args['sequence_array'] ); 00833 return false; 00834 } 00835 $cur_pos = $asEndPos; 00836 00837 // skip whitespaces 00838 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00839 00840 // parse sequence variable 00841 $seqVar = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 00842 if ( !$seqVar ) 00843 { 00844 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 00845 $funcName, "Sequence variable name cannot be empty" ); 00846 unset( $args['sequence_array'] ); 00847 return false; 00848 } 00849 $args['sequence_var'] = $seqVar; 00850 00851 return true; 00852 } 00853 00854 /*! 00855 Parse {for} function. 00856 Syntax: 00857 \code 00858 // for <firstValue> to <lastValue> as <$loopVar> [sequence <array> as <$var>] 00859 \endcode 00860 */ 00861 function parseForFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos, 00862 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 00863 { 00864 $firstValStartPos = $cur_pos; 00865 00866 // parse first value 00867 $firstVal = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $firstValStartPos, $firstValEndPos, $text_len, $rootNamespace 00868 /*, eZTemplate::TYPE_NUMERIC_BIT | eZTemplate::TYPE_VARIABLE_BIT*/ ); 00869 $args['first_val'] = $firstVal; 00870 00871 $toStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $firstValEndPos, $text_len ); 00872 00873 // parse 'to' 00874 $toEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $toStartPos, $text_len ); 00875 $to = substr( $text, $toStartPos, $toEndPos-$toStartPos ); 00876 if ( $to != 'to' ) 00877 { 00878 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 00879 'for', "Expected keyword 'to' not found" ); 00880 return; 00881 } 00882 00883 00884 $lastValStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $toEndPos, $text_len ); 00885 00886 // parse last value 00887 $args['last_val'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $lastValStartPos, $lastValEndPos, $text_len, $rootNamespace ); 00888 00889 $asStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $lastValEndPos, $text_len ); 00890 00891 // parse 'as' 00892 $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $asStartPos, $text_len ); 00893 $as = substr( $text, $asStartPos, $asEndPos-$asStartPos ); 00894 if ( $as != 'as' ) 00895 { 00896 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 00897 'for', "Expected keyword 'as' not found" ); 00898 return; 00899 } 00900 00901 $loopVarStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $asEndPos, $text_len ); 00902 00903 // parse loop variable 00904 $args['loop_var'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $loopVarStartPos, $loopVarEndPos, $text_len, $rootNamespace ); 00905 00906 if ( $loopVarEndPos == $text_len ) // no more parameters 00907 $cur_pos = $loopVarEndPos; 00908 else 00909 { 00910 // skip whitespaces 00911 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $loopVarEndPos, $text_len ); 00912 00913 if ( ! $this->parseSequenceParameter( true, 'for', 00914 $args, $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) ) 00915 return; 00916 } 00917 } 00918 00919 /*! 00920 Parse {foreach} function. 00921 Syntax: 00922 \code 00923 {foreach <array> as [$keyVar =>] $itemVar 00924 [sequence <array> as $sequenceVar] 00925 [offset <offset>] 00926 [max <max>] 00927 [reverse] 00928 } 00929 \endcode 00930 */ 00931 function parseForeachFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos, 00932 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 00933 { 00934 // parse array 00935 $args['array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 00936 00937 // skip whitespaces 00938 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00939 00940 // parse 'as' keyword 00941 $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 00942 $word = substr( $text, $cur_pos, $asEndPos-$cur_pos ); 00943 if ( $word != 'as' ) 00944 { 00945 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 00946 'foreach', "Expected keyword 'as' not found" ); 00947 return; 00948 } 00949 $cur_pos = $asEndPos; 00950 00951 // skip whitespaces 00952 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00953 00954 // parse variable name 00955 $var1 = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 00956 00957 $nextTokenPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00958 00959 // parse itemVar (if specified) 00960 if ( $nextTokenPos <= ( $text_len-2 ) && $text[$nextTokenPos] == '=' && $text[$nextTokenPos+1] == '>' ) 00961 { 00962 // skip whitespaces 00963 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $nextTokenPos+2, $text_len ); 00964 00965 $args['key_var'] = $var1; 00966 00967 // parse item variable name 00968 $args['item_var'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 00969 } 00970 else 00971 $args['item_var'] = $var1; 00972 00973 /* 00974 * parse optional parameters 00975 */ 00976 00977 while ( $cur_pos < $text_len ) 00978 { 00979 // skip whitespaces 00980 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00981 00982 $paramNameEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 00983 $paramName = substr( $text, $cur_pos, $paramNameEndPos-$cur_pos ); 00984 $cur_pos = $paramNameEndPos; 00985 00986 if ( $paramName == 'sequence' ) 00987 { 00988 if ( ! $this->parseSequenceParameter( false, 'foreach', 00989 $args, $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) ) 00990 return; 00991 } 00992 elseif ( $paramName == 'offset' ) 00993 { 00994 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 00995 $args['offset'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 00996 } 00997 elseif ( $paramName == 'max' ) 00998 { 00999 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01000 $args['max'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01001 } 01002 elseif ( $paramName == 'reverse' ) 01003 { 01004 $reverseValText = '1'; 01005 $args['reverse'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $reverseValText, 0, $reverseValPos, 1, $rootNamespace ); 01006 } 01007 else 01008 { 01009 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01010 'foreach', "Unknown parameter '$paramName'" ); 01011 return; 01012 } 01013 } 01014 } 01015 01016 /*! 01017 Parse do..while function 01018 Syntax: 01019 \code 01020 01021 {do} 01022 [{delimiter}...{/delimiter}] 01023 [{break}] 01024 [{continue}] 01025 [{skip}] 01026 {/do while <condition> [sequence <array> as $seqVar]} 01027 */ 01028 function parseDoFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos, 01029 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01030 { 01031 // skip whitespaces 01032 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01033 01034 // parse while keyword 01035 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 01036 $word = substr( $text, $cur_pos, $wordEndPos-$cur_pos ); 01037 if ( $word != 'while' ) 01038 { 01039 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01040 'do', "Expected keyword 'while' not found in parameters" ); 01041 return; 01042 } 01043 $cur_pos = $wordEndPos; 01044 01045 // skip whitespaces 01046 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01047 01048 $args['condition'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01049 01050 // skip whitespaces 01051 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01052 01053 if ( $cur_pos == $text_len ) // no more arguments 01054 return; 01055 01056 $this->parseSequenceParameter( true, 'do', 01057 $args, $tpl, $text, $text_len, $cur_pos, 01058 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 01059 } 01060 01061 01062 /*! 01063 Parse def/undef functions 01064 Syntax: 01065 \code 01066 {def $var1=<value1> [$var2=<value2> ...]} 01067 {undef [$var1 [$var2] ...]} 01068 \endcode 01069 */ 01070 01071 function parseDefFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, 01072 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01073 { 01074 if ( $cur_pos == $text_len && $funcName == 'def' ) // no more arguments 01075 { 01076 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01077 $funcName, 'Not enough arguments' ); 01078 return; 01079 } 01080 01081 while ( $cur_pos < $text_len ) 01082 { 01083 // parse variable name 01084 if ( $text[$cur_pos] != '$' ) 01085 { 01086 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01087 $funcName, '($) expected' ); 01088 return; 01089 } 01090 01091 $cur_pos++; 01092 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 01093 $varName = substr( $text, $cur_pos, $wordEndPos-$cur_pos ); 01094 $cur_pos = $wordEndPos; 01095 01096 if ( !$varName ) 01097 { 01098 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01099 $funcName, 'Empty variable name' ); 01100 return; 01101 } 01102 01103 if ( $funcName == 'def' ) 01104 { 01105 // skip whitespaces 01106 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01107 01108 // parse variable value 01109 if ( $cur_pos >= $text_len || $text[$cur_pos] != '=' ) 01110 { 01111 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01112 $funcName, '(=) expected' ); 01113 return; 01114 } 01115 $cur_pos++; 01116 01117 // skip whitespaces 01118 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01119 01120 $args[$varName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01121 } 01122 else 01123 { 01124 $varValueText = '1'; 01125 $args[$varName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $varValueText, 0, $varValPos, 1, $rootNamespace ); 01126 } 01127 01128 01129 // skip whitespaces 01130 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01131 } 01132 } 01133 01134 /*! 01135 Parse arguments for {if}/{elseif} 01136 */ 01137 function parseUnnamedCondition( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, 01138 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01139 { 01140 $cond = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01141 if ( !count( $cond ) ) 01142 { 01143 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01144 $funcName, 'Not enough arguments' ); 01145 return; 01146 01147 } 01148 $args['condition'] = $cond; 01149 } 01150 01151 /*! 01152 Parse arguments for {while} 01153 */ 01154 function parseWhileFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos, 01155 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01156 { 01157 $cond = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01158 if ( !count( $cond ) ) 01159 { 01160 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01161 'while', 'Not enough arguments' ); 01162 return; 01163 01164 } 01165 $args['condition'] = $cond; 01166 01167 // skip whitespaces 01168 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01169 01170 if ( $cur_pos == $text_len ) // no more arguments 01171 return; 01172 01173 $this->parseSequenceParameter( true, 'while', 01174 $args, $tpl, $text, $text_len, $cur_pos, 01175 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ); 01176 } 01177 01178 /*! 01179 Parse arguments for {set}/{let}/{default} 01180 */ 01181 function parseSetFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, 01182 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01183 { 01184 while ( $cur_pos < $text_len ) 01185 { 01186 $dollarSignFound = false; 01187 01188 // skip optional dollar sign 01189 if ( $text[$cur_pos] == '$' ) 01190 { 01191 $dollarSignFound = true; 01192 $cur_pos++; 01193 } 01194 01195 // parse variable name 01196 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 01197 $varName = substr( $text, $cur_pos, $wordEndPos-$cur_pos ); 01198 $cur_pos = $wordEndPos; 01199 01200 if ( !$varName ) 01201 { 01202 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01203 $funcName, 'Empty variable name' ); 01204 return; 01205 } 01206 01207 /* 01208 * If parameter 'name' or 'scope' was passed without dollar sign 01209 * change its name to '-name' or '-scope', respectively. 01210 * In this case it is treated specially in the {set}/{let}/{default} functions. 01211 */ 01212 if ( !$dollarSignFound && ( $varName == 'name' || $varName == 'scope' ) ) 01213 $varName = "-$varName"; 01214 01215 // skip whitespaces 01216 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01217 01218 // if no value, assume boolean true 01219 if ( $cur_pos >= $text_len or 01220 ( $text[$cur_pos] != '=' /*and preg_match( "/[ \t\r\n]/", $text[$cur_pos] )*/ ) ) 01221 { 01222 unset( $var_data ); 01223 $var_data = array(); 01224 $args[$varName] = array( array( eZTemplate::TYPE_NUMERIC, // type 01225 true, // content 01226 false // debug 01227 ) ); 01228 continue; 01229 } 01230 01231 if ( $cur_pos >= $text_len ) 01232 break; 01233 01234 $cur_pos++; 01235 01236 // skip whitespaces 01237 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01238 01239 $args[$varName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01240 01241 // skip whitespaces 01242 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01243 } 01244 } 01245 01246 /*! 01247 Parse arguments for {set-block}/{append-block}. 01248 This method has been created to correctly handle the case when ($) is used in variable name, e.g. {set-block variable=$var} 01249 Here we strip the dollar sign and pass the variable name as string. 01250 */ 01251 function parseBlockFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, 01252 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01253 { 01254 while ( $cur_pos < $text_len ) 01255 { 01256 // parse parameter name 01257 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 01258 $paramName = substr( $text, $cur_pos, $wordEndPos-$cur_pos ); 01259 $cur_pos = $wordEndPos; 01260 if ( !$paramName ) 01261 { 01262 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01263 $funcName, 'Empty parameter name' ); 01264 return; 01265 } 01266 01267 // skip whitespaces 01268 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01269 01270 // skip (=) 01271 if ( $text[$cur_pos] != '=' ) 01272 { 01273 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01274 $funcName, '(=) expected' ); 01275 return; 01276 } 01277 $cur_pos++; 01278 01279 // skip whitespaces 01280 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01281 01282 // skip optional dollar sign 01283 if ( $paramName == 'variable' && $cur_pos < $text_len && $text[$cur_pos] == '$' ) 01284 { 01285 $cur_pos++; 01286 } 01287 01288 // parse parameter value 01289 $args[$paramName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01290 01291 // skip whitespaces 01292 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01293 } 01294 } 01295 01296 /*! 01297 Parse arguments for {section}. 01298 This method has been created to correctly handle the case when ($) is used in variable name, e.g. {section var=$item} 01299 Here we strip the dollar sign and pass the variable name as string. 01300 */ 01301 function parseSectionFunction( $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos, 01302 $relatedTemplateName, $startLine, $startColumn, $rootNamespace ) 01303 { 01304 while ( $cur_pos < $text_len ) 01305 { 01306 // parse parameter name 01307 $wordEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len ); 01308 $paramName = substr( $text, $cur_pos, $wordEndPos-$cur_pos ); 01309 $cur_pos = $wordEndPos; 01310 if ( !$paramName ) 01311 { 01312 $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn, 01313 $funcName, 'Empty parameter name' ); 01314 return; 01315 } 01316 01317 // skip whitespaces 01318 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01319 01320 // skip (=) 01321 if ( $cur_pos >= $text_len || $text[$cur_pos] != '=' ) // if the parameter has no value, i.e. not followed by '=<value>' 01322 { 01323 // the parameter gets boolean true value. 01324 $args[$paramName] = array( array( eZTemplate::TYPE_NUMERIC, // type 01325 true, // content 01326 false // debug 01327 ) ); 01328 continue; 01329 } 01330 $cur_pos++; 01331 01332 // skip whitespaces 01333 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01334 01335 // skip optional dollar sign that is allowed in value of 'var' parameter 01336 if ( $paramName == 'var' && $cur_pos < $text_len && $text[$cur_pos] == '$' ) 01337 { 01338 $cur_pos++; 01339 } 01340 01341 // parse parameter value 01342 $args[$paramName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace ); 01343 01344 // skip whitespaces 01345 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len ); 01346 } 01347 } 01348 01349 function showParseErrorMessage( $tpl, &$text, $text_len, &$cur_pos, $tplName, $startLine, $startColumn, $funcName, $message ) 01350 { 01351 $subText = substr( $text, 0, $cur_pos ); 01352 $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn ); 01353 $tpl->error( $funcName, "parser error @ $tplName:$currentLine\n" . 01354 "$message at [" . substr( $text, $cur_pos ) . "]" ); 01355 $cur_pos = $text_len; 01356 } 01357 01358 /** 01359 * Returns a shared instance of the eZTemplateMultiPassParser class. 01360 * 01361 * @return eZTemplateMultiPassParser 01362 */ 01363 static function instance() 01364 { 01365 if ( !isset( $GLOBALS['eZTemplateMultiPassParserInstance'] ) || 01366 !( $GLOBALS['eZTemplateMultiPassParserInstance'] instanceof eZTemplateMultiPassParser ) ) 01367 { 01368 $GLOBALS['eZTemplateMultiPassParserInstance'] = new eZTemplateMultiPassParser(); 01369 } 01370 01371 return $GLOBALS['eZTemplateMultiPassParserInstance']; 01372 } 01373 01374 /// \privatesection 01375 public $ElementParser; 01376 } 01377 01378 ?>