diff options
author | Fatih Kızmaz <barka_21@hotmail.com> | 2022-05-19 05:03:44 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-19 05:03:44 +0300 |
commit | 3e6700d1576c6582169a5d50c95da106ee3017cf (patch) | |
tree | 66acb56fd05278a6f7ef328a1cc85c2ecfa9a8d2 /src/NXP | |
parent | f71b77a62eb27184b5653d6293250e7fda2fdfef (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/NXP')
-rw-r--r-- | src/NXP/Classes/CustomFunction.php | 22 | ||||
-rw-r--r-- | src/NXP/Classes/Tokenizer.php | 58 | ||||
-rw-r--r-- | src/NXP/MathExecutor.php | 28 |
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 |