Skip to content

Commit 0c5c0ea

Browse files
committed
Simplify parsing
1 parent 7d457b3 commit 0c5c0ea

File tree

6 files changed

+45
-54
lines changed

6 files changed

+45
-54
lines changed

src/InnerList.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,10 @@ public static function fromList(iterable $members, iterable $parameters = []): s
4747
return $instance;
4848
}
4949

50-
private static function filterMember(StructuredField|ByteSequence|Token|DateTimeInterface|Stringable|bool|int|float|string $member): Item
50+
private static function filterMember(Item|ByteSequence|Token|DateTimeInterface|Stringable|bool|int|float|string $member): Item
5151
{
5252
return match (true) {
5353
$member instanceof Item => $member,
54-
$member instanceof StructuredField => throw new InvalidArgument('Expecting a "'.Item::class.'" instance; received a "'.$member::class.'" instance instead.'),
5554
default => Item::from($member),
5655
};
5756
}

src/Item.php

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -162,25 +162,25 @@ public static function fromHttpValue(Stringable|string $httpValue): self
162162
{
163163
$itemString = trim((string) $httpValue, ' ');
164164

165-
[$value, $parameters] = match (true) {
165+
[$value, $offset] = match (true) {
166166
1 === preg_match("/[\r\t\n]|[^\x20-\x7E]/", $itemString),
167167
'' === $itemString => throw new SyntaxError('The HTTP textual representation "'.$httpValue.'" for an item contains invalid characters.'),
168168
'"' === $itemString[0] => self::parseString($itemString),
169-
':' === $itemString[0] => self::parseBytesSequence($itemString),
170-
'?' === $itemString[0] => self::parseBoolean($itemString),
169+
':' === $itemString[0] => self::parseByteSequence($itemString),
170+
'?' === $itemString[0] => Parser::parseBoolean($itemString),
171171
'@' === $itemString[0] => self::parseDate($itemString),
172172
1 === preg_match('/^(-?\d)/', $itemString) => self::parseNumber($itemString),
173173
1 === preg_match('/^([a-z*])/i', $itemString) => self::parseToken($itemString),
174174
default => throw new SyntaxError('The HTTP textual representation "'.$httpValue.'" for an item is unknown or unsupported.'),
175175
};
176176

177-
return new self($value, Parameters::fromHttpValue($parameters));
177+
return new self($value, Parameters::fromHttpValue(substr($itemString, $offset)));
178178
}
179179

180180
/**
181181
* Parses an HTTP textual representation of an Item as a Token Data Type.
182182
*
183-
* @return array{0:Token, 1:string}
183+
* @return array{0:Token, 1:int}
184184
*/
185185
private static function parseToken(string $string): array
186186
{
@@ -195,42 +195,28 @@ private static function parseToken(string $string): array
195195

196196
return [
197197
Token::fromString($found['token']),
198-
substr($string, strlen($found['token'])),
198+
strlen($found['token']),
199199
];
200200
}
201201

202-
/**
203-
* Parses an HTTP textual representation of an Item as a Boolean Data Type.
204-
*
205-
* @return array{0:bool, 1:string}
206-
*/
207-
private static function parseBoolean(string $string): array
208-
{
209-
if (1 !== preg_match('/^\?[01]/', $string)) {
210-
throw new SyntaxError("The HTTP textual representation \"$string\" for a Boolean contains invalid characters.");
211-
}
212-
213-
return [$string[1] === '1', substr($string, 2)];
214-
}
215-
216202
/**
217203
* Parses an HTTP textual representation of an Item as a Byte Sequence Type.
218204
*
219-
* @return array{0:ByteSequence, 1:string}
205+
* @return array{0:ByteSequence, 1:int}
220206
*/
221-
private static function parseBytesSequence(string $string): array
207+
private static function parseByteSequence(string $string): array
222208
{
223209
if (1 !== preg_match('/^:(?<bytes>[a-z\d+\/=]*):/i', $string, $matches)) {
224210
throw new SyntaxError("The HTTP textual representation \"$string\" for a Byte sequence contains invalid characters.");
225211
}
226212

227-
return [ByteSequence::fromEncoded($matches['bytes']), substr($string, strlen($matches[0]))];
213+
return [ByteSequence::fromEncoded($matches['bytes']), strlen($matches[0])];
228214
}
229215

230216
/**
231217
* Parses an HTTP textual representation of an Item as a Data Type number.
232218
*
233-
* @return array{0:int|float, 1:string}
219+
* @return array{0:int|float, 1:int}
234220
*/
235221
private static function parseNumber(string $string): array
236222
{
@@ -249,31 +235,35 @@ private static function parseNumber(string $string): array
249235
default => throw new SyntaxError("The HTTP textual representation \"$string\" for a Number contain too many digits."),
250236
};
251237

252-
return [$number, substr($string, strlen($found['number']))];
238+
return [$number, strlen($found['number'])];
253239
}
254240

255241
/**
256242
* Parses an HTTP textual representation of an Item as a Data Type number.
257243
*
258-
* @return array{0:DateTimeImmutable, 1:string}
244+
* @throws SyntaxError
245+
*
246+
* @return array{0:DateTimeImmutable, 1:int}
259247
*/
260248
private static function parseDate(string $string): array
261249
{
262-
[$timestamp, $parameters] = self::parseNumber(substr($string, 1));
250+
[$timestamp, $offset] = self::parseNumber(substr($string, 1));
263251
if (!is_int($timestamp)) {
264-
throw new SyntaxError("The HTTP textual representation \"$string\" for a date contains invalid characters.");
252+
throw new SyntaxError("The HTTP textual representation \"$string\" for a Date contains invalid characters.");
265253
}
266254

267255
return [
268256
(new DateTimeImmutable('NOW', new DateTimeZone('UTC')))->setTimestamp($timestamp),
269-
$parameters,
257+
++$offset,
270258
];
271259
}
272260

273261
/**
274262
* Parses an HTTP textual representation of an Item as a String Data Type.
275263
*
276-
* @return array{0:string, 1:string}
264+
* @throws SyntaxError
265+
*
266+
* @return array{0:string, 1:int}
277267
*/
278268
private static function parseString(string $string): array
279269
{
@@ -286,7 +276,7 @@ private static function parseString(string $string): array
286276
$string = substr($string, 1);
287277

288278
if ($char === '"') {
289-
return [$returnValue, $string];
279+
return [$returnValue, strlen($originalString) - strlen($string)];
290280
}
291281

292282
if ($char !== '\\') {

src/OrderedList.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,10 @@ public static function fromList(iterable $members): self
5050
return $instance;
5151
}
5252

53-
private static function filterMember(StructuredField|ByteSequence|Token|DateTimeInterface|Stringable|bool|int|float|string $member): InnerList|Item
53+
private static function filterMember(Item|InnerList|ByteSequence|Token|DateTimeInterface|Stringable|bool|int|float|string $member): InnerList|Item
5454
{
5555
return match (true) {
5656
$member instanceof InnerList, $member instanceof Item => $member,
57-
$member instanceof StructuredField => throw new InvalidArgument('Expecting a "'.Item::class.'" or a "'.InnerList::class.'" instance; received a "'.$member::class.'" instead.'),
5857
default => Item::from($member),
5958
};
6059
}

src/Parameters.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,10 @@ private static function filterMember(Item $item): Item
9696
throw new ForbiddenStateError('Parameters instances can only contain bare items.');
9797
}
9898

99-
private static function formatMember(StructuredField|ByteSequence|Token|DateTimeInterface|Stringable|bool|int|float|string $member): Item
99+
private static function formatMember(Item|ByteSequence|Token|DateTimeInterface|Stringable|bool|int|float|string $member): Item
100100
{
101101
return match (true) {
102102
$member instanceof Item => self::filterMember($member),
103-
$member instanceof StructuredField => throw new InvalidArgument('Expecting a "'.Item::class.'" instance; received "'.$member::class.'" instead.'),
104103
default => Item::from($member),
105104
};
106105
}

src/ParametersTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Bakame\Http\StructuredFields;
66

7+
use TypeError;
78
use function iterator_to_array;
89

910
/**
@@ -286,7 +287,7 @@ public function it_fails_to_fetch_an_value_using_an_integer(): void
286287
/** @test */
287288
public function it_throws_if_the_structured_field_is_not_supported(): void
288289
{
289-
$this->expectException(InvalidArgument::class);
290+
$this->expectException(TypeError::class);
290291

291292
Parameters::fromPairs([['foo', InnerList::from(42)]]); // @phpstan-ignore-line
292293
}

src/Parser.php

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,9 @@ private static function parseItemOrInnerList(string $httpValue): array
151151
return self::parseInnerListValue($httpValue);
152152
}
153153

154-
[$value, $offset] = self::parseBareItem($httpValue);
155-
$remainder = substr($httpValue, $offset);
154+
[$item, $remainder] = self::parseItem($httpValue);
156155

157-
[$parameters, $offset] = self::parseParameters($remainder);
158-
$remainder = substr($remainder, $offset);
159-
160-
return [Item::from($value, $parameters), strlen($httpValue) - strlen($remainder)];
156+
return [$item, strlen($httpValue) - strlen($remainder)];
161157
}
162158

163159
/**
@@ -185,13 +181,8 @@ private static function parseInnerListValue(string $httpValue): array
185181
return [[$list, $parameters], strlen($httpValue) - strlen($remainder)];
186182
}
187183

188-
[$value, $offset] = self::parseBareItem($remainder);
189-
$remainder = substr($remainder, $offset);
184+
[$list[], $remainder] = self::parseItem($remainder);
190185

191-
[$parameters, $offset] = self::parseParameters($remainder);
192-
$remainder = substr($remainder, $offset);
193-
194-
$list[] = Item::from($value, $parameters);
195186
if ('' !== $remainder && !in_array($remainder[0], [' ', ')'], true)) {
196187
throw new SyntaxError("The HTTP textual representation \"$remainder\" for a inner list is using invalid characters.");
197188
}
@@ -256,10 +247,10 @@ private static function parseParameters(string $httpValue): array
256247
*
257248
* @return array{0:bool, 1:int}
258249
*/
259-
private static function parseBoolean(string $httpValue): array
250+
public static function parseBoolean(string $httpValue): array
260251
{
261252
if (1 !== preg_match('/^\?[01]/', $httpValue)) {
262-
throw new SyntaxError("Invalid character in the HTTP textual representation of a boolean value \"$httpValue\".");
253+
throw new SyntaxError("The HTTP textual representation \"$httpValue\" for a Boolean contains invalid characters.");
263254
}
264255

265256
return ['1' === $httpValue[1], 2];
@@ -354,7 +345,7 @@ private static function parseString(string $httpValue): array
354345
*
355346
* @return array{0:Token, 1:int}
356347
*/
357-
private static function parseToken(string $httpValue): array
348+
public static function parseToken(string $httpValue): array
358349
{
359350
preg_match("/^(?<token>[a-z*][a-z\d:\/!#\$%&'*+\-.^_`|~]*)/i", $httpValue, $found);
360351

@@ -368,12 +359,24 @@ private static function parseToken(string $httpValue): array
368359
*
369360
* @return array{0:ByteSequence, 1:int}
370361
*/
371-
private static function parseByteSequence(string $httpValue): array
362+
public static function parseByteSequence(string $httpValue): array
372363
{
373364
if (1 !== preg_match('/^(?<sequence>:(?<byte>[a-z\d+\/=]*):)/i', $httpValue, $matches)) {
374365
throw new SyntaxError("Invalid characters in the HTTP textual representation of a Byte Sequence \"$httpValue\".");
375366
}
376367

377368
return [ByteSequence::fromEncoded($matches['byte']), strlen($matches['sequence'])];
378369
}
370+
371+
/**
372+
* @return array{0:Item, 1:string}
373+
*/
374+
public static function parseItem(string $remainder): array
375+
{
376+
[$value, $offset] = self::parseBareItem($remainder);
377+
$remainder = substr($remainder, $offset);
378+
[$parameters, $offset] = self::parseParameters($remainder);
379+
380+
return [Item::from($value, $parameters), substr($remainder, $offset)];
381+
}
379382
}

0 commit comments

Comments
 (0)