/** * @expectedException \Tbm\Peval\EvaluationException */ public function testInvalidBooleanExpressionException() { /* * These tests involve invalid expressions. */ $evaluator = new Evaluator(); $evaluator->evaluate1(new String("3 3 < 3")); $evaluator->evaluate1(new String("3 << 3")); $evaluator->evaluate1(new String("3 <> 4")); $evaluator->evaluate1(new String("!!(3 <> 4)")); $evaluator->evaluate1(new String("3 = 4")); $evaluator->evaluate1(new String("2 < 3 && 1 = 1")); $evaluator->evaluate1(new String("(3) (3 < 3)")); $evaluator->evaluate1(new String("3 (<<) 3")); $evaluator->evaluate1(new String("(2 < 3) && (1 = 1")); }
/** * @expectedException Tbm\Peval\EvaluationException */ public function testInvalidMathExpressionException() { /* * These tests involve invalid expressions. */ $evaluator = new Evaluator(); $evaluator->evaluate1(new String("-")); $evaluator->evaluate1(new String("4 + ")); $evaluator->evaluate1(new String("4 - ")); $evaluator->evaluate1(new String("4 + -")); $evaluator->evaluate1(new String("--4")); $evaluator->evaluate1(new String("4 * / 3")); $evaluator->evaluate1(new String("* 3")); $evaluator->evaluate1(new String("((4")); $evaluator->evaluate1(new String("4 (")); $evaluator->evaluate1(new String("(4))")); $evaluator->evaluate1(new String("((4 + 3)) * 2)")); $evaluator->evaluate1(new String("4 ()")); $evaluator->evaluate1(new String("4 (+) 3")); }
/** * Executes the function for the specified argument. This method is called * internally by Evaluator. * * @param Evaluator $evaluator * @param String|\Tbm\Peval\Types\String $arguments * A string argument that will be converted into one string and * one integer argument. The first argument is the source string * and the second argument is the index. The string argument(s) * HAS to be enclosed in quotes. White space that is not enclosed * within quotes will be trimmed. Quote characters in the first * and last positions of any string argument (after being * trimmed) will be removed also. The quote characters used must * be the same as the quote characters used by the current * instance of Evaluator. If there are multiple arguments, they * must be separated by a comma (","). * * @throws \Tbm\Peval\Func\FunctionException Thrown if the argument(s) are not valid for this use Tbm\Peval\Func\ * @return \Tbm\Peval\Func\FunctionResult A character that is located at the specified index. The value is * returned as a string. */ public function execute(Evaluator $evaluator, string $arguments) { $result = null; $exceptionMessage = "One string and one integer argument are required."; $values = FunctionHelper::getOneStringAndOneInteger($arguments, EvaluationConstants::FUNCTION_ARGUMENT_SEPARATOR); if ($values->size() != 2) { throw new FunctionException($exceptionMessage); } try { $argumentOne = FunctionHelper::trimAndRemoveQuoteChars($values->get(0), $evaluator->getQuoteCharacter()); $index = $values->get(1)->getValue(); $character = array(); $character[0] = $argumentOne->charAt($index); $result = new String($character); } catch (FunctionException $fe) { throw new FunctionException($fe . getMessage(), $fe); } catch (Exception $e) { throw new FunctionException($exceptionMessage, $e); } return new FunctionResult($result, FunctionConstants::FUNCTION_RESULT_TYPE_STRING); }
public function testCharAtFunction() { $evaluator = new Evaluator(); $this->assertEquals("'s'", $evaluator->evaluate1(new String("charAt('test', 2)"))); $this->assertEquals("'A'", $evaluator->evaluate1(new String("'A'"))); }
/** * Test expressions containing string operations. */ public function testEvaluateStringOperations() { $evaluator = new Evaluator(); try { /* * These tests involve valid expressions. */ //$this->assertEquals("'A'", $evaluator->evaluate1(new String("'A'"))); $this->assertEquals("'AC'", $evaluator->evaluate1(new String("'A' + 'C'"))); $this->assertEquals("'A + C'", $evaluator->evaluate1(new String("'A + C'"))); $this->assertEquals("'ABC'", $evaluator->evaluate1(new String("'AB' + 'C'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'A' < 'C'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_FALSE, $evaluator->evaluate1(new String("'C' < 'A'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'C' < 'F'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'C' < 'c'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_FALSE, $evaluator->evaluate1(new String("'c' < 'C'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_FALSE, $evaluator->evaluate1(new String("'A' > 'C'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'C' > 'A'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_FALSE, $evaluator->evaluate1(new String("'C' > 'F'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'A' <= 'A'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_FALSE, $evaluator->evaluate1(new String("'C' <= 'A'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'C' <= 'F'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'A' >= 'A'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("'C' >= 'A'"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_FALSE, $evaluator->evaluate1(new String("'C' >= 'F'"))); $this->assertEquals("'A'", $evaluator->evaluate1(new String("('A')"))); $this->assertEquals("'ABC'", $evaluator->evaluate1(new String("('AB' + 'C')"))); $this->assertEquals("'123ABC'", $evaluator->evaluate1(new String("'123' + ('AB' + 'C')"))); $this->assertEquals(EvaluationConstants . BOOLEAN_STRING_TRUE, $evaluator->evaluate1(new String("(('C' >= 'A'))"))); } catch (Exception $e) { throw new Exception($e); } }
/** * This method process nested function calls that may be in the arguments * passed into a higher level function. * * @param String|\Tbm\Peval\Types\String $arguments * * @throws \Tbm\Peval\EvaluationException * @return \Tbm\Peval\Types\String The arguments with any nested function calls evaluated. * */ public function processNestedFunctions(string $arguments) { $evaluatedArguments = new String(); // Process nested function calls. if ($arguments->length() > 0) { $argumentsEvaluator = new Evaluator($this->quoteCharacter, $this->loadMathVariables, $this->loadMathFunctions, $this->loadStringFunctions, $this->processNestedFunctions); $this->argumentsEvaluator->setFunctions(getFunctions()); $this->argumentsEvaluator->setVariables(getVariables()); $this->argumentsEvaluator->setVariableResolver(getVariableResolver()); $tokenizer = new ArgumentTokenizer($arguments, EvaluationConstants::FUNCTION_ARGUMENT_SEPARATOR); $evaluatedArgumentList = new ArrayList(); while ($tokenizer . hasMoreTokens()) { $argument = $tokenizer->nextToken()->trim(); try { $argument = $argumentsEvaluator->evaluate1($argument); } catch (Exception $e) { throw new EvaluationException($e->getMessage(), $e); } $evaluatedArgumentList->add($argument); } $evaluatedArgumentIterator = $evaluatedArgumentList->iterator(); while ($evaluatedArgumentIterator->valid()) { if ($evaluatedArguments->length() > 0) { $evaluatedArguments->append(EvaluationConstants::FUNCTION_ARGUMENT_SEPARATOR); } $evaluatedArgumentIterator->next(); $evaluatedArgument = (string) $evaluatedArgumentIterator->current(); $evaluatedArguments . append($evaluatedArgument); } } return $evaluatedArguments; }
/** * Unloads the functions in this function group from an instance of * Evaluator. * * @param \Tbm\Peval\Evaluator $evaluator * An instance of Evaluator to unload the functions from. */ public function unload(Evaluator $evaluator) { $functionIterator = $this->functions->iterator(); while ($functionIterator->valid()) { $function = $functionIterator->current(); $evaluator->removeFunction($function); $functionIterator->next(); } }
/** * Evaluates the operands for this tree using the operator and the unary * operator. * * @param wrapStringFunctionResults * Indicates if the results from functions that return strings * should be wrapped in quotes. The quote character used will be * whatever is the current quote character for this object. * * @exception EvaluateException * Thrown is an error is encountered while processing the * expression. * * @return String */ public function evaluate($wrapStringFunctionResults) { $rtnResult = null; // Get the left operand. $leftResultString = null; $leftResultDouble = null; if ($this->leftOperand instanceof ExpressionTree) { $leftResultString = $this->leftOperand->evaluate($wrapStringFunctionResults); try { $leftResultDouble = new Double($leftResultString); $leftResultString = null; } catch (NumberFormatException $exception) { $leftResultDouble = null; } } else { if ($this->leftOperand instanceof ExpressionOperand) { $leftExpressionOperand = $this->leftOperand; $leftResultString = $leftExpressionOperand->getValue(); $leftResultString = $this->evaluator->replaceVariables($leftResultString); // Check if the operand is a string or not. If it is not a string, // then it must be a number. if (!$this->evaluator->isExpressionString($leftResultString)) { try { $leftResultDouble = new Double($leftResultString); $leftResultString = null; } catch (NumberFormatException $nfe) { throw new EvaluationException("Expression is invalid.", $nfe); } if ($leftExpressionOperand->getUnaryOperator() != null) { $leftResultDouble = new Double($leftExpressionOperand->getUnaryOperator()->evaluate($leftResultDouble)); } } else { if ($leftExpressionOperand->getUnaryOperator() != null) { throw new EvaluationException("Invalid operand for unary operator."); } } } else { if ($this->leftOperand instanceof ParsedFunction) { $parsedFunction = $this->leftOperand; $function = $parsedFunction->getFunction(); $arguments = $parsedFunction->getArguments(); $arguments = $this->evaluator . replaceVariables($arguments); if ($this->evaluator->getProcessNestedFunctions()) { $arguments = $this->evaluator->processNestedFunctions($arguments); } try { $functionResult = $function->execute($this->evaluator, $arguments); $leftResultString = $functionResult->getResult(); if ($functionResult->getType() == FunctionConstants::FUNCTION_RESULT_TYPE_NUMERIC) { $resultDouble = new Double($leftResultString); // Process a unary operator if one exists. if ($parsedFunction->getUnaryOperator() != null) { $resultDouble = new Double($parsedFunction->getUnaryOperator()->evaluate($resultDouble . getValue())); } // Get the final result. $leftResultString = $resultDouble . toString(); } else { if ($functionResult->getType() == FunctionConstants::FUNCTION_RESULT_TYPE_STRING) { // The result must be a string result. if ($wrapStringFunctionResults) { $leftResultString = $this->evaluator->getQuoteCharacter() . $leftResultString . $this->evaluator->getQuoteCharacter(); } if ($parsedFunction->getUnaryOperator() != null) { throw new EvaluationException("Invalid operand for unary operator."); } } } } catch (FunctionException $fe) { throw new EvaluationException($fe->getMessage(), $fe); } if (!$this->evaluator->isExpressionString($leftResultString)) { try { $leftResultDouble = new Double($leftResultString); $leftResultString = null; } catch (NumberFormatException $nfe) { throw new EvaluationException("Expression is invalid.", $nfe); } } } else { if ($this->leftOperand != null) { throw new EvaluationException("Expression is invalid."); } } } } // Get the right operand. $rightResultString = null; $rightResultDouble = null; if ($this->rightOperand instanceof ExpressionTree) { $rightResultString = $this->rightOperand->evaluate($wrapStringFunctionResults); try { $rightResultDouble = new Double($rightResultString); $rightResultString = null; } catch (NumberFormatException $exception) { $rightResultDouble = null; } } else { if ($this->rightOperand instanceof ExpressionOperand) { $rightExpressionOperand = $this->rightOperand; $rightResultString = $this->rightOperand->getValue(); $rightResultString = $this->evaluator->replaceVariables($rightResultString); // Check if the operand is a string or not. If it not a string, // then it must be a number. if (!$this->evaluator->isExpressionString($rightResultString)) { try { $rightResultDouble = new Double($rightResultString); $rightResultString = null; } catch (NumberFormatException $nfe) { throw new EvaluationException("Expression is invalid.", $nfe); } if ($rightExpressionOperand->getUnaryOperator() != null) { $rightResultDouble = new Double($rightExpressionOperand->getUnaryOperator()->evaluate($rightResultDouble)); } } else { if ($rightExpressionOperand->getUnaryOperator() != null) { throw new EvaluationException("Invalid operand for unary operator."); } } } else { if ($this->rightOperand instanceof ParsedFunction) { $parsedFunction = $this->rightOperand; $function = $parsedFunction->getFunction(); $arguments = $parsedFunction->getArguments(); $arguments = $this->evaluator->replaceVariables($arguments); if ($this->evaluator->getProcessNestedFunctions()) { $arguments = $this->evaluator->processNestedFunctions($arguments); } try { $functionResult = $function->execute($this->evaluator, $arguments); $rightResultString = $functionResult->getResult(); if ($functionResult->getType() == FunctionConstants::FUNCTION_RESULT_TYPE_NUMERIC) { $resultDouble = new Double($rightResultString); // Process a unary operator if one exists. if ($parsedFunction->getUnaryOperator() != null) { $resultDouble = new Double($parsedFunction->getUnaryOperator()->evaluate($resultDouble->getValue())); } // Get the final result. $rightResultString = $resultDouble->toString(); } else { if ($functionResult->getType() == FunctionConstants::FUNCTION_RESULT_TYPE_STRING) { // The result must be a string result. if ($wrapStringFunctionResults) { $rightResultString = $this->evaluator->getQuoteCharacter() . $rightResultString . $this->evaluator->getQuoteCharacter(); } if ($parsedFunction->getUnaryOperator() != null) { throw new EvaluationException("Invalid operand for unary operator."); } } } } catch (FunctionException $fe) { throw new EvaluationException($fe . getMessage(), $fe); } if (!$this->evaluator->isExpressionString($rightResultString)) { try { $rightResultDouble = new Double($rightResultString); $rightResultString = null; } catch (NumberFormatException $nfe) { throw new EvaluationException("Expression is invalid.", $nfe); } } } else { if ($this->rightOperand == null) { // Do nothing. } else { throw new EvaluationException("Expression is invalid."); } } } } // Evaluate the the expression. if ($leftResultDouble != null && $rightResultDouble != null) { $doubleResult = $this->operator->evaluate($leftResultDouble, $rightResultDouble); if ($this->getUnaryOperator() != null) { $doubleResult = $this->getUnaryOperator()->evaluate($doubleResult); } $rtnResult = new Double($doubleResult); $rtnResult = $rtnResult->toString(); } else { if ($leftResultString != null && $rightResultString != null) { $rtnResult = $this->operator->evaluate($leftResultString, $rightResultString); } else { if ($leftResultDouble != null && $rightResultDouble == null) { $doubleResult = new Double(-1); if ($this->unaryOperator != null) { $doubleResult = $this->unaryOperator->evaluate($leftResultDouble); } else { // Do not allow numeric (left) and // string (right) to be evaluated together. throw new EvaluationException("Expression is invalid."); } $rtnResult = new Double($doubleResult); $rtnResult = $rtnResult->toString(); } else { throw new EvaluationException("Expression is invalid."); } } } return $rtnResult; }