From 76307e3f41b5582196e9620c687052f8bb8537cc Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Thu, 22 Nov 2018 21:25:16 -0500 Subject: Fixed parsing for () --- src/NXP/Classes/Lexer.php | 65 +++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php index 82b2c53..1650b80 100644 --- a/src/NXP/Classes/Lexer.php +++ b/src/NXP/Classes/Lexer.php @@ -9,6 +9,7 @@ */ namespace NXP\Classes; + use NXP\Classes\Token\AbstractOperator; use NXP\Classes\Token\InterfaceOperator; use NXP\Classes\Token\TokenComma; @@ -70,52 +71,54 @@ class Lexer if ($token instanceof TokenString) { $output[] = $token; } - if ($token instanceof TokenNumber) { + elseif ($token instanceof TokenNumber) { $output[] = $token; } - if ($token instanceof TokenVariable) { + elseif ($token instanceof TokenVariable) { $output[] = $token; } - if ($token instanceof TokenFunction) { + elseif ($token instanceof TokenFunction) { array_push($stack, $token); } - if ($token instanceof TokenLeftBracket) { + elseif ($token instanceof AbstractOperator) { + // While we have something on the stack + while (($count = count($stack)) > 0 + && ( + // If it is a function + ($stack[$count-1] instanceof TokenFunction) + + || + // Or the operator at the top of the operator stack + // has (left associative and equal precedence) + // or has greater precedence + (($stack[$count-1] instanceof InterfaceOperator) && + ( + ($stack[$count-1]->getAssociation() == AbstractOperator::LEFT_ASSOC && + $token->getPriority() == $stack[$count-1]->getPriority()) + || + ($stack[$count-1]->getPriority() > $token->getPriority()) + ) + ) + ) + + // And not a left bracket + && ( ! ($stack[$count-1] instanceof TokenLeftBracket)) ) { + $output[] = array_pop($stack); + } + array_push($stack, $token); } - if ($token instanceof TokenComma) { - while (($current = array_pop($stack)) && (!$current instanceof TokenLeftBracket)) { - $output[] = $current; - if (empty($stack)) { - throw new IncorrectExpressionException(); - } - } + elseif ($token instanceof TokenLeftBracket) { + array_push($stack, $token); } - if ($token instanceof TokenRightBracket) { - while (($current = array_pop($stack)) && (!$current instanceof TokenLeftBracket)) { + elseif ($token instanceof TokenRightBracket) { + while (($current = array_pop($stack)) && ( ! ($current instanceof TokenLeftBracket))) { $output[] = $current; } if (!empty($stack) && ($stack[count($stack)-1] instanceof TokenFunction)) { $output[] = array_pop($stack); } } - - if ($token instanceof AbstractOperator) { - while ( - count($stack) > 0 && - ($stack[count($stack)-1] instanceof InterfaceOperator) && - (( - $token->getAssociation() == AbstractOperator::LEFT_ASSOC && - $token->getPriority() <= $stack[count($stack)-1]->getPriority() - ) || ( - $token->getAssociation() == AbstractOperator::RIGHT_ASSOC && - $token->getPriority() < $stack[count($stack)-1]->getPriority() - )) - ) { - $output[] = array_pop($stack); - } - - array_push($stack, $token); - } } while (!empty($stack)) { $token = array_pop($stack); -- cgit v1.2.3 From 18b12aeeff34c8ac9a350165ae36f08f4138dc9c Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Thu, 10 Jan 2019 20:18:10 -0500 Subject: sync (#5) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Added simple coc (#37) * Added simple coc * Fix * Replaceable operators (#38) * Updated from NeonXP/MathExecutor * Fixed function in () block issue * Fixing typos in and clarifying documentation. * Syncing from origin (#3) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Allow for operators to be replaced based on regex expression * Fix md typo (#39) * Updated from NeonXP/MathExecutor * Fixed function in () block issue * Fixing typos in and clarifying documentation. * Syncing from origin (#3) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Syncing to origin (#4) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Added simple coc (#37) * Added simple coc * Fix * Replaceable operators (#38) * Updated from NeonXP/MathExecutor * Fixed function in () block issue * Fixing typos in and clarifying documentation. * Syncing from origin (#3) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Allow for operators to be replaced based on regex expression * \\ instead of \ * Update README.md Some small fixes * Fix single quotes parsing (#41) * Fix single quotes parsing Fix e-mails Some small fixes * Mistake in test * More PHP versions * Update README.md Deleted `dev` branch --- .travis.yml | 2 + README.md | 13 +- src/NXP/Classes/Calculator.php | 10 +- src/NXP/Classes/Lexer.php | 262 +++++++++++----------- src/NXP/Classes/Token/AbstractContainerToken.php | 2 +- src/NXP/Classes/Token/AbstractOperator.php | 2 +- src/NXP/Classes/Token/InterfaceFunction.php | 2 +- src/NXP/Classes/Token/InterfaceOperator.php | 2 +- src/NXP/Classes/Token/InterfaceToken.php | 2 +- src/NXP/Classes/Token/TokenComma.php | 2 +- src/NXP/Classes/Token/TokenDegree.php | 2 +- src/NXP/Classes/Token/TokenDivision.php | 2 +- src/NXP/Classes/Token/TokenFunction.php | 2 +- src/NXP/Classes/Token/TokenLeftBracket.php | 2 +- src/NXP/Classes/Token/TokenMinus.php | 2 +- src/NXP/Classes/Token/TokenMultiply.php | 2 +- src/NXP/Classes/Token/TokenNumber.php | 2 +- src/NXP/Classes/Token/TokenPlus.php | 2 +- src/NXP/Classes/Token/TokenRightBracket.php | 2 +- src/NXP/Classes/Token/TokenString.php | 25 --- src/NXP/Classes/Token/TokenStringDoubleQuoted.php | 25 +++ src/NXP/Classes/Token/TokenStringSingleQuoted.php | 26 +++ src/NXP/Classes/Token/TokenVariable.php | 2 +- src/NXP/Classes/TokenFactory.php | 26 ++- src/NXP/Exception/IncorrectBracketsException.php | 2 +- src/NXP/Exception/UnknownVariableException.php | 2 +- src/NXP/MathExecutor.php | 25 ++- tests/MathTest.php | 18 +- 28 files changed, 257 insertions(+), 211 deletions(-) delete mode 100644 src/NXP/Classes/Token/TokenString.php create mode 100644 src/NXP/Classes/Token/TokenStringDoubleQuoted.php create mode 100644 src/NXP/Classes/Token/TokenStringSingleQuoted.php diff --git a/.travis.yml b/.travis.yml index 47d1020..551e6ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,9 @@ language: php php: - 5.6 + - 7.1 - 7.2 + - 7.3 before_script: - wget http://getcomposer.org/composer.phar diff --git a/README.md b/README.md index 6579a23..b86f9c6 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,10 @@ A simple math expressions calculator * Easily extendable ## Install via Composer: -Stable branch ``` composer require "nxp/math-executor" ``` -Dev branch (currently unsupported) -``` -composer require "nxp/math-executor" "dev-dev" -``` - ## Sample usage: ```php require "vendor/autoload.php"; @@ -133,7 +127,7 @@ $executor->setVars([ echo $executor->execute("$var1 + $var2"); ``` ## Division By Zero Support: -By default, the result of division by zero is zero and no error is generated. You have the option to thow a \NXP\Exception\DivisionByZeroException by calling setDivisionByZeroException. +By default, the result of division by zero is zero and no error is generated. You have the option to throw a `\NXP\Exception\DivisionByZeroException` by calling `setDivisionByZeroException`. ```php $executor->setDivisionByZeroException(); @@ -145,7 +139,7 @@ try { ``` ## Unary Minus Operator: -Negative numbers are supported via the unary minus operator, but need to have a space before the minus sign. `-1+ -3` is legal, while '`-1+-3` will produce an error due to the way the parser works. Positive numbers are not explicitly supported as unsigned numbers are assumed positive. +Negative numbers are supported via the unary minus operator, but need to have a space before the minus sign. `-1+ -3` is legal, while `-1+-3` will produce an error due to the way the parser works. Positive numbers are not explicitly supported as unsigned numbers are assumed positive. ## String Support: Expressions can contain double or single quoted strings that are evaluated the same way as PHP evalutes strings as numbers. You can also pass strings to functions. @@ -162,5 +156,4 @@ You can add operators, functions and variables with the public methods in MathEx This will allow you to remove functions and operators if needed, or implement different types more simply. -Also note that you can replace an existing default operator by adding a new operator with the same regular expression string. For example if you just need to redefine TokenPlus, you can just add a new operator with the same regex string, in this case '\+'. - +Also note that you can replace an existing default operator by adding a new operator with the same regular expression string. For example if you just need to redefine TokenPlus, you can just add a new operator with the same regex string, in this case '\\+'. diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php index 253e70c..1ceac84 100644 --- a/src/NXP/Classes/Calculator.php +++ b/src/NXP/Classes/Calculator.php @@ -13,13 +13,14 @@ namespace NXP\Classes; use NXP\Classes\Token\InterfaceOperator; use NXP\Classes\Token\TokenFunction; use NXP\Classes\Token\TokenNumber; -use NXP\Classes\Token\TokenString; +use NXP\Classes\Token\TokenStringSingleQuoted; +use NXP\Classes\Token\TokenStringDoubleQuoted; use NXP\Classes\Token\TokenVariable; use NXP\Exception\IncorrectExpressionException; use NXP\Exception\UnknownVariableException; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class Calculator { @@ -38,7 +39,10 @@ class Calculator if ($token instanceof TokenNumber) { array_push($stack, $token); } - if ($token instanceof TokenString) { + if ($token instanceof TokenStringDoubleQuoted) { + array_push($stack, $token); + } + if ($token instanceof TokenStringSingleQuoted) { array_push($stack, $token); } if ($token instanceof TokenVariable) { diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php index 36eb43c..a511c9b 100644 --- a/src/NXP/Classes/Lexer.php +++ b/src/NXP/Classes/Lexer.php @@ -1,133 +1,129 @@ - - */ -class Lexer -{ - /** - * @var TokenFactory - */ - private $tokenFactory; - - public function __construct($tokenFactory) - { - $this->tokenFactory = $tokenFactory; - } - - /** - * @param string $input Source string of equation - * @return array Tokens stream - * @throws \NXP\Exception\IncorrectExpressionException - */ - public function stringToTokensStream($input) - { - $matches = []; - preg_match_all($this->tokenFactory->getTokenParserRegex(), $input, $matches); - $tokenFactory = $this->tokenFactory; - $tokensStream = array_map( - function ($token) use ($tokenFactory) { - return $tokenFactory->createToken($token); - }, - $matches[0] - ); - - return $tokensStream; - } - - /** - * @param array $tokensStream Tokens stream - * @return array Array of tokens in revers polish notation - * @throws \NXP\Exception\IncorrectExpressionException - */ - public function buildReversePolishNotation($tokensStream) - { - $output = []; - $stack = []; - - foreach ($tokensStream as $token) { - if ($token instanceof TokenString) { - $output[] = $token; - } - elseif ($token instanceof TokenNumber) { - $output[] = $token; - } - elseif ($token instanceof TokenVariable) { - $output[] = $token; - } - elseif ($token instanceof TokenFunction) { - array_push($stack, $token); - } - elseif ($token instanceof AbstractOperator) { - // While we have something on the stack - while (($count = count($stack)) > 0 - && ( - // If it is a function - ($stack[$count-1] instanceof TokenFunction) - - || - // Or the operator at the top of the operator stack - // has (left associative and equal precedence) - // or has greater precedence - (($stack[$count-1] instanceof InterfaceOperator) && - ( - ($stack[$count-1]->getAssociation() == AbstractOperator::LEFT_ASSOC && - $token->getPriority() == $stack[$count-1]->getPriority()) - || - ($stack[$count-1]->getPriority() > $token->getPriority()) - ) - ) - ) - - // And not a left bracket - && ( ! ($stack[$count-1] instanceof TokenLeftBracket)) ) { - $output[] = array_pop($stack); - } - - array_push($stack, $token); - } - elseif ($token instanceof TokenLeftBracket) { - array_push($stack, $token); - } - elseif ($token instanceof TokenRightBracket) { - while (($current = array_pop($stack)) && ( ! ($current instanceof TokenLeftBracket))) { - $output[] = $current; - } - if (!empty($stack) && ($stack[count($stack)-1] instanceof TokenFunction)) { - $output[] = array_pop($stack); - } - } - } - while (!empty($stack)) { - $token = array_pop($stack); - if ($token instanceof TokenLeftBracket || $token instanceof TokenRightBracket) { - throw new IncorrectBracketsException(); - } - $output[] = $token; - } - - return $output; - } -} + + */ +class Lexer +{ + /** + * @var TokenFactory + */ + private $tokenFactory; + + public function __construct($tokenFactory) + { + $this->tokenFactory = $tokenFactory; + } + + /** + * @param string $input Source string of equation + * @return array Tokens stream + */ + public function stringToTokensStream($input) + { + $matches = []; + preg_match_all($this->tokenFactory->getTokenParserRegex(), $input, $matches); + $tokenFactory = $this->tokenFactory; + $tokensStream = array_map( + function ($token) use ($tokenFactory) { + return $tokenFactory->createToken($token); + }, + $matches[0] + ); + + return $tokensStream; + } + + /** + * @param array $tokensStream Tokens stream + * @return array Array of tokens in revers polish notation + * @throws IncorrectBracketsException + */ + public function buildReversePolishNotation($tokensStream) + { + $output = []; + $stack = []; + + foreach ($tokensStream as $token) { + if ($token instanceof TokenStringDoubleQuoted) { + $output[] = $token; + } elseif ($token instanceof TokenStringSingleQuoted) { + $output[] = $token; + } elseif ($token instanceof TokenNumber) { + $output[] = $token; + } elseif ($token instanceof TokenVariable) { + $output[] = $token; + } elseif ($token instanceof TokenFunction) { + array_push($stack, $token); + } elseif ($token instanceof AbstractOperator) { + // While we have something on the stack + while (($count = count($stack)) > 0 + && ( + // If it is a function + ($stack[$count - 1] instanceof TokenFunction) + + || + // Or the operator at the top of the operator stack + // has (left associative and equal precedence) + // or has greater precedence + (($stack[$count - 1] instanceof InterfaceOperator) && + ( + ($stack[$count - 1]->getAssociation() == AbstractOperator::LEFT_ASSOC && + $token->getPriority() == $stack[$count - 1]->getPriority()) + || + ($stack[$count - 1]->getPriority() > $token->getPriority()) + ) + ) + ) + + // And not a left bracket + && (!($stack[$count - 1] instanceof TokenLeftBracket))) { + $output[] = array_pop($stack); + } + + array_push($stack, $token); + } elseif ($token instanceof TokenLeftBracket) { + array_push($stack, $token); + } elseif ($token instanceof TokenRightBracket) { + while (($current = array_pop($stack)) && (!($current instanceof TokenLeftBracket))) { + $output[] = $current; + } + if (!empty($stack) && ($stack[count($stack) - 1] instanceof TokenFunction)) { + $output[] = array_pop($stack); + } + } + } + while (!empty($stack)) { + $token = array_pop($stack); + if ($token instanceof TokenLeftBracket || $token instanceof TokenRightBracket) { + throw new IncorrectBracketsException(); + } + $output[] = $token; + } + + return $output; + } +} diff --git a/src/NXP/Classes/Token/AbstractContainerToken.php b/src/NXP/Classes/Token/AbstractContainerToken.php index 12d49d2..be2da5f 100644 --- a/src/NXP/Classes/Token/AbstractContainerToken.php +++ b/src/NXP/Classes/Token/AbstractContainerToken.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ abstract class AbstractContainerToken implements InterfaceToken { diff --git a/src/NXP/Classes/Token/AbstractOperator.php b/src/NXP/Classes/Token/AbstractOperator.php index 87634d5..8b23ad8 100644 --- a/src/NXP/Classes/Token/AbstractOperator.php +++ b/src/NXP/Classes/Token/AbstractOperator.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ abstract class AbstractOperator implements InterfaceToken, InterfaceOperator { diff --git a/src/NXP/Classes/Token/InterfaceFunction.php b/src/NXP/Classes/Token/InterfaceFunction.php index be867b0..a457d0e 100644 --- a/src/NXP/Classes/Token/InterfaceFunction.php +++ b/src/NXP/Classes/Token/InterfaceFunction.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ interface InterfaceFunction { diff --git a/src/NXP/Classes/Token/InterfaceOperator.php b/src/NXP/Classes/Token/InterfaceOperator.php index da6cdf0..9e3bae1 100644 --- a/src/NXP/Classes/Token/InterfaceOperator.php +++ b/src/NXP/Classes/Token/InterfaceOperator.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ interface InterfaceOperator { diff --git a/src/NXP/Classes/Token/InterfaceToken.php b/src/NXP/Classes/Token/InterfaceToken.php index 86fec91..db07aeb 100644 --- a/src/NXP/Classes/Token/InterfaceToken.php +++ b/src/NXP/Classes/Token/InterfaceToken.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ interface InterfaceToken { diff --git a/src/NXP/Classes/Token/TokenComma.php b/src/NXP/Classes/Token/TokenComma.php index f590e32..6a45595 100644 --- a/src/NXP/Classes/Token/TokenComma.php +++ b/src/NXP/Classes/Token/TokenComma.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenComma implements InterfaceToken { diff --git a/src/NXP/Classes/Token/TokenDegree.php b/src/NXP/Classes/Token/TokenDegree.php index 3eec23d..273183a 100644 --- a/src/NXP/Classes/Token/TokenDegree.php +++ b/src/NXP/Classes/Token/TokenDegree.php @@ -13,7 +13,7 @@ namespace NXP\Classes\Token; use NXP\Exception\IncorrectExpressionException; /** -* @author Alexander Kiryukhin +* @author Alexander Kiryukhin */ class TokenDegree extends AbstractOperator { diff --git a/src/NXP/Classes/Token/TokenDivision.php b/src/NXP/Classes/Token/TokenDivision.php index 9166d34..4a8f8ce 100644 --- a/src/NXP/Classes/Token/TokenDivision.php +++ b/src/NXP/Classes/Token/TokenDivision.php @@ -14,7 +14,7 @@ use NXP\Exception\IncorrectExpressionException; use NXP\Exception\DivisionByZeroException; /** -* @author Alexander Kiryukhin +* @author Alexander Kiryukhin */ class TokenDivision extends AbstractOperator { diff --git a/src/NXP/Classes/Token/TokenFunction.php b/src/NXP/Classes/Token/TokenFunction.php index 2ed8ace..b2866c3 100644 --- a/src/NXP/Classes/Token/TokenFunction.php +++ b/src/NXP/Classes/Token/TokenFunction.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenFunction extends AbstractContainerToken implements InterfaceFunction { diff --git a/src/NXP/Classes/Token/TokenLeftBracket.php b/src/NXP/Classes/Token/TokenLeftBracket.php index 0cfdc1a..08165d8 100644 --- a/src/NXP/Classes/Token/TokenLeftBracket.php +++ b/src/NXP/Classes/Token/TokenLeftBracket.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenLeftBracket implements InterfaceToken { diff --git a/src/NXP/Classes/Token/TokenMinus.php b/src/NXP/Classes/Token/TokenMinus.php index 566c950..ad0b8e5 100644 --- a/src/NXP/Classes/Token/TokenMinus.php +++ b/src/NXP/Classes/Token/TokenMinus.php @@ -13,7 +13,7 @@ namespace NXP\Classes\Token; use NXP\Exception\IncorrectExpressionException; /** -* @author Alexander Kiryukhin +* @author Alexander Kiryukhin */ class TokenMinus extends AbstractOperator { diff --git a/src/NXP/Classes/Token/TokenMultiply.php b/src/NXP/Classes/Token/TokenMultiply.php index 8b173b9..0b1ecfb 100644 --- a/src/NXP/Classes/Token/TokenMultiply.php +++ b/src/NXP/Classes/Token/TokenMultiply.php @@ -13,7 +13,7 @@ namespace NXP\Classes\Token; use NXP\Exception\IncorrectExpressionException; /** -* @author Alexander Kiryukhin +* @author Alexander Kiryukhin */ class TokenMultiply extends AbstractOperator { diff --git a/src/NXP/Classes/Token/TokenNumber.php b/src/NXP/Classes/Token/TokenNumber.php index a7eac57..982e316 100644 --- a/src/NXP/Classes/Token/TokenNumber.php +++ b/src/NXP/Classes/Token/TokenNumber.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenNumber extends AbstractContainerToken { diff --git a/src/NXP/Classes/Token/TokenPlus.php b/src/NXP/Classes/Token/TokenPlus.php index fe5a1d6..a6e5036 100644 --- a/src/NXP/Classes/Token/TokenPlus.php +++ b/src/NXP/Classes/Token/TokenPlus.php @@ -13,7 +13,7 @@ namespace NXP\Classes\Token; use NXP\Exception\IncorrectExpressionException; /** -* @author Alexander Kiryukhin +* @author Alexander Kiryukhin */ class TokenPlus extends AbstractOperator { diff --git a/src/NXP/Classes/Token/TokenRightBracket.php b/src/NXP/Classes/Token/TokenRightBracket.php index c68473a..306ae0b 100644 --- a/src/NXP/Classes/Token/TokenRightBracket.php +++ b/src/NXP/Classes/Token/TokenRightBracket.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenRightBracket implements InterfaceToken { diff --git a/src/NXP/Classes/Token/TokenString.php b/src/NXP/Classes/Token/TokenString.php deleted file mode 100644 index cab0711..0000000 --- a/src/NXP/Classes/Token/TokenString.php +++ /dev/null @@ -1,25 +0,0 @@ - - */ -class TokenString extends AbstractContainerToken -{ - /** - * @return string - */ - public static function getRegex() - { - return '"([^"]|"")*"'; - } -} diff --git a/src/NXP/Classes/Token/TokenStringDoubleQuoted.php b/src/NXP/Classes/Token/TokenStringDoubleQuoted.php new file mode 100644 index 0000000..6cff262 --- /dev/null +++ b/src/NXP/Classes/Token/TokenStringDoubleQuoted.php @@ -0,0 +1,25 @@ + + */ +class TokenStringDoubleQuoted extends AbstractContainerToken +{ + /** + * @return string + */ + public static function getRegex() + { + return '"([^"]|"")*"'; + } +} diff --git a/src/NXP/Classes/Token/TokenStringSingleQuoted.php b/src/NXP/Classes/Token/TokenStringSingleQuoted.php new file mode 100644 index 0000000..7a7ab92 --- /dev/null +++ b/src/NXP/Classes/Token/TokenStringSingleQuoted.php @@ -0,0 +1,26 @@ + + * @author Alexander Kiryukhin + */ +class TokenStringSingleQuoted extends AbstractContainerToken +{ + /** + * @return string + */ + public static function getRegex() + { + return "'([^']|'')*'"; + } +} diff --git a/src/NXP/Classes/Token/TokenVariable.php b/src/NXP/Classes/Token/TokenVariable.php index ccd7c83..a4a820a 100644 --- a/src/NXP/Classes/Token/TokenVariable.php +++ b/src/NXP/Classes/Token/TokenVariable.php @@ -11,7 +11,7 @@ namespace NXP\Classes\Token; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenVariable extends AbstractContainerToken { diff --git a/src/NXP/Classes/TokenFactory.php b/src/NXP/Classes/TokenFactory.php index 778cb59..74b5789 100644 --- a/src/NXP/Classes/TokenFactory.php +++ b/src/NXP/Classes/TokenFactory.php @@ -16,14 +16,15 @@ use NXP\Classes\Token\TokenFunction; use NXP\Classes\Token\TokenLeftBracket; use NXP\Classes\Token\TokenNumber; use NXP\Classes\Token\TokenRightBracket; +use NXP\Classes\Token\TokenStringSingleQuoted; use NXP\Classes\Token\TokenVariable; -use NXP\Classes\Token\TokenString; +use NXP\Classes\Token\TokenStringDoubleQuoted; use NXP\Exception\UnknownFunctionException; use NXP\Exception\UnknownOperatorException; use NXP\Exception\UnknownTokenException; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class TokenFactory { @@ -77,8 +78,9 @@ class TokenFactory /** * Add operator - * @param string $operatorClass - * @throws \NXP\Exception\UnknownOperatorException + * @param string $operatorClass + * @throws UnknownOperatorException + * @throws \ReflectionException */ public function addOperator($operatorClass) { @@ -135,9 +137,10 @@ class TokenFactory } return sprintf( - '/(%s)|(%s)|([%s])|(%s)|(%s)|([%s%s%s])/i', + '/(%s)|(%s)|(%s)|([%s])|(%s)|(%s)|([%s%s%s])/i', TokenNumber::getRegex(), - TokenString::getRegex(), + TokenStringDoubleQuoted::getRegex(), + TokenStringSingleQuoted::getRegex(), $operatorsRegex, TokenFunction::getRegex(), TokenVariable::getRegex(), @@ -148,9 +151,10 @@ class TokenFactory } /** - * @param string $token + * @param string $token * @return InterfaceToken * @throws UnknownTokenException + * @throws UnknownFunctionException */ public function createToken($token) { @@ -167,7 +171,11 @@ class TokenFactory } if ($token[0] == '"') { - return new TokenString(str_replace('"', '', $token)); + return new TokenStringDoubleQuoted(str_replace('"', '', $token)); + } + + if ($token[0] == "'") { + return new TokenStringSingleQuoted(str_replace("'", '', $token)); } if ($token == ',') { @@ -184,7 +192,7 @@ class TokenFactory $regex = sprintf('/%s/i', TokenVariable::getRegex()); if (preg_match($regex, $token)) { - return new TokenVariable(substr($token,1)); + return new TokenVariable(substr($token, 1)); } $regex = sprintf('/%s/i', TokenFunction::getRegex()); diff --git a/src/NXP/Exception/IncorrectBracketsException.php b/src/NXP/Exception/IncorrectBracketsException.php index b3e8315..3b2d2b7 100644 --- a/src/NXP/Exception/IncorrectBracketsException.php +++ b/src/NXP/Exception/IncorrectBracketsException.php @@ -12,7 +12,7 @@ namespace NXP\Exception; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class IncorrectBracketsException extends MathExecutorException { diff --git a/src/NXP/Exception/UnknownVariableException.php b/src/NXP/Exception/UnknownVariableException.php index 8c215db..031a603 100644 --- a/src/NXP/Exception/UnknownVariableException.php +++ b/src/NXP/Exception/UnknownVariableException.php @@ -12,7 +12,7 @@ namespace NXP\Exception; /** - * @author Alexander Kiryukhin + * @author Alexander Kiryukhin */ class UnknownVariableException extends MathExecutorException { diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php index 706f8af..29c6a64 100644 --- a/src/NXP/MathExecutor.php +++ b/src/NXP/MathExecutor.php @@ -13,7 +13,6 @@ namespace NXP; use NXP\Classes\Calculator; use NXP\Classes\Lexer; -use NXP\Classes\Token; use NXP\Classes\TokenFactory; use NXP\Exception\UnknownVariableException; @@ -66,13 +65,13 @@ class MathExecutor /** * Get a specific var * - * @param string $variable + * @param string $variable * @return integer|float * @throws UnknownVariableException */ public function getVar($variable) { - if (! isset($this->variables[$variable])) { + if (!isset($this->variables[$variable])) { throw new UnknownVariableException("Variable ({$variable}) not set"); } @@ -82,9 +81,10 @@ class MathExecutor /** * Add variable to executor * - * @param string $variable + * @param string $variable * @param integer|float $value * @return MathExecutor + * @throws \Exception */ public function setVar($variable, $value) { @@ -100,9 +100,10 @@ class MathExecutor /** * Add variables to executor * - * @param array $variables - * @param bool $clear Clear previous variables + * @param array $variables + * @param bool $clear Clear previous variables * @return MathExecutor + * @throws \Exception */ public function setVars(array $variables, $clear = true) { @@ -120,7 +121,7 @@ class MathExecutor /** * Remove variable from executor * - * @param string $variable + * @param string $variable * @return MathExecutor */ public function removeVar($variable) @@ -143,8 +144,9 @@ class MathExecutor /** * Add operator to executor * - * @param string $operatorClass Class of operator token + * @param string $operatorClass Class of operator token * @return MathExecutor + * @throws Exception\UnknownOperatorException */ public function addOperator($operatorClass) { @@ -166,10 +168,11 @@ class MathExecutor /** * Add function to executor * - * @param string $name Name of function - * @param callable $function Function - * @param int $places Count of arguments + * @param string $name Name of function + * @param callable $function Function + * @param int $places Count of arguments * @return MathExecutor + * @throws \ReflectionException */ public function addFunction($name, $function = null, $places = 1) { diff --git a/tests/MathTest.php b/tests/MathTest.php index 9acdb63..55e0799 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -32,7 +32,7 @@ class MathTest extends \PHPUnit_Framework_TestCase /** @var float $phpResult */ eval('$phpResult = ' . $expression . ';'); - $this->assertEquals($calculator->execute($expression), $phpResult); + $this->assertEquals($calculator->execute($expression), $phpResult, "Expression was: ${expression}"); } /** @@ -138,9 +138,23 @@ class MathTest extends \PHPUnit_Framework_TestCase { $calculator = new MathExecutor(); - $calculator->addFunction('round', function ($arg) { return round($arg); }, 1); + $calculator->addFunction('round', function ($arg) { + return round($arg); + }, 1); /** @var float $phpResult */ eval('$phpResult = round(100/30);'); $this->assertEquals($calculator->execute('round(100/30)'), $phpResult); } + + public function testQuotes() + { + $calculator = new MathExecutor(); + $testString = "some, long. arg; with: different-separators!"; + $calculator->addFunction('test', function ($arg) use ($testString) { + $this->assertEquals($arg, $testString); + return 0; + }, 1); + $calculator->execute('test("' . $testString . '")'); // single quotes + $calculator->execute("test('" . $testString . "')"); // double quotes + } } \ No newline at end of file -- cgit v1.2.3 From 44e2bb192eb1c847741894ef24c8fbe24fe2f15a Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Fri, 11 Jan 2019 23:48:43 -0500 Subject: Fixed function parameter order Corrected $places default value for addFunction to match TokenFactory Added function order test and put expected order first in assertEquals If else blocks in calculator Updated docs --- README.md | 9 ++++----- src/NXP/Classes/Calculator.php | 12 ++++-------- src/NXP/Classes/Token/TokenFunction.php | 4 ++-- src/NXP/MathExecutor.php | 2 +- tests/MathTest.php | 23 +++++++++++++++-------- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index b86f9c6..81d9475 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MathExecutor [![Stories in Ready](https://badge.waffle.io/NeonXP/MathExecutor.png?label=ready&title=Ready)](https://waffle.io/NeonXP/MathExecutor) [![Build Status](https://travis-ci.org/NeonXP/MathExecutor.png?branch=master)](https://travis-ci.org/NeonXP/MathExecutor) -A simple math expressions calculator +# A simple and extensible math expressions calculator ## Features: * Built in support for +, -, *, / and power (^) operators plus () @@ -11,7 +11,7 @@ A simple math expressions calculator * Exceptions on divide by zero, or treat as zero * Unary Minus (e.g. -3) * Pi ($pi) and Euler's number ($e) support to 11 decimal places -* Easily extendable +* Easily extensible ## Install via Composer: ``` @@ -41,10 +41,9 @@ Default functions: Add custom function to executor: ```php -$executor->addFunction('abs', function($arg) { - return abs($arg); -}, 1); +$executor->addFunction('abs', function($arg) {return abs($arg);}); ``` +Function default parameters are not supported at this time. ## Operators: Default operators: `+ - * / ^` diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php index 1ceac84..62dbc17 100644 --- a/src/NXP/Classes/Calculator.php +++ b/src/NXP/Classes/Calculator.php @@ -38,22 +38,18 @@ class Calculator foreach ($tokens as $token) { if ($token instanceof TokenNumber) { array_push($stack, $token); - } - if ($token instanceof TokenStringDoubleQuoted) { + } else if ($token instanceof TokenStringDoubleQuoted) { array_push($stack, $token); - } - if ($token instanceof TokenStringSingleQuoted) { + } else if ($token instanceof TokenStringSingleQuoted) { array_push($stack, $token); - } - if ($token instanceof TokenVariable) { + } else if ($token instanceof TokenVariable) { $variable = $token->getValue(); if (!array_key_exists($variable, $variables)) { throw new UnknownVariableException($variable); } $value = $variables[$variable]; array_push($stack, new TokenNumber($value)); - } - if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) { + } else if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) { array_push($stack, $token->execute($stack)); } } diff --git a/src/NXP/Classes/Token/TokenFunction.php b/src/NXP/Classes/Token/TokenFunction.php index b2866c3..04eae30 100644 --- a/src/NXP/Classes/Token/TokenFunction.php +++ b/src/NXP/Classes/Token/TokenFunction.php @@ -32,9 +32,9 @@ class TokenFunction extends AbstractContainerToken implements InterfaceFunction $args = []; list($places, $function) = $this->value; for ($i = 0; $i < $places; $i++) { - array_push($args, array_pop($stack)->getValue()); + $args[] = array_pop($stack)->getValue(); } - $result = call_user_func_array($function, $args); + $result = call_user_func_array($function, array_reverse($args)); return new TokenNumber($result); } diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php index 29c6a64..6325d35 100644 --- a/src/NXP/MathExecutor.php +++ b/src/NXP/MathExecutor.php @@ -174,7 +174,7 @@ class MathExecutor * @return MathExecutor * @throws \ReflectionException */ - public function addFunction($name, $function = null, $places = 1) + public function addFunction($name, $function = null, $places = null) { $this->tokenFactory->addFunction($name, $function, $places); diff --git a/tests/MathTest.php b/tests/MathTest.php index 55e0799..20f4d23 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -32,7 +32,7 @@ class MathTest extends \PHPUnit_Framework_TestCase /** @var float $phpResult */ eval('$phpResult = ' . $expression . ';'); - $this->assertEquals($calculator->execute($expression), $phpResult, "Expression was: ${expression}"); + $this->assertEquals($phpResult, $calculator->execute($expression), "Expression was: ${expression}"); } /** @@ -117,7 +117,7 @@ class MathTest extends \PHPUnit_Framework_TestCase public function testZeroDivision() { $calculator = new MathExecutor(); - $this->assertEquals($calculator->execute('10 / 0'), 0); + $this->assertEquals(0, $calculator->execute('10 / 0')); } public function testZeroDivisionException() @@ -131,19 +131,26 @@ class MathTest extends \PHPUnit_Framework_TestCase public function testExponentiation() { $calculator = new MathExecutor(); - $this->assertEquals($calculator->execute('10 ^ 2'), 100); + $this->assertEquals(100, $calculator->execute('10 ^ 2')); } + public function testFunctionParameterOrder() + { + $calculator = new MathExecutor(); + + $calculator->addFunction('concat', function ($arg1, $arg2) {return $arg1.$arg2;}); + $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); + $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); + } + public function testFunction() { $calculator = new MathExecutor(); - $calculator->addFunction('round', function ($arg) { - return round($arg); - }, 1); + $calculator->addFunction('round', function ($arg) {return round($arg);}); /** @var float $phpResult */ eval('$phpResult = round(100/30);'); - $this->assertEquals($calculator->execute('round(100/30)'), $phpResult); + $this->assertEquals($phpResult, $calculator->execute('round(100/30)')); } public function testQuotes() @@ -151,7 +158,7 @@ class MathTest extends \PHPUnit_Framework_TestCase $calculator = new MathExecutor(); $testString = "some, long. arg; with: different-separators!"; $calculator->addFunction('test', function ($arg) use ($testString) { - $this->assertEquals($arg, $testString); + $this->assertEquals($testString, $arg); return 0; }, 1); $calculator->execute('test("' . $testString . '")'); // single quotes -- cgit v1.2.3 From 0437f808f229de08dd980618ac8f90a1ccd9b0c8 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Tue, 15 Jan 2019 18:33:27 -0500 Subject: sync (#6) * Fixed function parameter order (#42) * Fixed parsing for () * sync (#5) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Added simple coc (#37) * Added simple coc * Fix * Replaceable operators (#38) * Updated from NeonXP/MathExecutor * Fixed function in () block issue * Fixing typos in and clarifying documentation. * Syncing from origin (#3) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Allow for operators to be replaced based on regex expression * Fix md typo (#39) * Updated from NeonXP/MathExecutor * Fixed function in () block issue * Fixing typos in and clarifying documentation. * Syncing from origin (#3) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Syncing to origin (#4) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Added simple coc (#37) * Added simple coc * Fix * Replaceable operators (#38) * Updated from NeonXP/MathExecutor * Fixed function in () block issue * Fixing typos in and clarifying documentation. * Syncing from origin (#3) * Documentation fixes (#34) Fixing typos in and clarifying documentation. * MathExecutor allow override default operators, functions and vars (#36) * Allow for operators to be replaced based on regex expression * \\ instead of \ * Update README.md Some small fixes * Fix single quotes parsing (#41) * Fix single quotes parsing Fix e-mails Some small fixes * Mistake in test * More PHP versions * Update README.md Deleted `dev` branch * Fixed function parameter order Corrected $places default value for addFunction to match TokenFactory Added function order test and put expected order first in assertEquals If else blocks in calculator Updated docs * Create code-of-conduct.ru.md * Update code-of-conduct.ru.md --- code-of-conduct.ru.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 code-of-conduct.ru.md diff --git a/code-of-conduct.ru.md b/code-of-conduct.ru.md new file mode 100644 index 0000000..04a566f --- /dev/null +++ b/code-of-conduct.ru.md @@ -0,0 +1,5 @@ +# Кодекс поведения + +Нам всё равно, кто ты в реальной жизни, просто будь профессионалом и всё будет хорошо. + +Если ты будешь вести себя как сволочь - не удивляйся, что и к тебе будут относиться так же. -- cgit v1.2.3 From 265cff175eb1c0be4b59d937286059532361820f Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Tue, 15 Jan 2019 18:36:10 -0500 Subject: Fixed function parameter order Corrected $places default value for addFunction to match TokenFactory Added function order test and put expected order first in assertEquals If else blocks in calculator Updated docs --- tests/MathTest.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/MathTest.php b/tests/MathTest.php index 8eb7827..81f0230 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -138,7 +138,11 @@ class MathTest extends \PHPUnit_Framework_TestCase { $calculator = new MathExecutor(); - $calculator->addFunction('concat', function ($arg1, $arg2) {return $arg1.$arg2;}); + $calculator->addFunction('concat', function ($arg1, $arg2) + { + return $arg1.$arg2; + } + ); $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); } @@ -147,19 +151,19 @@ class MathTest extends \PHPUnit_Framework_TestCase { $calculator = new MathExecutor(); $calculator->addFunction('round', function ($arg) {return round($arg);}); - /** @var float $phpResult */ - eval('$phpResult = round(100/30);'); - $this->assertEquals($phpResult, $calculator->execute('round(100/30)')); + $this->assertEquals(round(100/30), $calculator->execute('round(100/30)')); } public function testQuotes() { $calculator = new MathExecutor(); $testString = "some, long. arg; with: different-separators!"; - $calculator->addFunction('test', function ($arg) use ($testString) { - $this->assertEquals($testString, $arg); - return 0;} - ); + $calculator->addFunction('test', function ($arg) use ($testString) + { + $this->assertEquals($testString, $arg); + return 0; + } + ); $calculator->execute('test("' . $testString . '")'); // single quotes $calculator->execute("test('" . $testString . "')"); // double quotes } -- cgit v1.2.3 From 47df3edbb6c437a049deee356db84f58edcba681 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Tue, 15 Jan 2019 20:04:16 -0500 Subject: Fixed comma operator Added unit tests for expressions in function arguments. Changed array_push to $var[] = native code. --- src/NXP/Classes/Calculator.php | 12 +++------ src/NXP/Classes/Lexer.php | 9 ++++--- src/NXP/Classes/Token/TokenComma.php | 30 ++++++++++++++++++++- src/NXP/Classes/Token/TokenFunction.php | 5 ++-- tests/MathTest.php | 48 ++++++++++++++++++++++----------- 5 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php index 62dbc17..980a52b 100644 --- a/src/NXP/Classes/Calculator.php +++ b/src/NXP/Classes/Calculator.php @@ -36,21 +36,17 @@ class Calculator { $stack = []; foreach ($tokens as $token) { - if ($token instanceof TokenNumber) { - array_push($stack, $token); - } else if ($token instanceof TokenStringDoubleQuoted) { - array_push($stack, $token); - } else if ($token instanceof TokenStringSingleQuoted) { - array_push($stack, $token); + if ($token instanceof TokenNumber || $token instanceof TokenStringDoubleQuoted || $token instanceof TokenStringSingleQuoted) { + $stack[] = $token; } else if ($token instanceof TokenVariable) { $variable = $token->getValue(); if (!array_key_exists($variable, $variables)) { throw new UnknownVariableException($variable); } $value = $variables[$variable]; - array_push($stack, new TokenNumber($value)); + $stack[] = new TokenNumber($value); } else if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) { - array_push($stack, $token->execute($stack)); + $stack[] = $token->execute($stack); } } $result = array_pop($stack); diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php index a511c9b..898d8c1 100644 --- a/src/NXP/Classes/Lexer.php +++ b/src/NXP/Classes/Lexer.php @@ -77,7 +77,7 @@ class Lexer } elseif ($token instanceof TokenVariable) { $output[] = $token; } elseif ($token instanceof TokenFunction) { - array_push($stack, $token); + $stack[] = $token; } elseif ($token instanceof AbstractOperator) { // While we have something on the stack while (($count = count($stack)) > 0 @@ -104,9 +104,12 @@ class Lexer $output[] = array_pop($stack); } - array_push($stack, $token); + // Comma operators do nothing really, don't put them on the stack + if (! ($token instanceof TokenComma)) { + $stack[] = $token; + } } elseif ($token instanceof TokenLeftBracket) { - array_push($stack, $token); + $stack[] = $token; } elseif ($token instanceof TokenRightBracket) { while (($current = array_pop($stack)) && (!($current instanceof TokenLeftBracket))) { $output[] = $current; diff --git a/src/NXP/Classes/Token/TokenComma.php b/src/NXP/Classes/Token/TokenComma.php index 6a45595..9d997e1 100644 --- a/src/NXP/Classes/Token/TokenComma.php +++ b/src/NXP/Classes/Token/TokenComma.php @@ -13,7 +13,7 @@ namespace NXP\Classes\Token; /** * @author Alexander Kiryukhin */ -class TokenComma implements InterfaceToken +class TokenComma extends AbstractOperator { /** * @return string @@ -22,4 +22,32 @@ class TokenComma implements InterfaceToken { return '\,'; } + + /** + * Comma operator is lowest priority + * + * @return int + */ + public function getPriority() + { + return 0; + } + + /** + * @return string + */ + public function getAssociation() + { + return self::RIGHT_RIGHT; + } + + /** + * @param array $stack + * @return TokenNumber + */ + public function execute(&$stack) + { + // Comma operators don't do anything, stack has already executed + } + } diff --git a/src/NXP/Classes/Token/TokenFunction.php b/src/NXP/Classes/Token/TokenFunction.php index 04eae30..432f107 100644 --- a/src/NXP/Classes/Token/TokenFunction.php +++ b/src/NXP/Classes/Token/TokenFunction.php @@ -32,9 +32,10 @@ class TokenFunction extends AbstractContainerToken implements InterfaceFunction $args = []; list($places, $function) = $this->value; for ($i = 0; $i < $places; $i++) { - $args[] = array_pop($stack)->getValue(); + array_unshift($args, array_pop($stack)->getValue()); } - $result = call_user_func_array($function, array_reverse($args)); + + $result = call_user_func_array($function, $args); return new TokenNumber($result); } diff --git a/tests/MathTest.php b/tests/MathTest.php index 81f0230..5bb2ec0 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -135,17 +135,17 @@ class MathTest extends \PHPUnit_Framework_TestCase } public function testFunctionParameterOrder() - { - $calculator = new MathExecutor(); - - $calculator->addFunction('concat', function ($arg1, $arg2) - { - return $arg1.$arg2; - } - ); - $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); - $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); - } + { + $calculator = new MathExecutor(); + + $calculator->addFunction('concat', function ($arg1, $arg2) + { + return $arg1.$arg2; + } + ); + $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); + $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); + } public function testFunction() { @@ -154,17 +154,33 @@ class MathTest extends \PHPUnit_Framework_TestCase $this->assertEquals(round(100/30), $calculator->execute('round(100/30)')); } + public function testEvaluateFunctionParameters() + { + $calculator = new MathExecutor(); + $calculator->addFunction('round', function ($value, $decimals) + { + return round($value, $decimals); + } + ); + $expression = 'round(100 * 1.111111, 2)'; + eval('$phpResult = ' . $expression . ';'); + $this->assertEquals($phpResult, $calculator->execute($expression)); + $expression = 'round((100*0.04)+(((100*1.02)+0.5)*1.28),2)'; + eval('$phpResult = ' . $expression . ';'); + $this->assertEquals($phpResult, $calculator->execute($expression)); + } + public function testQuotes() { $calculator = new MathExecutor(); $testString = "some, long. arg; with: different-separators!"; $calculator->addFunction('test', function ($arg) use ($testString) - { - $this->assertEquals($testString, $arg); + { + $this->assertEquals($testString, $arg); return 0; - } - ); + } + ); $calculator->execute('test("' . $testString . '")'); // single quotes $calculator->execute("test('" . $testString . "')"); // double quotes } -} \ No newline at end of file +} -- cgit v1.2.3 From 2e847d6b8144ceabe95a5b369d5c2bc720770fc8 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Tue, 15 Jan 2019 20:12:24 -0500 Subject: Fixed merge error --- tests/MathTest.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/MathTest.php b/tests/MathTest.php index 09168c2..3cf4dbd 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -138,24 +138,11 @@ class MathTest extends \PHPUnit_Framework_TestCase { $calculator = new MathExecutor(); - $calculator->addFunction('concat', function ($arg1, $arg2) - { - return $arg1.$arg2; - } - ); + $calculator->addFunction('concat', function ($arg1, $arg2) {return $arg1.$arg2;}); $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); } - public function testFunctionParameterOrder() - { - $calculator = new MathExecutor(); - - $calculator->addFunction('concat', function ($arg1, $arg2) {return $arg1.$arg2;}); - $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); - $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); - } - public function testFunction() { $calculator = new MathExecutor(); -- cgit v1.2.3 From e1b770d6c884d79b8c3c6226d2e6cc8cc5a633ca Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Tue, 15 Jan 2019 20:51:21 -0500 Subject: Fixed typo in constant --- src/NXP/Classes/Token/TokenComma.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NXP/Classes/Token/TokenComma.php b/src/NXP/Classes/Token/TokenComma.php index 9d997e1..f6fc068 100644 --- a/src/NXP/Classes/Token/TokenComma.php +++ b/src/NXP/Classes/Token/TokenComma.php @@ -38,7 +38,7 @@ class TokenComma extends AbstractOperator */ public function getAssociation() { - return self::RIGHT_RIGHT; + return self::LEFT_ASSOC; } /** -- cgit v1.2.3