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