Completed
Push — master ( 82eb41...4f6b0a )
by Alexander
03:49
created

TokenStream::expect()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 50
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 3.7614

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 50
ccs 23
cts 41
cp 0.561
rs 9.3333
cc 3
eloc 33
nc 2
nop 2
crap 3.7614
1
<?php
2
namespace Xiag\Rql\Parser;
3
4
use Xiag\Rql\Parser\Exception\SyntaxErrorException;
5
6
class TokenStream implements \Countable
7
{
8
    /**
9
     * @var Token[]
10
     */
11
    protected $tokens;
12
    /**
13
     * @var int Current position
14
     */
15
    protected $current;
16
17
    /**
18
     * @param array $tokens An array of tokens
19
     */
20 81
    public function __construct(array $tokens)
21
    {
22 81
        $this->tokens  = $tokens;
23 81
        $this->current = 0;
24 81
    }
25
26
    /**
27
     * @inheritdoc
28
     */
29 17
    public function count()
30
    {
31 17
        return count($this->tokens);
32
    }
33
34
    /**
35
     * @return Token
36
     * @throws SyntaxErrorException If the stream ends
37
     */
38 80
    public function next()
39
    {
40 80
        if (!isset($this->tokens[++$this->current])) {
41
            throw new SyntaxErrorException('Unexpected end of stream');
42
        }
43
44 80
        return $this->tokens[$this->current - 1];
45
    }
46
47
    /**
48
     * @param int|int[] $type
49
     * @param string|string[] $value
50
     * @return Token|null
51
     * @throws SyntaxErrorException If the stream ends
52
     */
53 60
    public function nextIf($type, $value = null)
54
    {
55 60
        if ($this->test($type, $value)) {
56 26
            return $this->next();
57
        }
58
59 57
        return null;
60
    }
61
62
    /**
63
     * @param int $number
64
     * @return Token
65
     * @throws SyntaxErrorException If the stream ends
66
     */
67
    public function lookAhead($number = 1)
68
    {
69
        if (!isset($this->tokens[$this->current + $number])) {
70
            throw new SyntaxErrorException('Unexpected end of stream');
71
        }
72
73
        return $this->tokens[$this->current + $number];
74
    }
75
76
    /**
77
     * @param int|int[] $type
78
     * @param string|string[] $value
79
     * @return Token
80
     * @throws SyntaxErrorException If the current token isn't expected
81
     */
82 64
    public function expect($type, $value = null)
83
    {
84 64
        $token = $this->getCurrent();
85 64
        if (!$this->test($type, $value)) {
86 7
            throw new SyntaxErrorException(
87 7
                sprintf(
88 7
                    'Unexpected token "%s" (%s) (%s)',
89 7
                    $token->getValue(),
90 7
                    $token->getName(),
91 7
                    $value === null ?
92 7
                        sprintf(
93 7
                            'expected %s',
94 7
                            implode(
95 7
                                '|',
96 7
                                array_map(
97
                                    function ($type) {
98 7
                                        return Token::getTypeName($type);
99 7
                                    },
100
                                    (array)$type
101 7
                                )
102 7
                            )
103 7
                        ) :
104
                        sprintf(
105
                            'expected %s (%s)',
106
                            implode(
107
                                '|',
108
                                array_map(
109
                                    function ($value) {
110
                                        return '"' . $value . '"';
111
                                    },
112
                                    (array)$type
113
                                )
114
                            ),
115
                            implode(
116
                                '|',
117
                                array_map(
118
                                    function ($type) {
119
                                        return Token::getTypeName($type);
120
                                    },
121
                                    (array)$type
122
                                )
123
                            )
124
                        )
125 7
                )
126 7
            );
127
        }
128 63
        $this->next();
129
130 63
        return $token;
131
    }
132
133
    /**
134
     * Checks whether is end of stream
135
     *
136
     * @return bool
137
     */
138 64
    public function isEnd()
139
    {
140 64
        return $this->tokens[$this->current]->getType() === Token::T_END;
141
    }
142
143
    /**
144
     * Gets the current token
145
     *
146
     * @return Token
147
     */
148 81
    public function getCurrent()
149
    {
150 81
        return $this->tokens[$this->current];
151
    }
152
153
    /**
154
     * @param int|int[] $type
155
     * @param string|string[] $value
156
     * @return bool
157
     */
158 64
    public function test($type, $value = null)
159
    {
160 64
        return  $this->tokens[$this->current]->test($type, $value);
161
    }
162
}
163