Completed
Branch master (8a10e7)
by Nico
08:15 queued 05:53
created

StandardCompiler::getLastChar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
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\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
    const BOOL_TRUE = '1';
19
    const BOOL_FALSE = '0';
20
21
    const LOGICAL_AND = '&';
22
    const LOGICAL_OR = '|';
23
24
    const OPENING_PARENTHESIS = '(';
25
    const CLOSING_PARENTHESIS = ')';
26
27
    /** @var string */
28
    private $output = '';
29
    /** @var int */
30
    private $openParenthesis = 0;
31
    /** @var int */
32
    private $closedParenthesis = 0;
33
34 168
    public function getCompiledRule(): string
35
    {
36 168
        if ($this->isIncompleteCondition()) {
37 4
            throw new ParserException('Incomplete condition');
38 164
        } elseif (!$this->numParenthesesMatch()) {
39 2
            throw new ParserException('Missing closing parenthesis');
40
        }
41
42 162
        return $this->output;
43
    }
44
45 20
    private function openParenthesis(): void
46
    {
47 20
        $this->openParenthesis++;
48 20
        $this->output .= self::OPENING_PARENTHESIS;
49 20
    }
50
51 20
    private function closeParenthesis(): void
52
    {
53 20
        if ($this->openParenthesis < 1) {
54 2
            throw new ParserException('Missing opening parenthesis');
55
        }
56
57 18
        $this->closedParenthesis++;
58 18
        $this->output .= self::CLOSING_PARENTHESIS;
59 18
    }
60
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
    public function addLogical(BaseToken $token): void
74
    {
75 36
        $lastChar = $this->getLastChar();
76
77 36
        if ($lastChar === self::LOGICAL_AND || $lastChar === self::LOGICAL_OR) {
78 2
            throw ParserException::unexpectedToken($token);
79
        }
80
81 36
        if ($token instanceof TokenAnd) {
82 34
            $this->output .= self::LOGICAL_AND;
83
        } else {
84 14
            $this->output .= self::LOGICAL_OR;
85
        }
86 36
    }
87
88 180
    public function addBoolean(bool $bool): void
89
    {
90 180
        $lastChar = $this->getLastChar();
91
92 180
        if ($lastChar === self::BOOL_TRUE || $lastChar === self::BOOL_FALSE) {
93 2
            throw new MissingOperatorException();
94
        }
95
96 180
        $this->output .= $bool ? self::BOOL_TRUE : self::BOOL_FALSE;
97 180
    }
98
99 164
    private function numParenthesesMatch(): bool
100
    {
101 164
        return $this->openParenthesis === $this->closedParenthesis;
102
    }
103
104 168
    private function isIncompleteCondition(): bool
105
    {
106 168
        $lastChar = $this->getLastChar();
107
108
        return (
109 168
            $lastChar === self::LOGICAL_AND ||
110 168
            $lastChar === self::LOGICAL_OR
111
        );
112
    }
113
114 20
    private function expectOpeningParenthesis(): bool
115
    {
116 20
        $lastChar = $this->getLastChar();
117
118
        return (
119 20
            $lastChar === '' ||
120 18
            $lastChar === self::LOGICAL_AND ||
121 12
            $lastChar === self::LOGICAL_OR ||
122 20
            $lastChar === self::OPENING_PARENTHESIS
123
        );
124
    }
125
126 182
    private function getLastChar(): string
127
    {
128 182
        return substr($this->output, -1);
129
    }
130
}
131