From a4849cbcc5402f3dd00965abe44df3239341bae8 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Fri, 16 Aug 2019 14:01:53 -0400 Subject: Subtraction fix (#46) (#7) * Updated unit tests * Fixed docs * Better unary minus support --- src/NXP/Classes/Lexer.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src/NXP') diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php index 898d8c1..73c25ac 100644 --- a/src/NXP/Classes/Lexer.php +++ b/src/NXP/Classes/Lexer.php @@ -15,11 +15,12 @@ use NXP\Classes\Token\InterfaceOperator; use NXP\Classes\Token\TokenComma; use NXP\Classes\Token\TokenFunction; use NXP\Classes\Token\TokenLeftBracket; +use NXP\Classes\Token\TokenMinus; use NXP\Classes\Token\TokenNumber; use NXP\Classes\Token\TokenRightBracket; +use NXP\Classes\Token\TokenStringDoubleQuoted; use NXP\Classes\Token\TokenStringSingleQuoted; use NXP\Classes\Token\TokenVariable; -use NXP\Classes\Token\TokenStringDoubleQuoted; use NXP\Exception\IncorrectBracketsException; use NXP\Exception\IncorrectExpressionException; @@ -66,6 +67,7 @@ class Lexer { $output = []; $stack = []; + $lastToken = null; foreach ($tokensStream as $token) { if ($token instanceof TokenStringDoubleQuoted) { @@ -73,7 +75,20 @@ class Lexer } elseif ($token instanceof TokenStringSingleQuoted) { $output[] = $token; } elseif ($token instanceof TokenNumber) { - $output[] = $token; + // if the number starts with a minus sign, it could be a negative number, or it could be an operator grabbed by the greedy regex + // if previous token is an operator, then it negative, otherwise remove the minus sign and put a negative operator on the stack + if ($lastToken !== null) { + $value = (int)$token->getValue(); + if ($value < 0 && ! ($lastToken instanceof AbstractOperator)) { + $token = new TokenNumber(abs($value)); + $output[] = $token; + $output[] = new TokenMinus('-'); + } else { + $output[] = $token; + } + } else { + $output[] = $token; + } } elseif ($token instanceof TokenVariable) { $output[] = $token; } elseif ($token instanceof TokenFunction) { @@ -118,6 +133,7 @@ class Lexer $output[] = array_pop($stack); } } + $lastToken = $token; } while (!empty($stack)) { $token = array_pop($stack); -- cgit v1.2.3 From 84f3f967b71fc39bf61be13e46c89158ad0a34a9 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Wed, 27 Nov 2019 11:39:51 -0500 Subject: Update README.md and more function support --- README.md | 67 ++++++++++++++--- src/NXP/Classes/Token/TokenNotEqual.php | 53 ++++++++++++++ src/NXP/Classes/Token/TokenUnequal.php | 53 -------------- src/NXP/MathExecutor.php | 123 ++++++++++++++++++++++++++++---- tests/MathTest.php | 38 +++++++++- 5 files changed, 254 insertions(+), 80 deletions(-) create mode 100644 src/NXP/Classes/Token/TokenNotEqual.php delete mode 100644 src/NXP/Classes/Token/TokenUnequal.php (limited to 'src/NXP') diff --git a/README.md b/README.md index 7238a0b..7e0573b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ ## Features: * Built in support for +, -, *, / and power (^) operators plus () +* Logical operators (==, !=, <, <, >=, <=, &&, ||) +* Built in support for most PHP math functions +* Conditional If logic * Support for user defined operators * Support for user defined functions * Unlimited variable name lengths @@ -20,24 +23,54 @@ composer require "nxp/math-executor" ## Sample usage: ```php -require "vendor/autoload.php"; +require 'vendor/autoload.php'; $executor = new \NXP\MathExecutor(); -echo $executor->execute("1 + 2 * (2 - (4+10))^2 + sin(10)"); +echo $executor->execute('1 + 2 * (2 - (4+10))^2 + sin(10)'); ``` ## Functions: Default functions: -* sin -* cos -* tn -* asin +* abs * acos -* atn -* min -* max +* acosh +* asin +* atan (atn) +* atan2 +* atanh * avg +* bindec +* ceil +* cos +* cosh +* decbin +* dechex +* decoct +* deg2rad +* exp +* expm1 +* floor +* fmod +* hexdec +* hypot +* if +* intdiv +* log +* log10 +* log1p +* max +* min +* octdec +* pi +* pow +* rad2deg +* round +* sin +* sinh +* sqrt +* tan (tn) +* tanh Add custom function to executor: ```php @@ -75,7 +108,7 @@ class ModulusToken extends AbstractOperator */ public function getPriority() { - return 3; + return 180; } /** @@ -109,6 +142,18 @@ And adding to executor: $executor->addOperator('MyNamespace\ModulusToken'); ``` +## Logical operators: +Logical operators (==, !=, <, <, >=, <=, &&, ||) are supported, but logically they can only return true (1) or false (0). In order to leverage them, use the built in **if** function: + +``` +if($a > $b, $a - $b, $b - $a) +``` + +You can think of the **if** function as prototyped like: + +``` +function if($condition, $returnIfTrue, $returnIfFalse) +``` ## Variables: Default variables: @@ -161,4 +206,4 @@ Also note that you can replace an existing default operator by adding a new oper ## Future Enhancements -At some point this package will be upgraded to a currently supported version of PHP. +This package will continue to track currently supported versions of PHP. We recommend you keep PHP up-to-date. Currently the code will run under 5.6, but don't expect 5.6 support going forward. diff --git a/src/NXP/Classes/Token/TokenNotEqual.php b/src/NXP/Classes/Token/TokenNotEqual.php new file mode 100644 index 0000000..21c9454 --- /dev/null +++ b/src/NXP/Classes/Token/TokenNotEqual.php @@ -0,0 +1,53 @@ +getValue() != $op2->getValue(); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenUnequal.php b/src/NXP/Classes/Token/TokenUnequal.php deleted file mode 100644 index c8c5d1a..0000000 --- a/src/NXP/Classes/Token/TokenUnequal.php +++ /dev/null @@ -1,53 +0,0 @@ -getValue() != $op2->getValue(); - - return new TokenNumber($result); - } -} diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php index 2a5f9fb..5de7dc5 100644 --- a/src/NXP/MathExecutor.php +++ b/src/NXP/MathExecutor.php @@ -267,7 +267,7 @@ class MathExecutor 'NXP\Classes\Token\TokenAnd', 'NXP\Classes\Token\TokenOr', 'NXP\Classes\Token\TokenEqual', - 'NXP\Classes\Token\TokenUnequal', + 'NXP\Classes\Token\TokenNotEqual', 'NXP\Classes\Token\TokenGreaterThanOrEqual', 'NXP\Classes\Token\TokenGreaterThan', 'NXP\Classes\Token\TokenLessThanOrEqual', @@ -278,33 +278,75 @@ class MathExecutor protected function defaultFunctions() { return [ - 'sin' => function ($arg) { - return sin($arg); + 'abs' => function ($arg) { + return abs($arg); }, - 'cos' => function ($arg) { - return cos($arg); + 'acos' => function ($arg) { + return acos($arg); }, - 'tn' => function ($arg) { - return tan($arg); + 'acosh' => function ($arg) { + return acosh($arg); }, 'asin' => function ($arg) { return asin($arg); }, - 'acos' => function ($arg) { - return acos($arg); - }, - 'atn' => function ($arg) { + 'atan' => function ($arg) { return atan($arg); }, - 'min' => function ($arg1, $arg2) { - return min($arg1, $arg2); + 'atan2' => function ($arg1, $arg2) { + return atan2($arg1, $arg2); }, - 'max' => function ($arg1, $arg2) { - return max($arg1, $arg2); + 'atanh' => function ($arg) { + return atanh($arg); + }, + 'atn' => function ($arg) { + return atan($arg); }, 'avg' => function ($arg1, $arg2) { return ($arg1 + $arg2) / 2; }, + 'bindec' => function ($arg) { + return bindec($arg); + }, + 'ceil' => function ($arg) { + return ceil($arg); + }, + 'cos' => function ($arg) { + return cos($arg); + }, + 'cosh' => function ($arg) { + return cosh($arg); + }, + 'decbin' => function ($arg) { + return decbin($arg); + }, + 'dechex' => function ($arg) { + return dechex($arg); + }, + 'decoct' => function ($arg) { + return decoct($arg); + }, + 'deg2rad' => function ($arg) { + return deg2rad($arg); + }, + 'exp' => function ($arg) { + return exp($arg); + }, + 'expm1' => function ($arg) { + return expm1($arg); + }, + 'floor' => function ($arg) { + return floor($arg); + }, + 'fmod' => function ($arg1, $arg2) { + return fmod($arg1, $arg2); + }, + 'hexdec' => function ($arg) { + return hexdec($arg); + }, + 'hypot' => function ($arg1, $arg2) { + return hypot($arg1, $arg2); + }, 'if' => function ($expr, $trueval, $falseval) { if ($expr === true || $expr === false) { $exres = $expr; @@ -316,6 +358,57 @@ class MathExecutor } else { return $this->execute($falseval); } + }, + 'intdiv' => function ($arg1, $arg2) { + return intdiv($arg1, $arg2); + }, + 'log' => function ($arg) { + return log($arg); + }, + 'log10' => function ($arg) { + return log10($arg); + }, + 'log1p' => function ($arg) { + return log1p($arg); + }, + 'max' => function ($arg1, $arg2) { + return max($arg1, $arg2); + }, + 'min' => function ($arg1, $arg2) { + return min($arg1, $arg2); + }, + 'octdec' => function ($arg) { + return octdec($arg); + }, + 'pi' => function () { + return pi(); + }, + 'pow' => function ($arg1, $arg2) { + return pow($arg1, $arg2); + }, + 'rad2deg' => function ($arg) { + return rad2deg($arg); + }, + 'round' => function ($arg) { + return round($arg); + }, + 'sin' => function ($arg) { + return sin($arg); + }, + 'sinh' => function ($arg) { + return sinh($arg); + }, + 'sqrt' => function ($arg) { + return sqrt($arg); + }, + 'tan' => function ($arg) { + return tan($arg); + }, + 'tanh' => function ($arg) { + return tanh($arg); + }, + 'tn' => function ($arg) { + return tan($arg); } ]; } diff --git a/tests/MathTest.php b/tests/MathTest.php index 90cdccf..27817db 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -50,7 +50,43 @@ class MathTest extends \PHPUnit\Framework\TestCase ['4*-5'], ['4 * -5'], - [cos(2)], + ['abs(1.5)'], + ['acos(0.15)'], + ['acosh(1.5)'], + ['asin(0.15)'], + ['atan(0.15)'], + ['atan2(1.5, 3.5)'], + ['atanh(0.15)'], + ['bindec("10101")'], + ['ceil(1.5)'], + ['cos(1.5)'], + ['cosh(1.5)'], + ['decbin("15")'], + ['dechex("15")'], + ['decoct("15")'], + ['deg2rad(1.5)'], + ['exp(1.5)'], + ['expm1(1.5)'], + ['floor(1.5)'], + ['fmod(1.5, 3.5)'], + ['hexdec("abcdef")'], + ['hypot(1.5, 3.5)'], + ['intdiv(10, 2)'], + ['log(1.5)'], + ['log10(1.5)'], + ['log1p(1.5)'], + ['max(1.5, 3.5)'], + ['min(1.5, 3.5)'], + ['octdec(1.5)'], + ['pi()'], + ['pow(1.5, 3.5)'], + ['rad2deg(1.5)'], + ['round(1.5)'], + ['sin(1.5)'], + ['sinh(1.5)'], + ['sqrt(1.5)'], + ['tan(1.5)'], + ['tanh(1.5)'], ['0.1 + 0.2'], ['1 + 2'], -- cgit v1.2.3 From 2db48eff956f5a63513685cb5b576b588c698912 Mon Sep 17 00:00:00 2001 From: Bruce Wells Date: Sat, 30 Nov 2019 18:41:36 -0500 Subject: PHP 7.4 support --- .travis.yml | 1 + README.md | 2 -- src/NXP/MathExecutor.php | 4 ++-- tests/MathTest.php | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/NXP') diff --git a/.travis.yml b/.travis.yml index 3a63f2f..a471c3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 7.1 - 7.2 - 7.3 + - 7.4 before_script: - wget http://getcomposer.org/composer.phar diff --git a/README.md b/README.md index 7e0573b..18da2fd 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,6 @@ $executor->addFunction('abs', function($arg) {return abs($arg);}); ``` Function default parameters are not supported at this time. -Default parameters are not currently supported. - ## Operators: Default operators: `+ - * / ^` diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php index 5de7dc5..9d3f5e8 100644 --- a/src/NXP/MathExecutor.php +++ b/src/NXP/MathExecutor.php @@ -365,7 +365,7 @@ class MathExecutor 'log' => function ($arg) { return log($arg); }, - 'log10' => function ($arg) { + 'log10' => function ($arg) { return log10($arg); }, 'log1p' => function ($arg) { @@ -401,7 +401,7 @@ class MathExecutor 'sqrt' => function ($arg) { return sqrt($arg); }, - 'tan' => function ($arg) { + 'tan' => function ($arg) { return tan($arg); }, 'tanh' => function ($arg) { diff --git a/tests/MathTest.php b/tests/MathTest.php index 27817db..391408e 100644 --- a/tests/MathTest.php +++ b/tests/MathTest.php @@ -73,11 +73,11 @@ class MathTest extends \PHPUnit\Framework\TestCase ['hypot(1.5, 3.5)'], ['intdiv(10, 2)'], ['log(1.5)'], - ['log10(1.5)'], + ['log10(1.5)'], ['log1p(1.5)'], ['max(1.5, 3.5)'], ['min(1.5, 3.5)'], - ['octdec(1.5)'], + ['octdec("15")'], ['pi()'], ['pow(1.5, 3.5)'], ['rad2deg(1.5)'], @@ -85,7 +85,7 @@ class MathTest extends \PHPUnit\Framework\TestCase ['sin(1.5)'], ['sinh(1.5)'], ['sqrt(1.5)'], - ['tan(1.5)'], + ['tan(1.5)'], ['tanh(1.5)'], ['0.1 + 0.2'], -- cgit v1.2.3