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

AbstractLexer   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Test Coverage

Coverage 96.49%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 57
c 1
b 0
f 0
dl 0
loc 116
ccs 55
cts 57
cp 0.9649
rs 10
wmc 19

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 3
A getLine() 0 3 1
B yylex() 0 23 7
A error() 0 3 1
A push() 0 15 2
A getFilename() 0 3 1
A begin() 0 3 1
A computeRegex() 0 3 1
A pop() 0 14 2
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