Completed
Push — master ( 386907...166bd7 )
by Nico
01:52
created

Compiler::closeParentheses()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @license     http://opensource.org/licenses/mit-license.php MIT
7
 * @link        https://github.com/nicoSWD
8
 * @author      Nicolas Oelgart <[email protected]>
9
 */
10
namespace nicoSWD\Rules;
11
12
use nicoSWD\Rules\Tokens\BaseToken;
13
use nicoSWD\Rules\Tokens\TokenOpeningParenthesis;
14
15
class Compiler
16
{
17
    const BOOL_TRUE = '1';
18
    const BOOL_FALSE = '0';
19
20
    const LOGICAL_AND = '&';
21
    const LOGICAL_OR = '|';
22
23
    const OPENING_PARENTHESIS = '(';
24
    const CLOSING_PARENTHESIS = ')';
25
26
    private $output = '';
27
    private $openParenthesis = 0;
28
    private $closedParenthesis = 0;
29
30 220
    public function clear()
31
    {
32 220
        $this->output = '';
33 220
    }
34
35 160
    public function getCompiledRule()
36
    {
37 160
        if ($this->isIncompleteCondition()) {
38 4
            throw new Exceptions\ParserException('Incomplete condition');
39 156
        } elseif (!$this->numParenthesesMatch()) {
40 2
            throw new Exceptions\ParserException('Missing closing parenthesis');
41
        }
42
43 154
        return $this->output;
44
    }
45
46 20
    private function openParenthesis()
47
    {
48 20
        $this->openParenthesis++;
49 20
        $this->output .= self::OPENING_PARENTHESIS;
50 20
    }
51
52 20
    private function closeParenthesis(BaseToken $token)
53
    {
54 20
        if ($this->openParenthesis < 1) {
55 2
            throw new Exceptions\ParserException(sprintf(
56 2
                'Missing opening parenthesis at position %d on line %d',
57 2
                $token->getPosition(),
58 2
                $token->getLine()
59
            ));
60
        }
61
62 18
        $this->closedParenthesis++;
63 18
        $this->output .= self::CLOSING_PARENTHESIS;
64 18
    }
65
66 22
    public function addParentheses(BaseToken $token)
67
    {
68 22
        if ($token instanceof Tokens\TokenOpeningParenthesis) {
69 20
            if (!$this->expectOpeningParenthesis()) {
70 4
                throw Exceptions\ParserException::unexpectedToken($token);
71
            }
72 20
            $this->openParenthesis();
73
        } else {
74 20
            $this->closeParenthesis($token);
75
        }
76 20
    }
77
78 36
    public function addLogical(BaseToken $token)
79
    {
80 36
        $lastChar = $this->getLastChar();
81
82 36
        if ($lastChar === self::LOGICAL_AND || $lastChar === self::LOGICAL_OR) {
83 2
            throw Exceptions\ParserException::unexpectedToken($token);
84
        }
85
86 36
        if ($token instanceof Tokens\TokenAnd) {
87 34
            $this->output .= self::LOGICAL_AND;
88
        } else {
89 14
            $this->output .= self::LOGICAL_OR;
90
        }
91 36
    }
92
93 172
    public function addBoolean(bool $bool)
94
    {
95 172
        $lastChar = $this->getLastChar();
96
97 172
        if ($lastChar === self::BOOL_TRUE || $lastChar === self::BOOL_FALSE) {
98 2
            throw new Exceptions\MissingOperatorException();
99
        }
100
101 172
        $this->output .= $bool ? self::BOOL_TRUE : self::BOOL_FALSE;
102 172
    }
103
104 156
    private function numParenthesesMatch(): bool
105
    {
106 156
        return $this->openParenthesis === $this->closedParenthesis;
107
    }
108
109 160
    private function isIncompleteCondition(): bool
110
    {
111 160
        $lastChar = $this->getLastChar();
112
113
        return (
114 160
            $lastChar === self::LOGICAL_AND ||
115 160
            $lastChar === self::LOGICAL_OR
116
        );
117
    }
118
119 20
    private function expectOpeningParenthesis(): bool
120
    {
121 20
        $lastChar = $this->getLastChar();
122
123
        return (
124 20
            $lastChar === '' ||
125 18
            $lastChar === self::LOGICAL_AND ||
126 12
            $lastChar === self::LOGICAL_OR ||
127 20
            $lastChar === self::OPENING_PARENTHESIS
128
        );
129
    }
130
131 174
    private function getLastChar(): string
132
    {
133 174
        return substr($this->output, -1);
134
    }
135
}