[ Index ]
 

Code source de eZ Publish 3.9.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/eztemplate/classes/ -> eztemplatemultipassparser.php (source)

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


Généré le : Sat Feb 24 10:30:04 2007 par Balluche grâce à PHPXref 0.7