aboutsummaryrefslogtreecommitdiff
path: root/src/NXP/Classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/NXP/Classes')
-rw-r--r--src/NXP/Classes/Calculator.php2
-rw-r--r--src/NXP/Classes/CustomFunction.php36
-rw-r--r--src/NXP/Classes/Token.php2
-rw-r--r--src/NXP/Classes/Tokenizer.php34
4 files changed, 53 insertions, 21 deletions
diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php
index 10adc24..6b63503 100644
--- a/src/NXP/Classes/Calculator.php
+++ b/src/NXP/Classes/Calculator.php
@@ -74,7 +74,7 @@ class Calculator
if (! \array_key_exists($token->value, $this->functions)) {
throw new UnknownFunctionException($token->value);
}
- $stack[] = $this->functions[$token->value]->execute($stack);
+ $stack[] = $this->functions[$token->value]->execute($stack, $token->paramCount);
} elseif (Token::Operator === $token->type) {
if (! \array_key_exists($token->value, $this->operators)) {
throw new UnknownOperatorException($token->value);
diff --git a/src/NXP/Classes/CustomFunction.php b/src/NXP/Classes/CustomFunction.php
index 843cf82..1ebdd2c 100644
--- a/src/NXP/Classes/CustomFunction.php
+++ b/src/NXP/Classes/CustomFunction.php
@@ -2,6 +2,7 @@
namespace NXP\Classes;
+use NXP\Exception\IncorrectFunctionParameterException;
use NXP\Exception\IncorrectNumberOfFunctionParametersException;
use ReflectionException;
use ReflectionFunction;
@@ -15,41 +16,48 @@ class CustomFunction
*/
public $function;
- public int $places = 0;
+ private ReflectionFunction $reflectionFunction;
/**
* CustomFunction constructor.
*
* @throws ReflectionException
- * @throws IncorrectNumberOfFunctionParametersException
*/
- public function __construct(string $name, callable $function, ?int $places = null)
+ public function __construct(string $name, callable $function)
{
$this->name = $name;
$this->function = $function;
+ $this->reflectionFunction = new ReflectionFunction($function);
- if (null === $places) {
- $reflection = new ReflectionFunction($function);
- $this->places = $reflection->getNumberOfParameters();
- } else {
- $this->places = $places;
- }
}
/**
* @param array<Token> $stack
*
- * @throws IncorrectNumberOfFunctionParametersException
+ * @throws IncorrectNumberOfFunctionParametersException|IncorrectFunctionParameterException
*/
- public function execute(array &$stack) : Token
+ public function execute(array &$stack, int $paramCountInStack) : Token
{
- if (\count($stack) < $this->places) {
+ if ($paramCountInStack < $this->reflectionFunction->getNumberOfRequiredParameters()) {
throw new IncorrectNumberOfFunctionParametersException($this->name);
}
$args = [];
- for ($i = 0; $i < $this->places; $i++) {
- \array_unshift($args, \array_pop($stack)->value);
+ if ($paramCountInStack > 0) {
+ $reflectionParameters = $this->reflectionFunction->getParameters();
+
+ for ($i = 0; $i < $paramCountInStack; $i++) {
+ $value = \array_pop($stack)->value;
+ $valueType = \gettype($value);
+ $reflectionParameter = $reflectionParameters[\min(\count($reflectionParameters) - 1, $i)];
+ //TODO to support type check for union types (php >= 8.0) and intersection types (php >= 8.1), we should increase min php level in composer.json
+ // For now, only support basic types. @see testFunctionParameterTypes
+ if ($reflectionParameter->hasType() && $reflectionParameter->getType()->getName() !== $valueType){
+ throw new IncorrectFunctionParameterException();
+ }
+
+ \array_unshift($args, $value);
+ }
}
$result = \call_user_func_array($this->function, $args);
diff --git a/src/NXP/Classes/Token.php b/src/NXP/Classes/Token.php
index e75b17e..7532e77 100644
--- a/src/NXP/Classes/Token.php
+++ b/src/NXP/Classes/Token.php
@@ -28,6 +28,8 @@ class Token
public ?string $name;
+ public ?int $paramCount = null;//to store function parameter count in stack
+
/**
* Token constructor.
*
diff --git a/src/NXP/Classes/Tokenizer.php b/src/NXP/Classes/Tokenizer.php
index 32404a2..23e1cc9 100644
--- a/src/NXP/Classes/Tokenizer.php
+++ b/src/NXP/Classes/Tokenizer.php
@@ -20,7 +20,7 @@ use SplStack;
*/
class Tokenizer
{
- /** @var array<Token> */
+ /** @var array<Token> */
public array $tokens = [];
private string $input = '';
@@ -31,7 +31,7 @@ class Tokenizer
private bool $allowNegative = true;
- /** @var array<Operator> */
+ /** @var array<Operator> */
private array $operators = [];
private bool $inSingleQuotedString = false;
@@ -99,8 +99,8 @@ class Tokenizer
break;
}
- // no break
- // Intentionally fall through
+ // no break
+ // Intentionally fall through
case $this->isAlpha($ch):
if (\strlen($this->numberBuffer)) {
$this->emptyNumberBufferAsLiteral();
@@ -196,8 +196,8 @@ class Tokenizer
}
/**
- * @throws IncorrectBracketsException
* @throws UnknownOperatorException
+ * @throws IncorrectBracketsException
* @return Token[] Array of tokens in revers polish notation
*/
public function buildReversePolishNotation() : array
@@ -205,6 +205,10 @@ class Tokenizer
$tokens = [];
/** @var SplStack<Token> $stack */
$stack = new SplStack();
+ /**
+ * @var SplStack<int> $paramCounter
+ */
+ $paramCounter = new SplStack();
foreach ($this->tokens as $token) {
switch ($token->type) {
@@ -213,9 +217,21 @@ class Tokenizer
case Token::String:
$tokens[] = $token;
+ if ($paramCounter->count() > 0 && 0 === $paramCounter->top()) {
+ $paramCounter->push($paramCounter->pop() + 1);
+ }
+
break;
case Token::Function:
+ if ($paramCounter->count() > 0 && 0 === $paramCounter->top()) {
+ $paramCounter->push($paramCounter->pop() + 1);
+ }
+ $stack->push($token);
+ $paramCounter->push(0);
+
+ break;
+
case Token::LeftParenthesis:
$stack->push($token);
@@ -228,6 +244,7 @@ class Tokenizer
}
$tokens[] = $stack->pop();
}
+ $paramCounter->push($paramCounter->pop() + 1);
break;
@@ -270,7 +287,12 @@ class Tokenizer
}
if ($stack->count() > 0 && Token::Function == $stack->top()->type) {
- $tokens[] = $stack->pop();
+ /**
+ * @var Token $f
+ */
+ $f = $stack->pop();
+ $f->paramCount = $paramCounter->pop();
+ $tokens[] = $f;
}
break;