Completed
Push — master ( 88ff28...2dc58f )
by Kirill
06:03
created

Reader::add()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 7
cp 0
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 6
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;
11
12
use Railt\Compiler\Exception\IncludeNotFoundException;
13
use Railt\Compiler\Exception\UnrecognizedTokenException;
14
use Railt\Compiler\Reader\Grammar;
15
use Railt\Compiler\Reader\Result;
16
use Railt\Io\File;
17
use Railt\Io\Readable;
18
use Railt\Lexer\LexerInterface;
19
use Railt\Lexer\Result\Eoi;
20
use Railt\Lexer\Result\Unknown;
21
use Railt\Lexer\TokenInterface;
22
23
/**
24
 * Class Reader
25
 */
26
class Reader
27
{
28
    /**
29
     * File extensions list
30
     */
31
    private const FILE_EXTENSIONS = [
32
        '',
33
        '.pp',
34
        '.pp2',
35
    ];
36
37
    /**
38
     * @var LexerInterface
39
     */
40
    private $lexer;
41
42
    /**
43
     * @var Grammar
44
     */
45
    private $parser;
46
47
    /**
48
     * Reader constructor.
49
     */
50
    public function __construct()
51
    {
52
        $this->lexer = new Lexer();
53
        $this->parser = new Grammar();
54
    }
55
56
    /**
57
     * @param Readable $input
58
     * @return Result
59
     * @throws \Railt\Io\Exception\ExternalFileException
60
     * @throws \Railt\Io\Exception\NotReadableException
61
     */
62
    public function read(Readable $input): Result
63
    {
64
        return $this->add($input)->getResult();
65
    }
66
67
    /**
68
     * @param Readable $input
69
     * @return Reader
70
     * @throws \Railt\Io\Exception\ExternalFileException
71
     * @throws \Railt\Io\Exception\NotReadableException
72
     */
73
    public function add(Readable $input): Reader
74
    {
75
        /** @var Readable $file */
76
        foreach ($this->lex($input) as $file => $token) {
77
            $this->parser->process($file, $token);
0 ignored issues
show
Documentation introduced by
$file is of type integer|string, but the function expects a object<Railt\Io\Readable>.

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...
78
        }
79
80
        return $this;
81
    }
82
83
    /**
84
     * @return Result
85
     */
86
    public function getResult(): Result
87
    {
88
        return $this->parser->getResult();
89
    }
90
91
    /**
92
     * @param Readable $input
93
     * @return \Traversable
94
     * @throws \Railt\Io\Exception\NotReadableException
95
     * @throws \Railt\Io\Exception\ExternalFileException
96
     */
97
    private function lex(Readable $input): \Traversable
98
    {
99
        $tokens = $this->lexer->lex($input);
100
101
        foreach ($tokens as $token) {
102
            if ($token instanceof Unknown) {
103
                $error = \sprintf('Unrecognized token "%s" (%s)', $token->value(), $token->name());
104
                throw (new UnrecognizedTokenException($error))->throwsIn($input, $token->offset());
105
            }
106
107
            if ($token instanceof Eoi) {
108
                continue;
109
            }
110
111
            if ($token->name() === Lexer::T_INCLUDE) {
112
                yield from $this->lex($this->include($input, $token));
113
                continue;
114
            }
115
116
            yield $input => $token;
117
        }
118
    }
119
120
    /**
121
     * @param Readable $from
122
     * @param TokenInterface $token
123
     * @return Readable
124
     * @throws \Railt\Io\Exception\NotReadableException
125
     * @throws \Railt\Io\Exception\ExternalFileException
126
     */
127
    private function include(Readable $from, TokenInterface $token): Readable
128
    {
129
        $path = \trim($token->value(1), " \t\n\r\0\x0B\"'");
130
131
        foreach (self::FILE_EXTENSIONS as $extension) {
132
            $file = \dirname($from->getPathname()) . '/' . $path . $extension;
133
134
            if (\is_file($file)) {
135
                return File::fromPathname($file);
136
            }
137
        }
138
139
        $error = \sprintf('Could not read external grammar file "%s"', $path);
140
        throw (new IncludeNotFoundException($error))->throwsIn($from, $token->offset());
141
    }
142
}
143