Completed
Push — master ( 9cb85d...cd38f5 )
by Nico
10:31
created

Parser   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 6
dl 0
loc 93
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
C parse() 0 32 8
A assignOperator() 0 10 3
B evaluateExpression() 0 24 5
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\Parser;
11
12
use nicoSWD\Rules\Compiler\CompilerInterface;
13
use nicoSWD\Rules\Compiler\CompilerFactoryInterface;
14
use nicoSWD\Rules\Compiler\Exception\MissingOperatorException;
15
use nicoSWD\Rules\Expressions\ExpressionFactoryInterface;
16
use nicoSWD\Rules\Tokens\BaseToken;
17
use nicoSWD\Rules\Tokens\TokenType;
18
use nicoSWD\Rules\TokenStream\AST;
19
use SplStack;
20
21
class Parser
22
{
23
    /** @var AST */
24
    private $ast;
25
26
    /** @var ExpressionFactoryInterface */
27
    private $expressionFactory;
28
29
    /** @var CompilerFactoryInterface */
30
    private $compilerFactory;
31
32
    /** @var null|BaseToken */
33
    private $operator = null;
34
35
    public function __construct(
36
        AST $ast,
37
        ExpressionFactoryInterface $expressionFactory,
38
        CompilerFactoryInterface $compilerFactory
39
    ) {
40
        $this->ast = $ast;
41
        $this->expressionFactory = $expressionFactory;
42
        $this->compilerFactory = $compilerFactory;
43
    }
44
45
    public function parse(string $rule): string
46
    {
47
        $compiler = $this->compilerFactory->create();
48
        $this->operator = null;
49
        $values = new SplStack();
50
51
        foreach ($this->ast->getStream($rule) as $token) {
52
            switch ($token->getType()) {
53
                case TokenType::VALUE:
54
                    $values->push($token->getValue());
55
                    break;
56
                case TokenType::LOGICAL:
57
                    $compiler->addLogical($token);
58
                    continue 2;
59
                case TokenType::PARENTHESIS:
60
                    $compiler->addParentheses($token);
61
                    continue 2;
62
                case TokenType::OPERATOR:
63
                    $this->assignOperator($token, $values);
64
                    continue 2;
65
                case TokenType::COMMENT:
66
                case TokenType::SPACE:
67
                    continue 2;
68
                default:
69
                    throw Exception\ParserException::unknownToken($token);
70
            }
71
72
            $this->evaluateExpression($values, $compiler);
73
        }
74
75
        return $compiler->getCompiledRule();
76
    }
77
78
    private function assignOperator(BaseToken $token, SplStack $values)
79
    {
80
        if (isset($this->operator)) {
81
            throw Exception\ParserException::unexpectedToken($token);
82
        } elseif ($values->isEmpty()) {
83
            throw Exception\ParserException::incompleteExpression($token);
84
        }
85
86
        $this->operator = $token;
87
    }
88
89
    private function evaluateExpression(SplStack $values, CompilerInterface $compiler)
90
    {
91
        if (!isset($this->operator) || $values->count() !== 2) {
92
            return;
93
        }
94
95
        list ($rightValue, $leftValue) = $values;
96
97
        try {
98
            $expression = $this->expressionFactory->createFromOperator($this->operator);
99
100
            $compiler->addBoolean(
101
                $expression->evaluate($leftValue, $rightValue)
102
            );
103
        } catch (MissingOperatorException $e) {
104
            throw new Exception\ParserException('Missing operator');
105
        }
106
107
        do {
108
            $values->pop();
109
        } while (!$values->isEmpty());
110
111
        unset($this->operator);
112
    }
113
}
114