00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
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
00048
00049 function eZTemplateMultiPassParser()
00050 {
00051 $this->ElementParser = eZTemplateElementParser::instance();
00052 }
00053
00054
00055
00056
00057
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
00121 unset( $data );
00122 $data = substr( $sourceText, $sourcePosition );
00123 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
00124 $textElements[] = array( "text" => $data,
00125 "type" => EZ_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] == "*" )
00143 {
00144 $endPos = strpos( $sourceText, "*$rightDelimiter", $tagPos + 1 );
00145 $len = $endPos - $tagPos;
00146 if ( $sourcePosition < $blockStart )
00147 {
00148
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" => EZ_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" => EZ_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
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
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" => EZ_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
00233 $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition );
00234 $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
00235 $textElements[] = array( "text" => $data,
00236 "type" => EZ_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" => EZ_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 = EZ_ELEMENT_NORMAL_TAG;
00289 if ( $isEndTag )
00290 $type = EZ_ELEMENT_END_TAG;
00291 else if ( $isSingleTag )
00292 $type = EZ_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" => EZ_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 EZ_ELEMENT_COMMENT:
00350 {
00351
00352 } break;
00353
00354 case EZ_ELEMENT_TEXT:
00355 case EZ_ELEMENT_VARIABLE:
00356 {
00357 if ( $nextElement !== null )
00358 {
00359 switch ( $nextElement["type"] )
00360 {
00361 case EZ_ELEMENT_END_TAG:
00362 case EZ_ELEMENT_SINGLE_TAG:
00363 case EZ_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 EZ_ELEMENT_END_TAG:
00385 case EZ_ELEMENT_SINGLE_TAG:
00386 case EZ_ELEMENT_NORMAL_TAG:
00387 {
00388 if ( $nextElement !== null )
00389 {
00390 switch ( $nextElement["type"] )
00391 {
00392 case EZ_ELEMENT_TEXT:
00393 case EZ_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 EZ_ELEMENT_TEXT:
00455 {
00456 unset( $node );
00457 $node = array( EZ_TEMPLATE_NODE_TEXT,
00458 false,
00459 $element['text'],
00460 $placement );
00461 $this->appendChild( $currentRoot, $node );
00462 } break;
00463 case EZ_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( EZ_TEMPLATE_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 EZ_ELEMENT_SINGLE_TAG:
00489 case EZ_ELEMENT_NORMAL_TAG:
00490 case EZ_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
00504 if ( $type == EZ_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 == EZ_ELEMENT_END_TAG && $tag == 'do' )
00529 {
00530 $this->parseDoFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
00531 }
00532
00533
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
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( EZ_TEMPLATE_TYPE_NUMERIC,
00575 true,
00576 false
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 == EZ_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 == EZ_ELEMENT_NORMAL_TAG )
00616 {
00617 $ignoreCurrentTag = false;
00618 if( in_array( $tag, array_keys($outerElseTags) ) )
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
00631 {
00632
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
00646 $laterElements = array_slice( $textElements, $elementKey + 1 );
00647 $laterStack = array();
00648 foreach( $laterElements as $laterElement )
00649 {
00650 if ( $laterElement['type'] == EZ_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;
00661 }
00662 }
00663 }
00664 elseif ( $laterElement['type'] == EZ_ELEMENT_END_TAG )
00665 {
00666 if ( $laterStack !== array() )
00667 {
00668 if ( array_pop( $laterStack ) !== $laterElement['name'] )
00669 {
00670 break;
00671 }
00672 }
00673 else
00674 {
00675 if ( $laterElement['name'] == $oldTagName)
00676 {
00677 break;
00678 }
00679 elseif ( in_array( $laterElement['name'], $outerElseTags[$tag] ) )
00680 {
00681 $ignoreCurrentTag = false;
00682 break;
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( EZ_TEMPLATE_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 == EZ_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
00796 if ( $tag == 'do' )
00797 {
00798 $doOpenTag =& $currentRoot[1][count( $currentRoot[1] ) - 1];
00799 $doOpenTag[3] =& $args;
00800 }
00801 }
00802 }
00803 else
00804 {
00805 unset( $node );
00806 $node = array( EZ_TEMPLATE_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
00825
00826 function parseSequenceParameter( $parseSequenceKeyword, $funcName, &$args, &$tpl, &$text, &$text_len, &$cur_pos,
00827 $relatedTemplateName, $startLine, $startColumn, &$rootNamespace )
00828 {
00829 if ( $parseSequenceKeyword )
00830 {
00831
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
00843 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
00844 }
00845
00846
00847 $args['sequence_array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
00848
00849
00850 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
00851
00852
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
00865 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
00866
00867
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
00883
00884
00885
00886
00887
00888 function parseForFunction( &$args, &$tpl, &$text, &$text_len, &$cur_pos,
00889 $relatedTemplateName, $startLine, $startColumn, &$rootNamespace )
00890 {
00891 $firstValStartPos = $cur_pos;
00892
00893
00894 $firstVal = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $firstValStartPos, $firstValEndPos, $text_len, $rootNamespace
00895 );
00896 $args['first_val'] = $firstVal;
00897
00898 $toStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $firstValEndPos, $text_len );
00899
00900
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
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
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
00931 $args['loop_var'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $loopVarStartPos, $loopVarEndPos, $text_len, $rootNamespace );
00932
00933 if ( $loopVarEndPos == $text_len )
00934 $cur_pos = $loopVarEndPos;
00935 else
00936 {
00937
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
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 function parseForeachFunction( &$args, &$tpl, &$text, &$text_len, &$cur_pos,
00959 $relatedTemplateName, $startLine, $startColumn, &$rootNamespace )
00960 {
00961
00962 $args['array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
00963
00964
00965 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
00966
00967
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
00979 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
00980
00981
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
00987 if ( $nextTokenPos <= ( $text_len-2 ) && $text[$nextTokenPos] == '=' && $text[$nextTokenPos+1] == '>' )
00988 {
00989
00990 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $nextTokenPos+2, $text_len );
00991
00992 $args['key_var'] = $var1;
00993
00994
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
01002
01003
01004 while ( $cur_pos < $text_len )
01005 {
01006
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
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 function parseDoFunction( &$args, &$tpl, &$text, &$text_len, &$cur_pos,
01056 $relatedTemplateName, $startLine, $startColumn, &$rootNamespace )
01057 {
01058
01059 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01060
01061
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
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
01078 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01079
01080 if ( $cur_pos == $text_len )
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
01091
01092
01093
01094
01095
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' )
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
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
01133 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01134
01135
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
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
01157 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01158 }
01159 }
01160
01161
01162
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
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
01195 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01196
01197 if ( $cur_pos == $text_len )
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
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
01216 if ( $text[$cur_pos] == '$' )
01217 {
01218 $dollarSignFound = true;
01219 $cur_pos++;
01220 }
01221
01222
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
01236
01237
01238
01239 if ( !$dollarSignFound && ( $varName == 'name' || $varName == 'scope' ) )
01240 $varName = "-$varName";
01241
01242
01243 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01244
01245
01246 if ( $cur_pos >= $text_len or
01247 ( $text[$cur_pos] != '=' ) )
01248 {
01249 unset( $var_data );
01250 $var_data = array();
01251 $args[$varName] = array( array( EZ_TEMPLATE_TYPE_NUMERIC,
01252 true,
01253 false
01254 ) );
01255 continue;
01256 }
01257
01258 if ( $cur_pos >= $text_len )
01259 break;
01260
01261 $cur_pos++;
01262
01263
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
01269 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01270 }
01271 }
01272
01273
01274
01275
01276
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
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
01295 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01296
01297
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
01307 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01308
01309
01310 if ( $paramName == 'variable' && $cur_pos < $text_len && $text[$cur_pos] == '$' )
01311 {
01312 $cur_pos++;
01313 }
01314
01315
01316 $args[$paramName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
01317
01318
01319 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01320 }
01321 }
01322
01323
01324
01325
01326
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
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
01345 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01346
01347
01348 if ( $cur_pos >= $text_len || $text[$cur_pos] != '=' )
01349 {
01350
01351 $args[$paramName] = array( array( EZ_TEMPLATE_TYPE_NUMERIC,
01352 true,
01353 false
01354 ) );
01355 continue;
01356 }
01357 $cur_pos++;
01358
01359
01360 $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
01361
01362
01363 if ( $paramName == 'var' && $cur_pos < $text_len && $text[$cur_pos] == '$' )
01364 {
01365 $cur_pos++;
01366 }
01367
01368
01369 $args[$paramName] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
01370
01371
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 function &instance()
01386 {
01387 $instance =& $GLOBALS['eZTemplateMultiPassParserInstance'];
01388 if ( get_class( $instance ) != 'eztemplatemultipassparser' )
01389 {
01390 $instance = new eZTemplateMultiPassParser();
01391 }
01392 return $instance;
01393 }
01394
01395
01396 var $ElementParser;
01397 }
01398
01399 ?>