Passed
Pull Request — master (#20)
by Nico
14:59 queued 06:31
created

Parser::handleValueToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
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\Parser;
9
10
use Closure;
11
use nicoSWD\Rule\Compiler\CompilerFactoryInterface;
12
use nicoSWD\Rule\Compiler\CompilerInterface;
13
use nicoSWD\Rule\Expression\ExpressionFactoryInterface;
14
use nicoSWD\Rule\TokenStream\AST;
15
use nicoSWD\Rule\TokenStream\Token\BaseToken;
16
use nicoSWD\Rule\TokenStream\Token\TokenType;
17
18
class Parser
19
{
20
    private ?BaseToken $operator;
21
    private array $values = [];
22
23
    public function __construct(
24
        private AST $ast,
25
        private ExpressionFactoryInterface $expressionFactory,
26
        private CompilerFactoryInterface $compilerFactory
27
    ) {
28
    }
29
30
    public function parse(string $rule): string
31
    {
32
        $compiler = $this->compilerFactory->create();
33 278
        $this->resetState();
34
35
        foreach ($this->ast->getStream($rule) as $token) {
36
            $handler = $this->getHandlerForType($token->getType());
37
            $handler($token, $compiler);
38 278
39 278
            if ($this->expressionCanBeEvaluated()) {
40 278
                $this->evaluateExpression($compiler);
41 278
            }
42
        }
43 278
44
        return $compiler->getCompiledRule();
45 278
    }
46 278
47
    private function getHandlerForType(int $tokenType): Closure
48 278
    {
49 206
        return match ($tokenType) {
50 206
            TokenType::VALUE, TokenType::INT_VALUE => $this->handleValueToken(),
51
            TokenType::OPERATOR => $this->handleOperatorToken(),
52 204
            TokenType::LOGICAL => $this->handleLogicalToken(),
53 200
            TokenType::PARENTHESIS => $this->handleParenthesisToken(),
54
            TokenType::COMMENT, TokenType::SPACE => $this->handleDummyToken(),
55
            default => $this->handleUnknownToken(),
56
        };
57 182
    }
58
59
    private function evaluateExpression(CompilerInterface $compiler): void
60 206
    {
61
        $expression = $this->expressionFactory->createFromOperator($this->operator);
62 206
63 206
        $compiler->addBoolean(
64 206
            $expression->evaluate(...$this->values)
65 206
        );
66 206
67 206
        $this->resetState();
68 206
    }
69 206
70 206
    private function expressionCanBeEvaluated(): bool
71 206
    {
72
        return count($this->values) === 2;
73
    }
74
75 206
    private function handleValueToken(): Closure
76
    {
77
        return fn (BaseToken $token) => $this->values[] = $token->getValue();
78 196
    }
79
80 196
    private function handleLogicalToken(): Closure
81
    {
82 196
        return fn (BaseToken $token, CompilerInterface $compiler) => $compiler->addLogical($token);
83 196
    }
84
85
    private function handleParenthesisToken(): Closure
86 194
    {
87 194
        return fn (BaseToken $token, CompilerInterface $compiler) => $compiler->addParentheses($token);
88
    }
89 204
90
    private function handleUnknownToken(): Closure
91 204
    {
92
        return fn (BaseToken $token) => throw Exception\ParserException::unknownToken($token);
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_THROW on line 92 at column 40
Loading history...
93
    }
94 206
95
    private function handleOperatorToken(): Closure
96
    {
97 200
        return function (BaseToken $token): void {
98 206
            if (isset($this->operator)) {
99
                throw Exception\ParserException::unexpectedToken($token);
100
            } elseif (empty($this->values)) {
101 206
                throw Exception\ParserException::incompleteExpression($token);
102
            }
103
104 200
            $this->operator = $token;
105 2
        };
106 200
    }
107 2
108
    private function handleDummyToken(): Closure
109
    {
110 198
        return function (): void {
111 206
            // Do nothing
112
        };
113
    }
114 206
115
    private function resetState(): void
116
    {
117 38
        $this->operator = null;
118 206
        $this->values = [];
119
    }
120
}
121