Test Failed
Push — master ( b7ab7b...94ee03 )
by Kirill
02:59
created

ImportBuilder::tryOpen()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 16
ccs 0
cts 14
cp 0
crap 12
rs 9.7333
c 0
b 0
f 0
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\SDL\Frontend\Builder\Instruction;
11
12
use Railt\Io\Exception\NotReadableException;
13
use Railt\Io\File;
14
use Railt\Io\Readable;
15
use Railt\Parser\Ast\RuleInterface;
16
use Railt\SDL\Exception\FileNotReadableException;
17
use Railt\SDL\Exception\InvalidArgumentException;
18
use Railt\SDL\Frontend\Builder\BaseBuilder;
19
use Railt\SDL\Frontend\Context\ContextInterface;
20
use Railt\SDL\IR\SymbolTable\ValueInterface;
21
use Railt\SDL\IR\Type;
22
23
/**
24
 * Class IncludeBuilder
25
 */
26
class ImportBuilder extends BaseBuilder
27
{
28
    /**
29
     * @param RuleInterface $rule
30
     * @return bool
31
     */
32
    public function match(RuleInterface $rule): bool
33
    {
34
        return $rule->getName() === 'ImportDefinition';
35
    }
36
37
    /**
38
     * @param ContextInterface $ctx
39
     * @param RuleInterface $rule
40
     * @return mixed|\Generator|void
41
     */
42
    public function reduce(ContextInterface $ctx, RuleInterface $rule)
43
    {
44
        /** @var ValueInterface $value */
45
        $value = yield $rule->getChild(0);
46
47
        if ($value->getType()->typeOf(Type::string())) {
0 ignored issues
show
Bug introduced by
It seems like \Railt\SDL\IR\Type::string() targeting Railt\SDL\IR\Type\TypeCo...eConstructors::string() can also be of type object<Railt\SDL\IR\Type...untimeTypeConstructors>; however, Railt\SDL\IR\Type\TypeInterface::typeOf() does only seem to accept object<Railt\SDL\IR\Type\TypeInterface>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
48
            yield from $this->load($this->include($ctx, (string)$value->getValue()));
49
        }
50
51
        $error = 'Argument of include should be a string, but %s given';
52
        throw new InvalidArgumentException(\sprintf($error, $value->getType()));
53
    }
54
55
    /**
56
     * @param ContextInterface $ctx
57
     * @param string $inclusion
58
     * @return Readable
59
     */
60
    private function include(ContextInterface $ctx, string $inclusion): Readable
61
    {
62
        return $this->tryOpen($ctx, $inclusion);
63
    }
64
65
    /**
66
     * @param ContextInterface $ctx
67
     * @param string $inclusion
68
     * @return Readable
69
     * @throws FileNotReadableException
70
     */
71
    private function tryOpen(ContextInterface $ctx, string $inclusion): Readable
72
    {
73
        $pathname = $this->getPathname($ctx->getFile(), $inclusion);
74
75
        if ($ctx->getFile()->isFile()) {
76
            try {
77
                return File::fromPathname($pathname);
78
            } catch (NotReadableException $e) {
79
                $error = 'File "%s" not found or not readable';
80
                throw new FileNotReadableException(\sprintf($error, $pathname), $e->getCode());
81
            }
82
        }
83
84
        $error = 'It is impossible to include an external file "%s" inside a non-physical file';
85
        throw new FileNotReadableException(\sprintf($error, $inclusion));
86
    }
87
88
    /**
89
     * @param Readable $file
90
     * @param string $inclusion
91
     * @return string
92
     */
93
    private function getPathname(Readable $file, string $inclusion): string
94
    {
95
        if (\in_array($inclusion[0], ['/', \DIRECTORY_SEPARATOR], true)) {
96
            return $inclusion;
97
        }
98
99
        $pathname = \dirname($file->getPathname()) . \DIRECTORY_SEPARATOR . $inclusion;
100
        $pathname = \str_replace('/./', '/', $pathname);
101
102
        return $pathname;
103
    }
104
}
105