Passed
Push — master ( 42d865...54862f )
by Kacper
03:02
created

GreedyParser::process()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 22
ccs 15
cts 15
cp 1
rs 8.6737
cc 5
eloc 12
nc 4
nop 1
crap 5
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;
17
18
19
use Kadet\Highlighter\Language\Language;
20
use Kadet\Highlighter\Parser\Token\LanguageToken;
21
use Kadet\Highlighter\Parser\Token\MetaToken;
22
use Kadet\Highlighter\Parser\Token\Token;
23
use Kadet\Highlighter\Utils\ArrayHelper;
24
25
class GreedyParser implements ParserInterface
26
{
27
    /**
28
     * @var array
29
     */
30
    private $_context;
31
32
    /**
33
     * @var Result
34
     */
35
    private $_result;
36
37
    /**
38
     * @var TokenIterator
39
     */
40
    private $_iterator;
41
42
    /**
43
     * @var LanguageToken
44
     */
45
    private $_start;
46
47
    /**
48
     * @var Language
49
     */
50
    private $_language;
51
52 16
    public function __construct(Language $language = null) {
53 16
        if($language) {
54
            $this->setLanguage($language);
55
        }
56 16
    }
57
58 16
    public function setLanguage(Language $language) {
59 16
        $this->_language = $language;
60 16
    }
61
62 11
    public function process(TokenIterator $tokens) {
63
        // Reset variables to default state
64 11
        $this->_start    = $tokens->current();
65 11
        $this->_context  = [];
66 11
        $this->_result   = new Result($tokens->getSource(), [
67 11
            $this->_start
68 11
        ]);
69 11
        $this->_iterator = $tokens;
70
71
        /** @var Token $token */
72 11
        for ($tokens->next(); $tokens->valid(); $tokens->next()) {
73 11
            $token = $tokens->current();
74
75 11
            if ($token->isValid($this->_language, $this->_context)) {
76 11
                if(($token->isStart() ? $this->handleStart($token) : $this->handleEnd($token)) === false) {
77 11
                    break;
78
                };
79 10
            }
80 10
        }
81
82 11
        return $this->_result;
83
    }
84
85 10
    protected function handleStart(Token $token) {
86 10
        if ($token instanceof LanguageToken) {
87 2
            $this->_result->merge($token->getInjected()->parse($this->_iterator));
88 2
        } else {
89 10
            $this->_result[] = $token;
90 10
            $this->_context[$this->_iterator->key()] = $token->name;
91
        }
92
93 10
        return true;
94
    }
95
96 11
    protected function handleEnd(Token $token) {
97 11
        $start = $token->getStart();
98
99
        /** @noinspection PhpUndefinedMethodInspection bug */
100 11
        if ($token instanceof LanguageToken && $token->getLanguage() === $this->_language) {
101 11
            $this->_start->setEnd($token);
102
103 11
            if ($this->_start->postProcess) {
0 ignored issues
show
Documentation introduced by
The property postProcess does not exist on object<Kadet\Highlighter...er\Token\LanguageToken>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
104 1
                $source = substr($this->_iterator->getSource(), $this->_start->pos, $this->_start->getLength());
105
106 1
                $tokens = $this->_start->getInjected()->tokenize($source, $this->_result, $this->_start->pos, true);
0 ignored issues
show
Documentation introduced by
$this->_result is of type object<Kadet\Highlighter\Parser\Result>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
107 1
                $this->_result = $this->_start->getInjected()->parse($tokens);
108 1
            }
109
110
            # closing unclosed tokens
111 11
            foreach (array_reverse($this->_context) as $hash => $name) {
112 1
                $end = new Token([$name, 'pos' => $token->pos]);
113 1
                $this->_iterator[$hash]->setEnd($end);
114 1
                $this->_result[] = $end;
115 11
            }
116
117 11
            $this->_result[] = $token;
118 11
            return false;
119
        } else {
120 9
            if ($start) {
121 8
                unset($this->_context[spl_object_hash($start)]);
122 8
            } else {
123 1
                $start = ArrayHelper::find(array_reverse($this->_context), function ($k, $v) use ($token) {
124 1
                    return $v === $token->name;
125 1
                });
126
127 1
                if ($start !== false) {
128 1
                    $token->setStart($this->_iterator[$start]);
129 1
                    unset($this->_context[$start]);
130 1
                    $start = $this->_iterator[$start];
131 1
                }
132
            }
133
134 9
            if (!$start instanceof MetaToken) {
135 9
                $this->_result[] = $token;
136 9
            }
137
        }
138
139 9
        return true;
140
    }
141
}