Completed
Push — master ( 8cec06...5dae2f )
by Nico
01:28
created

Parser::parse()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 26
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 18
cts 18
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 19
nc 7
nop 1
crap 7
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\Rule\Parser;
11
12
use nicoSWD\Rule\Compiler\CompilerInterface;
13
use nicoSWD\Rule\Compiler\CompilerFactoryInterface;
14
use nicoSWD\Rule\Compiler\Exception\MissingOperatorException;
15
use nicoSWD\Rule\Expression\ExpressionFactoryInterface;
16
use nicoSWD\Rule\TokenStream\AST;
17
use nicoSWD\Rule\TokenStream\Token\BaseToken;
18
use SplStack;
19
20
class Parser
21
{
22
    /** @var AST */
23
    private $ast;
24
    /** @var ExpressionFactoryInterface */
25
    private $expressionFactory;
26
    /** @var CompilerFactoryInterface */
27
    private $compilerFactory;
28
    /** @var null|BaseToken */
29
    private $operator = null;
30
31 220
    public function __construct(
32
        AST $ast,
33
        ExpressionFactoryInterface $expressionFactory,
34
        CompilerFactoryInterface $compilerFactory
35
    ) {
36 220
        $this->ast = $ast;
37 220
        $this->expressionFactory = $expressionFactory;
38 220
        $this->compilerFactory = $compilerFactory;
39 220
    }
40
41 220
    public function parse(string $rule): string
42
    {
43 220
        $compiler = $this->compilerFactory->create();
44 220
        $this->operator = null;
45 220
        $values = new SplStack();
46
47 220
        foreach ($this->ast->getStream($rule) as $token) {
48 186
            if ($token->isValue()) {
49 180
                $values->push($token->getValue());
50 186
            } elseif ($token->isWhitespace()) {
51 182
                continue;
52 182
            } elseif ($token->isOperator()) {
53 180
                $this->assignOperator($token, $values);
54 48
            } elseif ($token->isLogical()) {
55 38
                $compiler->addLogical($token);
56 30
            } elseif ($token->isParenthesis()) {
57 24
                $compiler->addParentheses($token);
58
            } else {
59 6
                throw Exception\ParserException::unknownToken($token);
60
            }
61
62 180
            $this->evaluateExpression($values, $compiler);
63
        }
64
65 162
        return $compiler->getCompiledRule();
66
    }
67
68 180
    private function assignOperator(BaseToken $token, SplStack $values)
69
    {
70 180
        if (isset($this->operator)) {
71 2
            throw Exception\ParserException::unexpectedToken($token);
72 180
        } elseif ($values->isEmpty()) {
73 2
            throw Exception\ParserException::incompleteExpression($token);
74
        }
75
76 178
        $this->operator = $token;
77 178
    }
78
79 180
    private function evaluateExpression(SplStack $values, CompilerInterface $compiler)
80
    {
81 180
        if (!isset($this->operator) || $values->count() !== 2) {
82 180
            return;
83
        }
84
85 176
        list($rightValue, $leftValue) = $values;
86
87
        try {
88 176
            $expression = $this->expressionFactory->createFromOperator($this->operator);
89
90 176
            $compiler->addBoolean(
91 176
                $expression->evaluate($leftValue, $rightValue)
92
            );
93 4
        } catch (MissingOperatorException $e) {
94 2
            throw new Exception\ParserException('Missing operator');
95
        }
96
97
        do {
98 174
            $values->pop();
99 174
        } while (!$values->isEmpty());
100
101 174
        unset($this->operator);
102 174
    }
103
}
104