Passed
Push — master ( a7212f...b9d836 )
by Kirill
01:47
created

Backend::async()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
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\Compiler;
11
12
use Railt\Parser\Ast\RuleInterface;
13
use Railt\Reflection\Contracts\Definition as DefinitionInterface;
14
use Railt\Reflection\Contracts\Document;
15
use Railt\SDL\Builder\BuilderInterface;
16
use Railt\SDL\Builder\Context;
17
use Railt\SDL\Builder\Definition;
18
use Railt\SDL\Builder\Invocation;
19
use Railt\SDL\Exception\TypeException;
20
21
/**
22
 * Class Backend
23
 */
24
class Backend
25
{
26
    /**
27
     * @var string
28
     */
29
    private const ERR_UNSUPPORTED_RULE = '%s is not supported by this compiler';
30
31
    /**
32
     * @var string
33
     */
34
    private const ERR_UNRECOGNIZED_RULE = 'The language rule <%s> is not supported or implemented by this compiler';
35
36
    /**
37
     * @var string[]
38
     */
39
    private const BUILDERS = [
40
        // Root definitions
41
        'SchemaDefinition'    => Definition\SchemaBuilder::class,
42
        'ObjectDefinition'    => Definition\ObjectBuilder::class,
43
        'EnumDefinition'      => Definition\EnumBuilder::class,
44
        'ScalarDefinition'    => Definition\ScalarBuilder::class,
45
        'InputDefinition'     => Definition\InputBuilder::class,
46
        'DirectiveDefinition' => Definition\DirectiveBuilder::class,
47
        'InterfaceDefinition' => Definition\InterfaceBuilder::class,
48
        'UnionDefinition'     => Definition\UnionBuilder::class,
49
        // Invocations
50
        'Directive'           => Invocation\DirectiveBuilder::class,
51
    ];
52
53
    /**
54
     * @var string[]
55
     */
56
    private const UNSUPPORTED_BUILDERS = [
57
        'QueryOperation'        => 'Query expression',
58
        'MutationOperation'     => 'Mutation expression',
59
        'SubscriptionOperation' => 'Subscription expression',
60
        'FragmentDefinition'    => 'Fragment definition',
61
    ];
62
63
    /**
64
     * @var Process
65
     */
66
    private $process;
67
68
    /**
69
     * Backend constructor.
70
     * @param Process $process
71
     */
72
    public function __construct(Process $process)
73
    {
74
        $this->process = $process;
75
    }
76
77
    /**
78
     * @param \Closure $deferred
79
     */
80
    public function async(\Closure $deferred): void
81
    {
82
        $this->process->async($deferred);
83
    }
84
85
    /**
86
     * @param Document $document
87
     * @return Context
88
     */
89
    public function context(Document $document): Context
90
    {
91
        return new Context($document->getFile(), $document);
92
    }
93
94
    /**
95
     * @param Context $context
96
     * @param RuleInterface $ast
97
     * @return Document
98
     * @throws TypeException
99
     */
100
    public function each(Context $context, RuleInterface $ast): Document
101
    {
102
        /** @var \Railt\Reflection\Document $document */
103
        $document = $context->getDocument();
104
105
        foreach ($ast->getChildren() as $child) {
106
            $definition = $this->exec($context, $child);
107
108
            $document->withDefinition($definition);
109
        }
110
111
        return $document;
112
    }
113
114
    /**
115
     * @param Context $context
116
     * @param RuleInterface $ast
117
     * @return DefinitionInterface
118
     * @throws TypeException
119
     */
120
    public function exec(Context $context, RuleInterface $ast): DefinitionInterface
121
    {
122
        if ($builder = self::BUILDERS[$ast->getName()] ?? null) {
123
            return $this->execBuilder(new $builder($context, $ast, $this));
124
        }
125
126
        if ($unsupported = self::UNSUPPORTED_BUILDERS[$ast->getName()] ?? null) {
127
            $exception = new TypeException(\sprintf(self::ERR_UNSUPPORTED_RULE, $unsupported));
128
            $exception->throwsIn($context->getFile(), $ast->getOffset());
129
130
            throw $exception;
131
        }
132
133
        $exception = new TypeException(\sprintf(self::ERR_UNRECOGNIZED_RULE, $ast->getName()));
134
        $exception->throwsIn($context->getFile(), $ast->getOffset());
135
136
        throw $exception;
137
    }
138
139
    /**
140
     * @param BuilderInterface $builder
141
     * @return DefinitionInterface
142
     */
143
    private function execBuilder(BuilderInterface $builder): DefinitionInterface
144
    {
145
        return $builder->build();
146
    }
147
}
148