You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Python 3.6 CALL_FUNCTION_EX first attempt
This commit is contained in:
BIN
test/bytecode_3.6/01_call_function.pyc
Normal file
BIN
test/bytecode_3.6/01_call_function.pyc
Normal file
Binary file not shown.
5
test/simple_source/bug36/01_call_function.py
Normal file
5
test/simple_source/bug36/01_call_function.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# Python 3.6's changes for calling functions.
|
||||
# See https://github.com/rocky/python-uncompyle6/issues/58
|
||||
# CALL_FUNCTION_EX takes 2 to 3 arguments on the stack: the function, the tuple of positional arguments,
|
||||
# and optionally the dict of keyword arguments if bit 0 of oparg is 1.
|
||||
a(*[])
|
@@ -26,12 +26,16 @@ class Python36Parser(Python35Parser):
|
||||
|
||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
|
||||
call_function ::= expr expr CALL_FUNCTION_EX
|
||||
call_function ::= expr expr expr CALL_FUNCTION_EX_KW
|
||||
"""
|
||||
|
||||
def add_custom_rules(self, tokens, customize):
|
||||
super(Python36Parser, self).add_custom_rules(tokens, customize)
|
||||
for i, token in enumerate(tokens):
|
||||
opname = token.type
|
||||
|
||||
if opname == 'FORMAT_VALUE':
|
||||
rules_str = """
|
||||
expr ::= fstring_single
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) 2016 by Rocky Bernstein
|
||||
"""
|
||||
Python 3.5 bytecode scanner/deparser
|
||||
Python 3.6 bytecode scanner/deparser
|
||||
|
||||
This sets up opcodes Python's 3.5 and calls a generalized
|
||||
This sets up opcodes Python's 3.6 and calls a generalized
|
||||
scanner routine for Python 3.
|
||||
"""
|
||||
|
||||
@@ -19,6 +19,18 @@ class Scanner36(Scanner3):
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner3.__init__(self, 3.6, show_asm)
|
||||
return
|
||||
|
||||
def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||
tokens, customize = Scanner3.ingest(self, co, classname, code_objects, show_asm)
|
||||
for t in tokens:
|
||||
# The lowest bit of flags indicates whether the
|
||||
# var-keyword argument is placed at the top of the stack
|
||||
if t.op == self.opc.CALL_FUNCTION_EX and t.attr & 1:
|
||||
t.type = 'CALL_FUNCTION_EX_KW'
|
||||
pass
|
||||
pass
|
||||
return tokens, customize
|
||||
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -393,7 +393,11 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
'fstring_multi': ( "f'%c'", 0),
|
||||
'func_args36': ( "%c(**", 0),
|
||||
})
|
||||
|
||||
TABLE_R.update({
|
||||
'CALL_FUNCTION_EX': ('%c(*%P)', 0, (1, 2, ', ', 100)),
|
||||
# Not quite right
|
||||
'CALL_FUNCTION_EX_KW': ('%c%c *%c', 0, 1, 2)
|
||||
})
|
||||
FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a'}
|
||||
|
||||
def f_conversion(node):
|
||||
@@ -1698,14 +1702,20 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
self.prec = p
|
||||
arg += 1
|
||||
elif typ == 'C':
|
||||
low, high, sep = entry[arg]
|
||||
remaining = len(node[low:high])
|
||||
for subnode in node[low:high]:
|
||||
self.preorder(subnode)
|
||||
remaining -= 1
|
||||
if remaining > 0:
|
||||
self.write(sep)
|
||||
arg += 1
|
||||
try:
|
||||
low, high, sep = entry[arg]
|
||||
remaining = len(node[low:high])
|
||||
for subnode in node[low:high]:
|
||||
self.preorder(subnode)
|
||||
remaining -= 1
|
||||
if remaining > 0:
|
||||
self.write(sep)
|
||||
pass
|
||||
pass
|
||||
arg += 1
|
||||
except:
|
||||
from trepan.api import debug; debug()
|
||||
pass
|
||||
elif typ == 'D':
|
||||
low, high, sep = entry[arg]
|
||||
remaining = len(node[low:high])
|
||||
|
Reference in New Issue
Block a user