Completed
Push — master ( d70775...825d10 )
by Kacper
02:48
created

Python::getIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Highlighter
4
 *
5
 * Copyright (C) 2016, Some right reserved.
6
 *
7
 * @author Kacper "Kadet" Donat <[email protected]>
8
 *
9
 * Contact with author:
10
 * Xmpp: [email protected]
11
 * E-mail: [email protected]
12
 *
13
 * From Kadet with love.
14
 */
15
16
namespace Kadet\Highlighter\Language;
17
18
19
use Kadet\Highlighter\Matcher\CommentMatcher;
20
use Kadet\Highlighter\Matcher\RegexMatcher;
21
use Kadet\Highlighter\Matcher\SubStringMatcher;
22
use Kadet\Highlighter\Matcher\WordMatcher;
23
use Kadet\Highlighter\Parser\CloseRule;
24
use Kadet\Highlighter\Parser\Rule;
25
use Kadet\Highlighter\Parser\Token\ContextualToken;
26
use Kadet\Highlighter\Parser\Token\TerminatorToken;
27
use Kadet\Highlighter\Parser\Token\Token;
28
use Kadet\Highlighter\Parser\TokenFactory;
29
use Kadet\Highlighter\Parser\Validator\Validator;
30
31
class Python extends GreedyLanguage
32
{
33
34
    /**
35
     * Tokenization rules setup
36
     */
37
    public function setupRules()
38
    {
39
        $standard = new Validator(['!string', '!comment']);
40
41
        $this->rules->addMany([
42
            'keyword' => new Rule(new WordMatcher([
43
                'and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', 'or', 'with', 'assert', 'else', 'if',
44
                'pass', 'yield', 'break', 'except', 'import', 'print', 'class', 'exec', 'in', 'raise', 'continue',
45
                'finally', 'is', 'return', 'def', 'for', 'lambda', 'try',
46
            ])),
47
48
            'operator' => new Rule(
49
                new RegexMatcher('/([-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~])|\b(or|and|not)\b/'), [
50
                    'priority' => -1
51
                ]
52
            ),
53
54
            'expression' => new Rule(new RegexMatcher('/\{(\S+)\}/'), [
55
                'context' => ['string']
56
            ]),
57
58
            'variable' => [
59
                new Rule(new RegexMatcher('/[^\w.]([a-z_]\w*)\.\w/i')),
60
                'property' => new Rule(new RegexMatcher('/(?=(?:\w|\)|\])\s*\.([a-z_]\w*))/i'), [
61
                    'priority' => -2,
62
                    'context' => ['*none', '*expression']
63
                ]),
64
            ],
65
66
            'symbol' => [
67
                new Rule(new RegexMatcher('/import\s+([a-z_][\w.]*)(?:\s*,\s*([a-z_][\w.]*))*/i', [
68
                    1 => Token::NAME,
69
                    2 => Token::NAME,
70
                ])),
71
                'library' => new Rule(new RegexMatcher('/from\s+([a-z_][\w.]*)\s+import/i', [
72
                    1 => Token::NAME,
73
                ]))
74
            ],
75
76
            'keyword.escape' => new Rule(new RegexMatcher('/(\\\(?:.|[0-7]{3}|x\x{2}))/'), [
77
                'context' => Validator::everywhere()
78
            ]),
79
80
            'comment' => new Rule(new CommentMatcher(['#'])),
81
            'constant.special' => [
82
                new Rule(new WordMatcher(['True', 'False', 'NotImplemented', 'Ellipsis'], [
83
                    'case-sensitivity' => true
84
                ])),
85
                new Rule(new RegexMatcher('/\b(__\w+__)\b/'))
86
            ],
87
            'call' => new Rule(new RegexMatcher('/([a-z_]\w*)\s*\(/i'), ['priority' => 2]),
88
89
            'meta.newline' => new CloseRule(new RegexMatcher('/()\r?\n/'), [
90
                'factory' => new TokenFactory(TerminatorToken::class),
91
                'context' => ['!keyword.escape', 'string.single-line'],
92
                'closes'  => ['string.single-line.double', 'string.single-line.single']
93
            ]),
94
95
            'number' => new Rule(
96
                new RegexMatcher('/(-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?)\b/')
97
            ),
98
99
            'string' => [
100
                'single-line' => [
101
                    'double' => new Rule(new RegexMatcher('/(?:^|[^"])(")(?=[^"]|$)/'), [
102
                        'factory' => new TokenFactory(ContextualToken::class),
103
                        'context' => $standard,
104
                    ]),
105
                    'single' => new Rule(new RegexMatcher('/(?:^|[^\'])(\')(?=[^\']|$)/'), [
106
                        'factory' => new TokenFactory(ContextualToken::class),
107
                        'context' => $standard,
108
                    ]),
109
                ],
110
                'multi-line' => [
111
                    'double' => new Rule(new SubStringMatcher('"""'), [
112
                        'factory'  => new TokenFactory(ContextualToken::class),
113
                        'context'  => $standard,
114
                        'priority' => 2,
115
                    ]),
116
                    'single' => new Rule(new SubStringMatcher('\'\'\''), [
117
                        'factory'  => new TokenFactory(ContextualToken::class),
118
                        'context'  => $standard,
119
                        'priority' => 2,
120
                    ]),
121
                ]
122
            ],
123
124
            'symbol.function' => new Rule(new RegexMatcher('/def\s+([a-z_]\w+)\s*\(/i')),
125
            'symbol.class'    => new Rule(new RegexMatcher('/class\s+([a-z_]\w+)/i')),
126
        ]);
127
    }
128
129
    /**
130
     * Unique language identifier, for example 'php'
131
     *
132
     * @return string
133
     */
134
    public function getIdentifier()
135
    {
136
        return 'python';
137
    }
138
}
139