Python 3.6 CALL_FUNCTION_EX first attempt

This commit is contained in:
rocky
2017-04-25 07:31:01 -04:00
parent 50687e6317
commit 84fd71b73b
7 changed files with 42 additions and 11 deletions

Binary file not shown.

View 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(*[])

View File

@@ -26,12 +26,16 @@ class Python36Parser(Python35Parser):
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 expr CALL_FUNCTION_EX_KW
""" """
def add_custom_rules(self, tokens, customize): def add_custom_rules(self, tokens, customize):
super(Python36Parser, self).add_custom_rules(tokens, customize) super(Python36Parser, self).add_custom_rules(tokens, customize)
for i, token in enumerate(tokens): for i, token in enumerate(tokens):
opname = token.type opname = token.type
if opname == 'FORMAT_VALUE': if opname == 'FORMAT_VALUE':
rules_str = """ rules_str = """
expr ::= fstring_single expr ::= fstring_single

View File

@@ -1,8 +1,8 @@
# Copyright (c) 2016 by Rocky Bernstein # 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. scanner routine for Python 3.
""" """
@@ -19,6 +19,18 @@ class Scanner36(Scanner3):
def __init__(self, show_asm=None): def __init__(self, show_asm=None):
Scanner3.__init__(self, 3.6, show_asm) Scanner3.__init__(self, 3.6, show_asm)
return 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 pass
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -393,7 +393,11 @@ class SourceWalker(GenericASTTraversal, object):
'fstring_multi': ( "f'%c'", 0), 'fstring_multi': ( "f'%c'", 0),
'func_args36': ( "%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'} FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a'}
def f_conversion(node): def f_conversion(node):
@@ -1698,14 +1702,20 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = p self.prec = p
arg += 1 arg += 1
elif typ == 'C': elif typ == 'C':
low, high, sep = entry[arg] try:
remaining = len(node[low:high]) low, high, sep = entry[arg]
for subnode in node[low:high]: remaining = len(node[low:high])
self.preorder(subnode) for subnode in node[low:high]:
remaining -= 1 self.preorder(subnode)
if remaining > 0: remaining -= 1
self.write(sep) if remaining > 0:
arg += 1 self.write(sep)
pass
pass
arg += 1
except:
from trepan.api import debug; debug()
pass
elif typ == 'D': elif typ == 'D':
low, high, sep = entry[arg] low, high, sep = entry[arg]
remaining = len(node[low:high]) remaining = len(node[low:high])