示例#1
0
 public function Toolset_Parser($exp = null)
 {
     if (isset($exp) && $exp !== null) {
         $this->strInFix = $exp;
         $this->arrTokens = $this->arrPostFix = null;
     }
     // init tokenizer here, else tokens become undefined on addVar
     Toolset_Tokenizer::init();
 }
示例#2
0
 private function _EvaluateExpression(&$myarrPostFix, &$myvarArr)
 {
     if (!isset($myarrPostFix)) {
         $myarrPostFix = $this->_ParseExpression();
     }
     if (count($myarrPostFix) == 0) {
         throw new Exception("Unable to parse the expression!");
     }
     if (!isset($myarrPostFix) || count($myarrPostFix) == 0) {
         throw new Exception("Invalid postfix expression!");
     }
     $intIndex = 0;
     $myStack = new Toolset_Stack();
     //echo $this->_dumpPostFix($myarrPostFix);
     while ($intIndex < count($myarrPostFix)) {
         //echo $myStack->toString();
         $strTok = $myarrPostFix[$intIndex];
         switch ($strTok->type) {
             case Toolset_Tokenizer::$TOKEN_TYPE['ARG_TERMINAL']:
                 $myStack->Push($strTok);
                 break;
             case Toolset_Tokenizer::$TOKEN_TYPE['UNARY_NEGATIVE']:
                 if ($myStack->IsEmpty()) {
                     throw new Exception("No operand to negate!");
                 }
                 $objOp1 = null;
                 $objOp2 = null;
                 $objOp1 = $myStack->Pop();
                 if ($objOp1->isVariable) {
                     $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                 }
                 $dblNo = Toolset_Tokenizer::toNumber($objOp1->val);
                 if (is_nan($dblNo)) {
                     throw new Exception("Not a numeric value!");
                 } else {
                     $dblNo = 0 - $dblNo;
                     $myStack->Push(Toolset_Tokenizer::makeToken($dblNo, Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                 }
                 break;
             case Toolset_Tokenizer::$TOKEN_TYPE['UNARY_NEGATION']:
                 if ($myStack->IsEmpty()) {
                     throw new Exception("No operand on stack!");
                 }
                 $objOp1 = null;
                 $objOp2 = null;
                 $objOp1 = $myStack->Pop();
                 if ($objOp1->isVariable) {
                     $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                 }
                 $objOp1 = Toolset_Tokenizer::toBoolean($objOp1->val);
                 if ($objOp1 === null) {
                     throw new Exception($strTok->val . " applied not on a boolean value!");
                 } else {
                     $myStack->Push(Toolset_Tokenizer::makeToken(!$objOp1, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                 }
                 break;
             case Toolset_Tokenizer::$TOKEN_TYPE['ARITHMETIC_OP']:
                 switch ($strTok->val) {
                     case "*":
                     case "/":
                     case "%":
                     case "^":
                         if ($myStack->IsEmpty() || $myStack->Size() < 2) {
                             throw new Exception("Stack is empty, can not perform [" . $strTok->val . "]");
                         }
                         $objOp1 = null;
                         $objOp2 = null;
                         $objTmp = null;
                         $objOp2 = $myStack->Pop();
                         $objOp1 = $myStack->Pop();
                         if ($objOp1->isVariable) {
                             $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                         }
                         if ($objOp2->isVariable) {
                             $objOp2 = $this->_getVariable($objOp2->val, $myvarArr);
                         }
                         if (!$objOp1->isNumber || !$objOp2->isNumber) {
                             throw new Exception("Either one of the operand is not a number can not perform [" . $strTok->val . "]");
                         }
                         $dblVal1 = Toolset_Tokenizer::toNumber($objOp1->val);
                         $dblVal2 = Toolset_Tokenizer::toNumber($objOp2->val);
                         if (is_nan($dblVal1) || is_nan($dblVal2)) {
                             throw new Exception("Either one of the operand is not a number can not perform [" . $strTok->val . "]");
                         }
                         if ($strTok->val == "^") {
                             $myStack->Push(Toolset_Tokenizer::makeToken(pow($dblVal1, $dblVal2), Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                         } else {
                             if ($strTok->val == "*") {
                                 $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 * $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                             } else {
                                 if ($strTok->val == "/") {
                                     $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 / $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                                 } else {
                                     $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 % $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                                 }
                             }
                         }
                         break;
                     case "+":
                     case "-":
                         if ($myStack->IsEmpty() || $myStack->Size() < 2) {
                             throw new Exception("Stack is empty, can not perform [" . $strTok->val . "]");
                         }
                         $objOp1 = null;
                         $objOp2 = null;
                         $objTmp1 = null;
                         $objTmp2 = null;
                         $strOp = $strTok->val == "+" ? "Addition" : "Substraction";
                         $objOp2 = $myStack->Pop();
                         $objOp1 = $myStack->Pop();
                         if ($objOp1->isVariable) {
                             $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                         }
                         if ($objOp2->isVariable) {
                             $objOp2 = $this->_getVariable($objOp2->val, $myvarArr);
                         }
                         if ($objOp1->isNumber && $objOp2->isNumber) {
                             // Number addition
                             $dblVal1 = Toolset_Tokenizer::toNumber($objOp1->val);
                             $dblVal2 = Toolset_Tokenizer::toNumber($objOp2->val);
                             if ($strTok->val == "+") {
                                 $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 + $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                             } else {
                                 $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 - $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['NUMBER']));
                             }
                         } else {
                             if ($objOp1->isStringLiteral && $objOp2->isStringLiteral) {
                                 if ($strTok->val == "+") {
                                     $myStack->Push(Toolset_Tokenizer::makeToken($objOp1->val . $objOp2->val, Toolset_Tokenizer::$TOKEN_TYPE['STRING_LITERAL']));
                                 } else {
                                     throw new Exception($strOp . " not supported for strings!");
                                 }
                             } else {
                                 throw new Exception($strOp . " not supported for other types than numbers and strings!");
                             }
                         }
                         break;
                 }
                 break;
             case Toolset_Tokenizer::$TOKEN_TYPE['COMPARISON_OP']:
                 switch ($strTok->val) {
                     case "=":
                     case "<":
                     case ">":
                     case "<>":
                     case "<=":
                     case ">=":
                     case "eq":
                     case "lt":
                     case "gt":
                     case "ne":
                     case "lte":
                     case "gte":
                         if ($myStack->IsEmpty() || $myStack->Size() < 2) {
                             throw new Exception("Stack is empty, can not perform [" . $strTok->val . "]");
                         }
                         $objOp1 = null;
                         $objOp2 = null;
                         $objTmp1 = null;
                         $objTmp2 = null;
                         $objOp2 = $myStack->Pop();
                         $objOp1 = $myStack->Pop();
                         //cred_log(array($objOp1, $objOp2));
                         if ($objOp1->isVariable) {
                             $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                         }
                         if ($objOp2->isVariable) {
                             $objOp2 = $this->_getVariable($objOp2->val, $myvarArr);
                         }
                         //cred_log(array($objOp1, $objOp2));
                         if ($objOp1->isStringLiteral && $objOp2->isNumber) {
                             $dblVal1 = (string) $objOp1->val;
                             $dblVal2 = (string) $objOp2->val;
                         } else {
                             if ($objOp1->isNumber && $objOp2->isStringLiteral) {
                                 $dblVal1 = (string) $objOp1->val;
                                 $dblVal2 = (string) $objOp2->val;
                             } else {
                                 if ($objOp1->isNumber && $objOp2->isNumber) {
                                     $dblVal1 = Toolset_Tokenizer::toNumber($objOp1->val);
                                     $dblVal2 = Toolset_Tokenizer::toNumber($objOp2->val);
                                 } else {
                                     if ($objOp1->isNumber && $objOp2->isBoolean) {
                                         $dblVal1 = Toolset_Tokenizer::toNumber($objOp1->val);
                                         $dblVal2 = Toolset_Tokenizer::toNumber($objOp2->val);
                                     } else {
                                         if ($objOp2->isNumber && $objOp1->isBoolean) {
                                             $dblVal1 = Toolset_Tokenizer::toNumber($objOp1->val);
                                             $dblVal2 = Toolset_Tokenizer::toNumber($objOp2->val);
                                         } else {
                                             if ($objOp1->isDate && $objOp2->isDate) {
                                                 $dblVal1 = $objOp1->val->getNormalizedTimestamp();
                                                 $dblVal2 = $objOp2->val->getNormalizedTimestamp();
                                             } else {
                                                 if ($objOp1->isStringLiteral && $objOp2->isStringLiteral) {
                                                     $dblVal1 = (string) $objOp1->val;
                                                     $dblVal2 = (string) $objOp2->val;
                                                 } else {
                                                     if ($objOp1->isBoolean && $objOp2->isBoolean) {
                                                         if ($strTok->val == "=" || $strTok->val == "<>" || $strTok->val == "eq" || $strTok->val == "ne") {
                                                             $dblVal1 = Toolset_Tokenizer::toBoolean($objOp1->val);
                                                             $dblVal2 = Toolset_Tokenizer::toBoolean($objOp2->val);
                                                         } else {
                                                             throw new Exception($strTok->val + " not supported for boolean values!");
                                                         }
                                                     } else {
                                                         if (($strTok->val == '=' || $strTok->val == '<>' || $strTok->val == 'eq' || $strTok->val == 'ne') && ($objOp1->isStringLiteral && $objOp2->isRegex)) {
                                                             if ($strTok->val == '=' || $strTok->val == 'eq') {
                                                                 $myStack->Push(Toolset_Tokenizer::makeToken($objOp2->val->test((string) $objOp1->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                             } else {
                                                                 $myStack->Push(Toolset_Tokenizer::makeToken(!$objOp2->val->test((string) $objOp1->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                             }
                                                             break;
                                                         } else {
                                                             if (($strTok->val == '=' || $strTok->val == '<>' || $strTok->val == 'eq' || $strTok->val == 'ne') && ($objOp2->isStringLiteral && $objOp1->isRegex)) {
                                                                 if ($strTok->val == '=' || $strTok->val == 'eq') {
                                                                     $myStack->Push(Toolset_Tokenizer::makeToken($objOp1->val->test((string) $objOp2->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                                 } else {
                                                                     $myStack->Push(Toolset_Tokenizer::makeToken(!$objOp1->val->test((string) $objOp2->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                                 }
                                                                 break;
                                                             } else {
                                                                 if (($strTok->val == '=' || $strTok->val == '<>' || $strTok->val == 'eq' || $strTok->val == 'ne') && ($objOp1->isArray && ($objOp2->isStringLiteral || $objOp2->isNumber))) {
                                                                     if ($strTok->val == '=' || $strTok->val == 'eq') {
                                                                         $myStack->Push(Toolset_Tokenizer::makeToken(Toolset_Functions::Contains($objOp1->val, $objOp2->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                                     } else {
                                                                         $myStack->Push(Toolset_Tokenizer::makeToken(!Toolset_Functions::Contains($objOp1->val, $objOp2->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                                     }
                                                                     break;
                                                                 } else {
                                                                     if (($strTok->val == '=' || $strTok->val == '<>' || $strTok->val == 'eq' || $strTok->val == 'ne') && ($objOp2->isArray && ($objOp1->isStringLiteral || $objOp1->isNumber))) {
                                                                         if ($strTok->val == '=' || $strTok->val == 'eq') {
                                                                             $myStack->Push(Toolset_Tokenizer::makeToken(Toolset_Functions::Contains($objOp2->val, $objOp1->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                                         } else {
                                                                             $myStack->Push(Toolset_Tokenizer::makeToken(!Toolset_Functions::Contains($objOp2->val, $objOp1->val), Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                                                         }
                                                                         break;
                                                                     } else {
                                                                         throw new Exception("For " . $strTok->val . " operator LHS & RHS should be of same data type!");
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                         if ($strTok->val == "=" || $strTok->val == "eq") {
                             $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 == $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                         } else {
                             if ($strTok->val == "<>" || $strTok->val == "ne") {
                                 $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 != $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                             } else {
                                 if ($strTok->val == ">" || $strTok->val == "gt") {
                                     $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 > $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                 } else {
                                     if ($strTok->val == "<" || $strTok->val == "lt") {
                                         $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 < $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                     } else {
                                         if ($strTok->val == "<=" || $strTok->val == "lte") {
                                             $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 <= $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                         } else {
                                             if ($strTok->val == ">=" || $strTok->val == "gte") {
                                                 $myStack->Push(Toolset_Tokenizer::makeToken($dblVal1 >= $dblVal2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                         break;
                 }
                 break;
             case Toolset_Tokenizer::$TOKEN_TYPE['LOGICAL_OP']:
                 switch ($strTok->val) {
                     case 'NOT':
                     case '!':
                         if ($myStack->IsEmpty()) {
                             throw new Exception("No operand on stack!");
                         }
                         $objOp1 = null;
                         $objOp2 = null;
                         $objOp1 = $myStack->Pop();
                         if ($objOp1->isVariable) {
                             $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                         }
                         $objOp1 = Toolset_Tokenizer::toBoolean($objOp1->val);
                         if ($objOp1 === null) {
                             throw new Exception($strTok->val . " applied not on a boolean value!");
                         } else {
                             $myStack->Push(Toolset_Tokenizer::makeToken(!$objOp1, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                         }
                         break;
                     case "AND":
                     case "&":
                     case "OR":
                     case "|":
                         if ($myStack->IsEmpty() || $myStack->Size() < 2) {
                             throw new Exception("Stack is empty, can not perform [" . $strTok->val . "]");
                         }
                         $objOp1 = null;
                         $objOp2 = null;
                         $objTmp1 = null;
                         $objTmp2 = null;
                         $objOp2 = $myStack->Pop();
                         $objOp1 = $myStack->Pop();
                         if ($objOp1->isVariable) {
                             $objOp1 = $this->_getVariable($objOp1->val, $myvarArr);
                         }
                         if ($objOp2->isVariable) {
                             $objOp2 = $this->_getVariable($objOp2->val, $myvarArr);
                         }
                         if ($objOp1->isBoolean && $objOp2->isBoolean || $objOp1->isNumber && $objOp2->isNumber || $objOp1->isNumber && $objOp2->isBoolean || $objOp1->isBoolean && $objOp2->isNumber) {
                             $objTmp1 = Toolset_Tokenizer::toBoolean($objOp1->val);
                             $objTmp2 = Toolset_Tokenizer::toBoolean($objOp2->val);
                             if ($strTok->val == "AND" || $strTok->val == "&") {
                                 $myStack->Push(Toolset_Tokenizer::makeToken($objTmp1 && $objTmp2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                             } else {
                                 if ($strTok->val == "OR" || $strTok->val == "|") {
                                     $myStack->Push(Toolset_Tokenizer::makeToken($objTmp1 || $objTmp2, Toolset_Tokenizer::$TOKEN_TYPE['BOOLEAN']));
                                 }
                             }
                         } else {
                             throw new Exception("Logical operator requires LHS & RHS of boolean type!");
                         }
                         break;
                 }
                 break;
             case Toolset_Tokenizer::$TOKEN_TYPE['FUNCTION']:
                 $this->_HandleFunctions($strTok, $myStack, $this->dtFormat, $myvarArr);
                 break;
             default:
                 $myStack->Push($strTok);
                 break;
         }
         $intIndex++;
         //echo (string)$myStack->toString();
     }
     if ($myStack->IsEmpty() || $myStack->Size() > 1 || $myStack->Get(0)->isVariable) {
         throw new Exception("Unable to evaluate expression!");
     } else {
         return $myStack->Pop()->val;
     }
 }
 /**
  * Uses the Toolset_Tokenizer to break down the expression, replace problematic operators by their text-only
  * equivalents and glue the expression back together.
  *
  * Side-effects: Loses custom whitespace characters. All operators (except parentheses) will be surrounded by spaces
  * while everywhere else the whitespace characters will be trimmed.
  *
  * Note: If an invalid expression is provided, it doesn't do anything with it.
  *
  * @param string $expression Condition expression.
  * @return string Equivalent expression but without <, <=, etc.
  * @since 2.0
  */
 protected function transform_operators_to_text_equivalents($expression)
 {
     try {
         // The expression may come directly from parse_str() which may add backslashes to quotes. The tokenizer
         // wouldn't survive that.
         $expression = stripslashes($expression);
         $toolset_bootstrap = Toolset_Common_Bootstrap::getInstance();
         $toolset_bootstrap->register_parser();
         $tokenizer = new Toolset_Tokenizer();
         $tokens = $tokenizer->Tokanize($expression);
         $token_value_replacements = array('<' => 'lt', '>' => 'gt', '<=' => 'lte', '>=' => 'gte', '<>' => 'ne', '=' => 'eq');
         $result = '';
         foreach ($tokens as $token) {
             if ($token->isCompOp) {
                 $token->val = wpcf_getarr($token_value_replacements, $token->val, $token->val);
             }
             if ($token->isCompOp || $token->isArithmeticOp || $token->isLogicOp) {
                 $result .= ' ' . $token->val . ' ';
             } else {
                 if ($token->isStringLiteral) {
                     $result .= '\'' . $token->val . '\'';
                 } else {
                     $result .= $token->val;
                 }
             }
         }
         return $result;
     } catch (Exception $e) {
         // Most probably we were unable to tokenize the expression. We give up.
         return $expression;
     }
 }