Completed
Push — master ( f06ad0...9cb85d )
by Nico
06:26
created

StandardCompiler::addParentheses()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

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