StandardCompiler::addBoolean()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 3
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 4
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\Compiler;
9
10
use nicoSWD\Rule\Compiler\Exception\MissingOperatorException;
11
use nicoSWD\Rule\Parser\Exception\ParserException;
12
use nicoSWD\Rule\TokenStream\Token\BaseToken;
13
use nicoSWD\Rule\TokenStream\Token\TokenAnd;
14
use nicoSWD\Rule\TokenStream\Token\TokenOpeningParenthesis;
15
16
class StandardCompiler implements CompilerInterface
17
{
18
    private const BOOL_TRUE = '1';
19
    private const BOOL_FALSE = '0';
20
21
    private const LOGICAL_AND = '&';
22
    private const LOGICAL_OR = '|';
23
24
    private const OPENING_PARENTHESIS = '(';
25
    private const CLOSING_PARENTHESIS = ')';
26
27
    private string $output = '';
28
    private int $openParenthesis = 0;
29
    private int $closedParenthesis = 0;
30
31
    /** @throws ParserException */
32
    public function getCompiledRule(): string
33
    {
34 184
        if ($this->isIncompleteCondition()) {
35
            throw new ParserException('Incomplete condition');
36 184
        } elseif (!$this->numParenthesesMatch()) {
37 4
            throw new ParserException('Missing closing parenthesis');
38 180
        }
39 2
40
        return $this->output;
41
    }
42 178
43
    private function openParenthesis(): void
44
    {
45 20
        $this->openParenthesis++;
46
        $this->output .= self::OPENING_PARENTHESIS;
47 20
    }
48 20
49 20
    /** @throws ParserException */
50
    private function closeParenthesis(): void
51 20
    {
52
        if ($this->openParenthesis < 1) {
53 20
            throw new ParserException('Missing opening parenthesis');
54 2
        }
55
56
        $this->closedParenthesis++;
57 18
        $this->output .= self::CLOSING_PARENTHESIS;
58 18
    }
59 18
60
    /** @throws ParserException */
61 22
    public function addParentheses(BaseToken $token): void
62
    {
63 22
        if ($token instanceof TokenOpeningParenthesis) {
64 20
            if (!$this->expectOpeningParenthesis()) {
65 4
                throw ParserException::unexpectedToken($token);
66
            }
67 20
            $this->openParenthesis();
68
        } else {
69 20
            $this->closeParenthesis();
70
        }
71 20
    }
72
73 36
    /** @throws ParserException */
74
    public function addLogical(BaseToken $token): void
75 36
    {
76
        $lastChar = $this->getLastChar();
77 36
78 2
        if ($lastChar === self::LOGICAL_AND || $lastChar === self::LOGICAL_OR) {
79
            throw ParserException::unexpectedToken($token);
80
        }
81 36
82 34
        if ($token instanceof TokenAnd) {
83
            $this->output .= self::LOGICAL_AND;
84 14
        } else {
85
            $this->output .= self::LOGICAL_OR;
86 36
        }
87
    }
88 196
89
    /** @throws MissingOperatorException */
90 196
    public function addBoolean(bool $bool): void
91
    {
92 196
        $lastChar = $this->getLastChar();
93 2
94
        if ($lastChar === self::BOOL_TRUE || $lastChar === self::BOOL_FALSE) {
95
            throw new MissingOperatorException();
96 196
        }
97 196
98
        $this->output .= $bool ? self::BOOL_TRUE : self::BOOL_FALSE;
99 180
    }
100
101 180
    private function numParenthesesMatch(): bool
102
    {
103
        return $this->openParenthesis === $this->closedParenthesis;
104 184
    }
105
106 184
    private function isIncompleteCondition(): bool
107
    {
108
        $lastChar = $this->getLastChar();
109 184
110 184
        return
111
            $lastChar === self::LOGICAL_AND ||
112
            $lastChar === self::LOGICAL_OR;
113
    }
114 20
115
    private function expectOpeningParenthesis(): bool
116 20
    {
117
        $lastChar = $this->getLastChar();
118
119 20
        return
120 18
            $lastChar === '' ||
121 12
            $lastChar === self::LOGICAL_AND ||
122 20
            $lastChar === self::LOGICAL_OR ||
123
            $lastChar === self::OPENING_PARENTHESIS;
124
    }
125
126 198
    private function getLastChar(): string
127
    {
128 198
        return substr($this->output, offset: -1);
129
    }
130
}
131