X Tutup
Skip to content

Commit 70d4841

Browse files
committed
Fix python 3 set comprehension and ...
Add a few set/list comprehension offsets for Python 3
1 parent 4f8714f commit 70d4841

File tree

7 files changed

+88
-49
lines changed

7 files changed

+88
-49
lines changed

pytest/test_deparse.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ def for_range_stmt():
2020
for i in range(2):
2121
i+1
2222

23+
# FIXME: add this test
24+
def set_comp():
25+
{y for y in range(3)}
26+
27+
# FIXME: add this test
28+
def list_comp():
29+
[y for y in range(3)]
30+
2331
def get_parsed_for_fn(fn):
2432
code = fn.__code__ if PYTHON3 else fn.func_code
2533
return deparse(PYTHON_VERSION, code)
275 Bytes
Binary file not shown.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Bug in python 3.x handling set comprehensions
2+
{y for y in range(3)}

uncompyle6/parser.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ def nonterminal(self, nt, args):
5050

5151
if nt in collect and len(args) > 1:
5252
#
53-
# Collect iterated thingies together.
53+
# Collect iterated thingies together. That is rather than
54+
# stmts -> stmts stmt -> stmts stmt -> ...
55+
# stmms -> stmt stmt ...
5456
#
5557
rv = args[0]
5658
rv.append(args[1])

uncompyle6/parsers/parse3.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -494,15 +494,14 @@ def add_custom_rules(self, tokens, customize):
494494
rule = ("listcomp ::= LOAD_LISTCOMP MAKE_FUNCTION_0 expr "
495495
"GET_ITER CALL_FUNCTION_1")
496496
self.add_unique_rule(rule, opname, token.attr, customize)
497-
# FIXME: add in after fixing bug in semantics
498-
# elif opname == 'LOAD_SETCOMP':
499-
# if self.version >= 3.4:
500-
# rule = ("setcomp ::= LOAD_SETCOMP LOAD_CONST MAKE_FUNCTION_0 expr "
501-
# "GET_ITER CALL_FUNCTION_1")
502-
# else:
503-
# rule = ("setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr "
504-
# "GET_ITER CALL_FUNCTION_1")
505-
# self.add_unique_rule(rule, opname, token.attr, customize)
497+
elif opname == 'LOAD_SETCOMP':
498+
if self.version >= 3.4:
499+
rule = ("setcomp ::= LOAD_SETCOMP LOAD_CONST MAKE_FUNCTION_0 expr "
500+
"GET_ITER CALL_FUNCTION_1")
501+
else:
502+
rule = ("setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr "
503+
"GET_ITER CALL_FUNCTION_1")
504+
self.add_unique_rule(rule, opname, token.attr, customize)
506505
elif opname == 'LOAD_BUILD_CLASS':
507506
self.custom_build_class_rule(opname, i, token, tokens, customize)
508507
elif opname_base in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'):

uncompyle6/semantics/fragments.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -580,27 +580,43 @@ def listcomprehension_walk3(self, node, iter_index, code_index=-5):
580580

581581
ast = self.build_ast(code._tokens, code._customize)
582582
self.customize(code._customize)
583-
ast = ast[0][0][0][0][0]
583+
# skip over stmts sstmt smt
584+
ast = ast[0][0][0]
584585

585-
n = ast[iter_index]
586-
assert n == 'list_iter'
586+
if ast == 'setcomp_func':
587+
for k in ast:
588+
if k == 'comp_iter':
589+
n = k
590+
elif k == 'designator':
591+
designator = k
592+
pass
593+
pass
594+
pass
595+
else:
596+
ast = ast[0][0]
597+
n = ast[iter_index]
598+
assert n == 'list_iter'
599+
600+
## FIXME: I'm not totally sure this is right.
587601

588602
# find innermost node
589-
while n == 'list_iter':
603+
list_if_node = None
604+
while n in ('list_iter', 'comp_iter'):
590605
n = n[0] # recurse one step
591606
if n == 'list_for':
592-
designator = n[2]
607+
if n[2] == 'designator':
608+
designator = n[2]
593609
n = n[3]
594-
elif n == 'list_if':
595-
# FIXME: just a guess
596-
designator = n[1]
597-
598-
n = n[2]
599-
elif n == 'list_if_not':
600-
# FIXME: just a guess
601-
designator = n[1]
610+
elif n in ['list_if', 'list_if_not']:
611+
list_if_node = n[0]
612+
if n[1] == 'designator':
613+
designator = n[1]
602614
n = n[2]
603-
assert n == 'lc_body', ast
615+
pass
616+
pass
617+
618+
assert n.type in ('lc_body', 'comp_body'), ast
619+
assert designator, "Couldn't find designator in list/set comprehension"
604620

605621
self.preorder(n[0])
606622
self.write(' for ')
@@ -612,7 +628,9 @@ def listcomprehension_walk3(self, node, iter_index, code_index=-5):
612628
node[-3].parent = node
613629
self.preorder(node[-3])
614630
self.set_pos_info(node[-3], start, len(self.f.getvalue()))
615-
# self.preorder(ast[iter_index])
631+
if list_if_node:
632+
self.write(' if ')
633+
self.preorder(list_if_node)
616634
self.prec = p
617635

618636
def listcomprehension_walk2(self, node):
@@ -680,7 +698,12 @@ def n_genexpr(self, node):
680698
def n_setcomp(self, node):
681699
start = len(self.f.getvalue())
682700
self.write('{')
683-
self.comprehension_walk(node, 4)
701+
if node[0] == 'LOAD_SETCOMP':
702+
start = len(self.f.getvalue())
703+
self.set_pos_info(node[0], start-1, start)
704+
self.listcomprehension_walk3(node, 1, 0)
705+
else:
706+
self.comprehension_walk(node, iter_index=4)
684707
self.write('}')
685708
self.set_pos_info(node, start, len(self.f.getvalue()))
686709
self.prune()
@@ -767,7 +790,7 @@ def n_classdef(self, node):
767790
self.prune()
768791

769792
def gen_source(self, ast, name, customize, isLambda=False, returnNone=False):
770-
"""convert AST to source code"""
793+
"""convert AST to Python source code"""
771794

772795
rn = self.return_none
773796
self.return_none = returnNone
@@ -1585,7 +1608,7 @@ def get_code_for_fn(fn):
15851608
return fn.__code__
15861609

15871610
def test():
1588-
[x for x in range(3)]
1611+
{x for x in range(3)}
15891612

15901613
def gcd(a, b):
15911614
if a > b:

uncompyle6/semantics/pysource.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,6 @@ def traverse(self, node, indent=None, isLambda=False):
590590
def write(self, *data):
591591
if (len(data) == 0) or (len(data) == 1 and data[0] == ''):
592592
return
593-
# import pdb; pdb.set_trace()
594593
out = ''.join((str(j) for j in data))
595594
n = 0
596595
for i in out:
@@ -812,10 +811,6 @@ def n_delete_subscr(self, node):
812811
if node[-2][0][-1] != 'BUILD_TUPLE_0':
813812
node[-2][0].type = 'build_tuple2'
814813
self.default(node)
815-
# maybe_tuple = node[-2][-1]
816-
# if maybe_tuple.type.startswith('BUILD_TUPLE'):
817-
# maybe_tuple.type = 'build_tuple2'
818-
# self.default(node)
819814

820815
n_store_subscr = n_binary_subscr = n_delete_subscr
821816

@@ -988,7 +983,7 @@ def n_mklambda(self, node):
988983
self.prune() # stop recursing
989984

990985
def n_list_compr(self, node):
991-
"""List comprehensions the way they are done in Python2.
986+
"""List comprehensions the way they are done in Python 2.
992987
"""
993988
p = self.prec
994989
self.prec = 27
@@ -1057,7 +1052,10 @@ def n_genexpr(self, node):
10571052

10581053
def n_setcomp(self, node):
10591054
self.write('{')
1060-
self.comprehension_walk(node, iter_index=4)
1055+
if node[0] == 'LOAD_SETCOMP':
1056+
self.listcomprehension_walk3(node, 1, 0)
1057+
else:
1058+
self.comprehension_walk(node, iter_index=4)
10611059
self.write('}')
10621060
self.prune()
10631061

@@ -1076,17 +1074,28 @@ def listcomprehension_walk3(self, node, iter_index, code_index=-5):
10761074

10771075
ast = self.build_ast(code._tokens, code._customize)
10781076
self.customize(code._customize)
1079-
ast = ast[0][0][0][0][0]
1080-
1081-
n = ast[iter_index]
1082-
assert n == 'list_iter'
1077+
# skip over stmts sstmt smt
1078+
ast = ast[0][0][0]
1079+
designator = None
1080+
if ast == 'setcomp_func':
1081+
for k in ast:
1082+
if k == 'comp_iter':
1083+
n = k
1084+
elif k == 'designator':
1085+
designator = k
1086+
pass
1087+
pass
1088+
pass
1089+
else:
1090+
ast = ast[0][0]
1091+
n = ast[iter_index]
1092+
assert n == 'list_iter'
10831093

10841094
## FIXME: I'm not totally sure this is right.
10851095

10861096
# find innermost node
1087-
designator = None
10881097
list_if_node = None
1089-
while n == 'list_iter':
1098+
while n in ('list_iter', 'comp_iter'):
10901099
n = n[0] # recurse one step
10911100
if n == 'list_for':
10921101
if n[2] == 'designator':
@@ -1099,8 +1108,8 @@ def listcomprehension_walk3(self, node, iter_index, code_index=-5):
10991108
n = n[2]
11001109
pass
11011110
pass
1102-
assert n == 'lc_body', ast
1103-
assert designator, "Couldn't find designator in list comprehension"
1111+
assert n.type in ('lc_body', 'comp_body'), ast
1112+
assert designator, "Couldn't find designator in list/set comprehension"
11041113

11051114
self.preorder(n[0])
11061115
self.write(' for ')
@@ -1322,10 +1331,7 @@ def n_mapexpr(self, node):
13221331
l = list(kv_node)
13231332
i = 0
13241333
while i < len(l):
1325-
try:
1326-
name = self.traverse(l[i+1], indent='')
1327-
except:
1328-
from trepan.api import debug; debug()
1334+
name = self.traverse(l[i+1], indent='')
13291335
value = self.traverse(l[i], indent=self.indent+(len(name)+2)*' ')
13301336
self.write(sep, name, ': ', value)
13311337
sep = line_seperator
@@ -1504,7 +1510,6 @@ def engine(self, entry, startnode):
15041510
elif typ == 'C':
15051511
low, high, sep = entry[arg]
15061512
remaining = len(node[low:high])
1507-
# remaining = len(node[low:high])
15081513
for subnode in node[low:high]:
15091514
self.preorder(subnode)
15101515
remaining -= 1
@@ -1821,7 +1826,7 @@ def build_class(self, code):
18211826
self.classes.pop(-1)
18221827

18231828
def gen_source(self, ast, name, customize, isLambda=False, returnNone=False):
1824-
"""convert AST to source code"""
1829+
"""convert AST to Python source code"""
18251830

18261831
rn = self.return_none
18271832
self.return_none = returnNone

0 commit comments

Comments
 (0)
X Tutup