aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFatih Kızmaz <barka_21@hotmail.com>2022-05-19 05:03:44 +0300
committerGitHub <noreply@github.com>2022-05-19 05:03:44 +0300
commit3e6700d1576c6582169a5d50c95da106ee3017cf (patch)
tree66acb56fd05278a6f7ef328a1cc85c2ecfa9a8d2 /src
parentf71b77a62eb27184b5653d6293250e7fda2fdfef (diff)
Added ability to escape quotes in strings. (#110)
* Added ability to escape quotes in strings. * Removed type checking for customfunc arguments. It was a bad idea to check types, because php automatically tries to convert a parameter to required type and throws if it failures. On the other hand, we can check types also in callables if required. * Update phpdoc * Fix some typos + improve min, max, avg funcs. * Update readme + improvements. * Fix a typo in sample. * Fix unshown backslash in readme.
Diffstat (limited to 'src')
-rw-r--r--src/NXP/Classes/CustomFunction.php22
-rw-r--r--src/NXP/Classes/Tokenizer.php58
-rw-r--r--src/NXP/MathExecutor.php28
3 files changed, 68 insertions, 40 deletions
diff --git a/src/NXP/Classes/CustomFunction.php b/src/NXP/Classes/CustomFunction.php
index 1ebdd2c..6e9ffc5 100644
--- a/src/NXP/Classes/CustomFunction.php
+++ b/src/NXP/Classes/CustomFunction.php
@@ -2,7 +2,6 @@
namespace NXP\Classes;
-use NXP\Exception\IncorrectFunctionParameterException;
use NXP\Exception\IncorrectNumberOfFunctionParametersException;
use ReflectionException;
use ReflectionFunction;
@@ -16,7 +15,7 @@ class CustomFunction
*/
public $function;
- private ReflectionFunction $reflectionFunction;
+ private int $requiredParamCount;
/**
* CustomFunction constructor.
@@ -27,36 +26,25 @@ class CustomFunction
{
$this->name = $name;
$this->function = $function;
- $this->reflectionFunction = new ReflectionFunction($function);
+ $this->requiredParamCount = (new ReflectionFunction($function))->getNumberOfRequiredParameters();
}
/**
* @param array<Token> $stack
*
- * @throws IncorrectNumberOfFunctionParametersException|IncorrectFunctionParameterException
+ * @throws IncorrectNumberOfFunctionParametersException
*/
public function execute(array &$stack, int $paramCountInStack) : Token
{
- if ($paramCountInStack < $this->reflectionFunction->getNumberOfRequiredParameters()) {
+ if ($paramCountInStack < $this->requiredParamCount) {
throw new IncorrectNumberOfFunctionParametersException($this->name);
}
$args = [];
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);
+ \array_unshift($args, \array_pop($stack)->value);
}
}
diff --git a/src/NXP/Classes/Tokenizer.php b/src/NXP/Classes/Tokenizer.php
index c8b415d..af041c1 100644
--- a/src/NXP/Classes/Tokenizer.php
+++ b/src/NXP/Classes/Tokenizer.php
@@ -50,27 +50,67 @@ class Tokenizer
public function tokenize() : self
{
- foreach (\str_split($this->input, 1) as $ch) {
+ $isLastCharEscape = false;
+
+ foreach (\str_split($this->input) as $ch) {
switch (true) {
case $this->inSingleQuotedString:
- if ("'" === $ch) {
- $this->tokens[] = new Token(Token::String, $this->stringBuffer);
- $this->inSingleQuotedString = false;
- $this->stringBuffer = '';
+ if ('\\' === $ch) {
+ if ($isLastCharEscape) {
+ $this->stringBuffer .= '\\';
+ $isLastCharEscape = false;
+ } else {
+ $isLastCharEscape = true;
+ }
+
+ continue 2;
+ } elseif ("'" === $ch) {
+ if ($isLastCharEscape) {
+ $this->stringBuffer .= "'";
+ $isLastCharEscape = false;
+ } else {
+ $this->tokens[] = new Token(Token::String, $this->stringBuffer);
+ $this->inSingleQuotedString = false;
+ $this->stringBuffer = '';
+ }
continue 2;
}
+
+ if ($isLastCharEscape) {
+ $this->stringBuffer .= '\\';
+ $isLastCharEscape = false;
+ }
$this->stringBuffer .= $ch;
continue 2;
case $this->inDoubleQuotedString:
- if ('"' === $ch) {
- $this->tokens[] = new Token(Token::String, $this->stringBuffer);
- $this->inDoubleQuotedString = false;
- $this->stringBuffer = '';
+ if ('\\' === $ch) {
+ if ($isLastCharEscape) {
+ $this->stringBuffer .= '\\';
+ $isLastCharEscape = false;
+ } else {
+ $isLastCharEscape = true;
+ }
continue 2;
+ } elseif ('"' === $ch) {
+ if ($isLastCharEscape) {
+ $this->stringBuffer .= '"';
+ $isLastCharEscape = false;
+ } else {
+ $this->tokens[] = new Token(Token::String, $this->stringBuffer);
+ $this->inDoubleQuotedString = false;
+ $this->stringBuffer = '';
+ }
+
+ continue 2;
+ }
+
+ if ($isLastCharEscape) {
+ $this->stringBuffer .= '\\';
+ $isLastCharEscape = false;
}
$this->stringBuffer .= $ch;
diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php
index dd90e22..1e1cd2d 100644
--- a/src/NXP/MathExecutor.php
+++ b/src/NXP/MathExecutor.php
@@ -16,7 +16,6 @@ use NXP\Classes\Operator;
use NXP\Classes\Token;
use NXP\Classes\Tokenizer;
use NXP\Exception\DivisionByZeroException;
-use NXP\Exception\IncorrectNumberOfFunctionParametersException;
use NXP\Exception\MathExecutorException;
use NXP\Exception\UnknownVariableException;
use ReflectionException;
@@ -386,19 +385,21 @@ class MathExecutor
'arccos' => static fn($arg) => \acos($arg),
'arctan' => static fn($arg) => \atan($arg),
'arctg' => static fn($arg) => \atan($arg),
+ 'array' => static fn(...$args) => $args,
'asin' => static fn($arg) => \asin($arg),
'atan' => static fn($arg) => \atan($arg),
'atan2' => static fn($arg1, $arg2) => \atan2($arg1, $arg2),
'atanh' => static fn($arg) => \atanh($arg),
'atn' => static fn($arg) => \atan($arg),
- 'avg' => static function($arg1, $args) {
+ 'avg' => static function($arg1, ...$args) {
if (\is_array($arg1)){
+ if (0 === \count($arg1)){
+ throw new \InvalidArgumentException('Array must contain at least one element!');
+ }
+
return \array_sum($arg1) / \count($arg1);
}
- if (0 === \count($args)){
- throw new IncorrectNumberOfFunctionParametersException();
- }
$args = [$arg1, ...$args];
return \array_sum($args) / \count($args);
@@ -444,18 +445,18 @@ class MathExecutor
'log10' => static fn($arg) => \log10($arg),
'log1p' => static fn($arg) => \log1p($arg),
'max' => static function($arg1, ...$args) {
- if (! \is_array($arg1) && 0 === \count($args)){
- throw new IncorrectNumberOfFunctionParametersException();
+ if (\is_array($arg1) && 0 === \count($arg1)){
+ throw new \InvalidArgumentException('Array must contain at least one element!');
}
- return \max($arg1, ...$args);
+ return \max(\is_array($arg1) ? $arg1 : [$arg1, ...$args]);
},
'min' => static function($arg1, ...$args) {
- if (! \is_array($arg1) && 0 === \count($args)){
- throw new IncorrectNumberOfFunctionParametersException();
+ if (\is_array($arg1) && 0 === \count($arg1)){
+ throw new \InvalidArgumentException('Array must contain at least one element!');
}
- return \min($arg1, ...$args);
+ return \min(\is_array($arg1) ? $arg1 : [$arg1, ...$args]);
},
'octdec' => static fn($arg) => \octdec($arg),
'pi' => static fn() => M_PI,
@@ -469,8 +470,7 @@ class MathExecutor
'tan' => static fn($arg) => \tan($arg),
'tanh' => static fn($arg) => \tanh($arg),
'tn' => static fn($arg) => \tan($arg),
- 'tg' => static fn($arg) => \tan($arg),
- 'array' => static fn(...$args) => [...$args]
+ 'tg' => static fn($arg) => \tan($arg)
];
}
@@ -488,7 +488,7 @@ class MathExecutor
}
/**
- * Default variable validation, ensures that the value is a scalar.
+ * Default variable validation, ensures that the value is a scalar or array.
* @throws MathExecutorException if the value is not a scalar
*/
protected function defaultVarValidation(string $variable, $value) : void