Compare commits

..

1 Commits

Author SHA1 Message Date
rocky
39ce40004b Get ready for release 2.3.0 2016-04-30 11:22:58 -04:00
17 changed files with 195 additions and 282 deletions

View File

@@ -1,50 +1,6 @@
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>
* ChangeLog, NEWS, README.rst, __pkginfo__.py: Get ready for release
2.3.1
* README.rst, __pkginfo__.py: Get ready for release 2.3.0
2016-04-30 rocky <rocky@gnu.org>

13
NEWS
View File

@@ -1,16 +1,3 @@
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
uncompyle6 2.2.0 2016-04-30
- Spark is no longer here but pulled separate package spark_parse

View File

@@ -9,7 +9,7 @@
# Things that change more often go here.
copyright = """
Copyright (C) 2015, 2016 Rocky Bernstein <rb@dustyfeet.com>.
Copyright (C) 2015 Rocky Bernstein <rb@dustyfeet.com>.
"""
classifiers = ['Development Status :: 3 - Alpha',
@@ -31,10 +31,7 @@ classifiers = ['Development Status :: 3 - Alpha',
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
author_email = "rb@dustyfeet.com"
ftp_url = None
install_requires = ['python-spark >= 1.1.0']
license = 'GPL'
license = 'MIT'
# license = 'BSDish'
mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6'
packages = ['uncompyle6', 'uncompyle6.opcodes', 'uncompyle6.semantics', 'uncompyle6.scanners', 'uncompyle6.parsers']
@@ -50,6 +47,7 @@ def get_srcdir():
return os.path.realpath(filename)
ns = {}
version = '2.3.0'
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-2016 by Rocky Bernstein <rb@dustyfeet.com>
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com>
#
from __future__ import print_function
import sys, os, getopt
@@ -9,13 +9,11 @@ import sys, os, getopt
program = os.path.basename(__file__)
__doc__ = """
Usage:
%s [OPTIONS]... FILE
%s [--help | -h | -V | --version]
Usage: %s [OPTIONS]... FILE
Examples:
%s foo.pyc
%s foo.py
%s foo.pyc
%s foo.py
%s -o foo.pydis foo.pyc
%s -o /tmp foo.pyc
@@ -26,7 +24,7 @@ Options:
<path>
--help show this message
""" % ((program,) * 6)
""" % ((program,) * 5)
Usage_short = \
@@ -34,7 +32,6 @@ Usage_short = \
from uncompyle6 import check_python_version
from uncompyle6.disas import disassemble_files
from uncompyle6.version import VERSION
check_python_version(program)
@@ -43,7 +40,7 @@ out_base = None
try:
opts, files = getopt.getopt(sys.argv[1:], 'hVo:', ['help', 'version'])
opts, files = getopt.getopt(sys.argv[1:], 'ho:', ['help'])
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
sys.exit(-1)
@@ -51,9 +48,6 @@ 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,23 +1,16 @@
#!/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>
#
from __future__ import print_function
import sys, os, getopt, time
# Copyright (c) 2015 by Rocky Bernstein
program = os.path.basename(__file__)
__doc__ = """
Usage:
%s [OPTIONS]... [ FILE | DIR]...
%s [--help | -h | --V | --version]
"""
Usage: uncompyle6 [OPTIONS]... [ FILE | DIR]...
Examples:
%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
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
Options:
-o <path> output decompiled files to this path:
@@ -41,25 +34,26 @@ Options:
Debugging Options:
--asm -a include byte-code (disables --verify)
--grammar -g show matching grammar
--tree -t include syntax tree (disables --verify)
--treee -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)
""" % ((program,) * 6
"""
from __future__ import print_function
import sys, os, getopt, time
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 [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
%s [--help | -h | --version | -V]
""" % (program, program))
%s [--help] [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
""" % program)
sys.exit(1)
@@ -74,8 +68,8 @@ timestamp = False
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
try:
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
'help asm grammar recurse timestamp tree verify version '
opts, files = getopt.getopt(sys.argv[1:], 'hagtdro:c:p:',
'help asm grammar recurse timestamp tree verify '
'showgrammar'.split(' '))
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
@@ -86,9 +80,6 @@ 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,24 +2,29 @@
"""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, \
license, long_description, \
long_description, \
modname, packages, py_modules, scripts, \
short_desc, web, zip_safe
short_desc, version, 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,
@@ -28,5 +33,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

@@ -1,7 +0,0 @@
# 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,8 +30,6 @@ 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
@@ -52,11 +50,6 @@ 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,6 +18,7 @@ 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,51 +192,6 @@ 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)
@@ -246,11 +201,12 @@ def parse(p, tokens, customize):
def get_python_parser(version, debug_parser, compile_mode='exec'):
"""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.
"""
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.
"""
if version < 3.0:
@@ -261,34 +217,13 @@ def get_python_parser(version, debug_parser, compile_mode='exec'):
p = parse2.Python2ParserSingle(debug_parser)
else:
import uncompyle6.parsers.parse3 as parse3
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)
if compile_mode == 'exec':
p = parse3.Python3Parser(debug_parser)
else:
if compile_mode == 'exec':
p = parse3.Python3Parser(debug_parser)
else:
p = parse3.Python3ParserSingle(debug_parser)
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, PythonParserSingle, nop_func
from uncompyle6.parser import PythonParser, nop_func
from uncompyle6.parsers.astnode import AST
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6 import PYTHON3
class Python2Parser(PythonParser):
@@ -31,14 +31,52 @@ class Python2Parser(PythonParser):
super(Python2Parser, self).__init__(AST, 'stmts', debug=debug_parser)
self.customized = {}
def p_list_comprehension2(self, args):
"""
list_for ::= expr _for designator list_iter JUMP_BACK
"""
def p_setcomp2(self, args):
def p_list_comprehension(self, args):
'''
# This is different in python3 - should it be?
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 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_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?
comp_for ::= expr _for designator comp_iter JUMP_BACK
'''
@@ -571,5 +609,12 @@ class Python2Parser(PythonParser):
raise Exception('unknown customize token %s' % k)
self.addRule(rule, nop_func)
class Python2ParserSingle(Python2Parser, PythonParserSingle):
pass
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
'''

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, PythonParserSingle, nop_func
from uncompyle6.parser import PythonParser, nop_func
from uncompyle6.parsers.astnode import AST
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6 import PYTHON3
@@ -42,26 +42,60 @@ class Python3Parser(PythonParser):
pass
return
def p_list_comprehension3(self, args):
"""
def p_list_comprehension(self, args):
'''
# Python3 scanner adds LOAD_LISTCOMP. Python3 does list comprehension like
# other comprehensions (set, dictionary).
# listcomp is a custom Python3 rule
# listcomp is a custom 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
# See also common Python p_list_comprehension
"""
lc_body ::= expr LIST_APPEND
'''
def p_setcomp3(self, args):
"""
# This is different in Python 2 - should it be?
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?
comp_for ::= expr _for designator comp_iter JUMP_ABSOLUTE
# See also common Python p_setcomp
"""
'''
def p_grammar(self, args):
'''
@@ -120,6 +154,9 @@ 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
@@ -241,6 +278,9 @@ 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
@@ -615,12 +655,6 @@ 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)
@@ -659,25 +693,12 @@ class Python3Parser(PythonParser):
self.add_unique_rule(rule, opname, token.attr, customize)
return
class Python32Parser(Python3Parser):
def p_32(self, args):
"""
# Store locals is only used in Python 3.2
designator ::= STORE_LOCALS
"""
class Python3ParserSingle(Python3Parser):
def p_call_stmt(self, args):
'''
# single-mode compilation. Eval-mode interactive compilation
# drops the last rule.
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
call_stmt ::= expr POP_TOP
call_stmt ::= expr PRINT_EXPR
'''

View File

@@ -14,6 +14,7 @@ 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
@@ -28,10 +29,13 @@ from uncompyle6.opcodes.opcode_35 import *
class Scanner35(scan3.Scanner3):
# 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={}):
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={}):
# Container for tokens
tokens = []
customize = {}
@@ -112,11 +116,17 @@ 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,42 +1148,29 @@ 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('{')
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
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

View File

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