Completed
Push — master ( 0cd8d9...287b1e )
by Martijn
02:19
created

Repeat::kleene()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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