Completed
Pull Request — master (#532)
by Daniel
04:18
created

SymmetricParenthesesChunks   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 54
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 54
rs 10
c 0
b 0
f 0
wmc 10
lcom 0
cbo 1

3 Methods

Rating   Name   Duplication   Size   Complexity  
A chunk() 0 4 1
B makeChunks() 0 39 8
A filterNonNull() 0 6 1
1
<?php
2
3
namespace Coyote\Services\Parser\Parsers\Parentheses;
4
5
use Tests\Feature\Services\Parser\Parsers\Parentheses\SymmetricParenthesesChunksTest;
6
7
/**
8
 * If you read {@link SymmetricParenthesesChunksTest} you will see examples, of how this
9
 * class works.
10
 *
11
 * This class responsibility is to split an arbitrary string into chunks, by parentheses.
12
 * The resulting chunks will always have:
13
 *  - Symmetric parentheses (e.g. `()`, `(())`, `()()`, etc.)
14
 *  - Mismatched parentheses (e.g. `(()`, `())`, etc.)
15
 * But will never have asymmetric parentheses (e.g. `)(`, etc.)
16
 *
17
 * The resulting chunks are used in {@link ParenthesesParser} to "comb" them into actual
18
 * valid parenthesis expressions. This class can be thought of as an internal implementation.
19
 */
20
class SymmetricParenthesesChunks
21
{
22
    public function chunk(string $content): array
23
    {
24
        return $this->filterNonNull($this->makeChunks(pattern('([()])')->split($content)));
25
    }
26
27
    private function makeChunks(array $elements): array
28
    {
29
        $stack = [];
30
        $current = null;
31
        $nestLevel = 0;
32
        foreach ($elements as $element) {
33
            if ($element === '') {
34
                continue;
35
            }
36
            if ($element === '(') {
37
                $nestLevel++;
38
                $stack[] = $current;
39
                $current = $element;
40
                continue;
41
            }
42
            if ($element === ')') {
43
                $nestLevel--;
44
                if ($nestLevel > 0) {
45
                    $current .= $element;
46
                    continue;
47
                }
48
                if ($nestLevel === 0) {
49
                    $stack[] = $current . $element;
50
                    $current = null;
51
                    continue;
52
                }
53
                if ($nestLevel < 0) {
54
                    $stack[] = $current;
55
                    $stack[] = $element;
56
                    $current = null;
57
                    $nestLevel = 0;
58
                }
59
                continue;
60
            }
61
            $current .= $element;
62
        }
63
        $stack[] = $current;
64
        return $stack;
65
    }
66
67
    private function filterNonNull(array $elements): array
68
    {
69
        return array_values(array_filter($elements, function (?string $element) {
70
            return $element !== null;
71
        }));
72
    }
73
}
74