Passed
Branch master (ef264b)
by Pierrick
01:53
created

AbstractLexer::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 14
ccs 9
cts 9
cp 1
crap 3
rs 10
1
<?php
2
/**
3
 * This file is part of NACL.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @copyright 2019 Nuglif (2018) Inc.
9
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
10
 * @author    Pierrick Charron <[email protected]>
11
 * @author    Charle Demers <[email protected]>
12
 */
13
14
declare(strict_types=1);
15
16
namespace Nuglif\Nacl;
17
18
abstract class AbstractLexer
19
{
20
    const STATE_INITIAL = 0;
21
    const EOF            = '<<EOF>>';
22
23
    private $regexes   = [];
24
    private $tokenMaps = [];
25
26
    private $state = self::STATE_INITIAL;
27
    private $stack = [];
28
29
    protected $line;
30
    protected $content;
31
    protected $count;
32
    protected $filename;
33
34
    abstract protected function getRules();
35
36 590
    public function __construct()
37
    {
38 590
        foreach ($this->getRules() as $state => $patterns) {
39 590
            $eofCallback = false;
40
41 590
            if (isset($patterns[self::EOF])) {
42 590
                $eofCallback = $patterns[self::EOF];
43 590
                unset($patterns[self::EOF]);
44
            }
45
46 590
            $this->regexes[$state]   = $this->computeRegex(array_keys($patterns));
47 590
            $this->tokenMaps[$state] = array_values($patterns);
48
49 590
            $this->tokenMaps[$state][-1] = $eofCallback;
50
        }
51 590
    }
52
53 589
    public function yylex()
54
    {
55
        do {
56 589
            if (isset($this->content[$this->count])) {
57 588
                if (!preg_match($this->regexes[$this->state], $this->content, $matches, 0, $this->count)) {
58
                    $this->error(sprintf('Unexpected character "%s"', $this->content[$this->count]));
59
                }
60 588
                for ($i = 1; '' === $matches[$i]; ++$i) {
61
                }
62 588
                $this->count += strlen($matches[0]);
63 588
                $this->line  += substr_count($matches[0], "\n");
64
            } else {
65 584
                $i       = 0;
66 584
                $matches = [ '' ];
67
            }
68
69 589
            if ($this->tokenMaps[$this->state][$i - 1]) {
70 589
                $callback = $this->tokenMaps[$this->state][$i - 1];
71 589
                if ($token = $callback($matches[$i])) {
72 588
                    return new Token($token, $matches[$i]);
73
                }
74
            }
75 585
        } while ($i);
76
    }
77
78 3
    protected function error($errorMessage)
79
    {
80 3
        throw new LexingException($errorMessage, $this->filename, $this->line);
81
    }
82
83 564
    protected function begin($state)
84
    {
85 564
        $this->state = $state;
86 564
    }
87
88 590
    private function computeRegex($patterns)
89
    {
90 590
        return '#\G(' . implode(')|\G(', $patterns) . ')#A';
91
    }
92
93 589
    public function push($content, $filename = null)
94
    {
95 589
        if (null !== $this->content) {
96 10
            $this->stack[] = [
97 10
                $this->line,
98 10
                $this->content,
99 10
                $this->count,
100 10
                $this->filename,
101
            ];
102
        }
103
104 589
        $this->line     = 1;
105 589
        $this->content  = $content;
106 589
        $this->count    = 0;
107 589
        $this->filename = $filename;
108 589
    }
109
110 581
    public function pop()
111
    {
112 581
        if (empty($this->stack)) {
113 581
            return false;
114
        }
115
116
        [
117 10
            $this->line,
118 10
            $this->content,
119 10
            $this->count,
120 10
            $this->filename
121 10
        ] = array_pop($this->stack);
122
123 10
        return true;
124
    }
125
126 12
    public function getLine()
127
    {
128 12
        return $this->line;
129
    }
130
131 23
    public function getFilename()
132
    {
133 23
        return $this->filename;
134
    }
135
}
136