ValuePathParser::eatSeparator()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 2
nc 2
nop 0
crap 2
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/entity project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\Entity\Path;
10
11
use Daikon\Interop\Assertion;
12
use JMS\Parser\AbstractParser;
13
use JMS\Parser\SimpleLexer;
14
15
final class ValuePathParser extends AbstractParser
16
{
17
    private const T_ATTRIBUTE = 1;
18
19
    private const T_POSITION = 2;
20
21
    private const T_COMPONENT_SEP = 3;
22
23
    private const T_PART_SEP = 4;
24
25
    private const TOKEN_REGEX = <<<REGEX
26
/
27
    # type identifier which refers to an attribute
28
    ([a-zA-Z_]+)
29
30
    # value position
31
    |(\d+)
32
33
    # value-path-component separator. the two components of a value-path-part being attribute and position.
34
    |(\.)
35
36
    # value-path separator
37
    |(\-)
38
/x
39
REGEX;
40
41
    private const TOKEN_MAP = [
42
        0 => 'T_UNKNOWN',
43
        1 => 'T_ATTRIBUTE',
44
        2 => 'T_POSITION',
45
        3 => 'T_PART_SEP'
46
    ];
47
48 14
    public static function create(): ValuePathParser
49
    {
50 14
        $mapToken = function (string $token): array {
51 6
            switch ($token) {
52 6
                case '.':
53 4
                    return [ self::T_COMPONENT_SEP, $token ];
54 6
                case '-':
55 4
                    return [ self::T_PART_SEP, $token ];
56
                default:
57 6
                    return is_numeric($token)
58 5
                        ? [ self::T_POSITION, (int)$token ]
59 6
                        : [ self::T_ATTRIBUTE, $token ];
60
            }
61 14
        };
62 14
        $lexer = new SimpleLexer(self::TOKEN_REGEX, self::TOKEN_MAP, $mapToken);
63 14
        return new ValuePathParser($lexer);
64
    }
65
66
    /**
67
     * @param string $path
68
     * @param string $context
69
     */
70 6
    public function parse($path, $context = null): ValuePath
71
    {
72 6
        return parent::parse($path, $context);
73
    }
74
75 6
    public function parseInternal(): ValuePath
76
    {
77 6
        $valuePathParts = [];
78 6
        while ($valuePathPart = $this->consume()) {
79 5
            $valuePathParts[] = $valuePathPart;
80
        }
81 5
        return new ValuePath($valuePathParts);
82
    }
83
84 6
    private function consume(): ?ValuePathPart
85
    {
86 6
        $this->eatSeparator();
87 6
        $attribute = $this->parseAttribute();
88 5
        return is_null($attribute) ? null : new ValuePathPart($attribute, $this->parsePosition());
89
    }
90
91 6
    private function eatSeparator(): void
92
    {
93 6
        if ($this->lexer->isNext(self::T_PART_SEP)) {
94 3
            $this->match(self::T_PART_SEP);
95
        }
96 6
    }
97
98 6
    private function parseAttribute(): ?string
99
    {
100 6
        if (!$this->lexer->isNext(self::T_ATTRIBUTE)) {
101 6
            Assertion::null($this->lexer->next, 'Expecting T_TYPE at the beginning of a new path-part.');
102 5
            return null;
103
        }
104 5
        return $this->match(self::T_ATTRIBUTE);
105
    }
106
107 5
    private function parsePosition(): int
108
    {
109 5
        if ($this->lexer->isNext(self::T_COMPONENT_SEP)) {
110 4
            $this->match(self::T_COMPONENT_SEP);
111 4
            return $this->match(self::T_POSITION);
112
        }
113 4
        return -1;
114
    }
115
}
116