Completed
Push — master ( 76acb2...4e56bc )
by Nico
02:11
created

Parser::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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