You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by ch...@apache.org on 2009/05/11 14:49:29 UTC

svn commit: r773547 - /incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php

Author: chabotc
Date: Mon May 11 12:49:29 2009
New Revision: 773547

URL: http://svn.apache.org/viewvc?rev=773547&view=rev
Log:
Adds support for array[] expressions to the ExpressionParser

Modified:
    incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php

Modified: incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php?rev=773547&r1=773546&r2=773547&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/templates/ExpressionParser.php Mon May 11 12:49:29 2009
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -27,11 +28,10 @@
  *
  */
 
-//TODO support array selection, ie: ${Foo[Bar]}
+//TODO == seems to not be working correctly
 //TODO support unary expressions, ie: ${Foo * -Bar}, or simpler: ${!Foo}
 //TODO support ${Viewer.likesRed ? 'Red' : 'Blue'} type expressions
 //TODO support string variables, ie 'Red' and it's variants like 'Red\'' and '"Red"', etc
-//TODO : add recursive loop on [] blocks and use recurse evaluate's return as array index
 
 class ExpressionException extends Exception {
 }
@@ -59,7 +59,6 @@
    */
   static public function evaluate($expression, $dataContext) {
     self::$dataContext = $dataContext;
-    // split expression on [] and foo == true ? a : b constructs, and evaluate each seperately
     $postfix = self::infixToPostfix($expression);
     $result = self::postfixEval($postfix);
     return $result;
@@ -73,11 +72,14 @@
    * @return mixed value
    */
   static public function evaluateVar($var, $dataContext) {
+    if ($var === null || $var === false) {
+      return $var;
+    }
     if (empty($var)) {
       throw new ExpressionException("Invalid variable statement");
     }
     if (in_array($var, self::$reservedWords)) {
-      throw new ExpressionException("Variable name  ".htmlentities($var) . " is reserved word");
+      throw new ExpressionException("Variable name  " . htmlentities($var) . " is reserved word");
     }
     $parts = explode('.', $var);
     if (count($parts) < 1) {
@@ -102,14 +104,13 @@
         break;
       }
     }
-    if (!$found) {
+    if (! $found) {
       // variable wasn't found in Cur, My and Top scope, throw an error
       throw new ExpressionException("Unknown variable: " . htmlentities($var) . ($var != $key ? " ($key)" : ''));
     }
     return $context;
   }
 
-
   /**
    * Returns the string value of the (mixed) $val, ie:
    * on array, return "1, 2, 3, 4"
@@ -120,13 +121,12 @@
     if (is_array($val)) {
       return implode(',', $val);
     } elseif (is_numeric($val)) {
-      return (string) $val;
+      return (string)$val;
     } else {
       return $val;
     }
   }
 
-
   static private function isOperand($string, $index = 0) {
     if (is_array($string)) {
       // complex types are always operands
@@ -254,6 +254,61 @@
     $tokens = array();
     $tokensIndex = 0;
     for ($i = 0; $i < strlen($str); $i ++) {
+      // Resolve array index selections[] by calling self::evaluate on the nested index key, and using the return value of that to resolve the var
+      // Note: this will recurse when there's multiple levels[of[brackets]]
+      if ($str[$i] == '[') {
+        if (! empty($temp)) {
+          $tokens[$tokensIndex] = $temp;
+          $tokensIndex++;
+        }
+        $tokenOperand = array_pop($tokens);
+        if (!self::isOperand($tokenOperand)) {
+          throw new ExpressionException("Trying to reference an index on an operator");
+        }
+        $tokenOperand = self::evaluateVar($tokenOperand, self::$dataContext);
+        if (!is_array($tokenOperand)) {
+          throw new ExpressionException("Trying to reference an index on a non-array value");
+        }
+        $resolved = false;
+        $temp = '';
+        $nestCounter = $expressionLength = 0;
+        $indexExpression = '';
+        for ($y = $i + 1; $y < strlen($str); $y ++) {
+          $expressionLength ++;
+          $char = $str[$y];
+          if ($char == '[') {
+            $nestCounter ++;
+          } elseif ($char == ']') {
+            if ($nestCounter == 0) {
+              $indexResult = self::evaluate($indexExpression, self::$dataContext);
+              if (!isset($tokenOperand[$indexResult])) {
+                $resolved = null;
+              } else {
+                $resolved = $tokenOperand[$indexResult];
+              }
+              break;
+            } else {
+              $nestCounter --;
+            }
+          }
+          $indexExpression .= $char;
+        }
+        if ($resolved === false) {
+          throw new ExpressionException("Unbalanced [] expression");
+        }
+        $i += $expressionLength + 1;
+        if ($resolved === null && $i < (strlen($str) - 1)) {
+          // a null value is ok for a Foo[Bar] expression, but an "property not found" exception on Foo[Bar].id
+          if ($str[$i] != ' ' && !self::isOperator($str, $i)) {
+            throw new ExpressionException("Trying to get a property on a null value");
+          }
+        }
+        // this token has been resolved, advance our string pointer ($i) and continue to the next position in the string
+        $tokens[$tokensIndex - 1] = $resolved;
+        continue;
+      }
+
+      // Regular operant/operator token parsing
       if ($str[$i] == ' ' || $str[$i] == "\t" || $str[$i] == "\n" || $str == "\r") {
         if (! empty($temp)) {
           $tokens[$tokensIndex] = $temp;
@@ -285,12 +340,14 @@
         }
       }
     }
+
+    // Resolve all named variables to their actual value
     foreach ($tokens as $key => $val) {
-      if (self::isOperand($val) && ! is_numeric($val)) {
+      if (self::isOperand($val) && ! is_numeric($val) && $val !== false && $val !== null) {
         $tokens[$key] = self::evaluateVar($val, self::$dataContext);
       }
     }
-    return ($tokens);
+    return $tokens;
   }
 
   static private function compute($var1, $var2, $sym) {