Passed
Pull Request — master (#184)
by Christoffer
02:18
created

isSpread()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 3
nc 3
nop 3
1
<?php
2
3
namespace Digia\GraphQL\Language;
4
5
/**
6
 * @param int $code
7
 * @return string
8
 */
9
function unicodeChr(int $code)
10
{
11
    if (0x80 > $code %= 0x200000) {
12
        return \chr($code);
13
    }
14
    if (0x800 > $code) {
15
        return \chr(0xC0 | $code >> 6) . \chr(0x80 | $code & 0x3F);
16
    }
17
    if (0x10000 > $code) {
18
        return \chr(0xE0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F);
19
    }
20
21
    return \chr(0xF0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3F) . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F);
22
}
23
24
/**
25
 * @param string $string
26
 * @param string $encoding
27
 * @return int
28
 */
29
function unicodeOrd(string $s)
30
{
31
    $code = ($s = \unpack('C*', \substr($s, 0, 4))) ? $s[1] : 0;
32
33
    if (0xF0 <= $code) {
34
        return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
35
    }
36
    if (0xE0 <= $code) {
37
        return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
38
    }
39
    if (0xC0 <= $code) {
40
        return (($code - 0xC0) << 6) + $s[2] - 0x80;
41
    }
42
43
    return $code;
44
}
45
46
/**
47
 * @param string $string
48
 * @param int    $position
49
 * @return int
50
 */
51
function charCodeAt(string $string, int $position): int
52
{
53
    return unicodeOrd(\mb_substr($string, $position, 1, 'UTF-8'));
54
}
55
56
/**
57
 * @param int $code
58
 * @return string
59
 */
60
function printCharCode(int $code): string
61
{
62
    if ($code === 0x0000) {
63
        return '<EOF>';
64
    }
65
66
    return $code < 0x007F
67
        // Trust JSON for ASCII.
68
        ? \json_encode(unicodeChr($code))
69
        // Otherwise print the escaped form.
70
        : '"\\u' . \dechex($code) . '"';
71
}
72
73
/**
74
 * @param string   $string
75
 * @param int      $start
76
 * @param int|null $end
77
 * @return string
78
 */
79
function sliceString(string $string, int $start, int $end = null): string
80
{
81
    $length = $end !== null ? $end - $start : \mb_strlen($string) - $start;
82
    return \mb_substr($string, $start, $length);
83
}
84
85
/**
86
 * @param int $code
87
 * @return bool
88
 */
89
function isLetter(int $code): bool
90
{
91
    return ($code >= 65 && $code <= 90) || ($code >= 97 && $code <= 122); // a-z or A-Z
92
}
93
94
/**
95
 * @param int $code
96
 * @return bool
97
 */
98
function isNumber(int $code): bool
99
{
100
    return $code >= 48 && $code <= 57; // 0-9
101
}
102
103
/**
104
 * @param int $code
105
 * @return bool
106
 */
107
function isUnderscore(int $code): bool
108
{
109
    return $code === 95; // _
110
}
111
112
/**
113
 * @param int $code
114
 * @return bool
115
 */
116
function isAlphaNumeric(int $code): bool
117
{
118
    return isLetter($code) || isNumber($code) || isUnderscore($code);
119
}
120
121
/**
122
 * @param int $code
123
 * @return bool
124
 */
125
function isLineTerminator(int $code): bool
126
{
127
    return $code === 0x000a || $code === 0x000d;
128
}
129
130
/**
131
 * @param int $code
132
 * @return bool
133
 */
134
function isSourceCharacter(int $code): bool
135
{
136
    return $code < 0x0020 && $code !== 0x0009; // any source character EXCEPT HT (Horizontal Tab)
137
}
138
139
/**
140
 * @param string $body
141
 * @param int    $code
142
 * @param int    $pos
143
 * @return bool
144
 */
145
function isSpread(string $body, int $code, int $pos): bool
146
{
147
    return $code === 46 &&
148
        charCodeAt($body, $pos + 1) === 46 &&
149
        charCodeAt($body, $pos + 2) === 46; // ...
150
}
151
152
/**
153
 * @param string $body
154
 * @param int    $code
155
 * @param int    $pos
156
 * @return bool
157
 */
158
function isString(string $body, int $code, int $pos): bool
159
{
160
    return $code === 34 && charCodeAt($body, $pos + 1) !== 34;
161
}
162
163
/**
164
 * @param string $body
165
 * @param int    $code
166
 * @param int    $pos
167
 * @return bool
168
 */
169
function isTripleQuote(string $body, int $code, int $pos): bool
170
{
171
    return $code === 34 &&
172
        charCodeAt($body, $pos + 1) === 34 &&
173
        charCodeAt($body, $pos + 2) === 34; // """
174
}
175
176
/**
177
 * @param string $body
178
 * @param int    $code
179
 * @param int    $pos
180
 * @return bool
181
 */
182
function isEscapedTripleQuote(
183
    string $body,
184
    int $code,
185
    int $pos
186
): bool {
187
    return $code === 92 &&
188
        charCodeAt($body, $pos + 1) === 34 &&
189
        charCodeAt($body, $pos + 2) === 34 &&
190
        charCodeAt($body, $pos + 3) === 34;
191
}
192
193
/**
194
 * Converts four hexidecimal chars to the integer that the
195
 * string represents. For example, uniCharCode('0','0','0','f')
196
 * will return 15, and uniCharCode('0','0','f','f') returns 255.
197
 *
198
 * @param string $a
199
 * @param string $b
200
 * @param string $c
201
 * @param string $d
202
 * @return string
203
 */
204
function uniCharCode(string $a, string $b, string $c, string $d): string
205
{
206
    return (\dechex(unicodeOrd($a)) << 12) |
207
        (\dechex(unicodeOrd($b)) << 8) |
208
        (\dechex(unicodeOrd($c)) << 4) |
209
        \dechex(unicodeOrd($d));
210
}
211
212
/**
213
 * @param string $value
214
 * @return bool
215
 */
216
function isOperation(string $value): bool
217
{
218
    // TODO: Benchmark
219
    return \in_array($value, ['query', 'mutation', 'subscription'], true);
220
}
221
222
/**
223
 * @param array $location
224
 * @return array|null
225
 */
226
function locationShorthandToArray(array $location): ?array
227
{
228
    return isset($location[0], $location[1]) ? ['line' => $location[0], 'column' => $location[1]] : null;
229
}
230
231
/**
232
 * @param array $locations
233
 * @return array
234
 */
235
function locationsShorthandToArray(array $locations): array
236
{
237
    return array_map(function ($shorthand) {
238
        return locationShorthandToArray($shorthand);
239
    }, $locations);
240
}
241
242
/**
243
 * @param array $array
244
 * @return string
245
 */
246
function block(array $array): string
247
{
248
    return !empty($array) ? "{\n" . indent(implode("\n", $array)) . "\n}" : '';
249
}
250
251
/**
252
 * @param string      $start
253
 * @param null|string $maybeString
254
 * @param null|string $end
255
 * @return string
256
 */
257
function wrap(string $start, ?string $maybeString = null, ?string $end = null): string
258
{
259
    return null !== $maybeString ? ($start . $maybeString . ($end ?? '')) : '';
260
}
261
262
/**
263
 * @param null|string $maybeString
264
 * @return string
265
 */
266
function indent(?string $maybeString): string
267
{
268
    return null !== $maybeString ? '  ' . preg_replace("/\n/", "\n  ", $maybeString) : '';
269
}
270
271
/**
272
 * @param string $str
273
 * @return string
274
 */
275
function dedent(string $str): string
276
{
277
    $trimmed = \preg_replace("/^\n*|[ \t]*$/", '', $str); // Remove leading newline and trailing whitespace
278
    $matches = [];
279
    \preg_match("/^[ \t]*/", $trimmed, $matches); // Figure out indent
280
    $indent = $matches[0];
281
    return \str_replace($indent, '', $trimmed); // Remove indent
282
}
283