Skip to content

Commit b1b9011

Browse files
committed
add support for nullable type
1 parent 7492b2a commit b1b9011

File tree

5 files changed

+57
-7
lines changed

5 files changed

+57
-7
lines changed

doc/grammer.ebnf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
Type
22
::= Atomic (Union | Intersection)?
3+
| Nullable
34

45
Union
56
::= ('|' Atomic)+
67

78
Intersection
89
::= ('&' Atomic)+
910

11+
Nullable
12+
::= '?' Identifier Generic?
13+
1014
Atomic
1115
::= Identifier (Generic | Array)?
1216
| '(' Type ')' Array?

doc/grammer.peg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
Type
22
= Atomic (Union / Intersection)?
3+
/ Nullable
34

45
Union
56
= ('|' Atomic)+
67

78
Intersection
89
= ('&' Atomic)+
910

11+
Nullable
12+
= '?' Identifier Generic?
13+
1014
Atomic
1115
= Identifier (Generic / Array)?
1216
/ '(' Type ')' Array?

src/Ast/NullableType.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PhpStan\TypeParser\Ast;
4+
5+
6+
class NullableType implements Node
7+
{
8+
/** @var Node */
9+
public $type;
10+
11+
12+
public function __construct(Node $type)
13+
{
14+
$this->type = $type;
15+
}
16+
17+
18+
public function __toString(): string
19+
{
20+
return '?' . $this->type;
21+
}
22+
}

src/Lexer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Lexer
1010
const TOKEN_IDENTIFIER = 0;
1111
const TOKEN_UNION = 1;
1212
const TOKEN_INTERSECTION = 2;
13-
const TOKEN_COMPLEMENT = 3;
13+
const TOKEN_NULLABLE = 3;
1414
const TOKEN_OPEN_PARENTHESES = 4;
1515
const TOKEN_CLOSE_PARENTHESES = 5;
1616
const TOKEN_OPEN_ANGLE_BRACKET = 6;
@@ -64,7 +64,7 @@ private function initialize(): void
6464
self::TOKEN_IDENTIFIER => '(?:[\\\\]?+[a-z_\\x7F-\\xFF][0-9a-z_\\x7F-\\xFF]*+)++',
6565
self::TOKEN_UNION => '\\|',
6666
self::TOKEN_INTERSECTION => '&',
67-
self::TOKEN_COMPLEMENT => '\\~',
67+
self::TOKEN_NULLABLE => '\\?',
6868
self::TOKEN_OPEN_PARENTHESES => '\\(',
6969
self::TOKEN_CLOSE_PARENTHESES => '\\)',
7070
self::TOKEN_OPEN_ANGLE_BRACKET => '<',

src/Parser.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,18 @@ private function tearDown(): void
6767

6868
private function parseType(): Ast\Node
6969
{
70-
$type = $this->parseAtomic();
70+
if ($this->tokenType === Lexer::TOKEN_NULLABLE) {
71+
$type = $this->parseNullable();
7172

72-
if ($this->tokenType === Lexer::TOKEN_UNION) {
73-
$type = $this->parseUnion($type);
73+
} else {
74+
$type = $this->parseAtomic();
75+
76+
if ($this->tokenType === Lexer::TOKEN_UNION) {
77+
$type = $this->parseUnion($type);
7478

75-
} elseif ($this->tokenType === Lexer::TOKEN_INTERSECTION) {
76-
$type = $this->parseIntersection($type);
79+
} elseif ($this->tokenType === Lexer::TOKEN_INTERSECTION) {
80+
$type = $this->parseIntersection($type);
81+
}
7782
}
7883

7984
return $type;
@@ -135,6 +140,21 @@ private function parseIntersection(Ast\Node $type): Ast\Node
135140
}
136141

137142

143+
private function parseNullable(): Ast\Node
144+
{
145+
$this->consume(Lexer::TOKEN_NULLABLE);
146+
147+
$type = new Ast\SimpleNode($this->value());
148+
$this->consume(Lexer::TOKEN_IDENTIFIER);
149+
150+
if ($this->tokenType === Lexer::TOKEN_OPEN_ANGLE_BRACKET) {
151+
$type = $this->parseGeneric($type);
152+
}
153+
154+
return new Ast\NullableNode($type);
155+
}
156+
157+
138158
private function parseGeneric(Ast\SimpleNode $baseType): Ast\Node
139159
{
140160
$this->consume(Lexer::TOKEN_OPEN_ANGLE_BRACKET);

0 commit comments

Comments
 (0)