Skip to content

Commit

Permalink
Full support for arrays => min, max and avg funcs accept array argume…
Browse files Browse the repository at this point in the history
…nt. Also array function is defined which return arguments as array. Square bracket arrays are also supported. (#108)

valid expression -> "max([1,2,3])"
valid expression -> "max(array(1,2,3))"
valid expression -> "max($ages_arr)"
valid expression -> "max(ages_arr())"
  • Loading branch information
fatihkizmaz authored May 16, 2022
1 parent 2874b11 commit 5d6b4a5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 7 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Default functions:
* arcctg (arccot, arccotan)
* arcsec
* arccsc (arccosec)
* array
* asin (arcsin)
* atan (atn, arctan, arctg)
* atan2
Expand Down Expand Up @@ -84,7 +85,10 @@ Add custom function to executor:
```php
$executor->addFunction('abs', function($arg) {return abs($arg);});
```
Function default parameters are not supported at this time.
Function default parameters (optional parameters) are also supported.
```php
$executor->addFunction('round', function($num, int $precision = 0) {return round($num, $precision);});
```

## Operators:
Default operators: `+ - * / ^`
Expand Down Expand Up @@ -139,12 +143,20 @@ $executor->setVar('var1', 0.15)->setVar('var2', 0.22);
echo $executor->execute("$var1 + var2");
```

By default, variables must be scalar values (int, float, bool or string). If you would like to support another type, use **setVarValidationHandler**
Arrays are also supported (as variables, as func params or can be returned in user defined funcs):
```php
$executor->setVar('monthly_salaries', [1800, 1900, 1200, 1600]);

echo $executor->execute("avg(monthly_salaries) * min([1.1, 1.3])");
```


By default, variables must be scalar values (int, float, bool or string) or array. If you would like to support another type, use **setVarValidationHandler**

```php
$executor->setVarValidationHandler(function (string $name, $variable) {
// allow all scalars and null
if (is_scalar($variable) || $variable === null) {
// allow all scalars, array and null
if (is_scalar($variable) || is_array($variable) || $variable === null) {
return;
}
// Allow variables of type DateTime, but not others
Expand Down
11 changes: 9 additions & 2 deletions src/NXP/Classes/Tokenizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ public function tokenize() : self

continue 2;

case '[' === $ch:
$this->tokens[] = new Token(Token::Function, 'array');
$this->allowNegative = true;
$this->tokens[] = new Token(Token::LeftParenthesis, '');

continue 2;

case ' ' == $ch || "\n" == $ch || "\r" == $ch || "\t" == $ch:
$this->tokens[] = new Token(Token::Space, '');

Expand Down Expand Up @@ -140,7 +147,7 @@ public function tokenize() : self

break;

case $this->isRP($ch):
case $this->isRP($ch) || ']' === $ch :
$this->emptyNumberBufferAsLiteral();
$this->emptyStrBufferAsVariable();
$this->allowNegative = false;
Expand Down Expand Up @@ -196,8 +203,8 @@ public function tokenize() : self
}

/**
* @throws UnknownOperatorException
* @throws IncorrectBracketsException
* @throws UnknownOperatorException
* @return Token[] Array of tokens in revers polish notation
*/
public function buildReversePolishNotation() : array
Expand Down
3 changes: 2 additions & 1 deletion src/NXP/MathExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,8 @@ protected function defaultFunctions() : array
'tan' => static fn($arg) => \tan($arg),
'tanh' => static fn($arg) => \tanh($arg),
'tn' => static fn($arg) => \tan($arg),
'tg' => static fn($arg) => \tan($arg)
'tg' => static fn($arg) => \tan($arg),
'array' => static fn(...$args) => [...$args]
];
}

Expand Down
16 changes: 16 additions & 0 deletions tests/MathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,22 @@ public function testExponentiation() : void
$this->assertEquals(100, $calculator->execute('10 ^ 2'));
}

public function testArrays() : void
{
$calculator = new MathExecutor();
$this->assertEquals([1, 5, 2], $calculator->execute('array(1, 5, 2)'));
$this->assertEquals([1, 5, 2], $calculator->execute('[1, 5, 2]'));
$this->assertEquals(\max([1, 5, 2]), $calculator->execute('max([1, 5, 2])'));
$this->assertEquals(\max([1, 5, 2]), $calculator->execute('max(array(1, 5, 2))'));
$calculator->addFunction('arr_with_max_elements', static function($arg1, ...$args) {
$args = \is_array($arg1) ? $arg1 : [$arg1, ...$args];
\usort($args, static fn($arr1, $arr2) => \count($arr2) <=> \count($arr1));

return $args[0];
});
$this->assertEquals([3, 3, 3], $calculator->execute('arr_with_max_elements([[1],array(2,2),[3,3,3]])'));
}

public function testFunctionParameterOrder() : void
{
$calculator = new MathExecutor();
Expand Down

0 comments on commit 5d6b4a5

Please sign in to comment.