[ Index ]

PHP Cross Reference of Web Application Component Toolkit

title

Body

[close]

/framework/template/compiler/ -> expression.inc.php (source)

   1  <?php
   2  //--------------------------------------------------------------------------------
   3  // Copyright 2003 Procata, Inc.
   4  // Released under the LGPL license (http://www.gnu.org/copyleft/lesser.html)
   5  //--------------------------------------------------------------------------------
   6  /**
   7  * @package WACT_TEMPLATE
   8  * @version $Id: expression.inc.php,v 1.29 2004/11/18 04:22:46 jeffmoore Exp $
   9  */
  10  
  11  require_once WACT_ROOT . 'template/compiler/expressionlexer.inc.php';
  12  
  13  //--------------------------------------------------------------------------------
  14  /**
  15  * Represents a single Expression found in the template. Responsibly for parsing
  16  * the expression and building a filter chain for the expression (if expression
  17  * contained filter syntax)
  18  * @access protected
  19  * @package WACT_TEMPLATE
  20  */
  21  class Expression {
  22      
  23      /**
  24      * Tree of compiler filters
  25      * @var object subclass of CompileFilter
  26      * @access private
  27      */
  28      var $filterChain;
  29  
  30      /**
  31      * used for error messages
  32      * @var string
  33      * @access private
  34      */
  35      var $expression;
  36  
  37      /**
  38      * @param string expression
  39      * @param object Compiler Component that attribute was found in
  40      * @param string (optional) default filter to apply
  41      * @access protected
  42      */
  43  	function Expression($expression, &$ComponentContext, $DefaultFilter = 'raw') {
  44          $this->expression = $expression;
  45          $ApplyDefaultFilter = TRUE;
  46          if (preg_match('/^(.*)\s*\|\s*raw$/is', $expression, $match)) {
  47              $ApplyDefaultFilter = FALSE;
  48              $expression = $match[1];
  49          }
  50          if ($DefaultFilter == 'raw') {
  51              $ApplyDefaultFilter = FALSE;
  52          }
  53          
  54          $pos = strpos($expression, "|");
  55          if ($pos === FALSE) {
  56              $base =& $this->createValue($expression, $ComponentContext);
  57          } else {
  58              $dbe = trim(substr($expression, 0, $pos));
  59              $filters = trim(substr($expression, $pos + 1));
  60              $base =& $this->createFilterChain(
  61                  $filters,
  62                  $this->createValue($dbe, $ComponentContext),
  63                  $ComponentContext);
  64          }
  65          
  66          if ($ApplyDefaultFilter) {
  67              $fd =& FilterDictionary::getInstance();
  68              $filterInfo =& $fd->getFilterInfo($DefaultFilter);
  69              if (is_object($filterInfo)) {
  70                  $filterInfo->load();
  71                  $filter_class = $filterInfo->FilterClass;
  72  
  73                  // Don't apply the default filter if the last filter in the
  74                  // chain is already that filter.
  75                  if (strcasecmp(get_class($base), $filter_class) == 0) {
  76                      $this->filterChain =& $base;
  77                  } else {
  78                      $filter =& new $filter_class();
  79                      $filter->registerBase($base);
  80                      $this->filterChain =& $filter;
  81                  }
  82              } else {
  83                  RaiseError('compiler', 'MISSING_FILTER', array(
  84                      'filter' => $DefaultFilter,
  85                      'file' => $ComponentContext->SourceFile,
  86                      'line' => $ComponentContext->StartingLineNo));
  87              }
  88          } else {
  89              $this->filterChain =& $base;
  90          }
  91      }
  92  
  93      /**
  94      * Parses an expression and returns an object representing the expression
  95      * @param string expression
  96      * @param object Compiler Component that attribute was found in
  97      * @return object ConstantProperty or DataBindingExpression
  98      * @access private
  99      */
 100      function &createValue($expression, &$ComponentContext) {
 101          $Parser = & new ExpressionValueParser($expression);
 102  
 103          switch ( $Parser->ValueType ) {
 104              // NULL and BOOLEAN values left out on purpose
 105              case EXPRESSION_VALUE_INT:
 106              case EXPRESSION_VALUE_FLOAT:
 107              case EXPRESSION_VALUE_STRING:
 108                  return new ConstantProperty($Parser->Value);
 109              break;
 110  
 111              case EXPRESSION_VALUE_DATABINDING:
 112              default:
 113                  return new DataBindingExpression($expression, $ComponentContext);
 114              break;
 115  
 116          }
 117  
 118      }
 119  
 120      /**
 121      * Parses an expression, building a chain of filters for it
 122      * @param string expression
 123      * @param object base filter to start with (CompilerFilter)
 124      * @param object Compiler Component that attribute was found in
 125      * @return object filter with chain of filters attached
 126      * @access private
 127      */
 128      function &createFilterChain($expr, $Value, &$ComponentContext) {
 129  
 130          $Fd =& FilterDictionary::getInstance();
 131  
 132          $FFp = & new ExpressionFilterFindingParser($expr);
 133  
 134          $Base = & $Value;
 135  
 136          if ( count($FFp->Filters) == 0 ) {
 137              return $Value;
 138          }
 139  
 140          foreach ( $FFp->Filters as $filter_expr ) {
 141  
 142              $Fp = & new ExpressionFilterParser($filter_expr);
 143  
 144              if ( is_null($Fp->Name) ) {
 145                  RaiseError('compiler', 'INVALID_FILTER_SPEC', array(
 146                      'file' => $ComponentContext->SourceFile,
 147                      'line' => $ComponentContext->StartingLineNo));
 148                  return $Value;
 149              }
 150  
 151              $FilterInfo =& $Fd->getFilterInfo($Fp->Name);
 152  
 153              if (!is_object($FilterInfo)) {
 154                  RaiseError('compiler', 'MISSING_FILTER', array(
 155                      'filter' => $Fp->Name,
 156                      'file' => $ComponentContext->SourceFile,
 157                      'line' => $ComponentContext->StartingLineNo));
 158                  return $Value;
 159              }
 160              
 161              $FilterInfo->load();
 162              $filter_class = $FilterInfo->FilterClass;
 163              $Filter =& new $filter_class();
 164  
 165              if ( !is_null($Fp->Args) ) {
 166  
 167                  $numArgs = count($Fp->Args);
 168  
 169                  if ( $numArgs < $FilterInfo->MinParameterCount ) {
 170                      RaiseError('compiler', 'MISSING_FILTER_PARAMETER', array(
 171                          'filter' => $Fp->Name,
 172                          'file' => $ComponentContext->SourceFile,
 173                          'line' => $ComponentContext->StartingLineNo));
 174                      return $Value;
 175                  }
 176  
 177                  if ($numArgs > $FilterInfo->MaxParameterCount) {
 178                      RaiseError('compiler', 'TOO_MANY_PARAMETERS', array(
 179                          'filter' => $Fp->Name,
 180                          'file' => $ComponentContext->SourceFile,
 181                          'line' => $ComponentContext->StartingLineNo));
 182                      return $Value;
 183                  }
 184  
 185                  foreach ( $Fp->Args as $value_expr ) {
 186  
 187                      $Filter->registerParameter($this->createValue($value_expr, $ComponentContext));
 188  
 189                  }
 190              }
 191  
 192              $Filter->registerBase($Base);
 193  
 194              $Base = & $Filter;
 195  
 196          }
 197  
 198          return $Base;
 199  
 200      }
 201  
 202      /**
 203      * Does this expression refer to a constant value (at compile time)?
 204      * @return Boolean
 205      * @access public
 206      */
 207  	function isConstant() {
 208            return $this->filterChain->isConstant();
 209      }
 210  
 211      /**
 212      * Return the value of this expression
 213      * @return String
 214      * @access public
 215      */
 216  	function getValue() {
 217          return $this->filterChain->getValue();
 218      }
 219  
 220      /**
 221      * Generate setup code for an expression reference
 222      * @param CodeWriter
 223      * @return void
 224      * @access protected
 225      */
 226  	function generatePreStatement(&$code) {
 227          $this->filterChain->generatePreStatement($code);
 228      }
 229  
 230      /**
 231      * Generate the code to read the data value at run time
 232      * Must generate only a valid PHP Expression.
 233      * @param CodeWriter
 234      * @return void
 235      * @access protected
 236      */
 237  	function generateExpression(&$code) {
 238          $this->filterChain->generateExpression($code);
 239      }
 240  
 241      /**
 242      * Generate tear down code for an expression reference
 243      * @param CodeWriter
 244      * @return void
 245      * @access protected
 246      */
 247  	function generatePostStatement(&$code) {
 248          $this->filterChain->generatePostStatement($code);
 249      }
 250  
 251      /**
 252      * Calls the prepare method on the root of the filter chain
 253      * @return void
 254      * @access protected
 255      */
 256  	function prepare() {
 257          return $this->filterChain->prepare();
 258      }
 259  
 260  }
 261  
 262  //--------------------------------------------------------------------------------
 263  /**#@+
 264   * Value parser constants
 265   */
 266  define ('EXPRESSION_VALUE_DATABINDING',0);
 267  define ('EXPRESSION_VALUE_INT',1);
 268  define ('EXPRESSION_VALUE_FLOAT',2);
 269  define ('EXPRESSION_VALUE_STRING',3);
 270  //--------------------------------------------------------------------------------
 271  /**
 272  * Searches expression strings for constant values
 273  * WARNING: this parser defaults to data binding expressions. That means if it
 274  * doest recognise a integer, float or string constant, what it calls a data binding
 275  * expression may not in fact be a data binding expression. It assumes that
 276  * Expression::createValue asks it a parse a valid value string
 277  * @package WACT_TEMPLATE
 278  * @access protected
 279  */
 280  class ExpressionValueParser {
 281      /**
 282      * @var int constant identifying type of value
 283      * @access protected
 284      */
 285      var $ValueType = EXPRESSION_VALUE_DATABINDING;
 286  
 287      /**
 288      * @var mixed constant value (string/int/float)
 289      * @access protected
 290      */
 291      var $Value;
 292  
 293      /**
 294      * Invokes the Lexer to parse the expression
 295      * @param string expression to parse
 296      */
 297  	function ExpressionValueParser($expression) {
 298          $Lexer = & ExpressionValueParser::getLexer();
 299          $Lexer->parse($expression);
 300      }
 301  
 302      /**
 303      * Lexer callback - accepts the default data binding
 304      * expression - called if no constants found
 305      * @param string parsed expression
 306      * @param int expression lexer state
 307      * @access private
 308      * @return boolean TRUE
 309      */
 310  	function acceptDatabinding($expression,$state) {
 311          switch ( $state ) {
 312              case EXPRESSION_LEXER_UNMATCHED:
 313                  // This doesnt actually get used in Expression::getValue
 314                  $this->Value = $expression;
 315              break;
 316          }
 317          return TRUE;
 318      }
 319  
 320      /**
 321      * Lexer callback - called for integer constants
 322      * @param string matched integer
 323      * @param int expression lexer state
 324      * @access private
 325      * @return boolean TRUE
 326      */
 327  	function acceptInteger($int,$state) {
 328          switch ( $state ) {
 329              case EXPRESSION_LEXER_SPECIAL:
 330                  $this->ValueType = EXPRESSION_VALUE_INT;
 331                  $this->Value = intval($int);
 332              break;
 333          }
 334  
 335          return TRUE;
 336      }
 337  
 338      /**
 339      * Lexer callback - called for float constants
 340      * @param string matched float
 341      * @param int expression lexer state
 342      * @access private
 343      * @return boolean TRUE
 344      */
 345  	function acceptFloat($float,$state) {
 346          switch ( $state ) {
 347              case EXPRESSION_LEXER_SPECIAL:
 348                  $this->ValueType = EXPRESSION_VALUE_FLOAT;
 349                  if (!function_exists('floatval')) {
 350                      require_once WACT_ROOT . 'util/phpcompat/floatval.php';
 351                  }
 352                  $this->Value = floatval($float);
 353              break;
 354          }
 355          return TRUE;
 356      }
 357  
 358      /**
 359      * Lexer callback - called for string constants
 360      * @param string matched string
 361      * @param int expression lexer state
 362      * @access private
 363      * @return boolean TRUE
 364      */
 365  	function acceptString($string,$state) {
 366          switch ( $state ) {
 367              case EXPRESSION_LEXER_SPECIAL:
 368                  $this->ValueType = EXPRESSION_VALUE_STRING;
 369  
 370                  // Strip the quotes
 371                  // hack but saves introducing further Lexer complexity
 372                  $string = substr($string,1,strlen($string)-2);
 373  
 374                  $this->Value = $string;
 375              break;
 376          }
 377          return TRUE;
 378      }
 379  
 380      /**
 381      * Creates the Lexer. Ideally this should be a static instance for
 382      * performance but Lexer left in strange state after parsing if
 383      * static
 384      * @return ExpressionLexer
 385      * @access private
 386      */
 387      function & getLexer() {
 388          $Lexer = new ExpressionLexer($this,'databinding');
 389  
 390          $Lexer->addSpecialPattern('^-?\d+$','databinding','integer');
 391          $Lexer->addSpecialPattern('^-?\d+\.\d+$','databinding','float');
 392          $Lexer->addSpecialPattern('^".*"$','databinding','doublequote');
 393          $Lexer->addSpecialPattern('^\'.*\'$','databinding','singlequote');
 394  
 395          $Lexer->mapHandler('databinding','acceptDatabinding');
 396          $Lexer->mapHandler('integer','acceptInteger');
 397          $Lexer->mapHandler('float','acceptFloat');
 398          $Lexer->mapHandler('doublequote','acceptString');
 399          $Lexer->mapHandler('singlequote','acceptString');
 400  
 401          return $Lexer;
 402      }
 403  }
 404  
 405  //--------------------------------------------------------------------------------
 406  /**
 407  * Searches expression strings for filters
 408  * WARNING: this parser expects the initial variable / value to have been stripped
 409  * as happens in the Expression constructor
 410  * @package WACT_TEMPLATE
 411  * @access protected
 412  */
 413  class ExpressionFilterFindingParser {
 414  
 415      /**
 416      * List of values found in expression, marked by filter delimiter
 417      * @var array
 418      * @access protected
 419      */
 420      var $Filters = array();
 421  
 422      /**
 423      * Current value
 424      * @var mixed NULL when no value or string as value is built
 425      * @access private
 426      */
 427      var $filter = NULL;
 428  
 429      /**
 430      * Invokes the Lexer to parse the expression
 431      * @param string expression to parse
 432      */
 433  	function ExpressionFilterFindingParser($expression) {
 434          $Lexer = & ExpressionFilterFindingParser::getLexer();
 435          $Lexer->parse($expression);
 436  
 437          // Make sure final value added to values
 438          if ( !is_null($this->filter) ) {
 439              $this->Filters[] = $this->filter;
 440          }
 441      }
 442  
 443      /**
 444      * Lexer callback - called for value strings
 445      * @param string
 446      * @param int expression lexer state
 447      * @access private
 448      * @return boolean TRUE
 449      */
 450  	function acceptFilter($filter,$state) {
 451          switch ( $state ) {
 452              case EXPRESSION_LEXER_UNMATCHED:
 453                  if ( is_null($this->filter) ) {
 454                      $this->filter = $filter;
 455                  } else {
 456                      $this->filter .= $filter;
 457                  }
 458              break;
 459              case EXPRESSION_LEXER_SPECIAL:
 460                  if ( is_null($this->filter) ) {
 461                      $this->filter = $filter;
 462                  } else {
 463                      $this->filter .= $filter;
 464                  }
 465              break;
 466          }
 467          return TRUE;
 468      }
 469  
 470      /**
 471      * Lexer callback - called every time a filter delimiter
 472      * is found. Populates the Values array with the current
 473      * value
 474      * @access private
 475      * @return boolean TRUE
 476      */
 477  	function addFilter() {
 478          if ( !is_null ($this->filter) ) {
 479              $this->Filters[] = $this->filter;
 480              $this->filter = NULL;
 481          }
 482          return TRUE;
 483      }
 484      
 485      /**
 486      * Creates the Lexer.
 487      * @return ExpressionLexer
 488      * @access private
 489      */
 490      function & getLexer() {
 491          $Lexer = new ExpressionLexer($this,'filter');
 492  
 493          $Lexer->addSpecialPattern('\|','filter','add');
 494  //        $Lexer->addSpecialPattern('".*"','filter','doublequote');
 495  //        $Lexer->addSpecialPattern('\'.*\'','filter','singlequote');
 496          $Lexer->addSpecialPattern('"[^"]*"','filter','doublequote');
 497          $Lexer->addSpecialPattern("'[^']*'",'filter','singlequote');
 498  
 499          $Lexer->mapHandler('filter','acceptFilter');
 500          $Lexer->mapHandler('doublequote','acceptFilter');
 501          $Lexer->mapHandler('singlequote','acceptFilter');
 502          $Lexer->mapHandler('add','addFilter');
 503  
 504          return $Lexer;
 505      }
 506  }
 507  
 508  /**
 509  * Parses a single filter expression
 510  * WARNING: this parser expects strings parsed by ExpressionFilterFindingParser
 511  * @package WACT_TEMPLATE
 512  * @access protected
 513  */
 514  class ExpressionFilterParser {
 515  
 516      /**
 517      * Name of the filter
 518      * @var string
 519      * @access protected
 520      */
 521      var $Name = NULL;
 522  
 523      /**
 524      * List of arguments
 525      * @var array
 526      * @access protected
 527      */
 528      var $Args = NULL;
 529  
 530      /**
 531      * Current argument
 532      * @var string
 533      * @access private
 534      */
 535      var $arg = NULL;
 536  
 537      /**
 538      * Invokes the Lexer to parse the expression
 539      * @param string expression to parse
 540      */
 541  	function ExpressionFilterParser($expression) {
 542          $Lexer = & ExpressionFilterParser::getLexer();
 543          $Lexer->parse($expression);
 544  
 545          // Make sure remaining argument added
 546          if ( !is_null ($this->Args) && !is_null($this->arg) ) {
 547              $this->Args[] = $this->arg;
 548          }
 549      }
 550  
 551      /**
 552      * Lexer callback - if the : delimiter is found, prepares the Args array
 553      * @access private
 554      * @return boolean TRUE
 555      */
 556  	function initArgs() {
 557          $this->Args = array();
 558          return TRUE;
 559      }
 560  
 561      /**
 562      * Lexer callback - if the , delimiter is found, adds the current arg
 563      * to the Args array
 564      * @access private
 565      * @return boolean TRUE
 566      */
 567  	function addArg() {
 568          if ( !is_null($this->Args) && !is_null($this->arg) ) {
 569              $this->Args[] = $this->arg;
 570              $this->arg = NULL;
 571          }
 572          return TRUE;
 573      }
 574  
 575      /**
 576      * Lexer callback - accepts a single argument
 577      * @param string
 578      * @param int expression lexer state
 579      * @access private
 580      * @return boolean TRUE
 581      */
 582  	function accept($expression,$state) {
 583  
 584          switch ( $state ) {
 585  
 586              case EXPRESSION_LEXER_UNMATCHED:
 587                  if ( !is_null($this->Args) ) {
 588                      if ( is_null($this->arg) ) {
 589                          $this->arg = $expression;
 590                      } else {
 591                          $this->arg .= $expression;
 592                      }
 593                  } else {
 594                      if ( is_null($this->Name) ) {
 595                          $this->Name = $expression;
 596                      }
 597                  }
 598              break;
 599  
 600              case EXPRESSION_LEXER_SPECIAL:
 601                  if ( !is_null($this->Args) ) {
 602                      if ( is_null($this->arg) ) {
 603                          $this->arg = $expression;
 604                      } else {
 605                          $this->arg .= $expression;
 606                      }
 607                  }
 608              break;
 609          }
 610  
 611          return TRUE;
 612      }
 613  
 614      /**
 615      * Creates the Lexer.
 616      * @return ExpressionLexer
 617      * @access private
 618      */
 619      function & getLexer() {
 620          $Lexer = new ExpressionLexer($this,'value');
 621  
 622          $Lexer->addSpecialPattern(':','value','args');
 623          $Lexer->addSpecialPattern(',','value','arg');
 624  
 625          $Lexer->addSpecialPattern('"[^"]*"','value','doublequote');
 626          $Lexer->addSpecialPattern("'[^']*'",'value','singlequote');
 627  
 628          $Lexer->addPattern('\s','value');
 629  
 630          $Lexer->mapHandler('value','accept');
 631          $Lexer->mapHandler('args','initArgs');
 632          $Lexer->mapHandler('arg','addArg');
 633          $Lexer->mapHandler('doublequote','accept');
 634          $Lexer->mapHandler('singlequote','accept');
 635  
 636  
 637          return $Lexer;
 638      }
 639  
 640  }
 641  ?>


Generated: Sun Nov 28 19:36:09 2004 Cross-referenced by PHPXref 0.5