You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 16:59:52 +08:00
Compare commits
20 Commits
release-py
...
release-2.
Author | SHA1 | Date | |
---|---|---|---|
|
af10f99776 | ||
|
0cbafa6e3a | ||
|
4afaee2a36 | ||
|
daea3c348c | ||
|
bf45260588 | ||
|
34a356d237 | ||
|
d9c1374a59 | ||
|
2e05137f2b | ||
|
267ecda070 | ||
|
7e89839777 | ||
|
c7f8edd5ef | ||
|
6a991833a3 | ||
|
28ee3f1257 | ||
|
e9588e56e2 | ||
|
7b2217fda4 | ||
|
5ca219f3d3 | ||
|
b733a1b036 | ||
|
4615cda03f | ||
|
eb92418224 | ||
|
844221cd43 |
111
ChangeLog
111
ChangeLog
@@ -1,6 +1,115 @@
|
|||||||
|
2017-06-18 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/version.py: Get ready for release 2.11.0
|
||||||
|
|
||||||
|
2017-06-13 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py: Adjust nodeInfo if it is a
|
||||||
|
Token
|
||||||
|
|
||||||
|
2017-06-13 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py: Add nonterminal node in
|
||||||
|
extractInfo
|
||||||
|
|
||||||
|
2017-06-10 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py,
|
||||||
|
uncompyle6/semantics/make_function.py: Fragment tag more expressions Revise make_function3 comment wrt args and kwargs
|
||||||
|
|
||||||
|
2017-06-10 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py: Fragment tag array subscripts
|
||||||
|
|
||||||
|
2017-06-10 R. Bernstein <rocky@users.noreply.github.com>
|
||||||
|
|
||||||
|
* README.rst: Create README.rst
|
||||||
|
|
||||||
|
2017-06-10 R. Bernstein <rocky@users.noreply.github.com>
|
||||||
|
|
||||||
|
* README.rst: Create README.rst
|
||||||
|
|
||||||
|
2017-06-10 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py: Set YIELD_VALUE offset in a
|
||||||
|
<yield> expr
|
||||||
|
|
||||||
|
2017-06-10 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/make_function.py: Python 3.2 MAKE_FUNCTION
|
||||||
|
again.. Was handling bug32/01_named_and_kwargs.py wrong again
|
||||||
|
|
||||||
|
2017-06-09 R. Bernstein <rocky@users.noreply.github.com>
|
||||||
|
|
||||||
|
* : Merge pull request #119 from rocky/scan-longconstant Simplify access to L65536 ...
|
||||||
|
|
||||||
|
2017-06-09 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/make_function.py: Attempt to document the
|
||||||
|
MAKE_FUNCTION/MAKE_LAMBDA mess... in Python 3.0+
|
||||||
|
|
||||||
|
2017-06-08 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/make_function.py: Correct make_function3 for
|
||||||
|
Pytohn 3.2
|
||||||
|
|
||||||
|
2017-06-08 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/pysource.py: Disable "continue" removal in
|
||||||
|
pysource.py "continue" could be the only statement and then removing it might
|
||||||
|
lead to a dangling "else".
|
||||||
|
|
||||||
|
2017-06-07 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py: Mark "pass" offsets. Start routine to find previous node.
|
||||||
|
|
||||||
|
2017-06-06 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py:
|
||||||
|
Remove hacky fragments try fixup... hacky call_function code is also not needed or will be reinstated
|
||||||
|
properly. Better grammar structure for Python 3.6 call_function.
|
||||||
|
|
||||||
|
2017-06-05 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py,
|
||||||
|
uncompyle6/scanners/scanner36.py: BUILD_{MAP,TUPLE}_UNPACK &
|
||||||
|
CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally succesfull right now. In fact a
|
||||||
|
regression on one of the test cases
|
||||||
|
|
||||||
|
2017-06-05 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/semantics/fragments.py: Important fragments bug fix... start, finish that had been adjusted wasn't getting reflected in
|
||||||
|
final returned deparsed.offsets dictionary. Redo keeping API
|
||||||
|
compatibility, i.e we still use namedtuple NodeInfo.
|
||||||
|
|
||||||
|
2017-06-04 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py:
|
||||||
|
Python 3.5 *args with kwargs handling. 3.5 is a snowflake here. Thank you, Python. Fully fixes Issue 95. 3.6 is broken on this source, but for a *different* reason. Sigh.
|
||||||
|
|
||||||
2017-06-03 rocky <rb@dustyfeet.com>
|
2017-06-03 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
* uncompyle6/version.py: Get ready for release 2.10.1
|
* README.rst, __pkginfo__.py,
|
||||||
|
test/simple_source/bug35/04_CALL_FUNCTION_VAR_KW.py,
|
||||||
|
uncompyle6/semantics/fragments.py: Small changes. fragment tag EXEC_STMT
|
||||||
|
|
||||||
|
2017-06-03 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* .travis.yml: Streamline .travis.yml a little bit
|
||||||
|
|
||||||
|
2017-06-03 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* __pkginfo__.py: We need six
|
||||||
|
|
||||||
|
2017-06-03 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* README.rst, circle.yml, requirements-dev.txt: Go over
|
||||||
|
administrivia
|
||||||
|
|
||||||
|
2017-06-03 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release
|
||||||
|
2.10.1
|
||||||
|
|
||||||
2017-06-03 rocky <rb@dustyfeet.com>
|
2017-06-03 rocky <rb@dustyfeet.com>
|
||||||
|
|
||||||
|
10
NEWS
10
NEWS
@@ -1,3 +1,13 @@
|
|||||||
|
uncompyle6 2.11.1 2016-06-18 Fleetwood
|
||||||
|
- Major improvements in fragment tracking
|
||||||
|
* Add nonterminal node in extractInfo
|
||||||
|
* tag more offsets in expressions
|
||||||
|
* tag array subscripts
|
||||||
|
* set YIELD value offset in a <yield> expr
|
||||||
|
* fix a long-standing bug in not adjusting final AST when melding other deparse ASTs
|
||||||
|
- Fixes yet again for make_function node handling; document what's up here
|
||||||
|
- Fix bug in snowflake Python 3.5 *args kwargs
|
||||||
|
|
||||||
uncompyle6 2.10.1 2016-06-3 Marylin Frankel
|
uncompyle6 2.10.1 2016-06-3 Marylin Frankel
|
||||||
|
|
||||||
- fix some fragments parsing bugs
|
- fix some fragments parsing bugs
|
||||||
|
@@ -56,7 +56,7 @@ This uses setup.py, so it follows the standard Python routine:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pip install -e setup.py
|
pip install -e .
|
||||||
pip install -r requirements-dev.txt
|
pip install -r requirements-dev.txt
|
||||||
python setup.py install # may need sudo
|
python setup.py install # may need sudo
|
||||||
# or if you have pyenv:
|
# or if you have pyenv:
|
||||||
@@ -171,7 +171,7 @@ See Also
|
|||||||
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here.
|
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here.
|
||||||
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Include some fixes like supporting function annotations
|
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Include some fixes like supporting function annotations
|
||||||
* The HISTORY_ file.
|
* The HISTORY_ file.
|
||||||
|
* `How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md>`_
|
||||||
.. |downloads| image:: https://img.shields.io/pypi/dd/uncompyle6.svg
|
.. |downloads| image:: https://img.shields.io/pypi/dd/uncompyle6.svg
|
||||||
.. _trepan: https://pypi.python.org/pypi/trepan
|
.. _trepan: https://pypi.python.org/pypi/trepan
|
||||||
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
||||||
|
@@ -33,7 +33,7 @@ classifiers = ['Development Status :: 5 - Production/Stable',
|
|||||||
# The rest in alphabetic order
|
# The rest in alphabetic order
|
||||||
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
||||||
author_email = "rb@dustyfeet.com"
|
author_email = "rb@dustyfeet.com"
|
||||||
entry_points={
|
entry_points = {
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'uncompyle6=uncompyle6.bin.uncompile:main_bin',
|
'uncompyle6=uncompyle6.bin.uncompile:main_bin',
|
||||||
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
||||||
|
BIN
test/bytecode_3.6/04_CALL_FUNCTION_VAR_KW.pyc-notyet
Normal file
BIN
test/bytecode_3.6/04_CALL_FUNCTION_VAR_KW.pyc-notyet
Normal file
Binary file not shown.
@@ -1,4 +1,5 @@
|
|||||||
# sql/schema.py
|
# sql/schema.py
|
||||||
|
# Note that kwargs comes before "positional" args
|
||||||
def tometadata(self, metadata, schema, Table, args, name=None):
|
def tometadata(self, metadata, schema, Table, args, name=None):
|
||||||
table = Table(
|
table = Table(
|
||||||
name, metadata, schema=schema,
|
name, metadata, schema=schema,
|
||||||
|
@@ -496,8 +496,8 @@ class Python3Parser(PythonParser):
|
|||||||
token.type = self.call_fn_name(token)
|
token.type = self.call_fn_name(token)
|
||||||
uniq_param = args_kw + args_pos
|
uniq_param = args_kw + args_pos
|
||||||
if self.version == 3.5 and opname.startswith('CALL_FUNCTION_VAR'):
|
if self.version == 3.5 and opname.startswith('CALL_FUNCTION_VAR'):
|
||||||
# Python 3.5 changes the stack position of where * args, the
|
# Python 3.5 changes the stack position of *args. KW args come
|
||||||
# first LOAD_FAST, below are located.
|
# after *args.
|
||||||
# Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX
|
# Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX
|
||||||
if opname.endswith('KW'):
|
if opname.endswith('KW'):
|
||||||
kw = 'expr '
|
kw = 'expr '
|
||||||
@@ -507,11 +507,17 @@ class Python3Parser(PythonParser):
|
|||||||
('pos_arg ' * args_pos) +
|
('pos_arg ' * args_pos) +
|
||||||
('kwarg ' * args_kw) + kw + token.type)
|
('kwarg ' * args_kw) + kw + token.type)
|
||||||
self.add_unique_rule(rule, token.type, uniq_param, customize)
|
self.add_unique_rule(rule, token.type, uniq_param, customize)
|
||||||
|
if self.version >= 3.6 and opname == 'CALL_FUNCTION_EX_KW':
|
||||||
rule = ('call_function ::= expr ' +
|
rule = ('call_function36 ::= '
|
||||||
('pos_arg ' * args_pos) +
|
'expr build_tuple_unpack_with_call build_map_unpack_with_call '
|
||||||
('kwarg ' * args_kw) +
|
'CALL_FUNCTION_EX_KW_1')
|
||||||
'expr ' * nak + token.type)
|
self.add_unique_rule(rule, token.type, uniq_param, customize)
|
||||||
|
rule = 'call_function ::= call_function36'
|
||||||
|
else:
|
||||||
|
rule = ('call_function ::= expr ' +
|
||||||
|
('pos_arg ' * args_pos) +
|
||||||
|
('kwarg ' * args_kw) +
|
||||||
|
'expr ' * nak + token.type)
|
||||||
|
|
||||||
self.add_unique_rule(rule, token.type, uniq_param, customize)
|
self.add_unique_rule(rule, token.type, uniq_param, customize)
|
||||||
if self.version >= 3.5:
|
if self.version >= 3.5:
|
||||||
@@ -610,9 +616,9 @@ class Python3Parser(PythonParser):
|
|||||||
assign2_pypy ::= expr expr designator designator
|
assign2_pypy ::= expr expr designator designator
|
||||||
""", nop_func)
|
""", nop_func)
|
||||||
continue
|
continue
|
||||||
elif opname in ('CALL_FUNCTION', 'CALL_FUNCTION_VAR',
|
elif (opname in ('CALL_FUNCTION', 'CALL_FUNCTION_VAR',
|
||||||
'CALL_FUNCTION_VAR_KW') \
|
'CALL_FUNCTION_VAR_KW', 'CALL_FUNCTION_EX_KW')
|
||||||
or opname.startswith('CALL_FUNCTION_KW'):
|
or opname.startswith('CALL_FUNCTION_KW')):
|
||||||
self.custom_classfunc_rule(opname, token, customize)
|
self.custom_classfunc_rule(opname, token, customize)
|
||||||
elif opname == 'LOAD_DICTCOMP':
|
elif opname == 'LOAD_DICTCOMP':
|
||||||
rule_pat = ("dictcomp ::= LOAD_DICTCOMP %sMAKE_FUNCTION_0 expr "
|
rule_pat = ("dictcomp ::= LOAD_DICTCOMP %sMAKE_FUNCTION_0 expr "
|
||||||
@@ -633,6 +639,18 @@ class Python3Parser(PythonParser):
|
|||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
rule = 'expr ::= build_list_unpack'
|
rule = 'expr ::= build_list_unpack'
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
elif opname.startswith('BUILD_TUPLE_UNPACK_WITH_CALL'):
|
||||||
|
v = token.attr
|
||||||
|
rule = ('build_tuple_unpack_with_call ::= ' + 'expr1024 ' * int(v//1024) +
|
||||||
|
'expr32 ' * int((v//32) % 32) +
|
||||||
|
'expr ' * (v % 32) + opname)
|
||||||
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
elif opname.startswith('BUILD_MAP_UNPACK_WITH_CALL'):
|
||||||
|
v = token.attr
|
||||||
|
rule = ('build_map_unpack_with_call ::= ' + 'expr1024 ' * int(v//1024) +
|
||||||
|
'expr32 ' * int((v//32) % 32) +
|
||||||
|
'expr ' * (v % 32) + opname)
|
||||||
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
elif opname_base in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'):
|
elif opname_base in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'):
|
||||||
v = token.attr
|
v = token.attr
|
||||||
rule = ('build_list ::= ' + 'expr1024 ' * int(v//1024) +
|
rule = ('build_list ::= ' + 'expr1024 ' * int(v//1024) +
|
||||||
@@ -642,7 +660,10 @@ class Python3Parser(PythonParser):
|
|||||||
if opname_base == 'BUILD_TUPLE':
|
if opname_base == 'BUILD_TUPLE':
|
||||||
rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname))
|
rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
rule = ('build_tuple ::= ' + 'expr1024 ' * int(v//1024) +
|
||||||
|
'expr32 ' * int((v//32) % 32) +
|
||||||
|
'expr ' * (v % 32) + opname)
|
||||||
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
elif opname == 'LOOKUP_METHOD':
|
elif opname == 'LOOKUP_METHOD':
|
||||||
# A PyPy speciality - DRY with parse2
|
# A PyPy speciality - DRY with parse2
|
||||||
self.add_unique_rule("load_attr ::= expr LOOKUP_METHOD",
|
self.add_unique_rule("load_attr ::= expr LOOKUP_METHOD",
|
||||||
|
@@ -25,12 +25,13 @@ class Python36Parser(Python35Parser):
|
|||||||
|
|
||||||
func_args36 ::= expr BUILD_TUPLE_0
|
func_args36 ::= expr BUILD_TUPLE_0
|
||||||
call_function ::= func_args36 unmapexpr CALL_FUNCTION_EX
|
call_function ::= func_args36 unmapexpr CALL_FUNCTION_EX
|
||||||
|
call_function ::= func_args36 build_map_unpack_with_call CALL_FUNCTION_EX_KW_1
|
||||||
|
|
||||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST
|
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST
|
||||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||||
|
|
||||||
call_function ::= expr expr CALL_FUNCTION_EX
|
call_function ::= expr expr CALL_FUNCTION_EX
|
||||||
call_function ::= expr expr expr CALL_FUNCTION_EX_KW
|
call_function ::= expr expr expr CALL_FUNCTION_EX_KW_1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def add_custom_rules(self, tokens, customize):
|
def add_custom_rules(self, tokens, customize):
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015, 2016 by Rocky Bernstein
|
# Copyright (c) 2015-2017 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
"""
|
"""
|
||||||
@@ -25,14 +25,14 @@ from __future__ import print_function
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from array import array
|
from array import array
|
||||||
|
|
||||||
from uncompyle6.scanner import op_has_argument
|
from uncompyle6.scanner import op_has_argument, L65536
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
|
|
||||||
import uncompyle6.scanner as scan
|
from uncompyle6.scanner import Scanner
|
||||||
|
|
||||||
class Scanner2(scan.Scanner):
|
class Scanner2(Scanner):
|
||||||
def __init__(self, version, show_asm=None, is_pypy=False):
|
def __init__(self, version, show_asm=None, is_pypy=False):
|
||||||
scan.Scanner.__init__(self, version, show_asm, is_pypy)
|
Scanner.__init__(self, version, show_asm, is_pypy)
|
||||||
self.pop_jump_if = frozenset([self.opc.PJIF, self.opc.PJIT])
|
self.pop_jump_if = frozenset([self.opc.PJIF, self.opc.PJIT])
|
||||||
self.jump_forward = frozenset([self.opc.JUMP_ABSOLUTE, self.opc.JUMP_FORWARD])
|
self.jump_forward = frozenset([self.opc.JUMP_ABSOLUTE, self.opc.JUMP_FORWARD])
|
||||||
# This is the 2.5+ default
|
# This is the 2.5+ default
|
||||||
@@ -186,7 +186,7 @@ class Scanner2(scan.Scanner):
|
|||||||
oparg = self.get_argument(offset) + extended_arg
|
oparg = self.get_argument(offset) + extended_arg
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
if op == self.opc.EXTENDED_ARG:
|
if op == self.opc.EXTENDED_ARG:
|
||||||
extended_arg = oparg * scan.L65536
|
extended_arg = oparg * L65536
|
||||||
continue
|
continue
|
||||||
if op in self.opc.hasconst:
|
if op in self.opc.hasconst:
|
||||||
const = co.co_consts[oparg]
|
const = co.co_consts[oparg]
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015, 2016 by Rocky Bernstein
|
# Copyright (c) 2015-2017 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
"""
|
"""
|
||||||
@@ -15,6 +15,7 @@ if PYTHON3:
|
|||||||
intern = sys.intern
|
intern = sys.intern
|
||||||
|
|
||||||
import uncompyle6.scanners.scanner2 as scan
|
import uncompyle6.scanners.scanner2 as scan
|
||||||
|
from uncompyle6.scanner import L65536
|
||||||
|
|
||||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||||
from xdis.opcodes import opcode_26
|
from xdis.opcodes import opcode_26
|
||||||
@@ -178,7 +179,7 @@ class Scanner26(scan.Scanner2):
|
|||||||
oparg = self.get_argument(offset) + extended_arg
|
oparg = self.get_argument(offset) + extended_arg
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
if op == self.opc.EXTENDED_ARG:
|
if op == self.opc.EXTENDED_ARG:
|
||||||
extended_arg = oparg * scan.L65536
|
extended_arg = oparg * L65536
|
||||||
continue
|
continue
|
||||||
if op in self.opc.hasconst:
|
if op in self.opc.hasconst:
|
||||||
const = co.co_consts[oparg]
|
const = co.co_consts[oparg]
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2016 by Rocky Bernstein
|
# Copyright (c) 2016-2017 by Rocky Bernstein
|
||||||
"""
|
"""
|
||||||
Python 3.6 bytecode scanner/deparser
|
Python 3.6 bytecode scanner/deparser
|
||||||
|
|
||||||
@@ -28,8 +28,12 @@ class Scanner36(Scanner3):
|
|||||||
if t.op == self.opc.CALL_FUNCTION_EX and t.attr & 1:
|
if t.op == self.opc.CALL_FUNCTION_EX and t.attr & 1:
|
||||||
t.type = 'CALL_FUNCTION_EX_KW'
|
t.type = 'CALL_FUNCTION_EX_KW'
|
||||||
pass
|
pass
|
||||||
if t.op == self.opc.CALL_FUNCTION_KW:
|
elif t.op == self.opc.CALL_FUNCTION_KW:
|
||||||
t.type = 'CALL_FUNCTION_KW_{t.attr}'.format(**locals())
|
t.type = 'CALL_FUNCTION_KW_{t.attr}'.format(**locals())
|
||||||
|
elif t.op == self.opc.BUILD_TUPLE_UNPACK_WITH_CALL:
|
||||||
|
t.type = 'BUILD_TUPLE_UNPACK_WITH_CALL_%d' % t.attr
|
||||||
|
elif t.op == self.opc.BUILD_MAP_UNPACK_WITH_CALL:
|
||||||
|
t.type = 'BUILD_MAP_UNPACK_WITH_CALL_%d' % t.attr
|
||||||
pass
|
pass
|
||||||
return tokens, customize
|
return tokens, customize
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ do it recursively which is where offsets are probably located.
|
|||||||
|
|
||||||
For example in:
|
For example in:
|
||||||
'importmultiple': ( '%|import%b %c%c\n', 0, 2, 3 ),
|
'importmultiple': ( '%|import%b %c%c\n', 0, 2, 3 ),
|
||||||
|
n
|
||||||
The node position 0 will be associated with "import".
|
The node position 0 will be associated with "import".
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -77,11 +77,12 @@ from uncompyle6.semantics.consts import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||||
|
from spark_parser.ast import GenericASTTraversalPruningException
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
NodeInfo = namedtuple("NodeInfo", "node start finish")
|
NodeInfo = namedtuple("NodeInfo", "node start finish")
|
||||||
ExtractInfo = namedtuple("ExtractInfo",
|
ExtractInfo = namedtuple("ExtractInfo",
|
||||||
"lineNo lineStartOffset markerLine selectedLine selectedText")
|
"lineNo lineStartOffset markerLine selectedLine selectedText nonterminal")
|
||||||
|
|
||||||
TABLE_DIRECT_FRAGMENT = {
|
TABLE_DIRECT_FRAGMENT = {
|
||||||
'break_stmt': ( '%|%rbreak\n', ),
|
'break_stmt': ( '%|%rbreak\n', ),
|
||||||
@@ -159,8 +160,9 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
def set_pos_info(self, node, start, finish, name=None):
|
def set_pos_info(self, node, start, finish, name=None):
|
||||||
if name is None: name = self.name
|
if name is None: name = self.name
|
||||||
if hasattr(node, 'offset'):
|
if hasattr(node, 'offset'):
|
||||||
self.offsets[name, node.offset] = \
|
node.start = start
|
||||||
NodeInfo(node = node, start = start, finish = finish)
|
node.finish = finish
|
||||||
|
self.offsets[name, node.offset] = node
|
||||||
|
|
||||||
if hasattr(node, 'parent'):
|
if hasattr(node, 'parent'):
|
||||||
assert node.parent != node
|
assert node.parent != node
|
||||||
@@ -176,6 +178,34 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def table_r_node(self, node):
|
||||||
|
"""General pattern where the last node should should
|
||||||
|
get the text span attributes of the entire tree"""
|
||||||
|
start = len(self.f.getvalue())
|
||||||
|
try:
|
||||||
|
self.default(node)
|
||||||
|
except GenericASTTraversalPruningException:
|
||||||
|
final = len(self.f.getvalue())
|
||||||
|
self.set_pos_info(node, start, final)
|
||||||
|
self.set_pos_info(node[-1], start, final)
|
||||||
|
raise GenericASTTraversalPruningException
|
||||||
|
|
||||||
|
n_slice0 = n_slice1 = n_slice2 = n_slice3 = n_binary_subscr = table_r_node
|
||||||
|
n_augassign_1 = n_print_item = exec_stmt = print_to_item = del_stmt = table_r_node
|
||||||
|
n_classdefco1 = n_classdefco2 = except_cond1 = except_cond2 = table_r_node
|
||||||
|
|
||||||
|
def n_passtmt(self, node):
|
||||||
|
start = len(self.f.getvalue()) + len(self.indent)
|
||||||
|
self.set_pos_info(node, start, start+len("pass"))
|
||||||
|
self.default(node)
|
||||||
|
|
||||||
|
def n_trystmt(self, node):
|
||||||
|
start = len(self.f.getvalue()) + len(self.indent)
|
||||||
|
self.set_pos_info(node[0], start, start+len("try:"))
|
||||||
|
self.default(node)
|
||||||
|
|
||||||
|
n_tryelsestmt = n_tryelsestmtc = n_tryelsestmtl = n_tryfinallystmt = n_trystmt
|
||||||
|
|
||||||
def n_return_stmt(self, node):
|
def n_return_stmt(self, node):
|
||||||
start = len(self.f.getvalue()) + len(self.indent)
|
start = len(self.f.getvalue()) + len(self.indent)
|
||||||
if self.params['isLambda']:
|
if self.params['isLambda']:
|
||||||
@@ -229,6 +259,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.write(' ')
|
self.write(' ')
|
||||||
node[0].parent = node
|
node[0].parent = node
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
|
self.set_pos_info(node[-1], start, len(self.f.getvalue()))
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
@@ -366,6 +397,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.write(sep); sep = ", "
|
self.write(sep); sep = ", "
|
||||||
self.preorder(subnode)
|
self.preorder(subnode)
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
|
self.set_pos_info(node[-1], start, len(self.f.getvalue()))
|
||||||
self.println()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
@@ -1089,7 +1121,6 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
def traverse(self, node, indent=None, isLambda=False):
|
def traverse(self, node, indent=None, isLambda=False):
|
||||||
'''Buulds up fragment which can be used inside a larger
|
'''Buulds up fragment which can be used inside a larger
|
||||||
block of code'''
|
block of code'''
|
||||||
|
|
||||||
self.param_stack.append(self.params)
|
self.param_stack.append(self.params)
|
||||||
if indent is None: indent = self.indent
|
if indent is None: indent = self.indent
|
||||||
p = self.pending_newlines
|
p = self.pending_newlines
|
||||||
@@ -1184,16 +1215,38 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
if elided: selectedLine += ' ...'
|
if elided: selectedLine += ' ...'
|
||||||
|
|
||||||
|
if isinstance(nodeInfo, Token):
|
||||||
|
nodeInfo = nodeInfo.parent
|
||||||
|
else:
|
||||||
|
nodeInfo = nodeInfo
|
||||||
|
|
||||||
|
if isinstance(nodeInfo, AST):
|
||||||
|
nonterminal = nodeInfo[0]
|
||||||
|
else:
|
||||||
|
nonterminal = nodeInfo.node
|
||||||
|
|
||||||
return ExtractInfo(lineNo = len(lines), lineStartOffset = lineStart,
|
return ExtractInfo(lineNo = len(lines), lineStartOffset = lineStart,
|
||||||
markerLine = markerLine,
|
markerLine = markerLine,
|
||||||
selectedLine = selectedLine,
|
selectedLine = selectedLine,
|
||||||
selectedText = selectedText)
|
selectedText = selectedText,
|
||||||
|
nonterminal = nonterminal)
|
||||||
|
|
||||||
def extract_line_info(self, name, offset):
|
def extract_line_info(self, name, offset):
|
||||||
if (name, offset) not in list(self.offsets.keys()):
|
if (name, offset) not in list(self.offsets.keys()):
|
||||||
return None
|
return None
|
||||||
return self.extract_node_info(self.offsets[name, offset])
|
return self.extract_node_info(self.offsets[name, offset])
|
||||||
|
|
||||||
|
def prev_node(self, node):
|
||||||
|
prev = None
|
||||||
|
if not hasattr(node, 'parent'):
|
||||||
|
return prev
|
||||||
|
p = node.parent
|
||||||
|
for n in p:
|
||||||
|
if node == n:
|
||||||
|
return prev
|
||||||
|
prev = n
|
||||||
|
return prev
|
||||||
|
|
||||||
def extract_parent_info(self, node):
|
def extract_parent_info(self, node):
|
||||||
if not hasattr(node, 'parent'):
|
if not hasattr(node, 'parent'):
|
||||||
return None, None
|
return None, None
|
||||||
@@ -1557,25 +1610,14 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.set_pos_info(startnode, startnode_start, fin)
|
self.set_pos_info(startnode, startnode_start, fin)
|
||||||
|
|
||||||
# FIXME rocky: figure out how to get these casess to be table driven.
|
# FIXME rocky: figure out how to get these casess to be table driven.
|
||||||
#
|
|
||||||
# 1. for loops. For loops have two positions that correspond to a single text
|
|
||||||
# location. In "for i in ..." there is the initialization "i" code as well
|
|
||||||
# as the iteration code with "i". A "copy" spec like %X3,3 - copy parame
|
|
||||||
# 3 to param 2 would work
|
|
||||||
#
|
|
||||||
# 2. subroutine calls. It the last op is the call and for purposes of printing
|
# 2. subroutine calls. It the last op is the call and for purposes of printing
|
||||||
# we don't need to print anything special there. However it encompases the
|
# we don't need to print anything special there. However it encompases the
|
||||||
# entire string of the node fn(...)
|
# entire string of the node fn(...)
|
||||||
match = re.search(r'^try', startnode.type)
|
match = re.search(r'^call_function', startnode.type)
|
||||||
if match:
|
if match:
|
||||||
self.set_pos_info(node[0], startnode_start, startnode_start+len("try:"))
|
last_node = startnode[-1]
|
||||||
self.set_pos_info(node[2], node[3].finish, node[3].finish)
|
# import traceback; traceback.print_stack()
|
||||||
else:
|
self.set_pos_info(last_node, startnode_start, self.last_finish)
|
||||||
match = re.search(r'^call_function', startnode.type)
|
|
||||||
if match:
|
|
||||||
last_node = startnode[-1]
|
|
||||||
# import traceback; traceback.print_stack()
|
|
||||||
self.set_pos_info(last_node, startnode_start, self.last_finish)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -1657,6 +1699,13 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
|
|||||||
if deparsed.ERROR:
|
if deparsed.ERROR:
|
||||||
raise deparsed.ERROR
|
raise deparsed.ERROR
|
||||||
|
|
||||||
|
# To keep the API consistent with previous releases, convert
|
||||||
|
# deparse.offset values into NodeInfo items
|
||||||
|
for tup, node in deparsed.offsets.items():
|
||||||
|
deparsed.offsets[tup] = NodeInfo(node = node, start = node.start,
|
||||||
|
finish = node.finish)
|
||||||
|
|
||||||
|
deparsed.scanner = scanner
|
||||||
return deparsed
|
return deparsed
|
||||||
|
|
||||||
from bisect import bisect_right
|
from bisect import bisect_right
|
||||||
@@ -1691,6 +1740,7 @@ def deparse_code_around_offset(name, offset, version, co, out=StringIO(),
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
from uncompyle6 import IS_PYPY
|
||||||
def deparse_test(co, is_pypy=IS_PYPY):
|
def deparse_test(co, is_pypy=IS_PYPY):
|
||||||
sys_version = sys.version_info.major + (sys.version_info.minor / 10.0)
|
sys_version = sys.version_info.major + (sys.version_info.minor / 10.0)
|
||||||
walk = deparse_code(sys_version, co, showasm=False, showast=False,
|
walk = deparse_code(sys_version, co, showasm=False, showast=False,
|
||||||
|
@@ -428,10 +428,34 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None):
|
|||||||
|
|
||||||
|
|
||||||
def make_function3(self, node, isLambda, nested=1, codeNode=None):
|
def make_function3(self, node, isLambda, nested=1, codeNode=None):
|
||||||
"""Dump function definition, doc string, and function body."""
|
"""Dump function definition, doc string, and function body in
|
||||||
|
Python version 3.0 and above
|
||||||
|
"""
|
||||||
|
|
||||||
# FIXME: call make_function3 if we are self.version >= 3.0
|
# For Python 3.3, the evaluation stack in MAKE_FUNCTION is:
|
||||||
# and then simplify the below.
|
|
||||||
|
# * default argument objects in positional order
|
||||||
|
# * pairs of name and default argument, with the name just below
|
||||||
|
# the object on the stack, for keyword-only parameters
|
||||||
|
# * parameter annotation objects
|
||||||
|
# * a tuple listing the parameter names for the annotations
|
||||||
|
# (only if there are ony annotation objects)
|
||||||
|
# * the code associated with the function (at TOS1)
|
||||||
|
# * the qualified name of the function (at TOS)
|
||||||
|
|
||||||
|
# For Python 3.0 .. 3.2 the evaluation stack is:
|
||||||
|
# The function object is defined to have argc default parameters,
|
||||||
|
# which are found below TOS.
|
||||||
|
# * first come positional args in the order they are given in the source,
|
||||||
|
# * next come the keyword args in the order they given in the source,
|
||||||
|
# * finally is the code associated with the function (at TOS)
|
||||||
|
#
|
||||||
|
# Note: There is no qualified name at TOS
|
||||||
|
|
||||||
|
# MAKE_CLOSURE adds an additional closure slot
|
||||||
|
|
||||||
|
# Thank you, Python, for a such a well-thought out system that has
|
||||||
|
# changed 4 or so times.
|
||||||
|
|
||||||
def build_param(ast, name, default):
|
def build_param(ast, name, default):
|
||||||
"""build parameters:
|
"""build parameters:
|
||||||
@@ -451,21 +475,31 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
|
|||||||
# MAKE_FUNCTION_... or MAKE_CLOSURE_...
|
# MAKE_FUNCTION_... or MAKE_CLOSURE_...
|
||||||
assert node[-1].type.startswith('MAKE_')
|
assert node[-1].type.startswith('MAKE_')
|
||||||
|
|
||||||
|
|
||||||
|
# Python 3.3+ adds a qualified name at TOS (-1)
|
||||||
|
# moving down the LOAD_LAMBDA instruction
|
||||||
|
if 3.0 <= self.version <= 3.2:
|
||||||
|
lambda_index = -2
|
||||||
|
elif 3.03 <= self.version:
|
||||||
|
lambda_index = -3
|
||||||
|
else:
|
||||||
|
lambda_index = None
|
||||||
|
|
||||||
args_node = node[-1]
|
args_node = node[-1]
|
||||||
if isinstance(args_node.attr, tuple):
|
if isinstance(args_node.attr, tuple):
|
||||||
if self.version <= 3.3 and len(node) > 2 and node[-3] != 'LOAD_LAMBDA':
|
pos_args, kw_args, annotate_argc = args_node.attr
|
||||||
# positional args are after kwargs
|
if self.version <= 3.3 and len(node) > 2 and node[lambda_index] != 'LOAD_LAMBDA':
|
||||||
|
# args are after kwargs; kwargs are bundled as one node
|
||||||
defparams = node[1:args_node.attr[0]+1]
|
defparams = node[1:args_node.attr[0]+1]
|
||||||
else:
|
else:
|
||||||
# positional args are before kwargs
|
# args are before kwargs; kwags as bundled as one node
|
||||||
defparams = node[:args_node.attr[0]]
|
defparams = node[:args_node.attr[0]]
|
||||||
pos_args, kw_args, annotate_argc = args_node.attr
|
|
||||||
else:
|
else:
|
||||||
if self.version < 3.6:
|
if self.version < 3.6:
|
||||||
defparams = node[:args_node.attr]
|
defparams = node[:args_node.attr]
|
||||||
else:
|
else:
|
||||||
default, kw, annotate, closure = args_node.attr
|
default, kw, annotate, closure = args_node.attr
|
||||||
# FIXME: start here.
|
# FIXME: start here for Python 3.6 and above:
|
||||||
defparams = []
|
defparams = []
|
||||||
# if default:
|
# if default:
|
||||||
# defparams = node[-(2 + kw + annotate + closure)]
|
# defparams = node[-(2 + kw + annotate + closure)]
|
||||||
@@ -475,12 +509,6 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
|
|||||||
kw_args = 0
|
kw_args = 0
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if 3.0 <= self.version <= 3.2:
|
|
||||||
lambda_index = -2
|
|
||||||
elif 3.03 <= self.version:
|
|
||||||
lambda_index = -3
|
|
||||||
else:
|
|
||||||
lambda_index = None
|
|
||||||
|
|
||||||
if lambda_index and isLambda and iscode(node[lambda_index].attr):
|
if lambda_index and isLambda and iscode(node[lambda_index].attr):
|
||||||
assert node[lambda_index].type == 'LOAD_LAMBDA'
|
assert node[lambda_index].type == 'LOAD_LAMBDA'
|
||||||
@@ -496,7 +524,7 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
|
|||||||
paramnames = list(code.co_varnames[:argc])
|
paramnames = list(code.co_varnames[:argc])
|
||||||
|
|
||||||
# defaults are for last n parameters, thus reverse
|
# defaults are for last n parameters, thus reverse
|
||||||
if not 3.0 <= self.version <= 3.2:
|
if not 3.0 <= self.version <= 3.1:
|
||||||
paramnames.reverse(); defparams.reverse()
|
paramnames.reverse(); defparams.reverse()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -510,58 +538,27 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
|
|||||||
return
|
return
|
||||||
|
|
||||||
kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0
|
kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0
|
||||||
indent = self.indent
|
|
||||||
|
|
||||||
# build parameters
|
# build parameters
|
||||||
if self.version != 3.2:
|
params = [build_param(ast, name, d) for
|
||||||
params = [build_param(ast, name, default) for
|
name, d in zip_longest(paramnames, defparams, fillvalue=None)]
|
||||||
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
|
|
||||||
|
if not 3.0 <= self.version <= 3.1:
|
||||||
params.reverse() # back to correct order
|
params.reverse() # back to correct order
|
||||||
|
|
||||||
if code_has_star_arg(code):
|
if code_has_star_arg(code):
|
||||||
if self.version > 3.0:
|
if self.version > 3.0:
|
||||||
params.append('*%s' % code.co_varnames[argc + kw_pairs])
|
params.append('*%s' % code.co_varnames[argc + kw_pairs])
|
||||||
else:
|
|
||||||
params.append('*%s' % code.co_varnames[argc])
|
|
||||||
argc += 1
|
|
||||||
|
|
||||||
# dump parameter list (with default values)
|
|
||||||
if isLambda:
|
|
||||||
self.write("lambda ", ", ".join(params))
|
|
||||||
else:
|
else:
|
||||||
self.write("(", ", ".join(params))
|
params.append('*%s' % code.co_varnames[argc])
|
||||||
# self.println(indent, '#flags:\t', int(code.co_flags))
|
argc += 1
|
||||||
|
|
||||||
|
# dump parameter list (with default values)
|
||||||
|
if isLambda:
|
||||||
|
self.write("lambda ", ", ".join(params))
|
||||||
else:
|
else:
|
||||||
if isLambda:
|
self.write("(", ", ".join(params))
|
||||||
self.write("lambda ")
|
# self.println(indent, '#flags:\t', int(code.co_flags))
|
||||||
else:
|
|
||||||
self.write("(")
|
|
||||||
pass
|
|
||||||
|
|
||||||
last_line = self.f.getvalue().split("\n")[-1]
|
|
||||||
l = len(last_line)
|
|
||||||
indent = ' ' * l
|
|
||||||
line_number = self.line_number
|
|
||||||
|
|
||||||
if code_has_star_arg(code):
|
|
||||||
self.write('*%s' % code.co_varnames[argc + kw_pairs])
|
|
||||||
argc += 1
|
|
||||||
|
|
||||||
i = len(paramnames) - len(defparams)
|
|
||||||
self.write(", ".join(paramnames[:i]))
|
|
||||||
suffix = ', ' if i > 0 else ''
|
|
||||||
for n in node:
|
|
||||||
if n == 'pos_arg':
|
|
||||||
self.write(suffix)
|
|
||||||
self.write(paramnames[i] + '=')
|
|
||||||
i += 1
|
|
||||||
self.preorder(n)
|
|
||||||
if (line_number != self.line_number):
|
|
||||||
suffix = ",\n" + indent
|
|
||||||
line_number = self.line_number
|
|
||||||
else:
|
|
||||||
suffix = ', '
|
|
||||||
|
|
||||||
if kw_args > 0:
|
if kw_args > 0:
|
||||||
if not (4 & code.co_flags):
|
if not (4 & code.co_flags):
|
||||||
|
@@ -358,9 +358,33 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.prec = p
|
self.prec = p
|
||||||
self.prune()
|
self.prune()
|
||||||
self.n_async_call_function = n_async_call_function
|
self.n_async_call_function = n_async_call_function
|
||||||
|
|
||||||
self.n_build_list_unpack = self.n_build_list
|
self.n_build_list_unpack = self.n_build_list
|
||||||
|
|
||||||
|
if version == 3.5:
|
||||||
|
def n_call_function(node):
|
||||||
|
mapping = self._get_mapping(node)
|
||||||
|
table = mapping[0]
|
||||||
|
key = node
|
||||||
|
for i in mapping[1:]:
|
||||||
|
key = key[i]
|
||||||
|
pass
|
||||||
|
if key.type.startswith('CALL_FUNCTION_VAR_KW'):
|
||||||
|
# Python 3.5 changes the stack position of *args. kwargs come
|
||||||
|
# after *args whereas in earlier Pythons, *args is at the end
|
||||||
|
# which simpilfiies things from our perspective.
|
||||||
|
# Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX
|
||||||
|
# We will just swap the order to make it look like earlier Python 3.
|
||||||
|
entry = table[key.type]
|
||||||
|
kwarg_pos = entry[2][1]
|
||||||
|
args_pos = kwarg_pos - 1
|
||||||
|
# Put last node[args_pos] after subsequent kwargs
|
||||||
|
while node[kwarg_pos] == 'kwarg' and kwarg_pos < len(node):
|
||||||
|
# swap node[args_pos] with node[kwargs_pos]
|
||||||
|
node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
|
||||||
|
args_pos = kwarg_pos
|
||||||
|
kwarg_pos += 1
|
||||||
|
self.default(node)
|
||||||
|
self.n_call_function = n_call_function
|
||||||
|
|
||||||
def n_funcdef(node):
|
def n_funcdef(node):
|
||||||
if self.version == 3.6:
|
if self.version == 3.6:
|
||||||
@@ -547,25 +571,32 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
node == AST('return_stmt',
|
node == AST('return_stmt',
|
||||||
[AST('ret_expr', [NONE]), Token('RETURN_VALUE')]))
|
[AST('ret_expr', [NONE]), Token('RETURN_VALUE')]))
|
||||||
|
|
||||||
def n_continue_stmt(self, node):
|
## The below doesn't work because continue may be the only thing inside an 'else'. For example
|
||||||
if self.version >= 3.0 and node[0] == 'CONTINUE':
|
# for ...
|
||||||
t = node[0]
|
# if ...
|
||||||
if not t.linestart:
|
# else:
|
||||||
# Artificially-added "continue" statements derived from JUMP_ABSOLUTE
|
# continue
|
||||||
# don't have line numbers associated with them.
|
#
|
||||||
# If this is a CONTINUE is to the same target as a JUMP_ABSOLUTE following it,
|
# def n_continue_stmt(self, node):
|
||||||
# then the "continue" can be suppressed.
|
# if self.version >= 3.0 and node[0] == 'CONTINUE':
|
||||||
op, offset = t.op, t.offset
|
# t = node[0]
|
||||||
next_offset = self.scanner.next_offset(op, offset)
|
# if not t.linestart:
|
||||||
scanner = self.scanner
|
# # Artificially-added "continue" statements derived from JUMP_ABSOLUTE
|
||||||
code = scanner.code
|
# # don't have line numbers associated with them.
|
||||||
if next_offset < len(code):
|
# # If this is a CONTINUE is to the same target as a JUMP_ABSOLUTE following it,
|
||||||
next_inst = code[next_offset]
|
# # then the "continue" can be suppressed.
|
||||||
if (scanner.opc.opname[next_inst] == 'JUMP_ABSOLUTE'
|
# op, offset = t.op, t.offset
|
||||||
and t.pattr == code[next_offset+1]):
|
# next_offset = self.scanner.next_offset(op, offset)
|
||||||
# Suppress "continue"
|
# scanner = self.scanner
|
||||||
self.prune()
|
# code = scanner.code
|
||||||
self.default(node)
|
# if next_offset < len(code):
|
||||||
|
# next_inst = code[next_offset]
|
||||||
|
# if (scanner.opc.opname[next_inst] == 'JUMP_ABSOLUTE'
|
||||||
|
# and t.pattr == code[next_offset+1]):
|
||||||
|
# # Suppress "continue"
|
||||||
|
# import pdb; pdb.set_trace()
|
||||||
|
# self.prune()
|
||||||
|
# self.default(node)
|
||||||
|
|
||||||
def n_return_stmt(self, node):
|
def n_return_stmt(self, node):
|
||||||
if self.params['isLambda']:
|
if self.params['isLambda']:
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
# This file is suitable for sourcing inside bash as
|
# This file is suitable for sourcing inside bash as
|
||||||
# well as importing into Python
|
# well as importing into Python
|
||||||
VERSION='2.10.1'
|
VERSION='2.11.0'
|
||||||
|
Reference in New Issue
Block a user