Compare commits

..

9 Commits

Author SHA1 Message Date
rocky
ceb47aba9c Add -V | --version and simplfy changing it 2016-05-02 04:09:51 -04:00
rocky
08720474bf Expose uncompyle_file 2016-05-01 23:11:48 -04:00
rocky
119bb9bb26 Bug 2016-05-01 21:14:25 -04:00
rocky
4455b5e280 Add test for last fix.
Drop 2.5 test until we figure out what's wrong
2016-05-01 21:07:10 -04:00
rocky
dcbf8d2cf7 Bug in 3.5 constant map parsing 2016-05-01 20:54:42 -04:00
rocky
b52baddab6 Export module load and fns load_file, load_module 2016-05-01 13:27:00 -04:00
rocky
03bb54f8ea License is MIT
marsh.py: remove unused import
2016-05-01 11:58:46 -04:00
rocky
313e468bdc Forgot to define Python3ParserSingle 2016-05-01 07:18:29 -04:00
rocky
dc80b140c6 Start to DRY Python2 and Python3 grammars
Separate out 3.2, and 3.5+ specific grammar code
2016-05-01 07:13:36 -04:00
17 changed files with 273 additions and 193 deletions

View File

@@ -1,6 +1,50 @@
2016-05-02 rocky <rocky@gnu.org>
* __pkginfo__.py, bin/pydisassemble, bin/uncompyle6, setup.py,
uncompyle6/__init__.py, uncompyle6/version.py: Add -V | --version
and simplfy changing it
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/__init__.py: Expose uncompyle_file
2016-05-01 rocky <rocky@gnu.org>
* test/Makefile, uncompyle6/semantics/pysource.py: Bug
2016-05-01 rocky <rocky@gnu.org>
* test/Makefile, test/simple_source/expression/05_const_map.py: Add
test for last fix. Drop 2.5 test until we figure out what's wrong
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py,
uncompyle6/semantics/pysource.py: Bug in 3.5 constant map parsing
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/__init__.py: Export module load and fns load_file,
load_module
2016-05-01 rocky <rocky@gnu.org>
* __pkginfo__.py, setup.py, uncompyle6/marsh.py: License is MIT marsh.py: remove unused import
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/parsers/parse3.py: Forgot to define Python3ParserSingle
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/parser.py, uncompyle6/parsers/parse2.py,
uncompyle6/parsers/parse3.py: Start to DRY Python2 and Python3
grammars Separate out 3.2, and 3.5+ specific grammar code
2016-04-30 rocky <rocky@gnu.org>
* README.rst, __pkginfo__.py: Get ready for release 2.3.0
* ChangeLog, NEWS, README.rst, __pkginfo__.py: Get ready for release
2.3.1
2016-04-30 rocky <rocky@gnu.org>

11
NEWS
View File

@@ -1,4 +1,13 @@
uncompyle6 2.2.1 2016-04-30
uncompyle6 2.3.2 2016-05-1
- Add --version option standalone scripts
- Correct License information in package
- expose fns uncompyle_file, load_file, and load_module
- Start to DRY Python2 and Python3 grammars Separate out 3.2, and 3.5+
specific grammar code
- Fix bug in 3.5+ constant map parsing
uncompyle6 2.3.0, 2.3.1 2016-04-30
- Require spark_parser >= 1.1.0

View File

@@ -34,7 +34,7 @@ ftp_url = None
install_requires = ['python-spark >= 1.1.0']
license = 'GPL'
# license = 'BSDish'
license = 'MIT'
mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6'
packages = ['uncompyle6', 'uncompyle6.opcodes', 'uncompyle6.semantics', 'uncompyle6.scanners', 'uncompyle6.parsers']
@@ -50,7 +50,6 @@ def get_srcdir():
return os.path.realpath(filename)
ns = {}
version = '2.3.1'
web = 'https://github.com/rocky/python-uncompyle6/'
# tracebacks in zip files are funky and not debuggable

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com>
# Copyright (c) 2015-2016 by Rocky Bernstein <rb@dustyfeet.com>
#
from __future__ import print_function
import sys, os, getopt
@@ -9,11 +9,13 @@ import sys, os, getopt
program = os.path.basename(__file__)
__doc__ = """
Usage: %s [OPTIONS]... FILE
Usage:
%s [OPTIONS]... FILE
%s [--help | -h | -V | --version]
Examples:
%s foo.pyc
%s foo.py
%s foo.pyc
%s foo.py
%s -o foo.pydis foo.pyc
%s -o /tmp foo.pyc
@@ -24,7 +26,7 @@ Options:
<path>
--help show this message
""" % ((program,) * 5)
""" % ((program,) * 6)
Usage_short = \
@@ -32,6 +34,7 @@ Usage_short = \
from uncompyle6 import check_python_version
from uncompyle6.disas import disassemble_files
from uncompyle6.version import VERSION
check_python_version(program)
@@ -40,7 +43,7 @@ out_base = None
try:
opts, files = getopt.getopt(sys.argv[1:], 'ho:', ['help'])
opts, files = getopt.getopt(sys.argv[1:], 'hVo:', ['help', 'version'])
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
sys.exit(-1)
@@ -48,6 +51,9 @@ except getopt.GetoptError as e:
for opt, val in opts:
if opt in ('-h', '--help'):
print(__doc__)
sys.exit(1)
elif opt in ('-V', '--version'):
print("%s %s" % (program, VERSION))
sys.exit(0)
elif opt == '-o':
outfile = val

View File

@@ -1,16 +1,23 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015-2016 by Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2015 by Rocky Bernstein
#
from __future__ import print_function
import sys, os, getopt, time
"""
Usage: uncompyle6 [OPTIONS]... [ FILE | DIR]...
program = os.path.basename(__file__)
__doc__ = """
Usage:
%s [OPTIONS]... [ FILE | DIR]...
%s [--help | -h | --V | --version]
Examples:
uncompyle6 foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
uncompyle6 -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
uncompyle6 -o /tmp /usr/lib/python1.5 # decompile whole library
%s foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
%s -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
%s -o /tmp /usr/lib/python1.5 # decompile whole library
Options:
-o <path> output decompiled files to this path:
@@ -34,26 +41,25 @@ Options:
Debugging Options:
--asm -a include byte-code (disables --verify)
--grammar -g show matching grammar
--treee -t include syntax tree (disables --verify)
--tree -t include syntax tree (disables --verify)
Extensions of generated files:
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
+ '_unverified' successfully decompile but --verify failed
+ '_failed' decompile failed (contact author for enhancement)
"""
from __future__ import print_function
import sys, os, getopt, time
""" % ((program,) * 6
program = os.path.basename(__file__)
from uncompyle6 import verify, check_python_version
from uncompyle6.main import main, status_msg
from uncompyle6.version import VERSION
def usage():
print("""usage:
%s [--help] [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
""" % program)
%s [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
%s [--help | -h | --version | -V]
""" % (program, program))
sys.exit(1)
@@ -68,8 +74,8 @@ timestamp = False
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
try:
opts, files = getopt.getopt(sys.argv[1:], 'hagtdro:c:p:',
'help asm grammar recurse timestamp tree verify '
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
'help asm grammar recurse timestamp tree verify version '
'showgrammar'.split(' '))
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
@@ -80,6 +86,9 @@ for opt, val in opts:
if opt in ('-h', '--help'):
print(__doc__)
sys.exit(0)
elif opt in ('-V', '--version'):
print("%s %s" % (program, VERSION))
sys.exit(0)
elif opt == '--verify':
options['do_verify'] = True
elif opt in ('--asm', '-a'):

View File

@@ -2,29 +2,24 @@
"""Setup script for the 'uncompyle6' distribution."""
# Get the package information used in setup().
# from __pkginfo__ import \
# author, author_email, classifiers, \
# install_requires, license, long_description, \
# modname, packages, py_modules, \
# short_desc, version, web, zip_safe
from __pkginfo__ import \
author, author_email, \
long_description, \
license, long_description, \
modname, packages, py_modules, scripts, \
short_desc, version, web, zip_safe
short_desc, web, zip_safe
__import__('pkg_resources')
from setuptools import setup
exec(open('uncompyle6/version.py').read())
setup(
author = author,
author_email = author_email,
# classifiers = classifiers,
description = short_desc,
# install_requires = install_requires,
# license = license,
license = license,
long_description = long_description,
py_modules = py_modules,
name = modname,
@@ -33,5 +28,5 @@ setup(
url = web,
setup_requires = ['nose>=1.0'],
scripts = scripts,
version = version,
version = VERSION,
zip_safe = zip_safe)

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,7 @@
# Addresses a bug in the way Python 3.5+ handles
# creation of map constants
opts = {'highlight': True,
'start_line': -1,
'end_line': None
}
print(opts)

View File

@@ -30,6 +30,8 @@ from __future__ import print_function
import sys
__docformat__ = 'restructuredtext'
PYTHON3 = (sys.version_info >= (3, 0))
# We do this crazy way to support Python 2.6 which
@@ -50,6 +52,11 @@ def check_python_version(program):
import uncompyle6.semantics.pysource
import uncompyle6.semantics.fragments
import uncompyle6.load
# Export some functions
from uncompyle6.load import load_module, load_file
from uncompyle6.main import uncompyle_file
# Conventience functions so you can say:
# from uncompyle6 import deparse_code

View File

@@ -18,7 +18,6 @@ from __future__ import print_function
import sys, types
from struct import unpack
import uncompyle6.scanners.scanner3 as scan3
from uncompyle6.magics import PYTHON_MAGIC_INT
from uncompyle6.code import Code3

View File

@@ -192,6 +192,51 @@ class PythonParser(GenericASTBuilder):
load_attrs ::= load_attrs LOAD_ATTR
'''
def p_list_comprehension(self, args):
"""
expr ::= list_compr
list_compr ::= BUILD_LIST_0 list_iter
list_iter ::= list_for
list_iter ::= list_if
list_iter ::= list_if_not
list_iter ::= lc_body
_come_from ::= COME_FROM
_come_from ::=
list_if ::= expr jmp_false list_iter
list_if_not ::= expr jmp_true list_iter
lc_body ::= expr LIST_APPEND
"""
def p_setcomp(self, args):
"""
expr ::= setcomp
setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= setcomp_func
setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER designator comp_iter
JUMP_BACK RETURN_VALUE RETURN_LAST
comp_iter ::= comp_if
comp_iter ::= comp_ifnot
comp_iter ::= comp_for
comp_iter ::= comp_body
comp_body ::= set_comp_body
comp_body ::= gen_comp_body
comp_body ::= dict_comp_body
set_comp_body ::= expr SET_ADD
gen_comp_body ::= expr YIELD_VALUE POP_TOP
dict_comp_body ::= expr expr MAP_ADD
comp_if ::= expr jmp_false comp_iter
comp_ifnot ::= expr jmp_true comp_iter
"""
def parse(p, tokens, customize):
p.add_custom_rules(tokens, customize)
@@ -201,12 +246,11 @@ def parse(p, tokens, customize):
def get_python_parser(version, debug_parser, compile_mode='exec'):
"""
Returns parser object for Python version 2 or 3
depending on the parameter passed. *compile_mode*
is either 'exec', 'eval', or 'single'. See
https://docs.python.org/3.6/library/functions.html#compile for an explanation
of the different modes.
"""Returns parser object for Python version 2 or 3, 3.2, 3.5on,
etc., depending on the parameters passed. *compile_mode* is either
'exec', 'eval', or 'single'. See
https://docs.python.org/3.6/library/functions.html#compile for an
explanation of the different modes.
"""
if version < 3.0:
@@ -217,13 +261,34 @@ def get_python_parser(version, debug_parser, compile_mode='exec'):
p = parse2.Python2ParserSingle(debug_parser)
else:
import uncompyle6.parsers.parse3 as parse3
if compile_mode == 'exec':
p = parse3.Python3Parser(debug_parser)
if version == 3.2:
if compile_mode == 'exec':
p = parse3.Python32Parser(debug_parser)
else:
p = parse3.Python32ParserSingle(debug_parser)
elif version >= 3.5:
if compile_mode == 'exec':
p = parse3.Python35onParser(debug_parser)
else:
p = parse3.Python35onParserSingle(debug_parser)
else:
p = parse3.Python3ParserSingle(debug_parser)
if compile_mode == 'exec':
p = parse3.Python3Parser(debug_parser)
else:
p = parse3.Python3ParserSingle(debug_parser)
p.version = version
return p
class PythonParserSingle(PythonParser):
def p_call_stmt(self, args):
'''
# single-mode compilation. Eval-mode interactive compilation
# drops the last rule.
call_stmt ::= expr POP_TOP
call_stmt ::= expr PRINT_EXPR
'''
def python_parser(version, co, out=sys.stdout, showasm=False,
parser_debug=PARSER_DEFAULT_DEBUG):
assert iscode(co)

View File

@@ -17,9 +17,9 @@ that a later phase can tern into a sequence of ASCII text.
from __future__ import print_function
from uncompyle6.parser import PythonParser, nop_func
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
from uncompyle6.parsers.astnode import AST
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6 import PYTHON3
class Python2Parser(PythonParser):
@@ -31,52 +31,14 @@ class Python2Parser(PythonParser):
super(Python2Parser, self).__init__(AST, 'stmts', debug=debug_parser)
self.customized = {}
def p_list_comprehension(self, args):
'''
expr ::= list_compr
list_compr ::= BUILD_LIST_0 list_iter
list_iter ::= list_for
list_iter ::= list_if
list_iter ::= list_if_not
list_iter ::= lc_body
_come_from ::= COME_FROM
_come_from ::=
def p_list_comprehension2(self, args):
"""
list_for ::= expr _for designator list_iter JUMP_BACK
list_if ::= expr jmp_false list_iter
list_if_not ::= expr jmp_true list_iter
"""
lc_body ::= expr LIST_APPEND
def p_setcomp2(self, args):
'''
def p_setcomp(self, args):
'''
expr ::= setcomp
setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= setcomp_func
setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER designator comp_iter
JUMP_BACK RETURN_VALUE RETURN_LAST
comp_iter ::= comp_if
comp_iter ::= comp_ifnot
comp_iter ::= comp_for
comp_iter ::= comp_body
comp_body ::= set_comp_body
comp_body ::= gen_comp_body
comp_body ::= dict_comp_body
set_comp_body ::= expr SET_ADD
gen_comp_body ::= expr YIELD_VALUE POP_TOP
dict_comp_body ::= expr expr MAP_ADD
comp_if ::= expr jmp_false comp_iter
comp_ifnot ::= expr jmp_true comp_iter
# This is different in python3 - shout it be?
# This is different in python3 - should it be?
comp_for ::= expr _for designator comp_iter JUMP_BACK
'''
@@ -609,12 +571,5 @@ class Python2Parser(PythonParser):
raise Exception('unknown customize token %s' % k)
self.addRule(rule, nop_func)
class Python2ParserSingle(Python2Parser):
def p_call_stmt(self, args):
'''
# single-mode compilation. eval-mode interactive compilation
# drops the last rule.
call_stmt ::= expr POP_TOP
call_stmt ::= expr PRINT_EXPR
'''
class Python2ParserSingle(Python2Parser, PythonParserSingle):
pass

View File

@@ -17,7 +17,7 @@ that a later phase can tern into a sequence of ASCII text.
from __future__ import print_function
from uncompyle6.parser import PythonParser, nop_func
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
from uncompyle6.parsers.astnode import AST
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6 import PYTHON3
@@ -42,60 +42,26 @@ class Python3Parser(PythonParser):
pass
return
def p_list_comprehension(self, args):
'''
def p_list_comprehension3(self, args):
"""
# Python3 scanner adds LOAD_LISTCOMP. Python3 does list comprehension like
# other comprehensions (set, dictionary).
# listcomp is a custom rule
# listcomp is a custom Python3 rule
expr ::= listcomp
expr ::= list_compr
list_compr ::= BUILD_LIST_0 list_iter
list_iter ::= list_for
list_iter ::= list_if
list_iter ::= list_if_not
list_iter ::= lc_body
_come_from ::= COME_FROM
_come_from ::=
list_for ::= expr FOR_ITER designator list_iter JUMP_BACK
list_if ::= expr jmp_false list_iter
list_if_not ::= expr jmp_true list_iter
lc_body ::= expr LIST_APPEND
'''
# See also common Python p_list_comprehension
"""
def p_setcomp(self, args):
'''
expr ::= setcomp
setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= setcomp_func
setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER designator comp_iter
JUMP_BACK RETURN_VALUE RETURN_LAST
comp_iter ::= comp_if
comp_iter ::= comp_ifnot
comp_iter ::= comp_for
comp_iter ::= comp_body
comp_body ::= set_comp_body
comp_body ::= gen_comp_body
comp_body ::= dict_comp_body
set_comp_body ::= expr SET_ADD
gen_comp_body ::= expr YIELD_VALUE POP_TOP
dict_comp_body ::= expr expr MAP_ADD
comp_if ::= expr jmp_false comp_iter
comp_ifnot ::= expr jmp_true comp_iter
# This is different in python2 - should it be?
def p_setcomp3(self, args):
"""
# This is different in Python 2 - should it be?
comp_for ::= expr _for designator comp_iter JUMP_ABSOLUTE
'''
# See also common Python p_setcomp
"""
def p_grammar(self, args):
'''
@@ -154,9 +120,6 @@ class Python3Parser(PythonParser):
designList ::= designator designator
designList ::= designator DUP_TOP designList
# FIXME: Store local is only used in Python 3.2
designator ::= STORE_LOCALS
designator ::= STORE_FAST
designator ::= STORE_NAME
designator ::= STORE_GLOBAL
@@ -278,9 +241,6 @@ class Python3Parser(PythonParser):
_ifstmts_jump ::= return_if_stmts
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_from _come_from
# FIXME: this optimization is only used in Python 3.5 and beyond
_ifstmts_jump ::= c_stmts_opt
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE
iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK
@@ -655,6 +615,12 @@ class Python3Parser(PythonParser):
elif opname_base in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'):
rule = 'build_list ::= ' + 'expr ' * token.attr + opname
self.add_unique_rule(rule, opname, token.attr, customize)
elif self.version >= 3.5 and opname_base == 'BUILD_MAP':
kvlist_n = "kvlist_%s" % token.attr
rule = kvlist_n + ' ::= ' + 'expr ' * (token.attr*2)
self.add_unique_rule(rule, opname, token.attr, customize)
rule = "mapexpr ::= %s %s" % (kvlist_n, opname)
self.add_unique_rule(rule, opname, token.attr, customize)
elif opname_base in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
rule = 'unpack ::= ' + opname + ' designator' * token.attr
self.add_unique_rule(rule, opname, token.attr, customize)
@@ -693,12 +659,25 @@ class Python3Parser(PythonParser):
self.add_unique_rule(rule, opname, token.attr, customize)
return
class Python3ParserSingle(Python3Parser):
def p_call_stmt(self, args):
'''
# single-mode compilation. Eval-mode interactive compilation
# drops the last rule.
class Python32Parser(Python3Parser):
def p_32(self, args):
"""
# Store locals is only used in Python 3.2
designator ::= STORE_LOCALS
"""
call_stmt ::= expr POP_TOP
call_stmt ::= expr PRINT_EXPR
'''
class Python3ParserSingle(Python3Parser, PythonParserSingle):
pass
class Python32ParserSingle(Python32Parser, PythonParserSingle):
pass
class Python35onParser(Python3Parser):
def p_35on(self, args):
"""
# this optimization is only used in Python 3.5 and beyond
_ifstmts_jump ::= c_stmts_opt
"""
class Python35onParserSingle(Python35onParser, PythonParserSingle):
pass

View File

@@ -14,7 +14,6 @@ import dis, inspect
from array import array
import uncompyle6.scanners.scanner3 as scan3
from uncompyle6 import PYTHON_VERSION
from uncompyle6.code import iscode
from uncompyle6.scanner import Token
@@ -29,13 +28,10 @@ from uncompyle6.opcodes.opcode_35 import *
class Scanner35(scan3.Scanner3):
def disassemble(self, co, classname=None, code_objects={}):
fn = self.disassemble_built_in if PYTHON_VERSION == 3.4 \
else self.disassemble_generic
return fn(co, classname, code_objects=code_objects)
def disassemble_built_in(self, co, classname=None,
code_objects={}):
# Note: we can't use built-in disassembly routines, unless
# we do post-processing like we do here.
def disassemble(self, co, classname=None,
code_objects={}):
# Container for tokens
tokens = []
customize = {}
@@ -116,17 +112,11 @@ class Scanner35(scan3.Scanner3):
pattr = const
pass
elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
'BUILD_MAP',
'UNPACK_SEQUENCE',
'MAKE_FUNCTION', 'MAKE_CLOSURE',
'DUP_TOPX', 'RAISE_VARARGS'
):
# if opname == 'BUILD_TUPLE' and \
# self.code[self.prev[offset]] == LOAD_CLOSURE:
# continue
# else:
# op_name = '%s_%d' % (op_name, oparg)
# if opname != BUILD_SLICE:
# customize[op_name] = oparg
opname = '%s_%d' % (opname, inst.argval)
if inst.opname != 'BUILD_SLICE':
customize[opname] = inst.argval

View File

@@ -1148,29 +1148,42 @@ class SourceWalker(GenericASTTraversal, object):
"""
p = self.prec
self.prec = 100
assert node[-1] == 'kvlist'
node = node[-1] # goto kvlist
self.indentMore(INDENT_PER_LEVEL)
line_seperator = ',\n' + self.indent
sep = INDENT_PER_LEVEL[:-1]
self.write('{')
for kv in node:
assert kv in ('kv', 'kv2', 'kv3')
# kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR
# kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
# kv3 ::= expr expr STORE_MAP
if kv == 'kv':
name = self.traverse(kv[-2], indent='')
value = self.traverse(kv[1], indent=self.indent+(len(name)+2)*' ')
elif kv == 'kv2':
name = self.traverse(kv[1], indent='')
value = self.traverse(kv[-3], indent=self.indent+(len(name)+2)*' ')
elif kv == 'kv3':
name = self.traverse(kv[-2], indent='')
value = self.traverse(kv[0], indent=self.indent+(len(name)+2)*' ')
self.write(sep, name, ': ', value)
sep = line_seperator
if node[0].type.startswith('kvlist'):
# Python 3.5 style key/value list in mapexpr
l = list(node[0])
i = 0
while i < len(l):
name = self.traverse(l[i], indent='')
value = self.traverse(l[i+1], indent=self.indent+(len(name)+2)*' ')
self.write(sep, name, ': ', value)
sep = line_seperator
i += 2
else:
assert node[-1] == 'kvlist'
node = node[-1] # goto kvlist
for kv in node:
assert kv in ('kv', 'kv2', 'kv3')
# kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR
# kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
# kv3 ::= expr expr STORE_MAP
if kv == 'kv':
name = self.traverse(kv[-2], indent='')
value = self.traverse(kv[1], indent=self.indent+(len(name)+2)*' ')
elif kv == 'kv2':
name = self.traverse(kv[1], indent='')
value = self.traverse(kv[-3], indent=self.indent+(len(name)+2)*' ')
elif kv == 'kv3':
name = self.traverse(kv[-2], indent='')
value = self.traverse(kv[0], indent=self.indent+(len(name)+2)*' ')
self.write(sep, name, ': ', value)
sep = line_seperator
self.write('}')
self.indentLess(INDENT_PER_LEVEL)
self.prec = p

3
uncompyle6/version.py Normal file
View File

@@ -0,0 +1,3 @@
# This file is suitable for sourcing inside bash as
# well as importing into Python
VERSION='2.3.2'