/lib/eztemplate/classes/eztemplatemultipassparser.php
https://github.com/GunioRobot/ezpublish · PHP · 904 lines · 865 code · 13 blank · 26 comment · 21 complexity · 496f2c01f632da39af2099c4c818d3a4 MD5 · raw file
- <?php
- /**
- * File containing the eZTemplateMultiPassParser class.
- *
- * @copyright Copyright (C) 1999-2011 eZ Systems AS. All rights reserved.
- * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
- * @version //autogentag//
- * @package lib
- */
- /*!
- \class eZTemplateMultiPassParser eztemplatemultipassparser.php
- \brief The class eZTemplateMultiPassParser does
- */
- class eZTemplateMultiPassParser extends eZTemplateParser
- {
- /*!
- Constructor
- */
- function eZTemplateMultiPassParser()
- {
- $this->ElementParser = eZTemplateElementParser::instance();
- }
- /*!
- Parses the template file $sourceText. See the description of this class
- for more information on the parsing process.
- */
- function parse( $tpl, $sourceText, &$rootElement, $rootNamespace, &$resourceData )
- {
- $relatedResource = $resourceData['resource'];
- $relatedTemplateName = $resourceData['template-filename'];
- $currentRoot =& $rootElement;
- $leftDelimiter = $tpl->LDelim;
- $rightDelimiter = $tpl->RDelim;
- $sourceLength = strlen( $sourceText );
- $sourcePosition = 0;
- eZDebug::accumulatorStart( 'template_multi_parser_1', 'template_total', 'Template parser: create text elements' );
- $textElements = $this->parseIntoTextElements( $tpl, $sourceText, $sourcePosition,
- $leftDelimiter, $rightDelimiter, $sourceLength,
- $relatedTemplateName );
- eZDebug::accumulatorStop( 'template_multi_parser_1' );
- eZDebug::accumulatorStart( 'template_multi_parser_2', 'template_total', 'Template parser: remove whitespace' );
- $textElements = $this->parseWhitespaceRemoval( $tpl, $textElements );
- eZDebug::accumulatorStop( 'template_multi_parser_2' );
- eZDebug::accumulatorStart( 'template_multi_parser_3', 'template_total', 'Template parser: construct tree' );
- $this->parseIntoTree( $tpl, $textElements, $currentRoot,
- $rootNamespace, $relatedResource, $relatedTemplateName );
- eZDebug::accumulatorStop( 'template_multi_parser_3' );
- }
- function gotoEndPosition( $text, $line, $column, &$endLine, &$endColumn )
- {
- $lines = preg_split( "#\r\n|\r|\n#", $text );
- $c = count( $lines );
- if ( $c > 0 )
- {
- $endLine = $line + $c - 1;
- $lastLine = $lines[$c - 1];
- if ( $c > 1 )
- $endColumn = strlen( $lastLine );
- else
- $endColumn = $column + strlen( $lastLine );
- }
- else
- {
- $endLine = $line;
- $endColumn = $column;
- }
- }
- function parseIntoTextElements( $tpl, $sourceText, $sourcePosition,
- $leftDelimiter, $rightDelimiter, $sourceLength,
- $relatedTemplateName )
- {
- if ( $tpl->ShowDetails )
- eZDebug::addTimingPoint( "Parse pass 1 (simple tag parsing)" );
- $currentLine = 1;
- $currentColumn = 0;
- $textElements = array();
- while( $sourcePosition < $sourceLength )
- {
- $tagPos = strpos( $sourceText, $leftDelimiter, $sourcePosition );
- if ( $tagPos === false )
- {
- // No more tags
- unset( $data );
- $data = substr( $sourceText, $sourcePosition );
- $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
- $textElements[] = array( "text" => $data,
- "type" => eZTemplate::ELEMENT_TEXT,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $sourcePosition ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $sourceLength - 1 ) ) );
- $sourcePosition = $sourceLength;
- $currentLine = $endLine;
- $currentColumn = $endColumn;
- }
- else
- {
- $blockStart = $tagPos;
- $tagPos++;
- if ( $tagPos < $sourceLength and
- $sourceText[$tagPos] == "*" ) // Comment
- {
- $endPos = strpos( $sourceText, "*$rightDelimiter", $tagPos + 1 );
- $len = $endPos - $tagPos;
- if ( $sourcePosition < $blockStart )
- {
- // Add text before tag.
- unset( $data );
- $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition );
- $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
- $textElements[] = array( "text" => $data,
- "type" => eZTemplate::ELEMENT_TEXT,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $sourcePosition ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $blockStart ) ) );
- $currentLine = $endLine;
- $currentColumn = $endColumn;
- }
- if ( $endPos === false )
- {
- $endPos = $sourceLength;
- $blockEnd = $sourceLength;
- }
- else
- {
- $blockEnd = $endPos + 2;
- }
- $comment_text = substr( $sourceText, $tagPos + 1, $endPos - $tagPos - 1 );
- $this->gotoEndPosition( $comment_text, $currentLine, $currentColumn, $endLine, $endColumn );
- $textElements[] = array( "text" => $comment_text,
- "type" => eZTemplate::ELEMENT_COMMENT,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $tagPos + 1 ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $endPos - 1 ) ) );
- if ( $sourcePosition < $blockEnd )
- $sourcePosition = $blockEnd;
- $currentLine = $endLine;
- $currentColumn = $endColumn;
- // eZDebug::writeDebug( "eZTemplate: Comment: $comment" );
- }
- else
- {
- $tmp_pos = $tagPos;
- while( ( $endPos = strpos( $sourceText, $rightDelimiter, $tmp_pos ) ) !== false )
- {
- if ( $sourceText[$endPos-1] != "\\" )
- break;
- $tmp_pos = $endPos + 1;
- }
- if ( $endPos === false )
- {
- // Unterminated tag
- $data = substr( $sourceText, $sourcePosition );
- $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
- $textBefore = substr( $sourceText, $sourcePosition, $tagPos - $sourcePosition );
- $textPortion = substr( $sourceText, $tagPos );
- $this->gotoEndPosition( $textBefore, $currentLine, $currentColumn, $tagStartLine, $tagStartColumn );
- $this->gotoEndPosition( $textPortion, $tagStartLine, $tagStartColumn, $tagEndLine, $tagEndColumn );
- $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" .
- "Unterminated tag, needs a $rightDelimiter to end the tag.\n" . $leftDelimiter . $textPortion,
- array( array( $tagStartLine, $tagStartColumn, $tagPosition ),
- array( $tagEndLine, $tagEndColumn, $sourceLength - 1 ),
- $relatedTemplateName ) );
- $textElements[] = array( "text" => $data,
- "type" => eZTemplate::ELEMENT_TEXT,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $sourcePosition ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $sourceLength - 1 ) ) );
- $sourcePosition = $sourceLength;
- $currentLine = $endLine;
- $currentColumn = $endColumn;
- }
- else
- {
- $blockEnd = $endPos + 1;
- $len = $endPos - $tagPos;
- if ( $sourcePosition < $blockStart )
- {
- // Add text before tag.
- $data = substr( $sourceText, $sourcePosition, $blockStart - $sourcePosition );
- $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
- $textElements[] = array( "text" => $data,
- "type" => eZTemplate::ELEMENT_TEXT,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $sourcePosition ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $blockStart ) ) );
- $currentLine = $endLine;
- $currentColumn = $endColumn;
- }
- $tag = substr( $sourceText, $tagPos, $len );
- $tag = preg_replace( "/\\\\[}]/", "}", $tag );
- $tagTrim = trim( $tag );
- $isEndTag = false;
- $isSingleTag = false;
- if ( $tag[0] == "/" )
- {
- $isEndTag = true;
- $tag = substr( $tag, 1 );
- }
- else if ( $tagTrim[strlen( $tagTrim ) - 1] == "/" )
- {
- $isSingleTag = true;
- $tagTrim = trim( substr( $tagTrim, 0, strlen( $tagTrim ) - 1 ) );
- $tag = $tagTrim;
- }
- $this->gotoEndPosition( $tag, $currentLine, $currentColumn, $endLine, $endColumn );
- if ( $tag[0] == "$" or
- $tag[0] == "\"" or
- $tag[0] == "'" or
- is_numeric( $tag[0] ) or
- ( $tag[0] == '-' and
- isset( $tag[1] ) and
- is_numeric( $tag[1] ) ) or
- preg_match( "/^[a-z0-9_-]+\(/", $tag ) )
- {
- $textElements[] = array( "text" => $tag,
- "type" => eZTemplate::ELEMENT_VARIABLE,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $blockStart + 1 ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $blockEnd - 1 ) ) );
- }
- else
- {
- $type = eZTemplate::ELEMENT_NORMAL_TAG;
- if ( $isEndTag )
- $type = eZTemplate::ELEMENT_END_TAG;
- else if ( $isSingleTag )
- $type = eZTemplate::ELEMENT_SINGLE_TAG;
- $spacepos = strpos( $tag, " " );
- if ( $spacepos === false )
- $name = $tag;
- else
- $name = substr( $tag, 0, $spacepos );
- if ( isset( $tpl->Literals[$name] ) )
- {
- $literalEndTag = "{/$name}";
- $literalEndPos = strpos( $sourceText, $literalEndTag, $blockEnd );
- if ( $literalEndPos === false )
- $literalEndPos = $sourceLength;
- $data = substr( $sourceText, $blockEnd, $literalEndPos - $blockEnd );
- $this->gotoEndPosition( $data, $currentLine, $currentColumn, $endLine, $endColumn );
- $blockEnd = $literalEndPos + strlen( $literalEndTag );
- $textElements[] = array( "text" => $data,
- "type" => eZTemplate::ELEMENT_TEXT,
- 'placement' => false );
- }
- else
- $textElements[] = array( "text" => $tag,
- "name" => $name,
- "type" => $type,
- 'placement' => array( 'templatefile' => $relatedTemplateName,
- 'start' => array( 'line' => $currentLine,
- 'column' => $currentColumn,
- 'position' => $blockStart + 1 ),
- 'stop' => array( 'line' => $endLine,
- 'column' => $endColumn,
- 'position' => $blockEnd - 1 ) ) );
- }
- if ( $sourcePosition < $blockEnd )
- $sourcePosition = $blockEnd;
- $currentLine = $endLine;
- $currentColumn = $endColumn;
- }
- }
- }
- }
- return $textElements;
- }
- function parseWhitespaceRemoval( $tpl, &$textElements )
- {
- if ( $tpl->ShowDetails )
- eZDebug::addTimingPoint( "Parse pass 2 (whitespace removal)" );
- $tempTextElements = array();
- $textElements[] = null;
- $element = false;
- foreach( $textElements as $nextElement )
- {
- if ( $element )
- {
- switch ( $element["type"] )
- {
- case eZTemplate::ELEMENT_COMMENT:
- {
- // Ignore comments
- } break;
- case eZTemplate::ELEMENT_TEXT:
- case eZTemplate::ELEMENT_VARIABLE:
- {
- if ( $nextElement !== null )
- {
- switch ( $nextElement["type"] )
- {
- case eZTemplate::ELEMENT_END_TAG:
- case eZTemplate::ELEMENT_SINGLE_TAG:
- case eZTemplate::ELEMENT_NORMAL_TAG:
- {
- $text = $element["text"];
- $text_cnt = strlen( $text );
- if ( $text_cnt > 0 )
- {
- $char = $text[$text_cnt - 1];
- if ( $char == "\n" )
- {
- $element["text"] = substr( $text, 0, $text_cnt - 1 );
- }
- }
- } break;
- }
- }
- if ( $element["text"] !== '' )
- {
- $tempTextElements[] = $element;
- }
- } break;
- case eZTemplate::ELEMENT_END_TAG:
- case eZTemplate::ELEMENT_SINGLE_TAG:
- case eZTemplate::ELEMENT_NORMAL_TAG:
- {
- if ( $nextElement !== null )
- {
- switch ( $nextElement["type"] )
- {
- case eZTemplate::ELEMENT_TEXT:
- case eZTemplate::ELEMENT_VARIABLE:
- {
- $text = $nextElement["text"];
- $text_cnt = strlen( $text );
- if ( $text_cnt > 0 )
- {
- $char = $text[0];
- if ( $char == "\n" )
- {
- $nextElement["text"] = substr( $text, 1 );
- }
- }
- } break;
- }
- }
- $tempTextElements[] = $element;
- } break;
- }
- }
- $element = $nextElement;
- }
- return $tempTextElements;
- }
- function appendChild( &$root, &$node )
- {
- if ( !is_array( $root[1] ) )
- $root[1] = array();
- $root[1][] =& $node;
- }
- function parseIntoTree( $tpl, &$textElements, &$treeRoot,
- $rootNamespace, $relatedResource, $relatedTemplateName )
- {
- $outerElseTags = array( 'else' => array( 'if', 'elseif' ), 'section-else' => array( 'section' ) );
- $currentRoot =& $treeRoot;
- if ( $tpl->ShowDetails )
- eZDebug::addTimingPoint( "Parse pass 3 (build tree)" );
- $tagStack = array();
- foreach( $textElements as $elementKey => $element )
- {
- $elementPlacement = $element['placement'];
- $startLine = $elementPlacement['start']['line'];
- $startColumn = $elementPlacement['start']['column'];
- $startPosition = $elementPlacement['start']['position'];
- $stopLine = $elementPlacement['stop']['line'];
- $stopColumn = $elementPlacement['stop']['column'];
- $stopPosition = $elementPlacement['stop']['position'];
- $templateFile = $elementPlacement['templatefile'];
- $placement = array( array( $startLine,
- $startColumn,
- $startPosition ),
- array( $stopLine,
- $stopColumn,
- $stopPosition ),
- $templateFile );
- switch ( $element["type"] )
- {
- case eZTemplate::ELEMENT_TEXT:
- {
- unset( $node );
- $node = array( eZTemplate::NODE_TEXT,
- false,
- $element['text'],
- $placement );
- $this->appendChild( $currentRoot, $node );
- } break;
- case eZTemplate::ELEMENT_VARIABLE:
- {
- $text = $element["text"];
- $text_len = strlen( $text );
- $var_data = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, 0, $var_end, $text_len, $rootNamespace );
- unset( $node );
- $node = array( eZTemplate::NODE_VARIABLE,
- false,
- $var_data,
- $placement );
- $this->appendChild( $currentRoot, $node );
- if ( $var_end < $text_len )
- {
- $placement = $element['placement'];
- $startLine = $placement['start']['line'];
- $startColumn = $placement['start']['column'];
- $subText = substr( $text, 0, $var_end );
- $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
- $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" .
- "Extra characters found in expression, they will be ignored.\n" .
- substr( $text, $var_end, $text_len - $var_end ) . "' (" . substr( $text, 0, $var_end ) . ")",
- $placement );
- }
- } break;
- case eZTemplate::ELEMENT_SINGLE_TAG:
- case eZTemplate::ELEMENT_NORMAL_TAG:
- case eZTemplate::ELEMENT_END_TAG:
- {
- $text = $element["text"];
- $text_len = strlen( $text );
- $type = $element["type"];
- $ident_pos = $this->ElementParser->identifierEndPosition( $tpl, $text, 0, $text_len );
- $tag = substr( $text, 0, $ident_pos - 0 );
- $attr_pos = $ident_pos;
- unset( $args );
- $args = array();
- // special handling for some functions having complex syntax
- if ( $type == eZTemplate::ELEMENT_NORMAL_TAG &&
- in_array( $tag, array( 'if', 'elseif', 'while', 'for', 'foreach', 'def', 'undef',
- 'set', 'let', 'default', 'set-block', 'append-block', 'section' ) ) )
- {
- $attr_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_pos, $text_len );
- if ( $tag == 'if' || $tag == 'elseif' )
- $this->parseUnnamedCondition( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'while' )
- $this->parseWhileFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'for' )
- $this->parseForFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'foreach' )
- $this->parseForeachFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'def' || $tag == 'undef' )
- $this->parseDefFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'set' || $tag == 'let' || $tag == 'default' )
- $this->parseSetFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'set-block' || $tag == 'append-block' )
- $this->parseBlockFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- elseif ( $tag == 'section' )
- $this->parseSectionFunction( $tag, $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- }
- elseif ( $type == eZTemplate::ELEMENT_END_TAG && $tag == 'do' )
- {
- $this->parseDoFunction( $args, $tpl, $text, $text_len, $attr_pos, $relatedTemplateName, $startLine, $startColumn, $rootNamespace );
- }
- // other functions having simplier syntax are parsed below
- $lastPosition = false;
- while ( $attr_pos < $text_len )
- {
- if ( $lastPosition !== false and
- $lastPosition == $attr_pos )
- {
- break;
- }
- $lastPosition = $attr_pos;
- $attr_pos_start = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_pos, $text_len );
- if ( $attr_pos_start == $attr_pos and
- $attr_pos_start < $text_len )
- {
- $placement = $element['placement'];
- $startLine = $placement['start']['line'];
- $startColumn = $placement['start']['column'];
- $subText = substr( $text, 0, $attr_pos );
- $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
- $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]" . "\n" .
- "Extra characters found, should have been a whitespace or the end of the expression\n".
- "Characters: '" . substr( $text, $attr_pos ) . "'" );
- break;
- }
- $attr_pos = $attr_pos_start;
- $attr_name_pos = $this->ElementParser->identifierEndPosition( $tpl, $text, $attr_pos, $text_len );
- $attr_name = substr( $text, $attr_pos, $attr_name_pos - $attr_pos );
- /* Skip whitespace between here and the next one */
- $equal_sign_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $attr_name_pos, $text_len );
- if ( ( $equal_sign_pos < $text_len ) && ( $text[$equal_sign_pos] == '=' ) )
- {
- $attr_name_pos = $equal_sign_pos;
- }
- if ( $attr_name_pos >= $text_len or
- ( $text[$attr_name_pos] != '=' and
- preg_match( "/[ \t\r\n]/", $text[$attr_name_pos] ) ) )
- {
- unset( $var_data );
- $var_data = array();
- $var_data[] = array( eZTemplate::TYPE_NUMERIC, // type
- true, // content
- false // debug
- );
- $args[$attr_name] = $var_data;
- $attr_pos = $attr_name_pos;
- continue;
- }
- if ( $text[$attr_name_pos] != "=" )
- {
- $placement = $element['placement'];
- $startLine = $placement['start']['line'];
- $startColumn = $placement['start']['column'];
- $subText = substr( $text, 0, $attr_name_pos );
- $this->gotoEndPosition( $subText, $startLine, $startColumn, $currentLine, $currentColumn );
- $tpl->error( "", "parser error @ $relatedTemplateName:$currentLine" . "[$currentColumn]\n".
- "Invalid parameter characters in function '$tag': '" .
- substr( $text, $attr_name_pos ) . "'" );
- break;
- }
- ++$attr_name_pos;
- unset( $var_data );
- $var_data = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $attr_name_pos, $var_end, $text_len, $rootNamespace );
- $args[$attr_name] = $var_data;
- $attr_pos = $var_end;
- }
- if ( $type == eZTemplate::ELEMENT_END_TAG and count( $args ) > 0 )
- {
- if ( $tag != 'do' )
- {
- $placement = $element['placement'];
- $startLine = $placement['start']['line'];
- $startColumn = $placement['start']['column'];
- $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
- "End tag \"$tag\" cannot have attributes\n$tpl->LDelim/" . $text . $tpl->RDelim,
- $element['placement'] );
- $args = array();
- }
- }
- if ( $type == eZTemplate::ELEMENT_NORMAL_TAG )
- {
- $ignoreCurrentTag = false;
- if( in_array( $tag, array_keys($outerElseTags) ) ) // 'esle'-kind operators
- {
- unset( $oldTag );
- unset( $oldTagName );
- $oldTag = end( $tagStack );
- $oldTagName = $oldTag["Tag"];
- $ignoreCurrentTag = true;
- if ( in_array( $oldTagName, $outerElseTags[$tag] ) )
- {
- $ignoreCurrentTag = false;
- }
- else // if there is incorrect 'else' using
- {
- // checking for 'if' in stack
- $tagBackStack = $tagStack;
- $lastIfKey = false;
- foreach ( $tagBackStack as $prevTagKey => $prevTag )
- {
- if ( in_array( $prevTag['Tag'], $outerElseTags[$tag] ) )
- {
- $lastIfKey = $prevTagKey;
- }
- }
- if( $lastIfKey !== false )
- {
- // checking for later tags (search for closing tag)
- $laterElements = array_slice( $textElements, $elementKey + 1 );
- $laterStack = array();
- foreach( $laterElements as $laterElement )
- {
- if ( $laterElement['type'] == eZTemplate::ELEMENT_NORMAL_TAG)
- {
- if( !in_array( $laterElement['name'], array_keys($outerElseTags) ) )
- {
- $laterStack[] = $laterElement['name'];
- }
- else
- {
- if ( $laterStack === array() )
- {
- break; // double else (current else will be ignored)
- }
- }
- }
- elseif ( $laterElement['type'] == eZTemplate::ELEMENT_END_TAG )
- {
- if ( $laterStack !== array() )
- {
- if ( array_pop( $laterStack ) !== $laterElement['name'] )
- {
- break; // later tags mismatch (current else will be ignored)
- }
- }
- else
- {
- if ( $laterElement['name'] == $oldTagName)
- {
- break; // previous tag correctly closed (current else will be ignored)
- }
- elseif ( in_array( $laterElement['name'], $outerElseTags[$tag] ) )
- {
- $ignoreCurrentTag = false;
- break; // 'if' tag correctly closed (inner tags must be closed too)
- }
- }
- }
- }
- }
- $place = $element['placement'];
- $startLine = $place['start']['line'];
- $startColumn = $place['start']['column'];
- if ( $ignoreCurrentTag )
- {
- $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
- "Unterminated tag \"$oldTagName\" does not match tag \"$tag\". \"$tag\" will be ignored.",
- $element['placement'] );
- }
- else
- {
- unset( $currentRoot );
- $lastIfKey++;
- $currentRoot =& $tagStack[$lastIfKey]["Root"];
- $autoTerminatedTags = array_slice( $tagStack, $lastIfKey);
- $autoTerminatedTagNames = array();
- foreach( $autoTerminatedTags as $autoTerminatedTag)
- $autoTerminatedTagNames[] = $autoTerminatedTag["Tag"];
- $tagStack = array_slice( $tagStack, 0, $lastIfKey);
- $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
- "Unterminated tag \"".implode( "\", \"", $autoTerminatedTagNames)."\" does not match tag \"$tag\" and will be autoterminated.",
- $element['placement'] );
- unset( $autoTerminatedTags );
- unset( $autoTerminatedTagNames );
- }
- unset( $lastIfKey );
- }
- }
- if ( !$ignoreCurrentTag )
- {
- unset( $node );
- $node = array( eZTemplate::NODE_FUNCTION,
- false,
- $tag,
- $args,
- $placement );
- $this->appendChild( $currentRoot, $node );
- $has_children = true;
- if ( isset( $tpl->FunctionAttributes[$tag] ) )
- {
- if ( is_array( $tpl->FunctionAttributes[$tag] ) )
- $tpl->loadAndRegisterFunctions( $tpl->FunctionAttributes[$tag] );
- $has_children = $tpl->FunctionAttributes[$tag];
- }
- else if ( isset( $tpl->Functions[$tag] ) )
- {
- if ( is_array( $tpl->Functions[$tag] ) )
- $tpl->loadAndRegisterFunctions( $tpl->Functions[$tag] );
- $has_children = $tpl->hasChildren( $tpl->Functions[$tag], $tag );
- }
- if ( $has_children )
- {
- $tagStack[] = array( "Root" => &$currentRoot,
- "Tag" => $tag );
- unset( $currentRoot );
- $currentRoot =& $node;
- }
- }
- }
- else if ( $type == eZTemplate::ELEMENT_END_TAG )
- {
- $has_children = true;
- if ( isset( $tpl->FunctionAttributes[$tag] ) )
- {
- if ( is_array( $tpl->FunctionAttributes[$tag] ) )
- $tpl->loadAndRegisterFunctions( $tpl->FunctionAttributes[$tag] );
- $has_children = $tpl->FunctionAttributes[$tag];
- }
- else if ( isset( $tpl->Functions[$tag] ) )
- {
- if ( is_array( $tpl->Functions[$tag] ) )
- $tpl->loadAndRegisterFunctions( $tpl->Functions[$tag] );
- $has_children = $tpl->hasChildren( $tpl->Functions[$tag], $tag );
- }
- if ( !$has_children )
- {
- $placement = $element['placement'];
- $startLine = $placement['start']['line'];
- $startColumn = $placement['start']['column'];
- $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
- "End tag \"$tag\" for function which does not accept children, ignoring tag",
- $element['placement'] );
- }
- else
- {
- unset( $oldTag );
- unset( $oldTagName );
- $oldTag = array_pop( $tagStack );
- $oldTagName = $oldTag["Tag"];
- unset( $currentRoot );
- $currentRoot =& $oldTag["Root"];
- if ( $oldTagName != $tag )
- {
- $placement = $element['placement'];
- $startLine = $placement['start']['line'];
- $startColumn = $placement['start']['column'];
- $tpl->error( "", "parser error @ $relatedTemplateName:$startLine" . "[$startColumn]" . "\n" .
- "Unterminated tag \"$oldTagName\" does not match tag \"$tag\"",
- $element['placement'] );
- }
- // a dirty hack to pass arguments specified in {/do} to the corresponding function.
- if ( $tag == 'do' )
- {
- $doOpenTag =& $currentRoot[1][count( $currentRoot[1] ) - 1];
- $doOpenTag[3] =& $args;
- }
- }
- }
- else // eZTemplate::ELEMENT_SINGLE_TAG
- {
- unset( $node );
- $node = array( eZTemplate::NODE_FUNCTION,
- false,
- $tag,
- $args,
- $placement );
- $this->appendChild( $currentRoot, $node );
- }
- unset( $tag );
- } break;
- }
- }
- if ( $tpl->ShowDetails )
- eZDebug::addTimingPoint( "Parse pass 3 done" );
- }
- /*!
- * parse 'sequence' loop parameter: "sequence <array> as <$seqVar>"
- */
- function parseSequenceParameter( $parseSequenceKeyword, $funcName, &$args, $tpl, &$text, &$text_len, &$cur_pos,
- $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
- {
- if ( $parseSequenceKeyword )
- {
- // parse 'sequence' keyword
- $sequenceEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
- $sequence = substr( $text, $cur_pos, $sequenceEndPos-$cur_pos );
- if ( $sequence != 'sequence' )
- {
- $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
- $funcName, "Expected keyword 'sequence' not found" );
- return false;
- }
- $cur_pos = $sequenceEndPos;
- // skip whitespaces
- $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
- }
- // parse sequence array
- $args['sequence_array'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
- // skip whitespaces
- $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
- // parse 'as' keyword
- $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $cur_pos, $text_len );
- $word = substr( $text, $cur_pos, $asEndPos-$cur_pos );
- if ( $word != 'as' )
- {
- $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
- $funcName, "Expected keyword 'as' not found" );
- unset( $args['sequence_array'] );
- return false;
- }
- $cur_pos = $asEndPos;
- // skip whitespaces
- $cur_pos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $cur_pos, $text_len );
- // parse sequence variable
- $seqVar = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $cur_pos, $cur_pos, $text_len, $rootNamespace );
- if ( !$seqVar )
- {
- $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
- $funcName, "Sequence variable name cannot be empty" );
- unset( $args['sequence_array'] );
- return false;
- }
- $args['sequence_var'] = $seqVar;
- return true;
- }
- /*!
- Parse {for} function.
- Syntax:
- \code
- // for <firstValue> to <lastValue> as <$loopVar> [sequence <array> as <$var>]
- \endcode
- */
- function parseForFunction( &$args, $tpl, &$text, &$text_len, &$cur_pos,
- $relatedTemplateName, $startLine, $startColumn, $rootNamespace )
- {
- $firstValStartPos = $cur_pos;
- // parse first value
- $firstVal = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $firstValStartPos, $firstValEndPos, $text_len, $rootNamespace
- /*, eZTemplate::TYPE_NUMERIC_BIT | eZTemplate::TYPE_VARIABLE_BIT*/ );
- $args['first_val'] = $firstVal;
- $toStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $firstValEndPos, $text_len );
- // parse 'to'
- $toEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $toStartPos, $text_len );
- $to = substr( $text, $toStartPos, $toEndPos-$toStartPos );
- if ( $to != 'to' )
- {
- $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
- 'for', "Expected keyword 'to' not found" );
- return;
- }
- $lastValStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $toEndPos, $text_len );
- // parse last value
- $args['last_val'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $lastValStartPos, $lastValEndPos, $text_len, $rootNamespace );
- $asStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $lastValEndPos, $text_len );
- // parse 'as'
- $asEndPos = $this->ElementParser->identifierEndPosition( $tpl, $text, $asStartPos, $text_len );
- $as = substr( $text, $asStartPos, $asEndPos-$asStartPos );
- if ( $as != 'as' )
- {
- $this->showParseErrorMessage( $tpl, $text, $text_len, $cur_pos, $relatedTemplateName, $startLine, $startColumn,
- 'for', "Expected keyword 'as' not found" );
- return;
- }
- $loopVarStartPos = $this->ElementParser->whitespaceEndPos( $tpl, $text, $asEndPos, $text_len );
- // parse loop variable
- $args['loop_var'] = $this->ElementParser->parseVariableTag( $tpl, $relatedTemplateName, $text, $loopVarStartPos, $loopVarEndPos, $text