Completed
Push — master ( 332a4c...198c54 )
by Kirill
02:13
created

BaseProcessor::wrap()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 7
nop 2
dl 0
loc 24
rs 8.6026
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\Compiler\Processor;
11
12
use Railt\Lexer\Exception\LexerException;
13
use Railt\Parser\Exception\ParserException;
14
use Railt\Reflection\Contracts\Definition;
15
use Railt\Reflection\Contracts\Definition\TypeDefinition;
16
use Railt\Reflection\Contracts\Dictionary;
17
use Railt\Reflection\Exception\ReflectionException;
18
use Railt\SDL\Compiler\CallStack;
19
use Railt\SDL\Compiler\Pipeline;
20
use Railt\SDL\Exception\CompilerException;
21
use Railt\Reflection\Exception\TypeNotFoundException as TypeNotFoundReflectionException;
22
use Railt\SDL\Exception\SemanticException;
23
use Railt\SDL\Exception\SyntaxException;
24
use Railt\SDL\Exception\TypeNotFoundException;
25
26
/**
27
 * Class BaseProcessor
28
 */
29
abstract class BaseProcessor implements Processable
30
{
31
    /**
32
     * @var int
33
     */
34
    public const PRIORITY_DEFINITION = 0x01;
35
36
    /**
37
     * @var int
38
     */
39
    public const PRIORITY_EXTENSION = 0x02;
40
41
    /**
42
     * @var int
43
     */
44
    public const PRIORITY_INVOCATION = 0x03;
45
46
    /**
47
     * @var Pipeline
48
     */
49
    private $pipeline;
50
51
    /**
52
     * @var CallStack
53
     */
54
    private $stack;
55
56
    /**
57
     * @var Dictionary
58
     */
59
    private $dictionary;
60
61
    /**
62
     * BaseProcessor constructor.
63
     * @param Pipeline $pipeline
64
     * @param CallStack $stack
65
     * @param Dictionary $dictionary
66
     */
67
    public function __construct(Pipeline $pipeline, CallStack $stack, Dictionary $dictionary)
68
    {
69
        $this->stack = $stack;
70
        $this->pipeline = $pipeline;
71
        $this->dictionary = $dictionary;
72
    }
73
74
    /**
75
     * @param string $type
76
     * @param Definition|null $from
77
     * @return TypeDefinition
78
     * @throws TypeNotFoundReflectionException
79
     */
80
    protected function get(string $type, Definition $from = null): TypeDefinition
81
    {
82
        return $this->dictionary->get($type, $from);
83
    }
84
85
    /**
86
     * @param Definition $definition
87
     * @param \Closure $then
88
     * @return mixed
89
     * @throws CompilerException
90
     */
91
    protected function transaction(Definition $definition, \Closure $then)
92
    {
93
        $this->stack->push($definition);
94
95
        $result = $this->wrap($definition, $then);
96
97
        $this->stack->pop();
98
99
        return $result;
100
    }
101
102
    /**
103
     * @param \Closure $then
104
     * @param Definition $def
105
     * @return mixed
106
     * @throws CompilerException
107
     */
108
    private function wrap(Definition $def, \Closure $then)
109
    {
110
        try {
111
            return $then($def);
112
113
        } catch (TypeNotFoundReflectionException $e) {
114
            throw $this->error(new TypeNotFoundException($e->getMessage(), $e->getCode(), $e), $def);
115
116
        } catch (ReflectionException $e) {
117
            throw $this->error(new SemanticException($e->getMessage(), $e->getCode(), $e), $def);
118
119
        } catch (LexerException $e) {
120
            throw $this->error(new SyntaxException($e->getMessage(), $e->getCode(), $e), $def);
121
122
        } catch (ParserException $e) {
123
            throw $this->error(new SyntaxException($e->getMessage(), $e->getCode(), $e), $def);
124
125
        } catch (CompilerException $e) {
126
            throw $e->using($this->stack);
127
128
        } catch (\Throwable $e) {
129
            throw $this->error(new CompilerException($e->getMessage(), $e->getCode(), $e), $def);
130
        }
131
    }
132
133
    /**
134
     * @param CompilerException $error
135
     * @param Definition $in
136
     * @return CompilerException
137
     */
138
    private function error(CompilerException $error, Definition $in): CompilerException
139
    {
140
        return $error->using($this->stack)->in($in);
141
    }
142
143
    /**
144
     * @param \Closure $then
145
     * @return Processable|$this
146
     */
147
    protected function immediately(\Closure $then): Processable
148
    {
149
        $this->pipeline->push(self::PRIORITY_DEFINITION, $then);
150
151
        return $this;
152
    }
153
154
    /**
155
     * @param \Closure $then
156
     * @return Processable|$this
157
     */
158
    protected function deferred(\Closure $then): Processable
159
    {
160
        $this->pipeline->push(self::PRIORITY_EXTENSION, $then);
161
162
        return $this;
163
    }
164
165
    /**
166
     * @param \Closure $then
167
     * @return Processable|$this
168
     */
169
    protected function future(\Closure $then): Processable
170
    {
171
        $this->pipeline->push(self::PRIORITY_INVOCATION, $then);
172
173
        return $this;
174
    }
175
}
176