Skip to content

Commit c84fe5c

Browse files
committed
It's time we started using mypy again
I found a PR for mypy that supports the walrus operator: python/mypy#6899 (This fixes some of the more egregious errors, but there are about 50 more.)
1 parent 357e482 commit c84fe5c

File tree

6 files changed

+59
-43
lines changed

6 files changed

+59
-43
lines changed

pegen/__main__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import tokenize
1515
import traceback
1616

17+
from typing import Final
18+
1719
from pegen.parser_generator import ParserGenerator
1820
from pegen.tokenizer import Tokenizer
1921
from pegen.tokenizer import grammar_tokenizer
@@ -23,7 +25,7 @@
2325
def print_memstats() -> bool:
2426
MiB: Final = 2 ** 20
2527
try:
26-
import psutil
28+
import psutil # type: ignore
2729
except ImportError:
2830
return False
2931
print("Memory stats:")

pegen/grammar.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
import token
88
import tokenize
99
import traceback
10-
from typing import AbstractSet, Callable, Dict, Generic, Iterable, Optional, List, TypeVar, Union
10+
from typing import AbstractSet, Callable, Dict, Generic, Iterable, List, Optional, Tuple, TYPE_CHECKING, TypeVar, Union
1111

1212
from pegen.parser import memoize, Parser
1313
from pegen.tokenizer import exact_token_types
1414

15+
if TYPE_CHECKING:
16+
from pegen.parser_generator import ParserGenerator
17+
1518

1619
def dedupe(name: str, names: List[str]) -> str:
1720
origname = name
@@ -24,12 +27,12 @@ def dedupe(name: str, names: List[str]) -> str:
2427

2528

2629
class Rule:
27-
def __init__(self, name: str, type: str, rhs: Rhs):
30+
def __init__(self, name: str, type: Optional[str], rhs: Rhs):
2831
self.name = name
2932
self.type = type
3033
self.rhs = rhs
3134
self.visited = False
32-
self.nullable = None
35+
self.nullable = False
3336
self.left_recursive = False
3437
self.leader = False
3538

@@ -45,13 +48,12 @@ def __str__(self):
4548
def __repr__(self):
4649
return f"Rule({self.name!r}, {self.type!r}, {self.rhs!r})"
4750

48-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
51+
def visit(self, rules: Dict[str, Rule]) -> bool:
4952
if self.visited:
5053
# A left-recursive rule is considered non-nullable.
5154
return False
5255
self.visited = True
5356
self.nullable = self.rhs.visit(rules)
54-
assert self.nullable is not None
5557
return self.nullable
5658

5759
def initial_names(self) -> AbstractSet[str]:
@@ -188,6 +190,15 @@ def __init__(self, value: str):
188190
def __str__(self):
189191
return self.value
190192

193+
def visit(self, rules: Dict[str, Rule]) -> bool:
194+
raise NotImplementedError
195+
196+
def initial_names(self) -> AbstractSet[str]:
197+
raise NotImplementedError
198+
199+
def make_call(self, gen: ParserGenerator, cpython: bool) -> Tuple[str, str]:
200+
raise NotImplementedError
201+
191202

192203
class NameLeaf(Leaf):
193204
"""The value is the name."""
@@ -202,7 +213,7 @@ def __str__(self):
202213
def __repr__(self):
203214
return f"NameLeaf({self.value!r})"
204215

205-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
216+
def visit(self, rules: Dict[str, Rule]) -> bool:
206217
if self.value in rules:
207218
return rules[self.value].visit(rules)
208219
# Token or unknown; never empty.
@@ -237,7 +248,7 @@ class StringLeaf(Leaf):
237248
def __repr__(self):
238249
return f"StringLeaf({self.value!r})"
239250

240-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
251+
def visit(self, rules: Dict[str, Rule]) -> bool:
241252
# The string token '' is considered empty.
242253
return not self.value
243254

@@ -269,7 +280,7 @@ def __str__(self):
269280
def __repr__(self):
270281
return f"Rhs({self.alts!r})"
271282

272-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
283+
def visit(self, rules: Dict[str, Rule]) -> bool:
273284
for alt in self.alts:
274285
if alt.visit(rules):
275286
return True
@@ -341,7 +352,7 @@ def __repr__(self):
341352
args.append(f"action={self.action!r}")
342353
return f"Alt({', '.join(args)})"
343354

344-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
355+
def visit(self, rules: Dict[str, Rule]) -> bool:
345356
for item in self.items:
346357
if not item.visit(rules):
347358
return False
@@ -446,7 +457,7 @@ class NamedItem:
446457
def __init__(self, name: Optional[str], item: Item):
447458
self.name = name
448459
self.item = item
449-
self.nullable = None
460+
self.nullable = False
450461

451462
def __str__(self):
452463
if self.name:
@@ -457,9 +468,8 @@ def __str__(self):
457468
def __repr__(self):
458469
return f"NamedItem({self.name!r}, {self.item!r})"
459470

460-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
471+
def visit(self, rules: Dict[str, Rule]) -> bool:
461472
self.nullable = self.item.visit(rules)
462-
assert self.nullable is not None
463473
return self.nullable
464474

465475
def initial_names(self) -> AbstractSet[str]:
@@ -582,7 +592,7 @@ def make_call(self, gen: ParserGenerator, cpython: bool) -> Tuple[str, str]:
582592
else:
583593
return "opt", f"{call}," # Note trailing comma!
584594

585-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
595+
def visit(self, rules: Dict[str, Rule]) -> bool:
586596
return True
587597

588598
def initial_names(self) -> AbstractSet[str]:
@@ -596,6 +606,12 @@ def __init__(self, node: Plain):
596606
self.node = node
597607
self.memo = None
598608

609+
def visit(self, rules: Dict[str, Rule]) -> bool:
610+
raise NotImplementedError
611+
612+
def make_call(self, gen: ParserGenerator, cpython: bool) -> Tuple[str, str]:
613+
raise NotImplementedError
614+
599615
def initial_names(self) -> AbstractSet[str]:
600616
return self.node.initial_names()
601617

@@ -607,7 +623,7 @@ def __str__(self):
607623
def __repr__(self):
608624
return f"Repeat0({self.node!r})"
609625

610-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
626+
def visit(self, rules: Dict[str, Rule]) -> bool:
611627
return True
612628

613629
def make_call(self, gen: ParserGenerator, cpython: bool) -> Tuple[str, str]:
@@ -628,8 +644,7 @@ def __str__(self):
628644
def __repr__(self):
629645
return f"Repeat1({self.node!r})"
630646

631-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
632-
# TODO: What if self.node is itself nullable?
647+
def visit(self, rules: Dict[str, Rule]) -> bool:
633648
return False
634649

635650
def make_call(self, gen: ParserGenerator, cpython: bool) -> Tuple[str, str]:
@@ -653,7 +668,7 @@ def __str__(self):
653668
def __repr__(self):
654669
return f"Group({self.rhs!r})"
655670

656-
def visit(self, rules: Dict[str, Rule]) -> Optional[bool]:
671+
def visit(self, rules: Dict[str, Rule]) -> bool:
657672
return self.rhs.visit(rules)
658673

659674
def initial_names(self) -> AbstractSet[str]:

pegen/parser.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import time
66
import token
77
import tokenize
8-
from typing import TypeVar, Generic, Dict, Tuple, Callable, Optional, NoReturn
8+
from typing import Callable, Dict, Generic, Optional, Tuple, TypeVar
99

1010
from pegen.tokenizer import CURLY_STUFF
1111
from pegen.tokenizer import exact_token_types
@@ -16,7 +16,7 @@
1616
T = TypeVar('T')
1717

1818

19-
def memoize(method: Callable[[Parser], T]):
19+
def memoize(method: Callable[[Parser], T]) -> Callable[[Parser], T]:
2020
"""Memoize a symbol method."""
2121
method_name = method.__name__
2222

@@ -56,11 +56,11 @@ def symbol_wrapper(self: Parser) -> T:
5656
self.reset(endmark)
5757
return tree
5858

59-
symbol_wrapper.__wrapped__ = method
59+
symbol_wrapper.__wrapped__ = method # type: ignore
6060
return symbol_wrapper
6161

6262

63-
def memoize_left_rec(method: Callable[[Parser], T]):
63+
def memoize_left_rec(method: Callable[[Parser], T]) -> Callable[[Parser], T]:
6464
"""Memoize a left-recursive symbol method."""
6565
method_name = method.__name__
6666

@@ -134,14 +134,14 @@ def left_rec_symbol_wrapper(self: Parser) -> T:
134134
self.reset(endmark)
135135
return tree
136136

137-
left_rec_symbol_wrapper.__wrapped__ = method
137+
left_rec_symbol_wrapper.__wrapped__ = method # type: ignore
138138
return left_rec_symbol_wrapper
139139

140140

141-
def memoize_expect(method: Callable[[Parser], Optional[tokenize.TokenInfo]]) -> bool:
141+
def memoize_expect(method: Callable[[Parser, str], T]) -> Callable[[Parser, str], T]:
142142
"""Memoize the expect() method."""
143143

144-
def expect_wrapper(self: Parser, type: str) -> Optional[tokenize.TokenInfo]:
144+
def expect_wrapper(self: Parser, type: str) -> T:
145145
mark = self.mark()
146146
key = mark, type
147147
# Fast path: cache hit.
@@ -167,7 +167,7 @@ def expect_wrapper(self: Parser, type: str) -> Optional[tokenize.TokenInfo]:
167167
self.reset(endmark)
168168
return res
169169

170-
expect_wrapper.__wrapped__ = method
170+
expect_wrapper.__wrapped__ = method # type: ignore
171171
return expect_wrapper
172172

173173

@@ -178,10 +178,8 @@ def __init__(self, tokenizer: Tokenizer, *, verbose=False):
178178
self._tokenizer = tokenizer
179179
self._verbose = verbose
180180
self._level = 0
181-
self._symbol_cache: Dict[Tuple[Mark,
182-
Callable[[Parser], Optional[T]]],
183-
Tuple[Optional[T], Mark]] = {}
184-
self._token_cache: Dict[Tuple[Mark, str], bool] = {}
181+
self._symbol_cache: Dict[Tuple[Mark, str], Tuple[Optional[T], Mark]] = {}
182+
self._token_cache: Dict[Tuple[Mark, str], Tuple[Optional[T], Mark]] = {}
185183
# Pass through common tokeniser methods.
186184
# TODO: Rename to _mark and _reset.
187185
self.mark = self._tokenizer.mark
@@ -252,7 +250,7 @@ def negative_lookahead(self, func: Callable[..., T], *args) -> bool:
252250
self.reset(mark)
253251
return not ok
254252

255-
def make_syntax_error(self, filename="<unknown>") -> NoReturn:
253+
def make_syntax_error(self, filename="<unknown>") -> SyntaxError:
256254
tok = self._tokenizer.diagnose()
257255
return SyntaxError("pegen parse failure", (filename, tok.start[0], 1 + tok.start[1], tok.line))
258256

pegen/parser_generator.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from pegen.grammar import Rhs
99
from pegen.grammar import Alt
1010
from pegen.grammar import NamedItem
11+
from pegen.grammar import Plain
1112

1213
MODULE_PREFIX = """\
1314
#!/usr/bin/env python3.8
@@ -83,7 +84,7 @@ def __init__(self, rules: Dict[str, Rule], file: Optional[IO[Text]]):
8384
self.counter = 0 # For name_rule()/name_loop()
8485

8586
@contextlib.contextmanager
86-
def indent(self) -> None:
87+
def indent(self) -> Iterator[None]:
8788
self.level += 1
8889
try:
8990
yield
@@ -172,7 +173,7 @@ def compute_nullables(rules: Dict[str, Rule]) -> None:
172173
rule.visit(rules)
173174

174175

175-
def compute_left_recursives(rules: Dict[str, Rule]) -> Tuple[Dict[str, Set[str]], List[Set[str]]]:
176+
def compute_left_recursives(rules: Dict[str, Rule]) -> Tuple[Dict[str, AbstractSet[str]], List[AbstractSet[str]]]:
176177
graph = make_first_graph(rules)
177178
sccs = list(sccutils.strongly_connected_components(graph.keys(), graph))
178179
for scc in sccs:
@@ -199,7 +200,7 @@ def compute_left_recursives(rules: Dict[str, Rule]) -> Tuple[Dict[str, Set[str]]
199200
return graph, sccs
200201

201202

202-
def make_first_graph(rules: Dict[str, Rule]) -> Dict[str, str]:
203+
def make_first_graph(rules: Dict[str, Rule]) -> Dict[str, AbstractSet[str]]:
203204
"""Compute the graph of left-invocations.
204205
205206
There's an edge from A to B if A may invoke B at its initial
@@ -208,7 +209,7 @@ def make_first_graph(rules: Dict[str, Rule]) -> Dict[str, str]:
208209
Note that this requires the nullable flags to have been computed.
209210
"""
210211
graph = {}
211-
vertices = set()
212+
vertices: Set[str] = set()
212213
for rulename, rhs in rules.items():
213214
graph[rulename] = names = rhs.initial_names()
214215
vertices |= names

pegen/sccutils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import *
44

55
def strongly_connected_components(vertices: AbstractSet[str],
6-
edges: Dict[str, Iterable[str]]) -> Iterator[Set[str]]:
6+
edges: Dict[str, AbstractSet[str]]) -> Iterator[AbstractSet[str]]:
77
"""Compute Strongly Connected Components of a directed graph.
88
99
Args:
@@ -48,7 +48,7 @@ def dfs(v: str) -> Iterator[Set[str]]:
4848

4949

5050
def topsort(data: Dict[AbstractSet[str],
51-
Set[AbstractSet[str]]]) -> Iterable[Set[AbstractSet[str]]]:
51+
Set[AbstractSet[str]]]) -> Iterable[AbstractSet[AbstractSet[str]]]:
5252
"""Topological sort.
5353
5454
Args:
@@ -96,7 +96,7 @@ def topsort(data: Dict[AbstractSet[str],
9696
assert not data, "A cyclic dependency exists amongst %r" % data
9797

9898

99-
def find_cycles_in_scc(graph: Dict[str, Set[str]], scc: Set[str], start: str) -> Iterable[List[str]]:
99+
def find_cycles_in_scc(graph: Dict[str, AbstractSet[str]], scc: AbstractSet[str], start: str) -> Iterable[List[str]]:
100100
"""Find cycles in SCC emanating from start.
101101
102102
Yields lists of the form ['A', 'B', 'C', 'A'], which means there's

pegen/tokenizer.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import token
44
import tokenize
5-
from typing import List, Iterable
5+
from typing import List, Iterator
66

77
Mark = int # NewType('Mark', int)
88

@@ -13,7 +13,7 @@
1313
exact_token_types = token.EXACT_TOKEN_TYPES # type: ignore
1414

1515

16-
def shorttok(tok: tokenizer.TokenInfo) -> str:
16+
def shorttok(tok: tokenize.TokenInfo) -> str:
1717
return "%-25.25s" % f"{tok.start[0]}.{tok.start[1]}: {token.tok_name[tok.type]}:{tok.string!r}"
1818

1919

@@ -25,7 +25,7 @@ class Tokenizer:
2525

2626
_tokens: List[tokenize.TokenInfo]
2727

28-
def __init__(self, tokengen: Iterable[TokenInfo], *, verbose=False):
28+
def __init__(self, tokengen: Iterator[tokenize.TokenInfo], *, verbose=False):
2929
self._tokengen = tokengen
3030
self._tokens = []
3131
self._index = 0
@@ -38,7 +38,7 @@ def getnext(self) -> tokenize.TokenInfo:
3838
cached = True
3939
while self._index == len(self._tokens):
4040
tok = next(self._tokengen)
41-
if tok.type in (token.NL, token.COMMENT):
41+
if tok.type in (tokenize.NL, tokenize.COMMENT):
4242
continue
4343
if tok.type == token.ERRORTOKEN and tok.string.isspace():
4444
continue
@@ -54,7 +54,7 @@ def peek(self) -> tokenize.TokenInfo:
5454
"""Return the next token *without* updating the index."""
5555
while self._index == len(self._tokens):
5656
tok = next(self._tokengen)
57-
if tok.type in (token.NL, token.COMMENT):
57+
if tok.type in (tokenize.NL, tokenize.COMMENT):
5858
continue
5959
if tok.type == token.ERRORTOKEN and tok.string.isspace():
6060
continue

0 commit comments

Comments
 (0)