Passed
Push — master ( 05f929...203740 )
by Kacper
03:48 queued 01:02
created

Token::getLength()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 7
Bugs 1 Features 0
Metric Value
c 7
b 1
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 3
eloc 4
nc 3
nop 0
crap 3
1
<?php
2
/**
3
 * Highlighter
4
 *
5
 * Copyright (C) 2015, 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\Parser;
17
18
19
use Kadet\Highlighter\Language\Language;
20
use Kadet\Highlighter\Utils\Helper;
21
use Kadet\Highlighter\Utils\StringHelper;
22
23
class Token
24
{
25
    const NAME = null;
26
27
    protected static $_id = 0;
28
29
    public $pos;
30
    public $name;
31
    public $index = 1;
32
33
    /**
34
     * @var Token
35
     */
36
    protected $_end;
37
38
    /**
39
     * @var Token
40
     */
41
    protected $_start;
42
43
    /** @var Rule */
44
    protected $_rule;
45
46
    protected $_valid;
47
    protected $_length;
48
49
    public $id;
50
51
    /**
52
     * Token constructor.
53
     */
54 51
    public function __construct(array $options)
55
    {
56
        // Name
57 51
        if (isset($options[0])) {
58 39
            $this->name = $options[0];
59 39
        }
60
61 51
        if (isset($options['pos'])) {
62 48
            $this->pos = $options['pos'];
63 48
        }
64
65 51
        if (isset($options['index'])) {
66 35
            $this->index = $options['index'];
67 6
        }
68
69 51
        if (isset($options['start'])) {
70 39
            $this->setStart($options['start']);
71 39
        }
72
73 51
        if (isset($options['rule'])) {
74 43
            $this->setRule($options['rule']);
75 43
        } else {
76 34
            $this->setRule(new Rule());
77
        }
78
79 51
        if (isset($options['end'])) {
80 3
            $this->setEnd($options['end']);
81 3
        }
82
83 51
        $this->id = ++self::$_id;
84
85 51
        if (isset($options['length'])) {
86 37
            new static([$this->name, 'pos' => $this->pos + $options['length'], 'start' => $this, 'rule' => $this->getRule()]);
87 37
        }
88 51
    }
89
90 17
    public static function compare(Token $a, Token $b)
91
    {
92 17
        if ($a->pos === $b->pos) {
93 13
            $multiplier = $a->isEnd() ? -1 : 1;
94
95 13
            if (($a->isStart() && $b->isEnd()) || ($a->isEnd() && $b->isStart())) {
96 1
                if($a->getEnd() == $b) {
97 1
                    return -1;
98 1
                } elseif($a->getStart() == $b) {
99
                    return 1;
100
                } else {
101 1
                    return $multiplier;
102
                }
103 12
            } elseif (($rule = Helper::cmp($b->_rule->priority, $a->_rule->priority)) !== 0) {
104 10
                return $multiplier*$rule;
105 5
            } elseif (($rule = Helper::cmp($b->index, $a->index)) !== 0) {
106 1
                return $multiplier*$rule;
107
            } else {
108 5
                return $multiplier*($a->id < $b->id ? -1 : 1);
109
            }
110
        }
111
112 17
        return ($a->pos > $b->pos) ? 1 : -1;
113
    }
114
115 36
    public function isStart()
116
    {
117 36
        return $this->_start === null && !($this->_rule instanceof CloseRule);
118
    }
119
120 32
    public function isEnd()
121
    {
122 32
        return $this->_end === null && !($this->_rule instanceof OpenRule);
123
    }
124
125 15
    public function isValid(Language $language, $context = null)
126
    {
127 15
        if ($this->_valid === null) {
128 14
            $this->validate($language, $context);
129 14
        }
130
131 15
        return $this->_valid;
132
    }
133
134 11
    protected function validate(Language $language, $context)
135
    {
136 11
        $this->setValid(
137 11
            $language === $this->_rule->language &&
138 11
            $this->_rule->validateContext($context, $this->isEnd() ? [$this->name => Rule::CONTEXT_IN] : [])
139 11
        );
140 11
    }
141
142 14
    public function setValid($valid = true)
143
    {
144 14
        $this->_valid = $valid;
145
146 14
        if ($this->_end !== null) {
147 11
            $this->_end->_valid = $this->_valid;
148 14
        } elseif ($this->_start !== null) {
149 12
            $this->_start->_valid = $this->_valid;
150 12
        }
151 14
    }
152
153
    /**
154
     * @return mixed
155
     */
156 15
    public function getStart()
157
    {
158 15
        return $this->_start;
159
    }
160
161
    /**
162
     * @param Token $start
163
     */
164 39 View Code Duplication
    public function setStart(Token $start = null)
165
    {
166 39
        $this->_end = null;
167 39
        $this->_start = $start;
168
169 39
        if ($start !== null) {
170 39
            $this->_start->_end = $this;
171 39
        }
172 39
    }
173
174
    /**
175
     * @return Token|null
176
     */
177 38
    public function getEnd()
178
    {
179 38
        return $this->_end;
180
    }
181
182
    /**
183
     * @param Token $end
184
     */
185 14 View Code Duplication
    public function setEnd(Token $end = null)
186
    {
187 14
        $this->_start = null;
188 14
        $this->_end = $end;
189 14
        $this->_length = null;
190
191 14
        if ($end !== null) {
192 14
            $this->_end->_start = $this;
193 14
        }
194 14
    }
195
196
    /**
197
     * @return Rule
198
     */
199 39
    public function getRule()
200
    {
201 39
        return $this->_rule;
202
    }
203
204
    /**
205
     * @param Rule $rule
206
     */
207 51
    public function setRule(Rule $rule)
208
    {
209 51
        $this->_rule = $rule;
210 51
    }
211
212 2
    public function getLength()
213
    {
214 2
        if ($this->_length === null) {
215 2
            $this->_length = $this->_end === null ? 0 : $this->_end->pos - $this->pos;
216 2
        }
217
218 2
        return $this->_length;
219
    }
220
221
    /**
222
     * @codeCoverageIgnore
223
     */
224
    public function dump($text = null)
225
    {
226
        $pos = StringHelper::positionToLine($text, $this->pos);
227
        $pos = $pos['line'] . ':' . $pos['pos'];
228
229
        if ($this->isStart()) {
230
            $result = "Start ({$this->name}) $pos";
231
            if ($text !== null && $this->_end !== null) {
232
                $result .= "  \x02" . substr($text, $this->pos, $this->_end->pos - $this->pos) . "\x03";
233
            }
234
        } else {
235
            $result = "End ({$this->name}) $pos";
236
        }
237
238
        return $result;
239
    }
240
241 15
    public static function className() {
242 15
        return get_called_class();
243
    }
244
}