You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Merge branch 'master' into ast-format
This commit is contained in:
@@ -20,6 +20,14 @@ def for_range_stmt():
|
||||
for i in range(2):
|
||||
i+1
|
||||
|
||||
# # FIXME: add this test - but for Python 2.7+ only
|
||||
# def set_comp():
|
||||
# {y for y in range(3)}
|
||||
|
||||
# FIXME: add this test
|
||||
def list_comp():
|
||||
[y for y in range(3)]
|
||||
|
||||
def get_parsed_for_fn(fn):
|
||||
code = fn.__code__ if PYTHON3 else fn.func_code
|
||||
return deparse(PYTHON_VERSION, code)
|
||||
|
BIN
test/bytecode_3.4/05_set_comprehension.pyc
Normal file
BIN
test/bytecode_3.4/05_set_comprehension.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/05_set_comprehension.pyc
Normal file
BIN
test/bytecode_3.5/05_set_comprehension.pyc
Normal file
Binary file not shown.
5
test/simple_source/comprehension/05_set_comprehension.py
Normal file
5
test/simple_source/comprehension/05_set_comprehension.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# Bug in python 3.x handling set comprehensions
|
||||
{y for y in range(3)}
|
||||
|
||||
# Bug in python 3.4 (base64.py) in handling dict comprehension
|
||||
b = {v: k for k, v in enumerate(b3)}
|
@@ -0,0 +1,6 @@
|
||||
# Bug in python 3.4 abc.py
|
||||
# Set comprehension
|
||||
|
||||
abstracts = {name
|
||||
for name, value in namespace.items()
|
||||
if getattr(value, "__isabstractmethod__", False)}
|
@@ -34,6 +34,7 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
|
||||
except pysource.SourceWalkerError as e:
|
||||
# deparsing failed
|
||||
print("\n")
|
||||
print(co.co_filename)
|
||||
if real_out != out:
|
||||
print("\n", file=real_out)
|
||||
print(e, file=real_out)
|
||||
|
@@ -39,8 +39,15 @@ class PythonParser(GenericASTBuilder):
|
||||
for i in dir(self):
|
||||
setattr(self, i, None)
|
||||
|
||||
def error(self, token):
|
||||
raise ParserError(token, token.offset)
|
||||
def error(self, tokens, index):
|
||||
start = index - 2 if index - 2 > 0 else 0
|
||||
finish = index +2 if index + 2 < len(tokens) else len(tokens)
|
||||
err_token = tokens[index]
|
||||
print("Token context:")
|
||||
for i in range(start, finish):
|
||||
indent = ' ' if i != index else '-> '
|
||||
print("%s%s" % (indent, tokens[i]))
|
||||
raise ParserError(err_token, err_token.offset)
|
||||
|
||||
def typestring(self, token):
|
||||
return token.type
|
||||
@@ -114,12 +121,9 @@ class PythonParser(GenericASTBuilder):
|
||||
def p_dictcomp(self, args):
|
||||
'''
|
||||
expr ::= dictcomp
|
||||
dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
|
||||
stmt ::= dictcomp_func
|
||||
|
||||
dictcomp_func ::= BUILD_MAP LOAD_FAST FOR_ITER designator
|
||||
dictcomp_func ::= BUILD_MAP_0 LOAD_FAST FOR_ITER designator
|
||||
comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST
|
||||
|
||||
'''
|
||||
|
||||
def p_augmented_assign(self, args):
|
||||
@@ -307,7 +311,6 @@ class PythonParser(GenericASTBuilder):
|
||||
expr ::= LOAD_DEREF
|
||||
expr ::= load_attr
|
||||
expr ::= binary_expr
|
||||
expr ::= binary_expr_na
|
||||
expr ::= build_list
|
||||
expr ::= cmp
|
||||
expr ::= mapexpr
|
||||
@@ -441,12 +444,38 @@ class PythonParser(GenericASTBuilder):
|
||||
# Positional arguments in make_function
|
||||
pos_arg ::= expr
|
||||
|
||||
nullexprlist ::=
|
||||
|
||||
expr32 ::= expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr
|
||||
expr1024 ::= expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32
|
||||
'''
|
||||
|
||||
def p_designator(self, args):
|
||||
'''
|
||||
# Note. The below is right-recursive:
|
||||
designList ::= designator designator
|
||||
designList ::= designator DUP_TOP designList
|
||||
|
||||
## Can we replace with left-recursive, and redo with:
|
||||
##
|
||||
## designList ::= designLists designator designator
|
||||
## designLists ::= designLists designator DUP_TOP
|
||||
## designLists ::=
|
||||
## Will need to redo semantic actiion
|
||||
|
||||
designator ::= STORE_FAST
|
||||
designator ::= STORE_NAME
|
||||
designator ::= STORE_GLOBAL
|
||||
designator ::= STORE_DEREF
|
||||
designator ::= expr STORE_ATTR
|
||||
designator ::= expr STORE_SLICE+0
|
||||
designator ::= expr expr STORE_SLICE+1
|
||||
designator ::= expr expr STORE_SLICE+2
|
||||
designator ::= expr expr expr STORE_SLICE+3
|
||||
designator ::= store_subscr
|
||||
store_subscr ::= expr expr STORE_SUBSCR
|
||||
designator ::= unpack
|
||||
designator ::= unpack_list
|
||||
'''
|
||||
|
||||
|
||||
def parse(p, tokens, customize):
|
||||
p.add_custom_rules(tokens, customize)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015 Rocky Bernstein
|
||||
# Copyright (c) 2015-2016 Rocky Bernstein
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
"""
|
||||
@@ -64,8 +64,6 @@ class Python2Parser(PythonParser):
|
||||
sstmt ::= ifelsestmtr
|
||||
sstmt ::= return_stmt RETURN_LAST
|
||||
|
||||
stmts_opt ::= stmts
|
||||
stmts_opt ::= passstmt
|
||||
passstmt ::=
|
||||
|
||||
_stmts ::= _stmts stmt
|
||||
@@ -113,23 +111,6 @@ class Python2Parser(PythonParser):
|
||||
else_suitec ::= c_stmts
|
||||
else_suitec ::= return_stmts
|
||||
|
||||
designList ::= designator designator
|
||||
designList ::= designator DUP_TOP designList
|
||||
|
||||
designator ::= STORE_FAST
|
||||
designator ::= STORE_NAME
|
||||
designator ::= STORE_GLOBAL
|
||||
designator ::= STORE_DEREF
|
||||
designator ::= expr STORE_ATTR
|
||||
designator ::= expr STORE_SLICE+0
|
||||
designator ::= expr expr STORE_SLICE+1
|
||||
designator ::= expr expr STORE_SLICE+2
|
||||
designator ::= expr expr expr STORE_SLICE+3
|
||||
designator ::= store_subscr
|
||||
store_subscr ::= expr expr STORE_SUBSCR
|
||||
designator ::= unpack
|
||||
designator ::= unpack_list
|
||||
|
||||
stmt ::= classdef
|
||||
stmt ::= call_stmt
|
||||
|
||||
@@ -172,7 +153,6 @@ class Python2Parser(PythonParser):
|
||||
stmt ::= ifelsestmt
|
||||
|
||||
stmt ::= whilestmt
|
||||
stmt ::= whilenotstmt
|
||||
stmt ::= while1stmt
|
||||
stmt ::= whileelsestmt
|
||||
stmt ::= while1elsestmt
|
||||
@@ -307,6 +287,11 @@ class Python2Parser(PythonParser):
|
||||
|
||||
'''
|
||||
|
||||
def p_dictcomp2(self, args):
|
||||
""""
|
||||
dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
|
||||
"""
|
||||
|
||||
def p_genexpr2(self, args):
|
||||
'''
|
||||
genexpr ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
|
||||
@@ -395,3 +380,8 @@ class Python2Parser(PythonParser):
|
||||
|
||||
class Python2ParserSingle(Python2Parser, PythonParserSingle):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Check grammar
|
||||
p = Python2Parser()
|
||||
p.checkGrammar()
|
||||
|
@@ -6,29 +6,16 @@
|
||||
import string
|
||||
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
from uncompyle6.parsers.astnode import AST
|
||||
from uncompyle6.parser import PythonParserSingle, ParserError, nop_func
|
||||
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
|
||||
|
||||
class Python23Parser(PythonParser):
|
||||
|
||||
class Python23Parser(GenericASTBuilder):
|
||||
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
|
||||
GenericASTBuilder.__init__(self, AST, 'stmts', debug=debug_parser)
|
||||
super(Python23Parser, self).__init__(AST, 'stmts', debug=debug_parser)
|
||||
self.customized = {}
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Remove recursive references to allow garbage
|
||||
collector to collect this object.
|
||||
"""
|
||||
for dict in (self.rule2func, self.rules, self.rule2name, self.first):
|
||||
for i in dict.keys():
|
||||
dict[i] = None
|
||||
for i in dir(self):
|
||||
setattr(self, i, None)
|
||||
|
||||
def error(self, token):
|
||||
raise ParserError(token, token.offset)
|
||||
|
||||
def typestring(self, token):
|
||||
return token.type
|
||||
# FIXME: A lot of the functions below overwrite what is in parse.py which
|
||||
# have more rules. Probly that should be stripped down more instead.
|
||||
|
||||
def p_funcdef(self, args):
|
||||
'''
|
||||
@@ -171,23 +158,6 @@ class Python23Parser(GenericASTBuilder):
|
||||
stmts_opt ::= passstmt
|
||||
passstmt ::=
|
||||
|
||||
designList ::= designator designator
|
||||
designList ::= designator DUP_TOP designList
|
||||
|
||||
designator ::= STORE_FAST
|
||||
designator ::= STORE_NAME
|
||||
designator ::= STORE_GLOBAL
|
||||
designator ::= STORE_DEREF
|
||||
designator ::= expr STORE_ATTR
|
||||
designator ::= expr STORE_SLICE+0
|
||||
designator ::= expr expr STORE_SLICE+1
|
||||
designator ::= expr expr STORE_SLICE+2
|
||||
designator ::= expr expr expr STORE_SLICE+3
|
||||
designator ::= store_subscr
|
||||
store_subscr ::= expr expr STORE_SUBSCR
|
||||
designator ::= unpack
|
||||
designator ::= unpack_list
|
||||
|
||||
stmt ::= classdef
|
||||
stmt ::= call_stmt
|
||||
call_stmt ::= expr POP_TOP
|
||||
@@ -208,7 +178,7 @@ class Python23Parser(GenericASTBuilder):
|
||||
|
||||
stmt ::= raise_stmt
|
||||
raise_stmt ::= exprlist RAISE_VARARGS
|
||||
raise_stmt ::= nullexprlist RAISE_VARARGS
|
||||
raise_stmt ::= RAISE_VARARGS
|
||||
|
||||
stmt ::= exec_stmt
|
||||
exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT
|
||||
@@ -285,12 +255,12 @@ class Python23Parser(GenericASTBuilder):
|
||||
try_end ::= except_else
|
||||
except_else ::= END_FINALLY TRY_ELSE_START stmts TRY_ELSE_END
|
||||
|
||||
except_stmt ::= except_cond except_stmt
|
||||
except_stmt ::= except_stmt except_cond
|
||||
except_stmt ::= except_conds try_end
|
||||
except_stmt ::= except try_end
|
||||
except_stmt ::= try_end
|
||||
|
||||
except_conds ::= except_cond except_conds
|
||||
except_conds ::= except_conds except_cond
|
||||
except_conds ::=
|
||||
|
||||
except_cond ::= except_cond1
|
||||
@@ -440,8 +410,6 @@ class Python23Parser(GenericASTBuilder):
|
||||
|
||||
exprlist ::= exprlist expr
|
||||
exprlist ::= expr
|
||||
|
||||
nullexprlist ::=
|
||||
'''
|
||||
|
||||
def nonterminal(self, nt, args):
|
||||
@@ -532,5 +500,10 @@ class Python23Parser(GenericASTBuilder):
|
||||
class Python23ParserSingle(Python23Parser, PythonParserSingle):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Check grammar
|
||||
p = Python23Parser()
|
||||
p.checkGrammar()
|
||||
|
||||
# local variables:
|
||||
# tab-width: 4
|
||||
|
@@ -21,3 +21,8 @@ class Python26Parser(Python2Parser):
|
||||
|
||||
class Python26ParserSingle(Python2Parser, PythonParserSingle):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Check grammar
|
||||
p = Python26Parser()
|
||||
p.checkGrammar()
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) 1999 John Aycock
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2015, 2016 Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
#
|
||||
# See LICENSE for license
|
||||
"""
|
||||
@@ -56,6 +56,11 @@ class Python3Parser(PythonParser):
|
||||
# See also common Python p_list_comprehension
|
||||
"""
|
||||
|
||||
def p_dictcomp3(self, args):
|
||||
""""
|
||||
dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
|
||||
"""
|
||||
|
||||
def p_grammar(self, args):
|
||||
'''
|
||||
sstmt ::= stmt
|
||||
@@ -111,23 +116,6 @@ class Python3Parser(PythonParser):
|
||||
else_suitec ::= c_stmts
|
||||
else_suitec ::= return_stmts
|
||||
|
||||
designList ::= designator designator
|
||||
designList ::= designator DUP_TOP designList
|
||||
|
||||
designator ::= STORE_FAST
|
||||
designator ::= STORE_NAME
|
||||
designator ::= STORE_GLOBAL
|
||||
designator ::= STORE_DEREF
|
||||
designator ::= expr STORE_ATTR
|
||||
designator ::= expr STORE_SLICE+0
|
||||
designator ::= expr expr STORE_SLICE+1
|
||||
designator ::= expr expr STORE_SLICE+2
|
||||
designator ::= expr expr expr STORE_SLICE+3
|
||||
designator ::= store_subscr
|
||||
store_subscr ::= expr expr STORE_SUBSCR
|
||||
designator ::= unpack
|
||||
designator ::= unpack_list
|
||||
|
||||
stmt ::= classdef
|
||||
stmt ::= call_stmt
|
||||
|
||||
@@ -170,7 +158,6 @@ class Python3Parser(PythonParser):
|
||||
stmt ::= ifelsestmt
|
||||
|
||||
stmt ::= whilestmt
|
||||
stmt ::= whilenotstmt
|
||||
stmt ::= while1stmt
|
||||
stmt ::= whileelsestmt
|
||||
stmt ::= while1elsestmt
|
||||
@@ -446,6 +433,10 @@ class Python3Parser(PythonParser):
|
||||
GET_ITER CALL_FUNCTION_1
|
||||
listcomp ::= {expr}^n LOAD_LISTCOMP MAKE_CLOSURE
|
||||
GET_ITER CALL_FUNCTION_1
|
||||
|
||||
dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr
|
||||
GET_ITER CALL_FUNCTION_1
|
||||
|
||||
Python < 3.4
|
||||
listcomp ::= LOAD_LISTCOMP MAKE_FUNCTION_0 expr
|
||||
GET_ITER CALL_FUNCTION_1
|
||||
@@ -457,6 +448,7 @@ class Python3Parser(PythonParser):
|
||||
dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr
|
||||
GET_ITER CALL_FUNCTION_1
|
||||
|
||||
|
||||
# build_class (see load_build_class)
|
||||
|
||||
build_list ::= {expr}^n BUILD_LIST_n
|
||||
@@ -494,6 +486,22 @@ class Python3Parser(PythonParser):
|
||||
rule = ("listcomp ::= LOAD_LISTCOMP MAKE_FUNCTION_0 expr "
|
||||
"GET_ITER CALL_FUNCTION_1")
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
elif opname == 'LOAD_DICTCOMP':
|
||||
if self.version >= 3.4:
|
||||
rule = ("dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr "
|
||||
"GET_ITER CALL_FUNCTION_1")
|
||||
else:
|
||||
rule = ("dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr "
|
||||
"GET_ITER CALL_FUNCTION_1")
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
elif opname == 'LOAD_SETCOMP':
|
||||
if self.version >= 3.4:
|
||||
rule = ("setcomp ::= LOAD_SETCOMP LOAD_CONST MAKE_FUNCTION_0 expr "
|
||||
"GET_ITER CALL_FUNCTION_1")
|
||||
else:
|
||||
rule = ("setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr "
|
||||
"GET_ITER CALL_FUNCTION_1")
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
elif opname == 'LOAD_BUILD_CLASS':
|
||||
self.custom_build_class_rule(opname, i, token, tokens, customize)
|
||||
elif opname_base in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'):
|
||||
@@ -638,3 +646,8 @@ class Python34ParserSingle(Python34Parser, PythonParserSingle):
|
||||
|
||||
class Python35onParserSingle(Python35onParser, PythonParserSingle):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Check grammar
|
||||
p = Python3Parser()
|
||||
p.checkGrammar()
|
||||
|
@@ -101,6 +101,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
self.classes = []
|
||||
self.pending_newlines = 0
|
||||
self.hide_internal = False
|
||||
self.name = None
|
||||
|
||||
self.offsets = {}
|
||||
self.last_finish = -1
|
||||
@@ -285,11 +286,17 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
node[0].parent = node
|
||||
self.last_finish = len(self.f.getvalue())
|
||||
self.preorder(node[0])
|
||||
finish = len(self.f.getvalue())
|
||||
if hasattr(node[0], 'offset'):
|
||||
self.set_pos_info(node[0], self.last_finish, )
|
||||
self.write(')')
|
||||
self.last_finish = len(self.f.getvalue())
|
||||
self.last_finish = finish + 1
|
||||
else:
|
||||
node[0].parent = node
|
||||
start = len(self.f.getvalue())
|
||||
self.preorder(node[0])
|
||||
if hasattr(node[0], 'offset'):
|
||||
self.set_pos_info(node[0], start, len(self.f.getvalue()))
|
||||
self.prec = p
|
||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||
self.prune()
|
||||
@@ -461,7 +468,6 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
|
||||
def n_mkfunc(self, node):
|
||||
start = len(self.f.getvalue())
|
||||
old_name = self.name
|
||||
if self.version >= 3.0:
|
||||
# LOAD_CONST code object ..
|
||||
# LOAD_CONST 'x0' if >= 3.3
|
||||
@@ -484,7 +490,6 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
self.write(func_name)
|
||||
self.indentMore()
|
||||
self.make_function(node, isLambda=False, code_index=code_index)
|
||||
self.name = old_name
|
||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||
if len(self.param_stack) > 1:
|
||||
self.write('\n\n')
|
||||
@@ -493,6 +498,29 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
self.indentLess()
|
||||
self.prune() # stop recursing
|
||||
|
||||
def n_list_compr(self, node):
|
||||
"""List comprehensions the way they are done in Python 2."""
|
||||
p = self.prec
|
||||
self.prec = 27
|
||||
n = node[-1]
|
||||
assert n == 'list_iter'
|
||||
# find innermost node
|
||||
while n == 'list_iter':
|
||||
n = n[0] # recurse one step
|
||||
if n == 'list_for': n = n[3]
|
||||
elif n == 'list_if': n = n[2]
|
||||
elif n == 'list_if_not': n= n[2]
|
||||
assert n == 'lc_body'
|
||||
if node[0].type.startswith('BUILD_LIST'):
|
||||
start = len(self.f.getvalue())
|
||||
self.set_pos_info(node[0], start, start+1)
|
||||
self.write( '[ ')
|
||||
self.preorder(n[0]) # lc_body
|
||||
self.preorder(node[-1]) # for/if parts
|
||||
self.write( ' ]')
|
||||
self.prec = p
|
||||
self.prune() # stop recursing
|
||||
|
||||
def comprehension_walk(self, node, iter_index, code_index=-5):
|
||||
p = self.prec
|
||||
self.prec = 27
|
||||
@@ -557,27 +585,43 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
|
||||
ast = self.build_ast(code._tokens, code._customize)
|
||||
self.customize(code._customize)
|
||||
ast = ast[0][0][0][0][0]
|
||||
# skip over stmts sstmt smt
|
||||
ast = ast[0][0][0]
|
||||
|
||||
n = ast[iter_index]
|
||||
assert n == 'list_iter'
|
||||
if ast in ['setcomp_func', 'dictcomp_func']:
|
||||
for k in ast:
|
||||
if k == 'comp_iter':
|
||||
n = k
|
||||
elif k == 'designator':
|
||||
designator = k
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
ast = ast[0][0]
|
||||
n = ast[iter_index]
|
||||
assert n == 'list_iter'
|
||||
|
||||
## FIXME: I'm not totally sure this is right.
|
||||
|
||||
# find innermost node
|
||||
while n == 'list_iter':
|
||||
if_node = None
|
||||
while n in ('list_iter', 'comp_iter'):
|
||||
n = n[0] # recurse one step
|
||||
if n == 'list_for':
|
||||
designator = n[2]
|
||||
if n[2] == 'designator':
|
||||
designator = n[2]
|
||||
n = n[3]
|
||||
elif n == 'list_if':
|
||||
# FIXME: just a guess
|
||||
designator = n[1]
|
||||
elif n in ['list_if', 'list_if_not', 'comp_if']:
|
||||
if_node = n[0]
|
||||
if n[1] == 'designator':
|
||||
designator = n[1]
|
||||
n = n[2]
|
||||
pass
|
||||
pass
|
||||
|
||||
n = n[2]
|
||||
elif n == 'list_if_not':
|
||||
# FIXME: just a guess
|
||||
designator = n[1]
|
||||
n = n[2]
|
||||
assert n == 'lc_body', ast
|
||||
assert n.type in ('lc_body', 'comp_body'), ast
|
||||
assert designator, "Couldn't find designator in list/set comprehension"
|
||||
|
||||
self.preorder(n[0])
|
||||
self.write(' for ')
|
||||
@@ -589,7 +633,9 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
node[-3].parent = node
|
||||
self.preorder(node[-3])
|
||||
self.set_pos_info(node[-3], start, len(self.f.getvalue()))
|
||||
# self.preorder(ast[iter_index])
|
||||
if if_node:
|
||||
self.write(' if ')
|
||||
self.preorder(if_node)
|
||||
self.prec = p
|
||||
|
||||
def listcomprehension_walk2(self, node):
|
||||
@@ -657,11 +703,28 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
def n_setcomp(self, node):
|
||||
start = len(self.f.getvalue())
|
||||
self.write('{')
|
||||
self.comprehension_walk(node, 4)
|
||||
if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']:
|
||||
start = len(self.f.getvalue())
|
||||
self.set_pos_info(node[0], start-1, start)
|
||||
self.listcomprehension_walk3(node, 1, 0)
|
||||
else:
|
||||
self.comprehension_walk(node, iter_index=4)
|
||||
self.write('}')
|
||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||
self.prune()
|
||||
|
||||
def n_listcomp(self, node):
|
||||
self.write('[')
|
||||
if node[0].type == 'load_closure':
|
||||
self.listcomprehension_walk2(node)
|
||||
else:
|
||||
if node[0] == 'LOAD_LISTCOMP':
|
||||
start = len(self.f.getvalue())
|
||||
self.set_pos_info(node[0], start-1, start)
|
||||
self.listcomprehension_walk3(node, 1, 0)
|
||||
self.write(']')
|
||||
self.prune()
|
||||
|
||||
def n_classdef(self, node):
|
||||
# class definition ('class X(A,B,C):')
|
||||
cclass = self.currentclass
|
||||
@@ -669,6 +732,10 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
if self.version > 3.0:
|
||||
currentclass = node[1][0].pattr
|
||||
buildclass = node[0]
|
||||
if buildclass[0] == 'LOAD_BUILD_CLASS':
|
||||
start = len(self.f.getvalue())
|
||||
self.set_pos_info(buildclass[0], start, start + len('class')+2)
|
||||
|
||||
if buildclass[1][0] == 'kwargs':
|
||||
subclass = buildclass[1][1].attr
|
||||
subclass_info = node[0]
|
||||
@@ -736,6 +803,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
|
||||
rn = self.return_none
|
||||
self.return_none = returnNone
|
||||
old_name = self.name
|
||||
self.name = name
|
||||
# if code would be empty, append 'pass'
|
||||
if len(ast) == 0:
|
||||
@@ -743,6 +811,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
||||
else:
|
||||
self.customize(customize)
|
||||
self.text = self.traverse(ast, isLambda=isLambda)
|
||||
self.name = old_name
|
||||
self.return_none = rn
|
||||
|
||||
def build_ast(self, tokens, customize, isLambda=False, noneInNames=False):
|
||||
@@ -1549,6 +1618,9 @@ if __name__ == '__main__':
|
||||
def get_code_for_fn(fn):
|
||||
return fn.__code__
|
||||
|
||||
def test():
|
||||
[x for x in range(3)]
|
||||
|
||||
def gcd(a, b):
|
||||
if a > b:
|
||||
(a, b) = (b, a)
|
||||
@@ -1561,7 +1633,7 @@ if __name__ == '__main__':
|
||||
return gcd(b-a, a)
|
||||
|
||||
# check_args(['3', '5'])
|
||||
deparse_test(get_code_for_fn(gcd))
|
||||
# deparse_test(get_code_for_fn(gcd))
|
||||
deparse_test(get_code_for_fn(test))
|
||||
# deparse_test(get_code_for_fn(FragmentsWalker.fixup_offsets))
|
||||
# deparse_test(inspect.currentframe().f_code)
|
||||
|
@@ -536,6 +536,7 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
self.classes = []
|
||||
self.pending_newlines = 0
|
||||
self.hide_internal = True
|
||||
self.name = None
|
||||
self.version = version
|
||||
|
||||
if 2.0 <= version <= 2.3:
|
||||
@@ -1052,7 +1053,10 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
|
||||
def n_setcomp(self, node):
|
||||
self.write('{')
|
||||
self.comprehension_walk(node, iter_index=4)
|
||||
if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']:
|
||||
self.listcomprehension_walk3(node, 1, 0)
|
||||
else:
|
||||
self.comprehension_walk(node, iter_index=4)
|
||||
self.write('}')
|
||||
self.prune()
|
||||
|
||||
@@ -1071,40 +1075,52 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
|
||||
ast = self.build_ast(code._tokens, code._customize)
|
||||
self.customize(code._customize)
|
||||
ast = ast[0][0][0][0][0]
|
||||
|
||||
n = ast[iter_index]
|
||||
assert n == 'list_iter'
|
||||
# skip over stmts sstmt smt
|
||||
ast = ast[0][0][0]
|
||||
designator = None
|
||||
if ast in ['setcomp_func', 'dictcomp_func']:
|
||||
for k in ast:
|
||||
if k == 'comp_iter':
|
||||
n = k
|
||||
elif k == 'designator':
|
||||
designator = k
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
ast = ast[0][0]
|
||||
n = ast[iter_index]
|
||||
assert n == 'list_iter'
|
||||
|
||||
## FIXME: I'm not totally sure this is right.
|
||||
|
||||
# find innermost node
|
||||
designator = None
|
||||
list_if_node = None
|
||||
while n == 'list_iter':
|
||||
if_node = None
|
||||
while n in ('list_iter', 'comp_iter'):
|
||||
n = n[0] # recurse one step
|
||||
if n == 'list_for':
|
||||
if n == 'list_for':
|
||||
if n[2] == 'designator':
|
||||
designator = n[2]
|
||||
n = n[3]
|
||||
elif n in ['list_if', 'list_if_not']:
|
||||
list_if_node = n[0]
|
||||
elif n in ['list_if', 'list_if_not', 'comp_if']:
|
||||
if_node = n[0]
|
||||
if n[1] == 'designator':
|
||||
designator = n[1]
|
||||
n = n[2]
|
||||
pass
|
||||
pass
|
||||
assert n == 'lc_body', ast
|
||||
assert designator, "Couldn't find designator in list comprehension"
|
||||
|
||||
assert n.type in ('lc_body', 'comp_body'), ast
|
||||
assert designator, "Couldn't find designator in list/set comprehension"
|
||||
|
||||
self.preorder(n[0])
|
||||
self.write(' for ')
|
||||
self.preorder(designator)
|
||||
self.write(' in ')
|
||||
self.preorder(node[-3])
|
||||
if list_if_node:
|
||||
if if_node:
|
||||
self.write(' if ')
|
||||
self.preorder(list_if_node)
|
||||
self.preorder(if_node)
|
||||
self.prec = p
|
||||
|
||||
def listcomprehension_walk2(self, node):
|
||||
@@ -1359,8 +1375,15 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
self.prec = 100
|
||||
lastnode = node.pop()
|
||||
lastnodetype = lastnode.type
|
||||
have_star = False
|
||||
if lastnodetype.startswith('BUILD_LIST'):
|
||||
self.write('['); endchar = ']'
|
||||
# 3.5+ has BUILD_LIST_UNPACK
|
||||
if lastnodetype == 'BUILD_LIST_UNPACK':
|
||||
# FIXME: need to handle range of BUILD_LIST_UNPACK
|
||||
have_star = True
|
||||
endchar = ''
|
||||
else:
|
||||
self.write('['); endchar = ']'
|
||||
elif lastnodetype.startswith('BUILD_TUPLE'):
|
||||
self.write('('); endchar = ')'
|
||||
elif lastnodetype.startswith('BUILD_SET'):
|
||||
@@ -1399,6 +1422,8 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
value = self.traverse(elem)
|
||||
self.write(sep, value)
|
||||
sep = line_separator
|
||||
if have_star:
|
||||
sep += '*'
|
||||
if lastnode.attr == 1 and lastnodetype.startswith('BUILD_TUPLE'):
|
||||
self.write(',')
|
||||
self.write(endchar)
|
||||
@@ -1807,7 +1832,9 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
for g in find_globals(ast, set()):
|
||||
self.println(indent, 'global ', g)
|
||||
|
||||
old_name = self.name
|
||||
self.gen_source(ast, code.co_name, code._customize)
|
||||
self.name = old_name
|
||||
code._tokens = None; code._customize = None # save memory
|
||||
self.classes.pop(-1)
|
||||
|
||||
@@ -1816,6 +1843,7 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
|
||||
rn = self.return_none
|
||||
self.return_none = returnNone
|
||||
old_name = self.name
|
||||
self.name = name
|
||||
# if code would be empty, append 'pass'
|
||||
if len(ast) == 0:
|
||||
@@ -1827,6 +1855,7 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
else:
|
||||
self.text = self.traverse(ast, isLambda=isLambda)
|
||||
self.println(self.text)
|
||||
self.name = old_name
|
||||
self.return_none = rn
|
||||
|
||||
def build_ast(self, tokens, customize, isLambda=False,
|
||||
|
Reference in New Issue
Block a user