Implementation   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 47
dl 0
loc 149
ccs 52
cts 52
cp 1
rs 10
c 0
b 0
f 0
wmc 21

7 Methods

Rating   Name   Duplication   Size   Complexity  
A validateResults() 0 13 4
A addProcessors() 0 12 3
A __construct() 0 4 1
A build() 0 11 4
A __toString() 0 9 2
A __get() 0 13 3
A parse() 0 20 4
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\AbstractMatch;
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
     * @var Parser|callable|null
22
     */
23
    private $parser = null;
24
25
    /**
26
     * @var Definition
27
     */
28
    private $definition;
29
    private $arguments;
30
31
    /**
32
     * @param Definition $definition
33
     * @param array $arguments
34
     */
35 38
    public function __construct(Definition $definition, array $arguments = [])
36
    {
37 38
        $this->definition = $definition;
38 38
        $this->arguments = $arguments;
39 38
    }
40
41
    /**
42
     * @param $name
43
     *
44
     * @return callable|null|Parser
45
     */
46 5
    public function __get($name)
47
    {
48 5
        if ($name === 'parser') {
49
            try {
50 4
                $this->build();
51 2
            } catch (Exception $exception) {
52 2
                $this->parser = null;
53
            }
54
55 4
            return $this->parser;
56
        }
57
58 1
        throw new InvalidArgumentException('Property `' . $name . '` does not exist');
59
    }
60
61
    /**
62
     * @throws Exception
63
     */
64 167
    private function build()
65
    {
66 167
        if ($this->parser === null) {
67 163
            $this->parser = $this->definition->generator;
68 163
            if (!$this->parser instanceof Parser) {
69 18
                if (!is_callable($this->parser)) {
70 5
                    throw new Exception('Parser not defined');
71
                }
72
73 13
                $parser = ($this->parser);
74 13
                $this->parser = $parser(...$this->arguments);
75
            }
76
        }
77 162
    }
78
79
    /**
80
     * Get and validate a set of results for the local scope of this parser.
81
     *
82
     * @param AbstractMatch $match
83
     * @param string $text
84
     *
85
     * @return array|false
86
     */
87 160
    private function validateResults(AbstractMatch $match, $text)
88
    {
89 160
        $results = [];
90 160
        if ($match instanceof Success) {
91 125
            $results = $match->results;
92 125
            foreach ($this->definition->validators as $validator) {
93 4
                if (!($validator($text, $results))) {
94 4
                    return false;
95
                }
96
            }
97
        }
98
99 160
        return $results;
100
    }
101
102
    /**
103
     * Apply a callback to handle all processors.
104
     *
105
     * @param Success $match
106
     * @param array $localResults
107
     *
108
     * @return Success
109
     */
110 125
    private function addProcessors(Success $match, $localResults)
111
    {
112 125
        if (!empty($this->definition->processors)) {
113 1
            $processors = $this->definition->processors;
114 1
            $match->addResultCallback(function (&$results) use ($processors, $localResults) {
115 1
                foreach ($processors as $key => $processor) {
116 1
                    $results[$key] = $processor($localResults, $results);
117
                }
118 1
            });
119
        }
120
121 125
        return $match;
122
    }
123
124
    /**
125
     * @param string $input
126
     * @param int $offset
127
     * @param Context $context
128
     *
129
     * @return Failure|Success
130
     * @throws Exception
131
     *
132
     */
133 162
    protected function parse(&$input, $offset, Context $context)
134
    {
135 162
        $this->build();
136
137 160
        $match = $this->parser->parse($input, $offset, $context);
138
139 160
        $results = $this->validateResults($match, substr($input, $offset, $match->length));
140 160
        if ($results === false) {
141 4
            return $this->failure($input, $offset, $match->length);
142
        }
143
144 160
        if ($match instanceof Success) {
145 125
            $successes = empty($this->definition->processors)
146 124
                ? $match
147 125
                : [];
148
149 125
            return $this->addProcessors($this->success($input, $offset, $match->length, $successes), $results);
150
        }
151
152 72
        return $this->failure($input, $offset, $match->length);
153
    }
154
155
    /**
156
     * @return string
157
     */
158 132
    public function __toString()
159
    {
160
        try {
161 132
            $this->build();
162 1
        } catch (Exception $e) {
163
            // ignore
164
        }
165
166 132
        return (string)$this->parser;
167
    }
168
}
169