Passed
Push — master ( 58d249...3d1488 )
by Maxim
02:52
created

CommentLexer::getPropertyName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is a part of "Axessors" library.
4
 *
5
 * @author <[email protected]>
6
 * @license GPL
7
 */
8
9
namespace NoOne4rever\Axessors;
10
11
/**
12
 * Class CommentLexer.
13
 *
14
 * Splits Axessors comment into array of possible tokens.
15
 * 
16
 * @package NoOne4rever\Axessors
17
 */
18
class CommentLexer extends Lexer
19
{
20
    private const AXS_COMMENT = '{^#>}';
21
    private const ACCESS_MODIFIER = '{^(\+|~|-)}';
22
    private const KEYWORD = '{^((accessi|(writ|read)a)ble|axs|wrt|rdb)}';
23
    private const TYPE = '{^((((\\\\)?[a-zA-Z_][a-zA-Z\d_]*(\\\\[a-zA-Z_][a-zA-Z\d_]*)*)(\[(?1)\])?)(\|(?2))*)}';
24
    private const HANDLERS = '{^((?(1),\s*)([a-zA-Z_][a-zA-Z0-9_]*|`([^`]|\\\\`)+((?<!\\\\)`)))+}';
25
    private const CONDITIONS = '{^((?(1)\s*(&&|\|\|)\s*)(\d+(,\d+)?\.\.\d+(,\d+)?|((<|>|!|=)=|%|<|>)\s+\d+(,\d+)?|`([^`]|\\\\`)+((?<!\\\\)`)))+}';
26
    private const HANDLERS_SIGN = '{^>>}';
27
    private const ALIAS_SIGN = '{^=>}';
28
    private const ALIAS = '{^[a-zA-Z_][a-zA-Z0-9_]*}';
29
30
    private const TOKEN_LIST = [
31
        self::AXS_COMMENT,
32
        self::ACCESS_MODIFIER,
33
        self::KEYWORD,
34
        self::TYPE,
35
        self::CONDITIONS,
36
        self::HANDLERS_SIGN,
37
        self::HANDLERS,
38
        self::ACCESS_MODIFIER,
39
        self::KEYWORD,
40
        self::CONDITIONS,
41
        self::HANDLERS_SIGN,
42
        self::HANDLERS,
43
        self::ALIAS_SIGN,
44
        self::ALIAS
45
    ];
46
    private const REQUIRED_TOKENS = [0, 1, 2];
47
48
    private const AXS_COMMENT_TOKEN = '#>';
49
50
    /**
51
     * Returns class' data with Axessors properties.
52
     * 
53
     * @return ClassData class' data
54
     */
55
    public function getClassData(): ClassData
56
    {
57
        $classData = new ClassData($this->reflection);
58
        for ($i = $this->startLine; $this->isLineEmpty() && $i <= $this->endLine; ++$i) {
59
            $this->readLine();
60
            if (!$this->isAxsPropertyDef()) {
61
                continue;
62
            }
63
            $code = $this->addSlashes($this->getAxsComment());
64
            $propertyData = new PropertyData(
65
                $this->reflection->getProperty($this->getPropertyName()),
66
                $this->parse(
67
                    $code,
68
                    self::TOKEN_LIST,
69
                    self::REQUIRED_TOKENS
70
                )
71
            );
72
            $classData->addProperty($this->getPropertyName(), $propertyData);
73
        }
74
        return $classData;
75
    }
76
77
    /**
78
     * Adds slashes to special symbols in the *injected* string.
79
     * 
80
     * @param string $expr expression to handle
81
     * @return string processed string
82
     */
83
    private function addSlashes(string $expr): string 
84
    {
85
        return preg_replace_callback(
86
            '/`([^`]|\\\\`)+((?<!\\\\)`)/',
87
            function (array $matches): string {
88
                return addcslashes($matches[0], '\\');
89
            },
90
            $expr
91
        );
92
    }
93
94
    /**
95
     * Extracts Axessors comment from the code.
96
     * 
97
     * @return string Axessors comment
98
     */
99
    private function getAxsComment(): string
100
    {
101
        return substr($this->currentLine, strpos($this->currentLine, self::AXS_COMMENT_TOKEN));
102
    }
103
104
    /**
105
     * Extracts property name from the code.
106
     * 
107
     * @return string property name
108
     */
109
    private function getPropertyName(): string
110
    {
111
        preg_match('{\$[a-zA-Z_][a-zA-Z0-9_]*}', $this->currentLine, $property);
112
        return substr($property[0], 1);
113
    }
114
115
    /**
116
     * Checks if the code given is Axessors property definition. 
117
     * 
118
     * @return bool result of the checkout
119
     */
120
    private function isAxsPropertyDef(): bool
121
    {
122
        return (bool)preg_match('{^\s*(public|private|protected)\s+(static\s+)?\$[a-zA-Z_][a-zA-Z0-9_]*.*?;\s+#>}',
123
            $this->currentLine);
124
    }
125
}
126