AbstractLexer   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 43
c 2
b 0
f 0
dl 0
loc 111
rs 10
wmc 15

3 Methods

Rating   Name   Duplication   Size   Complexity  
C getNextToken() 0 73 13
A peekNextToken() 0 9 1
A __construct() 0 3 1
1
<?php declare(strict_types=1);
2
/**
3
 * portable-game-notation (https://github.com/chesszebra/portable-game-notation)
4
 *
5
 * @link https://github.com/chesszebra/portable-game-notation for the canonical source repository
6
 * @copyright Copyright (c) 2017 Chess Zebra (https://chesszebra.com)
7
 * @license https://github.com/chesszebra/portable-game-notation/blob/master/LICENSE.md MIT
8
 */
9
10
namespace ChessZebra\PortableGameNotation\Lexer;
11
12
use ChessZebra\PortableGameNotation\Token\Comment;
13
use ChessZebra\PortableGameNotation\Token\EndResult;
14
use ChessZebra\PortableGameNotation\Token\MoveNumber;
15
use ChessZebra\PortableGameNotation\Token\TokenInterface;
16
use ChessZebra\PortableGameNotation\Token\NullMove;
17
use ChessZebra\PortableGameNotation\Token\NumericAnnotationGlyph;
18
use ChessZebra\PortableGameNotation\Token\RecursiveAnnotationVariation;
19
use ChessZebra\PortableGameNotation\Token\StandardAlgebraicNotation;
20
use ChessZebra\PortableGameNotation\Token\TagPair;
21
use ChessZebra\PortableGameNotation\Lexer\Exception\InvalidTokenException;
22
use ChessZebra\StandardAlgebraicNotation\Notation;
23
24
abstract class AbstractLexer implements LexerInterface
25
{
26
    /**
27
     * @var string
28
     */
29
    protected $buffer;
30
31
    /**
32
     * Initializes a new instance of this class.
33
     */
34
    public function __construct()
35
    {
36
        $this->buffer = '';
37
    }
38
39
    /**
40
     * Gets the next token from the lexer.
41
     *
42
     * @return TokenInterface|null
43
     * @throws InvalidTokenException
44
     */
45
    public function getNextToken(): ?TokenInterface
46
    {
47
        if (!$this->buffer) {
48
            return null;
49
        }
50
51
        // Match a tag pair:
52
        if (preg_match('/^\s*\[(.+?)(\s+"(.+?)")?\]/s', $this->buffer, $matches) !== 0) {
53
            $this->buffer = substr($this->buffer, strlen($matches[0]));
54
            return new TagPair($matches[1], $matches[3]);
55
        }
56
57
        // Match a null move
58
        if (preg_match('/^\s*--\s*/', $this->buffer, $matches)) {
59
            $this->buffer = substr($this->buffer, strlen($matches[0]));
60
            return new NullMove();
61
        }
62
63
        // Match a null move
64
        if (preg_match('/^\s*Z0\s*/', $this->buffer, $matches)) {
65
            $this->buffer = substr($this->buffer, strlen($matches[0]));
66
            return new NullMove();
67
        }
68
69
        // Match an end result:
70
        if (preg_match('/^\s*(\*|1-0|0-1|1\/2-1\/2)\s*/', $this->buffer, $matches)) {
71
            $this->buffer = substr($this->buffer, strlen($matches[0]));
72
            return new EndResult($matches[1]);
73
        }
74
75
        // Match a move number:
76
        if (preg_match('/^\s*([0-9]+)\.+\s*/', $this->buffer, $matches)) {
77
            $this->buffer = substr($this->buffer, strlen($matches[0]));
78
            return new MoveNumber((int)$matches[1]);
79
        }
80
81
        // Match a SAN (castling):
82
        if (preg_match('/^\s*(O-O(?:-O)?[\+\-\!\#\=\?]*)\s*/s', $this->buffer, $matches)) {
83
            $this->buffer = substr($this->buffer, strlen($matches[0]));
84
            return new StandardAlgebraicNotation(new Notation($matches[1]));
85
        }
86
87
        // Match a SAN (castling):
88
        if (preg_match('/^\s*(0-0(?:-0)?[\+\-\!\#\=\?]*)\s*/s', $this->buffer, $matches)) {
89
            $this->buffer = substr($this->buffer, strlen($matches[0]));
90
            return new StandardAlgebraicNotation(new Notation($matches[1]));
91
        }
92
93
        // Match a SAN:
94
        if (preg_match('/^\s*([a-zA-Z][a-zA-Z0-9\+\-\!\#\=\?]+)\s*/s', $this->buffer, $matches)) {
95
            $this->buffer = substr($this->buffer, strlen($matches[0]));
96
            return new StandardAlgebraicNotation(new Notation($matches[1]));
97
        }
98
99
        // Match a comment:
100
        if (preg_match('/^\s*\{(.*?)\}\s*/s', $this->buffer, $matches)) {
101
            $this->buffer = substr($this->buffer, strlen($matches[0]));
102
            return new Comment($matches[1]);
103
        }
104
105
        // Match a Recursive Annotation Variation:
106
        if (preg_match('/^\s*[\(|\)]/s', $this->buffer, $matches)) {
107
            $this->buffer = substr($this->buffer, strlen($matches[0]));
108
            return new RecursiveAnnotationVariation(trim($matches[0]) === '(');
109
        }
110
111
        // Match a Numeric Annotation Glyph
112
        if (preg_match('/^\s*\$([0-9]+)\s*/', $this->buffer, $matches)) {
113
            $this->buffer = substr($this->buffer, strlen($matches[0]));
114
            return new NumericAnnotationGlyph((int)trim($matches[1]));
115
        }
116
117
        throw InvalidTokenException::createForBuffer($this->buffer);
118
    }
119
120
    /**
121
     * Peeks in the stream what the next token will be.
122
     *
123
     * @return TokenInterface|null
124
     * @throws InvalidTokenException
125
     */
126
    public function peekNextToken(): ?TokenInterface
127
    {
128
        $buffer = $this->buffer;
129
130
        $token = $this->getNextToken();
131
132
        $this->buffer = $buffer;
133
134
        return $token;
135
    }
136
}
137