diff --git a/phpunit.xml b/phpunit.xml
index ea7c8e9..886c9ee 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -26,6 +26,11 @@
tests
+
+
+ tests/MathParser/Interpreting/EvaluatorBooleanOperatorTest.php
+
+
diff --git a/src/MathParser/Interpreting/Evaluator.php b/src/MathParser/Interpreting/Evaluator.php
index 4b17c73..34931d6 100644
--- a/src/MathParser/Interpreting/Evaluator.php
+++ b/src/MathParser/Interpreting/Evaluator.php
@@ -11,6 +11,7 @@
use MathParser\Interpreting\Visitors\Visitor;
use MathParser\Parsing\Nodes\Node;
use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\NotBooleanNode;
use MathParser\Parsing\Nodes\NumberNode;
use MathParser\Parsing\Nodes\VariableNode;
use MathParser\Parsing\Nodes\FunctionNode;
@@ -104,16 +105,32 @@ public function visitExpressionNode(ExpressionNode $node)
// Perform the right operation based on the operator
switch ($operator) {
case '+':
- return $leftValue + $rightValue;
+ return $leftValue + $rightValue;
case '-':
- return $rightValue === null ? -$leftValue : $leftValue - $rightValue;
+ return $rightValue === null ? -$leftValue : $leftValue - $rightValue;
case '*':
- return $rightValue * $leftValue;
+ return $rightValue * $leftValue;
case '/':
- if ($rightValue == 0) throw new DivisionByZeroException();
- return $leftValue/$rightValue;
+ if ($rightValue == 0) throw new DivisionByZeroException();
+ return $leftValue/$rightValue;
case '^':
- return pow($leftValue, $rightValue);
+ return pow($leftValue, $rightValue);
+ case '=':
+ return intval(ceil($leftValue)) === intval(ceil($rightValue));
+ case '&&':
+ return intval(ceil($leftValue)) && intval(ceil($rightValue));
+ case '||':
+ return intval(ceil($leftValue)) || intval(ceil($rightValue));
+
+ case '>':
+ return ($leftValue > $rightValue);
+ case '>=':
+ return $leftValue >= $rightValue;
+ case '<':
+ return $leftValue < $rightValue;
+ case '<=':
+ return $leftValue <= $rightValue;
+
default:
throw new UnknownOperatorException($operator);
@@ -274,8 +291,15 @@ public function visitFunctionNode(FunctionNode $node)
return $inner >= 0 ? 1 : -1;
case '!':
- $logGamma = Math::logGamma(1+$inner);
- return exp($logGamma);
+ if($node instanceof NotBooleanNode) {
+ $intValue = intval(ceil($inner));
+ $result = !$intValue;
+ }
+ else {
+ $logGamma = Math::logGamma(1+$inner);
+ $result = exp($logGamma);
+ }
+ return $result;
case '!!':
if (round($inner) != $inner)throw new \UnexpectedValueException("Expecting positive integer (semifactorial)");
diff --git a/src/MathParser/Lexing/ComplexLexer.php b/src/MathParser/Lexing/ComplexLexer.php
index 14abe7a..d0dd23d 100644
--- a/src/MathParser/Lexing/ComplexLexer.php
+++ b/src/MathParser/Lexing/ComplexLexer.php
@@ -109,6 +109,16 @@ public function __construct()
$this->add(new TokenDefinition('/\//', TokenType::DivisionOperator));
$this->add(new TokenDefinition('/\^/', TokenType::ExponentiationOperator));
+ $this->add(new TokenDefinition('/\=/', TokenType::EqualCompareOperator));
+ $this->add(new TokenDefinition('/\>=/', TokenType::GreaterOrEqualOperator));
+ $this->add(new TokenDefinition('/\>/', TokenType::GreaterOperator));
+ $this->add(new TokenDefinition('/\<=/', TokenType::SmallerOrEqualOperator));
+ $this->add(new TokenDefinition('/\', TokenType::SmallerOperator));
+
+
+ $this->add(new TokenDefinition('/\&&/', TokenType::BooleanAndOperator));
+ $this->add(new TokenDefinition('/\|\|/', TokenType::BooleanOrOperator));
+
$this->add(new TokenDefinition('/pi/', TokenType::Constant));
$this->add(new TokenDefinition('/e/', TokenType::Constant));
$this->add(new TokenDefinition('/i/', TokenType::Constant));
diff --git a/src/MathParser/Lexing/Lexer.php b/src/MathParser/Lexing/Lexer.php
index 2bfa0cd..6553f4a 100644
--- a/src/MathParser/Lexing/Lexer.php
+++ b/src/MathParser/Lexing/Lexer.php
@@ -81,8 +81,10 @@ public function tokenize($input)
// If no tokens were matched, it means that the string has invalid tokens
// for which we did not define a token definition
- if (!$token)
+ if (!$token) {
throw new UnknownTokenException(0,$currentIndex);
+ }
+
// Add the matched token to our list of token
$tokens[] = $token;
diff --git a/src/MathParser/Lexing/StdMathLexer.php b/src/MathParser/Lexing/StdMathLexer.php
index c07b3b6..1e5a140 100644
--- a/src/MathParser/Lexing/StdMathLexer.php
+++ b/src/MathParser/Lexing/StdMathLexer.php
@@ -112,6 +112,16 @@ public function __construct()
$this->add(new TokenDefinition('/\//', TokenType::DivisionOperator));
$this->add(new TokenDefinition('/\^/', TokenType::ExponentiationOperator));
+
+ $this->add(new TokenDefinition('/\=/', TokenType::EqualCompareOperator));
+ $this->add(new TokenDefinition('/\>=/', TokenType::GreaterOrEqualOperator));
+ $this->add(new TokenDefinition('/\>/', TokenType::GreaterOperator));
+ $this->add(new TokenDefinition('/\<=/', TokenType::SmallerOrEqualOperator));
+ $this->add(new TokenDefinition('/\', TokenType::SmallerOperator));
+
+ $this->add(new TokenDefinition('/\&&/', TokenType::BooleanAndOperator));
+ $this->add(new TokenDefinition('/\|\|/', TokenType::BooleanOrOperator));
+
// Postfix operators
$this->add(new TokenDefinition('/\!\!/', TokenType::SemiFactorialOperator));
$this->add(new TokenDefinition('/\!/', TokenType::FactorialOperator));
diff --git a/src/MathParser/Lexing/Token.php b/src/MathParser/Lexing/Token.php
index 82ac9c2..00ee256 100644
--- a/src/MathParser/Lexing/Token.php
+++ b/src/MathParser/Lexing/Token.php
@@ -146,8 +146,14 @@ public static function canFactorsInImplicitMultiplication($token1, $token2)
if (!$check2) return false;
- if ($token1->type == TokenType::FunctionName && $token2->type == TokenType::OpenParenthesis)
+ if ($token1->type == TokenType::FunctionName && $token2->type == TokenType::OpenParenthesis) {
return false;
+ }
+
+ if($token1->type == TokenType::FactorialOperator && $check2) {
+ return false;
+ }
+
return true;
}
diff --git a/src/MathParser/Lexing/TokenType.php b/src/MathParser/Lexing/TokenType.php
index ef55fd8..b19ba13 100644
--- a/src/MathParser/Lexing/TokenType.php
+++ b/src/MathParser/Lexing/TokenType.php
@@ -67,6 +67,16 @@ final class TokenType
/** Token representing postfix subfactorial operator '!!' */
const SemiFactorialOperator = 105;
+ /** Token representing equal operator */
+ const EqualCompareOperator = 106;
+ const BooleanAndOperator = 107;
+ const BooleanOrOperator = 108;
+ const GreaterOperator = 109;
+ const GreaterOrEqualOperator = 110;
+ const SmallerOperator = 111;
+ const SmallerOrEqualOperator = 112;
+
+
/** Token represented a function name, e.g. 'sin' */
const FunctionName = 200;
diff --git a/src/MathParser/Parsing/Nodes/ExpressionNode.php b/src/MathParser/Parsing/Nodes/ExpressionNode.php
index e6d7992..73c0de2 100644
--- a/src/MathParser/Parsing/Nodes/ExpressionNode.php
+++ b/src/MathParser/Parsing/Nodes/ExpressionNode.php
@@ -96,6 +96,41 @@ function __construct($left, $operator = null, $right = null)
$this->associativity = self::RIGHT_ASSOC;
break;
+ case '=':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
+ case '&&':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
+ case '||':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
+ case '>':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
+ case '>=':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
+ case '<':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
+ case '<=':
+ $this->precedence = 5;
+ $this->associativity = self::LEFT_ASSOC;
+ break;
+
default:
throw new UnknownOperatorException($operator);
}
diff --git a/src/MathParser/Parsing/Nodes/Factories/BoolAndNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/BoolAndNodeFactory.php
new file mode 100644
index 0000000..0c6a129
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/BoolAndNodeFactory.php
@@ -0,0 +1,73 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing '&&'.
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class BoolAndNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '&&', $rightOperand);
+ }
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ( intval(ceil($leftOperand->getValue())) && intval(ceil($rightOperand->getValue())));
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $leftValue = intval(ceil($leftValue));
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $rightValue = intval(ceil($rightValue));
+ $result = ($leftValue && $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() && $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Factories/BoolEqualNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/BoolEqualNodeFactory.php
new file mode 100644
index 0000000..043a716
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/BoolEqualNodeFactory.php
@@ -0,0 +1,71 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing '='.
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class BoolEqualNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '=', $rightOperand);
+ }
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ($leftOperand->getValue() === $rightOperand->getValue());
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $result = ($leftValue === $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() === $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Factories/BoolOrNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/BoolOrNodeFactory.php
new file mode 100644
index 0000000..acfdb95
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/BoolOrNodeFactory.php
@@ -0,0 +1,75 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing '||'.
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class BoolOrNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '||', $rightOperand);
+ }
+
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ( intval(ceil($leftOperand->getValue())) || intval(ceil($rightOperand->getValue())));
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $leftValue = intval(ceil($leftValue));
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $rightValue = intval(ceil($rightValue));
+ $result = ($leftValue || $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() || $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Factories/GreaterNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/GreaterNodeFactory.php
new file mode 100644
index 0000000..33a727b
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/GreaterNodeFactory.php
@@ -0,0 +1,71 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing '='.
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class GreaterNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '>', $rightOperand);
+ }
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ($leftOperand->getValue() > $rightOperand->getValue());
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $result = ($leftValue > $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() > $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Factories/GreaterOrEqualNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/GreaterOrEqualNodeFactory.php
new file mode 100644
index 0000000..16c62b2
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/GreaterOrEqualNodeFactory.php
@@ -0,0 +1,71 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing >=
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class GreaterOrEqualNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '>=', $rightOperand);
+ }
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ($leftOperand->getValue() >= $rightOperand->getValue());
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $result = ($leftValue >= $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() >= $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Factories/NodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/NodeFactory.php
index aba72a6..f60d5bd 100644
--- a/src/MathParser/Parsing/Nodes/Factories/NodeFactory.php
+++ b/src/MathParser/Parsing/Nodes/Factories/NodeFactory.php
@@ -75,6 +75,17 @@ class NodeFactory {
**/
protected $exponentiationFactory;
+ protected $boolEqualNodeFactory;
+
+ protected $boolAndNodeFactory;
+
+ protected $boolOrNodeFactory;
+
+ protected $greaterNodeFactory;
+ protected $greaterOrEqualNodeFactory;
+ protected $smallerNodeFactory;
+ protected $smallerOrEqualNodeFactory;
+
/**
* Constructor
*/
@@ -85,6 +96,13 @@ public function __construct()
$this->multiplicationFactory = new MultiplicationNodeFactory();
$this->divisionFactory = new DivisionNodeFactory();
$this->exponentiationFactory = new ExponentiationNodeFactory();
+ $this->boolEqualNodeFactory = new BoolEqualNodeFactory();
+ $this->boolAndNodeFactory = new BoolAndNodeFactory();
+ $this->boolOrNodeFactory = new BoolOrNodeFactory();
+ $this->greaterNodeFactory = new GreaterNodeFactory();
+ $this->greaterOrEqualNodeFactory = new GreaterOrEqualNodeFactory();
+ $this->smallerNodeFactory = new SmallerNodeFactory();
+ $this->smallerOrEqualNodeFactory = new SmallerOrEqualNodeFactory();
}
/**
@@ -164,6 +182,36 @@ public function unaryMinus($operand)
return $this->subtractionFactory->createUnaryMinusNode($operand);
}
+
+ public function compareEqual($leftOperand, $rightOperand) {
+ return $this->boolEqualNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
+
+ public function boolAnd($leftOperand, $rightOperand) {
+ return $this->boolAndNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
+ public function boolOr($leftOperand, $rightOperand) {
+ return $this->boolOrNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
+ public function greater($leftOperand, $rightOperand) {
+ return $this->greaterNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
+ public function greaterOrEqual($leftOperand, $rightOperand) {
+ return $this->greaterOrEqualNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
+ public function smaller($leftOperand, $rightOperand) {
+ return $this->smallerNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
+ public function smallerOrEqual($leftOperand, $rightOperand) {
+ return $this->smallerOrEqualNodeFactory->makeNode($leftOperand, $rightOperand);
+ }
+
/**
* Simplify the given ExpressionNode, using the appropriate factory.
*
@@ -178,6 +226,14 @@ public function simplify(ExpressionNode $node)
case '*': return $this->multiplication($node->getLeft(), $node->getRight());
case '/': return $this->division($node->getLeft(), $node->getRight());
case '^': return $this->exponentiation($node->getLeft(), $node->getRight());
+ case '=': return $this->compareEqual($node->getLeft(), $node->getRight());
+ case '>': return $this->greater($node->getLeft(), $node->getRight());
+ case '>=': return $this->greaterOrEqual($node->getLeft(), $node->getRight());
+ case '<': return $this->smaller($node->getLeft(), $node->getRight());
+ case '<=': return $this->smallerOrEqual($node->getLeft(), $node->getRight());
+ case '&&': return $this->boolAnd($node->getLeft(), $node->getRight());
+ case '||': return $this->boolOr($node->getLeft(), $node->getRight());
+
}
}
diff --git a/src/MathParser/Parsing/Nodes/Factories/SmallerNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/SmallerNodeFactory.php
new file mode 100644
index 0000000..86ba8aa
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/SmallerNodeFactory.php
@@ -0,0 +1,71 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing '<'.
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class SmallerNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '<', $rightOperand);
+ }
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ($leftOperand->getValue() < $rightOperand->getValue());
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $result = ($leftValue < $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() < $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Factories/SmallerOrEqualNodeFactory.php b/src/MathParser/Parsing/Nodes/Factories/SmallerOrEqualNodeFactory.php
new file mode 100644
index 0000000..55b3b52
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/Factories/SmallerOrEqualNodeFactory.php
@@ -0,0 +1,71 @@
+
+* @copyright 2015 Frank Wikström
+* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+*
+*/
+
+namespace MathParser\Parsing\Nodes\Factories;
+
+use MathParser\Parsing\Nodes\Interfaces\ExpressionNodeFactory;
+
+use MathParser\Parsing\Nodes\Node;
+use MathParser\Parsing\Nodes\NumberNode;
+use MathParser\Parsing\Nodes\IntegerNode;
+use MathParser\Parsing\Nodes\RationalNode;
+
+use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\Traits\Sanitize;
+use MathParser\Parsing\Nodes\Traits\Numeric;
+
+/**
+* Factory for creating an ExpressionNode representing '<'.
+*
+* Some basic simplification is applied to the resulting Node.
+*
+*/
+class SmallerOrEqualNodeFactory implements ExpressionNodeFactory
+{
+ use Sanitize;
+ use Numeric;
+
+ public function makeNode($leftOperand, $rightOperand)
+ {
+ $leftOperand = $this->sanitize($leftOperand);
+ $rightOperand = $this->sanitize($rightOperand);
+
+ $node = $this->numericTerms($leftOperand, $rightOperand);
+ if ($node) return $node;
+
+ return new ExpressionNode($leftOperand, '<=', $rightOperand);
+ }
+
+ protected function numericTerms($leftOperand, $rightOperand)
+ {
+ if (!$this->isNumeric($leftOperand) || !$this->isNumeric($rightOperand)) {
+ return null;
+ }
+ $type = $this->resultingType($leftOperand, $rightOperand);
+
+ switch($type) {
+ case Node::NumericFloat:
+ $result = ($leftOperand->getValue() <= $rightOperand->getValue());
+ return new NumberNode($result);
+
+ case Node::NumericRational:
+ $leftValue = ($leftOperand->getNumerator() / $leftOperand->getDenominator());
+ $rightValue = ($rightOperand->getDenominator() / $rightOperand->getNumerator());
+ $result = ($leftValue <= $rightValue);
+ return new IntegerNode($result);
+
+ case Node::NumericInteger:
+ $result = ($leftOperand->getValue() <= $rightOperand->getValue());
+ return new IntegerNode($result);
+ }
+
+
+ return null;
+ }
+}
diff --git a/src/MathParser/Parsing/Nodes/Node.php b/src/MathParser/Parsing/Nodes/Node.php
index 72ec60c..9044d57 100644
--- a/src/MathParser/Parsing/Nodes/Node.php
+++ b/src/MathParser/Parsing/Nodes/Node.php
@@ -71,6 +71,8 @@ public static function rationalFactory(Token $token)
case TokenType::MultiplicationOperator:
case TokenType::DivisionOperator:
case TokenType::ExponentiationOperator:
+ case TokenType::EqualCompareOperator:
+ case TokenType::BooleanAndOperator:
return new ExpressionNode(null, $token->getValue(), null);
case TokenType::FactorialOperator:
@@ -118,6 +120,14 @@ public static function factory(Token $token)
case TokenType::MultiplicationOperator:
case TokenType::DivisionOperator:
case TokenType::ExponentiationOperator:
+ case TokenType::EqualCompareOperator:
+ case TokenType::BooleanAndOperator:
+ case TokenType::BooleanOrOperator:
+ case TokenType::GreaterOperator:
+ case TokenType::GreaterOrEqualOperator:
+ case TokenType::SmallerOperator:
+ case TokenType::SmallerOrEqualOperator:
+
return new ExpressionNode(null, $token->getValue(), null);
case TokenType::FactorialOperator:
diff --git a/src/MathParser/Parsing/Nodes/NotBooleanNode.php b/src/MathParser/Parsing/Nodes/NotBooleanNode.php
new file mode 100644
index 0000000..e0b3551
--- /dev/null
+++ b/src/MathParser/Parsing/Nodes/NotBooleanNode.php
@@ -0,0 +1,90 @@
+
+ * @copyright 2015 Frank Wikström
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ *
+ */
+
+namespace MathParser\Parsing\Nodes;
+
+use MathParser\Interpreting\Visitors\Visitor;
+
+/**
+ * AST node representing a function applications (e.g. sin(...))
+ */
+class NotBooleanNode extends FunctionNode
+{
+ /** string $name Function name, e.g. 'sin' */
+ private $name;
+ /** Node $operand AST of function operand */
+ private $operand;
+
+ /** Constructor, create a FunctionNode with given name and operand */
+ function __construct($name, $operand)
+ {
+ $this->name = $name;
+ if (is_int($operand)) {
+ $operand = new NumberNode($operand);
+ }
+ $this->operand = $operand;
+ }
+
+ /**
+ * Return the name of the function
+ * @retval string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Return the operand
+ * @retval Node
+ */
+ public function getOperand()
+ {
+ return $this->operand;
+ }
+
+ /**
+ * Set the operand
+ * @retval void
+ */
+ public function setOperand($operand)
+ {
+ return $this->operand = $operand;
+ }
+
+ public function getOperator()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Implementing the Visitable interface.
+ */
+ public function accept(Visitor $visitor)
+ {
+ return $visitor->visitFunctionNode($this);
+ }
+
+ /** Implementing the compareTo abstract method. */
+ public function compareTo($other)
+ {
+ if ($other === null) {
+ return false;
+ }
+ if (!($other instanceof FunctionNode)) {
+ return false;
+ }
+
+ $thisOperand = $this->getOperand();
+ $otherOperand = $other->getOperand();
+
+ return $this->getName() == $other->getName() && $thisOperand->compareTo($otherOperand);
+ }
+
+}
diff --git a/src/MathParser/Parsing/Parser.php b/src/MathParser/Parsing/Parser.php
index 5c9cae1..a86c5c1 100644
--- a/src/MathParser/Parsing/Parser.php
+++ b/src/MathParser/Parsing/Parser.php
@@ -9,10 +9,10 @@
/**
-* @namespace MathParser::Parsing
-*
-* Parser related classes
-*/
+ * @namespace MathParser::Parsing
+ *
+ * Parser related classes
+ */
namespace MathParser\Parsing;
use MathParser\Lexing\Token;
@@ -22,6 +22,7 @@
use MathParser\Parsing\Nodes\Node;
use MathParser\Parsing\Nodes\ExpressionNode;
+use MathParser\Parsing\Nodes\NotBooleanNode;
use MathParser\Parsing\Nodes\NumberNode;
use MathParser\Parsing\Nodes\VariableNode;
use MathParser\Parsing\Nodes\FunctionNode;
@@ -40,49 +41,50 @@
use MathParser\Interpreting\PrettyPrinter;
/**
-* Mathematical expression parser, based on the shunting yard algorithm.
-*
-* Parse a token string into an abstract syntax tree (AST).
-*
-* As the parser loops over the individual tokens, two stacks are kept
-* up to date. One stack ($operatorStack) consists of hitherto unhandled
-* tokens corresponding to ''operators'' (unary and binary operators, function
-* applications and parenthesis) and a stack of parsed sub-expressions (the
-* $operandStack).
-*
-* If the current token is a terminal token (number, variable or constant),
-* a corresponding node is pushed onto the operandStack.
-*
-* Otherwise, the precedence of the current token is compared to the top
-* element(t) on the operatorStack, and as long as the current token has
-* lower precedence, we keep popping operators from the stack to constuct
-* more complicated subexpressions together with the top items on the operandStack.
-*
-* Once the token list is empty, we pop the remaining operators as above, and
-* if the formula was well-formed, the only thing remaining on the operandStack
-* is a completely parsed AST, which we return.
-*/
+ * Mathematical expression parser, based on the shunting yard algorithm.
+ *
+ * Parse a token string into an abstract syntax tree (AST).
+ *
+ * As the parser loops over the individual tokens, two stacks are kept
+ * up to date. One stack ($operatorStack) consists of hitherto unhandled
+ * tokens corresponding to ''operators'' (unary and binary operators, function
+ * applications and parenthesis) and a stack of parsed sub-expressions (the
+ * $operandStack).
+ *
+ * If the current token is a terminal token (number, variable or constant),
+ * a corresponding node is pushed onto the operandStack.
+ *
+ * Otherwise, the precedence of the current token is compared to the top
+ * element(t) on the operatorStack, and as long as the current token has
+ * lower precedence, we keep popping operators from the stack to constuct
+ * more complicated subexpressions together with the top items on the operandStack.
+ *
+ * Once the token list is empty, we pop the remaining operators as above, and
+ * if the formula was well-formed, the only thing remaining on the operandStack
+ * is a completely parsed AST, which we return.
+ */
class Parser
{
/**
- * Token[] list of tokens to process
- */
+ * Token[] list of tokens to process
+ */
protected $tokens;
/**
- * Stack stack of operators waiting to process
- */
+ * Stack stack of operators waiting to process
+ */
protected $operatorStack;
/**
- * Stack stack of operands waiting to process
- */
+ * Stack stack of operands waiting to process
+ */
protected $operandStack;
/**
* NodeFactory
*/
- protected $nodeFactory;
+ protected $nodeFactory;
protected $rationalFactory = false;
protected $simplifyingParser = true;
+ protected $lastUnaryOperator = null;
/**
* Constructor
@@ -103,11 +105,11 @@ public function setSimplifying($flag)
}
/**
- * Parse list of tokens
- *
- * @param array $tokens Array (Token[]) of input tokens.
- * @retval Node AST representing the parsed expression.
- */
+ * Parse list of tokens
+ *
+ * @param array $tokens Array (Token[]) of input tokens.
+ * @retval Node AST representing the parsed expression.
+ */
public function parse(array $tokens)
{
// Filter away any whitespace
@@ -125,13 +127,13 @@ public function parse(array $tokens)
}
/**
- * Implementation of the shunting yard parsing algorithm
- *
- * @param array $tokens Token[] array of tokens to process
- * @retval Node AST of the parsed expression
- * @throws SyntaxErrorException
- * @throws ParenthesisMismatchException
- */
+ * Implementation of the shunting yard parsing algorithm
+ *
+ * @param array $tokens Token[] array of tokens to process
+ * @retval Node AST of the parsed expression
+ * @throws SyntaxErrorException
+ * @throws ParenthesisMismatchException
+ */
private function shuntingYard(array $tokens)
{
// Clear the oepratorStack
@@ -144,14 +146,11 @@ private function shuntingYard(array $tokens)
$lastNode = null;
// Loop over the tokens
+
for ($index = 0; $index < count($tokens); $index++)
{
$token = $tokens[$index];
- // echo "current token $token\n";
- // echo("operands:" . $this->operandStack . "\n");
- // echo("operators: " . $this->operatorStack . "\n\n");
-
if ($this->rationalFactory) {
$node = Node::rationalFactory($token);
} else {
@@ -165,7 +164,6 @@ private function shuntingYard(array $tokens)
// Push terminal tokens on the operandStack
elseif ($node->isTerminal()) {
$this->operandStack->push($node);
-
// Push function applications or open parentheses `(` onto the operatorStack
} elseif ($node instanceof FunctionNode) {
$this->operatorStack->push($node);
@@ -175,9 +173,14 @@ private function shuntingYard(array $tokens)
// Handle the remaining operators.
} elseif ($node instanceof PostfixOperatorNode) {
+
$op = $this->operandStack->pop();
- if ($op == NULL) throw new SyntaxErrorException();
- $this->operandStack->push(new FunctionNode($node->getOperator(), $op));
+ if ($op == NULL) {
+ $this->operatorStack->push(new NotBooleanNode($node->getOperator(), null));
+ continue;
+ } else {
+ $this->operandStack->push(new FunctionNode($node->getOperator(), $op));
+ }
} elseif ($node instanceof ExpressionNode) {
@@ -188,12 +191,13 @@ private function shuntingYard(array $tokens)
switch($token->getType()) {
// Unary +, just ignore it
case TokenType::AdditionOperator:
- $node = null;
- break;
+ $node = null;
+ break;
+
// Unary -, replace the token.
case TokenType::SubtractionOperator:
- $node->setOperator('~');
- break;
+ $node->setOperator('~');
+ break;
}
} else {
// Pop operators with higher priority
@@ -210,7 +214,9 @@ private function shuntingYard(array $tokens)
}
// Remember the current token (if it hasn't been nulled, for example being a unary +)
- if ($node) $lastNode = $node;
+ if ($node) {
+ $lastNode = $node;
+ }
}
@@ -231,18 +237,26 @@ private function shuntingYard(array $tokens)
}
+
+
/**
- * Populate node with operands.
- *
- * @param Node $node
- * @retval Node
- * @throws SyntaxErrorException
- */
+ * Populate node with operands.
+ *
+ * @param Node $node
+ * @retval Node
+ * @throws SyntaxErrorException
+ */
protected function handleExpression($node)
{
+
+ if ($node instanceof NotBooleanNode) {
+ $op = $this->operandStack->pop();
+ $node->setOperand($op);
+ return $node;
+ }
+
if ($node instanceof FunctionNode) throw new ParenthesisMismatchException($node->getOperator());
if ($node instanceof SubExpressionNode) throw new ParenthesisMismatchException($node->getOperator());
-
if (!$this->simplifyingParser) return $this->naiveHandleExpression($node);
if ($node->getOperator() == '~') {
@@ -270,6 +284,7 @@ protected function handleExpression($node)
return $this->nodeFactory->simplify($node);
}
+
$right = $this->operandStack->pop();
$left = $this->operandStack->pop();
if ($right === null || $left === null) {
@@ -279,16 +294,17 @@ protected function handleExpression($node)
$node->setLeft($left);
$node->setRight($right);
+
return $this->nodeFactory->simplify($node);
}
/**
- * Populate node with operands, without any simplification.
- *
- * @param Node $node
- * @retval Node
- * @throws SyntaxErrorException
- */
+ * Populate node with operands, without any simplification.
+ *
+ * @param Node $node
+ * @retval Node
+ * @throws SyntaxErrorException
+ */
protected function naiveHandleExpression($node)
{
if ($node->getOperator() == '~') {
@@ -317,11 +333,11 @@ protected function naiveHandleExpression($node)
}
/**
- * Remove Whitespace from the token list.
- *
- * @param array $tokens Input list of tokens
- * @retval Token[]
- */
+ * Remove Whitespace from the token list.
+ *
+ * @param array $tokens Input list of tokens
+ * @retval Token[]
+ */
protected function filterTokens(array $tokens)
{
$filteredTokens = array_filter($tokens, function (Token $t) {
@@ -333,11 +349,11 @@ protected function filterTokens(array $tokens)
}
/**
- * Insert multiplication tokens where needed (taking care of implicit mulitplication).
- *
- * @param array $tokens Input list of tokens (Token[])
- * @retval Token[]
- */
+ * Insert multiplication tokens where needed (taking care of implicit mulitplication).
+ *
+ * @param array $tokens Input list of tokens (Token[])
+ * @retval Token[]
+ */
protected function parseImplicitMultiplication(array $tokens)
{
$result = [];
@@ -353,27 +369,27 @@ protected function parseImplicitMultiplication(array $tokens)
}
/**
- * Determine if the parser allows implicit multiplication. Create a
- * subclass of Parser, overriding this function, returning false instead
- * to diallow implicit multiplication.
- *
- * ### Example:
- *
- * ~~~{.php}
- * class ParserWithoutImplicitMultiplication extends Parser {
- * protected static function allowImplicitMultiplication() {
- * return false;
- * }
- * }
- *
- * $lexer = new StdMathLexer();
- * $tokens = $lexer->tokenize('2x');
- * $parser = new ParserWithoutImplicitMultiplication();
- * $node = $parser->parse($tokens); // Throws a SyntaxErrorException
- * ~~~
- * @property allowImplicitMultiplication
- * @retval boolean
- */
+ * Determine if the parser allows implicit multiplication. Create a
+ * subclass of Parser, overriding this function, returning false instead
+ * to diallow implicit multiplication.
+ *
+ * ### Example:
+ *
+ * ~~~{.php}
+ * class ParserWithoutImplicitMultiplication extends Parser {
+ * protected static function allowImplicitMultiplication() {
+ * return false;
+ * }
+ * }
+ *
+ * $lexer = new StdMathLexer();
+ * $tokens = $lexer->tokenize('2x');
+ * $parser = new ParserWithoutImplicitMultiplication();
+ * $node = $parser->parse($tokens); // Throws a SyntaxErrorException
+ * ~~~
+ * @property allowImplicitMultiplication
+ * @retval boolean
+ */
protected static function allowImplicitMultiplication()
{
return true;
diff --git a/tests/MathParser/Interpreting/EvaluatorBooleanOperatorTest.php b/tests/MathParser/Interpreting/EvaluatorBooleanOperatorTest.php
new file mode 100644
index 0000000..ad036ba
--- /dev/null
+++ b/tests/MathParser/Interpreting/EvaluatorBooleanOperatorTest.php
@@ -0,0 +1,139 @@
+parser = new StdMathParser();
+ $this->rparser = new RationalMathParser();
+
+ $this->variables = array('x' => '0.7', 'y' => '2.1');
+ $this->evaluator = new Evaluator($this->variables);
+ }
+
+ private function evaluate($f)
+ {
+ $this->evaluator->setVariables($this->variables);
+ return $f->accept($this->evaluator);
+ }
+
+ private function assertResult($f, $x)
+ {
+ $value = $this->evaluate($this->parser->parse($f));
+ $this->assertEquals($x, $value);
+ }
+
+
+ public function testNumberExpressionWithEqualOperator() {
+ $this->assertResult('10=10', 1);
+ $this->assertResult('(10+8+2)=(10+10)', 1);
+ $this->assertResult('10+8+2=10+10', 1);
+ $this->assertResult('4/3=4/3', 1);
+ $this->assertResult('4=5', 0);
+ $this->assertResult('x=y', 0);
+ }
+
+
+
+ public function testNumberExpressionWithAndOperator() {
+ $this->assertResult('1 && 1', 1);
+ $this->assertResult('1 && 0', 0);
+ $this->assertResult('0 && 0', 0);
+ $this->assertResult('2.2 && 1', 1);
+ $this->assertResult('x && y', 1);
+ }
+
+
+ public function testOrOperatorIsValid() {
+ $expression = $this->parser->parse('1 || 1');
+ $this->assertNotNull($expression);
+ }
+
+ public function testNumberExpressionWithOrOperator() {
+ $this->assertResult('1 || 1', 1);
+ $this->assertResult('1 || 0', 1);
+ $this->assertResult('0 || 0', 0);
+ $this->assertResult('2.2 || 1', 1);
+ $this->assertResult('x || y', 1);
+ }
+
+ public function testNotFunctionIsValid() {
+ $expression = $this->parser->parse('!1');
+ $this->assertNotNull($expression);
+ }
+
+
+ public function testNotOperator() {
+ $this->assertResult('!1', 0);
+ $this->assertResult('!0', 1);
+ $this->assertResult('!(0+1)', 0);
+ $this->assertResult('!(!0)', 0);
+
+ $this->assertResult('!(0.1)', 0);
+ $this->assertResult('!x', 0);
+ $this->assertResult('!(x+y)', 0);
+
+ }
+
+
+ public function testGreaterOperatorValidSyntax() {
+ $expression = $this->parser->parse('3 > 1');
+ $this->assertNotNull($expression);
+ }
+
+ public function testGreaterOperator() {
+ $this->assertResult('3 > 1', 1);
+ $this->assertResult('1 > 3', 0);
+ $this->assertResult('1.1 > 3', 0);
+ $this->assertResult('3.1 > 3', 1);
+ $this->assertResult('x > y', 0);
+ }
+
+
+ public function testGreaterOrEqualOperatorValidSyntax() {
+ $expression = $this->parser->parse('3 >= 1');
+ $this->assertNotNull($expression);
+ }
+
+ public function testGreaterOrEqualOperator() {
+ $this->assertResult('3 >= 1', 1);
+ $this->assertResult('1 >= 3', 0);
+ $this->assertResult('3 >= 3', 1);
+ $this->assertResult('3 >= 3.0', 1);
+ $this->assertResult('1.1 >= 3', 0);
+ $this->assertResult('3.1 >= 3', 1);
+ $this->assertResult('x >= y', 0);
+ }
+
+ public function testSmallerOperatorValidSyntax() {
+ $expression = $this->parser->parse('1 < 3');
+ $this->assertNotNull($expression);
+ }
+
+ public function testSmallerOperator() {
+ $this->assertResult('1 < 3', 1);
+ $this->assertResult('3 < 1', 0);
+ $this->assertResult('2 < 1.01', 0);
+ $this->assertResult('x < y', 1);
+
+ }
+
+ public function testSmallerOrEqualOperatorValidSyntax() {
+ $expression = $this->parser->parse('1 <= 3');
+ $this->assertNotNull($expression);
+ }
+
+}
diff --git a/tests/MathParser/Interpreting/EvaluatorTest.php b/tests/MathParser/Interpreting/EvaluatorTest.php
index 0886eed..e93c85d 100644
--- a/tests/MathParser/Interpreting/EvaluatorTest.php
+++ b/tests/MathParser/Interpreting/EvaluatorTest.php
@@ -251,7 +251,7 @@ public function testCanEvaluateFactorial()
$this->assertResult('0!', 1);
$this->assertResult('3!', 6);
$this->assertResult('(3!)!', 720);
- $this->assertResult('5!/(2!3!)', 10);
+ $this->assertResult('5!/(2!*3!)', 10);
$this->assertResult('5!!', 15);
$this->assertApproximateResult('4.12124!', 28.85455491);
}