Passed
Pull Request — master (#184)
by Christoffer
03:07 queued 59s
created

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