Completed
Push — master ( e5de66...386907 )
by Nico
02:02
created

Parser::getFunction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
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\Expressions\ExpressionFactory;
13
use nicoSWD\Rules\Tokens\BaseToken;
14
use SplStack;
15
16
class Parser
17
{
18
    /** @var AST */
19
    private $ast;
20
21
    /** @var ExpressionFactory */
22
    private $expressionFactory;
23
24
    /** @var Compiler */
25
    private $compiler;
26
27
    /** @var null|BaseToken */
28
    private $operator = null;
29
30
    /** @var SplStack */
31
    private $values;
32
33 224
    public function __construct(AST $ast, ExpressionFactory $expressionFactory, Compiler $compiler)
34
    {
35 224
        $this->ast = $ast;
36 224
        $this->expressionFactory = $expressionFactory;
37 224
        $this->compiler = $compiler;
38 224
        $this->values = new SplStack();
39 224
    }
40
41 220
    public function parse(string $rule): string
42
    {
43 220
        $this->compiler->clear();
44 220
        $this->operator = null;
45
46 220
        foreach ($this->ast->getStream($rule) as $token) {
47 182
            switch ($token->getType()) {
48 182
                case TokenType::VALUE:
49 178
                    $this->assignVariableValueFromToken($token);
50 178
                    break;
51 182
                case TokenType::LOGICAL:
52 36
                    $this->compiler->addLogical($token);
53 36
                    continue 2;
54 182
                case TokenType::PARENTHESIS:
55 22
                    $this->compiler->addParentheses($token);
56 20
                    continue 2;
57 182
                case TokenType::OPERATOR:
58 178
                    $this->assignOperator($token);
59 176
                    continue 2;
60 180
                case TokenType::COMMENT:
61 180
                case TokenType::SPACE:
62 178
                    continue 2;
63
                default:
64 6
                    throw Exceptions\ParserException::unknownToken($token);
65
            }
66
67 178
            $this->evaluateExpression();
68
        }
69
70 160
        return $this->compiler->getCompiledRule();
71
    }
72
73 178
    private function assignVariableValueFromToken(BaseToken $token)
74
    {
75 178
        $this->compiler->flipOperatorRequired($token);
76 178
        $this->values->push($token->getValue());
77 178
    }
78
79 178
    private function assignOperator(BaseToken $token)
80
    {
81 178
        if (isset($this->operator)) {
82 2
            throw Exceptions\ParserException::unexpectedToken($token);
83 178
        } elseif ($this->values->isEmpty()) {
84 2
            throw Exceptions\ParserException::incompleteExpression($token);
85
        }
86
87 176
        $this->compiler->operatorRequired(false);
88 176
        $this->operator = $token;
89 176
    }
90
91 178
    private function evaluateExpression()
92
    {
93 178
        if (!isset($this->operator) || $this->values->count() !== 2) {
94 178
            return;
95
        }
96
97 174
        list ($rightValue, $leftValue) = $this->values;
98
99 174
        $this->compiler->addBoolean($this->getExpression()->evaluate($leftValue, $rightValue));
100 172
        $this->values->pop();
101 172
        $this->values->pop();
102
103 172
        unset($this->operator);
104 172
    }
105
106 174
    private function getExpression(): Expressions\BaseExpression
107
    {
108 174
        return $this->expressionFactory->createFromOperator($this->operator);
0 ignored issues
show
Bug introduced by
It seems like $this->operator can be null; however, createFromOperator() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
109
    }
110
}
111