Completed
Push — master ( 598945...316866 )
by Kirill
09:09
created

Reader::addGrammar()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 0
cts 23
cp 0
rs 8.5706
c 0
b 0
f 0
cc 7
nc 7
nop 1
crap 56
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\Compiler\Grammar;
11
12
use Railt\Compiler\Grammar\Delegate\IncludeDelegate;
13
use Railt\Compiler\Grammar\Delegate\RuleDelegate;
14
use Railt\Compiler\Grammar\Delegate\TokenDelegate;
15
use Railt\Io\Readable;
16
use Railt\Lexer\Driver\NativeRegex;
17
use Railt\Lexer\LexerInterface;
18
use Railt\Parser\Ast\RuleInterface;
19
use Railt\Parser\Driver\Llk;
20
use Railt\Parser\Grammar;
21
use Railt\Parser\GrammarInterface;
22
use Railt\Parser\ParserInterface;
23
24
/**
25
 * Class Reader
26
 */
27
class Reader
28
{
29
    /**
30
     * @var Readable
31
     */
32
    private $file;
33
34
    /**
35
     * @var ParserInterface
36
     */
37
    private $pp;
38
39
    /**
40
     * @var LexerInterface
41
     */
42
    private $lexer;
43
44
    /**
45
     * @var GrammarInterface
46
     */
47
    private $grammar;
48
49
    /**
50
     * @var Analyzer
51
     */
52
    private $analyzer;
53
54
    /**
55
     * Reader constructor.
56
     * @param Readable $file
57
     */
58
    public function __construct(Readable $file)
59
    {
60
        $this->file = $file;
61
        $this->pp = new Parser();
62
        $this->lexer = new NativeRegex();
63
        $this->grammar = new Grammar();
64
        $this->analyzer = new Analyzer($this->lexer);
65
66
        $this->boot();
67
    }
68
69
    /**
70
     * @return void
71
     */
72
    private function boot(): void
73
    {
74
        $env = $this->pp->env();
75
76
        $env->share(LexerInterface::class, $this->lexer);
77
        $env->share(GrammarInterface::class, $this->grammar);
78
        $env->share(self::class, $this);
79
    }
80
81
    /**
82
     * @return ParserInterface
83
     * @throws \Railt\Io\Exception\ExternalFileException
84
     * @throws \Railt\Io\Exception\NotReadableException
85
     */
86
    public function getParser(): ParserInterface
87
    {
88
        $this->addGrammar($this->file);
89
90
        foreach ($this->analyzer->analyze() as $rule) {
91
            $this->grammar->addRule($rule);
92
        }
93
94
        return new Llk($this->lexer, $this->grammar);
95
    }
96
97
    /**
98
     * @param Readable $file
99
     * @throws \Railt\Io\Exception\ExternalFileException
100
     * @throws \Railt\Io\Exception\NotReadableException
101
     */
102
    private function addGrammar(Readable $file): void
103
    {
104
        $ast = $this->pp->parse($file);
105
106
        foreach ($ast->getChildren() as $child) {
107
            switch (true) {
108
                case $child instanceof IncludeDelegate:
109
                    $this->addGrammar($child->getPathname($file));
110
                    break;
111
112
                case $child instanceof TokenDelegate:
113
                    $this->lexer->add($child->getTokenName(), $child->getTokenPattern());
114
                    if (! $child->isKept()) {
115
                        $this->lexer->skip($child->getTokenName());
116
                    }
117
                    break;
118
119
                case $child instanceof RuleDelegate:
120
                    $this->analyzer->addRuleDelegate($child);
121
                    if ($child->getDelegate()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $child->getDelegate() of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
122
                        $this->grammar->addDelegate($child->getRuleName(), $child->getDelegate());
0 ignored issues
show
Bug introduced by
The method addDelegate() does not exist on Railt\Parser\GrammarInterface. Did you maybe mean delegate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
123
                    }
124
                    break;
125
            }
126
        }
127
    }
128
}
129