-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathincdec.py
89 lines (68 loc) · 2.89 KB
/
incdec.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from io import StringIO
import keyword
from tokenize import TokenInfo, generate_tokens
import tokenize
def is_valid_unary_operator(token):
return token.type == tokenize.OP and token.string in ('+', '-')
def is_valid_name(token):
return token.type == tokenize.NAME and not keyword.iskeyword(token.string)
class UnaryExpr:
def __init__(self, name: str, operator: str, prefix: bool):
self.name = name
self.operator = operator
self.prefix = prefix
@staticmethod
def from_tokens(tokens: tuple[TokenInfo, TokenInfo, TokenInfo]):
if tokens[0].type == tokens[1].type == tokenize.OP:
return UnaryExpr(name=tokens[2].string, operator=tokens[0].string, prefix=True)
elif tokens[1].type == tokens[2].type == tokenize.OP:
return UnaryExpr(name=tokens[0].string, operator=tokens[1].string, prefix=False)
else:
raise TypeError("Invalid token tuple: expected the same tokenize.OP twice and a tokenize.NAME")
def __str__(self):
if self.prefix:
return f"{self.operator}{self.operator}{self.name}"
return f"{self.name}{self.operator}{self.operator}"
def to_python(self):
target = 0 if self.prefix else 1
return f"(({self.name}, {self.name} := {self.name}{self.operator}1)[{target}])"
def to_tokens(self):
return [
(tokenize.OP, '('),
(tokenize.OP, '('),
(tokenize.NAME, self.name),
(tokenize.OP, ','),
(tokenize.NAME, self.name),
(tokenize.OP, ':='),
(tokenize.NAME, self.name),
(tokenize.OP, self.operator),
(tokenize.NUMBER, '1'),
(tokenize.OP, ')'),
(tokenize.OP, '['),
(tokenize.NUMBER, str(int(self.prefix))),
(tokenize.OP, ']'),
(tokenize.OP, ')')
]
def transform(data):
tokens = list(generate_tokens(StringIO(data).readline))
idx = 0
while idx < len(tokens) - 2:
current = tokens[idx]
if is_valid_name(current):
peek1, peek2 = tokens[idx + 1], tokens[idx + 2]
if is_valid_unary_operator(peek1) and peek1.string == peek2.string:
yield from UnaryExpr.from_tokens((current, peek1, peek2)).to_tokens()
idx += 3
continue
elif is_valid_unary_operator(current):
peek, name = tokens[idx + 1], tokens[idx + 2]
if peek.string == current.string and is_valid_name(name):
yield from UnaryExpr.from_tokens((current, peek, name)).to_tokens()
idx += 3
continue
yield current.type, current.string
idx += 1
yield tokens[len(tokens) - 2].type, tokens[len(tokens) - 2].string
yield tokens[len(tokens) - 1].type, tokens[len(tokens) - 1].string
def preprocess(data: str):
return tokenize.untokenize(transform(data))