Test Setup Failed
Push — 3.0.0-dev ( e272a2...73dc53 )
by Eduardo Gulias
01:50
created

EmailLexer::reset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Egulias\EmailValidator;
4
5
use Doctrine\Common\Lexer\AbstractLexer;
6
7
class EmailLexer extends AbstractLexer
8
{
9
    //ASCII values
10
    const C_DEL              = 127;
11
    const C_NUL              = 0;
12
    const S_AT               = 64;
13
    const S_BACKSLASH        = 92;
14
    const S_DOT              = 46;
15
    const S_DQUOTE           = 34;
16
    const S_OPENPARENTHESIS  = 49;
17
    const S_CLOSEPARENTHESIS = 261;
18
    const S_OPENBRACKET      = 262;
19
    const S_CLOSEBRACKET     = 263;
20
    const S_HYPHEN           = 264;
21
    const S_COLON            = 265;
22
    const S_DOUBLECOLON      = 266;
23
    const S_SP               = 267;
24
    const S_HTAB             = 268;
25
    const S_CR               = 269;
26
    const S_LF               = 270;
27
    const S_IPV6TAG          = 271;
28
    const S_LOWERTHAN        = 272;
29
    const S_GREATERTHAN      = 273;
30
    const S_COMMA            = 274;
31
    const S_SEMICOLON        = 275;
32
    const S_OPENQBRACKET     = 276;
33
    const S_CLOSEQBRACKET    = 277;
34
    const S_SLASH            = 278;
35
    const S_EMPTY            = null;
36
    const GENERIC            = 300;
37
    const CRLF               = 301;
38
    const INVALID            = 302;
39
    const ASCII_INVALID_FROM = 127;
40
    const ASCII_INVALID_TO   = 199;
41
42
    /**
43
     * US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3)
44
     *
45
     * @var array
46
     */
47
    protected $charValue = array(
48
        '('    => self::S_OPENPARENTHESIS,
49
        ')'    => self::S_CLOSEPARENTHESIS,
50
        '<'    => self::S_LOWERTHAN,
51
        '>'    => self::S_GREATERTHAN,
52
        '['    => self::S_OPENBRACKET,
53
        ']'    => self::S_CLOSEBRACKET,
54
        ':'    => self::S_COLON,
55
        ';'    => self::S_SEMICOLON,
56
        '@'    => self::S_AT,
57
        '\\'   => self::S_BACKSLASH,
58
        '/'    => self::S_SLASH,
59
        ','    => self::S_COMMA,
60
        '.'    => self::S_DOT,
61
        '"'    => self::S_DQUOTE,
62
        '-'    => self::S_HYPHEN,
63
        '::'   => self::S_DOUBLECOLON,
64
        ' '    => self::S_SP,
65
        "\t"   => self::S_HTAB,
66
        "\r"   => self::S_CR,
67
        "\n"   => self::S_LF,
68
        "\r\n" => self::CRLF,
69
        'IPv6' => self::S_IPV6TAG,
70
        '{'    => self::S_OPENQBRACKET,
71
        '}'    => self::S_CLOSEQBRACKET,
72
        ''     => self::S_EMPTY,
73
        '\0'   => self::C_NUL,
74
    );
75
76
    /**
77
     * @var bool
78
     */
79
    protected $hasInvalidTokens = false;
80
81
    /**
82
     * @var array
83
     *
84
     * @psalm-var array{value:string, type:null|int, position:int}|array<empty, empty>
85
     */
86
    protected $previous = [];
87
88
    /**
89
     * The last matched/seen token.
90
     *
91
     * @var array
92
     *
93
     * @psalm-var array{value:string, type:null|int, position:int}
94
     */
95
    public $token;
96
97
    /**
98
     * The next token in the input.
99
     *
100
     * @var array|null
101
     */
102
    public $lookahead;
103
104
    /**
105
     * @psalm-var array{value:'', type:null, position:0}
106
     */
107
    private static $nullToken = [
108
        'value' => '',
109
        'type' => null,
110
        'position' => 0,
111
    ];
112
113
    private $accumulator = '';
114
    private $hasToRecord = false;
115
116
    public function __construct()
117
    {
118
        $this->previous = $this->token = self::$nullToken;
119
        $this->lookahead = null;
120
    }
121
122
    /**
123
     * @return void
124
     */
125
    public function reset()
126
    {
127
        $this->hasInvalidTokens = false;
128
        parent::reset();
129
        $this->previous = $this->token = self::$nullToken;
130
    }
131
132
    /**
133
     * @return bool
134
     */
135
    public function hasInvalidTokens()
136
    {
137
        return $this->hasInvalidTokens;
138
    }
139
140
    /**
141
     * @param int $type
142
     * @throws \UnexpectedValueException
143
     * @return boolean
144
     *
145
     * @psalm-suppress InvalidScalarArgument
146
     */
147
    public function find($type)
148
    {
149
        $search = clone $this;
150
        $search->skipUntil($type);
151
152
        if (!$search->lookahead) {
153
            throw new \UnexpectedValueException($type . ' not found');
154
        }
155
        return true;
156
    }
157
158
    /**
159
     * getPrevious
160
     *
161
     * @return array
162
     */
163
    public function getPrevious()
164
    {
165
        return $this->previous;
166
    }
167
168
    /**
169
     * moveNext
170
     *
171
     * @return boolean
172
     */
173
    public function moveNext()
174
    {
175
        if ($this->hasToRecord && $this->previous === self::$nullToken) {
176
            $this->accumulator .= $this->token['value'];
177
        }
178
179
        $this->previous = $this->token;
180
        $hasNext = parent::moveNext();
181
        $this->token = $this->token ?: self::$nullToken;
182
183
        if ($this->hasToRecord) {
184
            $this->accumulator .= $this->token['value'];
185
        }
186
187
        return $hasNext;
188
    }
189
190
    /**
191
     * Lexical catchable patterns.
192
     *
193
     * @return string[]
194
     */
195
    protected function getCatchablePatterns()
196
    {
197
        return array(
198
            '[a-zA-Z_]+[46]?', //ASCII and domain literal
199
            '[^\x00-\x7F]',  //UTF-8
200
            '[0-9]+',
201
            '\r\n',
202
            '::',
203
            '\s+?',
204
            '.',
205
            );
206
    }
207
208
    /**
209
     * Lexical non-catchable patterns.
210
     *
211
     * @return string[]
212
     */
213
    protected function getNonCatchablePatterns()
214
    {
215
        return array('[\xA0-\xff]+');
216
    }
217
218
    /**
219
     * Retrieve token type. Also processes the token value if necessary.
220
     *
221
     * @param string $value
222
     * @throws \InvalidArgumentException
223
     * @return integer
224
     */
225
    protected function getType(&$value)
226
    {
227
        if ($this->isNullType($value)) {
228
            return self::C_NUL;
229
        }
230
231
        if ($this->isValid($value)) {
232
            return $this->charValue[$value];
233
        }
234
235
        if ($this->isUTF8Invalid($value)) {
236
            $this->hasInvalidTokens = true;
237
            return self::INVALID;
238
        }
239
240
        return  self::GENERIC;
241
    }
242
243
    /**
244
     * @param string $value
245
     *
246
     * @return bool
247
     */
248
    protected function isValid($value)
249
    {
250
        if (isset($this->charValue[$value])) {
251
            return true;
252
        }
253
254
        return false;
255
    }
256
257
    /**
258
     * @param string $value
259
     * @return bool
260
     */
261
    protected function isNullType($value)
262
    {
263
        if ($value === "\0") {
264
            return true;
265
        }
266
267
        return false;
268
    }
269
270
    /**
271
     * @param string $value
272
     * @return bool
273
     */
274
    protected function isUTF8Invalid($value)
275
    {
276
        if (preg_match('/\p{Cc}+/u', $value)) {
277
            return true;
278
        }
279
280
        return false;
281
    }
282
283
    /**
284
     * @return string
285
     */
286
    protected function getModifiers()
287
    {
288
        return 'iu';
289
    }
290
291
    public function getAccumulatedValues() : string
292
    {
293
        return $this->accumulator;
294
    }
295
296
    public function startRecording() : void
297
    {
298
        $this->hasToRecord = true;
299
    }
300
301
    public function stopRecording() : void
302
    {
303
        $this->hasToRecord = false;
304
    }
305
306
    public function clearRecorded() : void
307
    {
308
        $this->accumulator = '';
309
    }
310
}
311