Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9b30d6f

Browse files
shmaxondrejmirtes
authored andcommitted
TypeParser - support comments at EOL with //
1 parent 12c4e9f commit 9b30d6f

File tree

13 files changed

+1110
-81
lines changed

13 files changed

+1110
-81
lines changed

‎README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ use PHPStan\PhpDocParser\Printer\Printer;
8383

8484
// basic setup with enabled required lexer attributes
8585

86-
$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true]);
86+
$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true, 'comments' => true]);
8787
$lexer = new Lexer($config);
8888
$constExprParser = new ConstExprParser($config);
8989
$typeParser = new TypeParser($config, $constExprParser);

‎src/Ast/Attribute.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ final class Attribute
1313

1414
public const ORIGINAL_NODE = 'originalNode';
1515

16+
public const COMMENTS = 'comments';
17+
1618
}

‎src/Ast/Comment.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDocParser\Ast;
4+
5+
use function trim;
6+
7+
class Comment
8+
{
9+
10+
public string $text;
11+
12+
public int $startLine;
13+
14+
public int $startIndex;
15+
16+
public function __construct(string $text, int $startLine = -1, int $startIndex = -1)
17+
{
18+
$this->text = $text;
19+
$this->startLine = $startLine;
20+
$this->startIndex = $startIndex;
21+
}
22+
23+
public function getReformattedText(): string
24+
{
25+
return trim($this->text);
26+
}
27+
28+
}

‎src/Ast/NodeAttributes.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ trait NodeAttributes
1515
*/
1616
public function setAttribute(string $key, $value): void
1717
{
18+
if ($value === null) {
19+
unset($this->attributes[$key]);
20+
return;
21+
}
1822
$this->attributes[$key] = $value;
1923
}
2024

‎src/Lexer/Lexer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class Lexer
5151
public const TOKEN_NEGATED = 35;
5252
public const TOKEN_ARROW = 36;
5353

54+
public const TOKEN_COMMENT = 37;
55+
5456
public const TOKEN_LABELS = [
5557
self::TOKEN_REFERENCE => '\'&\'',
5658
self::TOKEN_UNION => '\'|\'',
@@ -66,6 +68,7 @@ class Lexer
6668
self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'',
6769
self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'',
6870
self::TOKEN_COMMA => '\',\'',
71+
self::TOKEN_COMMENT => '\'//\'',
6972
self::TOKEN_COLON => '\':\'',
7073
self::TOKEN_VARIADIC => '\'...\'',
7174
self::TOKEN_DOUBLE_COLON => '\'::\'',
@@ -160,6 +163,7 @@ private function generateRegexp(): string
160163
self::TOKEN_CLOSE_CURLY_BRACKET => '\\}',
161164

162165
self::TOKEN_COMMA => ',',
166+
self::TOKEN_COMMENT => '\/\/[^\\r\\n]*(?=\n|\r|\*/)',
163167
self::TOKEN_VARIADIC => '\\.\\.\\.',
164168
self::TOKEN_DOUBLE_COLON => '::',
165169
self::TOKEN_DOUBLE_ARROW => '=>',

‎src/Parser/PhpDocParser.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,19 @@ public function parse(TokenIterator $tokens): Ast\PhpDoc\PhpDocNode
116116

117117
$tokens->forwardToTheEnd();
118118

119+
$comments = $tokens->flushComments();
120+
if ($comments !== []) {
121+
throw new LogicException('Comments should already be flushed');
122+
}
123+
119124
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0);
120125
}
121126

127+
$comments = $tokens->flushComments();
128+
if ($comments !== []) {
129+
throw new LogicException('Comments should already be flushed');
130+
}
131+
122132
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode($children), 1, 0);
123133
}
124134

‎src/Parser/TokenIterator.php

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\PhpDocParser\Parser;
44

55
use LogicException;
6+
use PHPStan\PhpDocParser\Ast\Comment;
67
use PHPStan\PhpDocParser\Lexer\Lexer;
78
use function array_pop;
89
use function assert;
@@ -19,7 +20,10 @@ class TokenIterator
1920

2021
private int $index;
2122

22-
/** @var int[] */
23+
/** @var list<Comment> */
24+
private array $comments = [];
25+
26+
/** @var list<array{int, list<Comment>}> */
2327
private array $savePoints = [];
2428

2529
/** @var list<int> */
@@ -152,8 +156,7 @@ public function consumeTokenType(int $tokenType): void
152156
}
153157
}
154158

155-
$this->index++;
156-
$this->skipIrrelevantTokens();
159+
$this->next();
157160
}
158161

159162

@@ -166,8 +169,7 @@ public function consumeTokenValue(int $tokenType, string $tokenValue): void
166169
$this->throwError($tokenType, $tokenValue);
167170
}
168171

169-
$this->index++;
170-
$this->skipIrrelevantTokens();
172+
$this->next();
171173
}
172174

173175

@@ -178,12 +180,20 @@ public function tryConsumeTokenValue(string $tokenValue): bool
178180
return false;
179181
}
180182

181-
$this->index++;
182-
$this->skipIrrelevantTokens();
183+
$this->next();
183184

184185
return true;
185186
}
186187

188+
/**
189+
* @return list<Comment>
190+
*/
191+
public function flushComments(): array
192+
{
193+
$res = $this->comments;
194+
$this->comments = [];
195+
return $res;
196+
}
187197

188198
/** @phpstan-impure */
189199
public function tryConsumeTokenType(int $tokenType): bool
@@ -198,14 +208,15 @@ public function tryConsumeTokenType(int $tokenType): bool
198208
}
199209
}
200210

201-
$this->index++;
202-
$this->skipIrrelevantTokens();
211+
$this->next();
203212

204213
return true;
205214
}
206215

207216

208-
/** @phpstan-impure */
217+
/**
218+
* @deprecated Use skipNewLineTokensAndConsumeComments instead (when parsing a type)
219+
*/
209220
public function skipNewLineTokens(): void
210221
{
211222
if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
@@ -218,6 +229,29 @@ public function skipNewLineTokens(): void
218229
}
219230

220231

232+
public function skipNewLineTokensAndConsumeComments(): void
233+
{
234+
if ($this->currentTokenType() === Lexer::TOKEN_COMMENT) {
235+
$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
236+
$this->next();
237+
}
238+
239+
if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
240+
return;
241+
}
242+
243+
do {
244+
$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
245+
if ($this->currentTokenType() !== Lexer::TOKEN_COMMENT) {
246+
continue;
247+
}
248+
249+
$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
250+
$this->next();
251+
} while ($foundNewLine === true);
252+
}
253+
254+
221255
private function detectNewline(): void
222256
{
223257
$value = $this->currentTokenValue();
@@ -293,7 +327,7 @@ public function forwardToTheEnd(): void
293327

294328
public function pushSavePoint(): void
295329
{
296-
$this->savePoints[] = $this->index;
330+
$this->savePoints[] = [$this->index, $this->comments];
297331
}
298332

299333

@@ -305,9 +339,9 @@ public function dropSavePoint(): void
305339

306340
public function rollback(): void
307341
{
308-
$index = array_pop($this->savePoints);
309-
assert($index !== null);
310-
$this->index= $index;
342+
$savepoint = array_pop($this->savePoints);
343+
assert($savepoint !== null);
344+
[$this->index, $this->comments] = $savepoint;
311345
}
312346

313347

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /