Passed
Push — master ( 9cb16b...0651df )
by Martijn
02:32
created

Implementation::parse()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 3
dl 0
loc 19
ccs 12
cts 12
cp 1
crap 4
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace Vanderlee\Comprehend\Builder;
4
5
use Exception;
6
use InvalidArgumentException;
7
use Vanderlee\Comprehend\Core\Context;
8
use Vanderlee\Comprehend\Match\Failure;
9
use Vanderlee\Comprehend\Match\Match;
10
use Vanderlee\Comprehend\Match\Success;
11
use Vanderlee\Comprehend\Parser\Parser;
12
13
/**
14
 * Description of Factory
15
 *
16
 * @author Martijn
17
 */
18
class Implementation extends Parser
19
{
20
21
    /**
22
     * @var Parser|callable|null
23
     */
24
    private $parser = null;
25
26
    /**
27
     * @var callable|null
28
     */
29
    public $validator = null;
30
31
    /**
32
     * @var callable|null
33
     */
34
    public $processor    = null;
35
    public $processorKey = null;
36
37
    /**
38
     * @var Definition
39
     */
40
    private $definition = null;
41
    private $arguments  = null;
42
43
    /**
44
     * @param Definition $definition
45
     * @param array $arguments
46
     */
47 38
    public function __construct(Definition &$definition, array $arguments = [])
48
    {
49 38
        $this->definition = $definition;
50 38
        $this->arguments  = $arguments;
51 38
    }
52
53
    /**
54
     * @param $name
55
     * @return callable|null|Parser
56
     */
57 5
    public function __get($name)
58
    {
59 5
        if ($name === 'parser') {
60
            try {
61 4
                $this->build();
62 2
            } catch (Exception $exception) {
63 2
                $this->parser = null;
64
            }
65
66 4
            return $this->parser;
67
        }
68
69 1
        throw new InvalidArgumentException("Property `{$name}` does not exist");
70
    }
71
72
    /**
73
     * @throws \Exception
74
     */
75 167
    private function build()
76
    {
77 167
        if ($this->parser === null) {
78 163
            $this->parser = $this->definition->generator;
79 163
            if (!$this->parser instanceof Parser) {
80 18
                if (!is_callable($this->parser)) {
81 5
                    throw new Exception('Parser not defined');
82
                }
83
84 13
                $parser       = ($this->parser);
85 13
                $this->parser = $parser(...$this->arguments);
86
            }
87
        }
88 162
    }
89
90
    /**
91
     * Get and validate a set of results for the local scope of this parser
92
     *
93
     * @param Match $match
94
     * @param string $text
95
     * @return array|bool
96
     */
97 160
    private function validateResults(Match $match, $text)
98
    {
99 160
        $results = [];
100 160
        if ($match instanceof Success) {
101 125
            $results = $match->results;
102 125
            foreach ($this->definition->validators as $validator) {
103 4
                if (!($validator($text, $results))) {
104 4
                    return false;
105
                }
106
            }
107
        }
108
109 160
        return $results;
110
    }
111
112
    /**
113
     * Apply a callback to handle all processors.
114
     *
115
     * @param Success $match
116
     * @param array $localResults
117
     * @return Success
118
     */
119 125
    private function addProcessors(Success $match, $localResults) {
120 125
        if (!empty($this->definition->processors)) {
121 1
            $processors = $this->definition->processors;
122 1
            $match->addResultCallback(function (&$results) use ($processors, $localResults) {
123 1
                foreach ($processors as $key => $processor) {
124 1
                    $results[$key] = $processor($localResults, $results);
125
                }
126 1
            });
127
        }
128
129 125
        return $match;
130
    }
131
132
    /**
133
     * @param string $input
134
     * @param int $offset
135
     * @param Context $context
136
     * @return Failure|Success
137
     * @throws Exception
138
     */
139 162
    protected function parse(&$input, $offset, Context $context)
140
    {
141 162
        $this->build();
142
143 160
        $match = $this->parser->parse($input, $offset, $context);
144
145 160
        $results = $this->validateResults($match, substr($input, $offset, $match->length));
146 160
        if ($results === false) {
0 ignored issues
show
introduced by
The condition $results === false is always false.
Loading history...
147 4
            return $this->failure($input, $offset, $match->length);
148
        }
149
150 160
        if ($match instanceof Success) {
151 125
            $successes = empty($this->definition->processors)
152 124
                ? $match
153 125
                : [];
154 125
            return $this->addProcessors($this->success($input, $offset, $match->length, $successes), $results);
155
        }
156
157 72
        return $this->failure($input, $offset, $match->length);
158
    }
159
160
    /**
161
     * @return string
162
     */
163 132
    public function __toString()
164
    {
165
        try {
166 132
            $this->build();
167 1
        } catch (Exception $e) {
168
            // ignore
169
        }
170
171 132
        return (string)$this->parser;
172
    }
173
174
}
175