Completed
Branch 0.8-dev (8bed0e)
by Kacper
02:45
created

Token::setEnd()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 10
loc 10
rs 9.4285
ccs 8
cts 8
cp 1
cc 2
eloc 6
nc 2
nop 1
crap 2
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\Parser\Token;
17
18
use Kadet\Highlighter\Language\Language;
19
use Kadet\Highlighter\Parser\Context;
20
use Kadet\Highlighter\Parser\Result;
21
use Kadet\Highlighter\Parser\Rule;
22
use Kadet\Highlighter\Parser\TokenIterator;
23
use Kadet\Highlighter\Parser\Validator\Validator;
24
use Kadet\Highlighter\Utils\Helper;
25
26
class Token
27
{
28
    const NAME  = null;
29
    const START = 0x1;
30
    const END   = 0x2;
31
32
    protected static $_id = 0;
33
34
    public $pos;
35
    public $name;
36
    public $closedBy;
37
    public $index = 1;
38
    public $id;
39
    public $rule;
40
41
    # region >>> cache
42
    /**
43
     * @var static|null|false
44
     */
45
    protected $_end;
46
47
    /**
48
     * @var static|null|false
49
     */
50
    protected $_start;
51
52
    protected $_valid;
53
    protected $_length;
54
    # endregion
55
56
    /**
57
     * Token constructor.
58
     *
59
     * @param array $options
60
     */
61 52
    public function __construct(array $options)
62
    {
63 52
        if (isset($options[0])) {
64 39
            $this->name     = $options[0];
65 39
            $this->closedBy = $this->name;
66 39
        }
67
68 52
        if (isset($options['pos'])) {
69 49
            $this->pos = $options['pos'];
70 49
        }
71
72 52
        if (isset($options['index'])) {
73 6
            $this->index = $options['index'];
74 6
        }
75
76 52
        if (isset($options['start'])) {
77 2
            $this->setStart($options['start']);
78 2
        }
79
80 52
        $this->rule = isset($options['rule']) ? $options['rule'] : new Rule();
81
82 52
        if (isset($options['end'])) {
83 42
            $this->setEnd($options['end']);
84 42
        }
85
86 52
        if (isset($options['closed-by'])) {
87
            $this->closedBy = $options['closed-by'];
88
        }
89
90 52
        $this->id = ++self::$_id;
91 52
    }
92
93 35
    public function isStart()
94
    {
95 35
        return $this->_start === null;
96
    }
97
98 33
    public function isEnd()
99
    {
100 33
        return $this->_end === null;
101
    }
102
103 16
    public function isValid(Context $context = null)
104
    {
105 16
        if ($this->_valid === null) {
106 15
            $this->validate($context);
0 ignored issues
show
Bug introduced by
It seems like $context defined by parameter $context on line 103 can be null; however, Kadet\Highlighter\Parser\Token\Token::validate() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
107 15
        }
108
109 16
        return $this->_valid;
110
    }
111
112 11
    protected function validate(Context $context)
113
    {
114 11
        $this->setValid(
115 11
            $context->language === $this->rule->language &&
116 11
            $this->rule->validator->validate($context, $this->isEnd() ? [$this->name => Validator::CONTEXT_IN] : [])
117 11
        );
118 11
    }
119
120 15
    public function setValid($valid = true)
121
    {
122 15
        $this->_valid = $valid;
123
124 15
        if ($this->_end) {
125 12
            $this->_end->_valid = $this->_valid;
126 15
        } elseif ($this->_start) {
127 12
            $this->_start->_valid = $this->_valid;
128 12
        }
129 15
    }
130
131
    /**
132
     * @return Token|null|false
133
     */
134 29
    public function getStart()
135
    {
136 29
        return $this->_start;
137
    }
138
139
    /**
140
     * @param Token|null|false $start
141
     */
142 13 View Code Duplication
    public function setStart($start = null)
143
    {
144 13
        $this->_end   = null;
145 13
        $this->_start = $start;
146
147 13
        if ($start instanceof Token) {
148 12
            $this->_start->_length = null;
149 12
            $start->_end = $this;
150 12
        }
151 13
    }
152
153
    /**
154
     * @return Token|null|false
155
     */
156 40
    public function getEnd()
157
    {
158 40
        return $this->_end;
159
    }
160
161
    /**
162
     * @param Token|null|false $end
163
     */
164 42 View Code Duplication
    public function setEnd($end = null)
165
    {
166 42
        $this->_start  = null;
167 42
        $this->_end    = $end;
168 42
        $this->_length = null;
169
170 42
        if ($end instanceof Token) {
171 42
            $end->_start = $this;
172 42
        }
173 42
    }
174
175 2
    public function getLength()
176
    {
177 2
        if ($this->_length === null) {
178 2
            $this->_length = !$this->_end ? 0 : $this->_end->pos - $this->pos;
179 2
        }
180
181 2
        return $this->_length;
182
    }
183
184 11
    public function __get($name)
185
    {
186 11
        return $this->rule->$name;
187
    }
188
189
    /**
190
     * @param Context       $context
191
     * @param Language      $language
192
     * @param Result        $result
193
     * @param TokenIterator $tokens
194
     *
195
     * todo: Documentation
196
     *
197
     * @return bool Return true to continue processing, false to return already processed tokens.
198
     */
199 11
    public function process(Context $context, Language $language, Result $result, TokenIterator $tokens) {
200 11
        if(!$this->isValid($context)) {
201 3
            return true;
202
        }
203
204 11
        return $this->isStart() ?
205 11
            $this->processStart($context, $language, $result, $tokens) :
206 11
            $this->processEnd($context, $language, $result, $tokens);
207
    }
208
209 10
    protected function processStart(Context $context, Language $language, Result $result, TokenIterator $tokens) {
1 ignored issue
show
Unused Code introduced by
The parameter $language is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
210 10
        $result->append($this);
211 10
        $context->push($this);
212
213 10
        return true;
214
    }
215
216 9
    protected function processEnd(Context $context, Language $language, Result $result, TokenIterator $tokens) {
1 ignored issue
show
Unused Code introduced by
The parameter $language is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
217 9
        if($this->_start) {
218 8
            $context->pop($this->_start);
219 8
        } else {
220 1
            if (($start = $context->find($this->closedBy)) !== false) {
221 1
                $this->setStart($tokens[$start]);
222
223 1
                unset($context->stack[$start]);
224 1
            }
225
        }
226
227 9
        if (!$this->_start instanceof MetaToken) {
228 9
            $result->append($this);
229 9
        }
230
231 9
        return true;
232
    }
233
234 13
    public static function compare(Token $a, Token $b)
235
    {
236 13
        $multiplier = $a->isEnd() ? -1 : 1;
237
238 13
        if (($a->isStart() && $b->isEnd()) || ($a->isEnd() && $b->isStart())) {
239 1
            if ($a->getStart() == $b) {
240 1
                return 1;
241 1
            } elseif ($a->getEnd() == $b) {
242
                return -1;
243
            } else {
244 1
                return $multiplier;
245
            }
246 12
        } elseif (($rule = Helper::cmp($b->rule->priority, $a->rule->priority)) !== 0) {
247 10
            return $multiplier*$rule;
248 5
        } elseif (($rule = Helper::cmp($b->index, $a->index)) !== 0) {
249 1
            return $multiplier*$rule;
250
        } else {
251 4
            return $multiplier*($a->id < $b->id ? -1 : 1);
252
        }
253
    }
254
}
255