Repeat::parse()   B
last analyzed

Complexity

Conditions 8
Paths 12

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 19
nc 12
nop 3
dl 0
loc 31
ccs 20
cts 20
cp 1
crap 8
rs 8.4444
c 1
b 0
f 0
1
<?php
2
3
namespace Vanderlee\Comprehend\Parser\Structure;
4
5
use InvalidArgumentException;
6
use Vanderlee\Comprehend\Core\Context;
7
use Vanderlee\Comprehend\Match\Success;
8
use Vanderlee\Comprehend\Parser\Parser;
9
10
/**
11
 * Description of RepeatParser.
12
 *
13
 * @author Martijn
14
 */
15
class Repeat extends Parser
16
{
17
    use SpacingTrait;
18
19
    //use GreedyTrait;
20
21
    private $parser;
22
    private $min;
23
    private $max;
24
25 42
    public function __construct($parser, $min = 0, $max = null)
26
    {
27 42
        $this->parser = $this->getArgument($parser);
28 42
        $this->min = $min;
29 42
        $this->max = $max;
30
31 42
        if ($this->max !== null && $this->max < $this->min) {
32 1
            throw new InvalidArgumentException('Invalid repeat range specified');
33
        }
34 41
    }
35
36 9
    public static function plus($parser)
37
    {
38 9
        return new self($parser, 1, null);
39
    }
40
41 9
    public static function star($parser)
42
    {
43 9
        return new self($parser, 0, null);
44
    }
45
46 9
    public static function optional($parser)
47
    {
48 9
        return new self($parser, 0, 1);
49
    }
50
51 1
    public static function exact($parser, $times)
52
    {
53 1
        return new self($parser, $times, $times);
54
    }
55
56 150
    protected function parse(&$input, $offset, Context $context)
57
    {
58 150
        $childMatches = [];
59
60 150
        $this->pushSpacer($context);
61
62 150
        $length = 0;
63
        do {
64
            // No skipping at very start
65 150
            $skip = $length > 0
66 104
                ? $context->skipSpacing($input, $offset + $length)
67 150
                : 0;
68
69 150
            if ($skip === false) {
70 1
                break;
71
            }
72
73 150
            $match = $this->parser->parse($input, $offset + $length + $skip, $context);
74 150
            if ($match instanceof Success) {
75 125
                $length += $skip + $match->length;
76 125
                $childMatches[] = $match;
77
            }
78 150
        } while (($match instanceof Success)
79 125
        && ($this->max === null
80 150
            || count($childMatches) < $this->max));
81
82 150
        $this->popSpacer($context);
83
84 150
        return count($childMatches) >= $this->min
85 133
            ? $this->success($input, $offset, $length, $childMatches)
86 150
            : $this->failure($input, $offset, $length);
87
    }
88
89 90
    public function __toString()
90
    {
91
        // Output ABNF formatting
92
93 90
        $min = $this->min > 0
94 70
            ? $this->min
95 90
            : '';
96 90
        $max = $this->max === null
97 44
            ? ''
98 90
            : $this->max;
99
100 90
        return ($min === $max
101 42
                ? $min
102 90
                : ($min . '*' . $max)) . $this->parser;
103
    }
104
}
105