Completed
Push — master ( 1e8320...6a42b9 )
by Kirill
03:17
created

Compiler::parse()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3.1852

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 11
ccs 2
cts 6
cp 0.3333
crap 3.1852
rs 9.9
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;
11
12
use Railt\Io\Readable;
13
use Railt\Parser\Ast\RuleInterface;
14
use Railt\Parser\Exception\UnexpectedTokenException;
15
use Railt\Parser\Exception\UnrecognizedTokenException;
16
use Railt\Reflection\Contracts\Definition;
17
use Railt\Reflection\Contracts\Dictionary;
18
use Railt\Reflection\Contracts\Document as DocumentInterface;
19
use Railt\Reflection\Contracts\Reflection as ReflectionInterface;
20
use Railt\Reflection\Dictionary\CallbackDictionary;
21
use Railt\Reflection\Document;
22
use Railt\Reflection\Reflection;
23
use Railt\SDL\Compiler\Factory;
24
use Railt\SDL\Compiler\Parser;
25
use Railt\SDL\Exception\CompilerException;
26
use Railt\SDL\Exception\SyntaxException;
27
28
/**
29
 * Class Compiler
30
 */
31
class Compiler
32
{
33
    /**
34
     * @var ReflectionInterface
35
     */
36
    private $reflection;
37
38
    /**
39
     * @var Dictionary|CallbackDictionary
40
     */
41
    private $dictionary;
42
43
    /**
44
     * @var Parser
45
     */
46
    private $parser;
47
48
    /**
49
     * Compiler constructor.
50
     * @throws \Railt\Io\Exception\ExternalFileException
51
     * @throws \Railt\Reflection\Exception\TypeConflictException
52
     */
53 1
    public function __construct()
54
    {
55 1
        $this->parser     = new Parser();
56 1
        $this->dictionary = new CallbackDictionary();
57 1
        $this->reflection = new Reflection($this->dictionary);
58 1
    }
59
60
    /**
61
     * @param \Closure $then
62
     */
63
    public function autoload(\Closure $then): void
64
    {
65
        $this->dictionary->onTypeNotFound(function (string $type, ?Definition $from) use ($then): void {
0 ignored issues
show
Bug introduced by
The method onTypeNotFound does only exist in Railt\Reflection\Dictionary\CallbackDictionary, but not in Railt\Reflection\Contracts\Dictionary.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
66
            if (($file = $then($type, $from)) instanceof Readable) {
67
                $this->compile($file);
68
            }
69
        });
70
    }
71
72
    /**
73
     * @param Readable $file
74
     * @return DocumentInterface
75
     * @throws \Railt\Io\Exception\ExternalFileException
76
     */
77 1
    public function compile(Readable $file): DocumentInterface
78
    {
79 1
        $ast = $this->parse($file);
80
81 1
        $document  = new Document($this->reflection, $file);
0 ignored issues
show
Compatibility introduced by
$this->reflection of type object<Railt\Reflection\Contracts\Reflection> is not a sub-type of object<Railt\Reflection\Reflection>. It seems like you assume a concrete implementation of the interface Railt\Reflection\Contracts\Reflection to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
82 1
        $processor = new Factory($document, $ast);
83
84 1
        return $processor->process();
85
    }
86
87
    /**
88
     * @param Readable $file
89
     * @return RuleInterface
90
     * @throws CompilerException
91
     */
92 1
    private function parse(Readable $file): RuleInterface
93
    {
94
        try {
95 1
            return $this->parser->parse($file);
96
        } catch (UnexpectedTokenException | UnrecognizedTokenException $e) {
97
            $error = new SyntaxException($e->getMessage());
98
            $error->throwsIn($file, $e->getLine(), $e->getColumn());
99
100
            throw $error;
101
        }
102
    }
103
}
104