Completed
Pull Request — master (#9)
by Dmitrii
14:33 queued 13:18
created

AST::getMethod()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 2
dl 0
loc 12
ccs 6
cts 6
cp 1
crap 3
rs 9.8666
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/**
4
 * @license     http://opensource.org/licenses/mit-license.php MIT
5
 * @link        https://github.com/nicoSWD
6
 * @author      Nicolas Oelgart <[email protected]>
7
 */
8
namespace nicoSWD\Rule\TokenStream;
9
10
use Closure;
11
use InvalidArgumentException;
12
use nicoSWD\Rule\Grammar\CallableUserFunctionInterface;
13
use nicoSWD\Rule\TokenStream\Exception\UndefinedVariableException;
14
use nicoSWD\Rule\TokenStream\Token\BaseToken;
15
use nicoSWD\Rule\TokenStream\Token\TokenFactory;
16
use nicoSWD\Rule\Tokenizer\TokenizerInterface;
17
18
class AST
19
{
20
    /** @var TokenizerInterface */
21
    private $tokenizer;
22
    /** @var TokenFactory */
23
    private $tokenFactory;
24
    /** @var TokenStreamFactory */
25
    private $tokenStreamFactory;
26
    /** @var Closure[] */
27
    private $functions = [];
28
    /** @var string[] */
29
    private $methods = [];
30
    /** @var mixed[] */
31
    private $variables = [];
32
    /** @var callable|null */
33
    private $variableCallback;
34
35 226
    public function __construct(
36
        TokenizerInterface $tokenizer,
37
        TokenFactory $tokenFactory,
38
        TokenStreamFactory $tokenStreamFactory
39
    ) {
40 226
        $this->tokenizer = $tokenizer;
41 226
        $this->tokenFactory = $tokenFactory;
42 226
        $this->tokenStreamFactory = $tokenStreamFactory;
43 226
    }
44
45 220
    public function getStream(string $rule): TokenStream
46
    {
47 220
        return $this->tokenStreamFactory->create($this->tokenizer->tokenize($rule), $this);
48
    }
49
50 108
    public function getMethod(string $methodName, BaseToken $token): CallableUserFunctionInterface
51
    {
52 108
        if (empty($this->methods)) {
53 108
            $this->registerMethods();
54
        }
55
56 108
        if (!isset($this->methods[$methodName])) {
57 4
            throw new Exception\UndefinedMethodException($methodName);
58
        }
59
60 104
        return new $this->methods[$methodName]($token);
61
    }
62
63 108
    private function registerMethods()
64
    {
65 108
        $this->methods = $this->tokenizer->getGrammar()->getInternalMethods();
66 108
    }
67
68 220
    public function setVariables(array $variables)
69
    {
70 220
        $this->variables = $variables;
71 220
    }
72
73 220
    public function registerVariableCallback(callable $callback = null)
74
    {
75 220
        $this->variableCallback = $callback;
76 220
    }
77
78 92
    public function getVariable(string $variableName): BaseToken
79
    {
80 92
        if ($this->variableExists($variableName)) {
81 86
            return $this->tokenFactory->createFromPHPType($this->variables[$variableName]);
82
        }
83 6
        if (is_callable($this->variableCallback)) {
84
            try {
85 2
                $value = call_user_func($this->variableCallback, $variableName);
86 2
                return $this->tokenFactory->createFromPHPType($value);
87
            } catch (\Throwable $e) {
88
                throw new UndefinedVariableException($variableName, $e->getCode(), $e);
89
            }
90
        }
91 4
        throw new UndefinedVariableException($variableName);
92
    }
93
94 92
    public function variableExists(string $variableName): bool
95
    {
96 92
        return array_key_exists($variableName, $this->variables);
97
    }
98
99 32
    public function getFunction(string $functionName): Closure
100
    {
101 32
        if (empty($this->functions)) {
102 32
            $this->registerFunctions();
103
        }
104
105 32
        if (!isset($this->functions[$functionName])) {
106 6
            throw new Exception\UndefinedFunctionException($functionName);
107
        }
108
109 26
        return $this->functions[$functionName];
110
    }
111
112
    private function registerFunctionClass(string $functionName, string $className)
113
    {
114 26
        $this->functions[$functionName] = function (BaseToken ...$args) use ($className): BaseToken {
115 26
            $function = new $className();
116
117 26
            if (!$function instanceof CallableUserFunctionInterface) {
118 2
                throw new InvalidArgumentException(
119 2
                    sprintf(
120 2
                        "%s must be an instance of %s",
121 1
                        $className,
122 2
                        CallableUserFunctionInterface::class
123
                    )
124
                );
125
            }
126
127 24
            return $function->call(...$args);
0 ignored issues
show
Documentation introduced by
$args is of type array<integer,object<nic...tream\Token\BaseToken>>, but the function expects a null|object<nicoSWD\Rule...Stream\Token\BaseToken>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
128
        };
129 30
    }
130
131 32
    private function registerFunctions()
132
    {
133 32
        foreach ($this->tokenizer->getGrammar()->getInternalFunctions() as $functionName => $className) {
134 30
            $this->registerFunctionClass($functionName, $className);
135
        }
136 32
    }
137
}
138