Passed
Pull Request — master (#315)
by Théo
02:33
created

AnnotationDumper::transformNodesToString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Annotation;
16
17
use Assert\Assertion;
18
use Hoa\Compiler\Llk\TreeNode;
19
use function array_filter;
20
use function array_map;
21
use function array_shift;
22
use function array_values;
23
use function implode;
24
use function in_array;
25
use function sprintf;
26
use function strtolower;
27
28
/**
29
 * @private
30
 */
31
final class AnnotationDumper
32
{
33
    /**
34
     * Dumps the list of annotations from the given tree.
35
     *
36
     * @param string[] $ignored List of annotations to ignore
37
     *
38
     * @throws InvalidToken
39
     *
40
     * @return string[]
41
     */
42
    public function dump(TreeNode $node, array $ignored): array
43
    {
44
        Assertion::allString($ignored);
45
46
        $ignored = array_map('strtolower', $ignored);
47
48
        if ('#annotations' !== $node->getId()) {
49
            return [];
50
        }
51
52
        return array_values(
53
            array_filter(
54
                $this->transformNodesToString(
55
                    $node->getChildren(),
56
                    $ignored
57
                )
58
            )
59
        );
60
    }
61
62
    /**
63
     * @param TreeNode $nodes
64
     * @param string[] $ignored
65
     *
66
     * @return (string|null)[]
67
     */
68
    private function transformNodesToString(array $nodes, array $ignored): array
69
    {
70
        return array_map(
71
            function (TreeNode $node) use ($ignored): ?string {
72
                return $this->transformNodeToString($node, $ignored);
73
            },
74
            $nodes
75
        );
76
    }
77
78
    /**
79
     * @param string[] $ignored
80
     */
81
    private function transformNodeToString(TreeNode $node, array $ignored): ?string
82
    {
83
        switch ($node->getId()) {
84
            case '#annotation':
85
                Assertion::greaterOrEqualThan($node->getChildrenNumber(), 1);
86
87
                $children = $node->getChildren();
88
89
                /** @var TreeNode $token */
90
                $token = array_shift($children);
91
                $parameters = array_values($children);
92
93
                if ('simple_identifier' === $token->getValueToken()) {
94
                    Assertion::count($parameters, 0);
95
96
                    $tokenValue = $token->getValueValue();
97
98
                    return in_array(strtolower($tokenValue), $ignored, true) ? null : '@'.$tokenValue;
99
                }
100
101
                if ('valued_identifier' === $token->getValueToken()) {
102
                    $transformedChildren = $this->transformNodesToString(
103
                        $parameters,
104
                        $ignored
105
                    );
106
107
                    return sprintf(
108
                        '@%s(%s)',
109
                        $token->getValueValue(),
110
                        implode(
111
                            '',
112
                            $transformedChildren
113
                        )
114
                    );
115
                }
116
117
                throw InvalidToken::createForUnknownType($token);
118
            case 'token':
119
                if (in_array($node->getValueToken(), ['identifier', 'simple_identifier', 'integer', 'float', 'boolean', 'identifier_ns', 'null'], true)) {
120
                    return $node->getValueValue();
121
                }
122
123
                if ('string' === $node->getValueToken()) {
124
                    return sprintf('"%s"', $node->getValueValue());
125
                }
126
127
                if ('valued_identifier' === $node->getValueToken()) {
128
                    return sprintf('%s()', $node->getValueValue());
129
                }
130
131
                throw InvalidToken::createForUnknownType($node);
132
            case '#parameters':
133
                $transformedChildren = $this->transformNodesToString(
134
                    $node->getChildren(),
135
                    $ignored
136
                );
137
138
                return implode(',', $transformedChildren);
139
            case '#named_parameter':
140
            case '#pair_equal':
141
            case '#pair_colon':
142
                Assertion::same($node->getChildrenNumber(), 2);
143
144
                $name = $node->getChild(0);
145
                $parameter = $node->getChild(1);
146
147
                return sprintf(
148
                    '%s%s%s',
149
                    $this->transformNodeToString($name, $ignored),
150
                    '#pair_colon' === $node->getId() ? ':' : '=',
151
                    $this->transformNodeToString($parameter, $ignored)
152
                );
153
154
            case '#value':
155
                Assertion::same($node->getChildrenNumber(), 1);
156
157
                return $this->transformNodeToString($node->getChild(0), $ignored);
158
            case '#string':
159
                Assertion::lessOrEqualThan($node->getChildrenNumber(), 1);
160
161
                return 1 === $node->getChildrenNumber() ? $this->transformNodeToString($node->getChild(0), $ignored) : '""';
162
            case '#list':
163
            case '#map':
164
                $transformedChildren = $this->transformNodesToString(
165
                    $node->getChildren(),
166
                    $ignored
167
                );
168
169
                return sprintf(
170
                    '{%s}',
171
                    implode(
172
                        ',',
173
                        $transformedChildren
174
                    )
175
                );
176
177
            case '#unnamed_parameter':
178
            case '#reference':
179
                Assertion::same($node->getChildrenNumber(), 1);
180
181
                return $this->transformNodeToString($node->getChild(0), $ignored);
182
            case '#constant':
183
                Assertion::same($node->getChildrenNumber(), 2);
184
185
                return sprintf(
186
                    '%s::%s',
187
                    $this->transformNodeToString($node->getChild(0), $ignored),
188
                    $this->transformNodeToString($node->getChild(1), $ignored)
189
                );
190
        }
191
192
        throw InvalidToken::createForUnknownId($node);
193
    }
194
}
195