ExpressionLexer   D
last analyzed

Complexity

Total Complexity 106

Size/Duplication

Total Lines 590
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 106
lcom 1
cbo 4
dl 0
loc 590
rs 4.8717
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A getCurrentToken() 0 4 1
A setCurrentToken() 0 4 1
A getExpressionText() 0 4 1
A getPosition() 0 4 1
B isNumeric() 0 9 5
F nextToken() 0 139 33
A peekNextToken() 0 14 1
A validateToken() 0 10 2
A readDottedIdentifier() 0 14 2
A _isInfinityOrNaNDouble() 0 12 4
A _isInfinityLiteralDouble() 0 4 1
B _isInfinityOrNanSingle() 0 14 6
A _isInfinityLiteralSingle() 0 7 4
C _handleTypePrefixedLiterals() 0 45 11
C _parseFromDigit() 0 56 21
A _parseIdentifier() 0 6 3
A _nextChar() 0 10 3
A _setTextPos() 0 7 2
A _validateDigit() 0 10 2
A _parseError() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like ExpressionLexer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ExpressionLexer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace POData\UriProcessor\QueryProcessor\ExpressionParser;
4
5
use POData\Common\Messages;
6
use POData\Common\ODataException;
7
use POData\Common\ODataConstants;
8
use POData\Providers\Metadata\Type\Char;
9
10
/**
11
 * Class ExpressionLexer
12
 *
13
 * Lexical analyzer for Astoria URI expression parsing
14
 * Literals        Representation
15
 * --------------------------------------------------------------------
16
 * Null            null
17
 * Boolean         true | false
18
 * Int32           (digit+)
19
 * Int64           (digit+)(L|l)
20
 * Decimal         (digit+ ['.' digit+])(M|m)
21
 * Float (Single)  (digit+ ['.' digit+][e|E [+|-] digit+)(f|F)
22
 * Double          (digit+ ['.' digit+][e|E [+|-] digit+)
23
 * String          "'" .* "'"
24
 * DateTime        datetime"'"dddd-dd-dd[T|' ']dd:mm[ss[.fffffff]]"'"
25
 * Binary          (binary|X)'digit*'
26
 * GUID            guid'digit*
27
 *
28
 * @package POData\UriProcessor\QueryProcessor\ExpressionParser
29
 */
30
class ExpressionLexer
31
{
32
    /**
33
     * Suffix for single literals
34
     * 
35
     * @var char
36
     */
37
    const SINGLE_SUFFIX_LOWER = 'f';
38
39
    /** 
40
     * Suffix for single literals
41
     * 
42
     * @var char
43
     */
44
    const SINGLE_SUFFIX_UPPER = 'F';
45
46
    /**     
47
     * Text being parsed
48
     * 
49
     * @var char[]
50
     */
51
    private $_text;
52
53
    /**
54
     * Length of text being parsed
55
     * 
56
     * @var int
57
     */
58
    private $_textLen;
59
60
    /**
61
     * Position on text being parsed
62
     * 
63
     * @var int
64
     */
65
    private $_textPos;
66
67
    /**
68
     * Character being processed
69
     * 
70
     * @var char
71
     */
72
    private $_ch;
73
 
74
    /**
75
     * ExpressionToken being processed
76
     * 
77
     * @var ExpressionToken
78
     */
79
    private $_token;
80
81
    /** 
82
     * Initialize a new instance of ExpressionLexer
83
     * 
84
     * @param string $expression Expression to parse
85
     */
86
    public function __construct($expression)
87
    {
88
        $this->_text = $expression;
0 ignored issues
show
Documentation Bug introduced by
It seems like $expression of type string is incompatible with the declared type array<integer,object<POD...ExpressionParser\char>> of property $_text.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
89
        $this->_textLen = strlen($this->_text);
90
        $this->_token = new ExpressionToken();
91
        $this->_setTextPos(0);
92
        $this->nextToken();
93
    }
94
95
    /**
96
     * To get the expression token being processed
97
     * 
98
     * @return ExpressionToken
99
     */
100
    public function getCurrentToken()
101
    {
102
        return $this->_token;
103
    }
104
105
    /**
106
     * To set the token being processed
107
     * 
108
     * @param ExpressionToken $token The expression token to set as current
109
     * 
110
     * @return void
111
     */
112
    public function setCurrentToken($token)
113
    {
114
        $this->_token = $token;
115
    }
116
117
    /**
118
     * To get the text being parsed
119
     * 
120
     * @return string
121
     */
122
    public function getExpressionText()
123
    {
124
        return $this->_text;
125
    }
126
127
    /** 
128
     * Position of the current token in the text being parsed
129
     * 
130
     * @return int
131
     */
132
    public function getPosition()
133
    {
134
        return $this->_token->Position;
135
    }
136
137
    /**
138
     * Whether the specified token identifier is a numeric literal
139
     * 
140
     * @param ExpressionTokenId $id Token identifier to check
141
     * 
142
     * @return bool true if it's a numeric literal; false otherwise
143
     */
144
    public static function isNumeric($id)
145
    {
146
        return
147
            $id == ExpressionTokenId::INTEGER_LITERAL 
148
            || $id == ExpressionTokenId::DECIMAL_LITERAL 
149
            || $id == ExpressionTokenId::DOUBLE_LITERAL 
150
            || $id == ExpressionTokenId::INT64_LITERAL 
151
            || $id == ExpressionTokenId::SINGLE_LITERAL;
152
    }
153
154
    /** 
155
     * Reads the next token, skipping whitespace as necessary.
156
     * 
157
     * @return void
158
     */
159
    public function nextToken()
160
    {
161
162
        while (Char::isWhiteSpace($this->_ch)) {
163
            $this->_nextChar();
164
        }
165
166
        $t = null;
167
        $tokenPos = $this->_textPos;
168
        switch ($this->_ch) {
169
	        case '(':
170
	            $this->_nextChar();
171
	            $t = ExpressionTokenId::OPENPARAM;
172
	            break;
173
	        case ')':
174
	            $this->_nextChar();
175
	            $t = ExpressionTokenId::CLOSEPARAM;
176
	            break;
177
	        case ',':
178
	            $this->_nextChar();
179
	            $t = ExpressionTokenId::COMMA;
180
	            break;
181
	        case '-':
182
	            $hasNext = $this->_textPos + 1 < $this->_textLen;
183
	            if ($hasNext && Char::isDigit($this->_text[$this->_textPos + 1])) {
184
	                $this->_nextChar();
185
	                $t = $this->_parseFromDigit();
186
	                if (self::isNumeric($t)) {
187
	                    break;
188
	                }
189
190
	                $this->_setTextPos($tokenPos);
191
	            } else if ($hasNext && $this->_text[$tokenPos + 1] == 'I') {
192
	                $this->_nextChar();
193
	                $this->_parseIdentifier();
194
	                $currentIdentifier = substr($this->_text, $tokenPos + 1, $this->_textPos - $tokenPos - 1);
195
196
	                if (self::_isInfinityLiteralDouble($currentIdentifier)) {
197
	                    $t = ExpressionTokenId::DOUBLE_LITERAL;
198
	                    break;
199
	                } else if (self::_isInfinityLiteralSingle($currentIdentifier)) {
200
	                    $t = ExpressionTokenId::SINGLE_LITERAL;
201
	                    break;
202
	                }
203
204
	                // If it looked like '-INF' but wasn't we'll rewind and fall
205
	                // through to a simple '-' token.
206
	                $this->_setTextPos($tokenPos);
207
	            }
208
209
	            $this->_nextChar();
210
	            $t = ExpressionTokenId::MINUS;
211
	            break;
212
	        case '=':
213
	            $this->_nextChar();
214
	            $t = ExpressionTokenId::EQUAL;
215
	            break;
216
	        case '/':
217
	            $this->_nextChar();
218
	            $t = ExpressionTokenId::SLASH;
219
	            break;
220
	        case '?':
221
	            $this->_nextChar();
222
	            $t = ExpressionTokenId::QUESTION;
223
	            break;
224
	        case '.':
225
	            $this->_nextChar();
226
	            $t = ExpressionTokenId::DOT;
227
	            break;
228
	        case '\'':
229
	            $quote = $this->_ch;
230
	            do {
231
	                $this->_nextChar();
232
	                while ($this->_textPos < $this->_textLen && $this->_ch != $quote) {
233
	                    $this->_nextChar();
234
	                }
235
236
	                if ($this->_textPos == $this->_textLen) {
237
	                    $this->_parseError(
238
	                        Messages::expressionLexerUnterminatedStringLiteral(
239
	                            $this->_textPos, $this->_text
0 ignored issues
show
Documentation introduced by
$this->_text is of type array<integer,object<POD...ExpressionParser\char>>, but the function expects a string.

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...
240
	                        )
241
	                    );
242
	                }
243
244
	                $this->_nextChar();
245
	            } while ($this->_ch == $quote);
246
	            $t = ExpressionTokenId::STRING_LITERAL;
247
	            break;
248
	        case '*':
249
	            $this->_nextChar();
250
	            $t = ExpressionTokenId::STAR;
251
	            break;
252
	        default:
253
	            if (Char::isLetter($this->_ch) || $this->_ch == '_') {
254
	                $this->_parseIdentifier();
255
	                $t = ExpressionTokenId::IDENTIFIER;
256
	                break;
257
	            }
258
259
	            if (Char::isDigit($this->_ch)) {
260
	                $t = $this->_parseFromDigit();
261
	                break;
262
	            }
263
264
	            if ($this->_textPos == $this->_textLen) {
265
	                $t = ExpressionTokenId::END;
266
	                break;
267
	            }
268
269
	            $this->_parseError(
270
	                Messages::expressionLexerInvalidCharacter(
271
	                    $this->_ch, $this->_textPos
272
	                )
273
	            );
274
        }
275
276
        $this->_token->Id = $t;
277
        $this->_token->Text = substr($this->_text, $tokenPos, $this->_textPos - $tokenPos);
278
        $this->_token->Position = $tokenPos;
279
280
        // Handle type-prefixed literals such as binary, datetime or guid.
281
        $this->_handleTypePrefixedLiterals();
282
283
        // Handle keywords.
284
        if ($this->_token->Id == ExpressionTokenId::IDENTIFIER) {
285
            if (self::_isInfinityOrNaNDouble($this->_token->Text)) {
286
                $this->_token->Id = ExpressionTokenId::DOUBLE_LITERAL;
287
            } else if (self::_isInfinityOrNanSingle($this->_token->Text)) {
288
                $this->_token->Id = ExpressionTokenId::SINGLE_LITERAL;
289
            } else if ($this->_token->Text == ODataConstants::KEYWORD_TRUE 
290
                || $this->_token->Text == ODataConstants::KEYWORD_FALSE
291
            ) {
292
                $this->_token->Id = ExpressionTokenId::BOOLEAN_LITERAL;
293
            } else if ($this->_token->Text == ODataConstants::KEYWORD_NULL) {
294
                $this->_token->Id = ExpressionTokenId::NULL_LITERAL;
295
            }
296
        }
297
    }
298
299
    /**
300
     * Returns the next token without advancing the lexer to next token
301
     * 
302
     * @return ExpressionToken
303
     */
304
    public function peekNextToken()
305
    {
306
        $savedTextPos = $this->_textPos;
307
        $savedChar = $this->_ch;
308
        $savedToken = clone $this->_token;
309
        $this->nextToken();
310
        $result = clone $this->_token;
311
        $this->_textPos = $savedTextPos;
312
        $this->_ch = $savedChar;        
313
        $this->_token->Id = $savedToken->Id;
314
        $this->_token->Position = $savedToken->Position;
315
        $this->_token->Text = $savedToken->Text;
316
        return $result;
317
    }
318
319
    /**
320
     * Validates the current token is of the specified kind
321
     * 
322
     * @param ExpressionTokenId $tokenId Expected token kind
323
     * 
324
     * @return void
325
     * 
326
     * @throws ODataException if current token is not of the 
327
     *                        specified kind.
328
     */
329
    public function validateToken($tokenId)
330
    {
331
        if ($this->_token->Id != $tokenId) {
332
            $this->_parseError(
333
                Messages::expressionLexerSyntaxError(
334
                    $this->_textPos
335
                )
336
            );
337
        }
338
    }
339
340
    /**
341
     * Starting from an identifier, reads alternate sequence of dots and identifiers 
342
     * and returns the text for it
343
     * 
344
     * @return string The dotted identifier starting at the current identifier
345
     */
346
    public function readDottedIdentifier()
347
    {
348
        $this->validateToken(ExpressionTokenId::IDENTIFIER);
349
        $identifier = $this->_token->Text;
350
        $this->nextToken();
351
        while ($this->_token->Id == ExpressionTokenId::DOT) {
352
            $this->nextToken();
353
            $this->validateToken(ExpressionTokenId::IDENTIFIER);
354
            $identifier = $identifier . '.' . $this->_token->Text;
355
            $this->nextToken();
356
        }
357
358
        return $identifier;
359
    }
360
361
    /**
362
     * Check if the parameter ($tokenText) is INF or NaN
363
     * 
364
     * @param string $tokenText Text to look in
365
     * 
366
     * @return boolean true if match found, false otherwise
367
     */
368
    private static function _isInfinityOrNaNDouble($tokenText)
369
    {
370
        if (strlen($tokenText) == 3) {
371
            if ($tokenText[0] == 'I') {
372
                return self::_isInfinityLiteralDouble($tokenText);
373
            } else if ($tokenText[0] == 'N') {
374
                return strncmp($tokenText, ODataConstants::XML_NAN_LITERAL, 3) == 0;
375
            }
376
        }
377
378
        return false;
379
    }
380
381
    /**
382
     * Check if the parameter ($text) is INF
383
     * 
384
     * @param string $text Text to look in
385
     * 
386
     * @return boolean true if match found, false otherwise
387
     */
388
    private static function _isInfinityLiteralDouble($text)
389
    {
390
        return strcmp($text, ODataConstants::XML_INFINITY_LITERAL) == 0;
391
    }
392
393
    /**
394
     * Checks if the parameter ($tokenText) is INFf/INFF or NaNf/NaNF.
395
     * 
396
     * @param string $tokenText Input token
397
     * 
398
     * @return bool true if match found, false otherwise
399
     */
400
    private static function _isInfinityOrNanSingle($tokenText)
401
    {
402
        if (strlen($tokenText) == 4) {
403
            if ($tokenText[0] == 'I') {
404
                return self::_isInfinityLiteralSingle($tokenText);
405
            } else if ($tokenText[0] == 'N') {
406
                return ($tokenText[3] == ExpressionLexer::SINGLE_SUFFIX_LOWER 
407
                    || $tokenText[3] == ExpressionLexer::SINGLE_SUFFIX_UPPER) 
408
                    && strncmp($tokenText, ODataConstants::XML_NAN_LITERAL, 3) == 0;
409
            }
410
        }
411
412
        return false;
413
    }
414
415
    /**     
416
     * Checks whether parameter ($text) EQUALS to 'INFf' or 'INFF' at position
417
     *  
418
     * @param string $text Text to look in
419
     * 
420
     * @return bool true if the substring is equal using an ordinal comparison;
421
     *         false otherwise
422
     */
423
    private static function _isInfinityLiteralSingle($text)
424
    {
425
        return strlen($text) == 4 
426
            && ($text[3] == ExpressionLexer::SINGLE_SUFFIX_LOWER 
427
            || $text[3] == ExpressionLexer::SINGLE_SUFFIX_UPPER) 
428
            && strncmp($text, ODataConstants::XML_INFINITY_LITERAL, 3) == 0;
429
    }
430
431
    /**
432
     * Handles the literals that are prefixed by types.
433
     * This method modified the token field as necessary.
434
     * 
435
     * @return void 
436
     * 
437
     * @throws ODataException
438
     */
439
    private function _handleTypePrefixedLiterals()
440
    {
441
        $id = $this->_token->Id;
442
        if ($id != ExpressionTokenId::IDENTIFIER) {
443
            return;
444
        }
445
446
        $quoteFollows = $this->_ch == '\'';
447
        if (!$quoteFollows) {
448
            return;
449
        }
450
451
        $tokenText = $this->_token->Text;
452
        
453
        if (strcasecmp('datetime', $tokenText) == 0) {
454
            $id = ExpressionTokenId::DATETIME_LITERAL;
455
        } else if (strcasecmp('guid', $tokenText) == 0) {
456
            $id = ExpressionTokenId::GUID_LITERAL;
457
        } else if (strcasecmp('binary', $tokenText) == 0 
458
            || strcasecmp('X', $tokenText) == 0 
459
            || strcasecmp('x', $tokenText) == 0
460
        ) {
461
            $id =  ExpressionTokenId::BINARY_LITERAL;
462
        } else {
463
            return;
464
        }
465
466
        $tokenPos = $this->_token->Position;
467
        do {
468
            $this->_nextChar();
469
        } while ($this->_ch != '\0' && $this->_ch != '\'');
470
471
        if ($this->_ch == '\0') {
472
            $this->_parseError(
473
                Messages::expressionLexerUnterminatedStringLiteral(
474
                    $this->_textPos, $this->_text
0 ignored issues
show
Documentation introduced by
$this->_text is of type array<integer,object<POD...ExpressionParser\char>>, but the function expects a string.

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...
475
                )
476
            );
477
        }
478
479
        $this->_nextChar();
480
        $this->_token->Id = $id;
481
        $this->_token->Text 
482
            = substr($this->_text, $tokenPos, $this->_textPos - $tokenPos);
483
    }
484
485
    /**
486
     * Parses a token that starts with a digit
487
     * 
488
     * @return ExpressionTokenId The kind of token recognized.
489
     */
490
    private function _parseFromDigit()
491
    {        
492
        $result = null;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
493
        $startChar = $this->_ch;
494
        $this->_nextChar();
495
        if ($startChar == '0' && $this->_ch == 'x' || $this->_ch == 'X') {
496
            $result = ExpressionTokenId::BINARY_LITERAL;
497
            do {
498
                $this->_nextChar();
499
            } while (ctype_xdigit($this->_ch));
500
        } else {
501
            $result = ExpressionTokenId::INTEGER_LITERAL;
502
            while (Char::isDigit($this->_ch)) {
503
                $this->_nextChar();
504
            }
505
506
            if ($this->_ch == '.') {
507
                $result = ExpressionTokenId::DOUBLE_LITERAL;
508
                $this->_nextChar();
509
                $this->_validateDigit();
510
511
                do {
512
                    $this->_nextChar();
513
                } while (Char::isDigit($this->_ch));
514
            }
515
516
            if ($this->_ch == 'E' || $this->_ch == 'e') {
517
                $result = ExpressionTokenId::DOUBLE_LITERAL;
518
                $this->_nextChar();
519
                if ($this->_ch == '+' || $this->_ch == '-') {
520
                    $this->_nextChar();
521
                }
522
523
                $this->_validateDigit();
524
                do {
525
                    $this->_nextChar();
526
                } while (Char::isDigit($this->_ch));
527
            }
528
529
            if ($this->_ch == 'M' || $this->_ch == 'm') {
530
                $result = ExpressionTokenId::DECIMAL_LITERAL;
531
                $this->_nextChar();
532
            } else if ($this->_ch == 'd' || $this->_ch == 'D') {
533
                $result = ExpressionTokenId::DOUBLE_LITERAL;
534
                $this->_nextChar();
535
            } else if ($this->_ch == 'L' || $this->_ch == 'l') {
536
                $result = ExpressionTokenId::INT64_LITERAL;
537
                $this->_nextChar();
538
            } else if ($this->_ch == 'f' || $this->_ch == 'F') {
539
                $result = ExpressionTokenId::SINGLE_LITERAL;
540
                $this->_nextChar();
541
            }
542
        }
543
544
        return $result;
545
    }
546
547
    /**
548
     * Parses an identifier by advancing the current character.
549
     * 
550
     * @return void
551
     */
552
    private function _parseIdentifier()
553
    {
554
        do {
555
            $this->_nextChar();
556
        } while (Char::isLetterOrDigit($this->_ch) || $this->_ch == '_');
557
    }
558
    
559
    /**
560
     * Advance to next character.
561
     * 
562
     * @return void
563
     */
564
    private function _nextChar()
565
    {
566
        if ($this->_textPos < $this->_textLen) {
567
            $this->_textPos++;
568
        }
569
570
        $this->_ch 
571
            = $this->_textPos < $this->_textLen 
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->_textPos < $this-...this->_textPos] : '\\0' can also be of type string. However, the property $_ch is declared as type object<POData\UriProcess...\ExpressionParser\char>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
572
             ? $this->_text[$this->_textPos] : '\0';
573
    }
574
575
    /**
576
     * Set the text position.
577
     * 
578
     * @param int $pos Value to position.
579
     * 
580
     * @return void
581
     */
582
    private function _setTextPos($pos)
583
    {
584
        $this->_textPos = $pos;
585
        $this->_ch 
586
            = $this->_textPos < $this->_textLen 
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->_textPos < $this-...this->_textPos] : '\\0' can also be of type string. However, the property $_ch is declared as type object<POData\UriProcess...\ExpressionParser\char>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
587
             ? $this->_text[$this->_textPos] : '\0';
588
    }
589
590
    /**
591
     * Validate current character is a digit.
592
     * 
593
     * @return void
594
     */
595
    private function _validateDigit()
596
    {
597
        if (!Char::isDigit($this->_ch)) {
598
            $this->_parseError(
599
                Messages::expressionLexerDigitExpected(
600
                    $this->_textPos
601
                )
602
            );
603
        }
604
    }
605
606
    /**
607
     * Throws parser error.
608
     * 
609
     * @param string $message The error message.
610
     * 
611
     * @return void
612
     * 
613
     * @throws ODataException
614
     */
615
    private function _parseError($message)
616
    {
617
        throw ODataException::createSyntaxError($message);
618
    }
619
}